Civs with a spy set up in a foreign city can view some information (#11396)

* Civs with a spy set up can view some foreign city information

* Spying Civs can only see city tiles that they are aware of

* Refactored EspionageManager getCitiesWithOurSpies

Co-authored-by: Yair Morgenstern <yairm210@hotmail.com>

* Removed extra parenthesis

---------

Co-authored-by: Yair Morgenstern <yairm210@hotmail.com>
This commit is contained in:
Oskar Niesen 2024-04-09 15:11:12 -05:00 committed by GitHub
parent 60bb8704ad
commit 892b54f651
No known key found for this signature in database
GPG Key ID: B5690EEEBB952194
5 changed files with 30 additions and 11 deletions

View File

@ -96,7 +96,7 @@ class DiplomacyAction(
if (showTrade && currentCiv.isAtWarWith(otherCiv)) if (showTrade && currentCiv.isAtWarWith(otherCiv))
showTrade = false // Can't trade right now showTrade = false // Can't trade right now
worldScreen.game.pushScreen(DiplomacyScreen(currentCiv, otherCiv, showTrade = showTrade)) worldScreen.game.pushScreen(DiplomacyScreen(currentCiv, otherCiv, showTrade = showTrade))
} }
} }

View File

@ -70,5 +70,11 @@ class EspionageManager : IsPartOfGameInfoSerialization {
return spyList.filter { it.getLocation() == city }.toMutableList() return spyList.filter { it.getLocation() == city }.toMutableList()
} }
/**
* Returns a list of all cities with our spies in them.
* The list needs to be stable accross calls on the same turn.
*/
fun getCitiesWithOurSpies(): List<City> = spyList.filter { it.isSetUp() }.mapNotNull { it.getLocation() }
fun getSpyAssignedToCity(city: City): Spy? = spyList.firstOrNull {it.getLocation() == city} fun getSpyAssignedToCity(city: City): Spy? = spyList.firstOrNull {it.getLocation() == city}
} }

View File

