From d7067d283550d38a6ed5e6392e5f1795bc372867 Mon Sep 17 00:00:00 2001 From: Yair Morgenstern Date: Mon, 21 Jan 2019 22:41:22 +0200 Subject: [PATCH] Resolved #409 - rewrite line-of-sight rules --- .../unciv/logic/automation/UnitAutomation.kt | 4 +-- core/src/com/unciv/logic/map/MapUnit.kt | 2 +- core/src/com/unciv/logic/map/TileInfo.kt | 4 +-- core/src/com/unciv/logic/map/TileMap.kt | 30 +++++++++++++++---- 4 files changed, 30 insertions(+), 10 deletions(-) diff --git a/core/src/com/unciv/logic/automation/UnitAutomation.kt b/core/src/com/unciv/logic/automation/UnitAutomation.kt index 4afeb45818..8c3b1d83aa 100644 --- a/core/src/com/unciv/logic/automation/UnitAutomation.kt +++ b/core/src/com/unciv/logic/automation/UnitAutomation.kt @@ -154,14 +154,14 @@ class UnitAutomation{ // and then later we round it off to a whole. // So the poor unit thought it could attack from the tile, but when it comes to do so it has no movement points! // Silly floats, basically - var tilesToAttackFrom = unitDistanceToTiles.asSequence() + val tilesToAttackFrom = unitDistanceToTiles.asSequence() .filter { unit.currentMovement - it.value >= minMovementBeforeAttack } .map { it.key } .filter { unit.canMoveTo(it) || it==unit.getTile() } for(reachableTile in tilesToAttackFrom){ // tiles we'll still have energy after we reach there val tilesInAttackRange = if (unit.hasUnique("Indirect Fire")) reachableTile.getTilesInDistance(rangeOfAttack) - else reachableTile.getViewableTiles(rangeOfAttack) + else reachableTile.getViewableTiles(rangeOfAttack, unit.type.isWaterUnit()) attackableTiles += tilesInAttackRange.asSequence().filter { it in tilesWithEnemies } .map { AttackableTile(reachableTile,it) } } diff --git a/core/src/com/unciv/logic/map/MapUnit.kt b/core/src/com/unciv/logic/map/MapUnit.kt index 3e87b1f758..9a4245dbbc 100644 --- a/core/src/com/unciv/logic/map/MapUnit.kt +++ b/core/src/com/unciv/logic/map/MapUnit.kt @@ -110,7 +110,7 @@ class MapUnit { visibilityRange += 1 val tile = getTile() if (tile.baseTerrain == "Hill" && type.isLandUnit()) visibilityRange += 1 - return tile.getViewableTiles(visibilityRange) + return tile.getViewableTiles(visibilityRange, type.isWaterUnit()) } fun isFortified(): Boolean { diff --git a/core/src/com/unciv/logic/map/TileInfo.kt b/core/src/com/unciv/logic/map/TileInfo.kt index cc99003770..98a3a7c176 100644 --- a/core/src/com/unciv/logic/map/TileInfo.kt +++ b/core/src/com/unciv/logic/map/TileInfo.kt @@ -210,8 +210,8 @@ open class TileInfo { return getUnits().any{it.isIdle()} } - fun getViewableTiles(distance:Int): MutableList { - return tileMap.getViewableTiles(this.position,distance) + fun getViewableTiles(distance:Int, ignoreCurrentTileHeight:Boolean = false): MutableList { + return tileMap.getViewableTiles(this.position,distance,ignoreCurrentTileHeight) } fun getTilesInDistance(distance:Int): List { diff --git a/core/src/com/unciv/logic/map/TileMap.kt b/core/src/com/unciv/logic/map/TileMap.kt index 53fedff24b..9fa969ec09 100644 --- a/core/src/com/unciv/logic/map/TileMap.kt +++ b/core/src/com/unciv/logic/map/TileMap.kt @@ -3,10 +3,8 @@ package com.unciv.logic.map import com.badlogic.gdx.math.Vector2 import com.unciv.logic.GameInfo import com.unciv.logic.HexMath -import com.unciv.logic.map.MapType import com.unciv.logic.civilization.CivilizationInfo import com.unciv.models.gamebasics.GameBasics -import com.unciv.ui.NewGameScreen class TileMap { @@ -90,18 +88,40 @@ class TileMap { return unit } - fun getViewableTiles(position: Vector2, sightDistance: Int): MutableList { + + fun getViewableTiles(position: Vector2, sightDistance: Int, ignoreCurrentTileHeight:Boolean=false): MutableList { val viewableTiles = getTilesInDistance(position, 1).toMutableList() + val currentTileHeight = if(ignoreCurrentTileHeight) 0 else get(position).getHeight() + 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() for (tile in getTilesAtDistance(position, i)) { // for each tile in that layer, - val tileHeight = tile.getHeight() + val targetTileHeight = tile.getHeight() + + /* + Okay so, if we're looking at a tile from a to c with 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 a==b==0, all flat ground, no hiding + 2.2 a>0, b>=c - b hides c from view (say I am in a forest/jungle and b is a forest/jungle, or hill) + 2.3 a>0, c>b - c is tall enough I can see it over b! + 3. a=c - b hides c + 3.2 bb || c>b || b==0 " + */ + val containsViewableNeighborThatCanSeeOver = tile.neighbors.any { val neighborHeight = it.getHeight() - viewableTiles.contains(it) && (neighborHeight == 0 || neighborHeight < tileHeight) + viewableTiles.contains(it) && ( + currentTileHeight > neighborHeight // a>b + || targetTileHeight > neighborHeight // c>b + || neighborHeight == 0) // b==0 } if (containsViewableNeighborThatCanSeeOver) tilesToAddInDistanceI.add(tile) }