From 00983dd00e6fe956310dfec961aed5e63db1f654 Mon Sep 17 00:00:00 2001 From: Alexander Korolyov <49795502+alkorolyov@users.noreply.github.com> Date: Sun, 19 Jul 2020 12:35:38 +0200 Subject: [PATCH] Spectators can enter and view other player cities (#2856) * Spectators can enter and view other player cities * Spectators not shown on diplomacy screen * master merge fix * Spectators can enter and view other player cities * Spectators not shown on diplomacy screen * Fix barbarians spawn in spectator mode * small post fixes * remove excessive spectator check * Remove spectators from diplomacy screen * Spectators cannot reallocate specialists in cities * Refactor using canChangeState value for CityScreen and WorldScreen. * Continue refactor using canChangeState value --- core/src/com/unciv/logic/GameInfo.kt | 2 +- core/src/com/unciv/ui/cityscreen/CityScreen.kt | 10 +++++++--- .../com/unciv/ui/cityscreen/CityScreenTileTable.kt | 7 +++++-- .../com/unciv/ui/cityscreen/ConstructionsTable.kt | 13 +++++++------ .../ui/cityscreen/SpecialistAllocationTable.kt | 4 ++-- .../unciv/ui/overviewscreen/EmpireOverviewScreen.kt | 6 +++--- core/src/com/unciv/ui/tilegroups/CityButton.kt | 9 +++++---- core/src/com/unciv/ui/trade/DiplomacyScreen.kt | 2 +- core/src/com/unciv/ui/worldscreen/WorldScreen.kt | 1 + 9 files changed, 32 insertions(+), 22 deletions(-) diff --git a/core/src/com/unciv/logic/GameInfo.kt b/core/src/com/unciv/logic/GameInfo.kt index 329a7210d8..90a91f4f88 100644 --- a/core/src/com/unciv/logic/GameInfo.kt +++ b/core/src/com/unciv/logic/GameInfo.kt @@ -182,7 +182,7 @@ class GameInfo { fun placeBarbarianEncampment(existingEncampments: List): TileInfo? { // Barbarians will only spawn in places that no one can see - val allViewableTiles = civilizations.filterNot { it.isBarbarian() } + val allViewableTiles = civilizations.filterNot { it.isBarbarian() || it.isSpectator() } .flatMap { it.viewableTiles }.toHashSet() val tilesWithin3ofExistingEncampment = existingEncampments.asSequence() .flatMap { it.getTilesInDistance(3) }.toSet() diff --git a/core/src/com/unciv/ui/cityscreen/CityScreen.kt b/core/src/com/unciv/ui/cityscreen/CityScreen.kt index c17056c8f8..eac02f1a65 100644 --- a/core/src/com/unciv/ui/cityscreen/CityScreen.kt +++ b/core/src/com/unciv/ui/cityscreen/CityScreen.kt @@ -22,6 +22,9 @@ class CityScreen(internal val city: CityInfo): CameraStageBaseScreen() { var selectedConstruction: IConstruction? = null var keyListener: InputListener? = null + /** Toggles or adds/removes all state changing buttons */ + val canChangeState = UncivGame.Current.worldScreen.canChangeState + /** Toggle between Constructions and cityInfo (buildings, specialists etc. */ var showConstructionsTable = true @@ -134,12 +137,13 @@ class CityScreen(internal val city: CityInfo): CameraStageBaseScreen() { city.annexCity() update() } + if (!canChangeState) annexCityButton.disable() razeCityButtonHolder.add(annexCityButton).colspan(cityPickerTable.columns) } else if(!city.isBeingRazed) { val razeCityButton = "Raze city".toTextButton() razeCityButton.labelCell.pad(10f) razeCityButton.onClick { city.isBeingRazed=true; update() } - if(!UncivGame.Current.worldScreen.isPlayersTurn || city.isOriginalCapital) + if(!canChangeState || city.isOriginalCapital) razeCityButton.disable() razeCityButtonHolder.add(razeCityButton).colspan(cityPickerTable.columns) @@ -147,7 +151,7 @@ class CityScreen(internal val city: CityInfo): CameraStageBaseScreen() { val stopRazingCityButton = "Stop razing city".toTextButton() stopRazingCityButton.labelCell.pad(10f) stopRazingCityButton.onClick { city.isBeingRazed=false; update() } - if(!UncivGame.Current.worldScreen.isPlayersTurn) stopRazingCityButton.disable() + if(!canChangeState) stopRazingCityButton.disable() razeCityButtonHolder.add(stopRazingCityButton).colspan(cityPickerTable.columns) } razeCityButtonHolder.pack() @@ -173,7 +177,7 @@ class CityScreen(internal val city: CityInfo): CameraStageBaseScreen() { selectedTile = tileInfo selectedConstruction = null - if (tileGroup.isWorkable && UncivGame.Current.worldScreen.isPlayersTurn) { + if (tileGroup.isWorkable && canChangeState) { if (!tileInfo.isWorked() && city.population.getFreePopulation() > 0) { city.workedTiles.add(tileInfo.position) game.settings.addCompletedTutorialTask("Reassign worked tiles") diff --git a/core/src/com/unciv/ui/cityscreen/CityScreenTileTable.kt b/core/src/com/unciv/ui/cityscreen/CityScreenTileTable.kt index e841fdb8f9..4da3f9de1e 100644 --- a/core/src/com/unciv/ui/cityscreen/CityScreenTileTable.kt +++ b/core/src/com/unciv/ui/cityscreen/CityScreenTileTable.kt @@ -34,7 +34,6 @@ class CityScreenTileTable(val cityScreen: CityScreen): Table(){ innerTable.row() innerTable.add(getTileStatsTable(stats)).row() - if(selectedTile.getOwner()==null && selectedTile.neighbors.any {it.getCity()==city} && selectedTile in city.tilesInRange){ val goldCostOfTile = city.expansion.getGoldCostOfTile(selectedTile) @@ -44,7 +43,9 @@ class CityScreenTileTable(val cityScreen: CityScreen): Table(){ city.expansion.buyTile(selectedTile) UncivGame.Current.setScreen(CityScreen(city)) } - if(goldCostOfTile>city.civInfo.gold || city.isPuppet || !UncivGame.Current.worldScreen.isPlayersTurn) + if(goldCostOfTile>city.civInfo.gold + || city.isPuppet + || !cityScreen.canChangeState) buyTileButton.disable() innerTable.add(buyTileButton).row() @@ -64,6 +65,7 @@ class CityScreenTileTable(val cityScreen: CityScreen): Table(){ update(selectedTile) cityScreen.update() } + if (!cityScreen.canChangeState) unlockButton.disable() innerTable.add(unlockButton).row() } else { @@ -73,6 +75,7 @@ class CityScreenTileTable(val cityScreen: CityScreen): Table(){ update(selectedTile) cityScreen.update() } + if (!cityScreen.canChangeState) lockButton.disable() innerTable.add(lockButton).row() } } diff --git a/core/src/com/unciv/ui/cityscreen/ConstructionsTable.kt b/core/src/com/unciv/ui/cityscreen/ConstructionsTable.kt index 5a51bc0f90..cdf4ae7144 100644 --- a/core/src/com/unciv/ui/cityscreen/ConstructionsTable.kt +++ b/core/src/com/unciv/ui/cityscreen/ConstructionsTable.kt @@ -270,7 +270,8 @@ class ConstructionsTable(val cityScreen: CityScreen) : Table(CameraStageBaseScre if (isSelectedQueueEntry()) { button = "Remove from queue".toTextButton() - if (!UncivGame.Current.worldScreen.isPlayersTurn || city.isPuppet) button.disable() + if (!cityScreen.canChangeState || city.isPuppet) + button.disable() else { button.onClick { cityConstructions.removeFromQueue(selectedQueueEntry,false) @@ -284,7 +285,7 @@ class ConstructionsTable(val cityScreen: CityScreen) : Table(CameraStageBaseScre if (construction == null || cityConstructions.isQueueFull() || !cityConstructions.getConstruction(construction.name).isBuildable(cityConstructions) - || !UncivGame.Current.worldScreen.isPlayersTurn + || !cityScreen.canChangeState || construction is PerpetualConstruction && cityConstructions.isBeingConstructedOrEnqueued(construction.name) || city.isPuppet) { button.disable() @@ -347,7 +348,7 @@ class ConstructionsTable(val cityScreen: CityScreen) : Table(CameraStageBaseScre } if ( !construction.isBuildable(cityConstructions) - || !UncivGame.Current.worldScreen.isPlayersTurn + || !cityScreen.canChangeState || city.isPuppet || city.isInResistance() || !city.canPurchase(construction) || constructionGoldCost > city.civInfo.gold ) @@ -362,7 +363,7 @@ class ConstructionsTable(val cityScreen: CityScreen) : Table(CameraStageBaseScre private fun getRaisePriorityButton(constructionQueueIndex: Int, name: String, city: CityInfo): Table { val tab = Table() tab.add(ImageGetter.getImage("OtherIcons/Up").surroundWithCircle(40f)) - if (UncivGame.Current.worldScreen.isPlayersTurn && !city.isPuppet) { + if (cityScreen.canChangeState && !city.isPuppet) { tab.touchable = Touchable.enabled tab.onClick { tab.touchable = Touchable.disabled @@ -379,7 +380,7 @@ class ConstructionsTable(val cityScreen: CityScreen) : Table(CameraStageBaseScre private fun getLowerPriorityButton(constructionQueueIndex: Int, name: String, city: CityInfo): Table { val tab = Table() tab.add(ImageGetter.getImage("OtherIcons/Down").surroundWithCircle(40f)) - if (UncivGame.Current.worldScreen.isPlayersTurn && !city.isPuppet) { + if (cityScreen.canChangeState && !city.isPuppet) { tab.touchable = Touchable.enabled tab.onClick { tab.touchable = Touchable.disabled @@ -396,7 +397,7 @@ class ConstructionsTable(val cityScreen: CityScreen) : Table(CameraStageBaseScre private fun getRemoveFromQueueButton(constructionQueueIndex: Int, city: CityInfo): Table { val tab = Table() tab.add(ImageGetter.getImage("OtherIcons/Stop").surroundWithCircle(40f)) - if (UncivGame.Current.worldScreen.isPlayersTurn && !city.isPuppet) { + if (cityScreen.canChangeState && !city.isPuppet) { tab.touchable = Touchable.enabled tab.onClick { tab.touchable = Touchable.disabled diff --git a/core/src/com/unciv/ui/cityscreen/SpecialistAllocationTable.kt b/core/src/com/unciv/ui/cityscreen/SpecialistAllocationTable.kt index 98aa8a9a35..3ac4aad360 100644 --- a/core/src/com/unciv/ui/cityscreen/SpecialistAllocationTable.kt +++ b/core/src/com/unciv/ui/cityscreen/SpecialistAllocationTable.kt @@ -22,9 +22,9 @@ class SpecialistAllocationTable(val cityScreen: CityScreen): Table(CameraStageBa val assignedSpecialists = cityInfo.population.specialists.get(stat).toInt() val maxSpecialists = cityInfo.population.getMaxSpecialists().get(stat).toInt() - add(getUnassignButton(assignedSpecialists,stat)) + if (cityScreen.canChangeState) add(getUnassignButton(assignedSpecialists,stat)) add(getAllocationTable(assignedSpecialists, maxSpecialists, stat)).pad(10f) - add(getAssignButton(assignedSpecialists,maxSpecialists,stat)) + if (cityScreen.canChangeState) add(getAssignButton(assignedSpecialists,maxSpecialists,stat)) addSeparatorVertical().pad(10f) add(getSpecialistStatsTable(stat)).row() } diff --git a/core/src/com/unciv/ui/overviewscreen/EmpireOverviewScreen.kt b/core/src/com/unciv/ui/overviewscreen/EmpireOverviewScreen.kt index 2d5b4bd2ce..1418de230a 100644 --- a/core/src/com/unciv/ui/overviewscreen/EmpireOverviewScreen.kt +++ b/core/src/com/unciv/ui/overviewscreen/EmpireOverviewScreen.kt @@ -308,7 +308,7 @@ class EmpireOverviewScreen(private val viewingPlayer:CivilizationInfo, defaultPa viewingPlayer.diplomacy.containsKey(civ.civName) private fun getDiplomacyGroup(): Group { - val relevantCivs = viewingPlayer.gameInfo.civilizations.filter { !it.isBarbarian() && !it.isCityState() } + val relevantCivs = viewingPlayer.gameInfo.civilizations.filter { it.isMajorCiv() } val freeWidth = stage.width val freeHeight = stage.height - topTable.height val group = Group() @@ -334,8 +334,8 @@ class EmpireOverviewScreen(private val viewingPlayer:CivilizationInfo, defaultPa for(civ in relevantCivs.filter { playerKnows(it) && !it.isDefeated() }) for(diplomacy in civ.diplomacy.values. - filter { !it.otherCiv().isBarbarian() && !it.otherCiv().isCityState() - && playerKnows(it.otherCiv()) && !it.otherCiv().isDefeated()}){ + filter { it.otherCiv().isMajorCiv() + && playerKnows(it.otherCiv()) && !it.otherCiv().isDefeated() }){ val civGroup = civGroups[civ.civName]!! val otherCivGroup = civGroups[diplomacy.otherCivName]!! diff --git a/core/src/com/unciv/ui/tilegroups/CityButton.kt b/core/src/com/unciv/ui/tilegroups/CityButton.kt index 41c81f7b5f..d59f6de49a 100644 --- a/core/src/com/unciv/ui/tilegroups/CityButton.kt +++ b/core/src/com/unciv/ui/tilegroups/CityButton.kt @@ -142,7 +142,7 @@ class CityButton(val city: CityInfo, private val tileGroup: WorldTileGroup): Tab val viewingCiv = worldScreen.viewingCiv // second tap on the button will go to the city screen // if this city belongs to you - if (uncivGame.viewEntireMapForDebug || belongsToViewingCiv()) { + if (uncivGame.viewEntireMapForDebug || belongsToViewingCiv() || viewingCiv.isSpectator()) { uncivGame.setScreen(CityScreen(city)) } else if (viewingCiv.knows(city.civInfo)) { // If city doesn't belong to you, go directly to its owner's diplomacy screen. @@ -203,15 +203,16 @@ class CityButton(val city: CityInfo, private val tileGroup: WorldTileGroup): Tab iconTable.add(connectionImage).size(20f).pad(2f).padLeft(5f) } - iconTable.add(getPopulationGroup(uncivGame.viewEntireMapForDebug || belongsToViewingCiv())) - .padLeft(10f) + iconTable.add(getPopulationGroup(uncivGame.viewEntireMapForDebug + || belongsToViewingCiv() + || worldScreen.viewingCiv.isSpectator())).padLeft(10f) val cityButtonText = city.name val label = cityButtonText.toLabel(secondaryColor) iconTable.add(label).pad(10f) // sufficient horizontal padding .fillY() // provide full-height clicking area - if (uncivGame.viewEntireMapForDebug || belongsToViewingCiv()) + if (uncivGame.viewEntireMapForDebug || belongsToViewingCiv() || worldScreen.viewingCiv.isSpectator()) iconTable.add(getConstructionGroup(city.cityConstructions)).padRight(10f).padLeft(10f) else if (city.civInfo.isMajorCiv()) { val nationIcon = ImageGetter.getNationIcon(city.civInfo.nation.name) diff --git a/core/src/com/unciv/ui/trade/DiplomacyScreen.kt b/core/src/com/unciv/ui/trade/DiplomacyScreen.kt index 72368ea605..9f8be3d21f 100644 --- a/core/src/com/unciv/ui/trade/DiplomacyScreen.kt +++ b/core/src/com/unciv/ui/trade/DiplomacyScreen.kt @@ -53,7 +53,7 @@ class DiplomacyScreen(val viewingCiv:CivilizationInfo):CameraStageBaseScreen() { private fun updateLeftSideTable() { leftSideTable.clear() for (civ in UncivGame.Current.gameInfo.civilizations - .filterNot { it.isDefeated() || it == viewingCiv || it.isBarbarian() }) { + .filterNot { it.isDefeated() || it == viewingCiv || it.isBarbarian() || it.isSpectator() }) { if (!viewingCiv.knows(civ)) continue val civIndicator = ImageGetter.getNationIndicator(civ.nation,100f) diff --git a/core/src/com/unciv/ui/worldscreen/WorldScreen.kt b/core/src/com/unciv/ui/worldscreen/WorldScreen.kt index 8af90a7984..4f761bf70b 100644 --- a/core/src/com/unciv/ui/worldscreen/WorldScreen.kt +++ b/core/src/com/unciv/ui/worldscreen/WorldScreen.kt @@ -41,6 +41,7 @@ import kotlin.concurrent.thread class WorldScreen(val viewingCiv:CivilizationInfo) : CameraStageBaseScreen() { val gameInfo = game.gameInfo var isPlayersTurn = viewingCiv == gameInfo.currentPlayerCiv // todo this should be updated when passing turns + val canChangeState = isPlayersTurn && !viewingCiv.isSpectator() private var waitingForAutosave = false val mapHolder = WorldMapHolder(this, gameInfo.tileMap)