@ -531,7 +531,8 @@ class CityButton(val city: City, private val tileGroup: TileGroup) : Table(BaseS
// 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 and you are not iterating though the air units // if this city belongs to you and you are not iterating though the air units
if (DebugUtils.VISIBLE_MAP || viewingPlayer.isSpectator() if (DebugUtils.VISIBLE_MAP || viewingPlayer.isSpectator()
|| (belongsToViewingCiv() && !tileGroup.tile.airUnits.contains(unitTable.selectedUnit))) { || belongsToViewingCiv() && !tileGroup.tile.airUnits.contains(unitTable.selectedUnit)
|| city.civ.gameInfo.isEspionageEnabled() && viewingPlayer.espionageManager.getSpyAssignedToCity(city)?.isSetUp() == true) {
GUI.pushScreen(CityScreen(city)) GUI.pushScreen(CityScreen(city))
} else if (viewingPlayer.knows(city.civ)) { } else if (viewingPlayer.knows(city.civ)) {
foreignCityInfoPopup() foreignCityInfoPopup()

View File

@ -8,6 +8,7 @@ import com.unciv.GUI
import com.unciv.UncivGame import com.unciv.UncivGame
import com.unciv.logic.automation.Automation import com.unciv.logic.automation.Automation
import com.unciv.logic.city.City import com.unciv.logic.city.City
import com.unciv.logic.civilization.Civilization
import com.unciv.logic.map.tile.Tile import com.unciv.logic.map.tile.Tile
import com.unciv.models.TutorialTrigger import com.unciv.models.TutorialTrigger
import com.unciv.models.UncivSound import com.unciv.models.UncivSound
@ -60,8 +61,19 @@ class CityScreen(
const val wltkIconSize = 40f const val wltkIconSize = 40f
} }
private val selectedCiv: Civilization = GUI.getWorldScreen().selectedCiv
private val isSpying = selectedCiv.gameInfo.isEspionageEnabled() && selectedCiv != city.civ
/**
* This is the regular civ city list if we are not spying, if we are spying then it is every foreign city that our spies are in
*/
val viewableCities = if (isSpying) selectedCiv.espionageManager.getCitiesWithOurSpies()
.filter { it.civ != GUI.getWorldScreen().selectedCiv }
else city.civ.cities
/** Toggles or adds/removes all state changing buttons */ /** Toggles or adds/removes all state changing buttons */
val canChangeState = GUI.isAllowedChangeState() val canChangeState = GUI.isAllowedChangeState() && !isSpying
// Clockwise from the top-left // Clockwise from the top-left
@ -136,6 +148,7 @@ class CityScreen(
//stage.setDebugTableUnderMouse(true) //stage.setDebugTableUnderMouse(true)
stage.addActor(cityStatsTable) stage.addActor(cityStatsTable)
// If we are spying then we shoulden't be able to see their construction screen.
constructionsTable.addActorsToStage() constructionsTable.addActorsToStage()
stage.addActor(selectedConstructionTable) stage.addActor(selectedConstructionTable)
stage.addActor(tileTable) stage.addActor(tileTable)
@ -151,7 +164,7 @@ class CityScreen(
// Recalculate Stats // Recalculate Stats
city.cityStats.update() city.cityStats.update()
constructionsTable.isVisible = true constructionsTable.isVisible = !isSpying
constructionsTable.update(selectedConstruction) constructionsTable.update(selectedConstruction)
updateWithoutConstructionAndMap() updateWithoutConstructionAndMap()
@ -313,7 +326,7 @@ class CityScreen(
private fun addTiles() { private fun addTiles() {
val tileSetStrings = TileSetStrings() val tileSetStrings = TileSetStrings()
val cityTileGroups = city.getCenterTile().getTilesInDistance(5) val cityTileGroups = city.getCenterTile().getTilesInDistance(5)
.filter { city.civ.hasExplored(it) } .filter { selectedCiv.hasExplored(it) }
.map { CityTileGroup(city, it, tileSetStrings) } .map { CityTileGroup(city, it, tileSetStrings) }
for (tileGroup in cityTileGroups) { for (tileGroup in cityTileGroups) {
@ -501,12 +514,11 @@ class CityScreen(
// Normal order is create new, then dispose old. But CityAmbiencePlayer delegates to a single instance of MusicController, // Normal order is create new, then dispose old. But CityAmbiencePlayer delegates to a single instance of MusicController,
// leading to one extra play followed by a stop for the city ambience sounds. To avoid that, we pass our player on and relinquish control. // leading to one extra play followed by a stop for the city ambience sounds. To avoid that, we pass our player on and relinquish control.
val civInfo = city.civ val numCities = viewableCities.size
val numCities = civInfo.cities.size
if (numCities == 0) return if (numCities == 0) return
val indexOfCity = civInfo.cities.indexOf(city) val indexOfCity = viewableCities.indexOf(city)
val indexOfNextCity = (indexOfCity + delta + numCities) % numCities val indexOfNextCity = (indexOfCity + delta + numCities) % numCities
val newCityScreen = CityScreen(civInfo.cities[indexOfNextCity], ambiencePlayer = passOnCityAmbiencePlayer()) val newCityScreen = CityScreen(viewableCities[indexOfNextCity], ambiencePlayer = passOnCityAmbiencePlayer())
newCityScreen.update() newCityScreen.update()
game.replaceCurrentScreen(newCityScreen) game.replaceCurrentScreen(newCityScreen)
} }

View File

@ -21,7 +21,7 @@ class CityScreenCityPickerTable(private val cityScreen: CityScreen) : Table() {
background = BaseScreen.skinStrings.getUiBackground("CityScreen/CityPickerTable", BaseScreen.skinStrings.roundedEdgeRectangleShape, civInfo.nation.getOuterColor()) background = BaseScreen.skinStrings.getUiBackground("CityScreen/CityPickerTable", BaseScreen.skinStrings.roundedEdgeRectangleShape, civInfo.nation.getOuterColor())
clear() clear()
if (civInfo.cities.size > 1) { if (cityScreen.viewableCities.size > 1) {
val prevCityButton = Table() // so we get a wider clickable area than just the image itself val prevCityButton = Table() // so we get a wider clickable area than just the image itself
val image = ImageGetter.getImage("OtherIcons/BackArrow") val image = ImageGetter.getImage("OtherIcons/BackArrow")
image.color = civInfo.nation.getInnerColor() image.color = civInfo.nation.getInnerColor()
@ -74,7 +74,7 @@ class CityScreenCityPickerTable(private val cityScreen: CityScreen) : Table() {
add(cityNameTable).width(stage.width / 4) add(cityNameTable).width(stage.width / 4)
if (civInfo.cities.size > 1) { if (cityScreen.viewableCities.size > 1) {
val nextCityButton = Table() // so we gt a wider clickable area than just the image itself val nextCityButton = Table() // so we gt a wider clickable area than just the image itself
val image = ImageGetter.getImage("OtherIcons/BackArrow") val image = ImageGetter.getImage("OtherIcons/BackArrow")
image.setSize(25f, 25f) image.setSize(25f, 25f)