mirror of
https://github.com/yairm210/Unciv.git
synced 2025-02-24 05:31:22 +07:00
New tile visibility framework!
This commit is contained in:
parent
924dbf70d0
commit
d1a9caaa88
@ -122,7 +122,7 @@
|
||||
"defenceBonus": 0.25,
|
||||
"RGB": [120, 120, 120],
|
||||
"uniques": ["Rough terrain",
|
||||
"Has an elevation of [4] for visibility calculations",
|
||||
"Has an elevation of [2] for visibility calculations",
|
||||
"Occurs in chains at high elevations",
|
||||
"Units ending their turn on this terrain take [50] damage",
|
||||
"Always Fertility [-2] for Map Generation",
|
||||
@ -158,7 +158,7 @@
|
||||
"occursOn": ["Tundra","Plains","Grassland","Desert","Snow"],
|
||||
"uniques": ["Rough terrain",
|
||||
"[+5] Strength for cities built on this terrain",
|
||||
"Has an elevation of [2] for visibility calculations",
|
||||
"Has an elevation of [1] for visibility calculations",
|
||||
"Occurs in groups around high elevations",
|
||||
"[+1] to Fertility for Map Generation",
|
||||
"A Region is formed with at least [40]% [Hill] tiles, with priority [5]",
|
||||
|
@ -122,7 +122,7 @@
|
||||
"defenceBonus": 0.25,
|
||||
"RGB": [120, 120, 120],
|
||||
"uniques": ["Rough terrain",
|
||||
"Has an elevation of [4] for visibility calculations",
|
||||
"Has an elevation of [2] for visibility calculations",
|
||||
"Occurs in chains at high elevations",
|
||||
"Units ending their turn on this terrain take [50] damage",
|
||||
"Always Fertility [-2] for Map Generation",
|
||||
@ -157,7 +157,7 @@
|
||||
"occursOn": ["Tundra","Plains","Grassland","Desert","Snow"],
|
||||
"uniques": ["Rough terrain",
|
||||
"[+5] Strength for cities built on this terrain",
|
||||
"Has an elevation of [2] for visibility calculations",
|
||||
"Has an elevation of [1] for visibility calculations",
|
||||
"Occurs in groups around high elevations",
|
||||
"[+1] to Fertility for Map Generation",
|
||||
"A Region is formed with at least [40]% [Hill] tiles, with priority [5]",
|
||||
|
@ -40,7 +40,7 @@ object UnitAutomation {
|
||||
unit.movement.getDistanceToTiles().keys.filter { isGoodTileToExplore(unit, it) }
|
||||
if (explorableTilesThisTurn.any()) {
|
||||
val bestTile = explorableTilesThisTurn
|
||||
.sortedByDescending { it.height } // secondary sort is by 'how far can you see'
|
||||
.sortedByDescending { it.tileHeight } // secondary sort is by 'how far can you see'
|
||||
.maxByOrNull { it.aerialDistanceTo(unit.currentTile) }!! // primary sort is by 'how far can you go'
|
||||
unit.movement.headTowards(bestTile)
|
||||
return true
|
||||
|
@ -345,7 +345,13 @@ open class TileInfo : IsPartOfGameInfoSerialization {
|
||||
}
|
||||
|
||||
@delegate:Transient
|
||||
val height : Int by lazy {
|
||||
val tileHeight : Int by lazy { // for e.g. hill+forest this is 2, since forest is visible above units
|
||||
if (terrainHasUnique(UniqueType.BlocksLineOfSightAtSameElevation)) unitHeight + 1
|
||||
else unitHeight
|
||||
}
|
||||
|
||||
@delegate:Transient
|
||||
val unitHeight : Int by lazy { // for e.g. hill+forest this is 1, since only hill provides height for units
|
||||
allTerrains.flatMap { it.getMatchingUniques(UniqueType.VisibilityElevation) }
|
||||
.map { it.params[0].toInt() }.sum()
|
||||
}
|
||||
|
@ -12,6 +12,7 @@ import com.unciv.models.ruleset.Nation
|
||||
import com.unciv.models.ruleset.Ruleset
|
||||
import com.unciv.models.ruleset.tile.TerrainType
|
||||
import com.unciv.models.ruleset.unique.UniqueType
|
||||
import java.lang.Integer.max
|
||||
import kotlin.math.abs
|
||||
|
||||
/** An Unciv map with all properties as produced by the [map editor][com.unciv.ui.mapeditor.MapEditorScreen]
|
||||
@ -325,52 +326,50 @@ class TileMap : IsPartOfGameInfoSerialization {
|
||||
vectorUnwrappedLeft
|
||||
}
|
||||
|
||||
data class ViewableTile(val tile:TileInfo, val maxHeightSeenToTile:Int, val isVisible:Boolean, val isAttackable: Boolean)
|
||||
|
||||
/** @return List of tiles visible from location [position] for a unit with sight range [sightDistance] */
|
||||
fun getViewableTiles(position: Vector2, sightDistance: Int): List<TileInfo> {
|
||||
val viewableTiles = getTilesInDistance(position, 1).toMutableList()
|
||||
val currentTileHeight = get(position).height
|
||||
val aUnitHeight = get(position).unitHeight
|
||||
val viewableTiles = mutableListOf(ViewableTile(
|
||||
get(position),
|
||||
aUnitHeight,
|
||||
isVisible = true,
|
||||
isAttackable = false
|
||||
))
|
||||
|
||||
for (i in 1..sightDistance) { // in each layer,
|
||||
// This is so we don't use tiles in the same distance to "see over",
|
||||
// that is to say, the "viewableTiles.contains(it) check will return false for neighbors from the same distance
|
||||
val tilesToAddInDistanceI = ArrayList<TileInfo>()
|
||||
val tilesToAddInDistanceI = ArrayList<ViewableTile>()
|
||||
|
||||
for (cTile in getTilesAtDistance(position, i)) { // for each tile in that layer,
|
||||
val cTileHeight = cTile.height
|
||||
val cTileHeight = cTile.tileHeight
|
||||
|
||||
/*
|
||||
Okay so, if we're looking at a tile from a to c with b in the middle,
|
||||
Okay so, if we're looking at a tile from height a to one with height c with a MAXIMUM HEIGHT of b in the middle,
|
||||
we have several scenarios:
|
||||
1. a>b - - I can see everything, b does not hide c
|
||||
2. a==b
|
||||
2.1 c>b - c is tall enough I can see it over b!
|
||||
2.2 b blocks view from same-elevation tiles - hides c
|
||||
2.3 none of the above - I can see c
|
||||
1. a>=b - I can see everything, b does not hide c (equals is 'flat plain' or 'string of hills' or 'hill viewing over forests')
|
||||
3. a<b
|
||||
3.1 b>=c - b hides c
|
||||
3.2 b<c - c is tall enough I can see it over b!
|
||||
3.1 b>=c - b hides c (hills hide other hills, forests, etc)
|
||||
3.2 b<c - c is tall enough I can see it over b (hill+forest, mountain)
|
||||
|
||||
This can all be summed up as "I can see c if a>b || c>b || (a==b && b !blocks same-elevation view)"
|
||||
This can all be summed up as "I can see c if a=>b || c>b"
|
||||
*/
|
||||
val bMinimumHighestSeenTerrainSoFar = viewableTiles.filter { it.tile in cTile.neighbors }
|
||||
.minOf { it.maxHeightSeenToTile }
|
||||
|
||||
val containsViewableNeighborThatCanSeeOver = cTile.neighbors.any { bNeighbor: TileInfo ->
|
||||
val bNeighborHeight = bNeighbor.height
|
||||
viewableTiles.contains(bNeighbor)
|
||||
&& (
|
||||
currentTileHeight > bNeighborHeight // a>b
|
||||
|| cTileHeight > bNeighborHeight // c>b
|
||||
|| (
|
||||
currentTileHeight == bNeighborHeight // a==b
|
||||
&& !bNeighbor.terrainHasUnique(UniqueType.BlocksLineOfSightAtSameElevation)
|
||||
)
|
||||
)
|
||||
}
|
||||
if (containsViewableNeighborThatCanSeeOver) tilesToAddInDistanceI.add(cTile)
|
||||
tilesToAddInDistanceI.add(ViewableTile(
|
||||
cTile,
|
||||
max(cTileHeight, bMinimumHighestSeenTerrainSoFar),
|
||||
aUnitHeight >= bMinimumHighestSeenTerrainSoFar || cTileHeight > bMinimumHighestSeenTerrainSoFar,
|
||||
aUnitHeight >= bMinimumHighestSeenTerrainSoFar || cTile.unitHeight > bMinimumHighestSeenTerrainSoFar,
|
||||
))
|
||||
}
|
||||
viewableTiles.addAll(tilesToAddInDistanceI)
|
||||
}
|
||||
|
||||
return viewableTiles
|
||||
return viewableTiles.filter { it.isVisible }.map { it.tile }
|
||||
}
|
||||
|
||||
/** Strips all units from [TileMap]
|
||||
|
@ -67,7 +67,7 @@ class VisibilityTests {
|
||||
fun canSeeForestOverPlains() {
|
||||
val grassland = addTile("Grassland", Vector2(0f,0f))
|
||||
addTile("Plains", Vector2(1f,0f))
|
||||
val forest = addTile(listOf("Grassland", "Forest"), Vector2(2f, 1f))
|
||||
val forest = addTile(listOf("Grassland", "Forest"), Vector2(2f, 0f))
|
||||
val viewableTiles = grassland.getViewableTilesList(2)
|
||||
assert(viewableTiles.contains(forest))
|
||||
}
|
||||
@ -75,7 +75,7 @@ class VisibilityTests {
|
||||
@Test
|
||||
fun cannotSeePlainsOverForest() {
|
||||
val grassland = addTile("Grassland", Vector2(0f,0f))
|
||||
addTile(listOf("Grassland", "Forest"), Vector2(1f, 1f))
|
||||
addTile(listOf("Grassland", "Forest"), Vector2(1f, 0f))
|
||||
val plains = addTile("Plains", Vector2(2f,0f))
|
||||
val viewableTiles = grassland.getViewableTilesList(2)
|
||||
assert(!viewableTiles.contains(plains))
|
||||
@ -84,7 +84,7 @@ class VisibilityTests {
|
||||
@Test
|
||||
fun cannotSeeForestOverForest() {
|
||||
val grassland = addTile("Grassland", Vector2(0f,0f))
|
||||
addTile(listOf("Grassland", "Forest"), Vector2(1f, 1f))
|
||||
addTile(listOf("Grassland", "Forest"), Vector2(1f, 0f))
|
||||
val plains = addTile(listOf("Plains", "Forest"), Vector2(2f,0f))
|
||||
val viewableTiles = grassland.getViewableTilesList(2)
|
||||
assert(!viewableTiles.contains(plains))
|
||||
@ -94,7 +94,7 @@ class VisibilityTests {
|
||||
fun canSeeHillOverPlains() {
|
||||
val grassland = addTile("Grassland", Vector2(0f,0f))
|
||||
addTile("Plains", Vector2(1f,0f))
|
||||
val hill = addTile(listOf("Grassland", "Hill"), Vector2(2f, 1f))
|
||||
val hill = addTile(listOf("Grassland", "Hill"), Vector2(2f, 0f))
|
||||
val viewableTiles = grassland.getViewableTilesList(2)
|
||||
assert(viewableTiles.contains(hill))
|
||||
}
|
||||
@ -102,10 +102,65 @@ class VisibilityTests {
|
||||
@Test
|
||||
fun cannotSeePlainsOverHill() {
|
||||
val grassland = addTile("Grassland", Vector2(0f,0f))
|
||||
addTile(listOf("Grassland", "Hill"), Vector2(1f, 1f))
|
||||
addTile(listOf("Grassland", "Hill"), Vector2(1f, 0f))
|
||||
val plains = addTile("Plains", Vector2(2f,0f))
|
||||
val viewableTiles = grassland.getViewableTilesList(2)
|
||||
assert(!viewableTiles.contains(plains))
|
||||
}
|
||||
|
||||
@Test
|
||||
fun cannotSeeHillOverHill() {
|
||||
val grassland = addTile("Grassland", Vector2(0f,0f))
|
||||
addTile(listOf("Grassland", "Hill"), Vector2(1f,0f))
|
||||
val hill = addTile(listOf("Grassland", "Hill"), Vector2(2f, 0f))
|
||||
val viewableTiles = grassland.getViewableTilesList(2)
|
||||
assert(!viewableTiles.contains(hill))
|
||||
}
|
||||
|
||||
|
||||
@Test
|
||||
fun cannotSeeHillOverForest() {
|
||||
val grassland = addTile("Grassland", Vector2(0f,0f))
|
||||
addTile(listOf("Grassland", "Forest"), Vector2(1f,0f))
|
||||
val hill = addTile(listOf("Grassland", "Hill"), Vector2(2f, 0f))
|
||||
val viewableTiles = grassland.getViewableTilesList(2)
|
||||
assert(!viewableTiles.contains(hill))
|
||||
}
|
||||
|
||||
@Test
|
||||
fun cannotSeeForestOverHill() {
|
||||
val grassland = addTile("Grassland", Vector2(0f,0f))
|
||||
addTile(listOf("Grassland", "Hill"), Vector2(1f,0f))
|
||||
val hill = addTile(listOf("Grassland", "Forest"), Vector2(2f, 0f))
|
||||
val viewableTiles = grassland.getViewableTilesList(2)
|
||||
assert(!viewableTiles.contains(hill))
|
||||
}
|
||||
|
||||
@Test
|
||||
fun canSeeHillForestOverHill() {
|
||||
val grassland = addTile("Grassland", Vector2(0f,0f))
|
||||
addTile(listOf("Grassland", "Forest"), Vector2(1f,0f))
|
||||
val hill = addTile(listOf("Grassland", "Hill", "Forest"), Vector2(2f, 0f))
|
||||
val viewableTiles = grassland.getViewableTilesList(2)
|
||||
assert(viewableTiles.contains(hill))
|
||||
}
|
||||
|
||||
@Test
|
||||
fun canSeeMountainOverHill() {
|
||||
val grassland = addTile("Grassland", Vector2(0f,0f))
|
||||
addTile(listOf("Grassland", "Hill"), Vector2(1f,0f))
|
||||
val hill = addTile(listOf("Mountain"), Vector2(2f, 0f))
|
||||
val viewableTiles = grassland.getViewableTilesList(2)
|
||||
assert(viewableTiles.contains(hill))
|
||||
}
|
||||
|
||||
@Test
|
||||
fun cannotSeeMountainOverHillForest() {
|
||||
val grassland = addTile("Grassland", Vector2(0f,0f))
|
||||
addTile(listOf("Grassland", "Hill", "Forest"), Vector2(1f,0f))
|
||||
val hill = addTile(listOf("Mountain"), Vector2(2f, 0f))
|
||||
val viewableTiles = grassland.getViewableTilesList(2)
|
||||
assert(!viewableTiles.contains(hill))
|
||||
}
|
||||
|
||||
}
|
||||
|
Loading…
Reference in New Issue
Block a user