diff --git a/android/ImagesToNotAddToGame/uncivicon2.png b/android/ImagesToNotAddToGame/uncivicon2.png new file mode 100644 index 00000000..6b86f360 Binary files /dev/null and b/android/ImagesToNotAddToGame/uncivicon2.png differ diff --git a/android/assets/jsons/Terrains.json b/android/assets/jsons/Terrains.json index 77d8df25..10c4bab9 100644 --- a/android/assets/jsons/Terrains.json +++ b/android/assets/jsons/Terrains.json @@ -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, diff --git a/android/build.gradle b/android/build.gradle index b0a34989..23608157 100644 --- a/android/build.gradle +++ b/android/build.gradle @@ -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 { diff --git a/android/res/drawable-xxxhdpi/uncivicon2.png b/android/res/drawable-xxxhdpi/uncivicon2.png index 28667631..1699da3a 100644 Binary files a/android/res/drawable-xxxhdpi/uncivicon2.png and b/android/res/drawable-xxxhdpi/uncivicon2.png differ diff --git a/core/src/com/unciv/logic/automation/UnitAutomation.kt b/core/src/com/unciv/logic/automation/UnitAutomation.kt index dd835a6f..3526d229 100644 --- a/core/src/com/unciv/logic/automation/UnitAutomation.kt +++ b/core/src/com/unciv/logic/automation/UnitAutomation.kt @@ -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) diff --git a/core/src/com/unciv/logic/map/MapUnit.kt b/core/src/com/unciv/logic/map/MapUnit.kt index f9f70242..9f35f0f4 100644 --- a/core/src/com/unciv/logic/map/MapUnit.kt +++ b/core/src/com/unciv/logic/map/MapUnit.kt @@ -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 diff --git a/core/src/com/unciv/logic/map/RandomMapGenerator.kt b/core/src/com/unciv/logic/map/RandomMapGenerator.kt index 702550e1..2638beee 100644 --- a/core/src/com/unciv/logic/map/RandomMapGenerator.kt +++ b/core/src/com/unciv/logic/map/RandomMapGenerator.kt @@ -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() + + for (vector in HexMath().GetVectorsInDistance(Vector2.Zero, distance)) + map[vector] = null + + val sparkList = ArrayList() + 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()() + 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 { + fun generateMap(distance: Int, waterPercent:Float): HashMap { val map = HashMap() for (vector in HexMath().GetVectorsInDistance(Vector2.Zero, distance)) map[vector] = null - class Area(val terrain: String) { - val locations = ArrayList() - 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() - - 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(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() for (entry in map){ @@ -78,8 +85,83 @@ class SeedRandomMapGenerator : RandomMapGenerator() { return mapToReturn } + + private fun divideIntoAreas(averageTilesPerArea: Int, waterPercent: Float, map: HashMap) { + val areas = ArrayList() + + 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(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 { val map = HashMap() for (vector in HexMath().GetVectorsInDistance(Vector2.Zero, distance)) diff --git a/core/src/com/unciv/logic/map/TileMap.kt b/core/src/com/unciv/logic/map/TileMap.kt index 9d622574..02390a14 100644 --- a/core/src/com/unciv/logic/map/TileMap.kt +++ b/core/src/com/unciv/logic/map/TileMap.kt @@ -31,7 +31,7 @@ class TileMap { constructor(distance: Int) { - tileList.addAll(SeedRandomMapGenerator().generateMap(distance).values) + tileList.addAll(SeedRandomMapGenerator().generateMap(distance,0f).values) setTransients() } diff --git a/core/src/com/unciv/logic/map/UnitMovementAlgorithms.kt b/core/src/com/unciv/logic/map/UnitMovementAlgorithms.kt index 5d84801a..e098ac89 100644 --- a/core/src/com/unciv/logic/map/UnitMovementAlgorithms.kt +++ b/core/src/com/unciv/logic/map/UnitMovementAlgorithms.kt @@ -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, diff --git a/core/src/com/unciv/models/gamebasics/tile/Terrain.kt b/core/src/com/unciv/models/gamebasics/tile/Terrain.kt index b9545e41..559009d6 100644 --- a/core/src/com/unciv/models/gamebasics/tile/Terrain.kt +++ b/core/src/com/unciv/models/gamebasics/tile/Terrain.kt @@ -51,6 +51,7 @@ class Terrain : NamedStats(), ICivilopedia { var RGB: List? = null var movementCost = 1 var defenceBonus:Float = 0f + var impassible = false fun getColor(): Color = colorFromRGB(RGB!![0], RGB!![1], RGB!![2]) } \ No newline at end of file diff --git a/core/src/com/unciv/models/gamebasics/tile/TerrainType.kt b/core/src/com/unciv/models/gamebasics/tile/TerrainType.kt index 830d7b77..85621cc2 100644 --- a/core/src/com/unciv/models/gamebasics/tile/TerrainType.kt +++ b/core/src/com/unciv/models/gamebasics/tile/TerrainType.kt @@ -1,6 +1,7 @@ package com.unciv.models.gamebasics.tile enum class TerrainType { - BaseTerrain, + Land, + Water, TerrainFeature } diff --git a/core/src/com/unciv/models/gamebasics/unit/UnitType.kt b/core/src/com/unciv/models/gamebasics/unit/UnitType.kt index 024d20aa..ff9eac63 100644 --- a/core/src/com/unciv/models/gamebasics/unit/UnitType.kt +++ b/core/src/com/unciv/models/gamebasics/unit/UnitType.kt @@ -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) + } } \ No newline at end of file