mirror of
https://github.com/yairm210/Unciv.git
synced 2025-09-25 21:03:15 -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.MapType
|
||||
import com.unciv.logic.map.TileMap
|
||||
import com.unciv.logic.map.mapgenerator.mapregions.MapRegions
|
||||
import com.unciv.logic.map.tile.Tile
|
||||
import com.unciv.models.Counter
|
||||
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.Vector2
|
||||
@ -7,6 +7,7 @@ import com.unciv.logic.civilization.Civilization
|
||||
import com.unciv.logic.map.MapResources
|
||||
import com.unciv.logic.map.MapShape
|
||||
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.models.metadata.GameParameters
|
||||
import com.unciv.models.ruleset.Ruleset
|
||||
@ -245,8 +246,7 @@ class MapRegions (val ruleset: Ruleset){
|
||||
|
||||
// Generate tile data for all tiles
|
||||
for (tile in tileMap.values) {
|
||||
val newData = MapGenTileData(tile, regions.firstOrNull { it.tiles.contains(tile) })
|
||||
newData.evaluate(ruleset)
|
||||
val newData = MapGenTileData(tile, regions.firstOrNull { it.tiles.contains(tile) }, ruleset)
|
||||
tileData[tile.position] = newData
|
||||
}
|
||||
|
||||
@ -1628,156 +1628,6 @@ class MapRegions (val ruleset: Ruleset){
|
||||
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.city.City
|
||||
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.tile.Tile
|
||||
|
||||
|
Loading…
x
Reference in New Issue
Block a user