Improve BaseUnit hasUnique(FoundCity) handling (#10063)

This commit is contained in:
SomeTroglodyte 2023-09-05 14:40:55 +02:00 committed by GitHub
parent f7069851c7
commit a2fa4cebf4
No known key found for this signature in database
GPG Key ID: 4AEE18F83AFDEB23
6 changed files with 21 additions and 17 deletions

View File

@ -18,8 +18,8 @@ import com.unciv.models.ruleset.ModOptionsConstants
import com.unciv.models.ruleset.Ruleset import com.unciv.models.ruleset.Ruleset
import com.unciv.models.ruleset.RulesetCache import com.unciv.models.ruleset.RulesetCache
import com.unciv.models.ruleset.unique.StateForConditionals import com.unciv.models.ruleset.unique.StateForConditionals
import com.unciv.models.ruleset.unique.UniqueType
import com.unciv.models.ruleset.unique.UniqueTriggerActivation import com.unciv.models.ruleset.unique.UniqueTriggerActivation
import com.unciv.models.ruleset.unique.UniqueType
import com.unciv.models.ruleset.unit.BaseUnit import com.unciv.models.ruleset.unit.BaseUnit
import com.unciv.models.stats.Stats import com.unciv.models.stats.Stats
import com.unciv.models.translations.equalsPlaceholderText import com.unciv.models.translations.equalsPlaceholderText
@ -416,7 +416,7 @@ object GameStarter {
ruleset: Ruleset ruleset: Ruleset
) { ) {
val startingEra = gameInfo.gameParameters.startingEra val startingEra = gameInfo.gameParameters.startingEra
val settlerLikeUnits = ruleset.units.filter { it.value.hasUnique(UniqueType.FoundCity) } val settlerLikeUnits = ruleset.units.filter { it.value.isCityFounder() }
for (civ in gameInfo.civilizations.filter { !it.isBarbarian() && !it.isSpectator() }) { for (civ in gameInfo.civilizations.filter { !it.isBarbarian() && !it.isSpectator() }) {
val startingLocation = startingLocations[civ]!! val startingLocation = startingLocations[civ]!!
@ -539,7 +539,7 @@ object GameStarter {
): HashMap<Civilization, Tile> { ): HashMap<Civilization, Tile> {
val civsOrderedByAvailableLocations = getCivsOrderedByAvailableLocations(civs, tileMap) val civsOrderedByAvailableLocations = getCivsOrderedByAvailableLocations(civs, tileMap)
for (minimumDistanceBetweenStartingLocations in tileMap.tileMatrix.size / 6 downTo 0) { for (minimumDistanceBetweenStartingLocations in tileMap.tileMatrix.size / 6 downTo 0) {
val freeTiles = getFreeTiles(tileMap, landTilesInBigEnoughGroup, minimumDistanceBetweenStartingLocations) val freeTiles = getFreeTiles(tileMap, landTilesInBigEnoughGroup, minimumDistanceBetweenStartingLocations)
@ -581,12 +581,12 @@ object GameStarter {
): HashMap<Civilization, Tile>? { ): HashMap<Civilization, Tile>? {
val startingLocations = HashMap<Civilization, Tile>() val startingLocations = HashMap<Civilization, Tile>()
for (civ in civsOrderedByAvailableLocations) { for (civ in civsOrderedByAvailableLocations) {
val startingLocation = getCivStartingLocation(civ, tileMap, freeTiles, startScores) val startingLocation = getCivStartingLocation(civ, tileMap, freeTiles, startScores)
startingLocation ?: break startingLocation ?: break
startingLocations[civ] = startingLocation startingLocations[civ] = startingLocation
val distanceToNext = minimumDistanceBetweenStartingLocations / val distanceToNext = minimumDistanceBetweenStartingLocations /
(if (civ.isCityState()) 2 else 1) // We allow city states to squeeze in tighter (if (civ.isCityState()) 2 else 1) // We allow city states to squeeze in tighter
freeTiles.removeAll(tileMap.getTilesInDistance(startingLocation.position, distanceToNext) freeTiles.removeAll(tileMap.getTilesInDistance(startingLocation.position, distanceToNext)

View File

@ -1026,7 +1026,7 @@ object NextTurnAutomation {
val sortedUnits = civInfo.units.getCivUnits().sortedBy { unit -> getUnitPriority(unit, isAtWar) } val sortedUnits = civInfo.units.getCivUnits().sortedBy { unit -> getUnitPriority(unit, isAtWar) }
for (unit in sortedUnits) UnitAutomation.automateUnitMoves(unit) for (unit in sortedUnits) UnitAutomation.automateUnitMoves(unit)
} }
private fun getUnitPriority(unit: MapUnit, isAtWar: Boolean): Int { private fun getUnitPriority(unit: MapUnit, isAtWar: Boolean): Int {
if (unit.isCivilian() && !unit.isGreatPersonOfType("War")) return 1 // Civilian if (unit.isCivilian() && !unit.isGreatPersonOfType("War")) return 1 // Civilian
if (unit.baseUnit.isAirUnit()) return 2 if (unit.baseUnit.isAirUnit()) return 2
@ -1078,13 +1078,13 @@ object NextTurnAutomation {
if (civInfo.getHappiness() <= civInfo.cities.size) return if (civInfo.getHappiness() <= civInfo.cities.size) return
val settlerUnits = civInfo.gameInfo.ruleset.units.values val settlerUnits = civInfo.gameInfo.ruleset.units.values
.filter { it.hasUnique(UniqueType.FoundCity) && it.isBuildable(civInfo) } .filter { it.isCityFounder() && it.isBuildable(civInfo) }
if (settlerUnits.isEmpty()) return if (settlerUnits.isEmpty()) return
if (!civInfo.units.getCivUnits().none { it.hasUnique(UniqueType.FoundCity) }) return if (!civInfo.units.getCivUnits().none { it.hasUnique(UniqueType.FoundCity) }) return
if (civInfo.cities.any { if (civInfo.cities.any {
val currentConstruction = it.cityConstructions.getCurrentConstruction() val currentConstruction = it.cityConstructions.getCurrentConstruction()
currentConstruction is BaseUnit && currentConstruction.hasUnique(UniqueType.FoundCity) currentConstruction is BaseUnit && currentConstruction.isCityFounder()
}) return }) return
if (civInfo.units.getCivUnits().none { it.isMilitary() }) return // We need someone to defend him first if (civInfo.units.getCivUnits().none { it.isMilitary() }) return // We need someone to defend him first

View File

@ -8,9 +8,9 @@ import com.unciv.models.ruleset.RulesetObject
import com.unciv.models.ruleset.unique.StateForConditionals import com.unciv.models.ruleset.unique.StateForConditionals
import com.unciv.models.ruleset.unique.UniqueTarget import com.unciv.models.ruleset.unique.UniqueTarget
import com.unciv.models.ruleset.unique.UniqueType import com.unciv.models.ruleset.unique.UniqueType
import com.unciv.ui.screens.civilopediascreen.FormattedLine
import com.unciv.ui.components.Fonts import com.unciv.ui.components.Fonts
import com.unciv.ui.components.extensions.colorFromRGB import com.unciv.ui.components.extensions.colorFromRGB
import com.unciv.ui.screens.civilopediascreen.FormattedLine
class Era : RulesetObject() { class Era : RulesetObject() {
var eraNumber: Int = -1 var eraNumber: Int = -1
@ -88,7 +88,7 @@ class Era : RulesetObject() {
val startingSettlerName: String = val startingSettlerName: String =
if (startingSettlerUnit in ruleset.units) startingSettlerUnit if (startingSettlerUnit in ruleset.units) startingSettlerUnit
else ruleset.units.values else ruleset.units.values
.firstOrNull { it.hasUnique(UniqueType.FoundCity) } .firstOrNull { it.isCityFounder() }
?.name ?.name
?: throw UncivShowableException("No Settler unit found for era $name") ?: throw UncivShowableException("No Settler unit found for era $name")
val startingWorkerName: String = val startingWorkerName: String =

View File

@ -56,7 +56,7 @@ object UniqueTriggerActivation {
val unit = ruleSet.units[unitName] val unit = ruleSet.units[unitName]
if ((chosenCity == null && tile == null) if ((chosenCity == null && tile == null)
|| unit == null || unit == null
|| unit.hasUnique(UniqueType.FoundCity) && civInfo.isOneCityChallenger()) || unit.isCityFounder() && civInfo.isOneCityChallenger())
return false return false
val limit = unit.getMatchingUniques(UniqueType.MaxNumberBuildable) val limit = unit.getMatchingUniques(UniqueType.MaxNumberBuildable)
@ -83,7 +83,7 @@ object UniqueTriggerActivation {
UniqueType.OneTimeAmountFreeUnits -> { UniqueType.OneTimeAmountFreeUnits -> {
val unitName = unique.params[1] val unitName = unique.params[1]
val unit = ruleSet.units[unitName] val unit = ruleSet.units[unitName]
if ((chosenCity == null && tile == null) || unit == null || (unit.hasUnique(UniqueType.FoundCity) && civInfo.isOneCityChallenger())) if ((chosenCity == null && tile == null) || unit == null || (unit.isCityFounder() && civInfo.isOneCityChallenger()))
return false return false
val limit = unit.getMatchingUniques(UniqueType.MaxNumberBuildable) val limit = unit.getMatchingUniques(UniqueType.MaxNumberBuildable)
@ -118,7 +118,7 @@ object UniqueTriggerActivation {
} }
UniqueType.OneTimeFreeUnitRuins -> { UniqueType.OneTimeFreeUnitRuins -> {
var unit = civInfo.getEquivalentUnit(unique.params[0]) var unit = civInfo.getEquivalentUnit(unique.params[0])
if ( unit.hasUnique(UniqueType.FoundCity) && civInfo.isOneCityChallenger()) { if ( unit.isCityFounder() && civInfo.isOneCityChallenger()) {
val replacementUnit = ruleSet.units.values val replacementUnit = ruleSet.units.values
.firstOrNull { .firstOrNull {
it.getMatchingUniques(UniqueType.BuildImprovements) it.getMatchingUniques(UniqueType.BuildImprovements)

View File

@ -215,7 +215,7 @@ class BaseUnit : RulesetObject(), INonPerpetualConstruction {
//movement penalty //movement penalty
if (boughtWith != null && !civInfo.gameInfo.gameParameters.godMode && !unit.hasUnique(UniqueType.MoveImmediatelyOnceBought)) if (boughtWith != null && !civInfo.gameInfo.gameParameters.godMode && !unit.hasUnique(UniqueType.MoveImmediatelyOnceBought))
unit.currentMovement = 0f unit.currentMovement = 0f
if (this.isCivilian()) return true // tiny optimization makes save files a few bytes smaller if (this.isCivilian()) return true // tiny optimization makes save files a few bytes smaller
addConstructionBonuses(unit, cityConstructions) addConstructionBonuses(unit, cityConstructions)
@ -300,6 +300,10 @@ class BaseUnit : RulesetObject(), INonPerpetualConstruction {
} }
} }
/** Determine whether this is a City-founding unit - abstract, **without any game context**.
* Use other methods for MapUnits or when there is a better StateForConditionals available. */
fun isCityFounder() = hasUnique(UniqueType.FoundCity, StateForConditionals.IgnoreConditionals)
fun isGreatPerson() = getMatchingUniques(UniqueType.GreatPerson).any() fun isGreatPerson() = getMatchingUniques(UniqueType.GreatPerson).any()
fun isGreatPersonOfType(type: String) = getMatchingUniques(UniqueType.GreatPerson).any { it.params[0] == type } fun isGreatPersonOfType(type: String) = getMatchingUniques(UniqueType.GreatPerson).any { it.params[0] == type }

View File

@ -173,7 +173,7 @@ class RulesetValidator(val ruleset: Ruleset) {
checkUniques(ruleset.globalUniques, lines, rulesetSpecific, tryFixUnknownUniques) checkUniques(ruleset.globalUniques, lines, rulesetSpecific, tryFixUnknownUniques)
if (ruleset.units.values.none { it.hasUnique(UniqueType.FoundCity, StateForConditionals.IgnoreConditionals) }) if (ruleset.units.values.none { it.isCityFounder() })
lines += "No city-founding units in ruleset!" lines += "No city-founding units in ruleset!"
for (unit in ruleset.units.values) { for (unit in ruleset.units.values) {
@ -348,7 +348,7 @@ class RulesetValidator(val ruleset: Ruleset) {
lines += "Nonexistent building $building built by settlers when starting in ${era.name}" lines += "Nonexistent building $building built by settlers when starting in ${era.name}"
// todo the whole 'starting unit' thing needs to be redone, there's no reason we can't have a single list containing all the starting units. // todo the whole 'starting unit' thing needs to be redone, there's no reason we can't have a single list containing all the starting units.
if (era.startingSettlerUnit !in ruleset.units if (era.startingSettlerUnit !in ruleset.units
&& ruleset.units.values.none { it.hasUnique(UniqueType.FoundCity) }) && ruleset.units.values.none { it.isCityFounder() })
lines += "Nonexistent unit ${era.startingSettlerUnit} marked as starting unit when starting in ${era.name}" lines += "Nonexistent unit ${era.startingSettlerUnit} marked as starting unit when starting in ${era.name}"
if (era.startingWorkerCount != 0 && era.startingWorkerUnit !in ruleset.units if (era.startingWorkerCount != 0 && era.startingWorkerUnit !in ruleset.units
&& ruleset.units.values.none { it.hasUnique(UniqueType.BuildImprovements) }) && ruleset.units.values.none { it.hasUnique(UniqueType.BuildImprovements) })