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() currentCityStats = Stats()
for (stat in baseStatList.values) currentCityStats.add(stat) 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.tile.TileResource
import com.unciv.models.gamebasics.unit.UnitType import com.unciv.models.gamebasics.unit.UnitType
import com.unciv.models.stats.Stats 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.getRandom
import com.unciv.ui.utils.tr
import kotlin.math.max import kotlin.math.max
import kotlin.math.pow import kotlin.math.pow
@ -34,7 +37,7 @@ class CivilizationInfo {
var goldenAges = GoldenAgeManager() var goldenAges = GoldenAgeManager()
var greatPeople = GreatPersonManager() var greatPeople = GreatPersonManager()
var scienceVictory = ScienceVictoryManager() var scienceVictory = ScienceVictoryManager()
// @Transient var diplomacy = HashMap<String,DiplomacyManager>() var diplomacy = HashMap<String,DiplomacyManager>()
var cities = ArrayList<CityInfo>() var cities = ArrayList<CityInfo>()
var exploredTiles = HashSet<Vector2>() var exploredTiles = HashSet<Vector2>()
@ -134,6 +137,7 @@ class CivilizationInfo {
fun getCivResources(): Counter<TileResource> { fun getCivResources(): Counter<TileResource> {
val civResources = Counter<TileResource>() val civResources = Counter<TileResource>()
for (city in cities) civResources.add(city.getCityResources()) for (city in cities) civResources.add(city.getCityResources())
for (dip in diplomacy.values) civResources.add(dip.resourcesFromTrade())
return civResources return civResources
} }
@ -155,6 +159,7 @@ class CivilizationInfo {
goldenAges.civInfo = this goldenAges.civInfo = this
policies.civInfo = this policies.civInfo = this
tech.civInfo = this tech.civInfo = this
diplomacy.values.forEach { it.civInfo=this}
for (unit in getCivUnits()) { for (unit in getCivUnits()) {
unit.civInfo=this unit.civInfo=this
@ -207,6 +212,7 @@ class CivilizationInfo {
goldenAges.endTurn(happiness) goldenAges.endTurn(happiness)
getCivUnits().forEach { it.endTurn() } getCivUnits().forEach { it.endTurn() }
diplomacy.values.forEach{it.nextTurn()}
gameInfo.updateTilesToCities() gameInfo.updateTilesToCities()
} }
@ -239,6 +245,18 @@ class CivilizationInfo {
viewablePositions += getCivUnits() viewablePositions += getCivUnits()
.flatMap { it.getViewableTiles()} // Tiles within 2 tiles of units .flatMap { it.getViewableTiles()} // Tiles within 2 tiles of units
viewablePositions.map { it.position }.filterNot { exploredTiles.contains(it) }.toCollection(exploredTiles) 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() return viewablePositions.distinct()
} }
@ -265,14 +283,40 @@ enum class DiplomaticStatus{
War War
} }
//class DiplomacyManager { class DiplomacyManager {
// @Transient lateinit var civInfo:CivilizationInfo @Transient lateinit var civInfo:CivilizationInfo
// lateinit var otherCivName:String lateinit var otherCivName:String
// var status:DiplomaticStatus = DiplomaticStatus.Peace // var status:DiplomaticStatus = DiplomaticStatus.War
// var trades = ArrayList<Trade>()
// fun otherCiv() = civInfo.gameInfo.civilizations.first{it.civName==otherCivName}
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(){ // fun declareWar(){
// status = DiplomaticStatus.War // status = DiplomaticStatus.War
// otherCiv().diplomacy[civInfo.civName]!!.status = DiplomaticStatus.War // otherCiv().diplomacy[civInfo.civName]!!.status = DiplomaticStatus.War
// } // }
//} }

View File

@ -1,32 +1,94 @@
package com.unciv.ui 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.badlogic.gdx.utils.Align
import com.unciv.UnCivGame import com.unciv.UnCivGame
import com.unciv.logic.civilization.CivilizationInfo
import com.unciv.ui.utils.* import com.unciv.ui.utils.*
import kotlin.math.max
import kotlin.math.roundToInt import kotlin.math.roundToInt
class EmpireOverviewScreen : CameraStageBaseScreen(){ 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.addClickListener { UnCivGame.Current.setWorldScreen() }
closeButton.y = stage.height - closeButton.height - 5 closeButton.y = stage.height - closeButton.height - 5
stage.addActor(closeButton) topTable.add(closeButton)
val table=Table() val setCityInfoButton = TextButton("Cities",skin)
table.defaults().pad(20f) val setCities = {
centerTable.clear()
centerTable.add(getCityInfoTable())
centerTable.pack()
centerTable.center(stage)
}
setCities()
setCityInfoButton.addClickListener(setCities)
topTable.add(setCityInfoButton)
table.add(getCityInfoTable(civInfo)) val setStatsInfoButton = TextButton("Stats",skin)
table.add(getHappinessTable(civInfo)) setStatsInfoButton.addClickListener {
table.add(getGoldTable(civInfo)) centerTable.clear()
table.center(stage) centerTable.add(getHappinessTable())
stage.addActor(table) 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) val happinessTable = Table(skin)
happinessTable.defaults().pad(5f) happinessTable.defaults().pad(5f)
happinessTable.add(Label("Happiness", skin).setFont(24)).colspan(2).row() happinessTable.add(Label("Happiness", skin).setFont(24)).colspan(2).row()
@ -40,7 +102,7 @@ class EmpireOverviewScreen : CameraStageBaseScreen(){
return happinessTable return happinessTable
} }
private fun getGoldTable(civInfo: CivilizationInfo): Table { private fun getGoldTable(): Table {
val goldTable = Table(skin) val goldTable = Table(skin)
goldTable.defaults().pad(5f) goldTable.defaults().pad(5f)
goldTable.add(Label("Gold", skin).setFont(24)).colspan(2).row() goldTable.add(Label("Gold", skin).setFont(24)).colspan(2).row()
@ -57,7 +119,7 @@ class EmpireOverviewScreen : CameraStageBaseScreen(){
return goldTable 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 iconSize = 20f//if you set this too low, there is a chance that the tables will be misaligned
val padding = 5f 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.badlogic.gdx.scenes.scene2d.ui.TextButton
import com.unciv.UnCivGame import com.unciv.UnCivGame
import com.unciv.logic.civilization.CivilizationInfo import com.unciv.logic.civilization.CivilizationInfo
import com.unciv.models.Counter
import com.unciv.models.gamebasics.tile.ResourceType import com.unciv.models.gamebasics.tile.ResourceType
import com.unciv.ui.utils.* import com.unciv.ui.utils.*
import kotlin.math.min import kotlin.math.min
@ -20,7 +19,10 @@ enum class TradeType{
City 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 { fun getText(): String {
var text = "{$name}" var text = "{$name}"
if(duration>0) text += " ($duration {turns})" 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 theirOffers = TradeOffersList()
val ourOffers = TradeOffersList() val ourOffers = TradeOffersList()
} }
@ -66,6 +86,13 @@ class TradeScreen(val otherCivilization: CivilizationInfo) : CameraStageBaseScre
} }
else tradeText.setText("I think not.") 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) lowerTable.add(offerButton)
@ -81,34 +108,34 @@ class TradeScreen(val otherCivilization: CivilizationInfo) : CameraStageBaseScre
fun update(){ fun update(){
table.clear() table.clear()
val ourAvailableOffersTable = ScrollPane(getTableOfOffers(ourAvailableOffers, currentTrade.ourOffers)) val ourAvailableOffersTable = getTableOfOffers(ourAvailableOffers, currentTrade.ourOffers)
val ourOffersTable = ScrollPane(getTableOfOffers(currentTrade.ourOffers, ourAvailableOffers)) val ourOffersTable = getTableOfOffers(currentTrade.ourOffers, ourAvailableOffers)
val theirOffersTable = ScrollPane(getTableOfOffers(currentTrade.theirOffers, theirAvailableOffers)) val theirOffersTable = getTableOfOffers(currentTrade.theirOffers, theirAvailableOffers)
val theirAvailableOffersTable = ScrollPane(getTableOfOffers(theirAvailableOffers, currentTrade.theirOffers)) val theirAvailableOffersTable = getTableOfOffers(theirAvailableOffers, currentTrade.theirOffers)
table.add("Our items") table.add("Our items")
table.add("Our trade offer") table.add("Our trade offer")
table.add(otherCivilization.civName+"'s trade offer") table.add(otherCivilization.civName+"'s trade offer")
table.add(otherCivilization.civName+"'s items").row() table.add(otherCivilization.civName+"'s items").row()
table.add(ourAvailableOffersTable).width(stage.width/4) table.add(ourAvailableOffersTable).size(stage.width/4,stage.width/2)
table.add(ourOffersTable).width(stage.width/4) table.add(ourOffersTable).size(stage.width/4,stage.width/2)
table.add(theirOffersTable).width(stage.width/4) table.add(theirOffersTable).size(stage.width/4,stage.width/2)
table.add(theirAvailableOffersTable).width(stage.width/4) table.add(theirAvailableOffersTable).size(stage.width/4,stage.width/2)
table.pack() table.pack()
table.center(stage) 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) } val table= Table(skin).apply { defaults().pad(5f) }
for(offer in offers) { for(offer in offers) {
val tb = TextButton(offer.key.name+" ("+offer.value+")",skin) val tb = TextButton(offer.name+" ("+offer.amount+")",skin)
val amountPerClick = val amountPerClick =
if(offer.key.type==TradeType.Gold) 50 if(offer.type==TradeType.Gold) 50
else 1 else 1
if(offer.value>0) if(offer.amount>0)
tb.addClickListener { tb.addClickListener {
val amountTransfered = min(amountPerClick, offer.value) val amountTransferred = min(amountPerClick, offer.amount)
offers.add(offer.key,-amountTransfered) offers += offer.copy(amount = -amountTransferred)
correspondingOffers.add(offer.key,amountTransfered) correspondingOffers += offer.copy(amount = amountTransferred)
offerButton.setText("Offer trade") offerButton.setText("Offer trade")
tradeText.setText("What do you have in mind?") tradeText.setText("What do you have in mind?")
update() update()
@ -116,7 +143,7 @@ class TradeScreen(val otherCivilization: CivilizationInfo) : CameraStageBaseScre
else tb.disable() // for instance we have negative gold else tb.disable() // for instance we have negative gold
table.add(tb).row() table.add(tb).row()
} }
return table return ScrollPane(table)
} }
fun getAvailableOffers(civInfo: CivilizationInfo): TradeOffersList { 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 }) { for(entry in civInfo.getCivResources().filterNot { it.key.resourceType == ResourceType.Bonus }) {
val resourceTradeType = if(entry.key.resourceType==ResourceType.Luxury) TradeType.Luxury_Resource val resourceTradeType = if(entry.key.resourceType==ResourceType.Luxury) TradeType.Luxury_Resource
else TradeType.Strategic_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 return offers
} }
fun isTradeAcceptable(trade:Trade): Boolean { fun isTradeAcceptable(trade:Trade): Boolean {
val sumOfTheirOffers = trade.theirOffers.map { evaluateOffer(it.key,false)*it.value }.sum() val sumOfTheirOffers = trade.theirOffers.map { evaluateOffer(it,false) }.sum()
val sumOfOurOffers = trade.ourOffers.map { evaluateOffer(it.key,true)*it.value }.sum() val sumOfOurOffers = trade.ourOffers.map { evaluateOffer(it,true)}.sum()
return sumOfOurOffers >= sumOfTheirOffers return sumOfOurOffers >= sumOfTheirOffers
} }
fun evaluateOffer(offer:TradeOffer, otherCivIsRecieving:Boolean): Int { fun evaluateOffer(offer:TradeOffer, otherCivIsRecieving:Boolean): Int {
if(offer.type==TradeType.Gold) return 1 if(offer.type==TradeType.Gold) return 1
if(offer.type == TradeType.Luxury_Resource){ 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 var value = 100*offer.amount
return 250 if(!theirAvailableOffers.any { it.name==offer.name }) // We want to take away their last luxury or give them one they don't have
if(!otherCivIsRecieving && !ourAvailableOffers.containsKey(offer)) return 250 // they're giving us a luxury we don't have yet value += 250
return 100 // this is useful only as a barter trade to other civs 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){ if(offer.type == TradeType.Strategic_Resource){
return 50 return 50 * offer.amount
} }
return 1000 // Dunno what this is? return 1000 // Dunno what this is?
} }

View File

@ -1,6 +1,7 @@
package com.unciv.ui.worldscreen package com.unciv.ui.worldscreen
import com.badlogic.gdx.Gdx import com.badlogic.gdx.Gdx
import com.badlogic.gdx.graphics.Color
import com.badlogic.gdx.math.Vector2 import com.badlogic.gdx.math.Vector2
import com.badlogic.gdx.scenes.scene2d.ui.Table import com.badlogic.gdx.scenes.scene2d.ui.Table
import com.badlogic.gdx.scenes.scene2d.ui.TextButton import com.badlogic.gdx.scenes.scene2d.ui.TextButton
@ -27,7 +28,7 @@ class WorldScreen : CameraStageBaseScreen() {
val bottomBar = WorldScreenBottomBar(this) val bottomBar = WorldScreenBottomBar(this)
val unitActionsTable = UnitActionsTable(this) val unitActionsTable = UnitActionsTable(this)
private val techButton = TextButton("", CameraStageBaseScreen.skin) private val techButton = TextButton("", CameraStageBaseScreen.skin).apply { color= Color.BLUE }
val tradeButtons = Table() val tradeButtons = Table()
private val nextTurnButton = createNextTurnButton() private val nextTurnButton = createNextTurnButton()
@ -59,14 +60,8 @@ class WorldScreen : CameraStageBaseScreen() {
tradeButtons.defaults().pad(5f) 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) stage.addActor(tradeButtons)
tradeButtons.isVisible=false // tradeButtons.isVisible=false
bottomBar.width = stage.width bottomBar.width = stage.width
stage.addActor(bottomBar) stage.addActor(bottomBar)
@ -86,6 +81,8 @@ class WorldScreen : CameraStageBaseScreen() {
} }
updateTechButton() updateTechButton()
updateTradeButtons()
bottomBar.update(tileMapHolder.selectedTile) // has to come before tilemapholder update because the tilemapholder actions depend on the selected unit! bottomBar.update(tileMapHolder.selectedTile) // has to come before tilemapholder update because the tilemapholder actions depend on the selected unit!
minimap.update() minimap.update()
minimap.y = bottomBar.height minimap.y = bottomBar.height
@ -104,6 +101,19 @@ class WorldScreen : CameraStageBaseScreen() {
else if(civInfo.greatPeople.freeGreatPeople>0) game.screen = GreatPersonPickerScreen() 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() { private fun updateTechButton() {
techButton.isVisible = civInfo.cities.isNotEmpty() techButton.isVisible = civInfo.cities.isNotEmpty()
@ -115,8 +125,6 @@ class WorldScreen : CameraStageBaseScreen() {
techButton.setSize(techButton.prefWidth, techButton.prefHeight) techButton.setSize(techButton.prefWidth, techButton.prefHeight)
techButton.setPosition(10f, topBar.y - techButton.height - 5f) techButton.setPosition(10f, topBar.y - techButton.height - 5f)
tradeButtons.y = techButton.y - tradeButtons.height
} }
private fun createNextTurnButton(): TextButton { private fun createNextTurnButton(): TextButton {