Spectator can view other civ stats: Tech, Trades, Cities, Units, Gold (#2877)

* Select units/cities in spectator mode

* Can enter EmpireOverviewScreen in spectator mode

* keep selectedCiv after nextTurn

* Add current civilization Label and Icon

* Clickable Civilization label

* Victory screen and next turn update
This commit is contained in:
Alexander Korolyov 2020-07-23 13:27:39 +02:00 committed by GitHub
parent b5a4591955
commit 0f70726c10
No known key found for this signature in database
GPG Key ID: 4AEE18F83AFDEB23
11 changed files with 112 additions and 32 deletions

View File

@ -8,6 +8,7 @@ import com.badlogic.gdx.scenes.scene2d.ui.Label
import com.badlogic.gdx.scenes.scene2d.ui.Table
import com.badlogic.gdx.utils.Align
import com.unciv.Constants
import com.unciv.UncivGame
import com.unciv.logic.HexMath
import com.unciv.logic.civilization.CivilizationInfo
import com.unciv.logic.civilization.diplomacy.DiplomaticStatus
@ -21,7 +22,7 @@ import java.text.DecimalFormat
import kotlin.math.*
import com.unciv.ui.utils.AutoScrollPane as ScrollPane
class EmpireOverviewScreen(private val viewingPlayer:CivilizationInfo, defaultPage: String = "Cities") : CameraStageBaseScreen(){
class EmpireOverviewScreen(private var viewingPlayer:CivilizationInfo, defaultPage: String = "Cities") : CameraStageBaseScreen(){
private val topTable = Table().apply { defaults().pad(10f) }
private val centerTable = Table().apply { defaults().pad(20f) }

View File

@ -42,7 +42,7 @@ class PolicyPickerScreen(val worldScreen: WorldScreen, civInfo: CivilizationInfo
}
else game.setScreen(PolicyPickerScreen(worldScreen)) // update policies
}
if(!UncivGame.Current.worldScreen.isPlayersTurn)
if(!UncivGame.Current.worldScreen.canChangeState)
rightSideButton.disable()

View File

@ -36,7 +36,8 @@ class PromotionPickerScreen(val unit: MapUnit) : PickerScreen() {
acceptPromotion(selectedPromotion)
}
val canBePromoted = unit.promotions.canBePromoted()
if(!canBePromoted)
val canChangeState = game.worldScreen.canChangeState
if(!canBePromoted || !canChangeState)
rightSideButton.disable()
val availablePromotionsGroup = Table()
@ -60,7 +61,7 @@ class PromotionPickerScreen(val unit: MapUnit) : PickerScreen() {
selectPromotionButton.onClick {
selectedPromotion = promotion
rightSideButton.setText(promotion.name.tr())
if(canBePromoted && isPromotionAvailable && !unitHasPromotion)
if(canBePromoted && isPromotionAvailable && !unitHasPromotion && canChangeState)
rightSideButton.enable()
else rightSideButton.disable()
@ -70,7 +71,7 @@ class PromotionPickerScreen(val unit: MapUnit) : PickerScreen() {
availablePromotionsGroup.add(selectPromotionButton)
if(canBePromoted && isPromotionAvailable) {
if(canBePromoted && isPromotionAvailable && canChangeState) {
val pickNow = "Pick now!".toLabel()
pickNow.setAlignment(Align.center)
pickNow.onClick {

View File

@ -61,7 +61,6 @@ class TechPickerScreen(internal val civInfo: CivilizationInfo, centerOnTech: Tec
dispose()
}
// per default show current/recent technology,
// and possibly select it to show description,
// which is very helpful when just discovered and clicking the notification
@ -212,6 +211,13 @@ class TechPickerScreen(internal val civInfo: CivilizationInfo, centerOnTech: Tec
return
}
if (!UncivGame.Current.worldScreen.canChangeState) {
rightSideButton.disable()
return
}
tempTechsToResearch.clear()
tempTechsToResearch.addAll(civTech.getRequiredTechsToDestination(tech))

View File

@ -32,7 +32,7 @@ class VictoryScreen(val worldScreen: WorldScreen) : PickerScreen() {
val tabsTable = Table().apply { defaults().pad(10f) }
val setMyVictoryButton = "Our status".toTextButton().onClick { setMyVictoryTable() }
tabsTable.add(setMyVictoryButton)
if (!playerCivInfo.isSpectator()) tabsTable.add(setMyVictoryButton)
val setGlobalVictoryButton = "Global status".toTextButton().onClick { setGlobalVictoryTable() }
tabsTable.add(setGlobalVictoryButton)
val setCivRankingsButton = "Rankings".toTextButton().onClick { setCivRankingsTable() }
@ -41,7 +41,10 @@ class VictoryScreen(val worldScreen: WorldScreen) : PickerScreen() {
topTable.addSeparator()
topTable.add(contentsTable)
setMyVictoryTable()
if (playerCivInfo.isSpectator())
setGlobalVictoryTable()
else
setMyVictoryTable()
rightSideButton.isVisible=false

View File

@ -126,13 +126,15 @@ class WorldMapHolder(internal val worldScreen: WorldScreen, internal val tileMap
private fun addTileOverlays(tileInfo: TileInfo, moveHereDto:MoveHereButtonDto?=null){
val table = Table().apply { defaults().pad(10f) }
if(moveHereDto!=null)
if(moveHereDto!=null && worldScreen.canChangeState)
table.add(getMoveHereButton(moveHereDto))
val unitList = ArrayList<MapUnit>()
if (tileInfo.isCityCenter() && tileInfo.getOwner()==worldScreen.viewingCiv) {
if (tileInfo.isCityCenter()
&& (tileInfo.getOwner()==worldScreen.viewingCiv || worldScreen.viewingCiv.isSpectator())) {
unitList.addAll(tileInfo.getCity()!!.getCenterTile().getUnits())
} else if (tileInfo.airUnits.isNotEmpty() && tileInfo.airUnits.first().civInfo==worldScreen.viewingCiv) {
} else if (tileInfo.airUnits.isNotEmpty()
&& (tileInfo.airUnits.first().civInfo==worldScreen.viewingCiv || worldScreen.viewingCiv.isSpectator())) {
unitList.addAll(tileInfo.getUnits())
}

View File

@ -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
var selectedCiv = viewingCiv // Selected civilization, used only in spectator mode
val canChangeState = isPlayersTurn && !viewingCiv.isSpectator()
private var waitingForAutosave = false
@ -63,6 +64,7 @@ class WorldScreen(val viewingCiv:CivilizationInfo) : CameraStageBaseScreen() {
private val notificationsScroll: NotificationsScroll
var shouldUpdate = false
private var backButtonListener : InputListener
// An initialized val always turned out to illegally be null...
@ -122,7 +124,12 @@ class WorldScreen(val viewingCiv:CivilizationInfo) : CameraStageBaseScreen() {
viewingCiv.getCivUnits().any() -> viewingCiv.getCivUnits().first().getTile().position
else -> Vector2.Zero
}
mapHolder.setCenterPosition(tileToCenterOn,true)
// Don't select unit and change selectedCiv when centering as spectator
if (viewingCiv.isSpectator())
mapHolder.setCenterPosition(tileToCenterOn,true, false)
else
mapHolder.setCenterPosition(tileToCenterOn,true, true)
if(gameInfo.gameParameters.isOnlineMultiplayer && !gameInfo.isUpToDate)
@ -275,6 +282,8 @@ class WorldScreen(val viewingCiv:CivilizationInfo) : CameraStageBaseScreen() {
bottomTileInfoTable.y = if (game.settings.showMinimap) minimapWrapper.height else 0f
battleTable.update()
updateSelectedCiv()
tutorialTaskTable.clear()
val tutorialTask = getCurrentTutorialTask()
if (tutorialTask == "" || !game.settings.showTutorials || viewingCiv.isDefeated()) {
@ -298,7 +307,10 @@ class WorldScreen(val viewingCiv:CivilizationInfo) : CameraStageBaseScreen() {
// it causes a bug when we move a unit to an unexplored tile (for instance a cavalry unit which can move far)
mapHolder.updateTiles(viewingCiv)
topBar.update(viewingCiv)
if (viewingCiv.isSpectator())
topBar.update(selectedCiv)
else
topBar.update(viewingCiv)
updateTechButton()
techPolicyAndVictoryHolder.pack()
@ -440,6 +452,14 @@ class WorldScreen(val viewingCiv:CivilizationInfo) : CameraStageBaseScreen() {
techButtonHolder.pack() //setSize(techButtonHolder.prefWidth, techButtonHolder.prefHeight)
}
private fun updateSelectedCiv() {
if (bottomUnitTable.selectedUnit != null)
selectedCiv = bottomUnitTable.selectedUnit!!.civInfo
else if (bottomUnitTable.selectedCity != null)
selectedCiv = bottomUnitTable.selectedCity!!.civInfo
else viewingCiv
}
private fun createNextTurnButton(): TextButton {
val nextTurnButton = TextButton("", skin) // text is set in update()
@ -500,6 +520,7 @@ class WorldScreen(val viewingCiv:CivilizationInfo) : CameraStageBaseScreen() {
newWorldScreen.mapHolder.scaleX = mapHolder.scaleX
newWorldScreen.mapHolder.scaleY = mapHolder.scaleY
newWorldScreen.mapHolder.updateVisualScroll()
newWorldScreen.selectedCiv = gameInfoClone.getCivilization(selectedCiv.civName)
game.worldScreen = newWorldScreen
game.setWorldScreen()
}

View File

@ -6,6 +6,7 @@ import com.badlogic.gdx.scenes.scene2d.Group
import com.badlogic.gdx.scenes.scene2d.ui.Image
import com.badlogic.gdx.scenes.scene2d.ui.Label
import com.badlogic.gdx.scenes.scene2d.ui.Table
import com.badlogic.gdx.scenes.scene2d.ui.TextButton
import com.unciv.logic.civilization.CivilizationInfo
import com.unciv.models.metadata.GameSpeed
import com.unciv.models.ruleset.tile.ResourceType
@ -23,6 +24,8 @@ import kotlin.math.roundToInt
class WorldScreenTopBar(val worldScreen: WorldScreen) : Table() {
private var selectedCivTable = Table()
private val turnsLabel = "Turns: 0/400".toLabel()
private val goldLabel = "Gold:".toLabel(colorFromRGB(225, 217, 71))
private val scienceLabel = "Science:".toLabel(colorFromRGB(78, 140, 151))
@ -48,13 +51,9 @@ class WorldScreenTopBar(val worldScreen: WorldScreen) : Table() {
pack()
addActor(getMenuButton()) // needs to be after pack
val overviewButton = "Overview".toTextButton()
overviewButton.labelCell.pad(10f)
overviewButton.pack()
overviewButton.onClick { worldScreen.game.setScreen(EmpireOverviewScreen(worldScreen.viewingCiv)) }
overviewButton.center(this)
overviewButton.x = worldScreen.stage.width - overviewButton.width - 10
addActor(overviewButton)
addSelectedCivilizationTable()
addActor(getOverviewButton())
}
private fun getResourceTable(): Table {
@ -70,7 +69,9 @@ class WorldScreenTopBar(val worldScreen: WorldScreen) : Table() {
val resourceLabel = "0".toLabel()
resourceLabels[resource.name] = resourceLabel
resourceTable.add(resourceLabel)
val invokeResourcesPage = { worldScreen.game.setScreen(EmpireOverviewScreen(worldScreen.viewingCiv, "Resources")) }
val invokeResourcesPage = {
worldScreen.game.setScreen(EmpireOverviewScreen(worldScreen.selectedCiv, "Resources"))
}
resourceLabel.onClick(invokeResourcesPage)
resourceImage.onClick(invokeResourcesPage)
}
@ -86,27 +87,35 @@ class WorldScreenTopBar(val worldScreen: WorldScreen) : Table() {
statsTable.add(goldLabel)
val goldImage = ImageGetter.getStatIcon("Gold")
statsTable.add(goldImage).padRight(20f).size(20f)
val invokeStatsPage = { worldScreen.game.setScreen(EmpireOverviewScreen(worldScreen.viewingCiv, "Stats")) }
val invokeStatsPage = {
worldScreen.game.setScreen(EmpireOverviewScreen(worldScreen.selectedCiv, "Stats"))
}
goldLabel.onClick(invokeStatsPage)
goldImage.onClick(invokeStatsPage)
statsTable.add(scienceLabel) //.apply { setAlignment(Align.center) }).align(Align.top)
val scienceImage = ImageGetter.getStatIcon("Science")
statsTable.add(scienceImage).padRight(20f).size(20f)
val invokeTechScreen = { worldScreen.game.setScreen(TechPickerScreen(worldScreen.viewingCiv)) }
val invokeTechScreen = {
worldScreen.game.setScreen(TechPickerScreen(worldScreen.selectedCiv))
}
scienceLabel.onClick(invokeTechScreen)
scienceImage.onClick(invokeTechScreen)
statsTable.add(happinessImage).size(20f)
statsTable.add(happinessLabel).padRight(20f)//.apply { setAlignment(Align.center) }).align(Align.top)
val invokeResourcesPage = { worldScreen.game.setScreen(EmpireOverviewScreen(worldScreen.viewingCiv, "Resources")) }
val invokeResourcesPage = {
worldScreen.game.setScreen(EmpireOverviewScreen(worldScreen.selectedCiv, "Resources"))
}
happinessImage.onClick(invokeResourcesPage)
happinessLabel.onClick(invokeResourcesPage)
statsTable.add(cultureLabel)//.apply { setAlignment(Align.center) }).align(Align.top)
val cultureImage = ImageGetter.getStatIcon("Culture")
statsTable.add(cultureImage).size(20f)
val invokePoliciesPage = { worldScreen.game.setScreen(PolicyPickerScreen(worldScreen)) }
val invokePoliciesPage = {
worldScreen.game.setScreen(PolicyPickerScreen(worldScreen, worldScreen.selectedCiv))
}
cultureLabel.onClick(invokePoliciesPage)
cultureImage.onClick(invokePoliciesPage)
@ -130,6 +139,23 @@ class WorldScreenTopBar(val worldScreen: WorldScreen) : Table() {
return menuButton
}
private fun getOverviewButton(): TextButton {
val overviewButton = "Overview".toTextButton()
overviewButton.labelCell.pad(10f)
overviewButton.pack()
overviewButton.onClick { worldScreen.game.setScreen(EmpireOverviewScreen(worldScreen.selectedCiv)) }
overviewButton.center(this)
overviewButton.x = worldScreen.stage.width - overviewButton.width - 10
return overviewButton
}
private fun addSelectedCivilizationTable() {
selectedCivTable.centerY(this)
selectedCivTable.left()
selectedCivTable.x = getMenuButton().width + 20f
updateSelectedCivTabel()
addActor(selectedCivTable)
}
internal fun update(civInfo: CivilizationInfo) {
val revealedStrategicResources = civInfo.gameInfo.ruleSet.tileResources.values
@ -168,6 +194,22 @@ class WorldScreenTopBar(val worldScreen: WorldScreen) : Table() {
}
cultureLabel.setText(getCultureText(civInfo, nextTurnStats))
updateSelectedCivTabel()
}
private fun updateSelectedCivTabel() {
selectedCivTable.clear()
val selectedCivLabel = worldScreen.selectedCiv.civName.toLabel()
selectedCivLabel.setFontSize(25)
selectedCivLabel.onClick { worldScreen.game.setScreen(EmpireOverviewScreen(worldScreen.selectedCiv)) }
selectedCivTable.add(selectedCivLabel).padRight(10f)
val nation = worldScreen.gameInfo.ruleSet.nations[worldScreen.selectedCiv.civName]!!
selectedCivTable.add(ImageGetter.getNationIndicator(nation, 35f).onClick {
worldScreen.game.setScreen(EmpireOverviewScreen(worldScreen.selectedCiv))
})
}
private fun getCultureText(civInfo: CivilizationInfo, nextTurnStats: Stats): String {

View File

@ -42,7 +42,7 @@ class BattleTable(val worldScreen: WorldScreen): Table() {
isVisible = true
val attacker = tryGetAttacker()
if(attacker==null){ hide(); return }
if(attacker==null || !worldScreen.canChangeState){ hide(); return }
if (attacker.getUnitType()==UnitType.Missile) {
val selectedTile = worldScreen.mapHolder.selectedTile

View File

@ -62,7 +62,7 @@ class UnitActionsTable(val worldScreen: WorldScreen) : Table() {
fun update(unit: MapUnit?) {
clear()
if (unit == null) return
if (!worldScreen.isPlayersTurn) return // No actions when it's not your turn!
if (!worldScreen.canChangeState) return // No actions when it's not your turn or spectator!
for (button in UnitActions.getUnitActions(unit, worldScreen).map { getUnitActionButton(it) })
add(button).left().padBottom(2f).row()
pack()

View File

@ -74,7 +74,7 @@ class UnitTable(val worldScreen: WorldScreen) : Table(){
fun update() {
if(selectedUnit!=null) {
isVisible=true
if (selectedUnit!!.civInfo != worldScreen.viewingCiv) { // The unit that was selected, was captured. It exists but is no longer ours.
if (selectedUnit!!.civInfo != worldScreen.viewingCiv && !worldScreen.viewingCiv.isSpectator()) { // The unit that was selected, was captured. It exists but is no longer ours.
selectedUnit = null
selectedCity = null
selectedUnitHasChanged = true
@ -194,17 +194,21 @@ class UnitTable(val worldScreen: WorldScreen) : Table(){
fun tileSelected(selectedTile: TileInfo) {
val previouslySelectedUnit = selectedUnit
if(selectedTile.isCityCenter() && selectedTile.getOwner()==worldScreen.viewingCiv){
if(selectedTile.isCityCenter()
&& (selectedTile.getOwner()==worldScreen.viewingCiv || worldScreen.viewingCiv.isSpectator())){
citySelected(selectedTile.getCity()!!)
}
else if(selectedTile.militaryUnit!=null && selectedTile.militaryUnit!!.civInfo == worldScreen.viewingCiv
else if(selectedTile.militaryUnit!=null
&& (selectedTile.militaryUnit!!.civInfo == worldScreen.viewingCiv || worldScreen.viewingCiv.isSpectator())
&& selectedUnit!=selectedTile.militaryUnit
&& (selectedTile.civilianUnit==null || selectedUnit!=selectedTile.civilianUnit)){
selectedUnit = selectedTile.militaryUnit
selectedCity = null
}
else if (selectedTile.civilianUnit!=null && selectedTile.civilianUnit!!.civInfo == worldScreen.viewingCiv
&& selectedUnit!=selectedTile.civilianUnit){
else if (selectedTile.civilianUnit!=null
&& (selectedTile.civilianUnit!!.civInfo == worldScreen.viewingCiv || worldScreen.viewingCiv.isSpectator())
&& selectedUnit!=selectedTile.civilianUnit){
selectedUnit = selectedTile.civilianUnit
selectedCity = null
} else if(selectedTile == previouslySelectedUnit?.currentTile) {