Improvements fog of war (#5504)

* fog of war for improvements

* fix spectator mode

* unnecessary imports

* getShownImprovement
This commit is contained in:
SimonCeder 2021-10-20 15:42:15 +02:00 committed by GitHub
parent 6cc55dd1a9
commit ae8c72adbc
No known key found for this signature in database
GPG Key ID: 4AEE18F83AFDEB23
7 changed files with 57 additions and 13 deletions

View File

@ -153,7 +153,10 @@ class BarbarianManager {
it.hasUnique("Notified of new Barbarian encampments")
&& it.exploredTiles.contains(tile.position)
}
.forEach { it.addNotification("A new barbarian encampment has spawned!", tile.position, NotificationIcon.War) }
.forEach {
it.addNotification("A new barbarian encampment has spawned!", tile.position, NotificationIcon.War)
it.lastSeenImprovement[tile.position] = Constants.barbarianEncampment
}
}
}

View File

@ -1,5 +1,6 @@
package com.unciv.logic.civilization
import com.unciv.UncivGame
import com.unciv.logic.map.TileInfo
import com.unciv.models.ruleset.tile.ResourceSupplyList
import com.unciv.models.ruleset.unique.UniqueType
@ -13,6 +14,7 @@ class CivInfoTransientUpdater(val civInfo: CivilizationInfo) {
updateViewableInvisibleTiles()
updateLastSeenImprovements()
// updating the viewable tiles also affects the explored tiles, obviously.
// So why don't we play switcharoo with the explored tiles as well?
@ -65,7 +67,7 @@ class CivInfoTransientUpdater(val civInfo: CivilizationInfo) {
val newViewableTiles = HashSet<TileInfo>()
// while spectating all map is visible
if (civInfo.isSpectator()) {
if (civInfo.isSpectator() || UncivGame.Current.viewEntireMapForDebug) {
val allTiles = civInfo.gameInfo.tileMap.values.toSet()
civInfo.viewableTiles = allTiles
civInfo.viewableInvisibleUnitsTiles = allTiles
@ -92,6 +94,18 @@ class CivInfoTransientUpdater(val civInfo: CivilizationInfo) {
civInfo.viewableTiles = newViewableTiles // to avoid concurrent modification problems
}
private fun updateLastSeenImprovements() {
if (civInfo.playerType == PlayerType.AI) return // don't bother for AI, they don't really use the info anyway
for (tile in civInfo.viewableTiles) {
val before = civInfo.lastSeenImprovement[tile.position]
if (tile.improvement == null)
civInfo.lastSeenImprovement.remove(tile.position)
else
civInfo.lastSeenImprovement[tile.position] = tile.improvement!!
}
}
private fun discoverNaturalWonders() {
val newlyViewedNaturalWonders = HashSet<TileInfo>()
for (tile in civInfo.viewableTiles) {

View File

@ -160,6 +160,14 @@ class CivilizationInfo {
var citiesCreated = 0
var exploredTiles = HashSet<Vector2>()
// This double construction because for some reason the game wants to load a
// map<Vector2, String> as a map<String, String> causing all sorts of type problems.
// So we let the game have its map<String, String> and remap it in setTransients,
// everyone's happy. Sort of.
var lastSeenImprovementSaved = HashMap<String, String>()
@Transient
var lastSeenImprovement = HashMap<Vector2, String>()
// To correctly determine "game over" condition as clarified in #4707
// Nullable type meant to be deprecated and converted to non-nullable,
// default false once we no longer want legacy save-game compatibility
@ -207,6 +215,7 @@ class CivilizationInfo {
// Cloning it by-pointer is a horrific move, since the serialization would go over it ANYWAY and still lead to concurrency problems.
// Cloning it by iterating on the tilemap values may seem ridiculous, but it's a perfectly thread-safe way to go about it, unlike the other solutions.
toReturn.exploredTiles.addAll(gameInfo.tileMap.values.asSequence().map { it.position }.filter { it in exploredTiles })
toReturn.lastSeenImprovementSaved.putAll(lastSeenImprovement.mapKeys { it.key.toString() })
toReturn.notifications.addAll(notifications)
toReturn.citiesCreated = citiesCreated
toReturn.popupAlerts.addAll(popupAlerts)
@ -730,6 +739,8 @@ class CivilizationInfo {
}
hasLongCountDisplayUnique = hasUnique(UniqueType.MayanCalendarDisplay)
lastSeenImprovement.putAll(lastSeenImprovementSaved.mapKeys { Vector2().fromString(it.key) })
}
fun updateSightAndResources() {

View File

@ -6,6 +6,7 @@ import com.unciv.UncivGame
import com.unciv.logic.HexMath
import com.unciv.logic.city.CityInfo
import com.unciv.logic.civilization.CivilizationInfo
import com.unciv.logic.civilization.PlayerType
import com.unciv.models.ruleset.Ruleset
import com.unciv.models.ruleset.unique.UniqueType
import com.unciv.models.ruleset.tile.*
@ -153,6 +154,13 @@ open class TileInfo {
fun getTileImprovement(): TileImprovement? = if (improvement == null) null else ruleset.tileImprovements[improvement!!]
fun getTileImprovementInProgress(): TileImprovement? = if (improvementInProgress == null) null else ruleset.tileImprovements[improvementInProgress!!]
fun getShownImprovement(viewingCiv: CivilizationInfo?): String? {
return if (viewingCiv == null || viewingCiv.playerType == PlayerType.AI)
improvement
else
viewingCiv.lastSeenImprovement[position]
}
// This is for performance - since we access the neighbors of a tile ALL THE TIME,
// and the neighbors of a tile never change, it's much more efficient to save the list once and for all!
@ -648,8 +656,9 @@ open class TileInfo {
lineList += FormattedLine(naturalWonder!!, link="Terrain/$naturalWonder")
if (roadStatus !== RoadStatus.None && !isCityCenter())
lineList += FormattedLine(roadStatus.name, link="Improvement/${roadStatus.name}")
if (improvement != null)
lineList += FormattedLine(improvement!!, link="Improvement/$improvement")
val shownImprovement = getShownImprovement(viewingCiv)
if (shownImprovement != null)
lineList += FormattedLine(shownImprovement, link="Improvement/$shownImprovement")
if (improvementInProgress != null && isViewableToPlayer) {
val line = "{$improvementInProgress}" +
if (turnsToImprovement > 0) " - $turnsToImprovement${Fonts.turn}" else " ({Under construction})"

View File

@ -180,14 +180,15 @@ open class TileGroup(var tileInfo: TileInfo, var tileSetStrings:TileSetStrings,
if (viewingCiv == null && !showEntireMap) return listOf(tileSetStrings.hexagon)
if (tileInfo.naturalWonder != null) return listOf(tileSetStrings.getTile(tileInfo.naturalWonder!!))
val shouldShowImprovement = tileInfo.improvement != null && UncivGame.Current.settings.showPixelImprovements
val shownImprovement = tileInfo.getShownImprovement(viewingCiv)
val shouldShowImprovement = (shownImprovement != null && UncivGame.Current.settings.showPixelImprovements)
val shouldShowResource = UncivGame.Current.settings.showPixelImprovements && tileInfo.resource != null &&
(showEntireMap || viewingCiv == null || tileInfo.hasViewableResource(viewingCiv))
var resourceAndImprovementSequence = sequenceOf<String?>()
if (shouldShowResource) resourceAndImprovementSequence += sequenceOf(tileInfo.resource)
if (shouldShowImprovement) resourceAndImprovementSequence += sequenceOf(tileInfo.improvement)
if (shouldShowImprovement) resourceAndImprovementSequence += sequenceOf(shownImprovement)
resourceAndImprovementSequence = resourceAndImprovementSequence.filterNotNull()
val terrainImages = (sequenceOf(tileInfo.baseTerrain) + tileInfo.terrainFeatures.asSequence()).filterNotNull()

View File

@ -23,7 +23,7 @@ class TileGroupIcons(val tileGroup: TileGroup) {
fun update(showResourcesAndImprovements: Boolean, showTileYields: Boolean, tileIsViewable: Boolean, showMilitaryUnit: Boolean, viewingCiv: CivilizationInfo?) {
updateResourceIcon(showResourcesAndImprovements)
updateImprovementIcon(showResourcesAndImprovements)
updateImprovementIcon(showResourcesAndImprovements, viewingCiv)
updateStartingLocationIcon(showResourcesAndImprovements)
if (viewingCiv != null) updateYieldIcon(showTileYields, viewingCiv)
@ -104,12 +104,13 @@ class TileGroupIcons(val tileGroup: TileGroup) {
}
private fun updateImprovementIcon(showResourcesAndImprovements: Boolean) {
private fun updateImprovementIcon(showResourcesAndImprovements: Boolean, viewingCiv: CivilizationInfo?) {
improvementIcon?.remove()
improvementIcon = null
if (tileGroup.tileInfo.improvement == null || !showResourcesAndImprovements) return
val shownImprovement = tileGroup.tileInfo.getShownImprovement(viewingCiv)
if (shownImprovement == null || !showResourcesAndImprovements) return
val newImprovementImage = ImageGetter.getImprovementIcon(tileGroup.tileInfo.improvement!!)
val newImprovementImage = ImageGetter.getImprovementIcon(shownImprovement)
tileGroup.miscLayerGroup.addActor(newImprovementImage)
newImprovementImage.run {
setSize(20f, 20f)

View File

@ -21,6 +21,7 @@ import com.unciv.logic.battle.Battle
import com.unciv.logic.battle.MapUnitCombatant
import com.unciv.logic.city.CityInfo
import com.unciv.logic.civilization.CivilizationInfo
import com.unciv.logic.civilization.PlayerType
import com.unciv.logic.map.*
import com.unciv.models.AttackableTile
import com.unciv.models.UncivSound
@ -445,7 +446,8 @@ class WorldMapHolder(internal val worldScreen: WorldScreen, internal val tileMap
for (tileGroup in allWorldTileGroups) {
tileGroup.update(viewingCiv)
if (tileGroup.tileInfo.improvement == Constants.barbarianEncampment
if (tileGroup.tileInfo.getShownImprovement(viewingCiv) == Constants.barbarianEncampment
&& tileGroup.tileInfo.position in viewingCiv.exploredTiles)
tileGroup.showCircle(Color.RED)
@ -494,8 +496,11 @@ class WorldMapHolder(internal val worldScreen: WorldScreen, internal val tileMap
else 0.5f
for (tile in allWorldTileGroups) {
if (tile.icons.populationIcon != null) tile.icons.populationIcon!!.color.a = fadeout
if (tile.icons.improvementIcon != null && tile.tileInfo.improvement != Constants.barbarianEncampment
&& tile.tileInfo.getTileImprovement()!!.isAncientRuinsEquivalent())
val shownImprovement = unit.civInfo.lastSeenImprovement[tile.tileInfo.position]
if (tile.icons.improvementIcon != null
&& shownImprovement != null && shownImprovement != Constants.barbarianEncampment
&& unit.civInfo.gameInfo.ruleSet.tileImprovements[shownImprovement]!!.isAncientRuinsEquivalent())
tile.icons.improvementIcon!!.color.a = fadeout
if (tile.resourceImage != null) tile.resourceImage!!.color.a = fadeout
}