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
This commit is contained in:
Alexander Korolyov 2020-07-19 12:35:38 +02:00 committed by GitHub
parent bd422fdb16
commit 00983dd00e
No known key found for this signature in database
GPG Key ID: 4AEE18F83AFDEB23
9 changed files with 32 additions and 22 deletions

View File

@ -182,7 +182,7 @@ class GameInfo {
fun placeBarbarianEncampment(existingEncampments: List<TileInfo>): TileInfo? { fun placeBarbarianEncampment(existingEncampments: List<TileInfo>): TileInfo? {
// Barbarians will only spawn in places that no one can see // 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() .flatMap { it.viewableTiles }.toHashSet()
val tilesWithin3ofExistingEncampment = existingEncampments.asSequence() val tilesWithin3ofExistingEncampment = existingEncampments.asSequence()
.flatMap { it.getTilesInDistance(3) }.toSet() .flatMap { it.getTilesInDistance(3) }.toSet()

View File

@ -22,6 +22,9 @@ class CityScreen(internal val city: CityInfo): CameraStageBaseScreen() {
var selectedConstruction: IConstruction? = null var selectedConstruction: IConstruction? = null
var keyListener: InputListener? = 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. */ /** Toggle between Constructions and cityInfo (buildings, specialists etc. */
var showConstructionsTable = true var showConstructionsTable = true
@ -134,12 +137,13 @@ class CityScreen(internal val city: CityInfo): CameraStageBaseScreen() {
city.annexCity() city.annexCity()
update() update()
} }
if (!canChangeState) annexCityButton.disable()
razeCityButtonHolder.add(annexCityButton).colspan(cityPickerTable.columns) razeCityButtonHolder.add(annexCityButton).colspan(cityPickerTable.columns)
} else if(!city.isBeingRazed) { } else if(!city.isBeingRazed) {
val razeCityButton = "Raze city".toTextButton() val razeCityButton = "Raze city".toTextButton()
razeCityButton.labelCell.pad(10f) razeCityButton.labelCell.pad(10f)
razeCityButton.onClick { city.isBeingRazed=true; update() } razeCityButton.onClick { city.isBeingRazed=true; update() }
if(!UncivGame.Current.worldScreen.isPlayersTurn || city.isOriginalCapital) if(!canChangeState || city.isOriginalCapital)
razeCityButton.disable() razeCityButton.disable()
razeCityButtonHolder.add(razeCityButton).colspan(cityPickerTable.columns) razeCityButtonHolder.add(razeCityButton).colspan(cityPickerTable.columns)
@ -147,7 +151,7 @@ class CityScreen(internal val city: CityInfo): CameraStageBaseScreen() {
val stopRazingCityButton = "Stop razing city".toTextButton() val stopRazingCityButton = "Stop razing city".toTextButton()
stopRazingCityButton.labelCell.pad(10f) stopRazingCityButton.labelCell.pad(10f)
stopRazingCityButton.onClick { city.isBeingRazed=false; update() } stopRazingCityButton.onClick { city.isBeingRazed=false; update() }
if(!UncivGame.Current.worldScreen.isPlayersTurn) stopRazingCityButton.disable() if(!canChangeState) stopRazingCityButton.disable()
razeCityButtonHolder.add(stopRazingCityButton).colspan(cityPickerTable.columns) razeCityButtonHolder.add(stopRazingCityButton).colspan(cityPickerTable.columns)
} }
razeCityButtonHolder.pack() razeCityButtonHolder.pack()
@ -173,7 +177,7 @@ class CityScreen(internal val city: CityInfo): CameraStageBaseScreen() {
selectedTile = tileInfo selectedTile = tileInfo
selectedConstruction = null selectedConstruction = null
if (tileGroup.isWorkable && UncivGame.Current.worldScreen.isPlayersTurn) { if (tileGroup.isWorkable && canChangeState) {
if (!tileInfo.isWorked() && city.population.getFreePopulation() > 0) { if (!tileInfo.isWorked() && city.population.getFreePopulation() > 0) {
city.workedTiles.add(tileInfo.position) city.workedTiles.add(tileInfo.position)
game.settings.addCompletedTutorialTask("Reassign worked tiles") game.settings.addCompletedTutorialTask("Reassign worked tiles")

View File

@ -34,7 +34,6 @@ class CityScreenTileTable(val cityScreen: CityScreen): Table(){
innerTable.row() innerTable.row()
innerTable.add(getTileStatsTable(stats)).row() innerTable.add(getTileStatsTable(stats)).row()
if(selectedTile.getOwner()==null && selectedTile.neighbors.any {it.getCity()==city} if(selectedTile.getOwner()==null && selectedTile.neighbors.any {it.getCity()==city}
&& selectedTile in city.tilesInRange){ && selectedTile in city.tilesInRange){
val goldCostOfTile = city.expansion.getGoldCostOfTile(selectedTile) val goldCostOfTile = city.expansion.getGoldCostOfTile(selectedTile)
@ -44,7 +43,9 @@ class CityScreenTileTable(val cityScreen: CityScreen): Table(){
city.expansion.buyTile(selectedTile) city.expansion.buyTile(selectedTile)
UncivGame.Current.setScreen(CityScreen(city)) 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() buyTileButton.disable()
innerTable.add(buyTileButton).row() innerTable.add(buyTileButton).row()
@ -64,6 +65,7 @@ class CityScreenTileTable(val cityScreen: CityScreen): Table(){
update(selectedTile) update(selectedTile)
cityScreen.update() cityScreen.update()
} }
if (!cityScreen.canChangeState) unlockButton.disable()
innerTable.add(unlockButton).row() innerTable.add(unlockButton).row()
} }
else { else {
@ -73,6 +75,7 @@ class CityScreenTileTable(val cityScreen: CityScreen): Table(){
update(selectedTile) update(selectedTile)
cityScreen.update() cityScreen.update()
} }
if (!cityScreen.canChangeState) lockButton.disable()
innerTable.add(lockButton).row() innerTable.add(lockButton).row()
} }
} }

View File

@ -270,7 +270,8 @@ class ConstructionsTable(val cityScreen: CityScreen) : Table(CameraStageBaseScre
if (isSelectedQueueEntry()) { if (isSelectedQueueEntry()) {
button = "Remove from queue".toTextButton() button = "Remove from queue".toTextButton()
if (!UncivGame.Current.worldScreen.isPlayersTurn || city.isPuppet) button.disable() if (!cityScreen.canChangeState || city.isPuppet)
button.disable()
else { else {
button.onClick { button.onClick {
cityConstructions.removeFromQueue(selectedQueueEntry,false) cityConstructions.removeFromQueue(selectedQueueEntry,false)
@ -284,7 +285,7 @@ class ConstructionsTable(val cityScreen: CityScreen) : Table(CameraStageBaseScre
if (construction == null if (construction == null
|| cityConstructions.isQueueFull() || cityConstructions.isQueueFull()
|| !cityConstructions.getConstruction(construction.name).isBuildable(cityConstructions) || !cityConstructions.getConstruction(construction.name).isBuildable(cityConstructions)
|| !UncivGame.Current.worldScreen.isPlayersTurn || !cityScreen.canChangeState
|| construction is PerpetualConstruction && cityConstructions.isBeingConstructedOrEnqueued(construction.name) || construction is PerpetualConstruction && cityConstructions.isBeingConstructedOrEnqueued(construction.name)
|| city.isPuppet) { || city.isPuppet) {
button.disable() button.disable()
@ -347,7 +348,7 @@ class ConstructionsTable(val cityScreen: CityScreen) : Table(CameraStageBaseScre
} }
if ( !construction.isBuildable(cityConstructions) if ( !construction.isBuildable(cityConstructions)
|| !UncivGame.Current.worldScreen.isPlayersTurn || !cityScreen.canChangeState
|| city.isPuppet || city.isInResistance() || city.isPuppet || city.isInResistance()
|| !city.canPurchase(construction) || !city.canPurchase(construction)
|| constructionGoldCost > city.civInfo.gold ) || 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 { private fun getRaisePriorityButton(constructionQueueIndex: Int, name: String, city: CityInfo): Table {
val tab = Table() val tab = Table()
tab.add(ImageGetter.getImage("OtherIcons/Up").surroundWithCircle(40f)) 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.touchable = Touchable.enabled
tab.onClick { tab.onClick {
tab.touchable = Touchable.disabled 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 { private fun getLowerPriorityButton(constructionQueueIndex: Int, name: String, city: CityInfo): Table {
val tab = Table() val tab = Table()
tab.add(ImageGetter.getImage("OtherIcons/Down").surroundWithCircle(40f)) 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.touchable = Touchable.enabled
tab.onClick { tab.onClick {
tab.touchable = Touchable.disabled tab.touchable = Touchable.disabled
@ -396,7 +397,7 @@ class ConstructionsTable(val cityScreen: CityScreen) : Table(CameraStageBaseScre
private fun getRemoveFromQueueButton(constructionQueueIndex: Int, city: CityInfo): Table { private fun getRemoveFromQueueButton(constructionQueueIndex: Int, city: CityInfo): Table {
val tab = Table() val tab = Table()
tab.add(ImageGetter.getImage("OtherIcons/Stop").surroundWithCircle(40f)) 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.touchable = Touchable.enabled
tab.onClick { tab.onClick {
tab.touchable = Touchable.disabled tab.touchable = Touchable.disabled

View File

@ -22,9 +22,9 @@ class SpecialistAllocationTable(val cityScreen: CityScreen): Table(CameraStageBa
val assignedSpecialists = cityInfo.population.specialists.get(stat).toInt() val assignedSpecialists = cityInfo.population.specialists.get(stat).toInt()
val maxSpecialists = cityInfo.population.getMaxSpecialists().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(getAllocationTable(assignedSpecialists, maxSpecialists, stat)).pad(10f)
add(getAssignButton(assignedSpecialists,maxSpecialists,stat)) if (cityScreen.canChangeState) add(getAssignButton(assignedSpecialists,maxSpecialists,stat))
addSeparatorVertical().pad(10f) addSeparatorVertical().pad(10f)
add(getSpecialistStatsTable(stat)).row() add(getSpecialistStatsTable(stat)).row()
} }

View File

@ -308,7 +308,7 @@ class EmpireOverviewScreen(private val viewingPlayer:CivilizationInfo, defaultPa
viewingPlayer.diplomacy.containsKey(civ.civName) viewingPlayer.diplomacy.containsKey(civ.civName)
private fun getDiplomacyGroup(): Group { 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 freeWidth = stage.width
val freeHeight = stage.height - topTable.height val freeHeight = stage.height - topTable.height
val group = Group() val group = Group()
@ -334,8 +334,8 @@ class EmpireOverviewScreen(private val viewingPlayer:CivilizationInfo, defaultPa
for(civ in relevantCivs.filter { playerKnows(it) && !it.isDefeated() }) for(civ in relevantCivs.filter { playerKnows(it) && !it.isDefeated() })
for(diplomacy in civ.diplomacy.values. for(diplomacy in civ.diplomacy.values.
filter { !it.otherCiv().isBarbarian() && !it.otherCiv().isCityState() filter { it.otherCiv().isMajorCiv()
&& playerKnows(it.otherCiv()) && !it.otherCiv().isDefeated()}){ && playerKnows(it.otherCiv()) && !it.otherCiv().isDefeated() }){
val civGroup = civGroups[civ.civName]!! val civGroup = civGroups[civ.civName]!!
val otherCivGroup = civGroups[diplomacy.otherCivName]!! val otherCivGroup = civGroups[diplomacy.otherCivName]!!

View File

@ -142,7 +142,7 @@ class CityButton(val city: CityInfo, private val tileGroup: WorldTileGroup): Tab
val viewingCiv = worldScreen.viewingCiv val viewingCiv = worldScreen.viewingCiv
// second tap on the button will go to the city screen // second tap on the button will go to the city screen
// if this city belongs to you // if this city belongs to you
if (uncivGame.viewEntireMapForDebug || belongsToViewingCiv()) { if (uncivGame.viewEntireMapForDebug || belongsToViewingCiv() || viewingCiv.isSpectator()) {
uncivGame.setScreen(CityScreen(city)) uncivGame.setScreen(CityScreen(city))
} else if (viewingCiv.knows(city.civInfo)) { } else if (viewingCiv.knows(city.civInfo)) {
// If city doesn't belong to you, go directly to its owner's diplomacy screen. // 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(connectionImage).size(20f).pad(2f).padLeft(5f)
} }
iconTable.add(getPopulationGroup(uncivGame.viewEntireMapForDebug || belongsToViewingCiv())) iconTable.add(getPopulationGroup(uncivGame.viewEntireMapForDebug
.padLeft(10f) || belongsToViewingCiv()
|| worldScreen.viewingCiv.isSpectator())).padLeft(10f)
val cityButtonText = city.name val cityButtonText = city.name
val label = cityButtonText.toLabel(secondaryColor) val label = cityButtonText.toLabel(secondaryColor)
iconTable.add(label).pad(10f) // sufficient horizontal padding iconTable.add(label).pad(10f) // sufficient horizontal padding
.fillY() // provide full-height clicking area .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) iconTable.add(getConstructionGroup(city.cityConstructions)).padRight(10f).padLeft(10f)
else if (city.civInfo.isMajorCiv()) { else if (city.civInfo.isMajorCiv()) {
val nationIcon = ImageGetter.getNationIcon(city.civInfo.nation.name) val nationIcon = ImageGetter.getNationIcon(city.civInfo.nation.name)

View File

@ -53,7 +53,7 @@ class DiplomacyScreen(val viewingCiv:CivilizationInfo):CameraStageBaseScreen() {
private fun updateLeftSideTable() { private fun updateLeftSideTable() {
leftSideTable.clear() leftSideTable.clear()
for (civ in UncivGame.Current.gameInfo.civilizations 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 if (!viewingCiv.knows(civ)) continue
val civIndicator = ImageGetter.getNationIndicator(civ.nation,100f) val civIndicator = ImageGetter.getNationIndicator(civ.nation,100f)

View File

@ -41,6 +41,7 @@ import kotlin.concurrent.thread
class WorldScreen(val viewingCiv:CivilizationInfo) : CameraStageBaseScreen() { class WorldScreen(val viewingCiv:CivilizationInfo) : CameraStageBaseScreen() {
val gameInfo = game.gameInfo val gameInfo = game.gameInfo
var isPlayersTurn = viewingCiv == gameInfo.currentPlayerCiv // todo this should be updated when passing turns var isPlayersTurn = viewingCiv == gameInfo.currentPlayerCiv // todo this should be updated when passing turns
val canChangeState = isPlayersTurn && !viewingCiv.isSpectator()
private var waitingForAutosave = false private var waitingForAutosave = false
val mapHolder = WorldMapHolder(this, gameInfo.tileMap) val mapHolder = WorldMapHolder(this, gameInfo.tileMap)