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
{
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",
type:"BaseTerrain",
type:"Land",
food:2,
movementCost:1,
RGB: [109,139,53]
},
{
name:"Plains",
type:"BaseTerrain",
type:"Land",
food:1,
production:1,
movementCost:1,
@ -17,27 +31,28 @@
},
{
name:"Tundra",
type:"BaseTerrain",
type:"Land",
food:1,
movementCost:1,
RGB: [125,122,113]
},
{
name:"Desert",
type:"BaseTerrain",
type:"Land",
movementCost:1,
RGB: [ 255, 255, 102]
},
{
name:"Lakes",
type:"BaseTerrain",
type:"Water",
food:1,
gold:1
gold:1,
RGB: [ 200, 200, 255],
canHaveOverlay:false
},
{
name:"Hill",
type:"BaseTerrain",
type:"Land",
production:2,
movementCost:2,
defenceBonus: 0.25,

View file

@ -21,8 +21,8 @@ android {
applicationId "com.unciv.game"
minSdkVersion 14
targetSdkVersion 26
versionCode 135
versionName "2.8.3"
versionCode 137
versionName "2.8.5"
}
buildTypes {
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
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.
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.civilization.CivilizationInfo
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.UnitType
import java.text.DecimalFormat
@ -89,6 +90,8 @@ class MapUnit {
*/
fun canMoveTo(tile: TileInfo): Boolean {
val tileOwner = tile.getOwner()
if(tile.getBaseTerrain().type==TerrainType.Water && baseUnit.unitType.isLandUnit())
return false
if(tileOwner!=null && tileOwner.civName!=owner
&& (tile.isCityCenter() || !civInfo.canEnterTiles(tileOwner))) return false

View file

@ -8,68 +8,75 @@ import com.unciv.models.gamebasics.tile.TerrainType
import com.unciv.models.gamebasics.tile.TileResource
import com.unciv.ui.utils.getRandom
class AlexanderRandomMapGenerator:RandomMapGenerator(){
fun generateMap(distance: Int, landExpansionChange:Float){
val map = HashMap<Vector2, TileInfo?>()
for (vector in HexMath().GetVectorsInDistance(Vector2.Zero, distance))
map[vector] = null
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>()
fun addTile(position: Vector2) : TileInfo{
locations+=position
val tile = TileInfo()
tile.position = position
tile.baseTerrain = terrain
RandomMapGenerator().addRandomTerrainFeature(tile)
RandomMapGenerator().addRandomResourceToTile(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() {
override fun generateMap(distance: Int): HashMap<String, TileInfo> {
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
class Area(val terrain: String) {
val locations = ArrayList<Vector2>()
fun addTile(position: Vector2) : TileInfo{
locations+=position
val tile = TileInfo()
tile.position = position
tile.baseTerrain = terrain
addRandomOverlay(tile)
addRandomResourceToTile(tile)
return tile
}
}
val areas = ArrayList<Area>()
val terrains = GameBasics.Terrains.values.filter { it.type === TerrainType.BaseTerrain && it.name != "Lakes" }
for (i in 0..(distance*distance/2)){
val area = Area(terrains.getRandom().name)
val location = map.filter { it.value==null }.map { it.key }.getRandom()
map[location] = area.addTile(location)
areas += area
}
fun expandAreas(){
val expandableAreas = ArrayList<Area>(areas)
while (expandableAreas.isNotEmpty()){
val areaToExpand = expandableAreas.getRandom()
val availableExpansionVectors = areaToExpand.locations.flatMap { HexMath().GetAdjacentVectors(it) }.distinct()
.filter { map.containsKey(it) && map[it] == null }
if(availableExpansionVectors.isEmpty()) expandableAreas -= areaToExpand
else {
val expansionVector = availableExpansionVectors.getRandom()
map[expansionVector] = areaToExpand.addTile(expansionVector)
}
}
}
expandAreas()
// 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.
for(area in areas.toList()){
if(area.locations.size<3){
areas -= area
for(location in area.locations) map[location] = null
}
}
expandAreas()
divideIntoAreas(6, waterPercent, map)
val mapToReturn = HashMap<String,TileInfo>()
for (entry in map){
@ -78,8 +85,83 @@ class SeedRandomMapGenerator : RandomMapGenerator() {
return mapToReturn
}
private fun divideIntoAreas(averageTilesPerArea: Int, waterPercent: Float, map: HashMap<Vector2, TileInfo?>) {
val areas = ArrayList<Area>()
val terrains = GameBasics.Terrains.values.filter { it.type === TerrainType.Land && it.name != "Lakes" }
for (i in 0..(map.count { it.value==null } / averageTilesPerArea)) {
val terrain = if (Math.random() > waterPercent) terrains.getRandom().name
else "Ocean"
val area = Area(terrain)
val location = map.filter { it.value == null }.map { it.key }.getRandom()
map[location] = area.addTile(location)
areas += area
}
fun expandAreas() {
val expandableAreas = ArrayList<Area>(areas)
while (expandableAreas.isNotEmpty()) {
val areaToExpand = expandableAreas.getRandom()
val availableExpansionVectors = areaToExpand.locations
.flatMap { HexMath().GetAdjacentVectors(it) }.distinct()
.filter { map.containsKey(it) && map[it] == null }
if (availableExpansionVectors.isEmpty()) expandableAreas -= areaToExpand
else {
val expansionVector = availableExpansionVectors.getRandom()
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()
// 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
for (area in areas.toList()) {
if (area.locations.size < 3) {
areas -= area
for (location in area.locations) map[location] = null
}
}
expandAreas()
// Once our map has all its tiles, we'll want to change the water tiles to Coasts, Oceans and Lakes
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 {
private fun addRandomTile(position: Vector2): TileInfo {
@ -87,16 +169,16 @@ open class RandomMapGenerator {
tileInfo.position = position
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
addRandomOverlay(tileInfo)
addRandomTerrainFeature(tileInfo)
addRandomResourceToTile(tileInfo)
return tileInfo
}
protected fun addRandomOverlay(tileInfo: TileInfo) {
fun addRandomTerrainFeature(tileInfo: TileInfo) {
if (tileInfo.getBaseTerrain().canHaveOverlay && Math.random() > 0.7f) {
val secondaryTerrains = GameBasics.Terrains.values
.filter { it.type === TerrainType.TerrainFeature && it.occursOn!!.contains(tileInfo.baseTerrain) }
@ -127,7 +209,6 @@ open class RandomMapGenerator {
else return filtered.getRandom()
}
open fun generateMap(distance: Int): HashMap<String, TileInfo> {
val map = HashMap<String, TileInfo>()
for (vector in HexMath().GetVectorsInDistance(Vector2.Zero, distance))

View file

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

View file

@ -1,6 +1,7 @@
package com.unciv.logic.map
import com.badlogic.gdx.math.Vector2
import com.unciv.models.gamebasics.tile.TerrainType
class UnitMovementAlgorithms(val unit:MapUnit) {
val tileMap = unit.getTile().tileMap
@ -37,9 +38,10 @@ class UnitMovementAlgorithms(val unit:MapUnit) {
var totalDistanceToTile:Float
val neighborOwner = neighbor.getOwner()
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
|| (isOwnedByEnemy && !unit.civInfo.canEnterTiles(neighborOwner!!)) // enemyTile
|| (isOwnedByEnemy && !unit.civInfo.canEnterTiles(neighborOwner!!)) // enemyTile
)
totalDistanceToTile = unitMovement // Can't go here.
// The reason that we don't just "return" is so that when calculating how to reach an enemy,

View file

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

View file

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

View file

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