Kotlin 1.5 new warnings - the rest (#5151)

This commit is contained in:
SomeTroglodyte 2021-09-09 05:21:44 +02:00 committed by GitHub
parent 9ff8435a21
commit 8b210fb798
No known key found for this signature in database
GPG Key ID: 4AEE18F83AFDEB23
16 changed files with 143 additions and 149 deletions

View File

@ -208,7 +208,7 @@ object HexMath {
val top = height / 2 - (x + y) / 2 val top = height / 2 - (x + y) / 2
// kotlin's Int division rounds in different directions depending on sign! Thus 1 extra `-1` // kotlin's Int division rounds in different directions depending on sign! Thus 1 extra `-1`
val bottom = (x + y - 1) / 2 + (height - 1) / 2 val bottom = (x + y - 1) / 2 + (height - 1) / 2
return min(min(left, right), min(top, bottom)) return minOf(left, right, top, bottom)
} else { } else {
val radius = mapParameters.mapSize.radius val radius = mapParameters.mapSize.radius
if (mapParameters.worldWrap) { if (mapParameters.worldWrap) {

View File

@ -170,7 +170,7 @@ object BattleDamage {
} else if (attacker is CityCombatant) { } else if (attacker is CityCombatant) {
if (attacker.city.getCenterTile().militaryUnit != null) { if (attacker.city.getCenterTile().militaryUnit != null) {
val garrisonBonus = attacker.city.getMatchingUniques("+[]% attacking strength for cities with garrisoned units") val garrisonBonus = attacker.city.getMatchingUniques("+[]% attacking strength for cities with garrisoned units")
.sumBy { it.params[0].toInt() } .sumOf { it.params[0].toInt() }
if (garrisonBonus != 0) if (garrisonBonus != 0)
modifiers["Garrisoned unit"] = garrisonBonus modifiers["Garrisoned unit"] = garrisonBonus
} }

View File

@ -57,7 +57,7 @@ class CityCombatant(val city: CityInfo) : ICombatant {
if (cityTile.militaryUnit != null) if (cityTile.militaryUnit != null)
strength += cityTile.militaryUnit!!.baseUnit().strength * (cityTile.militaryUnit!!.health / 100f) * 0.2f strength += cityTile.militaryUnit!!.baseUnit().strength * (cityTile.militaryUnit!!.health / 100f) * 0.2f
var buildingsStrength = city.cityConstructions.getBuiltBuildings().sumBy { it.cityStrength }.toFloat() var buildingsStrength = city.cityConstructions.getBuiltBuildings().sumOf { it.cityStrength }.toFloat()
if (getCivInfo().hasUnique("Defensive buildings in all cities are 25% more effective")) if (getCivInfo().hasUnique("Defensive buildings in all cities are 25% more effective"))
buildingsStrength *= 1.25f buildingsStrength *= 1.25f
strength += buildingsStrength strength += buildingsStrength

View File

@ -3,7 +3,6 @@ package com.unciv.logic.city
import com.badlogic.gdx.math.Vector2 import com.badlogic.gdx.math.Vector2
import com.unciv.logic.battle.CityCombatant import com.unciv.logic.battle.CityCombatant
import com.unciv.logic.civilization.CivilizationInfo import com.unciv.logic.civilization.CivilizationInfo
import com.unciv.logic.civilization.GreatPersonManager
import com.unciv.logic.civilization.ReligionState import com.unciv.logic.civilization.ReligionState
import com.unciv.logic.civilization.diplomacy.DiplomacyFlags import com.unciv.logic.civilization.diplomacy.DiplomacyFlags
import com.unciv.logic.map.RoadStatus import com.unciv.logic.map.RoadStatus
@ -15,10 +14,7 @@ import com.unciv.models.ruleset.tile.ResourceSupplyList
import com.unciv.models.ruleset.tile.ResourceType import com.unciv.models.ruleset.tile.ResourceType
import com.unciv.models.ruleset.unit.BaseUnit import com.unciv.models.ruleset.unit.BaseUnit
import com.unciv.models.stats.Stat import com.unciv.models.stats.Stat
import com.unciv.models.translations.equalsPlaceholderText
import com.unciv.models.translations.getPlaceholderParameters
import java.util.* import java.util.*
import kotlin.collections.ArrayList
import kotlin.collections.HashMap import kotlin.collections.HashMap
import kotlin.collections.HashSet import kotlin.collections.HashSet
import kotlin.math.ceil import kotlin.math.ceil
@ -27,6 +23,7 @@ import kotlin.math.pow
import kotlin.math.roundToInt import kotlin.math.roundToInt
class CityInfo { class CityInfo {
@Suppress("JoinDeclarationAndAssignment")
@Transient @Transient
lateinit var civInfo: CivilizationInfo lateinit var civInfo: CivilizationInfo
@ -87,7 +84,7 @@ class CityInfo {
this.civInfo = civInfo this.civInfo = civInfo
foundingCiv = civInfo.civName foundingCiv = civInfo.civName
turnAcquired = civInfo.gameInfo.turns turnAcquired = civInfo.gameInfo.turns
this.location = cityLocation location = cityLocation
setTransients() setTransients()
setNewCityName(civInfo) setNewCityName(civInfo)
@ -248,10 +245,9 @@ class CityInfo {
val indicatorBuildings = getRuleset().buildings.values val indicatorBuildings = getRuleset().buildings.values
.asSequence() .asSequence()
.filter { it.uniques.contains("Indicates the capital city") } .filter { it.uniques.contains("Indicates the capital city") }
val civSpecificBuilding = indicatorBuildings.firstOrNull { it.uniqueTo == civInfo.civName } val civSpecificBuilding = indicatorBuildings.firstOrNull { it.uniqueTo == civInfo.civName }
if (civSpecificBuilding != null) return civSpecificBuilding.name return civSpecificBuilding?.name ?: indicatorBuildings.first().name
else return indicatorBuildings.first().name
} }
fun isConnectedToCapital(connectionTypePredicate: (Set<String>) -> Boolean = { true }): Boolean { fun isConnectedToCapital(connectionTypePredicate: (Set<String>) -> Boolean = { true }): Boolean {
@ -382,7 +378,7 @@ class CityInfo {
buildingsCounter.add(building.greatPersonPoints) buildingsCounter.add(building.greatPersonPoints)
sourceToGPP["Buildings"] = buildingsCounter sourceToGPP["Buildings"] = buildingsCounter
for ((source, gppCounter) in sourceToGPP) { for ((_, gppCounter) in sourceToGPP) {
for (unique in civInfo.getMatchingUniques("[] is earned []% faster")) { for (unique in civInfo.getMatchingUniques("[] is earned []% faster")) {
val unitName = unique.params[0] val unitName = unique.params[0]
if (!gppCounter.containsKey(unitName)) continue if (!gppCounter.containsKey(unitName)) continue
@ -437,7 +433,7 @@ class CityInfo {
} }
internal fun getMaxHealth() = internal fun getMaxHealth() =
200 + cityConstructions.getBuiltBuildings().sumBy { it.cityHealth } 200 + cityConstructions.getBuiltBuildings().sumOf { it.cityHealth }
override fun toString() = name // for debug override fun toString() = name // for debug
//endregion //endregion
@ -498,7 +494,7 @@ class CityInfo {
if (isBeingRazed) { if (isBeingRazed) {
val removedPopulation = val removedPopulation =
1 + civInfo.getMatchingUniques("Cities are razed [] times as fast") 1 + civInfo.getMatchingUniques("Cities are razed [] times as fast")
.sumBy { it.params[0].toInt() - 1 } .sumOf { it.params[0].toInt() - 1 }
population.addPopulation(-1 * removedPopulation) population.addPopulation(-1 * removedPopulation)
if (population.population <= 0) { if (population.population <= 0) {
civInfo.addNotification( civInfo.addNotification(

View File

@ -20,7 +20,7 @@ import kotlin.random.Random
/** Helper class for containing 200 lines of "how to move cities between civs" */ /** Helper class for containing 200 lines of "how to move cities between civs" */
class CityInfoConquestFunctions(val city: CityInfo){ class CityInfoConquestFunctions(val city: CityInfo){
private val tileBasedRandom = Random(city.getCenterTile().position.toString().hashCode()) private val tileBasedRandom = Random(city.getCenterTile().position.toString().hashCode())
private fun getGoldForCapturingCity(conqueringCiv: CivilizationInfo): Int { private fun getGoldForCapturingCity(conqueringCiv: CivilizationInfo): Int {
val baseGold = 20 + 10 * city.population.population + tileBasedRandom.nextInt(40) val baseGold = 20 + 10 * city.population.population + tileBasedRandom.nextInt(40)
val turnModifier = max(0, min(50, city.civInfo.gameInfo.turns - city.turnAcquired)) / 50f val turnModifier = max(0, min(50, city.civInfo.gameInfo.turns - city.turnAcquired)) / 50f
@ -30,7 +30,7 @@ class CityInfoConquestFunctions(val city: CityInfo){
val goldPlundered = baseGold * turnModifier * cityModifier * conqueringCivModifier val goldPlundered = baseGold * turnModifier * cityModifier * conqueringCivModifier
return goldPlundered.toInt() return goldPlundered.toInt()
} }
private fun destroyBuildingsOnCapture() { private fun destroyBuildingsOnCapture() {
city.apply { city.apply {
for (building in cityConstructions.getBuiltBuildings()) { for (building in cityConstructions.getBuiltBuildings()) {
@ -47,7 +47,7 @@ class CityInfoConquestFunctions(val city: CityInfo){
} }
} }
} }
/** Function for stuff that should happen on any capture, be it puppet, annex or liberate. /** Function for stuff that should happen on any capture, be it puppet, annex or liberate.
* Stuff that should happen any time a city is moved between civs, so also when trading, * Stuff that should happen any time a city is moved between civs, so also when trading,
* should go in `this.moveToCiv()`, which this function also calls. * should go in `this.moveToCiv()`, which this function also calls.
@ -59,11 +59,11 @@ class CityInfoConquestFunctions(val city: CityInfo){
conqueringCiv.addNotification("Received [$goldPlundered] Gold for capturing [$name]", getCenterTile().position, NotificationIcon.Gold) conqueringCiv.addNotification("Received [$goldPlundered] Gold for capturing [$name]", getCenterTile().position, NotificationIcon.Gold)
val reconqueredCityWhileStillInResistance = previousOwner == conqueringCiv.civName && resistanceCounter != 0 val reconqueredCityWhileStillInResistance = previousOwner == conqueringCiv.civName && resistanceCounter != 0
this@CityInfoConquestFunctions.moveToCiv(receivingCiv) this@CityInfoConquestFunctions.moveToCiv(receivingCiv)
destroyBuildingsOnCapture() destroyBuildingsOnCapture()
Battle.destroyIfDefeated(conqueredCiv, conqueringCiv) Battle.destroyIfDefeated(conqueredCiv, conqueringCiv)
health = getMaxHealth() / 2 // I think that cities recover to half health when conquered? health = getMaxHealth() / 2 // I think that cities recover to half health when conquered?
@ -80,9 +80,9 @@ class CityInfoConquestFunctions(val city: CityInfo){
/** This happens when we either puppet OR annex, basically whenever we conquer a city and don't liberate it */ /** This happens when we either puppet OR annex, basically whenever we conquer a city and don't liberate it */
fun puppetCity(conqueringCiv: CivilizationInfo) { fun puppetCity(conqueringCiv: CivilizationInfo) {
// Gain gold for plundering city // Gain gold for plundering city
val goldPlundered = getGoldForCapturingCity(conqueringCiv) val goldPlundered = getGoldForCapturingCity(conqueringCiv) // todo: use this val
city.apply { city.apply {
val oldCiv = civInfo val oldCiv = civInfo
// must be before moving the city to the conquering civ, // must be before moving the city to the conquering civ,
@ -90,7 +90,7 @@ class CityInfoConquestFunctions(val city: CityInfo){
diplomaticRepercussionsForConqueringCity(oldCiv, conqueringCiv) diplomaticRepercussionsForConqueringCity(oldCiv, conqueringCiv)
conquerCity(conqueringCiv, oldCiv, conqueringCiv) conquerCity(conqueringCiv, oldCiv, conqueringCiv)
isPuppet = true isPuppet = true
cityStats.update() cityStats.update()
// The city could be producing something that puppets shouldn't, like units // The city could be producing something that puppets shouldn't, like units
@ -111,7 +111,7 @@ class CityInfoConquestFunctions(val city: CityInfo){
private fun diplomaticRepercussionsForConqueringCity(oldCiv: CivilizationInfo, conqueringCiv: CivilizationInfo) { private fun diplomaticRepercussionsForConqueringCity(oldCiv: CivilizationInfo, conqueringCiv: CivilizationInfo) {
val currentPopulation = city.population.population val currentPopulation = city.population.population
val percentageOfCivPopulationInThatCity = currentPopulation * 100f / val percentageOfCivPopulationInThatCity = currentPopulation * 100f /
oldCiv.cities.sumBy { it.population.population } oldCiv.cities.sumOf { it.population.population }
val aggroGenerated = 10f + percentageOfCivPopulationInThatCity.roundToInt() val aggroGenerated = 10f + percentageOfCivPopulationInThatCity.roundToInt()
// How can you conquer a city but not know the civ you conquered it from?! // How can you conquer a city but not know the civ you conquered it from?!
@ -147,9 +147,9 @@ class CityInfoConquestFunctions(val city: CityInfo){
diploManager.makePeace() diploManager.makePeace()
val oldCiv = civInfo val oldCiv = civInfo
diplomaticRepercussionsForLiberatingCity(conqueringCiv, oldCiv) diplomaticRepercussionsForLiberatingCity(conqueringCiv, oldCiv)
conquerCity(conqueringCiv, oldCiv, foundingCiv) conquerCity(conqueringCiv, oldCiv, foundingCiv)
if (foundingCiv.cities.size == 1) cityConstructions.addBuilding(capitalCityIndicator()) // Resurrection! if (foundingCiv.cities.size == 1) cityConstructions.addBuilding(capitalCityIndicator()) // Resurrection!
@ -169,7 +169,7 @@ class CityInfoConquestFunctions(val city: CityInfo){
private fun diplomaticRepercussionsForLiberatingCity(conqueringCiv: CivilizationInfo, conqueredCiv: CivilizationInfo) { private fun diplomaticRepercussionsForLiberatingCity(conqueringCiv: CivilizationInfo, conqueredCiv: CivilizationInfo) {
val foundingCiv = conqueredCiv.gameInfo.civilizations.first { it.civName == city.foundingCiv } val foundingCiv = conqueredCiv.gameInfo.civilizations.first { it.civName == city.foundingCiv }
val percentageOfCivPopulationInThatCity = city.population.population * val percentageOfCivPopulationInThatCity = city.population.population *
100f / (foundingCiv.cities.sumBy { it.population.population } + city.population.population) 100f / (foundingCiv.cities.sumOf { it.population.population } + city.population.population)
val respectForLiberatingOurCity = 10f + percentageOfCivPopulationInThatCity.roundToInt() val respectForLiberatingOurCity = 10f + percentageOfCivPopulationInThatCity.roundToInt()
// In order to get "plus points" in Diplomacy, you have to establish diplomatic relations if you haven't yet // In order to get "plus points" in Diplomacy, you have to establish diplomatic relations if you haven't yet
@ -190,10 +190,10 @@ class CityInfoConquestFunctions(val city: CityInfo){
} }
} }
val otherCivsRespecForLiberating = (respectForLiberatingOurCity / 10).roundToInt().toFloat() val otherCivsRespectForLiberating = (respectForLiberatingOurCity / 10).roundToInt().toFloat()
for (thirdPartyCiv in conqueringCiv.getKnownCivs().filter { it.isMajorCiv() && it != conqueredCiv }) { for (thirdPartyCiv in conqueringCiv.getKnownCivs().filter { it.isMajorCiv() && it != conqueredCiv }) {
thirdPartyCiv.getDiplomacyManager(conqueringCiv) thirdPartyCiv.getDiplomacyManager(conqueringCiv)
.addModifier(DiplomaticModifiers.LiberatedCity, otherCivsRespecForLiberating) // Cool, keep at at! =D .addModifier(DiplomaticModifiers.LiberatedCity, otherCivsRespectForLiberating) // Cool, keep at at! =D
} }
} }
@ -244,7 +244,7 @@ class CityInfoConquestFunctions(val city: CityInfo){
cityConstructions.addBuilding(civEquivalentBuilding.name) cityConstructions.addBuilding(civEquivalentBuilding.name)
} }
} }
if (civInfo.gameInfo.hasReligionEnabled()) religion.removeUnknownPantheons() if (civInfo.gameInfo.hasReligionEnabled()) religion.removeUnknownPantheons()
tryUpdateRoadStatus() tryUpdateRoadStatus()
@ -252,5 +252,4 @@ class CityInfoConquestFunctions(val city: CityInfo){
} }
} }
} }

View File

@ -223,24 +223,24 @@ class CityStats(val cityInfo: CityInfo) {
val amountOfEffects = (cityInfo.population.population / unique.params[1].toInt()).toFloat() val amountOfEffects = (cityInfo.population.population / unique.params[1].toInt()).toFloat()
stats.add(unique.stats.times(amountOfEffects)) stats.add(unique.stats.times(amountOfEffects))
} }
// "[stats] in cities with [amount] or more population // "[stats] in cities with [amount] or more population
if (unique.placeholderText == "[] in cities with [] or more population" && cityInfo.population.population >= unique.params[1].toInt()) if (unique.placeholderText == "[] in cities with [] or more population" && cityInfo.population.population >= unique.params[1].toInt())
stats.add(unique.stats) stats.add(unique.stats)
// "[stats] in cities on [tileFilter] tiles" // "[stats] in cities on [tileFilter] tiles"
if (unique.placeholderText == "[] in cities on [] tiles" && cityInfo.getCenterTile().matchesTerrainFilter(unique.params[1])) if (unique.placeholderText == "[] in cities on [] tiles" && cityInfo.getCenterTile().matchesTerrainFilter(unique.params[1]))
stats.add(unique.stats) stats.add(unique.stats)
// "[stats] if this city has at least [amount] specialists" // "[stats] if this city has at least [amount] specialists"
if (unique.placeholderText == "[] if this city has at least [] specialists" && cityInfo.population.getNumberOfSpecialists() >= unique.params[1].toInt()) if (unique.placeholderText == "[] if this city has at least [] specialists" && cityInfo.population.getNumberOfSpecialists() >= unique.params[1].toInt())
stats.add(unique.stats) stats.add(unique.stats)
// Deprecated since a very long time ago, moved here from another code section // Deprecated since a very long time ago, moved here from another code section
if (unique.placeholderText == "+2 Culture per turn from cities before discovering Steam Power" && !cityInfo.civInfo.tech.isResearched("Steam Power")) if (unique.placeholderText == "+2 Culture per turn from cities before discovering Steam Power" && !cityInfo.civInfo.tech.isResearched("Steam Power"))
stats.culture += 2 stats.culture += 2
// //
if (unique.placeholderText == "[] per turn from cities before []" && !cityInfo.civInfo.hasTechOrPolicy(unique.params[1])) if (unique.placeholderText == "[] per turn from cities before []" && !cityInfo.civInfo.hasTechOrPolicy(unique.params[1]))
stats.add(unique.stats) stats.add(unique.stats)
} }
@ -378,7 +378,7 @@ class CityStats(val cityInfo: CityInfo) {
for (unique in civInfo.getMatchingUniques("Specialists only produce []% of normal unhappiness")) for (unique in civInfo.getMatchingUniques("Specialists only produce []% of normal unhappiness"))
unhappinessFromSpecialists *= (1f - unique.params[0].toFloat() / 100f) unhappinessFromSpecialists *= (1f - unique.params[0].toFloat() / 100f)
// //
for (unique in cityInfo.getMatchingUniques("[]% unhappiness from specialists []")) { for (unique in cityInfo.getMatchingUniques("[]% unhappiness from specialists []")) {
if (cityInfo.matchesFilter(unique.params[1])) if (cityInfo.matchesFilter(unique.params[1]))
unhappinessFromSpecialists *= unique.params[0].toPercent() unhappinessFromSpecialists *= unique.params[0].toPercent()
@ -394,12 +394,12 @@ class CityStats(val cityInfo: CityInfo) {
// Deprecated since 3.16.11 // Deprecated since 3.16.11
for (unique in civInfo.getMatchingUniques("Unhappiness from population decreased by []%")) for (unique in civInfo.getMatchingUniques("Unhappiness from population decreased by []%"))
unhappinessFromCitizens *= (1 - unique.params[0].toFloat() / 100) unhappinessFromCitizens *= (1 - unique.params[0].toFloat() / 100)
for (unique in civInfo.getMatchingUniques("Unhappiness from population decreased by []% []")) for (unique in civInfo.getMatchingUniques("Unhappiness from population decreased by []% []"))
if (cityInfo.matchesFilter(unique.params[1])) if (cityInfo.matchesFilter(unique.params[1]))
unhappinessFromCitizens *= (1 - unique.params[0].toFloat() / 100) unhappinessFromCitizens *= (1 - unique.params[0].toFloat() / 100)
// //
for (unique in cityInfo.getMatchingUniques("[]% unhappiness from population []")) for (unique in cityInfo.getMatchingUniques("[]% unhappiness from population []"))
if (cityInfo.matchesFilter(unique.params[1])) if (cityInfo.matchesFilter(unique.params[1]))
unhappinessFromCitizens *= unique.params[0].toPercent() unhappinessFromCitizens *= unique.params[0].toPercent()
@ -520,7 +520,7 @@ class CityStats(val cityInfo: CityInfo) {
// AFTER we've gotten all the gold stats figured out, only THEN do we plonk that gold into Science // AFTER we've gotten all the gold stats figured out, only THEN do we plonk that gold into Science
if (cityInfo.getRuleset().modOptions.uniques.contains(ModOptionsConstants.convertGoldToScience)) { if (cityInfo.getRuleset().modOptions.uniques.contains(ModOptionsConstants.convertGoldToScience)) {
val amountConverted = (newFinalStatList.values.sumByDouble { it.gold.toDouble() } val amountConverted = (newFinalStatList.values.sumOf { it.gold.toDouble() }
* cityInfo.civInfo.tech.goldPercentConvertedToScience).toInt().toFloat() * cityInfo.civInfo.tech.goldPercentConvertedToScience).toInt().toFloat()
if (amountConverted > 0) // Don't want you converting negative gold to negative science yaknow if (amountConverted > 0) // Don't want you converting negative gold to negative science yaknow
newFinalStatList["Gold -> Science"] = Stats(science = amountConverted, gold = -amountConverted) newFinalStatList["Gold -> Science"] = Stats(science = amountConverted, gold = -amountConverted)
@ -582,7 +582,7 @@ class CityStats(val cityInfo: CityInfo) {
for (unique in cityInfo.civInfo.getMatchingUniques("-[]% food consumption by specialists")) for (unique in cityInfo.civInfo.getMatchingUniques("-[]% food consumption by specialists"))
foodEatenBySpecialists *= 1f - unique.params[0].toFloat() / 100f foodEatenBySpecialists *= 1f - unique.params[0].toFloat() / 100f
// //
for (unique in cityInfo.getMatchingUniques("[]% food consumption by specialists []")) for (unique in cityInfo.getMatchingUniques("[]% food consumption by specialists []"))
if (cityInfo.matchesFilter(unique.params[1])) if (cityInfo.matchesFilter(unique.params[1]))
foodEatenBySpecialists *= unique.params[0].toPercent() foodEatenBySpecialists *= unique.params[0].toPercent()

View File

@ -10,7 +10,6 @@ import com.unciv.models.stats.Stat
import com.unciv.models.translations.getPlaceholderParameters import com.unciv.models.translations.getPlaceholderParameters
import com.unciv.models.translations.getPlaceholderText import com.unciv.models.translations.getPlaceholderText
import com.unciv.ui.victoryscreen.RankingType import com.unciv.ui.victoryscreen.RankingType
import java.util.*
import kotlin.collections.HashMap import kotlin.collections.HashMap
import kotlin.collections.LinkedHashMap import kotlin.collections.LinkedHashMap
import kotlin.math.max import kotlin.math.max
@ -281,14 +280,14 @@ class CityStateFunctions(val civInfo: CivilizationInfo) {
val bullyRange = max(5, civInfo.gameInfo.tileMap.tileMatrix.size / 10) // Longer range for larger maps val bullyRange = max(5, civInfo.gameInfo.tileMap.tileMatrix.size / 10) // Longer range for larger maps
val inRangeTiles = civInfo.getCapital().getCenterTile().getTilesInDistanceRange(1..bullyRange) val inRangeTiles = civInfo.getCapital().getCenterTile().getTilesInDistanceRange(1..bullyRange)
val forceNearCity = inRangeTiles val forceNearCity = inRangeTiles
.sumBy { if (it.militaryUnit?.civInfo == demandingCiv) .sumOf { if (it.militaryUnit?.civInfo == demandingCiv)
it.militaryUnit!!.getForceEvaluation() it.militaryUnit!!.getForceEvaluation()
else 0 else 0
} }
val csForce = civInfo.getCapital().getForceEvaluation() + inRangeTiles val csForce = civInfo.getCapital().getForceEvaluation() + inRangeTiles
.sumBy { if (it.militaryUnit?.civInfo == civInfo) .sumOf { if (it.militaryUnit?.civInfo == civInfo)
it.militaryUnit!!.getForceEvaluation() it.militaryUnit!!.getForceEvaluation()
else 0 else 0
} }
val forceRatio = forceNearCity.toFloat() / csForce.toFloat() val forceRatio = forceNearCity.toFloat() / csForce.toFloat()
@ -337,9 +336,9 @@ class CityStateFunctions(val civInfo: CivilizationInfo) {
if (!civInfo.isCityState()) throw Exception("You can only demand workers from City-States!") if (!civInfo.isCityState()) throw Exception("You can only demand workers from City-States!")
val buildableWorkerLikeUnits = civInfo.gameInfo.ruleSet.units.filter { val buildableWorkerLikeUnits = civInfo.gameInfo.ruleSet.units.filter {
it.value.uniqueObjects.any { it.placeholderText == Constants.canBuildImprovements } it.value.uniqueObjects.any { unique -> unique.placeholderText == Constants.canBuildImprovements }
&& it.value.isBuildable(civInfo)
&& it.value.isCivilian() && it.value.isCivilian()
&& it.value.isBuildable(civInfo)
} }
if (buildableWorkerLikeUnits.isEmpty()) return // Bad luck? if (buildableWorkerLikeUnits.isEmpty()) return // Bad luck?
demandingCiv.placeUnitNearTile(civInfo.getCapital().location, buildableWorkerLikeUnits.keys.random()) demandingCiv.placeUnitNearTile(civInfo.getCapital().location, buildableWorkerLikeUnits.keys.random())
@ -356,7 +355,7 @@ class CityStateFunctions(val civInfo: CivilizationInfo) {
val allyBonuses = eraInfo.allyBonus[civInfo.cityStateType.name] val allyBonuses = eraInfo.allyBonus[civInfo.cityStateType.name]
if (allyBonuses != null) { if (allyBonuses != null) {
// Defined city states in json // Defined city states in json
val bonuses = allyBonuses + eraInfo!!.friendBonus[civInfo.cityStateType.name]!! val bonuses = allyBonuses + eraInfo.friendBonus[civInfo.cityStateType.name]!!
for (bonus in bonuses) { for (bonus in bonuses) {
if (statType == Stat.Happiness && bonus.getPlaceholderText() == "Provides [] Happiness") if (statType == Stat.Happiness && bonus.getPlaceholderText() == "Provides [] Happiness")
return true return true

View File

@ -74,7 +74,7 @@ class CivInfoStats(val civInfo: CivilizationInfo) {
for (city in civInfo.cities) { for (city in civInfo.cities) {
for (tile in city.getTiles()) { for (tile in city.getTiles()) {
if (tile.isCityCenter()) continue if (tile.isCityCenter()) continue
if (tile.roadStatus == RoadStatus.None) continue // Cheap checks before pricy checks if (tile.roadStatus == RoadStatus.None) continue // Cheap checks before pricey checks
if (ignoredTileTypes.any { tile.matchesFilter(it, civInfo) }) continue if (ignoredTileTypes.any { tile.matchesFilter(it, civInfo) }) continue
transportationUpkeep += tile.roadStatus.upkeep transportationUpkeep += tile.roadStatus.upkeep
@ -193,7 +193,7 @@ class CivInfoStats(val civInfo: CivilizationInfo) {
)// Leave at least 1 )// Leave at least 1
statMap["Treasury deficit"] = Stats(science = scienceDeficit) statMap["Treasury deficit"] = Stats(science = scienceDeficit)
} }
val goldDifferenceFromTrade = civInfo.diplomacy.values.sumBy { it.goldPerTurn() } val goldDifferenceFromTrade = civInfo.diplomacy.values.sumOf { it.goldPerTurn() }
if (goldDifferenceFromTrade != 0) if (goldDifferenceFromTrade != 0)
statMap["Trade"] = Stats(gold = goldDifferenceFromTrade.toFloat()) statMap["Trade"] = Stats(gold = goldDifferenceFromTrade.toFloat())
@ -218,7 +218,7 @@ class CivInfoStats(val civInfo: CivilizationInfo) {
val happinessBonusForCityStateProvidedLuxuries = val happinessBonusForCityStateProvidedLuxuries =
civInfo.getMatchingUniques("Happiness from Luxury Resources gifted by City-States increased by []%") civInfo.getMatchingUniques("Happiness from Luxury Resources gifted by City-States increased by []%")
.sumBy { it.params[0].toInt() } / 100f .sumOf { it.params[0].toInt() } / 100f
val luxuriesProvidedByCityStates = civInfo.getKnownCivs().asSequence() val luxuriesProvidedByCityStates = civInfo.getKnownCivs().asSequence()
.filter { it.isCityState() && it.getAllyCiv() == civInfo.civName } .filter { it.isCityState() && it.getAllyCiv() == civInfo.civName }
@ -240,7 +240,7 @@ class CivInfoStats(val civInfo: CivilizationInfo) {
statMap["Traded Luxuries"] = statMap["Traded Luxuries"] =
luxuriesAllOfWhichAreTradedAway.count() * happinessPerUniqueLuxury * luxuriesAllOfWhichAreTradedAway.count() * happinessPerUniqueLuxury *
civInfo.getMatchingUniques("Retain []% of the happiness from a luxury after the last copy has been traded away") civInfo.getMatchingUniques("Retain []% of the happiness from a luxury after the last copy has been traded away")
.sumBy { it.params[0].toInt() } / 100f .sumOf { it.params[0].toInt() } / 100f
for (city in civInfo.cities) { for (city in civInfo.cities) {
// There appears to be a concurrency problem? In concurrent thread in ConstructionsTable.getConstructionButtonDTOs // There appears to be a concurrency problem? In concurrent thread in ConstructionsTable.getConstructionButtonDTOs

View File

@ -1,25 +1,21 @@
package com.unciv.logic.civilization package com.unciv.logic.civilization
import com.badlogic.gdx.math.Vector2 import com.badlogic.gdx.math.Vector2
import com.unciv.Constants
import com.unciv.UncivGame import com.unciv.UncivGame
import com.unciv.logic.GameInfo import com.unciv.logic.GameInfo
import com.unciv.logic.UncivShowableException import com.unciv.logic.UncivShowableException
import com.unciv.logic.automation.NextTurnAutomation
import com.unciv.logic.automation.WorkerAutomation import com.unciv.logic.automation.WorkerAutomation
import com.unciv.logic.city.CityInfo import com.unciv.logic.city.CityInfo
import com.unciv.logic.civilization.RuinsManager.RuinsManager import com.unciv.logic.civilization.RuinsManager.RuinsManager
import com.unciv.logic.civilization.diplomacy.DiplomacyFlags import com.unciv.logic.civilization.diplomacy.DiplomacyFlags
import com.unciv.logic.civilization.diplomacy.DiplomacyManager import com.unciv.logic.civilization.diplomacy.DiplomacyManager
import com.unciv.logic.civilization.diplomacy.DiplomaticStatus import com.unciv.logic.civilization.diplomacy.DiplomaticStatus
import com.unciv.logic.civilization.diplomacy.RelationshipLevel
import com.unciv.logic.map.MapUnit import com.unciv.logic.map.MapUnit
import com.unciv.logic.map.TileInfo import com.unciv.logic.map.TileInfo
import com.unciv.logic.map.UnitMovementAlgorithms import com.unciv.logic.map.UnitMovementAlgorithms
import com.unciv.logic.trade.TradeEvaluation import com.unciv.logic.trade.TradeEvaluation
import com.unciv.logic.trade.TradeRequest import com.unciv.logic.trade.TradeRequest
import com.unciv.models.Counter import com.unciv.models.Counter
import com.unciv.models.metadata.GameSpeed
import com.unciv.models.ruleset.* import com.unciv.models.ruleset.*
import com.unciv.models.ruleset.tile.ResourceSupplyList import com.unciv.models.ruleset.tile.ResourceSupplyList
import com.unciv.models.ruleset.tile.ResourceType import com.unciv.models.ruleset.tile.ResourceType
@ -27,16 +23,15 @@ import com.unciv.models.ruleset.tile.TileResource
import com.unciv.models.ruleset.unit.BaseUnit import com.unciv.models.ruleset.unit.BaseUnit
import com.unciv.models.stats.Stat import com.unciv.models.stats.Stat
import com.unciv.models.stats.Stats import com.unciv.models.stats.Stats
import com.unciv.models.translations.getPlaceholderParameters
import com.unciv.models.translations.getPlaceholderText
import com.unciv.models.translations.tr import com.unciv.models.translations.tr
import com.unciv.ui.utils.toPercent import com.unciv.ui.utils.toPercent
import com.unciv.ui.victoryscreen.RankingType import com.unciv.ui.victoryscreen.RankingType
import java.util.* import java.util.*
import kotlin.collections.ArrayList import kotlin.collections.ArrayList
import kotlin.collections.HashMap import kotlin.collections.HashMap
import kotlin.collections.LinkedHashMap import kotlin.math.min
import kotlin.math.* import kotlin.math.roundToInt
import kotlin.math.sqrt
class CivilizationInfo { class CivilizationInfo {
@ -127,8 +122,8 @@ class CivilizationInfo {
* If the counter reaches 0 at the end of a turn, it is removed immediately * If the counter reaches 0 at the end of a turn, it is removed immediately
*/ */
val temporaryUniques = ArrayList<Pair<Unique, Int>>() val temporaryUniques = ArrayList<Pair<Unique, Int>>()
/** Maps the name of the construction to the amount of times bouhgt */ /** Maps the name of the construction to the amount of times bought */
val boughtConstructionsWithGloballyIncreasingPrice = HashMap<String, Int>() val boughtConstructionsWithGloballyIncreasingPrice = HashMap<String, Int>()
// if we only use lists, and change the list each time the cities are changed, // if we only use lists, and change the list each time the cities are changed,
@ -386,7 +381,7 @@ class CivilizationInfo {
meetCiv(otherCiv) meetCiv(otherCiv)
otherCiv.meetCiv(this) otherCiv.meetCiv(this)
} }
private fun meetCiv(otherCiv: CivilizationInfo) { private fun meetCiv(otherCiv: CivilizationInfo) {
diplomacy[otherCiv.civName] = DiplomacyManager(this, otherCiv.civName) diplomacy[otherCiv.civName] = DiplomacyManager(this, otherCiv.civName)
.apply { diplomaticStatus = DiplomaticStatus.Peace } .apply { diplomaticStatus = DiplomaticStatus.Peace }
@ -501,11 +496,11 @@ class CivilizationInfo {
fun getStatForRanking(category: RankingType): Int { fun getStatForRanking(category: RankingType): Int {
return when (category) { return when (category) {
RankingType.Population -> cities.sumBy { it.population.population } RankingType.Population -> cities.sumOf { it.population.population }
RankingType.Crop_Yield -> statsForNextTurn.food.roundToInt() RankingType.Crop_Yield -> statsForNextTurn.food.roundToInt()
RankingType.Production -> statsForNextTurn.production.roundToInt() RankingType.Production -> statsForNextTurn.production.roundToInt()
RankingType.Gold -> gold RankingType.Gold -> gold
RankingType.Territory -> cities.sumBy { it.tiles.size } RankingType.Territory -> cities.sumOf { it.tiles.size }
RankingType.Force -> getMilitaryMight() RankingType.Force -> getMilitaryMight()
RankingType.Happiness -> getHappiness() RankingType.Happiness -> getHappiness()
RankingType.Technologies -> tech.researchedTechnologies.size RankingType.Technologies -> tech.researchedTechnologies.size
@ -540,7 +535,7 @@ class CivilizationInfo {
return if (!gameInfo.hasReligionEnabled()) greatPeople.filter { !it.uniques.contains("Great Person - [Faith]")}.toHashSet() return if (!gameInfo.hasReligionEnabled()) greatPeople.filter { !it.uniques.contains("Great Person - [Faith]")}.toHashSet()
else greatPeople.toHashSet() else greatPeople.toHashSet()
} }
fun hasTechOrPolicy(techOrPolicyName: String) = fun hasTechOrPolicy(techOrPolicyName: String) =
tech.isResearched(techOrPolicyName) || policies.isAdopted(techOrPolicyName) tech.isResearched(techOrPolicyName) || policies.isAdopted(techOrPolicyName)
@ -710,9 +705,9 @@ class CivilizationInfo {
if (flagsCountdown[flag]!! > 0) if (flagsCountdown[flag]!! > 0)
flagsCountdown[flag] = flagsCountdown[flag]!! - 1 flagsCountdown[flag] = flagsCountdown[flag]!! - 1
if (flagsCountdown[flag]!! != 0) continue if (flagsCountdown[flag]!! != 0) continue
when (flag) { when (flag) {
CivFlags.TurnsTillNextDiplomaticVote.name -> addFlag(CivFlags.ShowDiplomaticVotingResults.name, 1) CivFlags.TurnsTillNextDiplomaticVote.name -> addFlag(CivFlags.ShowDiplomaticVotingResults.name, 1)
CivFlags.ShouldResetDiplomaticVotes.name -> { CivFlags.ShouldResetDiplomaticVotes.name -> {
@ -721,12 +716,12 @@ class CivilizationInfo {
removeFlag(CivFlags.ShowDiplomaticVotingResults.name) removeFlag(CivFlags.ShowDiplomaticVotingResults.name)
} }
CivFlags.ShowDiplomaticVotingResults.name -> { CivFlags.ShowDiplomaticVotingResults.name -> {
if (gameInfo.civilizations.any { it.victoryManager.hasWon() } ) if (gameInfo.civilizations.any { it.victoryManager.hasWon() } )
// We have either already done this calculation, or it doesn't matter anymore, // We have either already done this calculation, or it doesn't matter anymore,
// so don't waste resources doing it // so don't waste resources doing it
continue continue
addFlag(CivFlags.ShouldResetDiplomaticVotes.name, 1) addFlag(CivFlags.ShouldResetDiplomaticVotes.name, 1)
} }
} }
@ -737,27 +732,27 @@ class CivilizationInfo {
fun removeFlag(flag: String) { flagsCountdown.remove(flag) } fun removeFlag(flag: String) { flagsCountdown.remove(flag) }
fun getTurnsBetweenDiplomaticVotings() = (15 * gameInfo.gameParameters.gameSpeed.modifier).toInt() // Dunno the exact calculation, hidden in Lua files fun getTurnsBetweenDiplomaticVotings() = (15 * gameInfo.gameParameters.gameSpeed.modifier).toInt() // Dunno the exact calculation, hidden in Lua files
fun getTurnsTillNextDiplomaticVote() = flagsCountdown[CivFlags.TurnsTillNextDiplomaticVote.name] fun getTurnsTillNextDiplomaticVote() = flagsCountdown[CivFlags.TurnsTillNextDiplomaticVote.name]
fun getRecentBullyingCountdown() = flagsCountdown[CivFlags.RecentlyBullied.name] fun getRecentBullyingCountdown() = flagsCountdown[CivFlags.RecentlyBullied.name]
fun mayVoteForDiplomaticVictory() = fun mayVoteForDiplomaticVictory() =
getTurnsTillNextDiplomaticVote() == 0 getTurnsTillNextDiplomaticVote() == 0
&& civName !in gameInfo.diplomaticVictoryVotesCast.keys && civName !in gameInfo.diplomaticVictoryVotesCast.keys
fun diplomaticVoteForCiv(chosenCivName: String?) { fun diplomaticVoteForCiv(chosenCivName: String?) {
if (chosenCivName != null) gameInfo.diplomaticVictoryVotesCast[civName] = chosenCivName if (chosenCivName != null) gameInfo.diplomaticVictoryVotesCast[civName] = chosenCivName
addFlag(CivFlags.TurnsTillNextDiplomaticVote.name, getTurnsBetweenDiplomaticVotings()) addFlag(CivFlags.TurnsTillNextDiplomaticVote.name, getTurnsBetweenDiplomaticVotings())
} }
fun shouldShowDiplomaticVotingResults() = fun shouldShowDiplomaticVotingResults() =
flagsCountdown[CivFlags.ShowDiplomaticVotingResults.name] == 0 flagsCountdown[CivFlags.ShowDiplomaticVotingResults.name] == 0
// Yes, this is the same function as above, but with a different use case so it has a different name. // Yes, this is the same function as above, but with a different use case so it has a different name.
fun shouldCheckForDiplomaticVictory() = fun shouldCheckForDiplomaticVictory() =
flagsCountdown[CivFlags.ShowDiplomaticVotingResults.name] == 0 flagsCountdown[CivFlags.ShowDiplomaticVotingResults.name] == 0
/** Modify gold by a given amount making sure it does neither overflow nor underflow. /** Modify gold by a given amount making sure it does neither overflow nor underflow.
* @param delta the amount to add (can be negative) * @param delta the amount to add (can be negative)
*/ */
@ -781,7 +776,7 @@ class CivilizationInfo {
// Happiness cannot be added as it is recalculated again, use a unique instead // Happiness cannot be added as it is recalculated again, use a unique instead
} }
} }
fun getStatReserve(stat: Stat): Int { fun getStatReserve(stat: Stat): Int {
return when (stat) { return when (stat) {
Stat.Culture -> policies.storedCulture Stat.Culture -> policies.storedCulture
@ -842,7 +837,7 @@ class CivilizationInfo {
val unit = getEquivalentUnit(unitName) val unit = getEquivalentUnit(unitName)
val placedUnit = placeUnitNearTile(cityToAddTo.location, unit.name) val placedUnit = placeUnitNearTile(cityToAddTo.location, unit.name)
// silently bail if no tile to place the unit is found // silently bail if no tile to place the unit is found
if (placedUnit == null) return null ?: return null
if (unit.isGreatPerson()) { if (unit.isGreatPerson()) {
addNotification("A [${unit.name}] has been born in [${cityToAddTo.name}]!", placedUnit.getTile().position, unit.name) addNotification("A [${unit.name}] has been born in [${cityToAddTo.name}]!", placedUnit.getTile().position, unit.name)
} }
@ -890,14 +885,14 @@ class CivilizationInfo {
diplomacyManager.otherCiv().tradeRequests.remove(tradeRequest) // it would be really weird to get a trade request from a dead civ diplomacyManager.otherCiv().tradeRequests.remove(tradeRequest) // it would be really weird to get a trade request from a dead civ
} }
} }
fun getResearchAgreementCost(): Int { fun getResearchAgreementCost(): Int {
// https://forums.civfanatics.com/resources/research-agreements-bnw.25568/ // https://forums.civfanatics.com/resources/research-agreements-bnw.25568/
return ( return (
getEra().researchAgreementCost * gameInfo.gameParameters.gameSpeed.modifier getEra().researchAgreementCost * gameInfo.gameParameters.gameSpeed.modifier
).toInt() ).toInt()
} }
//////////////////////// City State wrapper functions //////////////////////// //////////////////////// City State wrapper functions ////////////////////////
/** Gain a random great person from the city state */ /** Gain a random great person from the city state */
private fun giveGreatPersonToPatron(receivingCiv: CivilizationInfo) { private fun giveGreatPersonToPatron(receivingCiv: CivilizationInfo) {
@ -950,7 +945,7 @@ class CivilizationInfo {
fun threateningBarbarianKilledBy(otherCiv: CivilizationInfo) { fun threateningBarbarianKilledBy(otherCiv: CivilizationInfo) {
cityStateFunctions.threateningBarbarianKilledBy(otherCiv) cityStateFunctions.threateningBarbarianKilledBy(otherCiv)
} }
fun getAllyCiv() = allyCivName fun getAllyCiv() = allyCivName
fun setAllyCiv(newAllyName: String?) { allyCivName = newAllyName } fun setAllyCiv(newAllyName: String?) { allyCivName = newAllyName }

View File

@ -116,9 +116,9 @@ class MapUnit {
return if (religion == null) baseName return if (religion == null) baseName
else "$baseName ([${getReligionDisplayName()}])" else "$baseName ([${getReligionDisplayName()}])"
} }
fun shortDisplayName(): String { fun shortDisplayName(): String {
return if (instanceName != null) "[$instanceName]"!! return if (instanceName != null) "[$instanceName]"
else "[$name]" else "[$name]"
} }
@ -133,15 +133,15 @@ class MapUnit {
var promotions = UnitPromotions() var promotions = UnitPromotions()
var due: Boolean = true var due: Boolean = true
var isTransported: Boolean = false var isTransported: Boolean = false
// Deprecated since 3.16.11 // Deprecated since 3.16.11
@Deprecated("Deprecated since 3.16.11", replaceWith = ReplaceWith("abilityUsesLeft")) @Deprecated("Deprecated since 3.16.11", replaceWith = ReplaceWith("abilityUsesLeft"))
var abilityUsedCount: HashMap<String, Int> = hashMapOf() var abilityUsedCount: HashMap<String, Int> = hashMapOf()
// //
var abilityUsesLeft: HashMap<String, Int> = hashMapOf() var abilityUsesLeft: HashMap<String, Int> = hashMapOf()
var maxAbilityUses: HashMap<String, Int> = hashMapOf() var maxAbilityUses: HashMap<String, Int> = hashMapOf()
var religion: String? = null var religion: String? = null
var religiousStrengthLost = 0 var religiousStrengthLost = 0
@ -181,7 +181,7 @@ class MapUnit {
var movement = var movement =
if (isEmbarked()) 2 if (isEmbarked()) 2
else baseUnit.movement else baseUnit.movement
movement += getMatchingUniques("[] Movement").sumOf { it.params[0].toInt() } movement += getMatchingUniques("[] Movement").sumOf { it.params[0].toInt() }
for (unique in civInfo.getMatchingUniques("+[] Movement for all [] units")) for (unique in civInfo.getMatchingUniques("+[] Movement for all [] units"))
@ -224,7 +224,7 @@ class MapUnit {
val baseUnit = baseUnit() val baseUnit = baseUnit()
uniques.addAll(baseUnit.uniqueObjects) uniques.addAll(baseUnit.uniqueObjects)
uniques.addAll(type.uniqueObjects) uniques.addAll(type.uniqueObjects)
for (promotion in promotions.promotions) { for (promotion in promotions.promotions) {
uniques.addAll(currentTile.tileMap.gameInfo.ruleSet.unitPromotions[promotion]!!.uniqueObjects) uniques.addAll(currentTile.tileMap.gameInfo.ruleSet.unitPromotions[promotion]!!.uniqueObjects)
} }
@ -259,13 +259,13 @@ class MapUnit {
for (promotion in newUnit.promotions.promotions) for (promotion in newUnit.promotions.promotions)
if (promotion !in promotions.promotions) if (promotion !in promotions.promotions)
promotions.addPromotion(promotion, isFree = true) promotions.addPromotion(promotion, isFree = true)
newUnit.promotions = promotions.clone() newUnit.promotions = promotions.clone()
newUnit.updateUniques() newUnit.updateUniques()
newUnit.updateVisibleTiles() newUnit.updateVisibleTiles()
} }
/** /**
* Determines this (land or sea) unit's current maximum vision range from unit properties, civ uniques and terrain. * Determines this (land or sea) unit's current maximum vision range from unit properties, civ uniques and terrain.
* @return Maximum distance of tiles this unit may possibly see * @return Maximum distance of tiles this unit may possibly see
@ -278,7 +278,7 @@ class MapUnit {
// TODO: This should be replaced with "Sight" like others, for naming consistency // TODO: This should be replaced with "Sight" like others, for naming consistency
visibilityRange += getMatchingUniques("[] Visibility Range").sumOf { it.params[0].toInt() } visibilityRange += getMatchingUniques("[] Visibility Range").sumOf { it.params[0].toInt() }
if (hasUnique("Limited Visibility")) visibilityRange -= 1 if (hasUnique("Limited Visibility")) visibilityRange -= 1
@ -315,7 +315,7 @@ class MapUnit {
fun isSleepingUntilHealed() = isSleeping() && isActionUntilHealed() fun isSleepingUntilHealed() = isSleeping() && isActionUntilHealed()
fun isMoving() = action?.startsWith("moveTo") == true fun isMoving() = action?.startsWith("moveTo") == true
fun isAutomated() = action == UnitActionType.Automate.value fun isAutomated() = action == UnitActionType.Automate.value
fun isExploring() = action == UnitActionType.Explore.value fun isExploring() = action == UnitActionType.Explore.value
fun isPreparingParadrop() = action == UnitActionType.Paradrop.value fun isPreparingParadrop() = action == UnitActionType.Paradrop.value
@ -344,10 +344,9 @@ class MapUnit {
} }
fun maxAttacksPerTurn(): Int { fun maxAttacksPerTurn(): Int {
var maxAttacksPerTurn = 1 + getMatchingUniques("[] additional attacks per turn").sumOf { it.params[0].toInt() } return 1 + getMatchingUniques("[] additional attacks per turn").sumOf { it.params[0].toInt() }
return maxAttacksPerTurn
} }
fun canAttack(): Boolean { fun canAttack(): Boolean {
if (currentMovement == 0f) return false if (currentMovement == 0f) return false
return attacksThisTurn < maxAttacksPerTurn() return attacksThisTurn < maxAttacksPerTurn()
@ -359,7 +358,7 @@ class MapUnit {
range += getMatchingUniques("[] Range").sumOf { it.params[0].toInt() } range += getMatchingUniques("[] Range").sumOf { it.params[0].toInt() }
return range return range
} }
fun getMaxMovementForAirUnits(): Int { fun getMaxMovementForAirUnits(): Int {
return getRange() * 2 return getRange() * 2
} }
@ -458,16 +457,16 @@ class MapUnit {
promotions.setTransients(this) promotions.setTransients(this)
baseUnit = ruleset.units[name] baseUnit = ruleset.units[name]
?: throw java.lang.Exception("Unit $name is not found!") ?: throw java.lang.Exception("Unit $name is not found!")
// "Religion Spread" ability deprecated since 3.16.7, replaced with "Spread Religion" // "Religion Spread" ability deprecated since 3.16.7, replaced with "Spread Religion"
if ("Religion Spread" in abilityUsedCount) { if ("Religion Spread" in abilityUsedCount) {
abilityUsedCount[Constants.spreadReligionAbilityCount] = abilityUsedCount["Religion Spread"]!! abilityUsedCount[Constants.spreadReligionAbilityCount] = abilityUsedCount["Religion Spread"]!!
abilityUsedCount.remove("Religion Spread") abilityUsedCount.remove("Religion Spread")
} }
// //
updateUniques() updateUniques()
// abilityUsedCount deprecated since 3.16.11, this is replacement code // abilityUsedCount deprecated since 3.16.11, this is replacement code
if (abilityUsedCount.isNotEmpty()) { if (abilityUsedCount.isNotEmpty()) {
for (ability in abilityUsedCount) { for (ability in abilityUsedCount) {
@ -480,7 +479,7 @@ class MapUnit {
abilityUsedCount.clear() abilityUsedCount.clear()
} }
// //
} }
fun useMovementPoints(amount: Float) { fun useMovementPoints(amount: Float) {
@ -600,7 +599,7 @@ class MapUnit {
if (amountToHealBy == 0 && !(hasUnique("May heal outside of friendly territory") && !getTile().isFriendlyTerritory(civInfo))) return if (amountToHealBy == 0 && !(hasUnique("May heal outside of friendly territory") && !getTile().isFriendlyTerritory(civInfo))) return
amountToHealBy += getMatchingUniques("[] HP when healing").sumOf { it.params[0].toInt() } amountToHealBy += getMatchingUniques("[] HP when healing").sumOf { it.params[0].toInt() }
val maxAdjacentHealingBonus = currentTile.getTilesInDistance(1) val maxAdjacentHealingBonus = currentTile.getTilesInDistance(1)
.flatMap { it.getUnits().asSequence() }.map { it.adjacentHealingBonus() }.maxOrNull() .flatMap { it.getUnits().asSequence() }.map { it.adjacentHealingBonus() }.maxOrNull()
if (maxAdjacentHealingBonus != null) if (maxAdjacentHealingBonus != null)
@ -627,17 +626,17 @@ class MapUnit {
isFriendlyTerritory -> 15 // Allied territory isFriendlyTerritory -> 15 // Allied territory
else -> 5 // Enemy territory else -> 5 // Enemy territory
} }
val mayHeal = healing > 0 || (tileInfo.isWater && hasUnique("May heal outside of friendly territory")) val mayHeal = healing > 0 || (tileInfo.isWater && hasUnique("May heal outside of friendly territory"))
if (!mayHeal) return healing if (!mayHeal) return healing
for (unique in getMatchingUniques("[] HP when healing in [] tiles")) { for (unique in getMatchingUniques("[] HP when healing in [] tiles")) {
if (tileInfo.matchesFilter(unique.params[1], civInfo)) { if (tileInfo.matchesFilter(unique.params[1], civInfo)) {
healing += unique.params[0].toInt() healing += unique.params[0].toInt()
} }
} }
val healingCity = tileInfo.getTilesInDistance(1).firstOrNull { val healingCity = tileInfo.getTilesInDistance(1).firstOrNull {
it.isCityCenter() && it.getCity()!!.getMatchingUniques("[] Units adjacent to this city heal [] HP per turn when healing").any() it.isCityCenter() && it.getCity()!!.getMatchingUniques("[] Units adjacent to this city heal [] HP per turn when healing").any()
}?.getCity() }?.getCity()
@ -863,7 +862,7 @@ class MapUnit {
if (currentTile.aerialDistanceTo(attackedTile) > baseUnit.interceptRange) return false if (currentTile.aerialDistanceTo(attackedTile) > baseUnit.interceptRange) return false
return true return true
} }
fun canIntercept(): Boolean { fun canIntercept(): Boolean {
if (interceptChance() == 0) return false if (interceptChance() == 0) return false
val maxAttacksPerTurn = 1 + val maxAttacksPerTurn = 1 +
@ -987,17 +986,17 @@ class MapUnit {
val matchingUniques = getMatchingUniques(Constants.canBuildImprovements) val matchingUniques = getMatchingUniques(Constants.canBuildImprovements)
return matchingUniques.any { improvement.matchesFilter(it.params[0]) || tile.matchesTerrainFilter(it.params[0]) } return matchingUniques.any { improvement.matchesFilter(it.params[0]) || tile.matchesTerrainFilter(it.params[0]) }
} }
fun getReligionDisplayName(): String? { fun getReligionDisplayName(): String? {
if (religion == null) return null if (religion == null) return null
return civInfo.gameInfo.religions[religion]!!.getReligionDisplayName() return civInfo.gameInfo.religions[religion]!!.getReligionDisplayName()
} }
fun religiousActionsUnitCanDo(): Sequence<String> { fun religiousActionsUnitCanDo(): Sequence<String> {
return getMatchingUniques("Can [] [] times") return getMatchingUniques("Can [] [] times")
.map { it.params[0] } .map { it.params[0] }
} }
fun canDoReligiousAction(action: String): Boolean { fun canDoReligiousAction(action: String): Boolean {
return getMatchingUniques("Can [] [] times").any { it.params[0] == action } return getMatchingUniques("Can [] [] times").any { it.params[0] == action }
} }
@ -1030,10 +1029,10 @@ class MapUnit {
for (unique in civInfo.getMatchingUniques("[]% Spread Religion Strength for [] units")) for (unique in civInfo.getMatchingUniques("[]% Spread Religion Strength for [] units"))
if (matchesFilter(unique.params[0])) if (matchesFilter(unique.params[0]))
pressureAdded *= unique.params[0].toPercent() pressureAdded *= unique.params[0].toPercent()
return pressureAdded.toInt() return pressureAdded.toInt()
} }
fun getActionString(action: String): String { fun getActionString(action: String): String {
val maxActionUses = maxAbilityUses[action] val maxActionUses = maxAbilityUses[action]
if (abilityUsesLeft[action] == null) return "0/0" // Something went wrong if (abilityUsesLeft[action] == null) return "0/0" // Something went wrong

View File

@ -34,7 +34,7 @@ class Building : NamedStats(), INonPerpetualConstruction, ICivilopediaText {
// Could have old specialist values of "gold", "science" etc - change them to the new specialist names // Could have old specialist values of "gold", "science" etc - change them to the new specialist names
val counter = Counter<String>() val counter = Counter<String>()
for ((entry, amount) in specialistSlots!!) { for ((entry, amount) in specialistSlots!!) {
val equivalentStat = Stat.values().firstOrNull { it.name.toLowerCase(Locale.ENGLISH) == entry } val equivalentStat = Stat.values().firstOrNull { it.name.lowercase() == entry }
if (equivalentStat != null) if (equivalentStat != null)
counter[Specialist.specialistNameByStat(equivalentStat)] = amount counter[Specialist.specialistNameByStat(equivalentStat)] = amount

View File

@ -415,11 +415,11 @@ class Ruleset {
fun getPrereqTree(technologyName: String): Set<String> { fun getPrereqTree(technologyName: String): Set<String> {
if (prereqsHashMap.containsKey(technologyName)) return prereqsHashMap[technologyName]!! if (prereqsHashMap.containsKey(technologyName)) return prereqsHashMap[technologyName]!!
val technology = technologies[technologyName] val technology = technologies[technologyName]
if (technology == null) return emptySet() ?: return emptySet()
val techHashSet = HashSet<String>() val techHashSet = HashSet<String>()
techHashSet += technology.prerequisites techHashSet += technology.prerequisites
for (prereq in technology.prerequisites) for (prerequisite in technology.prerequisites)
techHashSet += getPrereqTree(prereq) techHashSet += getPrereqTree(prerequisite)
prereqsHashMap[technologyName] = techHashSet prereqsHashMap[technologyName] = techHashSet
return techHashSet return techHashSet
} }

View File

@ -9,7 +9,13 @@ import com.unciv.ui.tilegroups.TileGroup
import kotlin.math.max import kotlin.math.max
import kotlin.math.min import kotlin.math.min
class TileGroupMap<T: TileGroup>(tileGroups: Collection<T>, private val leftAndRightPadding: Float, private val topAndBottomPadding: Float, worldWrap: Boolean = false, tileGroupsToUnwrap: Collection<T>? = null): Group(){ class TileGroupMap<T: TileGroup>(
tileGroups: Collection<T>,
private val leftAndRightPadding: Float,
private val topAndBottomPadding: Float,
worldWrap: Boolean = false,
tileGroupsToUnwrap: Collection<T>? = null
): Group() {
var topX = -Float.MAX_VALUE var topX = -Float.MAX_VALUE
var topY = -Float.MAX_VALUE var topY = -Float.MAX_VALUE
var bottomX = Float.MAX_VALUE var bottomX = Float.MAX_VALUE
@ -17,17 +23,18 @@ class TileGroupMap<T: TileGroup>(tileGroups: Collection<T>, private val leftAndR
private val groupSize = 50 private val groupSize = 50
private val mirrorTileGroups = HashMap<TileInfo, Pair<T, T>>() private val mirrorTileGroups = HashMap<TileInfo, Pair<T, T>>()
init{ init {
if (worldWrap) { if (worldWrap) {
for(tileGroup in tileGroups) { for (tileGroup in tileGroups) {
@Suppress("UNCHECKED_CAST") // T is constrained such that casting these TileGroup clones to T should be OK
mirrorTileGroups[tileGroup.tileInfo] = Pair(tileGroup.clone() as T, tileGroup.clone() as T) mirrorTileGroups[tileGroup.tileInfo] = Pair(tileGroup.clone() as T, tileGroup.clone() as T)
} }
} }
for(tileGroup in tileGroups) { for (tileGroup in tileGroups) {
val positionalVector = if (tileGroupsToUnwrap != null && tileGroupsToUnwrap.contains(tileGroup)){ val positionalVector = if (tileGroupsToUnwrap != null && tileGroupsToUnwrap.contains(tileGroup)) {
HexMath.hex2WorldCoords( HexMath.hex2WorldCoords(
tileGroup.tileInfo.tileMap.getUnWrappedPosition(tileGroup.tileInfo.position) tileGroup.tileInfo.tileMap.getUnWrappedPosition(tileGroup.tileInfo.position)
) )
} else { } else {
HexMath.hex2WorldCoords(tileGroup.tileInfo.position) HexMath.hex2WorldCoords(tileGroup.tileInfo.position)
@ -80,7 +87,7 @@ class TileGroupMap<T: TileGroup>(tileGroups: Collection<T>, private val leftAndR
val circleCrosshairFogLayers = ArrayList<Group>() val circleCrosshairFogLayers = ArrayList<Group>()
// Apparently the sortedByDescending is kinda memory-intensive because it needs to sort ALL the tiles // Apparently the sortedByDescending is kinda memory-intensive because it needs to sort ALL the tiles
for(group in tileGroups.sortedByDescending { it.tileInfo.position.x + it.tileInfo.position.y }){ for (group in tileGroups.sortedByDescending { it.tileInfo.position.x + it.tileInfo.position.y }) {
// now, we steal the subgroups from all the tilegroups, that's how we form layers! // now, we steal the subgroups from all the tilegroups, that's how we form layers!
baseLayers.add(group.baseLayerGroup.apply { setPosition(group.x,group.y) }) baseLayers.add(group.baseLayerGroup.apply { setPosition(group.x,group.y) })
featureLayers.add(group.terrainFeatureLayerGroup.apply { setPosition(group.x,group.y) }) featureLayers.add(group.terrainFeatureLayerGroup.apply { setPosition(group.x,group.y) })
@ -90,8 +97,8 @@ class TileGroupMap<T: TileGroup>(tileGroups: Collection<T>, private val leftAndR
cityButtonLayers.add(group.cityButtonLayerGroup.apply { setPosition(group.x,group.y) }) cityButtonLayers.add(group.cityButtonLayerGroup.apply { setPosition(group.x,group.y) })
circleCrosshairFogLayers.add(group.circleCrosshairFogLayerGroup.apply { setPosition(group.x,group.y) }) circleCrosshairFogLayers.add(group.circleCrosshairFogLayerGroup.apply { setPosition(group.x,group.y) })
if (worldWrap){ if (worldWrap) {
for (mirrorTile in mirrorTileGroups[group.tileInfo]!!.toList()){ for (mirrorTile in mirrorTileGroups[group.tileInfo]!!.toList()) {
baseLayers.add(mirrorTile.baseLayerGroup.apply { setPosition(mirrorTile.x,mirrorTile.y) }) baseLayers.add(mirrorTile.baseLayerGroup.apply { setPosition(mirrorTile.x,mirrorTile.y) })
featureLayers.add(mirrorTile.terrainFeatureLayerGroup.apply { setPosition(mirrorTile.x,mirrorTile.y) }) featureLayers.add(mirrorTile.terrainFeatureLayerGroup.apply { setPosition(mirrorTile.x,mirrorTile.y) })
miscLayers.add(mirrorTile.miscLayerGroup.apply { setPosition(mirrorTile.x,mirrorTile.y) }) miscLayers.add(mirrorTile.miscLayerGroup.apply { setPosition(mirrorTile.x,mirrorTile.y) })
@ -102,20 +109,20 @@ class TileGroupMap<T: TileGroup>(tileGroups: Collection<T>, private val leftAndR
} }
} }
} }
for(group in baseLayers) addActor(group) for (group in baseLayers) addActor(group)
for(group in featureLayers) addActor(group) for (group in featureLayers) addActor(group)
for(group in miscLayers) addActor(group) for (group in miscLayers) addActor(group)
for(group in circleCrosshairFogLayers) addActor(group) for (group in circleCrosshairFogLayers) addActor(group)
for(group in tileGroups) addActor(group) // The above layers are for the visual layers, this is for the clickability of the tile for (group in tileGroups) addActor(group) // The above layers are for the visual layers, this is for the clickability of the tile
if (worldWrap){ if (worldWrap) {
for (mirrorTiles in mirrorTileGroups.values){ for (mirrorTiles in mirrorTileGroups.values) {
addActor(mirrorTiles.first) addActor(mirrorTiles.first)
addActor(mirrorTiles.second) addActor(mirrorTiles.second)
} }
} }
for(group in unitLayers) addActor(group) // Aaand units above everything else. for (group in unitLayers) addActor(group) // Aaand units above everything else.
for(group in unitImageLayers) addActor(group) // This is so the individual textures for the units are rendered together for (group in unitImageLayers) addActor(group) // This is so the individual textures for the units are rendered together
for(group in cityButtonLayers) addActor(group) // city buttons + clickability for (group in cityButtonLayers) addActor(group) // city buttons + clickability
// there are tiles "below the zero", // there are tiles "below the zero",

View File

@ -87,11 +87,11 @@ class CityOverviewTable(private val viewingPlayer: CivilizationInfo, private val
.minWidth(iconSize) //we need the min width so we can align the different tables .minWidth(iconSize) //we need the min width so we can align the different tables
cityInfoTableTotal.add("Total".toLabel()) cityInfoTableTotal.add("Total".toLabel())
cityInfoTableTotal.add(viewingPlayer.cities.sumBy { it.population.population }.toString().toLabel()).myAlign(Align.center) cityInfoTableTotal.add(viewingPlayer.cities.sumOf { it.population.population }.toString().toLabel()).myAlign(Align.center)
for (column in columnsNames.filter { it.isStat() }) { for (column in columnsNames.filter { it.isStat() }) {
val stat = Stat.valueOf(column) val stat = Stat.valueOf(column)
if (stat == Stat.Food || stat == Stat.Production) cityInfoTableTotal.add() // an intended empty space if (stat == Stat.Food || stat == Stat.Production) cityInfoTableTotal.add() // an intended empty space
else cityInfoTableTotal.add(viewingPlayer.cities.sumBy { getStatOfCity(it, stat) }.toLabel()).myAlign(Align.center) else cityInfoTableTotal.add(viewingPlayer.cities.sumOf { getStatOfCity(it, stat) }.toLabel()).myAlign(Align.center)
} }
cityInfoTableTotal.pack() cityInfoTableTotal.pack()
@ -111,7 +111,7 @@ class CityOverviewTable(private val viewingPlayer: CivilizationInfo, private val
private fun getStatOfCity(cityInfo: CityInfo, stat: Stat): Int { private fun getStatOfCity(cityInfo: CityInfo, stat: Stat): Int {
return if (stat == Stat.Happiness) return if (stat == Stat.Happiness)
cityInfo.cityStats.happinessList.values.sum().roundToInt() cityInfo.cityStats.happinessList.values.sum().roundToInt()
else cityInfo.cityStats.currentCityStats.get(stat).roundToInt() else cityInfo.cityStats.currentCityStats[stat].roundToInt()
} }
private fun fillCitiesTable(citiesTable: Table, sortType: String, descending: Boolean) { private fun fillCitiesTable(citiesTable: Table, sortType: String, descending: Boolean) {

View File

@ -16,8 +16,7 @@ class ResourcesOverviewTable (
viewingPlayer: CivilizationInfo, viewingPlayer: CivilizationInfo,
overviewScreen: EmpireOverviewScreen overviewScreen: EmpireOverviewScreen
) : Table() { ) : Table() {
//val game = overviewScreen.game
init { init {
defaults().pad(10f) defaults().pad(10f)
@ -79,7 +78,7 @@ class ResourcesOverviewTable (
add("Total".toLabel()) add("Total".toLabel())
for (resource in resources) { for (resource in resources) {
val sum = resourceDrilldown.filter { it.resource == resource }.sumBy { it.amount } val sum = resourceDrilldown.filter { it.resource == resource }.sumOf { it.amount }
add(sum.toLabel()) add(sum.toLabel())
} }
} }

View File

@ -104,14 +104,14 @@ class TechPickerScreen(internal val civInfo: CivilizationInfo, centerOnTech: Tec
if (!erasNamesToColumns[era]!!.contains(columnNumber)) erasNamesToColumns[era]!!.add(columnNumber) if (!erasNamesToColumns[era]!!.contains(columnNumber)) erasNamesToColumns[era]!!.add(columnNumber)
} }
var i = 0 var i = 0
for ((era, columns) in erasNamesToColumns) { for ((era, eraColumns) in erasNamesToColumns) {
val columnSpan = columns.size val columnSpan = eraColumns.size
val color = if (i % 2 == 0) Color.BLUE else Color.FIREBRICK val color = if (i % 2 == 0) Color.BLUE else Color.FIREBRICK
i++ i++
techTable.add(era.toLabel().addBorder(2f, color)).fill().colspan(columnSpan) techTable.add(era.toLabel().addBorder(2f, color)).fill().colspan(columnSpan)
} }
for (rowIndex in 0..rows - 1) { for (rowIndex in 0 until rows) {
techTable.row().pad(5f).padRight(40f) techTable.row().pad(5f).padRight(40f)
for (columnIndex in techMatrix.indices) { for (columnIndex in techMatrix.indices) {
@ -206,13 +206,13 @@ class TechPickerScreen(internal val civInfo: CivilizationInfo, centerOnTech: Tec
} }
} }
private fun selectTechnology(tech: Technology?, center: Boolean = false, switchfromWorldScreen: Boolean = true) { private fun selectTechnology(tech: Technology?, center: Boolean = false, switchFromWorldScreen: Boolean = true) {
val previousSelectedTech = selectedTech val previousSelectedTech = selectedTech
selectedTech = tech selectedTech = tech
descriptionLabel.setText(tech?.getDescription(civInfo.gameInfo.ruleSet)) descriptionLabel.setText(tech?.getDescription(civInfo.gameInfo.ruleSet))
if (!switchfromWorldScreen) if (!switchFromWorldScreen)
return return
if (tech == null) if (tech == null)
@ -264,8 +264,8 @@ class TechPickerScreen(internal val civInfo: CivilizationInfo, centerOnTech: Tec
} }
private fun getTechProgressLabel(techs: List<String>): String { private fun getTechProgressLabel(techs: List<String>): String {
val progress = techs.sumBy { tech -> civTech.researchOfTech(tech) } val progress = techs.sumOf { tech -> civTech.researchOfTech(tech) }
val techCost = techs.sumBy { tech -> civInfo.tech.costOfTech(tech) } val techCost = techs.sumOf { tech -> civInfo.tech.costOfTech(tech) }
return "(${progress}/${techCost})" return "(${progress}/${techCost})"
} }