Merge remote-tracking branch 'origin/master'

This commit is contained in:
yairm210 2021-10-19 20:26:54 +03:00
commit 55bed3bf30
11 changed files with 71 additions and 40 deletions

View File

@ -6,6 +6,7 @@ import com.unciv.logic.civilization.NotificationIcon
import com.unciv.logic.map.TileInfo
import com.unciv.logic.map.TileMap
import com.unciv.models.metadata.GameSpeed
import com.unciv.models.ruleset.unique.UniqueType
import java.util.*
import kotlin.collections.HashMap
import kotlin.math.max
@ -210,7 +211,7 @@ class Encampment {
|| it.isCityCenter()
|| it.getFirstUnit() != null
|| (it.isWater && !canSpawnBoats)
|| (it.hasUnique("Fresh water") && it.isWater) // No Lakes
|| (it.hasUnique(UniqueType.FreshWater) && it.isWater) // No Lakes
}
if (validTiles.isEmpty()) return false

View File

@ -704,13 +704,13 @@ object Battle {
tile.turnsToImprovement = 0
tile.roadStatus = RoadStatus.None
if (tile.isLand && !tile.isImpassible() && !tile.terrainFeatures.contains("Fallout")) {
if (tile.terrainFeatures.any { attacker.getCivInfo().gameInfo.ruleSet.terrains[it]!!.uniques.contains("Resistant to nukes") }) {
if (tile.terrainFeatures.any { attacker.getCivInfo().gameInfo.ruleSet.terrains[it]!!.hasUnique(UniqueType.ResistsNukes) }) {
if (Random().nextFloat() < 0.25f) {
tile.terrainFeatures.removeAll { attacker.getCivInfo().gameInfo.ruleSet.terrains[it]!!.uniques.contains("Can be destroyed by nukes") }
tile.terrainFeatures.removeAll { attacker.getCivInfo().gameInfo.ruleSet.terrains[it]!!.hasUnique(UniqueType.DestroyableByNukes) }
tile.terrainFeatures.add("Fallout")
}
} else if (Random().nextFloat() < 0.5f) {
tile.terrainFeatures.removeAll { attacker.getCivInfo().gameInfo.ruleSet.terrains[it]!!.uniques.contains("Can be destroyed by nukes") }
tile.terrainFeatures.removeAll { attacker.getCivInfo().gameInfo.ruleSet.terrains[it]!!.hasUnique(UniqueType.DestroyableByNukes) }
tile.terrainFeatures.add("Fallout")
}
}
@ -767,13 +767,13 @@ object Battle {
tile.turnsToImprovement = 0
tile.roadStatus = RoadStatus.None
if (tile.isLand && !tile.isImpassible() && !tile.terrainFeatures.contains("Fallout")) {
if (tile.terrainFeatures.any { attacker.getCivInfo().gameInfo.ruleSet.terrains[it]!!.uniques.contains("Resistant to nukes") }) {
if (tile.terrainFeatures.any { attacker.getCivInfo().gameInfo.ruleSet.terrains[it]!!.hasUnique(UniqueType.ResistsNukes) }) {
if (Random().nextFloat() < 0.25f) {
tile.terrainFeatures.removeAll { attacker.getCivInfo().gameInfo.ruleSet.terrains[it]!!.uniques.contains("Can be destroyed by nukes") }
tile.terrainFeatures.removeAll { attacker.getCivInfo().gameInfo.ruleSet.terrains[it]!!.hasUnique(UniqueType.DestroyableByNukes) }
tile.terrainFeatures.add("Fallout")
}
} else if (Random().nextFloat() < 0.5f) {
tile.terrainFeatures.removeAll { attacker.getCivInfo().gameInfo.ruleSet.terrains[it]!!.uniques.contains("Can be destroyed by nukes") }
tile.terrainFeatures.removeAll { attacker.getCivInfo().gameInfo.ruleSet.terrains[it]!!.hasUnique(UniqueType.DestroyableByNukes) }
tile.terrainFeatures.add("Fallout")
}
}

View File

@ -4,6 +4,7 @@ import com.unciv.logic.city.CityInfo
import com.unciv.logic.civilization.CivilizationInfo
import com.unciv.logic.map.TileInfo
import com.unciv.models.UncivSound
import com.unciv.models.ruleset.unique.UniqueType
import com.unciv.models.ruleset.unit.UnitType
import kotlin.math.pow
import kotlin.math.roundToInt
@ -39,9 +40,8 @@ class CityCombatant(val city: CityInfo) : ICombatant {
var strength = 8f
strength += (city.population.population / 5) * 2 // Each 5 pop gives 2 defence
val cityTile = city.getCenterTile()
for (unique in cityTile.getAllTerrains().flatMap { it.uniqueObjects })
if (unique.placeholderText == "[] Strength for cities built on this terrain")
strength += unique.params[0].toInt()
for (unique in cityTile.getAllTerrains().flatMap { it.getMatchingUniques(UniqueType.GrantsCityStrength) })
strength += unique.params[0].toInt()
// as tech progresses so does city strength
val techCount = getCivInfo().gameInfo.ruleSet.technologies.count()
val techsPercentKnown: Float = if (techCount > 0) city.civInfo.tech.techsResearched.count().toFloat() / techCount else 0.5f // for mods with no tech

View File

@ -294,6 +294,7 @@ class CityStateFunctions(val civInfo: CivilizationInfo) {
city.moveToCiv(otherCiv)
city.isPuppet = true // Human players get a popup that allows them to annex instead
city.foundingCiv = "" // This is no longer a city-state
city.isOriginalCapital = false // It's now an ordinary city and can be razed in later conquests
}
civInfo.destroy()
}

View File

@ -1,7 +1,6 @@
package com.unciv.logic.civilization
import com.badlogic.gdx.math.Vector2
import com.unciv.Constants
import com.unciv.UncivGame
import com.unciv.logic.GameInfo
import com.unciv.logic.UncivShowableException
@ -343,7 +342,7 @@ class CivilizationInfo {
cities.asSequence().flatMap {
city ->
if (cityItIsFor != null && city == cityItIsFor)
city.getAllUniquesWithNonLocalEffects().filter { it.params.none { param -> param == "in other cities" } }
city.getAllUniquesWithNonLocalEffects().filter { it.params.none { param -> param == "in other cities" || param == "in all cities" } }
else city.getAllUniquesWithNonLocalEffects()
}
@ -714,7 +713,7 @@ class CivilizationInfo {
passThroughImpassableUnlocked = passableImpassables.isNotEmpty()
// Cache whether this civ gets nonstandard terrain damage for performance reasons.
nonStandardTerrainDamage = getMatchingUniques("Units ending their turn on [] tiles take [] damage")
nonStandardTerrainDamage = getMatchingUniques(UniqueType.DamagesContainingUnits)
.any { gameInfo.ruleSet.terrains[it.params[0]]!!.damagePerTurn != it.params[1].toInt() }
// Cache the last era each resource is used for buildings or units respectively for AI building evaluation

View File

@ -614,9 +614,7 @@ class MapUnit {
tile.roadStatus = RoadStatus.None
else {
val removedFeatureObject = tile.ruleset.terrains[removedFeatureName]
if (removedFeatureObject != null && removedFeatureObject.uniques
.contains("Provides a one-time Production bonus to the closest city when cut down")
) {
if (removedFeatureObject != null && removedFeatureObject.hasUnique(UniqueType.ProductionBonusWhenRemoved)) {
tryProvideProductionToClosestCity(removedFeatureName)
}
tile.terrainFeatures.remove(removedFeatureName)
@ -1006,7 +1004,7 @@ class MapUnit {
fun getDamageFromTerrain(tile: TileInfo = currentTile): Int {
if (civInfo.nonStandardTerrainDamage) {
for (unique in getMatchingUniques("Units ending their turn on [] tiles take [] damage")) {
for (unique in getMatchingUniques(UniqueType.DamagesContainingUnits)) {
if (unique.params[0] in tile.getAllTerrains().map { it.name }) {
return unique.params[1].toInt() // Use the damage from the unique
}

View File

@ -436,7 +436,7 @@ open class TileInfo {
&& getTileImprovement().let { it != null && it.hasUnique("Irremovable") } -> false
// Terrain blocks most improvements
getAllTerrains().any { it.getMatchingUniques("Only [] improvements may be built on this tile")
getAllTerrains().any { it.getMatchingUniques(UniqueType.RestrictedBuildableImprovements)
.any { unique -> !improvement.matchesFilter(unique.params[0]) } } -> false
// Decide cancelImprovementOrder earlier, otherwise next check breaks it
@ -630,6 +630,17 @@ open class TileInfo {
FormattedLine("{$resource} ($resourceAmount)", link="Resource/$resource")
else
FormattedLine(resource!!, link="Resource/$resource")
if (resource != null && viewingCiv != null && hasViewableResource(viewingCiv)) {
val tileImprovement = ruleset.tileImprovements[getTileResource().improvement]
if (tileImprovement?.techRequired != null
&& !viewingCiv.tech.isResearched(tileImprovement.techRequired!!)) {
lineList += FormattedLine(
"Requires [${tileImprovement.techRequired}]",
link="Technology/${tileImprovement.techRequired}",
color= "#FAA"
)
}
}
if (naturalWonder != null)
lineList += FormattedLine(naturalWonder!!, link="Terrain/$naturalWonder")
if (roadStatus !== RoadStatus.None && !isCityCenter())

View File

@ -317,14 +317,17 @@ class TileMap {
This can all be summed up as "I can see c if a>b || c>b || (a==b && b !blocks same-elevation view)"
*/
val containsViewableNeighborThatCanSeeOver = cTile.neighbors.any {
bNeighbor: TileInfo ->
val containsViewableNeighborThatCanSeeOver = cTile.neighbors.any { bNeighbor: TileInfo ->
val bNeighborHeight = bNeighbor.height
viewableTiles.contains(bNeighbor) && (
currentTileHeight > bNeighborHeight // a>b
|| cTileHeight > bNeighborHeight // c>b
|| currentTileHeight == bNeighborHeight // a==b
&& !bNeighbor.hasUnique("Blocks line-of-sight from tiles at same elevation"))
viewableTiles.contains(bNeighbor)
&& (
currentTileHeight > bNeighborHeight // a>b
|| cTileHeight > bNeighborHeight // c>b
|| (
currentTileHeight == bNeighborHeight // a==b
&& !bNeighbor.hasUnique(UniqueType.BlocksLineOfSightAtSameElevation)
)
)
}
if (containsViewableNeighborThatCanSeeOver) tilesToAddInDistanceI.add(cTile)
}

View File

@ -9,6 +9,7 @@ import com.unciv.models.ruleset.Ruleset
import com.unciv.models.ruleset.tile.ResourceType
import com.unciv.models.ruleset.tile.Terrain
import com.unciv.models.ruleset.tile.TerrainType
import com.unciv.models.ruleset.unique.UniqueType
import kotlin.math.abs
import kotlin.math.max
import kotlin.math.pow
@ -223,9 +224,11 @@ class MapGenerator(val ruleset: Ruleset) {
* [MapParameters.elevationExponent] favors high elevation
*/
private fun raiseMountainsAndHills(tileMap: TileMap) {
val mountain = ruleset.terrains.values.firstOrNull { it.uniques.contains("Occurs in chains at high elevations") }?.name
val hill = ruleset.terrains.values.firstOrNull { it.uniques.contains("Occurs in groups around high elevations") }?.name
val flat = ruleset.terrains.values.firstOrNull { !it.impassable && it.type == TerrainType.Land && !it.uniques.contains("Rough Terrain") }?.name
val mountain = ruleset.terrains.values.firstOrNull { it.hasUnique(UniqueType.OccursInChains) }?.name
val hill = ruleset.terrains.values.firstOrNull { it.hasUnique(UniqueType.OccursInGroups) }?.name
val flat = ruleset.terrains.values.firstOrNull {
!it.impassable && it.type == TerrainType.Land && !it.hasUnique(UniqueType.RoughTerrain)
}?.name
if (flat == null) {
println("Ruleset seems to contain no flat terrain - can't generate heightmap")
@ -358,12 +361,11 @@ class MapGenerator(val ruleset: Ruleset) {
val tempFrom: Float, val tempTo: Float,
val humidFrom: Float, val humidTo: Float
)
// List is OK here as it's only sequentially scanned
val limitsMap: List<TerrainOccursRange> =
// List is OK here as it's only sequentially scanned
ruleset.terrains.values.flatMap { terrain ->
terrain.uniqueObjects.filter {
it.placeholderText == "Occurs at temperature between [] and [] and humidity between [] and []"
}.map { unique ->
ruleset.terrains.values.flatMap { terrain ->
terrain.getMatchingUniques(UniqueType.TileGenerationConditions)
.map { unique ->
TerrainOccursRange(terrain,
unique.params[0].toFloat(), unique.params[1].toFloat(),
unique.params[2].toFloat(), unique.params[3].toFloat())
@ -432,7 +434,7 @@ class MapGenerator(val ruleset: Ruleset) {
*/
private fun spawnRareFeatures(tileMap: TileMap) {
val rareFeatures = ruleset.terrains.values.filter {
it.type == TerrainType.TerrainFeature && it.uniques.contains("Rare feature")
it.type == TerrainType.TerrainFeature && it.hasUnique(UniqueType.RareFeature)
}
for (tile in tileMap.values.asSequence().filter { it.terrainFeatures.isEmpty() }) {
if (randomness.RNG.nextDouble() <= tileMap.mapParameters.rareFeaturesRichness) {

View File

@ -40,7 +40,8 @@ class Terrain : RulesetStatsObject() {
@Transient
var damagePerTurn = 0
fun isRough(): Boolean = uniques.contains("Rough terrain")
// Shouldn't this just be a lazy property so it's automatically cached?
fun isRough(): Boolean = hasUnique(UniqueType.RoughTerrain)
/** Tests base terrains, features and natural wonders whether they should be treated as Land/Water.
* Currently only used for civilopedia display, as other code can test the tile itself.
@ -141,8 +142,6 @@ class Terrain : RulesetStatsObject() {
}
fun setTransients() {
damagePerTurn = uniqueObjects.sumOf {
if (it.placeholderText == "Units ending their turn on this terrain take [] damage") it.params[0].toInt() else 0
}
damagePerTurn = getMatchingUniques(UniqueType.DamagesContainingUnits).sumOf { it.params[0].toInt() }
}
}

View File

@ -261,16 +261,33 @@ enum class UniqueType(val text:String, vararg targets: UniqueTarget) {
// The "Except [terrainFilter]" could theoretically be implemented with a conditional
NaturalWonderConvertNeighborsExcept("Neighboring tiles except [baseTerrain] will convert to [baseTerrain]", UniqueTarget.Terrain),
DamagesContainingUnits("Units ending their turn on this terrain take [amount] damage", UniqueTarget.Terrain),
TerrainGrantsPromotion("Grants [promotion] ([comment]) to adjacent [mapUnitFilter] units for the rest of the game", UniqueTarget.Terrain),
GrantsCityStrength("[amount] Strength for cities built on this terrain", UniqueTarget.Terrain),
ProductionBonusWhenRemoved("Provides a one-time Production bonus to the closest city when cut down", UniqueTarget.Terrain),
TileProvidesYieldWithoutPopulation("Tile provides yield without assigned population", UniqueTarget.Terrain, UniqueTarget.Improvement),
NullifyYields("Nullifies all other stats this tile provides", UniqueTarget.Terrain),
RestrictedBuildableImprovements("Only [improvementFilter] improvements may be built on this tile", UniqueTarget.Terrain),
BlocksLineOfSightAtSameElevation("Blocks line-of-sight from tiles at same elevation", UniqueTarget.Terrain),
VisibilityElevation("Has an elevation of [amount] for visibility calculations", UniqueTarget.Terrain),
NoNaturalGeneration("Doesn't generate naturally", UniqueTarget.Terrain),
TileGenerationConditions("Occurs at temperature between [amount] and [amount] and humidity between [amount] and [amount]", UniqueTarget.Terrain),
OccursInChains("Occurs in chains at high elevations", UniqueTarget.Terrain),
OccursInGroups("Occurs in groups around high elevations", UniqueTarget.Terrain),
RareFeature("Rare feature", UniqueTarget.Terrain),
ResistsNukes("Resistant to nukes", UniqueTarget.Terrain),
DestroyableByNukes("Can be destroyed by nukes", UniqueTarget.Terrain),
FreshWater("Fresh water", UniqueTarget.Terrain),
RoughTerrain("Rough terrain", UniqueTarget.Terrain),
// Resource uniques
OverrideDepositAmountOnTileFilter("Deposits in [tileFilter] tiles always provide [amount] resources", UniqueTarget.Resource),
///////////////////////////////////////// CONDITIONALS /////////////////////////////////////////