mirror of
https://github.com/yairm210/Unciv.git
synced 2025-07-06 16:28:40 +07:00
Show notification to cycle through visible resources when clicking on resource icon in Resource Overview. (#5603)
* Show notif to cycle through resource tiles when tapping on icon in Resource Overview. * Make resource reveal notification more configurable, and move completely to `GameInfo`. * Make resource reveal notification loop through all explored tiles, instead of just visible tiles. * Have resource discovery notif cycle through matching CS centers for CS-only Luxuries. * Remove commented lines. * Remove extra comma. * Use Sequence in resource notif.
This commit is contained in:
@ -7,6 +7,7 @@ import com.unciv.logic.BackwardCompatibility.replaceDiplomacyFlag
|
|||||||
import com.unciv.logic.automation.NextTurnAutomation
|
import com.unciv.logic.automation.NextTurnAutomation
|
||||||
import com.unciv.logic.civilization.*
|
import com.unciv.logic.civilization.*
|
||||||
import com.unciv.logic.civilization.diplomacy.DiplomacyFlags
|
import com.unciv.logic.civilization.diplomacy.DiplomacyFlags
|
||||||
|
import com.unciv.logic.city.CityInfo
|
||||||
import com.unciv.logic.map.TileInfo
|
import com.unciv.logic.map.TileInfo
|
||||||
import com.unciv.logic.map.TileMap
|
import com.unciv.logic.map.TileMap
|
||||||
import com.unciv.models.Religion
|
import com.unciv.models.Religion
|
||||||
@ -16,6 +17,7 @@ import com.unciv.models.ruleset.Difficulty
|
|||||||
import com.unciv.models.ruleset.ModOptionsConstants
|
import com.unciv.models.ruleset.ModOptionsConstants
|
||||||
import com.unciv.models.ruleset.Ruleset
|
import com.unciv.models.ruleset.Ruleset
|
||||||
import com.unciv.models.ruleset.RulesetCache
|
import com.unciv.models.ruleset.RulesetCache
|
||||||
|
import com.unciv.models.ruleset.unique.UniqueType
|
||||||
import com.unciv.ui.audio.MusicMood
|
import com.unciv.ui.audio.MusicMood
|
||||||
import com.unciv.ui.audio.MusicTrackChooserFlags
|
import com.unciv.ui.audio.MusicTrackChooserFlags
|
||||||
import java.util.*
|
import java.util.*
|
||||||
@ -292,6 +294,57 @@ class GameInfo {
|
|||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
|
fun notifyExploredResources(civInfo: CivilizationInfo, resourceName: String, maxDistance: Int, showForeign: Boolean) {
|
||||||
|
// Calling with `maxDistance = 0` removes distance limitation.
|
||||||
|
data class CityTileAndDistance(val city: CityInfo, val tile: TileInfo, val distance: Int)
|
||||||
|
|
||||||
|
var exploredRevealTiles:Sequence<TileInfo>
|
||||||
|
|
||||||
|
if (ruleSet.tileResources[resourceName]!!.hasUnique(UniqueType.CityStateOnlyResource)) {
|
||||||
|
// Look for matching mercantile CS centers
|
||||||
|
exploredRevealTiles = getAliveCityStates()
|
||||||
|
.asSequence()
|
||||||
|
.filter { it.cityStateResource == resourceName }
|
||||||
|
.map { it.getCapital().getCenterTile() }
|
||||||
|
} else {
|
||||||
|
exploredRevealTiles = tileMap.values
|
||||||
|
.asSequence()
|
||||||
|
.filter { it.resource == resourceName }
|
||||||
|
}
|
||||||
|
|
||||||
|
val exploredRevealInfo = exploredRevealTiles
|
||||||
|
.filter { it.position in civInfo.exploredTiles }
|
||||||
|
.flatMap { tile -> civInfo.cities.asSequence()
|
||||||
|
.map {
|
||||||
|
// build a full cross join all revealed tiles * civ's cities (should rarely surpass a few hundred)
|
||||||
|
// cache distance for each pair as sort will call it ~ 2n log n times
|
||||||
|
// should still be cheaper than looking up 'the' closest city per reveal tile before sorting
|
||||||
|
city -> CityTileAndDistance(city, tile, tile.aerialDistanceTo(city.getCenterTile()))
|
||||||
|
}
|
||||||
|
}
|
||||||
|
.filter { (maxDistance == 0 || it.distance <= maxDistance) && (showForeign || it.tile.getOwner() == null || it.tile.getOwner() == civInfo) }
|
||||||
|
.sortedWith ( compareBy { it.distance } )
|
||||||
|
.distinctBy { it.tile }
|
||||||
|
|
||||||
|
val chosenCity = exploredRevealInfo.firstOrNull()?.city ?: return
|
||||||
|
val positions = exploredRevealInfo
|
||||||
|
// re-sort to a more pleasant display order
|
||||||
|
.sortedWith(compareBy{ it.tile.aerialDistanceTo(chosenCity.getCenterTile()) })
|
||||||
|
.map { it.tile.position }
|
||||||
|
.toList() // explicit materialization of sequence to satisfy addNotification overload
|
||||||
|
|
||||||
|
val text = if(positions.size==1)
|
||||||
|
"[$resourceName] revealed near [${chosenCity.name}]"
|
||||||
|
else
|
||||||
|
"[${positions.size}] sources of [$resourceName] revealed, e.g. near [${chosenCity.name}]"
|
||||||
|
|
||||||
|
civInfo.addNotification(
|
||||||
|
text,
|
||||||
|
LocationAction(positions),
|
||||||
|
"ResourceIcons/$resourceName"
|
||||||
|
)
|
||||||
|
}
|
||||||
|
|
||||||
// All cross-game data which needs to be altered (e.g. when removing or changing a name of a building/tech)
|
// All cross-game data which needs to be altered (e.g. when removing or changing a name of a building/tech)
|
||||||
// will be done here, and not in CivInfo.setTransients or CityInfo
|
// will be done here, and not in CivInfo.setTransients or CityInfo
|
||||||
fun setTransients() {
|
fun setTransients() {
|
||||||
|
@ -262,7 +262,11 @@ class TechManager {
|
|||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
if (civInfo.playerType == PlayerType.Human) notifyRevealedResources(techName)
|
if (civInfo.playerType == PlayerType.Human) {
|
||||||
|
for (revealedResource in getRuleset().tileResources.values.filter { techName == it.revealedBy }) {
|
||||||
|
civInfo.gameInfo.notifyExploredResources(civInfo, revealedResource.name, 5, false)
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
val obsoleteUnits = getRuleset().units.values.filter { it.obsoleteTech == techName }.map { it.name }
|
val obsoleteUnits = getRuleset().units.values.filter { it.obsoleteTech == techName }.map { it.name }
|
||||||
val unitUpgrades = HashMap<String, ArrayList<CityInfo>>()
|
val unitUpgrades = HashMap<String, ArrayList<CityInfo>>()
|
||||||
@ -323,46 +327,6 @@ class TechManager {
|
|||||||
techUniques.addUnique(unique)
|
techUniques.addUnique(unique)
|
||||||
}
|
}
|
||||||
|
|
||||||
private fun notifyRevealedResources(techName: String) {
|
|
||||||
data class CityTileAndDistance(val city: CityInfo, val tile: TileInfo, val distance: Int)
|
|
||||||
|
|
||||||
for (revealedResource in getRuleset().tileResources.values.filter { techName == it.revealedBy }) {
|
|
||||||
val revealedName = revealedResource.name
|
|
||||||
|
|
||||||
val visibleRevealTiles = civInfo.viewableTiles.asSequence()
|
|
||||||
.filter { it.resource == revealedName }
|
|
||||||
.flatMap { tile -> civInfo.cities.asSequence()
|
|
||||||
.map {
|
|
||||||
// build a full cross join all revealed tiles * civ's cities (should rarely surpass a few hundred)
|
|
||||||
// cache distance for each pair as sort will call it ~ 2n log n times
|
|
||||||
// should still be cheaper than looking up 'the' closest city per reveal tile before sorting
|
|
||||||
city -> CityTileAndDistance(city, tile, tile.aerialDistanceTo(city.getCenterTile()))
|
|
||||||
}
|
|
||||||
}
|
|
||||||
.filter { it.distance <= 5 && (it.tile.getOwner() == null || it.tile.getOwner() == civInfo) }
|
|
||||||
.sortedWith ( compareBy { it.distance } )
|
|
||||||
.distinctBy { it.tile }
|
|
||||||
|
|
||||||
val chosenCity = visibleRevealTiles.firstOrNull()?.city ?: continue
|
|
||||||
val positions = visibleRevealTiles
|
|
||||||
// re-sort to a more pleasant display order
|
|
||||||
.sortedWith(compareBy{ it.tile.aerialDistanceTo(chosenCity.getCenterTile()) })
|
|
||||||
.map { it.tile.position }
|
|
||||||
.toList() // explicit materialization of sequence to satisfy addNotification overload
|
|
||||||
|
|
||||||
val text = if(positions.size==1)
|
|
||||||
"[$revealedName] revealed near [${chosenCity.name}]"
|
|
||||||
else
|
|
||||||
"[${positions.size}] sources of [$revealedName] revealed, e.g. near [${chosenCity.name}]"
|
|
||||||
|
|
||||||
civInfo.addNotification(
|
|
||||||
text,
|
|
||||||
LocationAction(positions),
|
|
||||||
"ResourceIcons/$revealedName"
|
|
||||||
)
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
fun setTransients() {
|
fun setTransients() {
|
||||||
researchedTechnologies.addAll(techsResearched.map { getRuleset().technologies[it]!! })
|
researchedTechnologies.addAll(techsResearched.map { getRuleset().technologies[it]!! })
|
||||||
researchedTechnologies.forEach { addTechToTransients(it) }
|
researchedTechnologies.forEach { addTechToTransients(it) }
|
||||||
|
@ -31,25 +31,20 @@ class ResourcesOverviewTable (
|
|||||||
.filter { it.resourceType != ResourceType.Bonus }.distinct()
|
.filter { it.resourceType != ResourceType.Bonus }.distinct()
|
||||||
.sortedWith(compareBy({ it.resourceType }, { it.name.tr() }))
|
.sortedWith(compareBy({ it.resourceType }, { it.name.tr() }))
|
||||||
|
|
||||||
var visibleLabel: Label? = null
|
|
||||||
for (resource in resources) {
|
for (resource in resources) {
|
||||||
// Create a group of label and icon for each resource.
|
// Create a group of label and icon for each resource.
|
||||||
val resourceImage = ImageGetter.getResourceImage(resource.name, 50f)
|
val resourceImage = ImageGetter.getResourceImage(resource.name, 50f)
|
||||||
val resourceLabel = resource.name.toLabel()
|
|
||||||
val labelPadding = 10f
|
val labelPadding = 10f
|
||||||
// Using a table here leads to spacing issues
|
// Using a table here leads to spacing issues
|
||||||
// due to different label lengths.
|
// due to different label lengths.
|
||||||
val holder = Group()
|
val holder = Group()
|
||||||
resourceImage.onClick {
|
resourceImage.onClick {
|
||||||
if (visibleLabel != null)
|
viewingPlayer.gameInfo.notifyExploredResources(viewingPlayer, resource.name, 0, true)
|
||||||
visibleLabel!!.isVisible = false
|
overviewScreen.game.setWorldScreen()
|
||||||
resourceLabel.isVisible = true
|
|
||||||
visibleLabel = resourceLabel
|
|
||||||
}
|
}
|
||||||
holder.addActor(resourceImage)
|
holder.addActor(resourceImage)
|
||||||
holder.addActor(resourceLabel)
|
|
||||||
holder.setSize(resourceImage.width,
|
holder.setSize(resourceImage.width,
|
||||||
resourceImage.height + resourceLabel.height + labelPadding)
|
resourceImage.height + labelPadding)
|
||||||
// Center-align all labels, but right-align the last couple resources' labels
|
// Center-align all labels, but right-align the last couple resources' labels
|
||||||
// because they may get clipped otherwise. The leftmost label should be fine
|
// because they may get clipped otherwise. The leftmost label should be fine
|
||||||
// center-aligned (if there are more than 2 resources), because the left side
|
// center-aligned (if there are more than 2 resources), because the left side
|
||||||
@ -58,9 +53,6 @@ class ResourcesOverviewTable (
|
|||||||
(resources.indexOf(resource) + 2 >= resources.count()) -> 1
|
(resources.indexOf(resource) + 2 >= resources.count()) -> 1
|
||||||
else -> 2
|
else -> 2
|
||||||
}
|
}
|
||||||
resourceLabel.moveBy((resourceImage.width - resourceLabel.width) / alignFactor,
|
|
||||||
resourceImage.height + labelPadding)
|
|
||||||
resourceLabel.isVisible = false
|
|
||||||
add(holder)
|
add(holder)
|
||||||
}
|
}
|
||||||
addSeparator()
|
addSeparator()
|
||||||
|
Reference in New Issue
Block a user