River adjacency functions and gold bonus for tiles adjacent to rivers

This commit is contained in:
Yair Morgenstern
2020-05-17 21:29:12 +03:00
parent 8a43d5c5d6
commit 3032ba9c73

View File

@ -24,9 +24,9 @@ open class TileInfo {
@Transient var isWater = false @Transient var isWater = false
@Transient var isOcean = false @Transient var isOcean = false
var militaryUnit:MapUnit?=null var militaryUnit: MapUnit? = null
var civilianUnit:MapUnit?=null var civilianUnit: MapUnit? = null
var airUnits=ArrayList<MapUnit>() var airUnits = ArrayList<MapUnit>()
var position: Vector2 = Vector2.Zero var position: Vector2 = Vector2.Zero
lateinit var baseTerrain: String lateinit var baseTerrain: String
@ -50,18 +50,18 @@ open class TileInfo {
fun clone(): TileInfo { fun clone(): TileInfo {
val toReturn = TileInfo() val toReturn = TileInfo()
if(militaryUnit!=null) toReturn.militaryUnit=militaryUnit!!.clone() if (militaryUnit != null) toReturn.militaryUnit = militaryUnit!!.clone()
if(civilianUnit!=null) toReturn.civilianUnit=civilianUnit!!.clone() if (civilianUnit != null) toReturn.civilianUnit = civilianUnit!!.clone()
for(airUnit in airUnits) toReturn.airUnits.add(airUnit.clone()) for (airUnit in airUnits) toReturn.airUnits.add(airUnit.clone())
toReturn.position=position.cpy() toReturn.position = position.cpy()
toReturn.baseTerrain=baseTerrain toReturn.baseTerrain = baseTerrain
toReturn.terrainFeature=terrainFeature toReturn.terrainFeature = terrainFeature
toReturn.naturalWonder=naturalWonder toReturn.naturalWonder = naturalWonder
toReturn.resource=resource toReturn.resource = resource
toReturn.improvement=improvement toReturn.improvement = improvement
toReturn.improvementInProgress=improvementInProgress toReturn.improvementInProgress = improvementInProgress
toReturn.roadStatus=roadStatus toReturn.roadStatus = roadStatus
toReturn.turnsToImprovement=turnsToImprovement toReturn.turnsToImprovement = turnsToImprovement
return toReturn return toReturn
} }
@ -96,18 +96,18 @@ open class TileInfo {
fun getCity(): CityInfo? = owningCity fun getCity(): CityInfo? = owningCity
fun getLastTerrain(): Terrain = if (terrainFeature != null) getTerrainFeature()!! else if(naturalWonder != null) getNaturalWonder() else getBaseTerrain() fun getLastTerrain(): Terrain = if (terrainFeature != null) getTerrainFeature()!! else if (naturalWonder != null) getNaturalWonder() else getBaseTerrain()
fun getTileResource(): TileResource = fun getTileResource(): TileResource =
if (resource == null) throw Exception("No resource exists for this tile!") if (resource == null) throw Exception("No resource exists for this tile!")
else ruleset.tileResources[resource!!]!! else ruleset.tileResources[resource!!]!!
fun getNaturalWonder() : Terrain = fun getNaturalWonder(): Terrain =
if (naturalWonder == null) throw Exception("No natural wonder exists for this tile!") if (naturalWonder == null) throw Exception("No natural wonder exists for this tile!")
else ruleset.terrains[naturalWonder!!]!! else ruleset.terrains[naturalWonder!!]!!
fun isCityCenter(): Boolean = getCity()?.location == position fun isCityCenter(): Boolean = getCity()?.location == position
fun isNaturalWonder() : Boolean = naturalWonder != null fun isNaturalWonder(): Boolean = naturalWonder != null
fun getTileImprovement(): TileImprovement? = if (improvement == null) null else ruleset.tileImprovements[improvement!!] fun getTileImprovement(): TileImprovement? = if (improvement == null) null else ruleset.tileImprovements[improvement!!]
@ -130,7 +130,7 @@ open class TileInfo {
fun getOwner(): CivilizationInfo? { fun getOwner(): CivilizationInfo? {
val containingCity = getCity() val containingCity = getCity()
if(containingCity==null) return null if (containingCity == null) return null
return containingCity.civInfo return containingCity.civInfo
} }
@ -147,7 +147,7 @@ open class TileInfo {
fun getTerrainFeature(): Terrain? = fun getTerrainFeature(): Terrain? =
if (terrainFeature == null) null else ruleset.terrains[terrainFeature!!] if (terrainFeature == null) null else ruleset.terrains[terrainFeature!!]
fun getWorkingCity():CityInfo? { fun getWorkingCity(): CityInfo? {
val civInfo = getOwner() val civInfo = getOwner()
if (civInfo == null) return null if (civInfo == null) return null
return civInfo.cities.firstOrNull { it.workedTiles.contains(position) } return civInfo.cities.firstOrNull { it.workedTiles.contains(position) }
@ -157,9 +157,9 @@ open class TileInfo {
return getWorkingCity() != null return getWorkingCity() != null
} }
fun isLocked(): Boolean{ fun isLocked(): Boolean {
val workingCity = getWorkingCity() val workingCity = getWorkingCity()
return workingCity!=null && workingCity.lockedTiles.contains(position) return workingCity != null && workingCity.lockedTiles.contains(position)
} }
fun getTileStats(observingCiv: CivilizationInfo): Stats = getTileStats(getCity(), observingCiv) fun getTileStats(observingCiv: CivilizationInfo): Stats = getTileStats(getCity(), observingCiv)
@ -167,7 +167,7 @@ open class TileInfo {
fun getTileStats(city: CityInfo?, observingCiv: CivilizationInfo): Stats { fun getTileStats(city: CityInfo?, observingCiv: CivilizationInfo): Stats {
var stats = getBaseTerrain().clone() var stats = getBaseTerrain().clone()
if((baseTerrain== Constants.ocean||baseTerrain==Constants.coast) && city!=null if ((baseTerrain == Constants.ocean || baseTerrain == Constants.coast) && city != null
&& city.containsBuildingUnique("+1 food from Ocean and Coast tiles")) && city.containsBuildingUnique("+1 food from Ocean and Coast tiles"))
stats.food += 1 stats.food += 1
@ -206,7 +206,7 @@ open class TileInfo {
val resourceBuilding = tileMap.gameInfo.ruleSet.buildings[resource.building!!]!! val resourceBuilding = tileMap.gameInfo.ruleSet.buildings[resource.building!!]!!
stats.add(resourceBuilding.resourceBonusStats!!) // resource-specific building (eg forge, stable) bonus stats.add(resourceBuilding.resourceBonusStats!!) // resource-specific building (eg forge, stable) bonus
} }
if (resource.resourceType==ResourceType.Strategic if (resource.resourceType == ResourceType.Strategic
&& observingCiv.nation.unique == UniqueAbility.SIBERIAN_RICHES) && observingCiv.nation.unique == UniqueAbility.SIBERIAN_RICHES)
stats.production += 1 stats.production += 1
if (city != null) { if (city != null) {
@ -217,9 +217,9 @@ open class TileInfo {
&& city.containsBuildingUnique("+2 Gold for each source of Marble and Stone")) && city.containsBuildingUnique("+2 Gold for each source of Marble and Stone"))
stats.gold += 2 stats.gold += 2
if (isWater) { if (isWater) {
if(city.containsBuildingUnique("+1 production from all sea resources worked by the city")) if (city.containsBuildingUnique("+1 production from all sea resources worked by the city"))
stats.production += 1 stats.production += 1
if(city.containsBuildingUnique("+1 production and gold from all sea resources worked by the city")){ if (city.containsBuildingUnique("+1 production and gold from all sea resources worked by the city")) {
stats.production += 1 stats.production += 1
stats.gold += 1 stats.gold += 1
} }
@ -231,7 +231,7 @@ open class TileInfo {
if (improvement != null) if (improvement != null)
stats.add(getImprovementStats(improvement, observingCiv, city)) stats.add(getImprovementStats(improvement, observingCiv, city))
if(city!=null && isWater && city.containsBuildingUnique("+1 gold from worked water tiles in city")) if (city != null && isWater && city.containsBuildingUnique("+1 gold from worked water tiles in city"))
stats.gold += 1 stats.gold += 1
if (isCityCenter()) { if (isCityCenter()) {
@ -242,6 +242,8 @@ open class TileInfo {
if (stats.gold != 0f && observingCiv.goldenAges.isGoldenAge()) if (stats.gold != 0f && observingCiv.goldenAges.isGoldenAge())
stats.gold++ stats.gold++
if (isAdjacentToRiver()) stats.gold++
if (stats.production < 0) stats.production = 0f if (stats.production < 0) stats.production = 0f
return stats return stats
@ -249,10 +251,10 @@ open class TileInfo {
fun getImprovementStats(improvement: TileImprovement, observingCiv: CivilizationInfo, city: CityInfo?): Stats { fun getImprovementStats(improvement: TileImprovement, observingCiv: CivilizationInfo, city: CityInfo?): Stats {
val stats = val stats =
if (hasViewableResource(observingCiv) && getTileResource().improvement == improvement.name) if (hasViewableResource(observingCiv) && getTileResource().improvement == improvement.name)
getTileResource().improvementStats!!.clone() // resource-specific improvement getTileResource().improvementStats!!.clone() // resource-specific improvement
else else
improvement.clone() // basic improvement improvement.clone() // basic improvement
if (improvement.improvingTech != null && observingCiv.tech.isResearched(improvement.improvingTech!!)) stats.add(improvement.improvingTechStats!!) // eg Chemistry for mines if (improvement.improvingTech != null && observingCiv.tech.isResearched(improvement.improvingTech!!)) stats.add(improvement.improvingTechStats!!) // eg Chemistry for mines
if (improvement.name == "Trading post" && city != null if (improvement.name == "Trading post" && city != null
@ -284,7 +286,7 @@ open class TileInfo {
improvement.uniqueTo != null && improvement.uniqueTo != civInfo.civName -> false improvement.uniqueTo != null && improvement.uniqueTo != civInfo.civName -> false
improvement.techRequired?.let { civInfo.tech.isResearched(it) } == false -> false improvement.techRequired?.let { civInfo.tech.isResearched(it) } == false -> false
"Cannot be built on bonus resource" in improvement.uniques && resource != null "Cannot be built on bonus resource" in improvement.uniques && resource != null
&& getTileResource().resourceType == ResourceType.Bonus -> false && getTileResource().resourceType == ResourceType.Bonus -> false
improvement.terrainsCanBeBuiltOn.contains(topTerrain.name) -> true improvement.terrainsCanBeBuiltOn.contains(topTerrain.name) -> true
improvement.name == "Road" && roadStatus == RoadStatus.None -> true improvement.name == "Road" && roadStatus == RoadStatus.None -> true
improvement.name == "Railroad" && this.roadStatus != RoadStatus.Railroad -> true improvement.name == "Railroad" && this.roadStatus != RoadStatus.Railroad -> true
@ -297,72 +299,87 @@ open class TileInfo {
} }
} }
fun hasImprovementInProgress() = improvementInProgress!=null fun hasImprovementInProgress() = improvementInProgress != null
@delegate:Transient @delegate:Transient
private val _isCoastalTile: Boolean by lazy { neighbors.any { it.baseTerrain==Constants.coast } } private val _isCoastalTile: Boolean by lazy { neighbors.any { it.baseTerrain == Constants.coast } }
fun isCoastalTile() = _isCoastalTile fun isCoastalTile() = _isCoastalTile
fun hasViewableResource(civInfo: CivilizationInfo): Boolean = fun hasViewableResource(civInfo: CivilizationInfo): Boolean =
resource != null && (getTileResource().revealedBy == null || civInfo.tech.isResearched(getTileResource().revealedBy!!)) resource != null && (getTileResource().revealedBy == null || civInfo.tech.isResearched(getTileResource().revealedBy!!))
fun getViewableTilesList(distance:Int): List<TileInfo> = fun getViewableTilesList(distance: Int): List<TileInfo> =
tileMap.getViewableTiles(position, distance) tileMap.getViewableTiles(position, distance)
fun getTilesInDistance(distance: Int): Sequence<TileInfo> = fun getTilesInDistance(distance: Int): Sequence<TileInfo> =
tileMap.getTilesInDistance(position,distance) tileMap.getTilesInDistance(position, distance)
fun getTilesInDistanceRange(range: IntRange): Sequence<TileInfo> = fun getTilesInDistanceRange(range: IntRange): Sequence<TileInfo> =
tileMap.getTilesInDistanceRange(position, range) tileMap.getTilesInDistanceRange(position, range)
fun getTilesAtDistance(distance:Int): Sequence<TileInfo> = fun getTilesAtDistance(distance: Int): Sequence<TileInfo> =
tileMap.getTilesAtDistance(position, distance) tileMap.getTilesAtDistance(position, distance)
fun getDefensiveBonus(): Float { fun getDefensiveBonus(): Float {
var bonus = getBaseTerrain().defenceBonus var bonus = getBaseTerrain().defenceBonus
if(terrainFeature!=null) bonus += getTerrainFeature()!!.defenceBonus if (terrainFeature != null) bonus += getTerrainFeature()!!.defenceBonus
return bonus return bonus
} }
fun aerialDistanceTo(otherTile:TileInfo): Int { fun aerialDistanceTo(otherTile: TileInfo): Int {
val xDelta = position.x-otherTile.position.x val xDelta = position.x - otherTile.position.x
val yDelta = position.y-otherTile.position.y val yDelta = position.y - otherTile.position.y
return listOf(abs(xDelta),abs(yDelta), abs(xDelta-yDelta)).max()!!.toInt() return listOf(abs(xDelta), abs(yDelta), abs(xDelta - yDelta)).max()!!.toInt()
} }
fun isRoughTerrain() = getBaseTerrain().rough || getTerrainFeature()?.rough == true fun isRoughTerrain() = getBaseTerrain().rough || getTerrainFeature()?.rough == true
override fun toString():String { // for debugging, it helps to see what you're doing override fun toString(): String { // for debugging, it helps to see what you're doing
return toString(null) return toString(null)
} }
fun isConnectedByRiver(otherTile:TileInfo): Boolean {
if(otherTile !in neighbors) throw Exception("Should never call this function on a non-neighbor!")
val xDifference = this.position.x - otherTile.position.x
val yDifference = this.position.y - otherTile.position.y
return when {
xDifference == 1f && yDifference == 1f -> hasBottomRiver // we're directly above it
xDifference == 1f -> hasBottomRightRiver // we're to the top-left of it
yDifference == 1f -> hasBottomLeftRiver // we're to the top-right of it
else -> otherTile.isConnectedByRiver(this) // we're below it, check the other tile
}
}
fun isAdjacentToRiver() = neighbors.any { isConnectedByRiver(it) }
fun toString(viewingCiv: CivilizationInfo?): String { fun toString(viewingCiv: CivilizationInfo?): String {
val lineList = ArrayList<String>() // more readable than StringBuilder, with same performance for our use-case val lineList = ArrayList<String>() // more readable than StringBuilder, with same performance for our use-case
val isViewableToPlayer = viewingCiv==null || UncivGame.Current.viewEntireMapForDebug val isViewableToPlayer = viewingCiv == null || UncivGame.Current.viewEntireMapForDebug
|| viewingCiv.viewableTiles.contains(this) || viewingCiv.viewableTiles.contains(this)
if (isCityCenter()) { if (isCityCenter()) {
val city = getCity()!! val city = getCity()!!
var cityString = city.name.tr() var cityString = city.name.tr()
if(isViewableToPlayer) cityString += " ("+city.health+")" if (isViewableToPlayer) cityString += " (" + city.health + ")"
lineList += cityString lineList += cityString
if(UncivGame.Current.viewEntireMapForDebug || city.civInfo == viewingCiv) if (UncivGame.Current.viewEntireMapForDebug || city.civInfo == viewingCiv)
lineList += city.cityConstructions.getProductionForTileInfo() lineList += city.cityConstructions.getProductionForTileInfo()
} }
lineList += baseTerrain.tr() lineList += baseTerrain.tr()
if (terrainFeature != null) lineList += terrainFeature!!.tr() if (terrainFeature != null) lineList += terrainFeature!!.tr()
if (resource!=null && (viewingCiv==null || hasViewableResource(viewingCiv))) lineList += resource!!.tr() if (resource != null && (viewingCiv == null || hasViewableResource(viewingCiv))) lineList += resource!!.tr()
if (naturalWonder != null) lineList += naturalWonder!!.tr() if (naturalWonder != null) lineList += naturalWonder!!.tr()
if (roadStatus !== RoadStatus.None && !isCityCenter()) lineList += roadStatus.toString().tr() if (roadStatus !== RoadStatus.None && !isCityCenter()) lineList += roadStatus.toString().tr()
if (improvement != null) lineList += improvement!!.tr() if (improvement != null) lineList += improvement!!.tr()
if (improvementInProgress != null && isViewableToPlayer) if (improvementInProgress != null && isViewableToPlayer)
lineList += "{$improvementInProgress}\r\n{in} $turnsToImprovement {turns}".tr() // todo change to [] translation notation lineList += "{$improvementInProgress}\r\n{in} $turnsToImprovement {turns}".tr() // todo change to [] translation notation
if (civilianUnit != null && isViewableToPlayer) if (civilianUnit != null && isViewableToPlayer)
lineList += civilianUnit!!.name.tr()+" - "+civilianUnit!!.civInfo.civName.tr() lineList += civilianUnit!!.name.tr() + " - " + civilianUnit!!.civInfo.civName.tr()
if(militaryUnit!=null && isViewableToPlayer){ if (militaryUnit != null && isViewableToPlayer) {
var milUnitString = militaryUnit!!.name.tr() var milUnitString = militaryUnit!!.name.tr()
if(militaryUnit!!.health<100) milUnitString += "(" + militaryUnit!!.health + ")" if (militaryUnit!!.health < 100) milUnitString += "(" + militaryUnit!!.health + ")"
milUnitString += " - "+militaryUnit!!.civInfo.civName.tr() milUnitString += " - " + militaryUnit!!.civInfo.civName.tr()
lineList += milUnitString lineList += milUnitString
} }
var defenceBonus = getDefensiveBonus() var defenceBonus = getDefensiveBonus()
@ -374,12 +391,12 @@ open class TileInfo {
else -> 0.0f else -> 0.0f
} }
} }
if(defenceBonus != 0.0f){ if (defenceBonus != 0.0f) {
var defencePercentString = (defenceBonus*100).toInt().toString()+"%" var defencePercentString = (defenceBonus * 100).toInt().toString() + "%"
if(!defencePercentString.startsWith("-")) defencePercentString = "+$defencePercentString" if (!defencePercentString.startsWith("-")) defencePercentString = "+$defencePercentString"
lineList += "[$defencePercentString] to unit defence".tr() lineList += "[$defencePercentString] to unit defence".tr()
} }
if(getBaseTerrain().impassable) lineList += Constants.impassable.tr() if (getBaseTerrain().impassable) lineList += Constants.impassable.tr()
return lineList.joinToString("\n") return lineList.joinToString("\n")
} }
@ -387,23 +404,23 @@ open class TileInfo {
//endregion //endregion
//region state-changing functions //region state-changing functions
fun setTransients(){ fun setTransients() {
setTerrainTransients() setTerrainTransients()
setUnitTransients(true) setUnitTransients(true)
} }
fun setTerrainTransients(){ fun setTerrainTransients() {
baseTerrainObject = ruleset.terrains[baseTerrain]!! // This is a HACK. baseTerrainObject = ruleset.terrains[baseTerrain]!! // This is a HACK.
isWater = getBaseTerrain().type==TerrainType.Water isWater = getBaseTerrain().type == TerrainType.Water
isLand = getBaseTerrain().type==TerrainType.Land isLand = getBaseTerrain().type == TerrainType.Land
isOcean = baseTerrain == Constants.ocean isOcean = baseTerrain == Constants.ocean
} }
fun setUnitTransients(unitCivTransients: Boolean) { fun setUnitTransients(unitCivTransients: Boolean) {
for (unit in getUnits()) { for (unit in getUnits()) {
unit.currentTile = this unit.currentTile = this
if(unitCivTransients) if (unitCivTransients)
unit.assignOwner(tileMap.gameInfo.getCivilization(unit.owner),false) unit.assignOwner(tileMap.gameInfo.getCivilization(unit.owner), false)
unit.setTransients(ruleset) unit.setTransients(ruleset)
} }
} }
@ -412,15 +429,16 @@ open class TileInfo {
improvementInProgress = improvement.name improvementInProgress = improvement.name
turnsToImprovement = improvement.getTurnsToBuild(civInfo) turnsToImprovement = improvement.getTurnsToBuild(civInfo)
} }
fun stopWorkingOnImprovement() { fun stopWorkingOnImprovement() {
improvementInProgress = null improvementInProgress = null
turnsToImprovement = 0 turnsToImprovement = 0
} }
fun hasEnemySubmarine(viewingCiv:CivilizationInfo): Boolean { fun hasEnemySubmarine(viewingCiv: CivilizationInfo): Boolean {
val unitsInTile = getUnits() val unitsInTile = getUnits()
if (unitsInTile.none()) return false if (unitsInTile.none()) return false
if (unitsInTile.first().civInfo!=viewingCiv && if (unitsInTile.first().civInfo != viewingCiv &&
unitsInTile.firstOrNull { it.isInvisible() } != null) { unitsInTile.firstOrNull { it.isInvisible() } != null) {
return true return true
} }