diff --git a/core/src/com/unciv/logic/BarbarianManager.kt b/core/src/com/unciv/logic/BarbarianManager.kt index db65fe7416..a3644b6687 100644 --- a/core/src/com/unciv/logic/BarbarianManager.kt +++ b/core/src/com/unciv/logic/BarbarianManager.kt @@ -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 + } } } diff --git a/core/src/com/unciv/logic/civilization/CivInfoTransientUpdater.kt b/core/src/com/unciv/logic/civilization/CivInfoTransientUpdater.kt index 79130016ce..089f204c21 100644 --- a/core/src/com/unciv/logic/civilization/CivInfoTransientUpdater.kt +++ b/core/src/com/unciv/logic/civilization/CivInfoTransientUpdater.kt @@ -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() // 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() for (tile in civInfo.viewableTiles) { diff --git a/core/src/com/unciv/logic/civilization/CivilizationInfo.kt b/core/src/com/unciv/logic/civilization/CivilizationInfo.kt index a3ee092a1e..f4df4f5237 100644 --- a/core/src/com/unciv/logic/civilization/CivilizationInfo.kt +++ b/core/src/com/unciv/logic/civilization/CivilizationInfo.kt @@ -160,6 +160,14 @@ class CivilizationInfo { var citiesCreated = 0 var exploredTiles = HashSet() + // This double construction because for some reason the game wants to load a + // map as a map causing all sorts of type problems. + // So we let the game have its map and remap it in setTransients, + // everyone's happy. Sort of. + var lastSeenImprovementSaved = HashMap() + @Transient + var lastSeenImprovement = HashMap() + // 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() { diff --git a/core/src/com/unciv/logic/map/TileInfo.kt b/core/src/com/unciv/logic/map/TileInfo.kt index d47f203a7b..2853bf0bc3 100644 --- a/core/src/com/unciv/logic/map/TileInfo.kt +++ b/core/src/com/unciv/logic/map/TileInfo.kt @@ -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})" diff --git a/core/src/com/unciv/ui/tilegroups/TileGroup.kt b/core/src/com/unciv/ui/tilegroups/TileGroup.kt index 161fb234b7..881f1190d5 100644 --- a/core/src/com/unciv/ui/tilegroups/TileGroup.kt +++ b/core/src/com/unciv/ui/tilegroups/TileGroup.kt @@ -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() 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() diff --git a/core/src/com/unciv/ui/tilegroups/TileGroupIcons.kt b/core/src/com/unciv/ui/tilegroups/TileGroupIcons.kt index 3293102ea6..5310cc0c9b 100644 --- a/core/src/com/unciv/ui/tilegroups/TileGroupIcons.kt +++ b/core/src/com/unciv/ui/tilegroups/TileGroupIcons.kt @@ -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) diff --git a/core/src/com/unciv/ui/worldscreen/WorldMapHolder.kt b/core/src/com/unciv/ui/worldscreen/WorldMapHolder.kt index b40432def2..844a2d7c4e 100644 --- a/core/src/com/unciv/ui/worldscreen/WorldMapHolder.kt +++ b/core/src/com/unciv/ui/worldscreen/WorldMapHolder.kt @@ -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 }