Lots off background work for future water tiles

Resized xxxhdpi icon
This commit is contained in:
Yair Morgenstern
2018-09-11 23:07:12 +03:00
parent d7a08cfc01
commit 9c8e173f4e
12 changed files with 178 additions and 71 deletions

Binary file not shown.

After

Width:  |  Height:  |  Size: 366 KiB

View File

@ -1,15 +1,29 @@
[ [
// Base terrains // Base terrains
{
name:"Ocean",
type:"Water",
food:2,
movementCost:1,
RGB: [100,100,255]
},
{
name:"Coast",
type:"Water",
food:2,
movementCost:1,
RGB: [150,150,255]
},
{ {
name:"Grassland", name:"Grassland",
type:"BaseTerrain", type:"Land",
food:2, food:2,
movementCost:1, movementCost:1,
RGB: [109,139,53] RGB: [109,139,53]
}, },
{ {
name:"Plains", name:"Plains",
type:"BaseTerrain", type:"Land",
food:1, food:1,
production:1, production:1,
movementCost:1, movementCost:1,
@ -17,27 +31,28 @@
}, },
{ {
name:"Tundra", name:"Tundra",
type:"BaseTerrain", type:"Land",
food:1, food:1,
movementCost:1, movementCost:1,
RGB: [125,122,113] RGB: [125,122,113]
}, },
{ {
name:"Desert", name:"Desert",
type:"BaseTerrain", type:"Land",
movementCost:1, movementCost:1,
RGB: [ 255, 255, 102] RGB: [ 255, 255, 102]
}, },
{ {
name:"Lakes", name:"Lakes",
type:"BaseTerrain", type:"Water",
food:1, food:1,
gold:1 gold:1,
RGB: [ 200, 200, 255],
canHaveOverlay:false canHaveOverlay:false
}, },
{ {
name:"Hill", name:"Hill",
type:"BaseTerrain", type:"Land",
production:2, production:2,
movementCost:2, movementCost:2,
defenceBonus: 0.25, defenceBonus: 0.25,

View File

@ -21,8 +21,8 @@ android {
applicationId "com.unciv.game" applicationId "com.unciv.game"
minSdkVersion 14 minSdkVersion 14
targetSdkVersion 26 targetSdkVersion 26
versionCode 135 versionCode 137
versionName "2.8.3" versionName "2.8.5"
} }
buildTypes { buildTypes {
release { release {

Binary file not shown.

Before

Width:  |  Height:  |  Size: 366 KiB

After

Width:  |  Height:  |  Size: 13 KiB

View File

@ -281,7 +281,7 @@ class UnitAutomation{
// find best city location within 5 tiles // find best city location within 5 tiles
val tilesNearCities = unit.civInfo.gameInfo.civilizations.flatMap { it.cities } val tilesNearCities = unit.civInfo.gameInfo.civilizations.flatMap { it.cities }
.flatMap { it.getCenterTile().getTilesInDistance(2) } .flatMap { it.getCenterTile().getTilesInDistance(3) }
// This is to improve performance - instead of ranking each tile in the area up to 19 times, do it once. // This is to improve performance - instead of ranking each tile in the area up to 19 times, do it once.
val nearbyTileRankings = unit.getTile().getTilesInDistance(7) val nearbyTileRankings = unit.getTile().getTilesInDistance(7)

View File

@ -4,6 +4,7 @@ import com.badlogic.gdx.math.Vector2
import com.unciv.logic.automation.WorkerAutomation import com.unciv.logic.automation.WorkerAutomation
import com.unciv.logic.civilization.CivilizationInfo import com.unciv.logic.civilization.CivilizationInfo
import com.unciv.models.gamebasics.GameBasics import com.unciv.models.gamebasics.GameBasics
import com.unciv.models.gamebasics.tile.TerrainType
import com.unciv.models.gamebasics.unit.BaseUnit import com.unciv.models.gamebasics.unit.BaseUnit
import com.unciv.models.gamebasics.unit.UnitType import com.unciv.models.gamebasics.unit.UnitType
import java.text.DecimalFormat import java.text.DecimalFormat
@ -89,6 +90,8 @@ class MapUnit {
*/ */
fun canMoveTo(tile: TileInfo): Boolean { fun canMoveTo(tile: TileInfo): Boolean {
val tileOwner = tile.getOwner() val tileOwner = tile.getOwner()
if(tile.getBaseTerrain().type==TerrainType.Water && baseUnit.unitType.isLandUnit())
return false
if(tileOwner!=null && tileOwner.civName!=owner if(tileOwner!=null && tileOwner.civName!=owner
&& (tile.isCityCenter() || !civInfo.canEnterTiles(tileOwner))) return false && (tile.isCityCenter() || !civInfo.canEnterTiles(tileOwner))) return false

View File

@ -8,16 +8,46 @@ import com.unciv.models.gamebasics.tile.TerrainType
import com.unciv.models.gamebasics.tile.TileResource import com.unciv.models.gamebasics.tile.TileResource
import com.unciv.ui.utils.getRandom import com.unciv.ui.utils.getRandom
class SeedRandomMapGenerator : RandomMapGenerator() { class AlexanderRandomMapGenerator:RandomMapGenerator(){
fun generateMap(distance: Int, landExpansionChange:Float){
override fun generateMap(distance: Int): HashMap<String, TileInfo> {
val map = HashMap<Vector2, TileInfo?>() val map = HashMap<Vector2, TileInfo?>()
for (vector in HexMath().GetVectorsInDistance(Vector2.Zero, distance)) for (vector in HexMath().GetVectorsInDistance(Vector2.Zero, distance))
map[vector] = null map[vector] = null
class Area(val terrain: String) { val sparkList = ArrayList<Vector2>()
val grassland = "Grassland"
val ocean = "Ocean"
for(i in 0..distance*distance/6){
val location = map.filter { it.value==null }.map { it.key }.getRandom()
map[location] = TileInfo().apply { baseTerrain= grassland}
sparkList.add(location)
}
while(sparkList.any()){
val currentSpark = sparkList.getRandom()
val emptyTilesAroundSpark = HexMath().GetAdjacentVectors(currentSpark)
.filter { map.containsKey(it) && map[it]==null }
if(map[currentSpark]!!.baseTerrain==grassland){
for(tile in emptyTilesAroundSpark){
if(Math.random()<landExpansionChange) map[tile]=TileInfo().apply { baseTerrain=grassland }
else map[tile]=TileInfo().apply { baseTerrain=ocean }
}
}
else{
for(tile in emptyTilesAroundSpark)
map[tile]=TileInfo().apply { baseTerrain=ocean }
}
sparkList.remove(currentSpark)
sparkList.addAll(emptyTilesAroundSpark)
}
// now that we've divided them into land and not-land, stage 2 - seeding areas the way we did with the seed generator!
}
}
class Area(var terrain: String) {
val locations = ArrayList<Vector2>() val locations = ArrayList<Vector2>()
fun addTile(position: Vector2) : TileInfo{ fun addTile(position: Vector2) : TileInfo{
locations+=position locations+=position
@ -25,19 +55,46 @@ class SeedRandomMapGenerator : RandomMapGenerator() {
val tile = TileInfo() val tile = TileInfo()
tile.position = position tile.position = position
tile.baseTerrain = terrain tile.baseTerrain = terrain
addRandomOverlay(tile) RandomMapGenerator().addRandomTerrainFeature(tile)
addRandomResourceToTile(tile) RandomMapGenerator().addRandomResourceToTile(tile)
return tile return tile
} }
} }
/**
* This generator works by creating a number of seeds of different terrain types in random places,
* and choosing a random one each time to expand in a random direction, until the map is filled.
* With water, this creates canal-like structures.
*/
class SeedRandomMapGenerator : RandomMapGenerator() {
fun generateMap(distance: Int, waterPercent:Float): HashMap<String, TileInfo> {
val map = HashMap<Vector2, TileInfo?>()
for (vector in HexMath().GetVectorsInDistance(Vector2.Zero, distance))
map[vector] = null
divideIntoAreas(6, waterPercent, map)
val mapToReturn = HashMap<String,TileInfo>()
for (entry in map){
mapToReturn[entry.key.toString()] = entry.value!!
}
return mapToReturn
}
private fun divideIntoAreas(averageTilesPerArea: Int, waterPercent: Float, map: HashMap<Vector2, TileInfo?>) {
val areas = ArrayList<Area>() val areas = ArrayList<Area>()
val terrains = GameBasics.Terrains.values.filter { it.type === TerrainType.BaseTerrain && it.name != "Lakes" } val terrains = GameBasics.Terrains.values.filter { it.type === TerrainType.Land && it.name != "Lakes" }
for (i in 0..(map.count { it.value==null } / averageTilesPerArea)) {
for (i in 0..(distance*distance/2)){ val terrain = if (Math.random() > waterPercent) terrains.getRandom().name
val area = Area(terrains.getRandom().name) else "Ocean"
val area = Area(terrain)
val location = map.filter { it.value == null }.map { it.key }.getRandom() val location = map.filter { it.value == null }.map { it.key }.getRandom()
map[location] = area.addTile(location) map[location] = area.addTile(location)
areas += area areas += area
@ -49,19 +106,32 @@ class SeedRandomMapGenerator : RandomMapGenerator() {
val expandableAreas = ArrayList<Area>(areas) val expandableAreas = ArrayList<Area>(areas)
while (expandableAreas.isNotEmpty()) { while (expandableAreas.isNotEmpty()) {
val areaToExpand = expandableAreas.getRandom() val areaToExpand = expandableAreas.getRandom()
val availableExpansionVectors = areaToExpand.locations.flatMap { HexMath().GetAdjacentVectors(it) }.distinct() val availableExpansionVectors = areaToExpand.locations
.flatMap { HexMath().GetAdjacentVectors(it) }.distinct()
.filter { map.containsKey(it) && map[it] == null } .filter { map.containsKey(it) && map[it] == null }
if (availableExpansionVectors.isEmpty()) expandableAreas -= areaToExpand if (availableExpansionVectors.isEmpty()) expandableAreas -= areaToExpand
else { else {
val expansionVector = availableExpansionVectors.getRandom() val expansionVector = availableExpansionVectors.getRandom()
map[expansionVector] = areaToExpand.addTile(expansionVector) map[expansionVector] = areaToExpand.addTile(expansionVector)
val neighbors = HexMath().GetAdjacentVectors(expansionVector)
val areasToJoin = areas.filter {
it.terrain == areaToExpand.terrain
&& it != areaToExpand
&& it.locations.any { location -> location in neighbors }
}
for (area in areasToJoin) {
areaToExpand.locations += area.locations
areas.remove(area)
expandableAreas.remove(area)
}
} }
} }
} }
expandAreas() expandAreas()
// After we've assigned all the tiles, there will be some areas that contain only 1 or 2 tiles. // After we've assigned all the tiles, there will be some areas that contain only 1 or 2 tiles.
// So, we kill those areas, and have the world expand on and cover them too. // So, we kill those areas, and have the world expand on and cover them too
for (area in areas.toList()) { for (area in areas.toList()) {
if (area.locations.size < 3) { if (area.locations.size < 3) {
areas -= area areas -= area
@ -71,15 +141,27 @@ class SeedRandomMapGenerator : RandomMapGenerator() {
expandAreas() expandAreas()
val mapToReturn = HashMap<String,TileInfo>() // Once our map has all its tiles, we'll want to change the water tiles to Coasts, Oceans and Lakes
for (entry in map){
mapToReturn[entry.key.toString()] = entry.value!!
}
return mapToReturn for (area in areas.filter { it.terrain == "Ocean" && it.locations.size <= 10 }) {
// areas with 10 or less tiles are lakes.
for (location in area.locations)
map[location]!!.baseTerrain = "Lakes"
}
for (tile in map.values.filter { it != null && it.baseTerrain == "Ocean" }) {
if (HexMath().GetAdjacentVectors(tile!!.position)
.any { map.containsKey(it) && map[it]!!.getBaseTerrain().type == TerrainType.Land })
tile.baseTerrain = "Coast"
}
} }
} }
/**
* This contains the basic randomizing tasks (add random terrain feature/resource)
* and a basic map generator where every single tile is individually randomized.
* DDoeesn't look very good TBH.
*/
open class RandomMapGenerator { open class RandomMapGenerator {
private fun addRandomTile(position: Vector2): TileInfo { private fun addRandomTile(position: Vector2): TileInfo {
@ -87,16 +169,16 @@ open class RandomMapGenerator {
tileInfo.position = position tileInfo.position = position
val terrains = GameBasics.Terrains.values val terrains = GameBasics.Terrains.values
val baseTerrain = terrains.filter { it.type === TerrainType.BaseTerrain && it.name != "Lakes" }.getRandom() val baseTerrain = terrains.filter { it.type === TerrainType.Land && it.name != "Lakes" }.getRandom()
tileInfo.baseTerrain = baseTerrain.name tileInfo.baseTerrain = baseTerrain.name
addRandomOverlay(tileInfo) addRandomTerrainFeature(tileInfo)
addRandomResourceToTile(tileInfo) addRandomResourceToTile(tileInfo)
return tileInfo return tileInfo
} }
protected fun addRandomOverlay(tileInfo: TileInfo) { fun addRandomTerrainFeature(tileInfo: TileInfo) {
if (tileInfo.getBaseTerrain().canHaveOverlay && Math.random() > 0.7f) { if (tileInfo.getBaseTerrain().canHaveOverlay && Math.random() > 0.7f) {
val secondaryTerrains = GameBasics.Terrains.values val secondaryTerrains = GameBasics.Terrains.values
.filter { it.type === TerrainType.TerrainFeature && it.occursOn!!.contains(tileInfo.baseTerrain) } .filter { it.type === TerrainType.TerrainFeature && it.occursOn!!.contains(tileInfo.baseTerrain) }
@ -127,7 +209,6 @@ open class RandomMapGenerator {
else return filtered.getRandom() else return filtered.getRandom()
} }
open fun generateMap(distance: Int): HashMap<String, TileInfo> { open fun generateMap(distance: Int): HashMap<String, TileInfo> {
val map = HashMap<String, TileInfo>() val map = HashMap<String, TileInfo>()
for (vector in HexMath().GetVectorsInDistance(Vector2.Zero, distance)) for (vector in HexMath().GetVectorsInDistance(Vector2.Zero, distance))

View File

@ -31,7 +31,7 @@ class TileMap {
constructor(distance: Int) { constructor(distance: Int) {
tileList.addAll(SeedRandomMapGenerator().generateMap(distance).values) tileList.addAll(SeedRandomMapGenerator().generateMap(distance,0f).values)
setTransients() setTransients()
} }

View File

@ -1,6 +1,7 @@
package com.unciv.logic.map package com.unciv.logic.map
import com.badlogic.gdx.math.Vector2 import com.badlogic.gdx.math.Vector2
import com.unciv.models.gamebasics.tile.TerrainType
class UnitMovementAlgorithms(val unit:MapUnit) { class UnitMovementAlgorithms(val unit:MapUnit) {
val tileMap = unit.getTile().tileMap val tileMap = unit.getTile().tileMap
@ -37,7 +38,8 @@ class UnitMovementAlgorithms(val unit:MapUnit) {
var totalDistanceToTile:Float var totalDistanceToTile:Float
val neighborOwner = neighbor.getOwner() val neighborOwner = neighbor.getOwner()
val isOwnedByEnemy = neighborOwner!=null && neighborOwner!=unit.civInfo val isOwnedByEnemy = neighborOwner!=null && neighborOwner!=unit.civInfo
if ((isOwnedByEnemy && neighbor.isCityCenter())// Enemy city, if ( (unit.baseUnit.unitType.isLandUnit() && neighbor.getBaseTerrain().type== TerrainType.Water)
|| (isOwnedByEnemy && neighbor.isCityCenter())// Enemy city,
|| (neighbor.getUnits().isNotEmpty() && neighbor.getUnits().first().civInfo!=unit.civInfo) // Enemy unit || (neighbor.getUnits().isNotEmpty() && neighbor.getUnits().first().civInfo!=unit.civInfo) // Enemy unit
|| (isOwnedByEnemy && !unit.civInfo.canEnterTiles(neighborOwner!!)) // enemyTile || (isOwnedByEnemy && !unit.civInfo.canEnterTiles(neighborOwner!!)) // enemyTile
) )

View File

@ -51,6 +51,7 @@ class Terrain : NamedStats(), ICivilopedia {
var RGB: List<Int>? = null var RGB: List<Int>? = null
var movementCost = 1 var movementCost = 1
var defenceBonus:Float = 0f var defenceBonus:Float = 0f
var impassible = false
fun getColor(): Color = colorFromRGB(RGB!![0], RGB!![1], RGB!![2]) fun getColor(): Color = colorFromRGB(RGB!![0], RGB!![1], RGB!![2])
} }

View File

@ -1,6 +1,7 @@
package com.unciv.models.gamebasics.tile package com.unciv.models.gamebasics.tile
enum class TerrainType { enum class TerrainType {
BaseTerrain, Land,
Water,
TerrainFeature TerrainFeature
} }

View File

@ -15,4 +15,8 @@ enum class UnitType{
fun isRanged(): Boolean { fun isRanged(): Boolean {
return this in listOf(Ranged, Siege) return this in listOf(Ranged, Siege)
} }
fun isLandUnit(): Boolean {
return this in listOf(Civilian, Melee, Mounted, Scout, Ranged, Siege)
}
} }