mirror of
https://github.com/yairm210/Unciv.git
synced 2025-07-20 20:59:18 +07:00
Natural Wonders un-hardcoded (#5279)
* Natural Wonders un-hardcoded * Natural Wonders un-hardcoded - oops testing change revert * Natural Wonders un-hardcoded - tests OK * Natural Wonders un-hardcoded - requests * Natural Wonders un-hardcoded - hide from pedia * Natural Wonders un-hardcoded - readable unique
This commit is contained in:
@ -204,6 +204,10 @@
|
|||||||
"gold": 1,
|
"gold": 1,
|
||||||
"science": 2,
|
"science": 2,
|
||||||
"occursOn": ["Ocean"],
|
"occursOn": ["Ocean"],
|
||||||
|
"uniques": ["Must be adjacent to [1] to [6] [Coast] tiles",
|
||||||
|
"Must be adjacent to [6] [Water] tiles",
|
||||||
|
"Occurs on latitudes from [10] to [70] percent of distance equator to pole",
|
||||||
|
"Occurs in groups of [2] to [2] tiles"],
|
||||||
"turnsInto": "Coast",
|
"turnsInto": "Coast",
|
||||||
"impassable": true,
|
"impassable": true,
|
||||||
"unbuildable": true,
|
"unbuildable": true,
|
||||||
@ -215,6 +219,11 @@
|
|||||||
"science": 2,
|
"science": 2,
|
||||||
"happiness": 3,
|
"happiness": 3,
|
||||||
"occursOn": ["Grassland","Plains","Tundra","Mountain"],
|
"occursOn": ["Grassland","Plains","Tundra","Mountain"],
|
||||||
|
"uniques": ["Must be adjacent to [0] [Coast] tiles",
|
||||||
|
"Must be adjacent to [0] to [4] [Mountain] tiles",
|
||||||
|
"Must be adjacent to [3] to [6] [Elevated] tiles",
|
||||||
|
"Must be adjacent to [0] to [3] [Desert] tiles",
|
||||||
|
"Must be adjacent to [0] to [3] [Tundra] tiles"],
|
||||||
"turnsInto": "Mountain",
|
"turnsInto": "Mountain",
|
||||||
"impassable": true,
|
"impassable": true,
|
||||||
"unbuildable": true,
|
"unbuildable": true,
|
||||||
@ -228,7 +237,9 @@
|
|||||||
"turnsInto": "Plains",
|
"turnsInto": "Plains",
|
||||||
"impassable": true,
|
"impassable": true,
|
||||||
"unbuildable": true,
|
"unbuildable": true,
|
||||||
"uniques": ["Grants 500 Gold to the first civilization to discover it"],
|
"uniques": ["Must be adjacent to [0] [Coast] tiles",
|
||||||
|
"Must be adjacent to [1] to [6] [Jungle] tiles",
|
||||||
|
"Grants 500 Gold to the first civilization to discover it"],
|
||||||
"weight": 2
|
"weight": 2
|
||||||
},
|
},
|
||||||
{ // This will count as "Fresh water" in civ 6
|
{ // This will count as "Fresh water" in civ 6
|
||||||
@ -239,7 +250,8 @@
|
|||||||
"turnsInto": "Plains",
|
"turnsInto": "Plains",
|
||||||
"impassable": true,
|
"impassable": true,
|
||||||
"unbuildable": true,
|
"unbuildable": true,
|
||||||
"uniques": ["Grants Rejuvenation (all healing effects doubled) to adjacent military land units for the rest of the game"],
|
"uniques": ["Must be adjacent to [0] [Coast] tiles",
|
||||||
|
"Grants Rejuvenation (all healing effects doubled) to adjacent military land units for the rest of the game"],
|
||||||
"weight": 1
|
"weight": 1
|
||||||
},
|
},
|
||||||
{
|
{
|
||||||
@ -248,6 +260,10 @@
|
|||||||
"production": 2,
|
"production": 2,
|
||||||
"gold": 3,
|
"gold": 3,
|
||||||
"occursOn": ["Plains","Desert","Tundra"],
|
"occursOn": ["Plains","Desert","Tundra"],
|
||||||
|
"uniques": ["Must be adjacent to [0] [Coast] tiles",
|
||||||
|
"Must be adjacent to [0] [Grassland] tiles",
|
||||||
|
"Must be adjacent to [2] to [6] [Hill] tiles",
|
||||||
|
"Must be adjacent to [0] to [2] [Mountain] tiles"],
|
||||||
"turnsInto": "Mountain",
|
"turnsInto": "Mountain",
|
||||||
"impassable": true,
|
"impassable": true,
|
||||||
"unbuildable": true,
|
"unbuildable": true,
|
||||||
@ -260,6 +276,13 @@
|
|||||||
"culture": 3,
|
"culture": 3,
|
||||||
"faith": 3,
|
"faith": 3,
|
||||||
"occursOn": ["Grassland","Plains"],
|
"occursOn": ["Grassland","Plains"],
|
||||||
|
"uniques": ["Must be adjacent to [0] [Coast] tiles",
|
||||||
|
"Must be adjacent to [0] [Tundra] tiles",
|
||||||
|
"Must be adjacent to [0] [Desert] tiles",
|
||||||
|
"Must be adjacent to [0] [Mountain] tiles",
|
||||||
|
"Must be adjacent to [0] [Marsh] tiles",
|
||||||
|
"Must be adjacent to [0] to [2] [Hill] tiles",
|
||||||
|
"Must not be on [1] largest landmasses"],
|
||||||
"turnsInto": "Mountain",
|
"turnsInto": "Mountain",
|
||||||
"impassable": true,
|
"impassable": true,
|
||||||
"unbuildable": true,
|
"unbuildable": true,
|
||||||
@ -270,6 +293,9 @@
|
|||||||
"type": "NaturalWonder",
|
"type": "NaturalWonder",
|
||||||
"science": 5,
|
"science": 5,
|
||||||
"occursOn": ["Ocean"],
|
"occursOn": ["Ocean"],
|
||||||
|
"uniques": ["Must be adjacent to [1] to [6] [Coast] tiles",
|
||||||
|
"Must be adjacent to [0] [Ice] tiles",
|
||||||
|
"Neighboring tiles will convert to [Coast]"],
|
||||||
"turnsInto": "Mountain",
|
"turnsInto": "Mountain",
|
||||||
"impassable": true,
|
"impassable": true,
|
||||||
"unbuildable": true,
|
"unbuildable": true,
|
||||||
@ -281,6 +307,9 @@
|
|||||||
"food": 2,
|
"food": 2,
|
||||||
"gold": 5,
|
"gold": 5,
|
||||||
"occursOn": ["Grassland"],
|
"occursOn": ["Grassland"],
|
||||||
|
"uniques": ["Must be adjacent to [1] to [5] [Coast] tiles",
|
||||||
|
"Must be adjacent to [1] [Mountain] tiles",
|
||||||
|
"Neighboring tiles except [Mountain] will convert to [Coast]"],
|
||||||
"turnsInto": "Mountain",
|
"turnsInto": "Mountain",
|
||||||
"impassable": true,
|
"impassable": true,
|
||||||
"unbuildable": true,
|
"unbuildable": true,
|
||||||
@ -291,6 +320,8 @@
|
|||||||
"type": "NaturalWonder",
|
"type": "NaturalWonder",
|
||||||
"gold": 10,
|
"gold": 10,
|
||||||
"occursOn": ["Plains","Mountain"],
|
"occursOn": ["Plains","Mountain"],
|
||||||
|
"uniques": ["Must be adjacent to [0] [Coast] tiles",
|
||||||
|
"Must be adjacent to [1] to [6] [Hill] tiles"],
|
||||||
"turnsInto": "Mountain",
|
"turnsInto": "Mountain",
|
||||||
"impassable": true,
|
"impassable": true,
|
||||||
"unbuildable": true,
|
"unbuildable": true,
|
||||||
@ -302,17 +333,26 @@
|
|||||||
"gold": 2,
|
"gold": 2,
|
||||||
"science": 3,
|
"science": 3,
|
||||||
"occursOn": ["Desert","Tundra"],
|
"occursOn": ["Desert","Tundra"],
|
||||||
|
"uniques": ["Must be adjacent to [0] [Coast] tiles",
|
||||||
|
"Must be adjacent to [0] [Grassland] tiles",
|
||||||
|
"Must be adjacent to [0] to [2] [Mountain] tiles",
|
||||||
|
"Must be adjacent to [0] to [4] [Elevated] tiles"],
|
||||||
"turnsInto": "Mountain",
|
"turnsInto": "Mountain",
|
||||||
"impassable": true,
|
"impassable": true,
|
||||||
"unbuildable": true,
|
"unbuildable": true,
|
||||||
"weight": 10
|
"weight": 10
|
||||||
},
|
},
|
||||||
|
// G&K Wonders
|
||||||
{
|
{
|
||||||
"name": "Mount Kailash",
|
"name": "Mount Kailash",
|
||||||
"type": "NaturalWonder",
|
"type": "NaturalWonder",
|
||||||
"faith": 6,
|
"faith": 6,
|
||||||
"happiness": 2,
|
"happiness": 2,
|
||||||
"occursOn": ["Plains","Grassland"],
|
"occursOn": ["Plains","Grassland"],
|
||||||
|
"uniques": ["Must be adjacent to [0] [Coast] tiles",
|
||||||
|
"Must be adjacent to [0] [Marsh] tiles",
|
||||||
|
"Must be adjacent to [0] to [1] [Desert] tiles",
|
||||||
|
"Must be adjacent to [4] to [6] [Elevated] tiles"],
|
||||||
"turnsInto": "Mountain",
|
"turnsInto": "Mountain",
|
||||||
"impassable": true,
|
"impassable": true,
|
||||||
"unbuildable": true,
|
"unbuildable": true,
|
||||||
@ -323,6 +363,11 @@
|
|||||||
"type": "NaturalWonder",
|
"type": "NaturalWonder",
|
||||||
"faith": 8,
|
"faith": 8,
|
||||||
"occursOn": ["Desert","Plains"],
|
"occursOn": ["Desert","Plains"],
|
||||||
|
"uniques": ["Must be adjacent to [0] [Coast] tiles",
|
||||||
|
"Must be adjacent to [0] [Grassland] tiles",
|
||||||
|
"Must be adjacent to [0] [Tundra] tiles",
|
||||||
|
"Must be adjacent to [0] [Marsh] tiles",
|
||||||
|
"Must be adjacent to [3] to [6] [Desert] tiles"],
|
||||||
"turnsInto": "Mountain",
|
"turnsInto": "Mountain",
|
||||||
"impassable": true,
|
"impassable": true,
|
||||||
"unbuildable": true,
|
"unbuildable": true,
|
||||||
@ -335,6 +380,10 @@
|
|||||||
"faith": 4,
|
"faith": 4,
|
||||||
"happiness": 2,
|
"happiness": 2,
|
||||||
"occursOn": ["Plains","Grassland"],
|
"occursOn": ["Plains","Grassland"],
|
||||||
|
"uniques": ["Must be adjacent to [0] [Tundra] tiles",
|
||||||
|
"Must be adjacent to [0] [Desert] tiles",
|
||||||
|
"Must be adjacent to [0] [Marsh] tiles",
|
||||||
|
"Must not be on [1] largest landmasses"],
|
||||||
"turnsInto": "Mountain",
|
"turnsInto": "Mountain",
|
||||||
"impassable": true,
|
"impassable": true,
|
||||||
"unbuildable": true,
|
"unbuildable": true,
|
||||||
@ -346,6 +395,11 @@
|
|||||||
"food": 2,
|
"food": 2,
|
||||||
"faith": 6,
|
"faith": 6,
|
||||||
"occursOn": ["Plains","Desert"],
|
"occursOn": ["Plains","Desert"],
|
||||||
|
"uniques": ["Must be adjacent to [0] [Coast] tiles",
|
||||||
|
"Must be adjacent to [0] [Grassland] tiles",
|
||||||
|
"Must be adjacent to [0] [Tundra] tiles",
|
||||||
|
"Must be adjacent to [0] [Marsh] tiles",
|
||||||
|
"Must be adjacent to [3] to [6] [Plains] tiles"],
|
||||||
"turnsInto": "Mountain",
|
"turnsInto": "Mountain",
|
||||||
"impassable": true,
|
"impassable": true,
|
||||||
"unbuildable": true,
|
"unbuildable": true,
|
||||||
@ -358,6 +412,8 @@
|
|||||||
"type": "NaturalWonder",
|
"type": "NaturalWonder",
|
||||||
"production": 6,
|
"production": 6,
|
||||||
"occursOn": ["Plains","Desert"],
|
"occursOn": ["Plains","Desert"],
|
||||||
|
"uniques": ["Must be adjacent to [0] [Coast] tiles",
|
||||||
|
"Must be adjacent to [0] to [2] [Mountain] tiles"],
|
||||||
"turnsInto": "Plains",
|
"turnsInto": "Plains",
|
||||||
"impassable": true,
|
"impassable": true,
|
||||||
"unbuildable": true,
|
"unbuildable": true,
|
||||||
@ -368,6 +424,7 @@
|
|||||||
"type": "NaturalWonder",
|
"type": "NaturalWonder",
|
||||||
"food": 6,
|
"food": 6,
|
||||||
"occursOn": ["Plains"],
|
"occursOn": ["Plains"],
|
||||||
|
"uniques": ["Must be adjacent to [0] [Coast] tiles"],
|
||||||
"turnsInto": "Mountain",
|
"turnsInto": "Mountain",
|
||||||
"impassable": true,
|
"impassable": true,
|
||||||
"unbuildable": true,
|
"unbuildable": true,
|
||||||
@ -383,7 +440,10 @@
|
|||||||
"turnsInto": "Mountain",
|
"turnsInto": "Mountain",
|
||||||
"impassable": true,
|
"impassable": true,
|
||||||
"unbuildable": true,
|
"unbuildable": true,
|
||||||
"uniques": ["Grants Altitude Training (double movement and +10% Strength in hills) to adjacent land units for the rest of the game"], //ToDo
|
"uniques": ["Must be adjacent to [0] [Coast] tiles",
|
||||||
|
"Must be adjacent to [2] to [6] [Hill] tiles",
|
||||||
|
"Must be adjacent to [0] to [2] [Mountain] tiles",
|
||||||
|
"Grants Altitude Training (double movement and +10% Strength in hills) to adjacent land units for the rest of the game"], //ToDo
|
||||||
"weight": 10
|
"weight": 10
|
||||||
}
|
}
|
||||||
*/
|
*/
|
||||||
|
@ -84,8 +84,8 @@ object GameStarter {
|
|||||||
addCivStats(gameInfo)
|
addCivStats(gameInfo)
|
||||||
}
|
}
|
||||||
|
|
||||||
runAndMeasure("assignContinents?") {
|
|
||||||
if (tileMap.continentSizes.isEmpty()) // Probably saved map without continent data
|
if (tileMap.continentSizes.isEmpty()) // Probably saved map without continent data
|
||||||
|
runAndMeasure("assignContinents") {
|
||||||
mapGen.assignContinents(tileMap)
|
mapGen.assignContinents(tileMap)
|
||||||
}
|
}
|
||||||
|
|
||||||
|
@ -23,13 +23,10 @@ class BFS(
|
|||||||
tilesReached[startingPoint] = startingPoint
|
tilesReached[startingPoint] = startingPoint
|
||||||
}
|
}
|
||||||
|
|
||||||
/** Process fully until there's nowhere left to check
|
/** Process fully until there's nowhere left to check */
|
||||||
* Optionally assigns a continent ID as it goes */
|
fun stepToEnd() {
|
||||||
fun stepToEnd(continent: Int? = null) {
|
|
||||||
if (continent != null)
|
|
||||||
startingPoint.setContinent(continent)
|
|
||||||
while (!hasEnded())
|
while (!hasEnded())
|
||||||
nextStep(continent)
|
nextStep()
|
||||||
}
|
}
|
||||||
|
|
||||||
/**
|
/**
|
||||||
@ -49,15 +46,13 @@ class BFS(
|
|||||||
*
|
*
|
||||||
* Will do nothing when [hasEnded] returns `true`
|
* Will do nothing when [hasEnded] returns `true`
|
||||||
*/
|
*/
|
||||||
fun nextStep(continent: Int? = null) {
|
fun nextStep() {
|
||||||
if (tilesReached.size >= maxSize) { tilesToCheck.clear(); return }
|
if (tilesReached.size >= maxSize) { tilesToCheck.clear(); return }
|
||||||
val current = tilesToCheck.removeFirstOrNull() ?: return
|
val current = tilesToCheck.removeFirstOrNull() ?: return
|
||||||
for (neighbor in current.neighbors) {
|
for (neighbor in current.neighbors) {
|
||||||
if (neighbor !in tilesReached && predicate(neighbor)) {
|
if (neighbor !in tilesReached && predicate(neighbor)) {
|
||||||
tilesReached[neighbor] = current
|
tilesReached[neighbor] = current
|
||||||
tilesToCheck.add(neighbor)
|
tilesToCheck.add(neighbor)
|
||||||
if (continent != null)
|
|
||||||
neighbor.setContinent(continent)
|
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
@ -778,7 +778,13 @@ open class TileInfo {
|
|||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
// Should only be set once at map generation
|
/**
|
||||||
|
* Assign a continent ID to this tile.
|
||||||
|
*
|
||||||
|
* Should only be set once at map generation.
|
||||||
|
* @param continent Numeric ID >= 0
|
||||||
|
* @throws Exception when tile already has a continent ID
|
||||||
|
*/
|
||||||
fun setContinent(continent: Int) {
|
fun setContinent(continent: Int) {
|
||||||
if (this.continent != -1)
|
if (this.continent != -1)
|
||||||
throw Exception("Continent already assigned @ $position")
|
throw Exception("Continent already assigned @ $position")
|
||||||
|
@ -464,8 +464,10 @@ class MapGenerator(val ruleset: Ruleset) {
|
|||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
// Set a continent id for each tile, so we can quickly see which tiles are connected.
|
/** Set a continent id for each tile, so we can quickly see which tiles are connected.
|
||||||
// Can also be called on saved maps
|
* Can also be called on saved maps.
|
||||||
|
* @throws Exception when any land tile already has a continent ID
|
||||||
|
*/
|
||||||
fun assignContinents(tileMap: TileMap) {
|
fun assignContinents(tileMap: TileMap) {
|
||||||
var landTiles = tileMap.values
|
var landTiles = tileMap.values
|
||||||
.filter { it.isLand && !it.isImpassible()}
|
.filter { it.isLand && !it.isImpassible()}
|
||||||
@ -473,7 +475,10 @@ class MapGenerator(val ruleset: Ruleset) {
|
|||||||
|
|
||||||
while (landTiles.any()) {
|
while (landTiles.any()) {
|
||||||
val bfs = BFS(landTiles.random()) { it.isLand && !it.isImpassible() }
|
val bfs = BFS(landTiles.random()) { it.isLand && !it.isImpassible() }
|
||||||
bfs.stepToEnd(currentContinent)
|
bfs.stepToEnd()
|
||||||
|
bfs.getReachedTiles().forEach {
|
||||||
|
it.setContinent(currentContinent)
|
||||||
|
}
|
||||||
val continent = bfs.getReachedTiles()
|
val continent = bfs.getReachedTiles()
|
||||||
tileMap.continentSizes[currentContinent] = continent.size
|
tileMap.continentSizes[currentContinent] = continent.size
|
||||||
if (continent.size > 20) {
|
if (continent.size > 20) {
|
||||||
|
@ -6,11 +6,17 @@ import com.unciv.logic.map.TileMap
|
|||||||
import com.unciv.models.ruleset.Ruleset
|
import com.unciv.models.ruleset.Ruleset
|
||||||
import com.unciv.models.ruleset.tile.Terrain
|
import com.unciv.models.ruleset.tile.Terrain
|
||||||
import com.unciv.models.ruleset.tile.TerrainType
|
import com.unciv.models.ruleset.tile.TerrainType
|
||||||
|
import com.unciv.models.ruleset.unique.Unique
|
||||||
|
import com.unciv.models.ruleset.unique.UniqueType
|
||||||
import kotlin.math.abs
|
import kotlin.math.abs
|
||||||
import kotlin.math.round
|
import kotlin.math.round
|
||||||
|
|
||||||
class NaturalWonderGenerator(val ruleset: Ruleset, val randomness: MapGenerationRandomness) {
|
class NaturalWonderGenerator(val ruleset: Ruleset, val randomness: MapGenerationRandomness) {
|
||||||
|
|
||||||
|
private val allTerrainFeatures = ruleset.terrains.values
|
||||||
|
.filter { it.type == TerrainType.TerrainFeature }
|
||||||
|
.map { it.name }.toSet()
|
||||||
|
|
||||||
/*
|
/*
|
||||||
https://gaming.stackexchange.com/questions/95095/do-natural-wonders-spawn-more-closely-to-city-states/96479
|
https://gaming.stackexchange.com/questions/95095/do-natural-wonders-spawn-more-closely-to-city-states/96479
|
||||||
https://www.reddit.com/r/civ/comments/1jae5j/information_on_the_occurrence_of_natural_wonders/
|
https://www.reddit.com/r/civ/comments/1jae5j/information_on_the_occurrence_of_natural_wonders/
|
||||||
@ -22,18 +28,19 @@ class NaturalWonderGenerator(val ruleset: Ruleset, val randomness: MapGeneration
|
|||||||
// number of Natural Wonders scales linearly with mapRadius as #wonders = mapRadius * 0.13133208 - 0.56128831
|
// number of Natural Wonders scales linearly with mapRadius as #wonders = mapRadius * 0.13133208 - 0.56128831
|
||||||
val numberToSpawn = round(mapRadius * 0.13133208f - 0.56128831f).toInt()
|
val numberToSpawn = round(mapRadius * 0.13133208f - 0.56128831f).toInt()
|
||||||
|
|
||||||
val toBeSpawned = ArrayList<Terrain>()
|
val spawned = mutableListOf<Terrain>()
|
||||||
val allNaturalWonders = ruleset.terrains.values
|
val allNaturalWonders = ruleset.terrains.values
|
||||||
.filter { it.type == TerrainType.NaturalWonder }.toMutableList()
|
.filter { it.type == TerrainType.NaturalWonder }.toMutableList()
|
||||||
|
|
||||||
while (allNaturalWonders.isNotEmpty() && toBeSpawned.size < numberToSpawn) {
|
while (allNaturalWonders.isNotEmpty() && spawned.size < numberToSpawn) {
|
||||||
val totalWeight = allNaturalWonders.map { it.weight }.sum().toFloat()
|
val totalWeight = allNaturalWonders.sumOf { it.weight }.toFloat()
|
||||||
val random = randomness.RNG.nextDouble()
|
val random = randomness.RNG.nextDouble()
|
||||||
var sum = 0f
|
var sum = 0f
|
||||||
for (wonder in allNaturalWonders) {
|
for (wonder in allNaturalWonders) {
|
||||||
sum += wonder.weight / totalWeight
|
sum += wonder.weight / totalWeight
|
||||||
if (random <= sum) {
|
if (random <= sum) {
|
||||||
toBeSpawned.add(wonder)
|
if (spawnSpecificWonder(tileMap, wonder))
|
||||||
|
spawned.add(wonder)
|
||||||
allNaturalWonders.remove(wonder)
|
allNaturalWonders.remove(wonder)
|
||||||
break
|
break
|
||||||
}
|
}
|
||||||
@ -41,391 +48,183 @@ class NaturalWonderGenerator(val ruleset: Ruleset, val randomness: MapGeneration
|
|||||||
}
|
}
|
||||||
|
|
||||||
if (MapGenerator.consoleOutput)
|
if (MapGenerator.consoleOutput)
|
||||||
println("Natural Wonders for this game: $toBeSpawned")
|
println("Natural Wonders for this game: $spawned")
|
||||||
|
}
|
||||||
|
|
||||||
for (wonder in toBeSpawned) {
|
private fun Unique.getIntParam(index: Int) = params[index].toInt()
|
||||||
when (wonder.name) {
|
|
||||||
Constants.barringerCrater -> spawnBarringerCrater(tileMap)
|
private fun spawnSpecificWonder(tileMap: TileMap, wonder: Terrain): Boolean {
|
||||||
Constants.mountFuji -> spawnMountFuji(tileMap)
|
val suitableLocations = tileMap.values.filter { tile->
|
||||||
Constants.grandMesa -> spawnGrandMesa(tileMap)
|
tile.resource == null &&
|
||||||
Constants.greatBarrierReef -> spawnGreatBarrierReef(tileMap)
|
wonder.occursOn.contains(tile.getLastTerrain().name) &&
|
||||||
Constants.krakatoa -> spawnKrakatoa(tileMap)
|
wonder.uniqueObjects.all { unique ->
|
||||||
Constants.rockOfGibraltar -> spawnRockOfGibraltar(tileMap)
|
when (unique.type) {
|
||||||
Constants.oldFaithful -> spawnOldFaithful(tileMap)
|
UniqueType.NaturalWonderNeighborCount -> {
|
||||||
Constants.cerroDePotosi -> spawnCerroDePotosi(tileMap)
|
val count = tile.neighbors.count {
|
||||||
Constants.elDorado -> spawnElDorado(tileMap)
|
it.matchesWonderFilter(unique.params[1])
|
||||||
Constants.fountainOfYouth -> spawnFountainOfYouth(tileMap)
|
}
|
||||||
Constants.mountKailash -> spawnMountKailash(tileMap)
|
count == unique.getIntParam(0)
|
||||||
Constants.mountSinai -> spawnMountSinai(tileMap)
|
}
|
||||||
Constants.sriPada -> spawnSriPada(tileMap)
|
UniqueType.NaturalWonderNeighborsRange -> {
|
||||||
Constants.uluru -> spawnUluru(tileMap)
|
val count = tile.neighbors.count {
|
||||||
/*
|
it.matchesWonderFilter(unique.params[2])
|
||||||
Constants.kingSolomonsMines -> spawnSolomonMines(tileMap)
|
}
|
||||||
Constants.lakeVictoria -> spawnLakeVictoria(tileMap)
|
count in unique.getIntParam(0)..unique.getIntParam(1)
|
||||||
Constants.mountKilimanjaro -> spawnMountKilimanjaro(tileMap)
|
}
|
||||||
*/
|
UniqueType.NaturalWonderLandmass -> {
|
||||||
|
val sortedContinents = tileMap.continentSizes.asSequence()
|
||||||
|
.sortedByDescending { it.value }
|
||||||
|
.map { it.key }
|
||||||
|
.toList()
|
||||||
|
tile.getContinent() !in sortedContinents.take(unique.getIntParam(0))
|
||||||
|
}
|
||||||
|
UniqueType.NaturalWonderLatitude -> {
|
||||||
|
val lower = tileMap.maxLatitude * unique.getIntParam(0) * 0.01f
|
||||||
|
val upper = tileMap.maxLatitude * unique.getIntParam(1) * 0.01f
|
||||||
|
abs(tile.latitude) in lower..upper
|
||||||
|
}
|
||||||
|
else -> true
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
private fun trySpawnOnSuitableLocation(suitableLocations: List<TileInfo>, wonder: Terrain): TileInfo? {
|
return trySpawnOnSuitableLocation(suitableLocations, wonder)
|
||||||
if (suitableLocations.isNotEmpty()) {
|
}
|
||||||
|
|
||||||
|
private fun trySpawnOnSuitableLocation(suitableLocations: List<TileInfo>, wonder: Terrain): Boolean {
|
||||||
|
val minGroupSize: Int
|
||||||
|
val maxGroupSize: Int
|
||||||
|
val groupUnique = wonder.getMatchingUniques(UniqueType.NaturalWonderGroups).firstOrNull()
|
||||||
|
if (groupUnique == null) {
|
||||||
|
minGroupSize = 1
|
||||||
|
maxGroupSize = 1
|
||||||
|
} else {
|
||||||
|
minGroupSize = groupUnique.getIntParam(0)
|
||||||
|
maxGroupSize = groupUnique.getIntParam(1)
|
||||||
|
}
|
||||||
|
val targetGroupSize = if (minGroupSize == maxGroupSize) maxGroupSize
|
||||||
|
else (minGroupSize..maxGroupSize).random(randomness.RNG)
|
||||||
|
|
||||||
|
var convertNeighborsExcept: String? = null
|
||||||
|
var convertUnique = wonder.getMatchingUniques(UniqueType.NaturalWonderConvertNeighbors).firstOrNull()
|
||||||
|
var convertNeighborsTo = convertUnique?.params?.get(0)
|
||||||
|
if (convertNeighborsTo == null) {
|
||||||
|
convertUnique = wonder.getMatchingUniques(UniqueType.NaturalWonderConvertNeighborsExcept).firstOrNull()
|
||||||
|
convertNeighborsExcept = convertUnique?.params?.get(0)
|
||||||
|
convertNeighborsTo = convertUnique?.params?.get(1)
|
||||||
|
}
|
||||||
|
|
||||||
|
if (suitableLocations.size >= minGroupSize) {
|
||||||
val location = suitableLocations.random(randomness.RNG)
|
val location = suitableLocations.random(randomness.RNG)
|
||||||
clearTile(location)
|
val list = mutableListOf(location)
|
||||||
location.naturalWonder = wonder.name
|
while (list.size < targetGroupSize) {
|
||||||
location.baseTerrain = wonder.turnsInto!!
|
val allNeighbors = list.flatMap { it.neighbors }.minus(list).toHashSet()
|
||||||
return location
|
val candidates = suitableLocations.filter { it in allNeighbors }
|
||||||
|
if (candidates.isEmpty()) break
|
||||||
|
list.add(candidates.random(randomness.RNG))
|
||||||
}
|
}
|
||||||
|
if (list.size >= minGroupSize) {
|
||||||
if (MapGenerator.consoleOutput)
|
list.forEach {
|
||||||
println("No suitable location for ${wonder.name}")
|
clearTile(it)
|
||||||
return null
|
it.naturalWonder = wonder.name
|
||||||
|
it.baseTerrain = wonder.turnsInto!!
|
||||||
}
|
}
|
||||||
|
if (convertNeighborsTo != null) {
|
||||||
|
|
||||||
/*
|
|
||||||
Barringer Crater: Must be in tundra or desert; cannot be adjacent to grassland; can be adjacent to a maximum
|
|
||||||
of 2 mountains and a maximum of 4 hills and mountains; avoids oceans; becomes mountain
|
|
||||||
*/
|
|
||||||
private fun spawnBarringerCrater(tileMap: TileMap) {
|
|
||||||
val wonder = ruleset.terrains[Constants.barringerCrater]!!
|
|
||||||
val suitableLocations = tileMap.values.filter {
|
|
||||||
it.resource == null
|
|
||||||
&& wonder.occursOn.contains(it.getLastTerrain().name)
|
|
||||||
&& it.neighbors.none { neighbor -> neighbor.getBaseTerrain().name == Constants.grassland }
|
|
||||||
&& it.neighbors.none { neighbor -> neighbor.getBaseTerrain().name == Constants.coast }
|
|
||||||
&& it.neighbors.count { neighbor -> neighbor.getBaseTerrain().name == Constants.mountain } <= 2
|
|
||||||
&& it.neighbors.count { neighbor -> neighbor.getBaseTerrain().name == Constants.mountain || neighbor.isHill() } <= 4
|
|
||||||
}
|
|
||||||
|
|
||||||
trySpawnOnSuitableLocation(suitableLocations, wonder)
|
|
||||||
}
|
|
||||||
|
|
||||||
/*
|
|
||||||
Mt. Fuji: Must be in grass or plains; avoids oceans and the biggest landmass; cannot be adjacent to tundra,
|
|
||||||
desert, marsh, or mountains;can be adjacent to a maximum of 2 hills; becomes mountain
|
|
||||||
// ToDo: avoids the biggest landmass
|
|
||||||
*/
|
|
||||||
private fun spawnMountFuji(tileMap: TileMap) {
|
|
||||||
val wonder = ruleset.terrains[Constants.mountFuji]!!
|
|
||||||
val suitableLocations = tileMap.values.filter {
|
|
||||||
it.resource == null
|
|
||||||
&& wonder.occursOn.contains(it.getLastTerrain().name)
|
|
||||||
&& it.neighbors.none { neighbor -> neighbor.getBaseTerrain().name == Constants.tundra }
|
|
||||||
&& it.neighbors.none { neighbor -> neighbor.getBaseTerrain().name == Constants.desert }
|
|
||||||
&& it.neighbors.none { neighbor -> neighbor.getBaseTerrain().name == Constants.coast }
|
|
||||||
&& it.neighbors.none { neighbor -> neighbor.getBaseTerrain().name == Constants.mountain }
|
|
||||||
&& it.neighbors.none { neighbor -> neighbor.getLastTerrain().name == Constants.marsh }
|
|
||||||
&& it.neighbors.count { neighbor -> neighbor.isHill() } <= 2
|
|
||||||
}
|
|
||||||
|
|
||||||
trySpawnOnSuitableLocation(suitableLocations, wonder)
|
|
||||||
}
|
|
||||||
|
|
||||||
/*
|
|
||||||
Grand Mesa: Must be in plains, desert, or tundra, and must be adjacent to at least 2 hills;
|
|
||||||
cannot be adjacent to grass; can be adjacent to a maximum of 2 mountains; avoids oceans; becomes mountain
|
|
||||||
*/
|
|
||||||
private fun spawnGrandMesa(tileMap: TileMap) {
|
|
||||||
val wonder = ruleset.terrains[Constants.grandMesa]!!
|
|
||||||
val suitableLocations = tileMap.values.filter {
|
|
||||||
it.resource == null
|
|
||||||
&& wonder.occursOn.contains(it.getLastTerrain().name)
|
|
||||||
&& it.neighbors.count { neighbor -> neighbor.isHill() } >= 2
|
|
||||||
&& it.neighbors.none { neighbor -> neighbor.getBaseTerrain().name == Constants.coast }
|
|
||||||
&& it.neighbors.none { neighbor -> neighbor.getBaseTerrain().name == Constants.grassland }
|
|
||||||
&& it.neighbors.count { neighbor -> neighbor.getBaseTerrain().name == Constants.mountain } <= 2
|
|
||||||
}
|
|
||||||
|
|
||||||
trySpawnOnSuitableLocation(suitableLocations, wonder)
|
|
||||||
}
|
|
||||||
|
|
||||||
/*
|
|
||||||
Great Barrier Reef: Specifics currently unknown;
|
|
||||||
Assumption: at least 1 neighbour coast; no tundra; at least 1 neighbour coast; becomes coast
|
|
||||||
*/
|
|
||||||
private fun spawnGreatBarrierReef(tileMap: TileMap) {
|
|
||||||
val wonder = ruleset.terrains[Constants.greatBarrierReef]!!
|
|
||||||
val suitableLocations = tileMap.values.filter {
|
|
||||||
it.resource == null
|
|
||||||
&& wonder.occursOn.contains(it.getLastTerrain().name)
|
|
||||||
&& abs(it.latitude) > tileMap.maxLatitude * 0.1
|
|
||||||
&& abs(it.latitude) < tileMap.maxLatitude * 0.7
|
|
||||||
&& it.neighbors.any { it.baseTerrain == Constants.coast }
|
|
||||||
&& it.neighbors.all { neighbor -> neighbor.isWater }
|
|
||||||
&& it.neighbors.any { neighbor ->
|
|
||||||
neighbor.resource == null && neighbor.improvement == null
|
|
||||||
&& wonder.occursOn.contains(neighbor.getLastTerrain().name)
|
|
||||||
&& neighbor.neighbors.all { it.isWater }
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
val location = trySpawnOnSuitableLocation(suitableLocations, wonder)
|
|
||||||
if (location != null) {
|
|
||||||
val possibleLocations = location.neighbors
|
|
||||||
.filter {
|
|
||||||
it.resource == null
|
|
||||||
&& wonder.occursOn.contains(it.getLastTerrain().name)
|
|
||||||
&& it.neighbors.all { it.isWater }
|
|
||||||
}.toList()
|
|
||||||
trySpawnOnSuitableLocation(possibleLocations, wonder)
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
/*
|
|
||||||
Krakatoa: Must spawn in the ocean next to at least 1 shallow water tile; cannot be adjacent
|
|
||||||
to ice; changes tiles around it to shallow water; mountain
|
|
||||||
*/
|
|
||||||
private fun spawnKrakatoa(tileMap: TileMap) {
|
|
||||||
val wonder = ruleset.terrains[Constants.krakatoa]!!
|
|
||||||
val suitableLocations = tileMap.values.filter {
|
|
||||||
it.resource == null
|
|
||||||
&& wonder.occursOn.contains(it.getLastTerrain().name)
|
|
||||||
&& it.neighbors.any { neighbor -> neighbor.getBaseTerrain().name == Constants.coast }
|
|
||||||
&& it.neighbors.none { neighbor -> neighbor.getLastTerrain().name == Constants.ice }
|
|
||||||
}
|
|
||||||
|
|
||||||
val location = trySpawnOnSuitableLocation(suitableLocations, wonder)
|
|
||||||
if (location != null) {
|
|
||||||
for (tile in location.neighbors) {
|
for (tile in location.neighbors) {
|
||||||
if (tile.baseTerrain == Constants.coast) continue
|
if (tile.baseTerrain == convertNeighborsTo) continue
|
||||||
tile.baseTerrain = Constants.coast
|
if (tile.baseTerrain == convertNeighborsExcept) continue
|
||||||
clearTile(tile)
|
if (convertNeighborsTo == Constants.coast)
|
||||||
}
|
for (neighbor in tile.neighbors) {
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
/*
|
|
||||||
Rock of Gibraltar: Specifics currently unknown
|
|
||||||
Assumption: spawn on grassland, at least 1 coast and 1 mountain adjacent;
|
|
||||||
turn neighbours into coast)
|
|
||||||
*/
|
|
||||||
private fun spawnRockOfGibraltar(tileMap: TileMap) {
|
|
||||||
val wonder = ruleset.terrains[Constants.rockOfGibraltar]!!
|
|
||||||
val suitableLocations = tileMap.values.filter {
|
|
||||||
it.resource == null
|
|
||||||
&& wonder.occursOn.contains(it.getLastTerrain().name)
|
|
||||||
&& it.neighbors.any { neighbor -> neighbor.getBaseTerrain().name == Constants.coast }
|
|
||||||
&& it.neighbors.count { neighbor -> neighbor.getBaseTerrain().name == Constants.mountain } == 1
|
|
||||||
}
|
|
||||||
|
|
||||||
val location = trySpawnOnSuitableLocation(suitableLocations, wonder)
|
|
||||||
if (location != null) {
|
|
||||||
for (tile in location.neighbors) {
|
|
||||||
if (tile.baseTerrain == Constants.coast) continue
|
|
||||||
if (tile.baseTerrain == Constants.mountain) continue
|
|
||||||
for (neighbor in tile.neighbors)
|
|
||||||
// This is so we don't have this tile turn into Coast, and then it's touching a Lake tile.
|
// This is so we don't have this tile turn into Coast, and then it's touching a Lake tile.
|
||||||
// We just turn the lake tiles into this kind of tile.
|
// We just turn the lake tiles into this kind of tile.
|
||||||
if (neighbor.baseTerrain == Constants.lakes) {
|
if (neighbor.baseTerrain == Constants.lakes) {
|
||||||
neighbor.baseTerrain = tile.baseTerrain
|
neighbor.baseTerrain = tile.baseTerrain
|
||||||
neighbor.setTerrainTransients()
|
neighbor.setTerrainTransients()
|
||||||
}
|
}
|
||||||
|
}
|
||||||
tile.baseTerrain = Constants.coast
|
tile.baseTerrain = convertNeighborsTo
|
||||||
clearTile(tile)
|
clearTile(tile)
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
if (MapGenerator.consoleOutput)
|
||||||
|
println("Natural Wonder ${wonder.name} @${location.position}")
|
||||||
|
|
||||||
|
return true
|
||||||
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
/*
|
if (MapGenerator.consoleOutput)
|
||||||
Old Faithful: Must be adjacent to at least 3 hills and mountains; cannot be adjacent to
|
println("No suitable location for ${wonder.name}")
|
||||||
more than 4 mountains, and cannot be adjacent to more than 3 desert or 3 tundra tiles;
|
return false
|
||||||
avoids oceans; becomes mountain
|
|
||||||
*/
|
|
||||||
private fun spawnOldFaithful(tileMap: TileMap) {
|
|
||||||
val wonder = ruleset.terrains[Constants.oldFaithful]!!
|
|
||||||
val suitableLocations = tileMap.values.filter {
|
|
||||||
it.resource == null
|
|
||||||
&& wonder.occursOn.contains(it.getLastTerrain().name)
|
|
||||||
&& it.neighbors.none { neighbor -> neighbor.getBaseTerrain().name == Constants.coast }
|
|
||||||
&& it.neighbors.count { neighbor -> neighbor.getBaseTerrain().name == Constants.mountain } <= 4
|
|
||||||
&& it.neighbors.count { neighbor ->
|
|
||||||
neighbor.getBaseTerrain().name == Constants.mountain ||
|
|
||||||
neighbor.isHill()
|
|
||||||
} >= 3
|
|
||||||
&& it.neighbors.count { neighbor -> neighbor.getBaseTerrain().name == Constants.desert } <= 3
|
|
||||||
&& it.neighbors.count { neighbor -> neighbor.getBaseTerrain().name == Constants.tundra } <= 3
|
|
||||||
}
|
}
|
||||||
|
|
||||||
trySpawnOnSuitableLocation(suitableLocations, wonder)
|
|
||||||
}
|
|
||||||
|
|
||||||
/*
|
|
||||||
Cerro de Potosi: Must be adjacent to at least 1 hill; avoids oceans; becomes mountain
|
|
||||||
*/
|
|
||||||
private fun spawnCerroDePotosi(tileMap: TileMap) {
|
|
||||||
val wonder = ruleset.terrains[Constants.cerroDePotosi]!!
|
|
||||||
val suitableLocations = tileMap.values.filter {
|
|
||||||
it.resource == null
|
|
||||||
&& wonder.occursOn.contains(it.getLastTerrain().name)
|
|
||||||
&& it.neighbors.none { neighbor -> neighbor.getBaseTerrain().name == Constants.coast }
|
|
||||||
&& it.neighbors.any { neighbor -> neighbor.isHill() }
|
|
||||||
}
|
|
||||||
|
|
||||||
trySpawnOnSuitableLocation(suitableLocations, wonder)
|
|
||||||
}
|
|
||||||
|
|
||||||
/*
|
|
||||||
El Dorado: Must be next to at least 1 jungle tile; avoids oceans; becomes flatland plains
|
|
||||||
*/
|
|
||||||
private fun spawnElDorado(tileMap: TileMap) {
|
|
||||||
val wonder = ruleset.terrains[Constants.elDorado]!!
|
|
||||||
val suitableLocations = tileMap.values.filter {
|
|
||||||
it.resource == null
|
|
||||||
&& wonder.occursOn.contains(it.getLastTerrain().name)
|
|
||||||
&& it.neighbors.none { neighbor -> neighbor.getBaseTerrain().name == Constants.coast }
|
|
||||||
&& it.neighbors.any { neighbor -> neighbor.getLastTerrain().name == Constants.jungle }
|
|
||||||
}
|
|
||||||
|
|
||||||
trySpawnOnSuitableLocation(suitableLocations, wonder)
|
|
||||||
}
|
|
||||||
|
|
||||||
/*
|
|
||||||
Fountain of Youth: Avoids oceans; becomes flatland plains
|
|
||||||
*/
|
|
||||||
private fun spawnFountainOfYouth(tileMap: TileMap) {
|
|
||||||
val wonder = ruleset.terrains[Constants.fountainOfYouth]!!
|
|
||||||
val suitableLocations = tileMap.values.filter {
|
|
||||||
it.resource == null
|
|
||||||
&& wonder.occursOn.contains(it.getLastTerrain().name)
|
|
||||||
&& it.neighbors.none { neighbor -> neighbor.getBaseTerrain().name == Constants.coast }
|
|
||||||
}
|
|
||||||
|
|
||||||
trySpawnOnSuitableLocation(suitableLocations, wonder)
|
|
||||||
}
|
|
||||||
|
|
||||||
// G&K Natural Wonders
|
|
||||||
|
|
||||||
/*
|
|
||||||
Mount Kailash: Must be in plains or grassland, and must be adjacent to at least 4 hills and/or mountains;
|
|
||||||
cannot be adjacent to marshes; can be adjacent to a maximum of 1 desert tile; avoids oceans; becomes mountain
|
|
||||||
*/
|
|
||||||
private fun spawnMountKailash(tileMap: TileMap) {
|
|
||||||
val wonder = ruleset.terrains[Constants.mountKailash]!!
|
|
||||||
val suitableLocations = tileMap.values.filter {
|
|
||||||
it.resource == null
|
|
||||||
&& wonder.occursOn.contains(it.getLastTerrain().name)
|
|
||||||
&& it.neighbors.none { neighbor -> neighbor.getBaseTerrain().name == Constants.marsh }
|
|
||||||
&& it.neighbors.none { neighbor -> neighbor.getBaseTerrain().name == Constants.coast }
|
|
||||||
&& it.neighbors.count { neighbor -> neighbor.getBaseTerrain().name == Constants.mountain || neighbor.isHill() } >= 4
|
|
||||||
&& it.neighbors.count { neighbor -> neighbor.getBaseTerrain().name == Constants.desert} <= 1
|
|
||||||
}
|
|
||||||
|
|
||||||
trySpawnOnSuitableLocation(suitableLocations, wonder)
|
|
||||||
}
|
|
||||||
|
|
||||||
/*
|
|
||||||
Mount Sinai: Must be in plains or desert, and must be adjacent to a minimum of 3 desert tiles;
|
|
||||||
cannot be adjacent to tundra, marshes, or grassland; avoids oceans; becomes mountain
|
|
||||||
*/
|
|
||||||
private fun spawnMountSinai(tileMap: TileMap) {
|
|
||||||
val wonder = ruleset.terrains[Constants.mountSinai]!!
|
|
||||||
val suitableLocations = tileMap.values.filter {
|
|
||||||
it.resource == null
|
|
||||||
&& wonder.occursOn.contains(it.getLastTerrain().name)
|
|
||||||
&& it.neighbors.none { neighbor -> neighbor.getBaseTerrain().name == Constants.marsh }
|
|
||||||
&& it.neighbors.none { neighbor -> neighbor.getBaseTerrain().name == Constants.tundra }
|
|
||||||
&& it.neighbors.none { neighbor -> neighbor.getBaseTerrain().name == Constants.grassland }
|
|
||||||
&& it.neighbors.none { neighbor -> neighbor.getBaseTerrain().name == Constants.coast }
|
|
||||||
&& it.neighbors.count { neighbor -> neighbor.getBaseTerrain().name == Constants.desert } >= 3
|
|
||||||
}
|
|
||||||
|
|
||||||
trySpawnOnSuitableLocation(suitableLocations, wonder)
|
|
||||||
}
|
|
||||||
|
|
||||||
/*
|
|
||||||
Sri Pada: Must be in a grass or plains; cannot be adjacent to desert, tundra, or marshes;
|
|
||||||
avoids the biggest landmass ; becomes mountain
|
|
||||||
// ToDo: avoids the biggest landmass
|
|
||||||
*/
|
|
||||||
private fun spawnSriPada(tileMap: TileMap) {
|
|
||||||
val wonder = ruleset.terrains[Constants.sriPada]!!
|
|
||||||
val suitableLocations = tileMap.values.filter {
|
|
||||||
it.resource == null
|
|
||||||
&& wonder.occursOn.contains(it.getLastTerrain().name)
|
|
||||||
&& it.neighbors.none { neighbor -> neighbor.getBaseTerrain().name == Constants.desert }
|
|
||||||
&& it.neighbors.none { neighbor -> neighbor.getBaseTerrain().name == Constants.tundra }
|
|
||||||
&& it.neighbors.none { neighbor -> neighbor.getBaseTerrain().name == Constants.marsh }
|
|
||||||
}
|
|
||||||
|
|
||||||
trySpawnOnSuitableLocation(suitableLocations, wonder)
|
|
||||||
}
|
|
||||||
|
|
||||||
/*
|
|
||||||
Uluru: Must be in plains or desert, and must be adjacent to a minimum of 3 plains tiles;
|
|
||||||
cannot be adjacent to grassland, tundra, or marshes; avoids oceans; becomes mountain
|
|
||||||
*/
|
|
||||||
private fun spawnUluru(tileMap: TileMap) {
|
|
||||||
val wonder = ruleset.terrains[Constants.uluru]!!
|
|
||||||
val suitableLocations = tileMap.values.filter {
|
|
||||||
it.resource == null
|
|
||||||
&& wonder.occursOn.contains(it.getLastTerrain().name)
|
|
||||||
&& it.neighbors.none { neighbor -> neighbor.getBaseTerrain().name == Constants.grassland }
|
|
||||||
&& it.neighbors.none { neighbor -> neighbor.getBaseTerrain().name == Constants.coast }
|
|
||||||
&& it.neighbors.none { neighbor -> neighbor.getBaseTerrain().name == Constants.marsh }
|
|
||||||
&& it.neighbors.none { neighbor -> neighbor.getBaseTerrain().name == Constants.tundra }
|
|
||||||
&& it.neighbors.count { neighbor -> neighbor.getBaseTerrain().name == Constants.plains } >= 3
|
|
||||||
}
|
|
||||||
|
|
||||||
trySpawnOnSuitableLocation(suitableLocations, wonder)
|
|
||||||
}
|
|
||||||
|
|
||||||
//BNW Natural Wonders
|
|
||||||
/*
|
|
||||||
|
|
||||||
/*
|
|
||||||
King Solomon's Mines: Cannot be adjacent to more than 2 mountains; avoids oceans; becomes flatland plains
|
|
||||||
*/
|
|
||||||
private fun spawnSolomonMines(tileMap: TileMap) {
|
|
||||||
val wonder = ruleset.terrains[Constants.kingSolomonsMines]!!
|
|
||||||
val suitableLocations = tileMap.values.filter {
|
|
||||||
it.resource == null
|
|
||||||
&& wonder.occursOn.contains(it.getLastTerrain().name)
|
|
||||||
&& it.neighbors.none { neighbor -> neighbor.getBaseTerrain().name == Constants.coast }
|
|
||||||
&& it.neighbors.count { neighbor -> neighbor.getBaseTerrain().name == Constants.mountain } <= 2
|
|
||||||
}
|
|
||||||
|
|
||||||
trySpawnOnSuitableLocation(suitableLocations, wonder)
|
|
||||||
}
|
|
||||||
|
|
||||||
/*
|
|
||||||
Lake Victoria: Avoids oceans; becomes flatland plains
|
|
||||||
*/
|
|
||||||
private fun spawnLakeVictoria(tileMap: TileMap) {
|
|
||||||
val wonder = ruleset.terrains[Constants.lakeVictoria]!!
|
|
||||||
val suitableLocations = tileMap.values.filter {
|
|
||||||
it.resource == null
|
|
||||||
&& wonder.occursOn.contains(it.getLastTerrain().name)
|
|
||||||
&& it.neighbors.none { neighbor -> neighbor.getBaseTerrain().name == Constants.coast }
|
|
||||||
}
|
|
||||||
|
|
||||||
trySpawnOnSuitableLocation(suitableLocations, wonder)
|
|
||||||
}
|
|
||||||
|
|
||||||
/*
|
|
||||||
Mount Kilimanjaro: Must be in plains or grassland, and must be adjacent to at least 2 hills;
|
|
||||||
cannot be adjacent to more than 2 mountains; avoids oceans; becomes mountain
|
|
||||||
*/
|
|
||||||
private fun spawnMountKilimanjaro(tileMap: TileMap) {
|
|
||||||
val wonder = ruleset.terrains[Constants.mountKilimanjaro]!!
|
|
||||||
val suitableLocations = tileMap.values.filter {
|
|
||||||
it.resource == null
|
|
||||||
&& wonder.occursOn.contains(it.getLastTerrain().name)
|
|
||||||
&& it.neighbors.none { neighbor -> neighbor.getBaseTerrain().name == Constants.coast }
|
|
||||||
&& it.neighbors.count { neighbor -> neighbor.isHill() } >= 2
|
|
||||||
&& it.neighbors.count { neighbor -> neighbor.getBaseTerrain().name == Constants.mountain } <= 2
|
|
||||||
}
|
|
||||||
|
|
||||||
trySpawnOnSuitableLocation(suitableLocations, wonder)
|
|
||||||
}
|
|
||||||
|
|
||||||
*/
|
|
||||||
|
|
||||||
private fun clearTile(tile: TileInfo){
|
private fun clearTile(tile: TileInfo){
|
||||||
tile.terrainFeatures.clear()
|
tile.terrainFeatures.clear()
|
||||||
tile.resource = null
|
tile.resource = null
|
||||||
tile.improvement = null
|
tile.improvement = null
|
||||||
tile.setTerrainTransients()
|
tile.setTerrainTransients()
|
||||||
}
|
}
|
||||||
|
|
||||||
|
private fun TileInfo.matchesWonderFilter(filter: String) = when (filter) {
|
||||||
|
"Elevated" -> baseTerrain == Constants.mountain || isHill()
|
||||||
|
"Water" -> isWater
|
||||||
|
"Hill" -> isHill()
|
||||||
|
in allTerrainFeatures -> getLastTerrain().name == filter
|
||||||
|
else -> baseTerrain == filter
|
||||||
|
}
|
||||||
|
|
||||||
|
/*
|
||||||
|
Barringer Crater: Must be in tundra or desert; cannot be adjacent to grassland; can be adjacent to a maximum
|
||||||
|
of 2 mountains and a maximum of 4 hills and mountains; avoids oceans; becomes mountain
|
||||||
|
|
||||||
|
Grand Mesa: Must be in plains, desert, or tundra, and must be adjacent to at least 2 hills;
|
||||||
|
cannot be adjacent to grass; can be adjacent to a maximum of 2 mountains; avoids oceans; becomes mountain
|
||||||
|
|
||||||
|
Mt. Fuji: Must be in grass or plains; avoids oceans and the biggest landmass; cannot be adjacent to tundra,
|
||||||
|
desert, marsh, or mountains;can be adjacent to a maximum of 2 hills; becomes mountain
|
||||||
|
|
||||||
|
Great Barrier Reef: Specifics currently unknown;
|
||||||
|
Assumption: at least 1 neighbour coast; no tundra; at least 1 neighbour coast; becomes coast
|
||||||
|
|
||||||
|
Krakatoa: Must spawn in the ocean next to at least 1 shallow water tile; cannot be adjacent
|
||||||
|
to ice; changes tiles around it to shallow water; mountain
|
||||||
|
|
||||||
|
Rock of Gibraltar: Specifics currently unknown
|
||||||
|
Assumption: spawn on grassland, at least 1 coast and 1 mountain adjacent;
|
||||||
|
turn neighbours into coast)
|
||||||
|
|
||||||
|
Old Faithful: Must be adjacent to at least 3 hills and mountains; cannot be adjacent to
|
||||||
|
more than 4 mountains, and cannot be adjacent to more than 3 desert or 3 tundra tiles;
|
||||||
|
avoids oceans; becomes mountain
|
||||||
|
|
||||||
|
Cerro de Potosi: Must be adjacent to at least 1 hill; avoids oceans; becomes mountain
|
||||||
|
|
||||||
|
El Dorado: Must be next to at least 1 jungle tile; avoids oceans; becomes flatland plains
|
||||||
|
|
||||||
|
Fountain of Youth: Avoids oceans; becomes flatland plains
|
||||||
|
|
||||||
|
// G&K Natural Wonders
|
||||||
|
|
||||||
|
Mount Kailash: Must be in plains or grassland, and must be adjacent to at least 4 hills and/or mountains;
|
||||||
|
cannot be adjacent to marshes; can be adjacent to a maximum of 1 desert tile; avoids oceans; becomes mountain
|
||||||
|
|
||||||
|
Mount Sinai: Must be in plains or desert, and must be adjacent to a minimum of 3 desert tiles;
|
||||||
|
cannot be adjacent to tundra, marshes, or grassland; avoids oceans; becomes mountain
|
||||||
|
|
||||||
|
Sri Pada: Must be in a grass or plains; cannot be adjacent to desert, tundra, or marshes;
|
||||||
|
avoids the biggest landmass ; becomes mountain
|
||||||
|
|
||||||
|
Uluru: Must be in plains or desert, and must be adjacent to a minimum of 3 plains tiles;
|
||||||
|
cannot be adjacent to grassland, tundra, or marshes; avoids oceans; becomes mountain
|
||||||
|
|
||||||
|
//BNW Natural Wonders
|
||||||
|
|
||||||
|
King Solomon's Mines: Cannot be adjacent to more than 2 mountains; avoids oceans; becomes flatland plains
|
||||||
|
|
||||||
|
Lake Victoria: Avoids oceans; becomes flatland plains
|
||||||
|
|
||||||
|
Mount Kilimanjaro: Must be in plains or grassland, and must be adjacent to at least 2 hills;
|
||||||
|
cannot be adjacent to more than 2 mountains; avoids oceans; becomes mountain
|
||||||
|
*/
|
||||||
|
|
||||||
}
|
}
|
||||||
|
@ -1,8 +1,8 @@
|
|||||||
package com.unciv.models.ruleset.tile
|
package com.unciv.models.ruleset.tile
|
||||||
|
|
||||||
enum class TerrainType {
|
enum class TerrainType(val isBaseTerrain: Boolean) {
|
||||||
Land,
|
Land(true),
|
||||||
Water,
|
Water(true),
|
||||||
TerrainFeature,
|
TerrainFeature(false),
|
||||||
NaturalWonder
|
NaturalWonder(false)
|
||||||
}
|
}
|
||||||
|
@ -53,6 +53,8 @@ class Unique(val text: String, val sourceObjectType: UniqueTarget? = null, val s
|
|||||||
else -> false
|
else -> false
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
|
override fun toString() = if (type == null) "\"$text\"" else "$type (\"$text\")"
|
||||||
}
|
}
|
||||||
|
|
||||||
|
|
||||||
|
@ -1,6 +1,8 @@
|
|||||||
package com.unciv.models.ruleset.unique
|
package com.unciv.models.ruleset.unique
|
||||||
|
|
||||||
import com.unciv.models.ruleset.Ruleset
|
import com.unciv.models.ruleset.Ruleset
|
||||||
|
import com.unciv.models.ruleset.tile.ResourceType
|
||||||
|
import com.unciv.models.ruleset.tile.TerrainType
|
||||||
|
|
||||||
// parameterName values should be compliant with autogenerated values in TranslationFileWriter.generateStringsFromJSONs
|
// parameterName values should be compliant with autogenerated values in TranslationFileWriter.generateStringsFromJSONs
|
||||||
// Eventually we'll merge the translation generation to take this as the source of that
|
// Eventually we'll merge the translation generation to take this as the source of that
|
||||||
@ -13,7 +15,7 @@ enum class UniqueParameterType(val parameterName:String) {
|
|||||||
}
|
}
|
||||||
},
|
},
|
||||||
MapUnitFilter("mapUnitFilter"){
|
MapUnitFilter("mapUnitFilter"){
|
||||||
val knownValues = setOf("Wounded", "Barbarians", "City-State", "Embarked", "Non-City")
|
private val knownValues = setOf("Wounded", "Barbarians", "City-State", "Embarked", "Non-City")
|
||||||
override fun getErrorSeverity(parameterText: String, ruleset: Ruleset):
|
override fun getErrorSeverity(parameterText: String, ruleset: Ruleset):
|
||||||
UniqueType.UniqueComplianceErrorSeverity? {
|
UniqueType.UniqueComplianceErrorSeverity? {
|
||||||
if (parameterText in knownValues) return null
|
if (parameterText in knownValues) return null
|
||||||
@ -23,7 +25,7 @@ enum class UniqueParameterType(val parameterName:String) {
|
|||||||
BaseUnitFilter("baseUnitFilter"){
|
BaseUnitFilter("baseUnitFilter"){
|
||||||
// As you can see there is a difference between these and what's in unitTypeStrings (for translation) -
|
// As you can see there is a difference between these and what's in unitTypeStrings (for translation) -
|
||||||
// the goal is to unify, but for now this is the "real" list
|
// the goal is to unify, but for now this is the "real" list
|
||||||
val knownValues = setOf("All", "Melee", "Ranged", "Civilian", "Military", "Land", "Water", "Air",
|
private val knownValues = setOf("All", "Melee", "Ranged", "Civilian", "Military", "Land", "Water", "Air",
|
||||||
"non-air", "Nuclear Weapon", "Great Person", "Religious")
|
"non-air", "Nuclear Weapon", "Great Person", "Religious")
|
||||||
override fun getErrorSeverity(parameterText: String, ruleset: Ruleset):
|
override fun getErrorSeverity(parameterText: String, ruleset: Ruleset):
|
||||||
UniqueType.UniqueComplianceErrorSeverity? {
|
UniqueType.UniqueComplianceErrorSeverity? {
|
||||||
@ -62,6 +64,33 @@ enum class UniqueParameterType(val parameterName:String) {
|
|||||||
return UniqueType.UniqueComplianceErrorSeverity.RulesetSpecific
|
return UniqueType.UniqueComplianceErrorSeverity.RulesetSpecific
|
||||||
}
|
}
|
||||||
},
|
},
|
||||||
|
TerrainFilter("terrainFilter") {
|
||||||
|
private val knownValues = setOf("All",
|
||||||
|
"Coastal", "River", "Open terrain", "Rough terrain", "Water resource",
|
||||||
|
"Foreign Land", "Foreign", "Friendly Land", "Friendly", "Enemy Land", "Enemy")
|
||||||
|
override fun getErrorSeverity(parameterText: String, ruleset: Ruleset):
|
||||||
|
UniqueType.UniqueComplianceErrorSeverity? {
|
||||||
|
if (parameterText in knownValues) return null
|
||||||
|
if (ruleset.terrains.containsKey(parameterText)) return null
|
||||||
|
if (TerrainType.values().any { parameterText == it.name }) return null
|
||||||
|
if (ruleset.tileResources.containsKey(parameterText)) return null
|
||||||
|
if (ResourceType.values().any { parameterText == it.name + " resource" }) return null
|
||||||
|
return UniqueType.UniqueComplianceErrorSeverity.WarningOnly
|
||||||
|
}
|
||||||
|
},
|
||||||
|
/** Used by NaturalWonderGenerator, only tests base terrain or a feature */
|
||||||
|
SimpleTerrain("simpleTerrain") {
|
||||||
|
override fun getErrorSeverity(parameterText: String, ruleset: Ruleset):
|
||||||
|
UniqueType.UniqueComplianceErrorSeverity? {
|
||||||
|
if (parameterText == "Elevated") return null
|
||||||
|
if (ruleset.terrains.values.any {
|
||||||
|
it.name == parameterText &&
|
||||||
|
(it.type.isBaseTerrain || it.type == TerrainType.TerrainFeature)
|
||||||
|
})
|
||||||
|
return null
|
||||||
|
return UniqueType.UniqueComplianceErrorSeverity.RulesetSpecific
|
||||||
|
}
|
||||||
|
},
|
||||||
Unknown("param") {
|
Unknown("param") {
|
||||||
override fun getErrorSeverity(parameterText: String, ruleset: Ruleset):
|
override fun getErrorSeverity(parameterText: String, ruleset: Ruleset):
|
||||||
UniqueType.UniqueComplianceErrorSeverity? {
|
UniqueType.UniqueComplianceErrorSeverity? {
|
||||||
|
@ -4,9 +4,9 @@ import com.unciv.models.ruleset.Ruleset
|
|||||||
import com.unciv.models.translations.getPlaceholderParameters
|
import com.unciv.models.translations.getPlaceholderParameters
|
||||||
import com.unciv.models.translations.getPlaceholderText
|
import com.unciv.models.translations.getPlaceholderText
|
||||||
|
|
||||||
enum class UniqueTarget {
|
|
||||||
/** Buildings, units, nations, policies, religions, techs etc.
|
/** Buildings, units, nations, policies, religions, techs etc.
|
||||||
* Basically anything caught by CivInfo.getMatchingUniques. */
|
* Basically anything caught by CivInfo.getMatchingUniques. */
|
||||||
|
enum class UniqueTarget {
|
||||||
Global,
|
Global,
|
||||||
|
|
||||||
// Civilization-specific
|
// Civilization-specific
|
||||||
@ -71,6 +71,14 @@ enum class UniqueType(val text:String, vararg target: UniqueTarget) {
|
|||||||
CityStateMilitaryUnits("Provides military units every ≈[amount] turns", UniqueTarget.CityState), // No conditional support as of yet
|
CityStateMilitaryUnits("Provides military units every ≈[amount] turns", UniqueTarget.CityState), // No conditional support as of yet
|
||||||
CityStateUniqueLuxury("Provides a unique luxury", UniqueTarget.CityState), // No conditional support as of yet
|
CityStateUniqueLuxury("Provides a unique luxury", UniqueTarget.CityState), // No conditional support as of yet
|
||||||
|
|
||||||
|
NaturalWonderNeighborCount("Must be adjacent to [amount] [terrainFilter] tiles", UniqueTarget.Terrain),
|
||||||
|
NaturalWonderNeighborsRange("Must be adjacent to [amount] to [amount] [terrainFilter] tiles", UniqueTarget.Terrain),
|
||||||
|
NaturalWonderLandmass("Must not be on [amount] largest landmasses", UniqueTarget.Terrain),
|
||||||
|
NaturalWonderLatitude("Occurs on latitudes from [amount] to [amount] percent of distance equator to pole", UniqueTarget.Terrain),
|
||||||
|
NaturalWonderGroups("Occurs in groups of [amount] to [amount] tiles", UniqueTarget.Terrain),
|
||||||
|
NaturalWonderConvertNeighbors("Neighboring tiles will convert to [baseTerrain]", UniqueTarget.Terrain),
|
||||||
|
NaturalWonderConvertNeighborsExcept("Neighboring tiles except [terrainFilter] will convert to [baseTerrain]", UniqueTarget.Terrain),
|
||||||
|
|
||||||
|
|
||||||
///// CONDITIONALS
|
///// CONDITIONALS
|
||||||
|
|
||||||
|
Reference in New Issue
Block a user