Trade works!

This commit is contained in:
Yair Morgenstern
2018-07-06 16:28:42 +03:00
parent 895b4b55e2
commit 74b10e8a31
5 changed files with 207 additions and 64 deletions

View File

@ -262,7 +262,7 @@ class CityStats {
currentCityStats = Stats()
for (stat in baseStatList.values) currentCityStats.add(stat)
if(currentCityStats.production<1) currentCityStats.production=1
if(currentCityStats.production<1) currentCityStats.production=1f
}

View File

@ -15,7 +15,10 @@ import com.unciv.models.gamebasics.tile.ResourceType
import com.unciv.models.gamebasics.tile.TileResource
import com.unciv.models.gamebasics.unit.UnitType
import com.unciv.models.stats.Stats
import com.unciv.ui.Trade
import com.unciv.ui.TradeType
import com.unciv.ui.utils.getRandom
import com.unciv.ui.utils.tr
import kotlin.math.max
import kotlin.math.pow
@ -34,7 +37,7 @@ class CivilizationInfo {
var goldenAges = GoldenAgeManager()
var greatPeople = GreatPersonManager()
var scienceVictory = ScienceVictoryManager()
// @Transient var diplomacy = HashMap<String,DiplomacyManager>()
var diplomacy = HashMap<String,DiplomacyManager>()
var cities = ArrayList<CityInfo>()
var exploredTiles = HashSet<Vector2>()
@ -134,6 +137,7 @@ class CivilizationInfo {
fun getCivResources(): Counter<TileResource> {
val civResources = Counter<TileResource>()
for (city in cities) civResources.add(city.getCityResources())
for (dip in diplomacy.values) civResources.add(dip.resourcesFromTrade())
return civResources
}
@ -155,6 +159,7 @@ class CivilizationInfo {
goldenAges.civInfo = this
policies.civInfo = this
tech.civInfo = this
diplomacy.values.forEach { it.civInfo=this}
for (unit in getCivUnits()) {
unit.civInfo=this
@ -207,6 +212,7 @@ class CivilizationInfo {
goldenAges.endTurn(happiness)
getCivUnits().forEach { it.endTurn() }
diplomacy.values.forEach{it.nextTurn()}
gameInfo.updateTilesToCities()
}
@ -239,6 +245,18 @@ class CivilizationInfo {
viewablePositions += getCivUnits()
.flatMap { it.getViewableTiles()} // Tiles within 2 tiles of units
viewablePositions.map { it.position }.filterNot { exploredTiles.contains(it) }.toCollection(exploredTiles)
val viewedCivs = viewablePositions
.flatMap { it.getUnits().map { u->u.civInfo }.union(listOf(it.getOwner())) }
.filterNotNull().filterNot { it==this }
for(otherCiv in viewedCivs)
if(!diplomacy.containsKey(otherCiv.civName)){
diplomacy[otherCiv.civName] = DiplomacyManager().apply { otherCivName=otherCiv.civName }
otherCiv.diplomacy[civName] = DiplomacyManager().apply { otherCivName=civName }
addNotification("We have encountered ["+otherCiv.civName+"]!".tr(),null, Color.GOLD)
}
return viewablePositions.distinct()
}
@ -265,14 +283,40 @@ enum class DiplomaticStatus{
War
}
//class DiplomacyManager {
// @Transient lateinit var civInfo:CivilizationInfo
// lateinit var otherCivName:String
// var status:DiplomaticStatus = DiplomaticStatus.Peace
//
// fun otherCiv() = civInfo.gameInfo.civilizations.first{it.civName==otherCivName}
class DiplomacyManager {
@Transient lateinit var civInfo:CivilizationInfo
lateinit var otherCivName:String
// var status:DiplomaticStatus = DiplomaticStatus.War
var trades = ArrayList<Trade>()
fun resourcesFromTrade(): Counter<TileResource> {
val counter = Counter<TileResource>()
for(trade in trades){
for(offer in trade.ourOffers)
if(offer.type==TradeType.Strategic_Resource || offer.type==TradeType.Luxury_Resource)
counter.add(GameBasics.TileResources[offer.name]!!,-offer.amount)
for(offer in trade.theirOffers)
if(offer.type==TradeType.Strategic_Resource || offer.type==TradeType.Luxury_Resource)
counter.add(GameBasics.TileResources[offer.name]!!,offer.amount)
}
return counter
}
fun nextTurn(){
for(trade in trades.toList()){ // Each civ lowers their own offers by 1. If we were to lower the enemies as well, the offers would date twice as fast!
for(offer in trade.ourOffers.union(trade.theirOffers).filter { it.duration>0 })
offer.duration--
if(trade.ourOffers.all { it.duration<=0 } && trade.theirOffers.all { it.duration<=0 }) {
trades.remove(trade)
civInfo.addNotification("One of our trades with [$otherCivName] has ended!".tr(),null, Color.YELLOW)
}
}
}
fun otherCiv() = civInfo.gameInfo.civilizations.first{it.civName==otherCivName}
// fun declareWar(){
// status = DiplomaticStatus.War
// otherCiv().diplomacy[civInfo.civName]!!.status = DiplomaticStatus.War
// }
//}
}

View File

@ -1,32 +1,94 @@
package com.unciv.ui
import com.badlogic.gdx.scenes.scene2d.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.badlogic.gdx.utils.Align
import com.unciv.UnCivGame
import com.unciv.logic.civilization.CivilizationInfo
import com.unciv.ui.utils.*
import kotlin.math.max
import kotlin.math.roundToInt
class EmpireOverviewScreen : CameraStageBaseScreen(){
init {
val civInfo = UnCivGame.Current.gameInfo.getPlayerCivilization()
val closeButton = TextButton("Close".tr(), skin)
val civInfo = UnCivGame.Current.gameInfo.getPlayerCivilization()
init {
val topTable = Table().apply { defaults().pad(10f) }
val centerTable=Table().apply { defaults().pad(20f) }
val closeButton = TextButton("Close".tr(), skin)
closeButton.addClickListener { UnCivGame.Current.setWorldScreen() }
closeButton.y = stage.height - closeButton.height - 5
stage.addActor(closeButton)
topTable.add(closeButton)
val table=Table()
table.defaults().pad(20f)
val setCityInfoButton = TextButton("Cities",skin)
val setCities = {
centerTable.clear()
centerTable.add(getCityInfoTable())
centerTable.pack()
centerTable.center(stage)
}
setCities()
setCityInfoButton.addClickListener(setCities)
topTable.add(setCityInfoButton)
table.add(getCityInfoTable(civInfo))
table.add(getHappinessTable(civInfo))
table.add(getGoldTable(civInfo))
table.center(stage)
stage.addActor(table)
val setStatsInfoButton = TextButton("Stats",skin)
setStatsInfoButton.addClickListener {
centerTable.clear()
centerTable.add(getHappinessTable())
centerTable.add(getGoldTable())
centerTable.pack()
centerTable.center(stage)
}
topTable.add(setStatsInfoButton)
val setCurrentTradesButton = TextButton("Trades",skin)
setCurrentTradesButton.addClickListener {
centerTable.clear()
centerTable.add(getTradesTable())
centerTable.pack()
centerTable.center(stage)
}
topTable.add(setCurrentTradesButton)
topTable.pack()
topTable.width = stage.width
topTable.y = stage.height-topTable.height
stage.addActor(topTable)
stage.addActor(centerTable)
}
private fun getHappinessTable(civInfo: CivilizationInfo): Table {
private fun getTradesTable(): Table {
val tradesTable = Table()
for(diplomacy in civInfo.diplomacy.values)
for(trade in diplomacy.trades)
tradesTable.add(createTradeTable(trade,diplomacy.otherCivName)).row()
return tradesTable
}
private fun createTradeTable(trade:Trade, civName:String): Table {
val table = Table(skin)
table.defaults().pad(10f)
table.add(civInfo.civName)
table.add(civName).row()
val ourOffersStrings = trade.ourOffers.map { it.amount.toString()+" "+it.name +
(if (it.duration==0) "" else " ("+it.duration+" turns)") }
val theirOffersStrings = trade.theirOffers.map { it.amount.toString()+" "+it.name +
(if (it.duration==0) "" else " ("+it.duration+" turns)") }
for(i in 0 until max(trade.ourOffers.size,trade.theirOffers.size)){
if(ourOffersStrings.size>i) table.add(ourOffersStrings[i])
else table.add()
if(theirOffersStrings.size>i) table.add(theirOffersStrings[i])
else table.add()
table.row()
}
return table
}
private fun getHappinessTable(): Table {
val happinessTable = Table(skin)
happinessTable.defaults().pad(5f)
happinessTable.add(Label("Happiness", skin).setFont(24)).colspan(2).row()
@ -40,7 +102,7 @@ class EmpireOverviewScreen : CameraStageBaseScreen(){
return happinessTable
}
private fun getGoldTable(civInfo: CivilizationInfo): Table {
private fun getGoldTable(): Table {
val goldTable = Table(skin)
goldTable.defaults().pad(5f)
goldTable.add(Label("Gold", skin).setFont(24)).colspan(2).row()
@ -57,7 +119,7 @@ class EmpireOverviewScreen : CameraStageBaseScreen(){
return goldTable
}
private fun getCityInfoTable(civInfo: CivilizationInfo): Table {
private fun getCityInfoTable(): Table {
val iconSize = 20f//if you set this too low, there is a chance that the tables will be misaligned
val padding = 5f

View File

@ -6,7 +6,6 @@ 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
@ -20,7 +19,10 @@ enum class TradeType{
City
}
data class TradeOffer(val name:String, val type:TradeType, val duration:Int) {
data class TradeOffer(var name:String, var type:TradeType, var duration:Int, var amount:Int) {
constructor() : this("",TradeType.Gold,0,0) // so that the json deserializer can work
fun getText(): String {
var text = "{$name}"
if(duration>0) text += " ($duration {turns})"
@ -28,9 +30,27 @@ data class TradeOffer(val name:String, val type:TradeType, val duration:Int) {
}
}
class TradeOffersList():Counter<TradeOffer>(){}
class TradeOffersList:ArrayList<TradeOffer>(){
override fun add(element: TradeOffer): Boolean {
val equivalentOffer = firstOrNull { it.name==element.name&&it.type==element.type }
if(equivalentOffer==null){
super.add(element)
return true
}
equivalentOffer.amount += element.amount
if(equivalentOffer.amount==0) remove(equivalentOffer)
return true
}
}
class Trade{
fun reverse(): Trade {
val newTrade = Trade()
newTrade.theirOffers+=ourOffers.map { it.copy() }
newTrade.ourOffers+=theirOffers.map { it.copy() }
return newTrade
}
class Trade(){
val theirOffers = TradeOffersList()
val ourOffers = TradeOffersList()
}
@ -66,6 +86,13 @@ class TradeScreen(val otherCivilization: CivilizationInfo) : CameraStageBaseScre
}
else tradeText.setText("I think not.")
}
else if(offerButton.text.toString() == "Accept"){
civInfo.diplomacy[otherCivilization.civName]!!.trades.add(currentTrade)
otherCivilization.diplomacy[civInfo.civName]!!.trades.add(currentTrade.reverse())
val newTradeScreen = TradeScreen(otherCivilization)
UnCivGame.Current.screen = newTradeScreen
newTradeScreen.tradeText.setText("Pleasure doing business with you!")
}
}
lowerTable.add(offerButton)
@ -81,34 +108,34 @@ class TradeScreen(val otherCivilization: CivilizationInfo) : CameraStageBaseScre
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))
val ourAvailableOffersTable = getTableOfOffers(ourAvailableOffers, currentTrade.ourOffers)
val ourOffersTable = getTableOfOffers(currentTrade.ourOffers, ourAvailableOffers)
val theirOffersTable = getTableOfOffers(currentTrade.theirOffers, theirAvailableOffers)
val theirAvailableOffersTable = 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.add(ourAvailableOffersTable).size(stage.width/4,stage.width/2)
table.add(ourOffersTable).size(stage.width/4,stage.width/2)
table.add(theirOffersTable).size(stage.width/4,stage.width/2)
table.add(theirAvailableOffersTable).size(stage.width/4,stage.width/2)
table.pack()
table.center(stage)
}
fun getTableOfOffers(offers: TradeOffersList, correspondingOffers: TradeOffersList): Table {
fun getTableOfOffers(offers: TradeOffersList, correspondingOffers: TradeOffersList): ScrollPane {
val table= Table(skin).apply { defaults().pad(5f) }
for(offer in offers) {
val tb = TextButton(offer.key.name+" ("+offer.value+")",skin)
val tb = TextButton(offer.name+" ("+offer.amount+")",skin)
val amountPerClick =
if(offer.key.type==TradeType.Gold) 50
if(offer.type==TradeType.Gold) 50
else 1
if(offer.value>0)
if(offer.amount>0)
tb.addClickListener {
val amountTransfered = min(amountPerClick, offer.value)
offers.add(offer.key,-amountTransfered)
correspondingOffers.add(offer.key,amountTransfered)
val amountTransferred = min(amountPerClick, offer.amount)
offers += offer.copy(amount = -amountTransferred)
correspondingOffers += offer.copy(amount = amountTransferred)
offerButton.setText("Offer trade")
tradeText.setText("What do you have in mind?")
update()
@ -116,7 +143,7 @@ class TradeScreen(val otherCivilization: CivilizationInfo) : CameraStageBaseScre
else tb.disable() // for instance we have negative gold
table.add(tb).row()
}
return table
return ScrollPane(table)
}
fun getAvailableOffers(civInfo: CivilizationInfo): TradeOffersList {
@ -124,28 +151,30 @@ class TradeScreen(val otherCivilization: CivilizationInfo) : CameraStageBaseScre
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(entry.key.name, resourceTradeType, 30, entry.value))
}
offers.add(TradeOffer("Gold",TradeType.Gold,0),civInfo.gold)
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()
val sumOfTheirOffers = trade.theirOffers.map { evaluateOffer(it,false) }.sum()
val sumOfOurOffers = trade.ourOffers.map { evaluateOffer(it,true)}.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
var value = 100*offer.amount
if(!theirAvailableOffers.any { it.name==offer.name }) // We want to take away their last luxury or give them one they don't have
value += 250
else if(!otherCivIsRecieving && !ourAvailableOffers.any { it.name==offer.name })
value += 250 // they're giving us a luxury we don't have yet
return value // this is useful only as a barter trade to other civs
}
if(offer.type == TradeType.Strategic_Resource){
return 50
return 50 * offer.amount
}
return 1000 // Dunno what this is?
}

View File

@ -1,6 +1,7 @@
package com.unciv.ui.worldscreen
import com.badlogic.gdx.Gdx
import com.badlogic.gdx.graphics.Color
import com.badlogic.gdx.math.Vector2
import com.badlogic.gdx.scenes.scene2d.ui.Table
import com.badlogic.gdx.scenes.scene2d.ui.TextButton
@ -27,7 +28,7 @@ class WorldScreen : CameraStageBaseScreen() {
val bottomBar = WorldScreenBottomBar(this)
val unitActionsTable = UnitActionsTable(this)
private val techButton = TextButton("", CameraStageBaseScreen.skin)
private val techButton = TextButton("", CameraStageBaseScreen.skin).apply { color= Color.BLUE }
val tradeButtons = Table()
private val nextTurnButton = createNextTurnButton()
@ -59,14 +60,8 @@ class WorldScreen : CameraStageBaseScreen() {
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)
tradeButtons.isVisible=false
// tradeButtons.isVisible=false
bottomBar.width = stage.width
stage.addActor(bottomBar)
@ -86,6 +81,8 @@ class WorldScreen : CameraStageBaseScreen() {
}
updateTechButton()
updateTradeButtons()
bottomBar.update(tileMapHolder.selectedTile) // has to come before tilemapholder update because the tilemapholder actions depend on the selected unit!
minimap.update()
minimap.y = bottomBar.height
@ -104,6 +101,19 @@ class WorldScreen : CameraStageBaseScreen() {
else if(civInfo.greatPeople.freeGreatPeople>0) game.screen = GreatPersonPickerScreen()
}
private fun updateTradeButtons() {
tradeButtons.clear()
for(civ in gameInfo.civilizations.filterNot { it.isDefeated() || it.isPlayerCivilization() || it.isBarbarianCivilization() }){
if(!civInfo.diplomacy.containsKey(civ.civName)) continue
val tb = TextButton("Trade with [${civ.civName}]".tr(),skin)
tb.addClickListener { UnCivGame.Current.screen = TradeScreen(civ) }
tradeButtons.add(tb).row()
}
tradeButtons.pack()
tradeButtons.y = techButton.y -20 - tradeButtons.height
}
private fun updateTechButton() {
techButton.isVisible = civInfo.cities.isNotEmpty()
@ -115,8 +125,6 @@ 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 {