From 7d3a10b6abda489418e000e832a1c9ae81637d0d Mon Sep 17 00:00:00 2001 From: Yair Morgenstern Date: Thu, 16 Apr 2020 13:01:45 +0300 Subject: [PATCH] All constructions are now in the queue - no more separate "current construction" and "construction queue" - #2428 That went pretty simply, compared to the magnitude of the change --- core/src/com/unciv/logic/GameInfo.kt | 47 ++++++---- .../com/unciv/logic/automation/Automation.kt | 6 +- .../automation/ConstructionAutomation.kt | 2 +- .../logic/automation/NextTurnAutomation.kt | 5 +- .../com/unciv/logic/city/CityConstructions.kt | 94 +++++++++---------- core/src/com/unciv/logic/city/CityInfo.kt | 4 +- core/src/com/unciv/logic/city/CityStats.kt | 4 +- .../unciv/logic/civilization/TechManager.kt | 9 +- .../com/unciv/ui/cityscreen/CityStatsTable.kt | 2 +- .../unciv/ui/cityscreen/ConstructionsTable.kt | 21 +++-- .../src/com/unciv/ui/tilegroups/CityButton.kt | 2 +- .../com/unciv/ui/worldscreen/WorldScreen.kt | 4 +- 12 files changed, 102 insertions(+), 98 deletions(-) diff --git a/core/src/com/unciv/logic/GameInfo.kt b/core/src/com/unciv/logic/GameInfo.kt index 0e5f1df222..ec328613e2 100644 --- a/core/src/com/unciv/logic/GameInfo.kt +++ b/core/src/com/unciv/logic/GameInfo.kt @@ -233,10 +233,10 @@ class GameInfo { // Renames as of version 3.1.8, because of translation conflicts with the property "Range" and the difficulty "Immortal" // Needs to be BEFORE tileMap.setTransients, because the units' setTransients is called from there - for(tile in tileMap.values) - for(unit in tile.getUnits()){ - if(unit.name=="Immortal") unit.name="Persian Immortal" - if(unit.promotions.promotions.contains("Range")){ + for (tile in tileMap.values) + for (unit in tile.getUnits()) { + if (unit.name == "Immortal") unit.name = "Persian Immortal" + if (unit.promotions.promotions.contains("Range")) { unit.promotions.promotions.remove("Range") unit.promotions.promotions.add("Extended Range") } @@ -244,8 +244,8 @@ class GameInfo { tileMap.setTransients(ruleSet) - if(currentPlayer=="") currentPlayer=civilizations.first { it.isPlayerCivilization() }.civName - currentPlayerCiv=getCivilization(currentPlayer) + if (currentPlayer == "") currentPlayer = civilizations.first { it.isPlayerCivilization() }.civName + currentPlayerCiv = getCivilization(currentPlayer) // this is separated into 2 loops because when we activate updateVisibleTiles in civ.setTransients, // we try to find new civs, and we check if civ is barbarian, which we can't know unless the gameInfo is already set. @@ -259,7 +259,7 @@ class GameInfo { // which can fail if there's an "unregistered" building anywhere for (civInfo in civilizations) { // As of 3.3.7, Facism -> Fascism - if(civInfo.policies.adoptedPolicies.contains("Facism")){ + if (civInfo.policies.adoptedPolicies.contains("Facism")) { civInfo.policies.adoptedPolicies.remove("Facism") civInfo.policies.adoptedPolicies.add("Fascism") } @@ -267,7 +267,7 @@ class GameInfo { // This doesn't HAVE to go here, but why not. // As of version 3.1.3, trade offers of "Declare war on X" and "Introduction to X" were changed to X, // with the extra text being added only on UI display (solved a couple of problems). - for(trade in civInfo.tradeRequests.map { it.trade }) { + for (trade in civInfo.tradeRequests.map { it.trade }) { for (offer in trade.theirOffers.union(trade.ourOffers)) { offer.name = offer.name.removePrefix("Declare war on ") offer.name = offer.name.removePrefix("Introduction to ") @@ -276,15 +276,15 @@ class GameInfo { // As of 3.4.9 cities are referenced by id, not by name // So try to update every tradeRequest (if there are no conflicting names) - for(tradeRequest in civInfo.tradeRequests) { + for (tradeRequest in civInfo.tradeRequests) { val trade = tradeRequest.trade val toRemove = ArrayList() for (offer in trade.ourOffers) { if (offer.type == TradeType.City) { - val countNames = civInfo.cities.count { it.name == offer.name} + val countNames = civInfo.cities.count { it.name == offer.name } if (countNames == 1) - offer.name = civInfo.cities.first { it.name == offer.name}.id + offer.name = civInfo.cities.first { it.name == offer.name }.id // There are conflicting names: we can't guess what city was being offered else if (countNames > 1) toRemove.add(offer) @@ -297,10 +297,10 @@ class GameInfo { val themCivInfo = getCivilization(tradeRequest.requestingCiv) for (offer in trade.theirOffers) { if (offer.type == TradeType.City) { - val countNames = themCivInfo.cities.count { it.name == offer.name} + val countNames = themCivInfo.cities.count { it.name == offer.name } if (countNames == 1) - offer.name = themCivInfo.cities.first { it.name == offer.name}.id + offer.name = themCivInfo.cities.first { it.name == offer.name }.id // There are conflicting names: we can't guess what city was being offered else if (countNames > 1) toRemove.add(offer) @@ -329,8 +329,8 @@ class GameInfo { for (civInfo in civilizations) civInfo.setTransients() for (civInfo in civilizations) civInfo.updateSightAndResources() - for (civInfo in civilizations){ - for(unit in civInfo.getCivUnits()) + for (civInfo in civilizations) { + for (unit in civInfo.getCivUnits()) unit.updateVisibleTiles() // this needs to be done after all the units are assigned to their civs and all other transients are set // Since this depends on the cities of ALL civilizations, @@ -339,9 +339,19 @@ class GameInfo { civInfo.initialSetCitiesConnectedToCapitalTransients() // We need to determine the GLOBAL happiness state in order to determine the city stats - for(cityInfo in civInfo.cities) cityInfo.cityStats.updateCityHappiness() + for (cityInfo in civInfo.cities) cityInfo.cityStats.updateCityHappiness() - for (cityInfo in civInfo.cities) cityInfo.cityStats.update() + for (cityInfo in civInfo.cities) { + if(cityInfo.cityConstructions.currentConstruction!="") { // move it to the top of the queue + val constructionQueue = cityInfo.cityConstructions.constructionQueue + val itemsInQueue = constructionQueue.toList() + constructionQueue.clear() + constructionQueue.add(cityInfo.cityConstructions.currentConstruction) + constructionQueue.addAll(itemsInQueue) + cityInfo.cityConstructions.currentConstruction = "" + } + cityInfo.cityStats.update() + } } } @@ -350,8 +360,7 @@ class GameInfo { cityConstructions.builtBuildings.remove(oldBuildingName) cityConstructions.builtBuildings.add(newBuildingName) } - if (cityConstructions.currentConstruction == oldBuildingName) - cityConstructions.currentConstruction = newBuildingName + cityConstructions.constructionQueue.replaceAll { if(it==oldBuildingName) newBuildingName else it } if (cityConstructions.inProgressConstructions.containsKey(oldBuildingName)) { cityConstructions.inProgressConstructions[newBuildingName] = cityConstructions.inProgressConstructions[oldBuildingName]!! cityConstructions.inProgressConstructions.remove(oldBuildingName) diff --git a/core/src/com/unciv/logic/automation/Automation.kt b/core/src/com/unciv/logic/automation/Automation.kt index 331000aa1e..724f67b9cc 100644 --- a/core/src/com/unciv/logic/automation/Automation.kt +++ b/core/src/com/unciv/logic/automation/Automation.kt @@ -55,13 +55,13 @@ object Automation { fun trainMilitaryUnit(city: CityInfo) { val name = chooseMilitaryUnit(city) - city.cityConstructions.currentConstruction = name + city.cityConstructions.currentConstructionFromQueue = name } fun chooseMilitaryUnit(city: CityInfo) : String { var militaryUnits = city.cityConstructions.getConstructableUnits().filter { !it.unitType.isCivilian() } - if (militaryUnits.map { it.name }.contains(city.cityConstructions.currentConstruction)) - return city.cityConstructions.currentConstruction + if (militaryUnits.map { it.name }.contains(city.cityConstructions.currentConstructionFromQueue)) + return city.cityConstructions.currentConstructionFromQueue val findWaterConnectedCitiesAndEnemies = BFS(city.getCenterTile()){it.isWater || it.isCityCenter()} findWaterConnectedCitiesAndEnemies.stepToEnd() diff --git a/core/src/com/unciv/logic/automation/ConstructionAutomation.kt b/core/src/com/unciv/logic/automation/ConstructionAutomation.kt index c2f10a8afd..fa1eff9c9d 100644 --- a/core/src/com/unciv/logic/automation/ConstructionAutomation.kt +++ b/core/src/com/unciv/logic/automation/ConstructionAutomation.kt @@ -89,7 +89,7 @@ class ConstructionAutomation(val cityConstructions: CityConstructions){ else theChosenOne = relativeCostEffectiveness.minBy { it.remainingWork }!!.choice civInfo.addNotification("Work has started on [$theChosenOne]", Color.BROWN, CityAction(cityInfo.location)) - cityConstructions.currentConstruction = theChosenOne + cityConstructions.currentConstructionFromQueue = theChosenOne } private fun addMilitaryUnitChoice() { diff --git a/core/src/com/unciv/logic/automation/NextTurnAutomation.kt b/core/src/com/unciv/logic/automation/NextTurnAutomation.kt index 504b6b86d2..f4f7aeab53 100644 --- a/core/src/com/unciv/logic/automation/NextTurnAutomation.kt +++ b/core/src/com/unciv/logic/automation/NextTurnAutomation.kt @@ -10,7 +10,6 @@ import com.unciv.logic.civilization.diplomacy.DiplomaticStatus import com.unciv.logic.civilization.diplomacy.RelationshipLevel import com.unciv.logic.map.MapUnit import com.unciv.logic.trade.* -import com.unciv.models.metadata.GameSpeed import com.unciv.models.ruleset.VictoryType import com.unciv.models.ruleset.tech.Technology import com.unciv.models.translations.tr @@ -459,11 +458,11 @@ object NextTurnAutomation{ if (civInfo.cities.any() && civInfo.getHappiness() > civInfo.cities.size + 5 && civInfo.getCivUnits().none { it.name == Constants.settler } - && civInfo.cities.none { it.cityConstructions.currentConstruction == Constants.settler }) { + && civInfo.cities.none { it.cityConstructions.currentConstructionFromQueue == Constants.settler }) { val bestCity = civInfo.cities.maxBy { it.cityStats.currentCityStats.production }!! if (bestCity.cityConstructions.builtBuildings.size > 1) // 2 buildings or more, otherwise focus on self first - bestCity.cityConstructions.currentConstruction = Constants.settler + bestCity.cityConstructions.currentConstructionFromQueue = Constants.settler } } diff --git a/core/src/com/unciv/logic/city/CityConstructions.kt b/core/src/com/unciv/logic/city/CityConstructions.kt index 2f1bd45188..ace2cdbf98 100644 --- a/core/src/com/unciv/logic/city/CityConstructions.kt +++ b/core/src/com/unciv/logic/city/CityConstructions.kt @@ -19,8 +19,8 @@ import kotlin.math.roundToInt * City constructions manager. * * @property cityInfo the city it refers to - * @property currentConstruction the name of the construction is currently worked, default = "Monument" - * @property currentConstructionIsUserSet a flag indicating if the [currentConstruction] has been set by the user or by the AI + * @property currentConstructionFromQueue the name of the construction is currently worked, default = "Monument" + * @property currentConstructionIsUserSet a flag indicating if the [currentConstructionFromQueue] has been set by the user or by the AI * @property constructionQueue a list of constructions names enqueued */ class CityConstructions { @@ -29,7 +29,13 @@ class CityConstructions { var builtBuildings = HashSet() val inProgressConstructions = HashMap() - var currentConstruction: String = "Monument" + @Deprecated("As of 3.7.5, all constructions are in the queue") + var currentConstruction="" + var currentConstructionFromQueue: String + get() { + if(constructionQueue.isEmpty()) return "" else return constructionQueue.first() + } + set(value) { if(constructionQueue.isEmpty()) constructionQueue.add(value) else constructionQueue[0]=value } var currentConstructionIsUserSet = false var constructionQueue = mutableListOf() val queueMaxSize = 10 @@ -39,7 +45,6 @@ class CityConstructions { val toReturn = CityConstructions() toReturn.builtBuildings.addAll(builtBuildings) toReturn.inProgressConstructions.putAll(inProgressConstructions) - toReturn.currentConstruction=currentConstruction toReturn.currentConstructionIsUserSet=currentConstructionIsUserSet toReturn.constructionQueue.addAll(constructionQueue) return toReturn @@ -89,13 +94,13 @@ class CityConstructions { } fun getCityProductionTextForCityButton(): String { - val currentConstructionSnapshot = currentConstruction // See below + val currentConstructionSnapshot = currentConstructionFromQueue // See below var result = currentConstructionSnapshot.tr() if (currentConstructionSnapshot != "") { val construction = PerpetualConstruction.perpetualConstructionsMap[currentConstructionSnapshot] if (construction == null) { val turnsLeft = turnsToConstruction(currentConstructionSnapshot) - result += ("\r\n" + "Cost".tr() + " " + getConstruction(currentConstruction).getProductionCost(cityInfo.civInfo).toString()).tr() + result += ("\r\n" + "Cost".tr() + " " + getConstruction(currentConstructionFromQueue).getProductionCost(cityInfo.civInfo).toString()).tr() result += ConstructionInfoTable.turnOrTurns(turnsLeft) } else { result += construction.getProductionTooltip(cityInfo) @@ -107,7 +112,7 @@ class CityConstructions { fun getProductionForTileInfo(): String { /* this is because there were rare errors tht I assume were caused because currentContruction changed on another thread */ - val currentConstructionSnapshot = currentConstruction + val currentConstructionSnapshot = currentConstructionFromQueue var result = currentConstructionSnapshot.tr() if (currentConstructionSnapshot!="" && !PerpetualConstruction.perpetualConstructionsMap.containsKey(currentConstructionSnapshot)) { @@ -117,16 +122,14 @@ class CityConstructions { return result } - fun getCurrentConstruction(): IConstruction = getConstruction(currentConstruction) - fun getIConstructionQueue(): List = constructionQueue.map{ getConstruction(it) } + fun getCurrentConstruction(): IConstruction = getConstruction(currentConstructionFromQueue) fun isBuilt(buildingName: String): Boolean = builtBuildings.contains(buildingName) - fun isBeingConstructed(constructionName: String): Boolean = currentConstruction == constructionName + fun isBeingConstructed(constructionName: String): Boolean = currentConstructionFromQueue == constructionName fun isEnqueued(constructionName: String): Boolean = constructionQueue.contains(constructionName) fun isBeingConstructedOrEnqueued(constructionName: String): Boolean = isBeingConstructed(constructionName) || isEnqueued(constructionName) fun isQueueFull(): Boolean = constructionQueue.size == queueMaxSize - fun isQueueEmpty(): Boolean = constructionQueue.isEmpty() fun isBuildingWonder(): Boolean { val currentConstruction = getCurrentConstruction() @@ -135,13 +138,8 @@ class CityConstructions { /** If the city is constructing multiple units of the same type, subsequent units will require the full cost */ fun isFirstConstructionOfItsKind(constructionQueueIndex: Int, name: String): Boolean { - // idx = 1 is the currentConstruction, so it is the first - if (constructionQueueIndex == -1) - return true - // if the construction name is the same as the current construction, it isn't the first - return !isBeingConstructed(name) && - constructionQueueIndex == constructionQueue.indexOfFirst{it == name} + return constructionQueueIndex == constructionQueue.indexOfFirst { it == name } } @@ -150,10 +148,10 @@ class CityConstructions { when { gameBasics.buildings.containsKey(constructionName) -> return gameBasics.buildings[constructionName]!! gameBasics.units.containsKey(constructionName) -> return gameBasics.units[constructionName]!! - constructionName=="" -> return getConstruction("Nothing") + constructionName == "" -> return getConstruction("Nothing") else -> { val special = PerpetualConstruction.perpetualConstructionsMap[constructionName] - if(special!=null) return special + if (special != null) return special } } @@ -185,19 +183,23 @@ class CityConstructions { if(workLeft < 0) // we've done more work than actually necessary - possible if circumstances cause buildings to be cheaper later return 1 // we'll finish this next turn - val currConstruction = currentConstruction - val cityStatsForConstruction: Stats - if (currentConstruction == constructionName) cityStatsForConstruction = cityInfo.cityStats.currentCityStats + if (currentConstructionFromQueue == constructionName) cityStatsForConstruction = cityInfo.cityStats.currentCityStats else { // The ol' Switcharoo - what would our stats be if that was our current construction? // Since this is only ever used for UI purposes, I feel fine with having it be a bit inefficient // and recalculating the entire city stats - currentConstruction = constructionName + // We don't want to change our current construction queue - what if we have an empty queue, too many changes to check for - + // So we ust clone it and see what would happen f that was our construction + val cityConstructionsClone = clone() + cityConstructionsClone.currentConstructionFromQueue = constructionName + cityConstructionsClone.cityInfo = cityInfo + cityConstructionsClone.setTransients() + cityInfo.cityConstructions = cityConstructionsClone cityInfo.cityStats.update() cityStatsForConstruction = cityInfo.cityStats.currentCityStats // revert! - currentConstruction = currConstruction + cityInfo.cityConstructions = this cityInfo.cityStats.update() } @@ -215,19 +217,19 @@ class CityConstructions { } fun addProductionPoints(productionToAdd: Int) { - if (!inProgressConstructions.containsKey(currentConstruction)) inProgressConstructions[currentConstruction] = 0 - inProgressConstructions[currentConstruction] = inProgressConstructions[currentConstruction]!! + productionToAdd + if (!inProgressConstructions.containsKey(currentConstructionFromQueue)) inProgressConstructions[currentConstructionFromQueue] = 0 + inProgressConstructions[currentConstructionFromQueue] = inProgressConstructions[currentConstructionFromQueue]!! + productionToAdd } fun constructIfEnough(){ stopUnbuildableConstruction() - val construction = getConstruction(currentConstruction) + val construction = getConstruction(currentConstructionFromQueue) if(construction is PerpetualConstruction) chooseNextConstruction() // check every turn if we could be doing something better, because this doesn't end by itself else { val productionCost = construction.getProductionCost(cityInfo.civInfo) - if (inProgressConstructions.containsKey(currentConstruction) - && inProgressConstructions[currentConstruction]!! >= productionCost) { + if (inProgressConstructions.containsKey(currentConstructionFromQueue) + && inProgressConstructions[currentConstructionFromQueue]!! >= productionCost) { constructionComplete(construction) cancelCurrentConstruction() } @@ -238,22 +240,22 @@ class CityConstructions { stopUnbuildableConstruction() validateConstructionQueue() - if(getConstruction(currentConstruction) !is PerpetualConstruction) + if(getConstruction(currentConstructionFromQueue) !is PerpetualConstruction) addProductionPoints(cityStats.production.roundToInt()) } private fun stopUnbuildableConstruction() { // Let's try to remove the building from the city, and see if we can still build it (we need to remove because of wonders etc.) - val construction = getConstruction(currentConstruction) + val construction = getConstruction(currentConstructionFromQueue) - val saveCurrentConstruction = currentConstruction - currentConstruction = "" + val saveCurrentConstruction = currentConstructionFromQueue + currentConstructionFromQueue = "" if (!construction.isBuildable(this)) { // We can't build this building anymore! (Wonder has been built / resource is gone / etc.) cityInfo.civInfo.addNotification("[${cityInfo.name}] cannot continue work on [$saveCurrentConstruction]", cityInfo.location, Color.BROWN) cancelCurrentConstruction() } else - currentConstruction = saveCurrentConstruction + currentConstructionFromQueue = saveCurrentConstruction } private fun validateConstructionQueue() { @@ -266,7 +268,7 @@ class CityConstructions { } // remove obsolete stuff from in progress constructions - happens often and leaves clutter in memory and save files // should have NO visible consequences - any accumulated points that may be reused later should stay (nukes when manhattan project city lost, nat wonder when conquered an empty city...) - val inProgressSnapshot = inProgressConstructions.keys.filter { it != currentConstruction } + val inProgressSnapshot = inProgressConstructions.keys.filter { it != currentConstructionFromQueue } for (constructionName in inProgressSnapshot) { val rejectionReason:String = when (val construction = getConstruction(constructionName)) { @@ -317,7 +319,7 @@ class CityConstructions { return false // nothing built - no pay cityInfo.civInfo.gold -= getConstruction(constructionName).getGoldCost(cityInfo.civInfo) - if (currentConstruction == constructionName) + if (currentConstructionFromQueue == constructionName) cancelCurrentConstruction() return true @@ -351,7 +353,7 @@ class CityConstructions { private fun cancelCurrentConstruction() { currentConstructionIsUserSet = false - currentConstruction = "" + constructionQueue.removeAt(0) chooseNextConstruction() } @@ -359,12 +361,10 @@ class CityConstructions { if(currentConstructionIsUserSet) return if (constructionQueue.isNotEmpty()) { - currentConstructionIsUserSet = true - currentConstruction = constructionQueue.removeAt(0) stopUnbuildableConstruction() - if (currentConstruction != "") return + if (currentConstructionFromQueue != "") return } ConstructionAutomation(this).chooseNextConstruction() @@ -372,8 +372,8 @@ class CityConstructions { fun addToQueue(constructionName: String) { if (isQueueFull()) return - if (isQueueEmpty() && currentConstruction == "" || currentConstruction == "Nothing") { - currentConstruction = constructionName + if (currentConstructionFromQueue == "" || currentConstructionFromQueue == "Nothing") { + currentConstructionFromQueue = constructionName currentConstructionIsUserSet = true } else constructionQueue.add(constructionName) @@ -395,14 +395,8 @@ class CityConstructions { } fun raisePriority(constructionQueueIndex: Int) { - // change current construction - if(constructionQueueIndex == 0) { - // Add current construction to queue after the first element - constructionQueue.add(1, currentConstruction) - cancelCurrentConstruction() - } - else - constructionQueue.swap(constructionQueueIndex-1, constructionQueueIndex) + constructionQueue.swap(constructionQueueIndex - 1, constructionQueueIndex) + } // Lowering == Highering next element in queue diff --git a/core/src/com/unciv/logic/city/CityInfo.kt b/core/src/com/unciv/logic/city/CityInfo.kt index 8a3c144e4a..f0ba351996 100644 --- a/core/src/com/unciv/logic/city/CityInfo.kt +++ b/core/src/com/unciv/logic/city/CityInfo.kt @@ -88,7 +88,7 @@ class CityInfo { if (civInfo.cities.size == 1) { cityConstructions.addBuilding("Palace") - cityConstructions.currentConstruction = Constants.worker // Default for first city only! + cityConstructions.currentConstructionFromQueue = Constants.worker // Default for first city only! } if (civInfo.policies.isAdopted("Legalism")) @@ -213,7 +213,7 @@ class CityInfo { } fun isGrowing(): Boolean { - return foodForNextTurn() > 0 && cityConstructions.currentConstruction != Constants.settler + return foodForNextTurn() > 0 && cityConstructions.currentConstructionFromQueue != Constants.settler } fun isStarving(): Boolean = foodForNextTurn() < 0 diff --git a/core/src/com/unciv/logic/city/CityStats.kt b/core/src/com/unciv/logic/city/CityStats.kt index bda7bf05b0..26fb0be909 100644 --- a/core/src/com/unciv/logic/city/CityStats.kt +++ b/core/src/com/unciv/logic/city/CityStats.kt @@ -60,7 +60,7 @@ class CityStats { private fun getStatsFromProduction(production: Float): Stats { val stats = Stats() - when (cityInfo.cityConstructions.currentConstruction) { + when (cityInfo.cityConstructions.currentConstructionFromQueue) { "Gold" -> stats.gold += production / 4 "Science" -> { var scienceProduced = production / 4 @@ -476,7 +476,7 @@ class CityStats { newFinalStatList["Maintenance"] = Stats().apply { gold -= buildingsMaintenance.toInt() } - if (cityInfo.cityConstructions.currentConstruction == Constants.settler && totalFood > 0) { + if (cityInfo.cityConstructions.currentConstructionFromQueue == Constants.settler && totalFood > 0) { newFinalStatList["Excess food to production"] = Stats().apply { production=totalFood; food=-totalFood } } diff --git a/core/src/com/unciv/logic/civilization/TechManager.kt b/core/src/com/unciv/logic/civilization/TechManager.kt index 380cfa5978..fe6d94113f 100644 --- a/core/src/com/unciv/logic/civilization/TechManager.kt +++ b/core/src/com/unciv/logic/civilization/TechManager.kt @@ -256,11 +256,12 @@ class TechManager { } } - val obsoleteUnits = getRuleset().units.values.filter { it.obsoleteTech == techName } + val obsoleteUnits = getRuleset().units.values.filter { it.obsoleteTech == techName }.map { it.name } for (city in civInfo.cities) - if (city.cityConstructions.getCurrentConstruction() in obsoleteUnits) { - val currentConstructionUnit = city.cityConstructions.getCurrentConstruction() as BaseUnit - city.cityConstructions.currentConstruction = currentConstructionUnit.upgradesTo!! + for(constructionName in city.cityConstructions.constructionQueue.toList()){ // copy, since we're changing the queue + if(constructionName !in obsoleteUnits) continue + val constructionUnit = city.cityConstructions.getCurrentConstruction() as BaseUnit + city.cityConstructions.constructionQueue.replaceAll { if(it==constructionName) constructionUnit.upgradesTo!! else it } } if(techName=="Writing" && civInfo.nation.unique == UniqueAbility.INGENUITY diff --git a/core/src/com/unciv/ui/cityscreen/CityStatsTable.kt b/core/src/com/unciv/ui/cityscreen/CityStatsTable.kt index ee949c000a..b4da0a09d9 100644 --- a/core/src/com/unciv/ui/cityscreen/CityStatsTable.kt +++ b/core/src/com/unciv/ui/cityscreen/CityStatsTable.kt @@ -68,7 +68,7 @@ class CityStatsTable(val cityScreen: CityScreen): Table() { when { cityInfo.isGrowing() -> "[${cityInfo.getNumTurnsToNewPopulation()}] turns to new population".tr() cityInfo.isStarving() -> "[${cityInfo.getNumTurnsToStarvation()}] turns to lose population".tr() - cityInfo.cityConstructions.currentConstruction == Constants.settler -> "Food converts to production".tr() + cityInfo.cityConstructions.currentConstructionFromQueue == Constants.settler -> "Food converts to production".tr() else -> "Stopped population growth".tr() } turnsToPopString += " (" + cityInfo.population.foodStored + "/" + cityInfo.population.getFoodToNextPopulation() + ")" diff --git a/core/src/com/unciv/ui/cityscreen/ConstructionsTable.kt b/core/src/com/unciv/ui/cityscreen/ConstructionsTable.kt index 0528211a4d..3e7e7f7a59 100644 --- a/core/src/com/unciv/ui/cityscreen/ConstructionsTable.kt +++ b/core/src/com/unciv/ui/cityscreen/ConstructionsTable.kt @@ -92,7 +92,7 @@ class ConstructionsTable(val cityScreen: CityScreen) : Table(CameraStageBaseScre private fun updateConstructionQueue() { val city = cityScreen.city val cityConstructions = city.cityConstructions - val currentConstruction = cityConstructions.currentConstruction + val currentConstruction = cityConstructions.currentConstructionFromQueue val queue = cityConstructions.constructionQueue constructionsQueueTable.defaults().pad(0f) @@ -100,7 +100,7 @@ class ConstructionsTable(val cityScreen: CityScreen) : Table(CameraStageBaseScre constructionsQueueTable.addSeparator() if (currentConstruction != "") - constructionsQueueTable.add(getQueueEntry(-1, currentConstruction, queue.isEmpty(), isSelectedCurrentConstruction())) + constructionsQueueTable.add(getQueueEntry(0, currentConstruction)) .expandX().fillX().row() else constructionsQueueTable.add("Pick a construction".toLabel()).pad(2f).row() @@ -111,7 +111,8 @@ class ConstructionsTable(val cityScreen: CityScreen) : Table(CameraStageBaseScre if (queue.isNotEmpty()) { queue.forEachIndexed { i, constructionName -> - constructionsQueueTable.add(getQueueEntry(i, constructionName, i == queue.size - 1, i == selectedQueueEntry)) + if (i != 0) // This is already displayed as "Current construction" + constructionsQueueTable.add(getQueueEntry(i, constructionName)) .expandX().fillX().row() if (i != queue.size - 1) constructionsQueueTable.addSeparator() @@ -171,7 +172,7 @@ class ConstructionsTable(val cityScreen: CityScreen) : Table(CameraStageBaseScre availableConstructionsTable.addCategory("Other", specialConstructions) } - private fun getQueueEntry(constructionQueueIndex: Int, name: String, isLast: Boolean, isSelected: Boolean): Table { + private fun getQueueEntry(constructionQueueIndex: Int, name: String): Table { val city = cityScreen.city val cityConstructions = city.cityConstructions @@ -179,7 +180,7 @@ class ConstructionsTable(val cityScreen: CityScreen) : Table(CameraStageBaseScre table.align(Align.left).pad(5f) table.background = ImageGetter.getBackground(Color.BLACK) - if (isSelected) + if (constructionQueueIndex == selectedQueueEntry) table.background = ImageGetter.getBackground(Color.GREEN.cpy().lerp(Color.BLACK, 0.5f)) val isFirstConstructionOfItsKind = cityConstructions.isFirstConstructionOfItsKind(constructionQueueIndex, name) @@ -197,14 +198,15 @@ class ConstructionsTable(val cityScreen: CityScreen) : Table(CameraStageBaseScre table.add(ImageGetter.getConstructionImage(name).surroundWithCircle(40f)).padRight(10f) table.add(text.toLabel()).expandX().fillX().left() - if (constructionQueueIndex >= 0) table.add(getRaisePriorityButton(constructionQueueIndex, name, city)).right() + if (constructionQueueIndex > 0) table.add(getRaisePriorityButton(constructionQueueIndex, name, city)).right() else table.add().right() - if (!isLast) table.add(getLowerPriorityButton(constructionQueueIndex, name, city)).right() + if (constructionQueueIndex != cityConstructions.constructionQueue.lastIndex) + table.add(getLowerPriorityButton(constructionQueueIndex, name, city)).right() else table.add().right() table.touchable = Touchable.enabled table.onClick { - cityScreen.selectedConstruction = cityScreen.city.cityConstructions.getConstruction(name) + cityScreen.selectedConstruction = cityConstructions.getConstruction(name) cityScreen.selectedTile = null selectedQueueEntry = constructionQueueIndex cityScreen.update() @@ -256,7 +258,6 @@ class ConstructionsTable(val cityScreen: CityScreen) : Table(CameraStageBaseScre } private fun isSelectedQueueEntry(): Boolean = selectedQueueEntry > -2 - private fun isSelectedCurrentConstruction(): Boolean = selectedQueueEntry == -1 private fun getQueueButton(construction: IConstruction?): TextButton { val city = cityScreen.city @@ -303,7 +304,7 @@ class ConstructionsTable(val cityScreen: CityScreen) : Table(CameraStageBaseScre val cityConstructions = city.cityConstructions // We can't trust the isSelectedQueueEntry because that fails when we have the same unit as both the current construction and in the queue, // and then we purchase the unit from the queue - see #2157 - val constructionIsCurrentConstruction = construction.name==cityConstructions.currentConstruction + val constructionIsCurrentConstruction = construction.name==cityConstructions.currentConstructionFromQueue if (!cityConstructions.purchaseConstruction(construction.name)) { Popup(cityScreen).apply { diff --git a/core/src/com/unciv/ui/tilegroups/CityButton.kt b/core/src/com/unciv/ui/tilegroups/CityButton.kt index 10d546575b..ce49ca01c7 100644 --- a/core/src/com/unciv/ui/tilegroups/CityButton.kt +++ b/core/src/com/unciv/ui/tilegroups/CityButton.kt @@ -320,7 +320,7 @@ class CityButton(val city: CityInfo, private val tileGroup: WorldTileGroup, skin val circle = ImageGetter.getCircle() circle.setSize(25f,25f) - val image = ImageGetter.getConstructionImage(cityConstructions.currentConstruction) + val image = ImageGetter.getConstructionImage(cityConstructions.currentConstructionFromQueue) image.setSize(18f,18f) image.centerY(group) image.x = group.width-image.width diff --git a/core/src/com/unciv/ui/worldscreen/WorldScreen.kt b/core/src/com/unciv/ui/worldscreen/WorldScreen.kt index 6e69764560..83712a239c 100644 --- a/core/src/com/unciv/ui/worldscreen/WorldScreen.kt +++ b/core/src/com/unciv/ui/worldscreen/WorldScreen.kt @@ -527,10 +527,10 @@ class WorldScreen(val viewingCiv:CivilizationInfo) : CameraStageBaseScreen() { } } - viewingCiv.cities.any { it.cityConstructions.currentConstruction == "" } -> + viewingCiv.cities.any { it.cityConstructions.currentConstructionFromQueue == "" } -> NextTurnAction("Pick construction", Color.CORAL) { val cityWithNoProductionSet = viewingCiv.cities - .firstOrNull { it.cityConstructions.currentConstruction == "" } + .firstOrNull { it.cityConstructions.currentConstructionFromQueue == "" } if (cityWithNoProductionSet != null) game.setScreen(CityScreen(cityWithNoProductionSet)) }