mirror of
https://github.com/yairm210/Unciv.git
synced 2025-02-04 07:58:18 +07:00
Terraforming! (#11152)
* Terraforming! * comment * whoops * And better tests, that actually output text. * SomeTrog caught this doc error :) * Fix natural wonder placement, it better belongs with base terrain Also, normalize tiles to ruleset after plonking a new terrain * Out Of Cheese Error, Redo From Start - Only terrains, no improvements - one problem at a time - Fit new functional trigger format - Respect occursOn - Teleport units out of tiles if they can't pass through (nat wonders for example) - No need for terrainFeature unique parameter - Tested with "Turn this tile into a [Grand Mesa] tile <for [0] movement>", "Turn this tile into a [Forest] tile <for [0] movement>" uniques * Don't allow city tiles to turn into water/wonders etc kudos @SomeTrog
This commit is contained in:
parent
2c96c6f244
commit
23edf07a41
@ -151,18 +151,10 @@ class NaturalWonderGenerator(val ruleset: Ruleset, val randomness: MapGeneration
|
||||
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 list = mutableListOf(location)
|
||||
|
||||
while (list.size < targetGroupSize) {
|
||||
val allNeighbors = list.flatMap { it.neighbors }.minus(list).toHashSet()
|
||||
val candidates = suitableLocations.filter { it in allNeighbors }
|
||||
@ -171,30 +163,11 @@ class NaturalWonderGenerator(val ruleset: Ruleset, val randomness: MapGeneration
|
||||
}
|
||||
if (list.size >= minGroupSize) {
|
||||
list.forEach {
|
||||
clearTile(it)
|
||||
it.naturalWonder = wonder.name
|
||||
if (wonder.turnsInto != null)
|
||||
it.baseTerrain = wonder.turnsInto!!
|
||||
placeNaturalWonder(wonder, location)
|
||||
// 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) {
|
||||
for (tile in location.neighbors) {
|
||||
if (tile.baseTerrain == convertNeighborsTo) continue
|
||||
if (tile.baseTerrain == convertNeighborsExcept) continue
|
||||
if (convertNeighborsTo == Constants.coast)
|
||||
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.
|
||||
// We just turn the lake tiles into this kind of tile.
|
||||
if (neighbor.baseTerrain == Constants.lakes) {
|
||||
neighbor.baseTerrain = tile.baseTerrain
|
||||
neighbor.setTerrainTransients()
|
||||
}
|
||||
}
|
||||
tile.baseTerrain = convertNeighborsTo
|
||||
clearTile(tile)
|
||||
}
|
||||
}
|
||||
|
||||
debug("Natural Wonder %s @%s", wonder.name, location.position)
|
||||
|
||||
return true
|
||||
@ -205,11 +178,47 @@ class NaturalWonderGenerator(val ruleset: Ruleset, val randomness: MapGeneration
|
||||
return false
|
||||
}
|
||||
|
||||
private fun clearTile(tile: Tile) {
|
||||
tile.setTerrainFeatures(listOf())
|
||||
tile.resource = null
|
||||
tile.removeImprovement()
|
||||
tile.setTerrainTransients()
|
||||
companion object {
|
||||
fun placeNaturalWonder(wonder: Terrain, location: Tile) {
|
||||
clearTile(location)
|
||||
location.naturalWonder = wonder.name
|
||||
if (wonder.turnsInto != null)
|
||||
location.baseTerrain = wonder.turnsInto!!
|
||||
|
||||
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 (convertNeighborsTo != null) {
|
||||
for (tile in location.neighbors) {
|
||||
if (tile.baseTerrain == convertNeighborsTo) continue
|
||||
if (tile.baseTerrain == convertNeighborsExcept) continue
|
||||
if (convertNeighborsTo == Constants.coast)
|
||||
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.
|
||||
// We just turn the lake tiles into this kind of tile.
|
||||
if (neighbor.baseTerrain == Constants.lakes) {
|
||||
neighbor.baseTerrain = tile.baseTerrain
|
||||
neighbor.setTerrainTransients()
|
||||
}
|
||||
}
|
||||
tile.baseTerrain = convertNeighborsTo
|
||||
clearTile(tile)
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
private fun clearTile(tile: Tile) {
|
||||
tile.setTerrainFeatures(listOf())
|
||||
tile.resource = null
|
||||
tile.removeImprovement()
|
||||
tile.setTerrainTransients()
|
||||
}
|
||||
}
|
||||
|
||||
/** Implements [UniqueParameterType.SimpleTerrain][com.unciv.models.ruleset.unique.UniqueParameterType.SimpleTerrain] */
|
||||
|
@ -26,6 +26,7 @@ import com.unciv.models.ruleset.unique.UniqueMap
|
||||
import com.unciv.models.ruleset.unique.UniqueType
|
||||
import com.unciv.ui.components.extensions.withItem
|
||||
import com.unciv.ui.components.extensions.withoutItem
|
||||
import com.unciv.ui.screens.mapeditorscreen.TileInfoNormalizer
|
||||
import com.unciv.utils.DebugUtils
|
||||
import com.unciv.utils.Log
|
||||
import kotlin.math.abs
|
||||
@ -832,6 +833,14 @@ open class Tile : IsPartOfGameInfoSerialization {
|
||||
else unitHeight
|
||||
}
|
||||
|
||||
fun setBaseTerrain(baseTerrainObject: Terrain){
|
||||
baseTerrain = baseTerrainObject.name
|
||||
this.baseTerrainObject = baseTerrainObject
|
||||
TileInfoNormalizer.normalizeToRuleset(this, ruleset)
|
||||
setTerrainFeatures(terrainFeatures)
|
||||
setTerrainTransients()
|
||||
}
|
||||
|
||||
private fun updateUniqueMap() {
|
||||
if (!::tileMap.isInitialized) return // This tile is a fake tile, for visual display only (e.g. map editor, civilopedia)
|
||||
val terrainNameList = allTerrains.map { it.name }.toList()
|
||||
|
@ -375,7 +375,7 @@ enum class UniqueParameterType(
|
||||
/** Used by [NaturalWonderGenerator.trySpawnOnSuitableLocation][com.unciv.logic.map.mapgenerator.NaturalWonderGenerator.trySpawnOnSuitableLocation], only tests base terrain */
|
||||
BaseTerrain("baseTerrain", Constants.grassland, "The name of any terrain that is a base terrain according to the json file") {
|
||||
override fun getErrorSeverity(parameterText: String, ruleset: Ruleset):
|
||||
UniqueType.UniqueParameterErrorSeverity? {
|
||||
UniqueType.UniqueParameterErrorSeverity? {
|
||||
if (ruleset.terrains[parameterText]?.type?.isBaseTerrain == true) return null
|
||||
return UniqueType.UniqueParameterErrorSeverity.RulesetSpecific
|
||||
}
|
||||
|
@ -16,15 +16,18 @@ import com.unciv.logic.civilization.NotificationIcon
|
||||
import com.unciv.logic.civilization.PolicyAction
|
||||
import com.unciv.logic.civilization.TechAction
|
||||
import com.unciv.logic.civilization.managers.ReligionState
|
||||
import com.unciv.logic.map.mapgenerator.NaturalWonderGenerator
|
||||
import com.unciv.logic.map.mapunit.MapUnit
|
||||
import com.unciv.logic.map.tile.Tile
|
||||
import com.unciv.models.UpgradeUnitAction
|
||||
import com.unciv.models.ruleset.BeliefType
|
||||
import com.unciv.models.ruleset.tile.TerrainType
|
||||
import com.unciv.models.stats.Stat
|
||||
import com.unciv.models.stats.Stats
|
||||
import com.unciv.models.translations.fillPlaceholders
|
||||
import com.unciv.models.translations.hasPlaceholderParameters
|
||||
import com.unciv.ui.components.extensions.addToMapOfSets
|
||||
import com.unciv.ui.screens.mapeditorscreen.TileInfoNormalizer
|
||||
import com.unciv.ui.screens.worldscreen.unit.actions.UnitActionsUpgrade
|
||||
import kotlin.math.roundToInt
|
||||
import kotlin.random.Random
|
||||
@ -926,6 +929,28 @@ object UniqueTriggerActivation {
|
||||
true
|
||||
}
|
||||
}
|
||||
|
||||
UniqueType.OneTimeChangeTerrain -> {
|
||||
if (tile == null) return null
|
||||
val terrain = ruleSet.terrains[unique.params[0]] ?: return null
|
||||
if (terrain.type == TerrainType.TerrainFeature && !terrain.occursOn.contains(tile.lastTerrain.name))
|
||||
return null
|
||||
if (tile.terrainFeatures.contains(terrain.name)) return null
|
||||
if (tile.isCityCenter() && terrain.type != TerrainType.Land) return null
|
||||
if (terrain.type.isBaseTerrain && tile.baseTerrain == terrain.name) return null
|
||||
|
||||
return {
|
||||
when (terrain.type) {
|
||||
TerrainType.Land, TerrainType.Water -> tile.setBaseTerrain(terrain)
|
||||
TerrainType.TerrainFeature -> tile.addTerrainFeature(terrain.name)
|
||||
TerrainType.NaturalWonder -> NaturalWonderGenerator.placeNaturalWonder(terrain, tile)
|
||||
}
|
||||
TileInfoNormalizer.normalizeToRuleset(tile, ruleSet)
|
||||
tile.getUnits().filter { !it.movement.canPassThrough(tile) }.toList()
|
||||
.forEach { it.movement.teleportToClosestMoveableTile() }
|
||||
true
|
||||
}
|
||||
}
|
||||
else -> return null
|
||||
}
|
||||
}
|
||||
|
@ -761,6 +761,8 @@ enum class UniqueType(
|
||||
SkipPromotion("Doing so will consume this opportunity to choose a Promotion", UniqueTarget.Promotion),
|
||||
FreePromotion("This Promotion is free", UniqueTarget.Promotion),
|
||||
|
||||
OneTimeChangeTerrain("Turn this tile into a [terrainName] tile", UniqueTarget.UnitTriggerable),
|
||||
|
||||
UnitsGainPromotion("[mapUnitFilter] units gain the [promotion] promotion", UniqueTarget.Triggerable), // Not used in Vanilla
|
||||
FreeStatBuildings("Provides the cheapest [stat] building in your first [positiveAmount] cities for free", UniqueTarget.Triggerable), // used in Policy
|
||||
FreeSpecificBuildings("Provides a [buildingName] in your first [positiveAmount] cities for free", UniqueTarget.Triggerable), // used in Policy
|
||||
|
@ -190,6 +190,11 @@ Simple unique parameters are explained by mouseover. Complex parameters are expl
|
||||
|
||||
Applicable to: UnitTriggerable
|
||||
|
||||
??? example "Turn this tile into a [terrain] tile"
|
||||
Example: "Turn this tile into a [Unknown] tile"
|
||||
|
||||
Applicable to: UnitTriggerable
|
||||
|
||||
## Global uniques
|
||||
!!! note ""
|
||||
|
||||
|
@ -110,7 +110,7 @@ class BasicTests {
|
||||
for (paramType in entry.value) {
|
||||
if (paramType == UniqueParameterType.Unknown) {
|
||||
val badParam = uniqueType.text.getPlaceholderParameters()[entry.index]
|
||||
debug("%s param[%s] type \"%s\" is unknown", uniqueType.name, entry.index, badParam)
|
||||
println("${uniqueType.name} param[${entry.index}] type \"$badParam\" is unknown")
|
||||
noUnknownParameters = false
|
||||
}
|
||||
}
|
||||
|
Loading…
Reference in New Issue
Block a user