mirror of
https://github.com/yairm210/Unciv.git
synced 2025-03-17 03:25:54 +07:00
Fix NW placement
This commit is contained in:
parent
64e79ffa0d
commit
a6e61c120b
@ -139,18 +139,22 @@ class MapGenerator(val ruleset: Ruleset) {
|
|||||||
runAndMeasure("assignRegions") {
|
runAndMeasure("assignRegions") {
|
||||||
regions.assignRegions(map, civilizations.filter { ruleset.nations[it.civName]!!.isMajorCiv() }, gameParameters)
|
regions.assignRegions(map, civilizations.filter { ruleset.nations[it.civName]!!.isMajorCiv() }, gameParameters)
|
||||||
}
|
}
|
||||||
|
// Natural wonders need to go before most resources since there is a minimum distance
|
||||||
|
runAndMeasure("NaturalWonderGenerator") {
|
||||||
|
NaturalWonderGenerator(ruleset, randomness).spawnNaturalWonders(map)
|
||||||
|
}
|
||||||
runAndMeasure("placeResourcesAndMinorCivs") {
|
runAndMeasure("placeResourcesAndMinorCivs") {
|
||||||
regions.placeResourcesAndMinorCivs(map, civilizations.filter { ruleset.nations[it.civName]!!.isCityState() })
|
regions.placeResourcesAndMinorCivs(map, civilizations.filter { ruleset.nations[it.civName]!!.isCityState() })
|
||||||
}
|
}
|
||||||
} else {
|
} else {
|
||||||
|
runAndMeasure("NaturalWonderGenerator") {
|
||||||
|
NaturalWonderGenerator(ruleset, randomness).spawnNaturalWonders(map)
|
||||||
|
}
|
||||||
// Fallback spread resources function - used when generating maps in map editor
|
// Fallback spread resources function - used when generating maps in map editor
|
||||||
runAndMeasure("spreadResources") {
|
runAndMeasure("spreadResources") {
|
||||||
spreadResources(map)
|
spreadResources(map)
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
runAndMeasure("NaturalWonderGenerator") {
|
|
||||||
NaturalWonderGenerator(ruleset, randomness).spawnNaturalWonders(map)
|
|
||||||
}
|
|
||||||
runAndMeasure("spreadAncientRuins") {
|
runAndMeasure("spreadAncientRuins") {
|
||||||
spreadAncientRuins(map)
|
spreadAncientRuins(map)
|
||||||
}
|
}
|
||||||
@ -288,7 +292,9 @@ class MapGenerator(val ruleset: Ruleset) {
|
|||||||
private fun spreadStrategicResources(tileMap: TileMap, mapRadius: Int) {
|
private fun spreadStrategicResources(tileMap: TileMap, mapRadius: Int) {
|
||||||
val strategicResources = ruleset.tileResources.values.filter { it.resourceType == ResourceType.Strategic }
|
val strategicResources = ruleset.tileResources.values.filter { it.resourceType == ResourceType.Strategic }
|
||||||
// passable land tiles (no mountains, no wonders) without resources yet
|
// passable land tiles (no mountains, no wonders) without resources yet
|
||||||
val candidateTiles = tileMap.values.filter { it.resource == null && !it.isImpassible() }
|
// can't be next to NW
|
||||||
|
val candidateTiles = tileMap.values.filter { it.resource == null && !it.isImpassible()
|
||||||
|
&& it.neighbors.none { neighbor -> neighbor.isNaturalWonder() }}
|
||||||
val totalNumberOfResources = candidateTiles.count { it.isLand } * tileMap.mapParameters.resourceRichness
|
val totalNumberOfResources = candidateTiles.count { it.isLand } * tileMap.mapParameters.resourceRichness
|
||||||
val resourcesPerType = (totalNumberOfResources/strategicResources.size).toInt()
|
val resourcesPerType = (totalNumberOfResources/strategicResources.size).toInt()
|
||||||
for (resource in strategicResources) {
|
for (resource in strategicResources) {
|
||||||
@ -314,7 +320,8 @@ class MapGenerator(val ruleset: Ruleset) {
|
|||||||
|
|
||||||
val suitableTiles = tileMap.values
|
val suitableTiles = tileMap.values
|
||||||
.filterNot { it.baseTerrain == Constants.snow && it.isHill() }
|
.filterNot { it.baseTerrain == Constants.snow && it.isHill() }
|
||||||
.filter { it.resource == null && resourcesOfType.any { r -> r.terrainsCanBeFoundOn.contains(it.getLastTerrain().name) } }
|
.filter { it.resource == null && it.neighbors.none { neighbor -> neighbor.isNaturalWonder() }
|
||||||
|
&& resourcesOfType.any { r -> r.terrainsCanBeFoundOn.contains(it.getLastTerrain().name) } }
|
||||||
val numberOfResources = tileMap.values.count { it.isLand && !it.isImpassible() } *
|
val numberOfResources = tileMap.values.count { it.isLand && !it.isImpassible() } *
|
||||||
tileMap.mapParameters.resourceRichness
|
tileMap.mapParameters.resourceRichness
|
||||||
val locations = randomness.chooseSpreadOutLocations(numberOfResources.toInt(), suitableTiles, mapRadius)
|
val locations = randomness.chooseSpreadOutLocations(numberOfResources.toInt(), suitableTiles, mapRadius)
|
||||||
|
@ -829,12 +829,23 @@ class MapRegions (val ruleset: Ruleset){
|
|||||||
}
|
}
|
||||||
|
|
||||||
fun placeResourcesAndMinorCivs(tileMap: TileMap, minorCivs: List<CivilizationInfo>) {
|
fun placeResourcesAndMinorCivs(tileMap: TileMap, minorCivs: List<CivilizationInfo>) {
|
||||||
|
placeNaturalWonderImpacts(tileMap)
|
||||||
assignLuxuries()
|
assignLuxuries()
|
||||||
placeMinorCivs(tileMap, minorCivs)
|
placeMinorCivs(tileMap, minorCivs)
|
||||||
placeLuxuries(tileMap)
|
placeLuxuries(tileMap)
|
||||||
placeStrategicAndBonuses(tileMap)
|
placeStrategicAndBonuses(tileMap)
|
||||||
}
|
}
|
||||||
|
|
||||||
|
/** Places impacts from NWs that have been generated just prior to this step. */
|
||||||
|
private fun placeNaturalWonderImpacts(tileMap: TileMap) {
|
||||||
|
for (tile in tileMap.values.filter { it.isNaturalWonder() }) {
|
||||||
|
placeImpact(ImpactType.Bonus, tile, 1)
|
||||||
|
placeImpact(ImpactType.Strategic, tile, 1)
|
||||||
|
placeImpact(ImpactType.Luxury, tile, 1)
|
||||||
|
placeImpact(ImpactType.MinorCiv, tile, 1)
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
/** Assigns a luxury to each region. No luxury can be assigned to too many regions.
|
/** Assigns a luxury to each region. No luxury can be assigned to too many regions.
|
||||||
* Some luxuries are earmarked for city states. The rest are randomly distributed or
|
* Some luxuries are earmarked for city states. The rest are randomly distributed or
|
||||||
* don't occur att all in the map */
|
* don't occur att all in the map */
|
||||||
|
@ -18,9 +18,14 @@ class NaturalWonderGenerator(val ruleset: Ruleset, val randomness: MapGeneration
|
|||||||
.filter { it.type == TerrainType.TerrainFeature }
|
.filter { it.type == TerrainType.TerrainFeature }
|
||||||
.map { it.name }.toSet()
|
.map { it.name }.toSet()
|
||||||
|
|
||||||
|
private val blockedTiles = HashSet<TileInfo>()
|
||||||
|
|
||||||
/*
|
/*
|
||||||
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/
|
||||||
|
Above all, look in assignstartingplots.lua! The wonders are always attempted to be placed in order of
|
||||||
|
which has the least amount of candidate tiles. There is a minimum distance between wonders equal
|
||||||
|
to the map height / 5.
|
||||||
*/
|
*/
|
||||||
fun spawnNaturalWonders(tileMap: TileMap) {
|
fun spawnNaturalWonders(tileMap: TileMap) {
|
||||||
if (tileMap.mapParameters.noNaturalWonders)
|
if (tileMap.mapParameters.noNaturalWonders)
|
||||||
@ -31,31 +36,58 @@ class NaturalWonderGenerator(val ruleset: Ruleset, val randomness: MapGeneration
|
|||||||
mapRadius * naturalWonderCountMultiplier + naturalWonderCountAddedConstant
|
mapRadius * naturalWonderCountMultiplier + naturalWonderCountAddedConstant
|
||||||
}.roundToInt()
|
}.roundToInt()
|
||||||
|
|
||||||
val spawned = mutableListOf<Terrain>()
|
val chosenWonders = mutableListOf<Terrain>()
|
||||||
|
val wonderCandidateTiles = mutableMapOf<Terrain, Collection<TileInfo>>()
|
||||||
val allNaturalWonders = ruleset.terrains.values
|
val allNaturalWonders = ruleset.terrains.values
|
||||||
.filter { it.type == TerrainType.NaturalWonder }.toMutableList()
|
.filter { it.type == TerrainType.NaturalWonder }.toMutableList()
|
||||||
|
val spawned = mutableListOf<Terrain>()
|
||||||
|
|
||||||
while (allNaturalWonders.isNotEmpty() && spawned.size < numberToSpawn) {
|
while (allNaturalWonders.isNotEmpty() && chosenWonders.size < numberToSpawn) {
|
||||||
val totalWeight = allNaturalWonders.sumOf { it.weight }.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) {
|
||||||
if (spawnSpecificWonder(tileMap, wonder))
|
chosenWonders.add(wonder)
|
||||||
spawned.add(wonder)
|
|
||||||
allNaturalWonders.remove(wonder)
|
allNaturalWonders.remove(wonder)
|
||||||
break
|
break
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
|
// First attempt to spawn the chosen wonders in order of least candidate tiles
|
||||||
|
chosenWonders.forEach {
|
||||||
|
wonderCandidateTiles[it] = getCandidateTilesForWonder(tileMap, it)
|
||||||
|
}
|
||||||
|
chosenWonders.sortBy { wonderCandidateTiles[it]!!.size }
|
||||||
|
for (wonder in chosenWonders) {
|
||||||
|
if (trySpawnOnSuitableLocation(wonderCandidateTiles[wonder]!!.filter { it !in blockedTiles }.toList(), wonder))
|
||||||
|
spawned.add(wonder)
|
||||||
|
}
|
||||||
|
|
||||||
|
// If some wonders were not able to be spawned we will pull a wonder from the fallback list
|
||||||
|
if (spawned.size < numberToSpawn) {
|
||||||
|
// Now we have to do some more calculations. Unfortunately we have to calculate candidate tiles for everyone.
|
||||||
|
allNaturalWonders.forEach {
|
||||||
|
wonderCandidateTiles[it] = getCandidateTilesForWonder(tileMap, it)
|
||||||
|
}
|
||||||
|
allNaturalWonders.sortBy { wonderCandidateTiles[it]!!.size }
|
||||||
|
for (wonder in allNaturalWonders) {
|
||||||
|
if (trySpawnOnSuitableLocation(wonderCandidateTiles[wonder]!!.filter { it !in blockedTiles }
|
||||||
|
.toList(), wonder))
|
||||||
|
spawned.add(wonder)
|
||||||
|
if (spawned.size >= numberToSpawn)
|
||||||
|
break
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
debug("Natural Wonders for this game: %s", spawned)
|
debug("Natural Wonders for this game: %s", spawned)
|
||||||
}
|
}
|
||||||
|
|
||||||
private fun Unique.getIntParam(index: Int) = params[index].toInt()
|
private fun Unique.getIntParam(index: Int) = params[index].toInt()
|
||||||
|
|
||||||
private fun spawnSpecificWonder(tileMap: TileMap, naturalWonder: Terrain): Boolean {
|
private fun getCandidateTilesForWonder(tileMap: TileMap, naturalWonder: Terrain): Collection<TileInfo> {
|
||||||
val continentsRelevant = naturalWonder.hasUnique(UniqueType.NaturalWonderLargerLandmass) ||
|
val continentsRelevant = naturalWonder.hasUnique(UniqueType.NaturalWonderLargerLandmass) ||
|
||||||
naturalWonder.hasUnique(UniqueType.NaturalWonderSmallerLandmass)
|
naturalWonder.hasUnique(UniqueType.NaturalWonderSmallerLandmass)
|
||||||
val sortedContinents = if (continentsRelevant)
|
val sortedContinents = if (continentsRelevant)
|
||||||
@ -98,7 +130,7 @@ class NaturalWonderGenerator(val ruleset: Ruleset, val randomness: MapGeneration
|
|||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
return trySpawnOnSuitableLocation(suitableLocations, naturalWonder)
|
return suitableLocations
|
||||||
}
|
}
|
||||||
|
|
||||||
private fun trySpawnOnSuitableLocation(suitableLocations: List<TileInfo>, wonder: Terrain): Boolean {
|
private fun trySpawnOnSuitableLocation(suitableLocations: List<TileInfo>, wonder: Terrain): Boolean {
|
||||||
@ -138,6 +170,8 @@ class NaturalWonderGenerator(val ruleset: Ruleset, val randomness: MapGeneration
|
|||||||
clearTile(it)
|
clearTile(it)
|
||||||
it.naturalWonder = wonder.name
|
it.naturalWonder = wonder.name
|
||||||
it.baseTerrain = wonder.turnsInto!!
|
it.baseTerrain = wonder.turnsInto!!
|
||||||
|
// Add all tiles within a certain distance to a blacklist so NW:s don't cluster
|
||||||
|
blockedTiles.addAll(it.getTilesInDistance(it.tileMap.mapParameters.mapSize.height / 5))
|
||||||
}
|
}
|
||||||
if (convertNeighborsTo != null) {
|
if (convertNeighborsTo != null) {
|
||||||
for (tile in location.neighbors) {
|
for (tile in location.neighbors) {
|
||||||
|
Loading…
x
Reference in New Issue
Block a user