Merge branch 'yairm210:master' into updated-so-you-can-build-naval-unit-on-water-tile

This commit is contained in:
General_E 2025-08-03 12:46:13 +02:00 committed by GitHub
commit 8b37ba8182
No known key found for this signature in database
GPG Key ID: B5690EEEBB952194
11 changed files with 52 additions and 94 deletions

View File

@ -4,8 +4,8 @@ package com.unciv.build
object BuildConfig { object BuildConfig {
const val kotlinVersion = "2.1.20" const val kotlinVersion = "2.1.20"
const val appName = "Unciv" const val appName = "Unciv"
const val appCodeNumber = 1151 const val appCodeNumber = 1152
const val appVersion = "4.17.11" const val appVersion = "4.17.11-patch1"
const val gdxVersion = "1.13.1" const val gdxVersion = "1.13.1"
const val ktorVersion = "2.3.13" const val ktorVersion = "2.3.13"

View File

@ -487,7 +487,7 @@ open class UncivGame(val isConsoleMode: Boolean = false) : Game(), PlatformSpeci
companion object { companion object {
//region AUTOMATICALLY GENERATED VERSION DATA - DO NOT CHANGE THIS REGION, INCLUDING THIS COMMENT //region AUTOMATICALLY GENERATED VERSION DATA - DO NOT CHANGE THIS REGION, INCLUDING THIS COMMENT
val VERSION = Version("4.17.11", 1151) val VERSION = Version("4.17.11-patch1", 1152)
//endregion //endregion
/** Global reference to the one Gdx.Game instance created by the platform launchers - do not use without checking [isCurrentInitialized] first. */ /** Global reference to the one Gdx.Game instance created by the platform launchers - do not use without checking [isCurrentInitialized] first. */

View File

@ -559,7 +559,7 @@ class CityStateFunctions(val civInfo: Civilization) {
.filter { !it.hasUnique(UniqueType.ResearchableMultipleTimes) && civInfo.tech.canBeResearched(it.name) } .filter { !it.hasUnique(UniqueType.ResearchableMultipleTimes) && civInfo.tech.canBeResearched(it.name) }
for (tech in researchableTechs) { for (tech in researchableTechs) {
val aliveMajorCivs = civInfo.gameInfo.getAliveMajorCivs() val aliveMajorCivs = civInfo.gameInfo.getAliveMajorCivs()
if (aliveMajorCivs.count { it.tech.isResearched(tech.name) } >= aliveMajorCivs.size / 2) if (aliveMajorCivs.count { it.tech.isResearched(tech.name) } > aliveMajorCivs.size / 2)
civInfo.tech.addTechnology(tech.name) civInfo.tech.addTechnology(tech.name)
} }
return return

View File

@ -19,7 +19,6 @@ import com.unciv.logic.map.mapgenerator.MapResourceSetting
import com.unciv.logic.map.mapunit.MapUnit import com.unciv.logic.map.mapunit.MapUnit
import com.unciv.logic.map.mapunit.UnitTurnManager import com.unciv.logic.map.mapunit.UnitTurnManager
import com.unciv.logic.map.mapunit.movement.UnitMovement import com.unciv.logic.map.mapunit.movement.UnitMovement
import com.unciv.models.UnitAction
import com.unciv.models.ruleset.Ruleset import com.unciv.models.ruleset.Ruleset
import com.unciv.models.ruleset.tile.ResourceType import com.unciv.models.ruleset.tile.ResourceType
import com.unciv.models.ruleset.tile.Terrain import com.unciv.models.ruleset.tile.Terrain
@ -631,28 +630,13 @@ class Tile : IsPartOfGameInfoSerialization, Json.Serializable {
return min(distance, wrappedDistance).toInt() return min(distance, wrappedDistance).toInt()
} }
fun canBeSettled(unitCanFoundUnique: Unique?=null): Boolean { @Readonly
fun canBeSettled(): Boolean {
val modConstants = tileMap.gameInfo.ruleset.modOptions.constants val modConstants = tileMap.gameInfo.ruleset.modOptions.constants
var addedDistanceBeweenContinents: Int
var canSettleInTileWithUnique = false
if (unitCanFoundUnique != null) {
canSettleInTileWithUnique = (isWater || isImpassible()) &&
unitCanFoundUnique.getModifiers(UniqueType.ConditionalInTiles).none{
matchesFilter(it.params[0])
}
}
/*
Putting the ! to make sure the player/Ai doesn't place cities too near each other.
Because when .none return False when one element has a match.
*/
addedDistanceBeweenContinents = if (!canSettleInTileWithUnique) 1 else 0
return when { return when {
canSettleInTileWithUnique -> false isWater || isImpassible() -> false
getTilesInDistance(modConstants.minimalCityDistanceOnDifferentContinents+ getTilesInDistance(modConstants.minimalCityDistanceOnDifferentContinents)
addedDistanceBeweenContinents)
.any { it.isCityCenter() && it.getContinent() != getContinent() } -> false .any { it.isCityCenter() && it.getContinent() != getContinent() } -> false
getTilesInDistance(modConstants.minimalCityDistance) getTilesInDistance(modConstants.minimalCityDistance)
.any { it.isCityCenter() && it.getContinent() == getContinent() } -> false .any { it.isCityCenter() && it.getContinent() == getContinent() } -> false

View File

@ -291,12 +291,11 @@ class Ruleset {
personalities.clear() personalities.clear()
events.clear() events.clear()
} }
@Readonly fun allRulesetObjects(): Sequence<IRulesetObject> = RulesetFile.entries.asSequence().flatMap { it.getRulesetObjects(this) } @Readonly fun allRulesetObjects(): Sequence<IRulesetObject> = RulesetFile.entries.asSequence().flatMap { it.getRulesetObjects(this) }
@Readonly fun allUniques(): Sequence<Unique> = RulesetFile.entries.asSequence().flatMap { it.getUniques(this) } @Readonly fun allUniques(): Sequence<Unique> = RulesetFile.entries.asSequence().flatMap { it.getUniques(this) }
@Readonly fun allICivilopediaText(): Sequence<ICivilopediaText> = allRulesetObjects() + events.values.flatMap { it.choices } @Readonly fun allICivilopediaText(): Sequence<ICivilopediaText> = allRulesetObjects() + events.values.flatMap { it.choices }
fun load(folderHandle: FileHandle) { fun load(folderHandle: FileHandle) {
// Note: Most files are loaded using createHashmap, which sets originRuleset automatically. // Note: Most files are loaded using createHashmap, which sets originRuleset automatically.
// For other files containing IRulesetObject's we'll have to remember to do so manually - e.g. Tech. // For other files containing IRulesetObject's we'll have to remember to do so manually - e.g. Tech.

View File

@ -187,7 +187,6 @@ class Terrain : RulesetStatsObject() {
type.name -> true type.name -> true
"Natural Wonder" -> type == TerrainType.NaturalWonder "Natural Wonder" -> type == TerrainType.NaturalWonder
"Terrain Feature" -> type == TerrainType.TerrainFeature "Terrain Feature" -> type == TerrainType.TerrainFeature
"Impassable" -> impassable
else -> false else -> false
} }

View File

@ -805,8 +805,7 @@ enum class UniqueType(
/////// tile conditionals /////// tile conditionals
ConditionalNeighborTiles("with [nonNegativeAmount] to [nonNegativeAmount] neighboring [tileFilter] tiles", UniqueTarget.Conditional), ConditionalNeighborTiles("with [nonNegativeAmount] to [nonNegativeAmount] neighboring [tileFilter] tiles", UniqueTarget.Conditional),
ConditionalInTiles("in [tileFilter] tiles", UniqueTarget.Conditional, ConditionalInTiles("in [tileFilter] tiles", UniqueTarget.Conditional),
docDescription = "Can be used with FoundCity and FoundPuppetCity to only found cities in Water/Impassible tiles."),
ConditionalInTilesNot("in tiles without [tileFilter]", UniqueTarget.Conditional), ConditionalInTilesNot("in tiles without [tileFilter]", UniqueTarget.Conditional),
ConditionalNearTiles("within [positiveAmount] tiles of a [tileFilter]", UniqueTarget.Conditional), ConditionalNearTiles("within [positiveAmount] tiles of a [tileFilter]", UniqueTarget.Conditional),

View File

@ -15,8 +15,6 @@ import com.unciv.models.ruleset.unique.UniqueParameterType
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.models.ruleset.unique.expressions.Expressions import com.unciv.models.ruleset.unique.expressions.Expressions
import yairm210.purity.annotations.Cache
import yairm210.purity.annotations.LocalState
import yairm210.purity.annotations.Readonly import yairm210.purity.annotations.Readonly
class UniqueValidator(val ruleset: Ruleset) { class UniqueValidator(val ruleset: Ruleset) {
@ -66,7 +64,7 @@ class UniqueValidator(val ruleset: Ruleset) {
UniqueType.ConditionalNotAdjacentTo UniqueType.ConditionalNotAdjacentTo
) )
@Readonly @Readonly @Suppress("purity")
fun checkUnique( fun checkUnique(
unique: Unique, unique: Unique,
tryFixUnknownUniques: Boolean, tryFixUnknownUniques: Boolean,
@ -76,7 +74,7 @@ class UniqueValidator(val ruleset: Ruleset) {
val prefix by lazy { getUniqueContainerPrefix(uniqueContainer) + "\"${unique.text}\"" } val prefix by lazy { getUniqueContainerPrefix(uniqueContainer) + "\"${unique.text}\"" }
if (unique.type == null) return checkUntypedUnique(unique, tryFixUnknownUniques, uniqueContainer, prefix, reportRulesetSpecificErrors) if (unique.type == null) return checkUntypedUnique(unique, tryFixUnknownUniques, uniqueContainer, prefix, reportRulesetSpecificErrors)
@LocalState val rulesetErrors = RulesetErrorList(ruleset) val rulesetErrors = RulesetErrorList(ruleset)
if (uniqueContainer != null && if (uniqueContainer != null &&
!(unique.type.canAcceptUniqueTarget(uniqueContainer.getUniqueTarget()) || !(unique.type.canAcceptUniqueTarget(uniqueContainer.getUniqueTarget()) ||
@ -109,14 +107,14 @@ class UniqueValidator(val ruleset: Ruleset) {
complianceError.errorSeverity.getRulesetErrorSeverity(), uniqueContainer, unique complianceError.errorSeverity.getRulesetErrorSeverity(), uniqueContainer, unique
) )
rulesetErrors += getExpressionParseErrors(complianceError, uniqueContainer, unique) addExpressionParseErrors(complianceError, rulesetErrors, uniqueContainer, unique)
} }
for (conditional in unique.modifiers) { for (conditional in unique.modifiers) {
rulesetErrors += getConditionalErrors(conditional, prefix, unique, uniqueContainer, reportRulesetSpecificErrors) addConditionalErrors(conditional, rulesetErrors, prefix, unique, uniqueContainer, reportRulesetSpecificErrors)
} }
rulesetErrors += getUniqueTypeSpecificErrors(prefix, unique, uniqueContainer, reportRulesetSpecificErrors) addUniqueTypeSpecificErrors(rulesetErrors, prefix, unique, uniqueContainer, reportRulesetSpecificErrors)
val conditionals = unique.modifiers.filter { it.type?.canAcceptUniqueTarget(UniqueTarget.Conditional) == true } val conditionals = unique.modifiers.filter { it.type?.canAcceptUniqueTarget(UniqueTarget.Conditional) == true }
if (conditionals.size > 1){ if (conditionals.size > 1){
@ -146,19 +144,18 @@ class UniqueValidator(val ruleset: Ruleset) {
if (reportRulesetSpecificErrors) if (reportRulesetSpecificErrors)
// If we don't filter these messages will be listed twice as this function is called twice on most objects // If we don't filter these messages will be listed twice as this function is called twice on most objects
// The tests are RulesetInvariant in nature, but RulesetSpecific is called for _all_ objects, invariant is not. // The tests are RulesetInvariant in nature, but RulesetSpecific is called for _all_ objects, invariant is not.
rulesetErrors += addDeprecationAnnotationErrors(unique, prefix, uniqueContainer) addDeprecationAnnotationErrors(unique, prefix, rulesetErrors, uniqueContainer)
return rulesetErrors return rulesetErrors
} }
@Readonly private fun addExpressionParseErrors(
private fun getExpressionParseErrors(
complianceError: UniqueComplianceError, complianceError: UniqueComplianceError,
rulesetErrors: RulesetErrorList,
uniqueContainer: IHasUniques?, uniqueContainer: IHasUniques?,
unique: Unique unique: Unique
): RulesetErrorList { ) {
@LocalState val rulesetErrors = RulesetErrorList(ruleset) if (!complianceError.acceptableParameterTypes.contains(UniqueParameterType.Countable)) return
if (!complianceError.acceptableParameterTypes.contains(UniqueParameterType.Countable)) return rulesetErrors
val parseError = Expressions.getParsingError(complianceError.parameterName) val parseError = Expressions.getParsingError(complianceError.parameterName)
if (parseError != null) { if (parseError != null) {
@ -170,7 +167,7 @@ class UniqueValidator(val ruleset: Ruleset) {
val text = "\"${complianceError.parameterName}\" could not be parsed as an expression due to:" + val text = "\"${complianceError.parameterName}\" could not be parsed as an expression due to:" +
" ${parseError.message}. \n$parameterWithErrorLocationMarked" " ${parseError.message}. \n$parameterWithErrorLocationMarked"
rulesetErrors.add(text, RulesetErrorSeverity.WarningOptionsOnly, uniqueContainer, unique) rulesetErrors.add(text, RulesetErrorSeverity.WarningOptionsOnly, uniqueContainer, unique)
return rulesetErrors return
} }
val countableErrors = Expressions.getCountableErrors(complianceError.parameterName, ruleset) val countableErrors = Expressions.getCountableErrors(complianceError.parameterName, ruleset)
@ -179,7 +176,6 @@ class UniqueValidator(val ruleset: Ruleset) {
" ${countableErrors.joinToString(", ")}" " ${countableErrors.joinToString(", ")}"
rulesetErrors.add(text, RulesetErrorSeverity.WarningOptionsOnly, uniqueContainer, unique) rulesetErrors.add(text, RulesetErrorSeverity.WarningOptionsOnly, uniqueContainer, unique)
} }
return rulesetErrors
} }
private val resourceUniques = setOf(UniqueType.ProvidesResources, UniqueType.ConsumesResources, private val resourceUniques = setOf(UniqueType.ProvidesResources, UniqueType.ConsumesResources,
@ -192,37 +188,21 @@ class UniqueValidator(val ruleset: Ruleset) {
UniqueType.ConditionalWhenBelowAmountStatResource, UniqueType.ConditionalWhenBelowAmountStatResource,
) )
@Readonly private fun addConditionalErrors(
private fun getUniqueTypeSpecificErrors(
prefix: String, unique: Unique, uniqueContainer: IHasUniques?, reportRulesetSpecificErrors: Boolean
): RulesetErrorList {
@LocalState val rulesetErrors = RulesetErrorList(ruleset)
when (unique.type) {
UniqueType.RuinsUpgrade -> {
if (reportRulesetSpecificErrors && !anyAncientRuins)
rulesetErrors.add("$prefix is pointless - there are no ancient ruins", RulesetErrorSeverity.Warning, uniqueContainer, unique)
}
else -> {}
}
return rulesetErrors
}
@Readonly
private fun getConditionalErrors(
conditional: Unique, conditional: Unique,
rulesetErrors: RulesetErrorList,
prefix: String, prefix: String,
unique: Unique, unique: Unique,
uniqueContainer: IHasUniques?, uniqueContainer: IHasUniques?,
reportRulesetSpecificErrors: Boolean reportRulesetSpecificErrors: Boolean
): RulesetErrorList { ) {
@LocalState val rulesetErrors = RulesetErrorList(ruleset)
if (unique.hasFlag(UniqueFlag.NoConditionals)) { if (unique.hasFlag(UniqueFlag.NoConditionals)) {
rulesetErrors.add( rulesetErrors.add(
"$prefix contains the conditional \"${conditional.text}\"," + "$prefix contains the conditional \"${conditional.text}\"," +
" but the unique does not accept conditionals!", " but the unique does not accept conditionals!",
RulesetErrorSeverity.Error, uniqueContainer, unique RulesetErrorSeverity.Error, uniqueContainer, unique
) )
return rulesetErrors return
} }
if (conditional.type == null) { if (conditional.type == null) {
@ -241,7 +221,7 @@ class UniqueValidator(val ruleset: Ruleset) {
text, text,
RulesetErrorSeverity.Warning, uniqueContainer, unique RulesetErrorSeverity.Warning, uniqueContainer, unique
) )
return rulesetErrors return
} }
if (conditional.type.targetTypes.none { it.modifierType != UniqueTarget.ModifierType.None }) if (conditional.type.targetTypes.none { it.modifierType != UniqueTarget.ModifierType.None })
@ -296,21 +276,30 @@ class UniqueValidator(val ruleset: Ruleset) {
complianceError.errorSeverity.getRulesetErrorSeverity(), uniqueContainer, unique complianceError.errorSeverity.getRulesetErrorSeverity(), uniqueContainer, unique
) )
rulesetErrors += getExpressionParseErrors(complianceError, uniqueContainer, unique) addExpressionParseErrors(complianceError, rulesetErrors, uniqueContainer, unique)
} }
addDeprecationAnnotationErrors(conditional, "$prefix contains modifier \"${conditional.text}\" which", uniqueContainer) addDeprecationAnnotationErrors(conditional, "$prefix contains modifier \"${conditional.text}\" which", rulesetErrors, uniqueContainer)
}
return rulesetErrors
private fun addUniqueTypeSpecificErrors(
rulesetErrors: RulesetErrorList, prefix: String, unique: Unique, uniqueContainer: IHasUniques?, reportRulesetSpecificErrors: Boolean
) {
when(unique.type) {
UniqueType.RuinsUpgrade -> {
if (reportRulesetSpecificErrors && !anyAncientRuins)
rulesetErrors.add("$prefix is pointless - there are no ancient ruins", RulesetErrorSeverity.Warning, uniqueContainer, unique)
}
else -> return
}
} }
@Readonly
private fun addDeprecationAnnotationErrors( private fun addDeprecationAnnotationErrors(
unique: Unique, unique: Unique,
prefix: String, prefix: String,
rulesetErrors: RulesetErrorList,
uniqueContainer: IHasUniques? uniqueContainer: IHasUniques?
): RulesetErrorList { ) {
@LocalState val rulesetErrors = RulesetErrorList(ruleset)
val deprecationAnnotation = unique.getDeprecationAnnotation() val deprecationAnnotation = unique.getDeprecationAnnotation()
if (deprecationAnnotation != null) { if (deprecationAnnotation != null) {
val replacementUniqueText = unique.getReplacementText(ruleset) val replacementUniqueText = unique.getReplacementText(ruleset)
@ -325,13 +314,12 @@ class UniqueValidator(val ruleset: Ruleset) {
} }
// Check for deprecated Countables // Check for deprecated Countables
if (unique.type == null) return rulesetErrors if (unique.type == null) return
val countables = val countables =
unique.type.parameterTypeMap.withIndex() unique.type.parameterTypeMap.withIndex()
.filter { UniqueParameterType.Countable in it.value } .filter { UniqueParameterType.Countable in it.value }
.map { unique.params[it.index] } .map { unique.params[it.index] }
.mapNotNull { Countables.getMatching(it, ruleset) } .mapNotNull { Countables.getMatching(it, ruleset) }
for (countable in countables) { for (countable in countables) {
val deprecation = countable.getDeprecationAnnotation() ?: continue val deprecation = countable.getDeprecationAnnotation() ?: continue
// This is less flexible than unique.getReplacementText(ruleset) // This is less flexible than unique.getReplacementText(ruleset)
@ -343,18 +331,14 @@ class UniqueValidator(val ruleset: Ruleset) {
else RulesetErrorSeverity.ErrorOptionsOnly // User visible in new game and red in options else RulesetErrorSeverity.ErrorOptionsOnly // User visible in new game and red in options
rulesetErrors.add(text, severity, uniqueContainer, unique) rulesetErrors.add(text, severity, uniqueContainer, unique)
} }
return rulesetErrors
} }
/** Maps uncompliant parameters to their required types */ /** Maps uncompliant parameters to their required types */
@Readonly
private fun getComplianceErrors( private fun getComplianceErrors(
unique: Unique, unique: Unique,
): List<UniqueComplianceError> { ): List<UniqueComplianceError> {
if (unique.type == null) return emptyList() if (unique.type == null) return emptyList()
@LocalState val errorList = ArrayList<UniqueComplianceError>() val errorList = ArrayList<UniqueComplianceError>()
for ((index, param) in unique.params.withIndex()) { for ((index, param) in unique.params.withIndex()) {
// Trying to catch the error at #11404 // Trying to catch the error at #11404
if (unique.type.parameterTypeMap.size != unique.params.size) { if (unique.type.parameterTypeMap.size != unique.params.size) {
@ -379,13 +363,11 @@ class UniqueValidator(val ruleset: Ruleset) {
return errorList return errorList
} }
@Cache private val paramTypeErrorSeverityCache = HashMap<UniqueParameterType, HashMap<String, UniqueType.UniqueParameterErrorSeverity?>>() private val paramTypeErrorSeverityCache = HashMap<UniqueParameterType, HashMap<String, UniqueType.UniqueParameterErrorSeverity?>>()
@Readonly
private fun getParamTypeErrorSeverityCached(uniqueParameterType: UniqueParameterType, param: String): UniqueType.UniqueParameterErrorSeverity? { private fun getParamTypeErrorSeverityCached(uniqueParameterType: UniqueParameterType, param: String): UniqueType.UniqueParameterErrorSeverity? {
if (!paramTypeErrorSeverityCache.containsKey(uniqueParameterType)) if (!paramTypeErrorSeverityCache.containsKey(uniqueParameterType))
paramTypeErrorSeverityCache[uniqueParameterType] = hashMapOf() paramTypeErrorSeverityCache[uniqueParameterType] = hashMapOf()
val uniqueParamCache = paramTypeErrorSeverityCache[uniqueParameterType]!!
@LocalState val uniqueParamCache = paramTypeErrorSeverityCache[uniqueParameterType]!!
if (uniqueParamCache.containsKey(param)) return uniqueParamCache[param] if (uniqueParamCache.containsKey(param)) return uniqueParamCache[param]
@ -394,7 +376,6 @@ class UniqueValidator(val ruleset: Ruleset) {
return severity return severity
} }
@Readonly
private fun checkUntypedUnique( private fun checkUntypedUnique(
unique: Unique, unique: Unique,
tryFixUnknownUniques: Boolean, tryFixUnknownUniques: Boolean,
@ -410,7 +391,7 @@ class UniqueValidator(val ruleset: Ruleset) {
) )
// Support purely filtering Uniques without actual implementation // Support purely filtering Uniques without actual implementation
if (isFilteringUniqueAllowed(unique, reportRulesetSpecificErrors)) return RulesetErrorList(ruleset) if (isFilteringUniqueAllowed(unique, reportRulesetSpecificErrors)) return RulesetErrorList()
if (tryFixUnknownUniques) { if (tryFixUnknownUniques) {
val fixes = tryFixUnknownUnique(unique, uniqueContainer, prefix) val fixes = tryFixUnknownUnique(unique, uniqueContainer, prefix)
@ -424,7 +405,6 @@ class UniqueValidator(val ruleset: Ruleset) {
) )
} }
@Readonly
private fun isFilteringUniqueAllowed(unique: Unique, reportRulesetSpecificErrors: Boolean): Boolean { private fun isFilteringUniqueAllowed(unique: Unique, reportRulesetSpecificErrors: Boolean): Boolean {
// Isolate this decision, to allow easy change of approach // Isolate this decision, to allow easy change of approach
// This says: Must have no conditionals or parameters, and is used in any "filtering" parameter of another Unique // This says: Must have no conditionals or parameters, and is used in any "filtering" parameter of another Unique
@ -433,7 +413,6 @@ class UniqueValidator(val ruleset: Ruleset) {
return unique.text in allUniqueParameters // referenced at least once from elsewhere return unique.text in allUniqueParameters // referenced at least once from elsewhere
} }
@Readonly
private fun tryFixUnknownUnique(unique: Unique, uniqueContainer: IHasUniques?, prefix: String): RulesetErrorList { private fun tryFixUnknownUnique(unique: Unique, uniqueContainer: IHasUniques?, prefix: String): RulesetErrorList {
val similarUniques = UniqueType.entries.filter { val similarUniques = UniqueType.entries.filter {
getRelativeTextDistance( getRelativeTextDistance(
@ -464,14 +443,13 @@ class UniqueValidator(val ruleset: Ruleset) {
}.prependIndent("\t") }.prependIndent("\t")
RulesetErrorList.of(text, RulesetErrorSeverity.OK, ruleset, uniqueContainer, unique) RulesetErrorList.of(text, RulesetErrorSeverity.OK, ruleset, uniqueContainer, unique)
} }
else -> RulesetErrorList(ruleset) else -> RulesetErrorList()
} }
} }
companion object { companion object {
const val whichDoesNotFitParameterType = "which does not fit parameter type" const val whichDoesNotFitParameterType = "which does not fit parameter type"
@Readonly
internal fun getUniqueContainerPrefix(uniqueContainer: IHasUniques?) = internal fun getUniqueContainerPrefix(uniqueContainer: IHasUniques?) =
(if (uniqueContainer is IRulesetObject) "${uniqueContainer.originRuleset}: " else "") + (if (uniqueContainer is IRulesetObject) "${uniqueContainer.originRuleset}: " else "") +
(if (uniqueContainer == null) "The" else "(${uniqueContainer.getUniqueTarget().name}) ${uniqueContainer.name}'s") + (if (uniqueContainer == null) "The" else "(${uniqueContainer.getUniqueTarget().name}) ${uniqueContainer.name}'s") +

View File

@ -45,11 +45,11 @@ object UnitActionsFromUniques {
UnitActionModifiers.getUsableUnitActionUniques(unit, UnitActionModifiers.getUsableUnitActionUniques(unit,
UniqueType.FoundPuppetCity).firstOrNull() ?: return null UniqueType.FoundPuppetCity).firstOrNull() ?: return null
if (tile.isWater || tile.isImpassible()) return null
// Spain should still be able to build Conquistadors in a one city challenge - but can't settle them // Spain should still be able to build Conquistadors in a one city challenge - but can't settle them
if (unit.civ.isOneCityChallenger() && unit.civ.hasEverOwnedOriginalCapital) return null if (unit.civ.isOneCityChallenger() && unit.civ.hasEverOwnedOriginalCapital) return null
if (!unit.hasMovement() || !tile.canBeSettled(unique)) if (!unit.hasMovement() || !tile.canBeSettled())
return UnitAction(UnitActionType.FoundCity, 80f, action = null) return UnitAction(UnitActionType.FoundCity, 80f, action = null)
val hasActionModifiers = unique.modifiers.any { it.type?.targetTypes?.contains( val hasActionModifiers = unique.modifiers.any { it.type?.targetTypes?.contains(

View File

@ -3535,8 +3535,6 @@ Simple unique parameters are explained by mouseover. Complex parameters are expl
Applicable to: Conditional Applicable to: Conditional
??? example "&lt;in [tileFilter] tiles&gt;" ??? example "&lt;in [tileFilter] tiles&gt;"
Can be used with FoundCity and FoundPuppetCity to only found cities in Water/Impassible tiles.
Example: "&lt;in [Farm] tiles&gt;" Example: "&lt;in [Farm] tiles&gt;"
Applicable to: Conditional Applicable to: Conditional

View File

@ -23,6 +23,7 @@ theme:
repo_name: yairm210/unciv repo_name: yairm210/unciv
repo_url: https://github.com/yairm210/unciv repo_url: https://github.com/yairm210/unciv
site_url: https://yairm210.github.io/Unciv
markdown_extensions: markdown_extensions:
# For adminitions # For adminitions