mirror of
https://github.com/yairm210/Unciv.git
synced 2025-09-28 14:24:43 -04:00
chore: Split MapRegions into class files, first step of refactor
This commit is contained in:
parent
9386e4a7ce
commit
1e085eb60a
@ -8,6 +8,7 @@ import com.unciv.logic.map.MapParameters
|
|||||||
import com.unciv.logic.map.MapShape
|
import com.unciv.logic.map.MapShape
|
||||||
import com.unciv.logic.map.MapType
|
import com.unciv.logic.map.MapType
|
||||||
import com.unciv.logic.map.TileMap
|
import com.unciv.logic.map.TileMap
|
||||||
|
import com.unciv.logic.map.mapgenerator.mapregions.MapRegions
|
||||||
import com.unciv.logic.map.tile.Tile
|
import com.unciv.logic.map.tile.Tile
|
||||||
import com.unciv.models.Counter
|
import com.unciv.models.Counter
|
||||||
import com.unciv.models.metadata.GameParameters
|
import com.unciv.models.metadata.GameParameters
|
||||||
|
@ -0,0 +1,94 @@
|
|||||||
|
package com.unciv.logic.map.mapgenerator.mapregions
|
||||||
|
|
||||||
|
import com.unciv.logic.map.tile.Tile
|
||||||
|
import com.unciv.models.ruleset.Ruleset
|
||||||
|
import com.unciv.models.ruleset.unique.StateForConditionals
|
||||||
|
import com.unciv.models.ruleset.unique.UniqueType
|
||||||
|
import kotlin.math.max
|
||||||
|
import kotlin.math.min
|
||||||
|
|
||||||
|
// Holds a bunch of tile info that is only interesting during map gen
|
||||||
|
class MapGenTileData(val tile: Tile, val region: Region?, ruleset: Ruleset) {
|
||||||
|
var closeStartPenalty = 0
|
||||||
|
val impacts = HashMap<MapRegions.ImpactType, Int>()
|
||||||
|
var isFood = false
|
||||||
|
private set
|
||||||
|
var isProd = false
|
||||||
|
private set
|
||||||
|
var isGood = false
|
||||||
|
private set
|
||||||
|
var isJunk = false
|
||||||
|
private set
|
||||||
|
var isTwoFromCoast = false
|
||||||
|
private set
|
||||||
|
|
||||||
|
var isGoodStart = true
|
||||||
|
var startScore = 0
|
||||||
|
|
||||||
|
init {
|
||||||
|
evaluate(ruleset)
|
||||||
|
}
|
||||||
|
|
||||||
|
fun addCloseStartPenalty(penalty: Int) {
|
||||||
|
if (closeStartPenalty == 0)
|
||||||
|
closeStartPenalty = penalty
|
||||||
|
else {
|
||||||
|
// Multiple overlapping values - take the higher one and add 20 %
|
||||||
|
closeStartPenalty = max(closeStartPenalty, penalty)
|
||||||
|
closeStartPenalty = min(97, (closeStartPenalty * 1.2f).toInt())
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
/** Populates all private-set fields */
|
||||||
|
private fun evaluate(ruleset: Ruleset) {
|
||||||
|
// Check if we are two tiles from coast (a bad starting site)
|
||||||
|
if (!tile.isCoastalTile() && tile.neighbors.any { it.isCoastalTile() })
|
||||||
|
isTwoFromCoast = true
|
||||||
|
|
||||||
|
// Check first available out of unbuildable features, then other features, then base terrain
|
||||||
|
val terrainToCheck = if (tile.terrainFeatures.isEmpty()) tile.getBaseTerrain()
|
||||||
|
else tile.terrainFeatureObjects.firstOrNull { it.unbuildable }
|
||||||
|
?: tile.terrainFeatureObjects.first()
|
||||||
|
|
||||||
|
// Add all applicable qualities
|
||||||
|
for (unique in terrainToCheck.getMatchingUniques(
|
||||||
|
UniqueType.HasQuality,
|
||||||
|
StateForConditionals(region = region)
|
||||||
|
)) {
|
||||||
|
when (unique.params[0]) {
|
||||||
|
"Food" -> isFood = true
|
||||||
|
"Desirable" -> isGood = true
|
||||||
|
"Production" -> isProd = true
|
||||||
|
"Undesirable" -> isJunk = true
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
// Were there in fact no explicit qualities defined for any region at all? If so let's guess at qualities to preserve mod compatibility.
|
||||||
|
if (terrainToCheck.uniqueObjects.none { it.type == UniqueType.HasQuality }) {
|
||||||
|
if (tile.isWater) return // Most water type tiles have no qualities
|
||||||
|
|
||||||
|
// is it junk???
|
||||||
|
if (terrainToCheck.impassable) {
|
||||||
|
isJunk = true
|
||||||
|
return // Don't bother checking the rest, junk is junk
|
||||||
|
}
|
||||||
|
|
||||||
|
// Take possible improvements into account
|
||||||
|
val improvements = ruleset.tileImprovements.values.filter {
|
||||||
|
terrainToCheck.name in it.terrainsCanBeBuiltOn &&
|
||||||
|
it.uniqueTo == null &&
|
||||||
|
!it.hasUnique(UniqueType.GreatImprovement)
|
||||||
|
}
|
||||||
|
|
||||||
|
val maxFood = terrainToCheck.food + (improvements.maxOfOrNull { it.food } ?: 0f)
|
||||||
|
val maxProd = terrainToCheck.production + (improvements.maxOfOrNull { it.production } ?: 0f)
|
||||||
|
val bestImprovementValue = improvements.maxOfOrNull { it.food + it.production + it.gold + it.culture + it.science + it.faith } ?: 0f
|
||||||
|
val maxOverall = terrainToCheck.food + terrainToCheck.production + terrainToCheck.gold +
|
||||||
|
terrainToCheck.culture + terrainToCheck.science + terrainToCheck.faith + bestImprovementValue
|
||||||
|
|
||||||
|
if (maxFood >= 2) isFood = true
|
||||||
|
if (maxProd >= 2) isProd = true
|
||||||
|
if (maxOverall >= 3) isGood = true
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
@ -1,4 +1,4 @@
|
|||||||
package com.unciv.logic.map.mapgenerator
|
package com.unciv.logic.map.mapgenerator.mapregions
|
||||||
|
|
||||||
import com.badlogic.gdx.math.Rectangle
|
import com.badlogic.gdx.math.Rectangle
|
||||||
import com.badlogic.gdx.math.Vector2
|
import com.badlogic.gdx.math.Vector2
|
||||||
@ -7,6 +7,7 @@ import com.unciv.logic.civilization.Civilization
|
|||||||
import com.unciv.logic.map.MapResources
|
import com.unciv.logic.map.MapResources
|
||||||
import com.unciv.logic.map.MapShape
|
import com.unciv.logic.map.MapShape
|
||||||
import com.unciv.logic.map.TileMap
|
import com.unciv.logic.map.TileMap
|
||||||
|
import com.unciv.logic.map.mapgenerator.mapregions.MapRegions.BiasTypes.PositiveFallback
|
||||||
import com.unciv.logic.map.tile.Tile
|
import com.unciv.logic.map.tile.Tile
|
||||||
import com.unciv.models.metadata.GameParameters
|
import com.unciv.models.metadata.GameParameters
|
||||||
import com.unciv.models.ruleset.Ruleset
|
import com.unciv.models.ruleset.Ruleset
|
||||||
@ -245,8 +246,7 @@ class MapRegions (val ruleset: Ruleset){
|
|||||||
|
|
||||||
// Generate tile data for all tiles
|
// Generate tile data for all tiles
|
||||||
for (tile in tileMap.values) {
|
for (tile in tileMap.values) {
|
||||||
val newData = MapGenTileData(tile, regions.firstOrNull { it.tiles.contains(tile) })
|
val newData = MapGenTileData(tile, regions.firstOrNull { it.tiles.contains(tile) }, ruleset)
|
||||||
newData.evaluate(ruleset)
|
|
||||||
tileData[tile.position] = newData
|
tileData[tile.position] = newData
|
||||||
}
|
}
|
||||||
|
|
||||||
@ -1628,156 +1628,6 @@ class MapRegions (val ruleset: Ruleset){
|
|||||||
MinorCiv,
|
MinorCiv,
|
||||||
}
|
}
|
||||||
|
|
||||||
// Holds a bunch of tile info that is only interesting during map gen
|
|
||||||
class MapGenTileData(val tile: Tile, val region: Region?) {
|
|
||||||
var closeStartPenalty = 0
|
|
||||||
val impacts = HashMap<ImpactType, Int>()
|
|
||||||
var isFood = false
|
|
||||||
var isProd = false
|
|
||||||
var isGood = false
|
|
||||||
var isJunk = false
|
|
||||||
var isTwoFromCoast = false
|
|
||||||
|
|
||||||
var isGoodStart = true
|
|
||||||
var startScore = 0
|
|
||||||
|
|
||||||
fun addCloseStartPenalty(penalty: Int) {
|
|
||||||
if (closeStartPenalty == 0)
|
|
||||||
closeStartPenalty = penalty
|
|
||||||
else {
|
|
||||||
// Multiple overlapping values - take the higher one and add 20 %
|
|
||||||
closeStartPenalty = max(closeStartPenalty, penalty)
|
|
||||||
closeStartPenalty = min(97, (closeStartPenalty * 1.2f).toInt())
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
fun evaluate(ruleset: Ruleset) {
|
|
||||||
// Check if we are two tiles from coast (a bad starting site)
|
|
||||||
if (!tile.isCoastalTile() && tile.neighbors.any { it.isCoastalTile() })
|
|
||||||
isTwoFromCoast = true
|
|
||||||
|
|
||||||
// Check first available out of unbuildable features, then other features, then base terrain
|
|
||||||
val terrainToCheck = if (tile.terrainFeatures.isEmpty()) tile.getBaseTerrain()
|
|
||||||
else tile.terrainFeatureObjects.firstOrNull { it.unbuildable }
|
|
||||||
?: tile.terrainFeatureObjects.first()
|
|
||||||
|
|
||||||
// Add all applicable qualities
|
|
||||||
for (unique in terrainToCheck.getMatchingUniques(UniqueType.HasQuality, StateForConditionals(region = region))) {
|
|
||||||
when (unique.params[0]) {
|
|
||||||
"Food" -> isFood = true
|
|
||||||
"Desirable" -> isGood = true
|
|
||||||
"Production" -> isProd = true
|
|
||||||
"Undesirable" -> isJunk = true
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
// Were there in fact no explicit qualities defined for any region at all? If so let's guess at qualities to preserve mod compatibility.
|
|
||||||
if (terrainToCheck.uniqueObjects.none { it.type == UniqueType.HasQuality }) {
|
|
||||||
if (tile.isWater) return // Most water type tiles have no qualities
|
|
||||||
|
|
||||||
// is it junk???
|
|
||||||
if (terrainToCheck.impassable) {
|
|
||||||
isJunk = true
|
|
||||||
return // Don't bother checking the rest, junk is junk
|
|
||||||
}
|
|
||||||
|
|
||||||
// Take possible improvements into account
|
|
||||||
val improvements = ruleset.tileImprovements.values.filter {
|
|
||||||
terrainToCheck.name in it.terrainsCanBeBuiltOn &&
|
|
||||||
it.uniqueTo == null &&
|
|
||||||
!it.hasUnique(UniqueType.GreatImprovement)
|
|
||||||
}
|
|
||||||
|
|
||||||
val maxFood = terrainToCheck.food + (improvements.maxOfOrNull { it.food } ?: 0f)
|
|
||||||
val maxProd = terrainToCheck.production + (improvements.maxOfOrNull { it.production } ?: 0f)
|
|
||||||
val bestImprovementValue = improvements.maxOfOrNull { it.food + it.production + it.gold + it.culture + it.science + it.faith } ?: 0f
|
|
||||||
val maxOverall = terrainToCheck.food + terrainToCheck.production + terrainToCheck.gold +
|
|
||||||
terrainToCheck.culture + terrainToCheck.science + terrainToCheck.faith + bestImprovementValue
|
|
||||||
|
|
||||||
if (maxFood >= 2) isFood = true
|
|
||||||
if (maxProd >= 2) isProd = true
|
|
||||||
if (maxOverall >= 3) isGood = true
|
|
||||||
}
|
|
||||||
}
|
|
||||||
}
|
|
||||||
}
|
}
|
||||||
|
|
||||||
class Region (val tileMap: TileMap, val rect: Rectangle, val continentID: Int = -1) {
|
|
||||||
val tiles = HashSet<Tile>()
|
|
||||||
val terrainCounts = HashMap<String, Int>()
|
|
||||||
var totalFertility = 0
|
|
||||||
var type = "Hybrid" // being an undefined or indeterminate type
|
|
||||||
var luxury: String? = null
|
|
||||||
var startPosition: Vector2? = null
|
|
||||||
val assignedMinorCivs = ArrayList<Civilization>()
|
|
||||||
|
|
||||||
var affectedByWorldWrap = false
|
|
||||||
|
|
||||||
/** Recalculates tiles and fertility */
|
|
||||||
fun updateTiles(trim: Boolean = true) {
|
|
||||||
totalFertility = 0
|
|
||||||
var minColumn = 99999f
|
|
||||||
var maxColumn = -99999f
|
|
||||||
var minRow = 99999f
|
|
||||||
var maxRow = -99999f
|
|
||||||
|
|
||||||
val columnHasTile = HashSet<Int>()
|
|
||||||
|
|
||||||
tiles.clear()
|
|
||||||
for (tile in tileMap.getTilesInRectangle(rect).filter {
|
|
||||||
continentID == -1 || it.getContinent() == continentID } ) {
|
|
||||||
val fertility = tile.getTileFertility(continentID != -1)
|
|
||||||
tiles.add(tile)
|
|
||||||
totalFertility += fertility
|
|
||||||
|
|
||||||
if (affectedByWorldWrap)
|
|
||||||
columnHasTile.add(tile.getColumn())
|
|
||||||
|
|
||||||
if (trim) {
|
|
||||||
val row = tile.getRow().toFloat()
|
|
||||||
val column = tile.getColumn().toFloat()
|
|
||||||
minColumn = min(minColumn, column)
|
|
||||||
maxColumn = max(maxColumn, column)
|
|
||||||
minRow = min(minRow, row)
|
|
||||||
maxRow = max(maxRow, row)
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
if (trim) {
|
|
||||||
if (affectedByWorldWrap) // Need to be more thorough with origin longitude
|
|
||||||
rect.x = columnHasTile.filter { !columnHasTile.contains(it - 1) }.maxOf { it }.toFloat()
|
|
||||||
else
|
|
||||||
rect.x = minColumn // ez way for non-wrapping regions
|
|
||||||
rect.y = minRow
|
|
||||||
rect.height = maxRow - minRow + 1
|
|
||||||
if (affectedByWorldWrap && minColumn < rect.x) { // Thorough way
|
|
||||||
rect.width = columnHasTile.size.toFloat()
|
|
||||||
} else {
|
|
||||||
rect.width = maxColumn - minColumn + 1 // ez way
|
|
||||||
affectedByWorldWrap = false // also we're not wrapping anymore
|
|
||||||
}
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
/** Counts the terrains in the Region for type and start determination */
|
|
||||||
fun countTerrains() {
|
|
||||||
// Count terrains in the region
|
|
||||||
terrainCounts.clear()
|
|
||||||
for (tile in tiles) {
|
|
||||||
val terrainsToCount = if (tile.terrainHasUnique(UniqueType.IgnoreBaseTerrainForRegion))
|
|
||||||
tile.terrainFeatureObjects.map { it.name }.asSequence()
|
|
||||||
else
|
|
||||||
tile.allTerrains.map { it.name }
|
|
||||||
for (terrain in terrainsToCount) {
|
|
||||||
terrainCounts[terrain] = (terrainCounts[terrain] ?: 0) + 1
|
|
||||||
}
|
|
||||||
if (tile.isCoastalTile())
|
|
||||||
terrainCounts["Coastal"] = (terrainCounts["Coastal"] ?: 0) + 1
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
/** Returns number terrains with [name] */
|
|
||||||
fun getTerrainAmount(name: String) = terrainCounts[name] ?: 0
|
|
||||||
|
|
||||||
override fun toString() = "Region($type, ${tiles.size} tiles, ${terrainCounts.entries.joinToString { "${it.value} ${it.key}" }})"
|
|
||||||
}
|
|
@ -0,0 +1,90 @@
|
|||||||
|
package com.unciv.logic.map.mapgenerator.mapregions
|
||||||
|
|
||||||
|
import com.badlogic.gdx.math.Rectangle
|
||||||
|
import com.badlogic.gdx.math.Vector2
|
||||||
|
import com.unciv.logic.civilization.Civilization
|
||||||
|
import com.unciv.logic.map.TileMap
|
||||||
|
import com.unciv.logic.map.tile.Tile
|
||||||
|
import com.unciv.models.ruleset.unique.UniqueType
|
||||||
|
import kotlin.math.max
|
||||||
|
import kotlin.math.min
|
||||||
|
|
||||||
|
class Region (val tileMap: TileMap, val rect: Rectangle, val continentID: Int = -1) {
|
||||||
|
val tiles = HashSet<Tile>()
|
||||||
|
val terrainCounts = HashMap<String, Int>()
|
||||||
|
var totalFertility = 0
|
||||||
|
var type = "Hybrid" // being an undefined or indeterminate type
|
||||||
|
var luxury: String? = null
|
||||||
|
var startPosition: Vector2? = null
|
||||||
|
val assignedMinorCivs = ArrayList<Civilization>()
|
||||||
|
|
||||||
|
var affectedByWorldWrap = false
|
||||||
|
|
||||||
|
/** Recalculates tiles and fertility */
|
||||||
|
fun updateTiles(trim: Boolean = true) {
|
||||||
|
totalFertility = 0
|
||||||
|
var minColumn = 99999f
|
||||||
|
var maxColumn = -99999f
|
||||||
|
var minRow = 99999f
|
||||||
|
var maxRow = -99999f
|
||||||
|
|
||||||
|
val columnHasTile = HashSet<Int>()
|
||||||
|
|
||||||
|
tiles.clear()
|
||||||
|
for (tile in tileMap.getTilesInRectangle(rect).filter {
|
||||||
|
continentID == -1 || it.getContinent() == continentID } ) {
|
||||||
|
val fertility = tile.getTileFertility(continentID != -1)
|
||||||
|
tiles.add(tile)
|
||||||
|
totalFertility += fertility
|
||||||
|
|
||||||
|
if (affectedByWorldWrap)
|
||||||
|
columnHasTile.add(tile.getColumn())
|
||||||
|
|
||||||
|
if (trim) {
|
||||||
|
val row = tile.getRow().toFloat()
|
||||||
|
val column = tile.getColumn().toFloat()
|
||||||
|
minColumn = min(minColumn, column)
|
||||||
|
maxColumn = max(maxColumn, column)
|
||||||
|
minRow = min(minRow, row)
|
||||||
|
maxRow = max(maxRow, row)
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
if (trim) {
|
||||||
|
if (affectedByWorldWrap) // Need to be more thorough with origin longitude
|
||||||
|
rect.x = columnHasTile.filter { !columnHasTile.contains(it - 1) }.maxOf { it }.toFloat()
|
||||||
|
else
|
||||||
|
rect.x = minColumn // ez way for non-wrapping regions
|
||||||
|
rect.y = minRow
|
||||||
|
rect.height = maxRow - minRow + 1
|
||||||
|
if (affectedByWorldWrap && minColumn < rect.x) { // Thorough way
|
||||||
|
rect.width = columnHasTile.size.toFloat()
|
||||||
|
} else {
|
||||||
|
rect.width = maxColumn - minColumn + 1 // ez way
|
||||||
|
affectedByWorldWrap = false // also we're not wrapping anymore
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
/** Counts the terrains in the Region for type and start determination */
|
||||||
|
fun countTerrains() {
|
||||||
|
// Count terrains in the region
|
||||||
|
terrainCounts.clear()
|
||||||
|
for (tile in tiles) {
|
||||||
|
val terrainsToCount = if (tile.terrainHasUnique(UniqueType.IgnoreBaseTerrainForRegion))
|
||||||
|
tile.terrainFeatureObjects.map { it.name }.asSequence()
|
||||||
|
else
|
||||||
|
tile.allTerrains.map { it.name }
|
||||||
|
for (terrain in terrainsToCount) {
|
||||||
|
terrainCounts[terrain] = (terrainCounts[terrain] ?: 0) + 1
|
||||||
|
}
|
||||||
|
if (tile.isCoastalTile())
|
||||||
|
terrainCounts["Coastal"] = (terrainCounts["Coastal"] ?: 0) + 1
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
/** Returns number terrains with [name] */
|
||||||
|
fun getTerrainAmount(name: String) = terrainCounts[name] ?: 0
|
||||||
|
|
||||||
|
override fun toString() = "Region($type, ${tiles.size} tiles, ${terrainCounts.entries.joinToString { "${it.value} ${it.key}" }})"
|
||||||
|
}
|
@ -4,7 +4,7 @@ import com.unciv.logic.battle.CombatAction
|
|||||||
import com.unciv.logic.battle.ICombatant
|
import com.unciv.logic.battle.ICombatant
|
||||||
import com.unciv.logic.city.City
|
import com.unciv.logic.city.City
|
||||||
import com.unciv.logic.civilization.Civilization
|
import com.unciv.logic.civilization.Civilization
|
||||||
import com.unciv.logic.map.mapgenerator.Region
|
import com.unciv.logic.map.mapgenerator.mapregions.Region
|
||||||
import com.unciv.logic.map.mapunit.MapUnit
|
import com.unciv.logic.map.mapunit.MapUnit
|
||||||
import com.unciv.logic.map.tile.Tile
|
import com.unciv.logic.map.tile.Tile
|
||||||
|
|
||||||
|
Loading…
x
Reference in New Issue
Block a user