mirror of
https://github.com/yairm210/Unciv.git
synced 2025-01-05 21:11:35 +07:00
Unified 'does resource generate naturally on' checks to include all uniques everywhere
This commit is contained in:
parent
36baea9250
commit
903963787a
@ -23,7 +23,6 @@ import com.unciv.utils.debug
|
||||
import kotlinx.coroutines.CoroutineScope
|
||||
import kotlinx.coroutines.isActive
|
||||
import kotlin.math.abs
|
||||
import kotlin.math.max
|
||||
import kotlin.math.pow
|
||||
import kotlin.math.roundToInt
|
||||
import kotlin.math.sign
|
||||
@ -342,8 +341,7 @@ class MapGenerator(val ruleset: Ruleset, private val coroutineScope: CoroutineSc
|
||||
// remove the tiles where previous resources have been placed
|
||||
val suitableTiles = candidateTiles
|
||||
.filterNot { it.baseTerrain == Constants.snow && it.isHill() }
|
||||
.filter { it.resource == null
|
||||
&& resource.terrainsCanBeFoundOn.contains(it.lastTerrain.name) }
|
||||
.filter { it.resource == null && resource.generatesNaturallyOn(it) }
|
||||
|
||||
val locations = randomness.chooseSpreadOutLocations(resourcesPerType, suitableTiles, mapRadius)
|
||||
|
||||
@ -361,8 +359,10 @@ class MapGenerator(val ruleset: Ruleset, private val coroutineScope: CoroutineSc
|
||||
|
||||
val suitableTiles = tileMap.values
|
||||
.filterNot { it.baseTerrain == Constants.snow && it.isHill() }
|
||||
.filter { it.resource == null && it.neighbors.none { neighbor -> neighbor.isNaturalWonder() }
|
||||
&& resourcesOfType.any { r -> r.terrainsCanBeFoundOn.contains(it.lastTerrain.name) } }
|
||||
.filter { it.resource == null
|
||||
&& it.neighbors.none { neighbor -> neighbor.isNaturalWonder() }
|
||||
&& resourcesOfType.any { r -> r.generatesNaturallyOn(it) }
|
||||
}
|
||||
val numberOfResources = tileMap.values.count { it.isLand && !it.isImpassible() } *
|
||||
tileMap.mapParameters.resourceRichness
|
||||
val locations = randomness.chooseSpreadOutLocations(numberOfResources.toInt(), suitableTiles, mapRadius)
|
||||
@ -370,8 +370,7 @@ class MapGenerator(val ruleset: Ruleset, private val coroutineScope: CoroutineSc
|
||||
val resourceToNumber = Counter<String>()
|
||||
|
||||
for (tile in locations) {
|
||||
val possibleResources = resourcesOfType
|
||||
.filter { it.terrainsCanBeFoundOn.contains(tile.lastTerrain.name) }
|
||||
val possibleResources = resourcesOfType.filter { it.generatesNaturallyOn(tile) }
|
||||
if (possibleResources.isEmpty()) continue
|
||||
val resourceWithLeastAssignments = possibleResources.minByOrNull { resourceToNumber[it.name] }!!
|
||||
resourceToNumber.add(resourceWithLeastAssignments.name, 1)
|
||||
|
@ -30,14 +30,11 @@ object MapRegionResources {
|
||||
ResourceType.Luxury -> MapRegions.ImpactType.Luxury
|
||||
}
|
||||
val conditionalTerrain = StateForConditionals(attackedTile = tileList.firstOrNull())
|
||||
val weightings = resourceOptions.map {
|
||||
val weightings = resourceOptions.associateWith {
|
||||
val unique = it.getMatchingUniques(UniqueType.ResourceWeighting, conditionalTerrain).firstOrNull()
|
||||
if (unique != null)
|
||||
unique.params[0].toFloat()
|
||||
else
|
||||
1f
|
||||
val weight = if (unique != null) unique.params[0].toFloat() else 1f
|
||||
weight
|
||||
}
|
||||
val testTerrains = (resourceOptions.size == 1) && !forcePlacement
|
||||
val amountToPlace = (tileList.size / frequency) + 1
|
||||
var amountPlaced = 0
|
||||
val detailedPlaced = HashMap<TileResource, Int>()
|
||||
@ -45,17 +42,15 @@ object MapRegionResources {
|
||||
val fallbackTiles = ArrayList<Tile>()
|
||||
// First pass - avoid impacts entirely
|
||||
for (tile in tileList) {
|
||||
if (tile.resource != null ||
|
||||
(testTerrains &&
|
||||
(tile.lastTerrain.name !in resourceOptions.first().terrainsCanBeFoundOn ||
|
||||
resourceOptions.first().hasUnique(UniqueType.NoNaturalGeneration, conditionalTerrain)) ) ||
|
||||
tile.getBaseTerrain().hasUnique(UniqueType.BlocksResources, conditionalTerrain))
|
||||
continue // Can't place here, can't be a fallback tile
|
||||
if (tile.resource != null) continue
|
||||
val possibleResourcesForTile = resourceOptions.filter { it.generatesNaturallyOn(tile) }
|
||||
if (possibleResourcesForTile.isEmpty()) continue
|
||||
|
||||
if (tileData[tile.position]!!.impacts.containsKey(impactType)) {
|
||||
fallbackTiles.add(tile) // Taken but might be a viable fallback tile
|
||||
} else {
|
||||
// Add a resource to the tile
|
||||
val resourceToPlace = resourceOptions.randomWeighted(weightings)
|
||||
val resourceToPlace = possibleResourcesForTile.randomWeighted(possibleResourcesForTile.map { weightings[it] ?: 0f })
|
||||
tile.setTileResource(resourceToPlace, majorDeposit)
|
||||
tileData.placeImpact(impactType, tile, baseImpact + Random.nextInt(randomImpact + 1))
|
||||
amountPlaced++
|
||||
@ -70,7 +65,8 @@ object MapRegionResources {
|
||||
// Sorry, we do need to re-sort the list for every pass since new impacts are made with every placement
|
||||
val bestTile = fallbackTiles.minByOrNull { tileData[it.position]!!.impacts[impactType]!! }!!
|
||||
fallbackTiles.remove(bestTile)
|
||||
val resourceToPlace = resourceOptions.randomWeighted(weightings)
|
||||
val possibleResourcesForTile = resourceOptions.filter { it.generatesNaturallyOn(bestTile) }
|
||||
val resourceToPlace = possibleResourcesForTile.randomWeighted(possibleResourcesForTile.map { weightings[it] ?: 0f })
|
||||
bestTile.setTileResource(resourceToPlace, majorDeposit)
|
||||
tileData.placeImpact(impactType, bestTile, baseImpact + Random.nextInt(randomImpact + 1))
|
||||
amountPlaced++
|
||||
@ -95,17 +91,7 @@ object MapRegionResources {
|
||||
}
|
||||
|
||||
for (tile in tiles) {
|
||||
val conditionalTerrain = StateForConditionals(attackedTile = tile)
|
||||
if (tile.resource == null &&
|
||||
tile.lastTerrain.name in resource.terrainsCanBeFoundOn &&
|
||||
!tile.getBaseTerrain().hasUnique(UniqueType.BlocksResources, conditionalTerrain) &&
|
||||
!resource.hasUnique(UniqueType.NoNaturalGeneration, conditionalTerrain) &&
|
||||
|
||||
resource.getMatchingUniques(UniqueType.TileGenerationConditions).none {
|
||||
tile.temperature!! !in it.params[0].toDouble() .. it.params[1].toDouble()
|
||||
|| tile.humidity!! !in it.params[2].toDouble() .. it.params[3].toDouble()
|
||||
}
|
||||
) {
|
||||
if (tile.resource == null && resource.generatesNaturallyOn(tile)) {
|
||||
if (ratioProgress >= 1f &&
|
||||
!(respectImpacts && tileData[tile.position]!!.impacts.containsKey(impactType))) {
|
||||
tile.setTileResource(resource, majorDeposit)
|
||||
|
@ -792,7 +792,7 @@ class MapRegions (val ruleset: Ruleset) {
|
||||
continue
|
||||
val weightings = strategicResources.map {
|
||||
if (fallbackStrategic) {
|
||||
if (tile.lastTerrain.name in it.terrainsCanBeFoundOn) 1f else 0f
|
||||
if (it.generatesNaturallyOn(tile)) 1f else 0f
|
||||
} else {
|
||||
val uniques = it.getMatchingUniques(UniqueType.MinorDepositWeighting, conditionalTerrain).toList()
|
||||
uniques.sumOf { unique -> unique.params[0].toInt() }.toFloat()
|
||||
@ -822,10 +822,10 @@ class MapRegions (val ruleset: Ruleset) {
|
||||
for (resource in strategicResources) {
|
||||
val extraNeeded = min(2, regions.size - totalPlaced[resource]!!)
|
||||
if (extraNeeded > 0) {
|
||||
if (isWaterOnlyResource(resource, ruleset))
|
||||
MapRegionResources.tryAddingResourceToTiles(tileData, resource, extraNeeded, tileMap.values.asSequence().filter { it.isWater }.shuffled(), respectImpacts = true)
|
||||
else
|
||||
MapRegionResources.tryAddingResourceToTiles(tileData, resource, extraNeeded, landList.asSequence(), respectImpacts = true)
|
||||
val tilesToAddTo = if (!isWaterOnlyResource(resource, ruleset)) landList.asSequence()
|
||||
else tileMap.values.asSequence().filter { it.isWater }.shuffled()
|
||||
|
||||
MapRegionResources.tryAddingResourceToTiles(tileData, resource, extraNeeded, tilesToAddTo, respectImpacts = true)
|
||||
}
|
||||
}
|
||||
|
||||
|
@ -162,9 +162,7 @@ object StartNormalizer {
|
||||
|
||||
if (plot.resource != null) continue
|
||||
|
||||
val bonusToPlace =
|
||||
productionBonuses.filter { plot.lastTerrain.name in it.terrainsCanBeFoundOn }
|
||||
.randomOrNull()
|
||||
val bonusToPlace = productionBonuses.filter { it.generatesNaturallyOn(plot) }.randomOrNull()
|
||||
if (bonusToPlace != null) {
|
||||
plot.resource = bonusToPlace.name
|
||||
productionBonusesNeeded--
|
||||
@ -280,7 +278,7 @@ object StartNormalizer {
|
||||
val validBonuses = ruleset.tileResources.values.filter {
|
||||
it.resourceType == ResourceType.Bonus &&
|
||||
it.food >= 1 &&
|
||||
plot.lastTerrain.name in it.terrainsCanBeFoundOn
|
||||
it.generatesNaturallyOn(plot)
|
||||
}
|
||||
val goodPlotForOasis =
|
||||
canPlaceOasis && plot.lastTerrain.name in oasisEquivalent!!.occursOn
|
||||
|
@ -380,7 +380,7 @@ open class Tile : IsPartOfGameInfoSerialization {
|
||||
return civInfo.isAtWarWith(tileOwner)
|
||||
}
|
||||
|
||||
fun isRoughTerrain() = allTerrains.any{ it.isRough() }
|
||||
fun isRoughTerrain() = allTerrains.any { it.isRough() }
|
||||
|
||||
/** Checks whether any of the TERRAINS of this tile has a certain unique */
|
||||
fun terrainHasUnique(uniqueType: UniqueType) = terrainUniqueMap.getUniques(uniqueType).any()
|
||||
|
@ -2,6 +2,7 @@ package com.unciv.models.ruleset.tile
|
||||
|
||||
import com.badlogic.gdx.graphics.Color
|
||||
import com.unciv.Constants
|
||||
import com.unciv.logic.map.tile.Tile
|
||||
import com.unciv.models.ruleset.Belief
|
||||
import com.unciv.models.ruleset.Ruleset
|
||||
import com.unciv.models.ruleset.RulesetStatsObject
|
||||
@ -143,6 +144,10 @@ class Terrain : RulesetStatsObject() {
|
||||
return textList
|
||||
}
|
||||
|
||||
fun canBePlacedOn(tile: Tile){
|
||||
|
||||
}
|
||||
|
||||
fun setTransients() {
|
||||
damagePerTurn = getMatchingUniques(UniqueType.DamagesContainingUnits).sumOf { it.params[0].toInt() }
|
||||
}
|
||||
|
@ -207,7 +207,7 @@ class TileImprovement : RulesetStatsObject() {
|
||||
val cannotFilters = getMatchingUniques(UniqueType.CannotBuildOnTile).map { it.params[0] }.toSet()
|
||||
val resourcesImprovedByThis = ruleset.tileResources.values.filter { it.isImprovedBy(name) }
|
||||
|
||||
val expandedCanBeBuiltOn = sequence {
|
||||
val expandedTerrainsCanBeBuiltOn = sequence {
|
||||
yieldAll(terrainsCanBeBuiltOn)
|
||||
yieldAll(terrainsCanBeBuiltOn.asSequence().mapNotNull { ruleset.terrains[it] }.flatMap { it.occursOn.asSequence() })
|
||||
if (hasUnique(UniqueType.CanOnlyImproveResource))
|
||||
@ -220,21 +220,21 @@ class TileImprovement : RulesetStatsObject() {
|
||||
}.filter { it !in cannotFilters }.toMutableSet()
|
||||
|
||||
val terrainsCanBeBuiltOnTypes = sequence {
|
||||
yieldAll(expandedCanBeBuiltOn.asSequence()
|
||||
yieldAll(expandedTerrainsCanBeBuiltOn.asSequence()
|
||||
.mapNotNull { ruleset.terrains[it]?.type })
|
||||
yieldAll(TerrainType.values().asSequence()
|
||||
.filter { it.name in expandedCanBeBuiltOn })
|
||||
.filter { it.name in expandedTerrainsCanBeBuiltOn })
|
||||
}.filter { it.name !in cannotFilters }.toMutableSet()
|
||||
|
||||
if (canOnlyFilters.isNotEmpty() && canOnlyFilters.intersect(expandedCanBeBuiltOn).isEmpty()) {
|
||||
expandedCanBeBuiltOn.clear()
|
||||
if (canOnlyFilters.isNotEmpty() && canOnlyFilters.intersect(expandedTerrainsCanBeBuiltOn).isEmpty()) {
|
||||
expandedTerrainsCanBeBuiltOn.clear()
|
||||
if (terrainsCanBeBuiltOnTypes.none { it.name in canOnlyFilters })
|
||||
terrainsCanBeBuiltOnTypes.clear()
|
||||
}
|
||||
|
||||
fun matchesBuildImprovementsFilter(filter: String) =
|
||||
matchesFilter(filter) ||
|
||||
filter in expandedCanBeBuiltOn ||
|
||||
filter in expandedTerrainsCanBeBuiltOn ||
|
||||
terrainsCanBeBuiltOnTypes.any { it.name == filter }
|
||||
|
||||
return ruleset.units.values.asSequence()
|
||||
|
@ -50,9 +50,8 @@ class TileResource : RulesetStatsObject() {
|
||||
if (terrainsCanBeFoundOn.isNotEmpty()) {
|
||||
textList += FormattedLine()
|
||||
if (terrainsCanBeFoundOn.size == 1) {
|
||||
with (terrainsCanBeFoundOn[0]) {
|
||||
textList += FormattedLine("{Can be found on} {$this}", link = "Terrain/$this")
|
||||
}
|
||||
val terrainName = terrainsCanBeFoundOn[0]
|
||||
textList += FormattedLine("{Can be found on} {$terrainName}", link = "Terrain/$terrainName")
|
||||
} else {
|
||||
textList += FormattedLine("{Can be found on}:")
|
||||
terrainsCanBeFoundOn.forEach {
|
||||
@ -142,6 +141,21 @@ class TileResource : RulesetStatsObject() {
|
||||
}
|
||||
}
|
||||
|
||||
fun generatesNaturallyOn(tile:Tile): Boolean {
|
||||
if (tile.lastTerrain.name !in terrainsCanBeFoundOn) return false
|
||||
val stateForConditionals = StateForConditionals(tile = tile)
|
||||
if (hasUnique(UniqueType.NoNaturalGeneration, stateForConditionals)) return false
|
||||
if (tile.allTerrains.any { it.hasUnique(UniqueType.BlocksResources, stateForConditionals) }) return false
|
||||
|
||||
if (tile.temperature!=null && tile.humidity!=null) // Only works when in map generation
|
||||
for (unique in getMatchingUniques(UniqueType.TileGenerationConditions, stateForConditionals)){
|
||||
if (tile.temperature!! !in unique.params[0].toDouble() .. unique.params[1].toDouble()) return false
|
||||
if (tile.humidity!! !in unique.params[2].toDouble() .. unique.params[3].toDouble()) return false
|
||||
}
|
||||
|
||||
return true
|
||||
}
|
||||
|
||||
fun isStockpiled() = hasUnique(UniqueType.Stockpiled)
|
||||
|
||||
class DepositAmount {
|
||||
@ -149,5 +163,4 @@ class TileResource : RulesetStatsObject() {
|
||||
var default: Int = 2
|
||||
var abundant: Int = 3
|
||||
}
|
||||
|
||||
}
|
||||
|
@ -790,9 +790,6 @@ Simple unique parameters are explained by mouseover. Complex parameters are expl
|
||||
|
||||
Applicable to: Global, Unit
|
||||
|
||||
??? example "+30% Strength when fighting City-State units and cities"
|
||||
Applicable to: Global
|
||||
|
||||
??? example "[amount] additional attacks per turn"
|
||||
Example: "[3] additional attacks per turn"
|
||||
|
||||
@ -2026,6 +2023,11 @@ Simple unique parameters are explained by mouseover. Complex parameters are expl
|
||||
|
||||
Applicable to: Conditional
|
||||
|
||||
??? example "<vs [combatantFilter]>"
|
||||
Example: "<vs [City]>"
|
||||
|
||||
Applicable to: Conditional
|
||||
|
||||
??? example "<when fighting units from a Civilization with more Cities than you>"
|
||||
Applicable to: Conditional
|
||||
|
||||
@ -2066,23 +2068,23 @@ Simple unique parameters are explained by mouseover. Complex parameters are expl
|
||||
|
||||
Applicable to: Conditional
|
||||
|
||||
??? example "<with [amount] to [amount] neighboring [tileFilter] [tileFilter] tiles>"
|
||||
Example: "<with [3] to [3] neighboring [Farm] [Farm] tiles>"
|
||||
|
||||
Applicable to: Conditional
|
||||
|
||||
??? example "<in [tileFilter] tiles>"
|
||||
Example: "<in [Farm] tiles>"
|
||||
|
||||
Applicable to: Conditional
|
||||
|
||||
??? example "<in [tileFilter] [tileFilter] tiles>"
|
||||
Example: "<in [Farm] [Farm] tiles>"
|
||||
??? example "<in tiles without [tileFilter]>"
|
||||
Example: "<in tiles without [Farm]>"
|
||||
|
||||
Applicable to: Conditional
|
||||
|
||||
??? example "<in tiles without [tileFilter]>"
|
||||
Example: "<in tiles without [Farm]>"
|
||||
??? example "<in tiles adjacent to [tileFilter]>"
|
||||
Example: "<in tiles adjacent to [Farm]>"
|
||||
|
||||
Applicable to: Conditional
|
||||
|
||||
??? example "<in tiles not adjacent to [tileFilter]>"
|
||||
Example: "<in tiles not adjacent to [Farm]>"
|
||||
|
||||
Applicable to: Conditional
|
||||
|
||||
|
Loading…
Reference in New Issue
Block a user