From 4df0d5871ff140beac8b6d9aa48d94568961235b Mon Sep 17 00:00:00 2001 From: Rob Loach Date: Wed, 27 Aug 2025 06:03:25 -0400 Subject: [PATCH 1/5] Add unique to get resources from a percent of stat (#13858) * Add unique to get resources from a percent of stat yield * Remove 'output' * Update * Apply suggestion from @RobLoach * Fix filter naming * Switch from tileFilter to improvementFilter * Result afterwards * Apply suggestion from @RobLoach * Apply suggestion from @RobLoach * Add a getWorkedTiles() function * Apply suggestion from @RobLoach * Remove the need for a result variable * Use Doubles instead of Float-math --- .../automation/city/ConstructionAutomation.kt | 1 + core/src/com/unciv/logic/city/City.kt | 2 +- .../src/com/unciv/logic/city/CityResources.kt | 60 ++++++++++++------- .../unciv/models/ruleset/tile/TileResource.kt | 6 +- .../ruleset/unique/UniqueTriggerActivation.kt | 2 +- .../unciv/models/ruleset/unique/UniqueType.kt | 1 + .../ruleset/validation/UniqueValidator.kt | 2 +- docs/Modders/uniques.md | 5 ++ tests/src/com/unciv/uniques/ResourceTests.kt | 20 +++++++ 9 files changed, 73 insertions(+), 26 deletions(-) diff --git a/core/src/com/unciv/logic/automation/city/ConstructionAutomation.kt b/core/src/com/unciv/logic/automation/city/ConstructionAutomation.kt index 34c46112d2..aa668668f1 100644 --- a/core/src/com/unciv/logic/automation/city/ConstructionAutomation.kt +++ b/core/src/com/unciv/logic/automation/city/ConstructionAutomation.kt @@ -297,6 +297,7 @@ class ConstructionAutomation(val cityConstructions: CityConstructions) { } else value += when { building.hasUnique(UniqueType.CreatesOneImprovement) -> 5f // District-type buildings, should be weighed by the stats (incl. adjacencies) of the improvement building.hasUnique(UniqueType.ProvidesResources) -> 2f // Should be weighed by how much we need the resources + building.hasUnique(UniqueType.StatPercentFromObjectToResource) -> 1.5f // Should be weighed by the amount of active improvementFilter/buildingFilter in the city else -> 0f } return value diff --git a/core/src/com/unciv/logic/city/City.kt b/core/src/com/unciv/logic/city/City.kt index c9e6da9299..bf85b3e09c 100644 --- a/core/src/com/unciv/logic/city/City.kt +++ b/core/src/com/unciv/logic/city/City.kt @@ -170,9 +170,9 @@ class City : IsPartOfGameInfoSerialization, INamed { @Readonly fun getCenterTileOrNull(): Tile? = if (::centerTile.isInitialized) centerTile else null @Readonly fun getTiles(): Sequence = tiles.asSequence().map { tileMap[it] } @Readonly fun getWorkableTiles() = tilesInRange.asSequence().filter { it.getOwner() == civ } + @Readonly fun getWorkedTiles(): Sequence = workedTiles.asSequence().map { tileMap[it] } @Readonly fun isWorked(tile: Tile) = workedTiles.contains(tile.position) - @Readonly fun isCapital(): Boolean = cityConstructions.builtBuildingUniqueMap.hasUnique(UniqueType.IndicatesCapital, state) @Readonly fun isCoastal(): Boolean = centerTile.isCoastalTile() diff --git a/core/src/com/unciv/logic/city/CityResources.kt b/core/src/com/unciv/logic/city/CityResources.kt index 6abb211c7c..6b89ec0c9f 100644 --- a/core/src/com/unciv/logic/city/CityResources.kt +++ b/core/src/com/unciv/logic/city/CityResources.kt @@ -1,12 +1,14 @@ package com.unciv.logic.city import com.unciv.logic.map.tile.Tile +import com.unciv.models.stats.Stat import com.unciv.models.ruleset.tile.ResourceSupplyList import com.unciv.models.ruleset.tile.ResourceType import com.unciv.models.ruleset.unique.GameContext import com.unciv.models.ruleset.unique.UniqueType import yairm210.purity.annotations.LocalState import yairm210.purity.annotations.Readonly +import com.unciv.models.ruleset.unique.UniqueParameterType object CityResources { @@ -14,7 +16,7 @@ object CityResources { @Readonly fun getResourcesGeneratedByCity(city: City, resourceModifiers: Map): ResourceSupplyList { @LocalState val cityResources = getResourcesGeneratedByCityNotIncludingBuildings(city, resourceModifiers) - cityResources += getCityResourcesGeneratedFromUniqueBuildings(city, resourceModifiers) + cityResources += getCityResourcesGeneratedFromUniques(city, resourceModifiers, false) return cityResources } @@ -30,7 +32,7 @@ object CityResources { // We can't use getResourcesGeneratedByCity directly, because that would include the resources generated by buildings - // which are part of the civ-wide uniques, so we'd be getting them twice! // This way we get them once, but it is ugly, I welcome other ideas :/ - cityResources.add(getCityResourcesFromCiv(city, resourceModifers)) + cityResources.add(getCityResourcesGeneratedFromUniques(city, resourceModifers, true)) cityResources.removeAll { !it.resource.isCityWide } @@ -56,20 +58,6 @@ object CityResources { return cityResources } - @Readonly - private fun getCityResourcesGeneratedFromUniqueBuildings(city: City, resourceModifer: Map): ResourceSupplyList { - val buildingResources = ResourceSupplyList() - for (unique in city.getMatchingUniques(UniqueType.ProvidesResources, city.state, false)) { // E.G "Provides [1] [Iron]" - val resource = city.getRuleset().tileResources[unique.params[1]] - ?: continue - buildingResources.add( - resource, unique.getSourceNameForUser(), - (unique.params[0].toFloat() * resourceModifer[resource.name]!!).toInt() - ) - } - return buildingResources - } - /** Gets the number of resources available to this city * Accommodates both city-wide and civ-wide resources */ @Readonly @@ -129,18 +117,46 @@ object CityResources { } @Readonly - private fun getCityResourcesFromCiv(city: City, resourceModifers: HashMap): ResourceSupplyList { - val resourceSupplyList = ResourceSupplyList() - // This includes the uniques from buildings, from this and all other cities - for (unique in city.getMatchingUniques(UniqueType.ProvidesResources, city.state)) { // E.G "Provides [1] [Iron]" + private fun getCityResourcesGeneratedFromUniques(city: City, resourceModifers: Map, includeCivUniques: Boolean = true): ResourceSupplyList { + val buildingResources = ResourceSupplyList() + for (unique in city.getMatchingUniques(UniqueType.ProvidesResources, city.state, includeCivUniques)) { // E.G "Provides [1] [Iron]" val resource = city.getRuleset().tileResources[unique.params[1]] ?: continue - resourceSupplyList.add( + buildingResources.add( resource, unique.getSourceNameForUser(), (unique.params[0].toFloat() * resourceModifers[resource.name]!!).toInt() ) } - return resourceSupplyList + + // StatPercentFromObjectToResource - Example: "[50]% of [Culture] from every [improvementFilter/buildingFilter] in the city added to [Iron]" + for (unique in city.getMatchingUniques(UniqueType.StatPercentFromObjectToResource, city.state, includeCivUniques)) { + val resource = city.getRuleset().tileResources[unique.params[3]] ?: continue + val stat = Stat.safeValueOf(unique.params[1]) ?: continue + val filter = unique.params[2] + var amount = 0.0 + + // Building Filter + if (UniqueParameterType.BuildingFilter.isKnownValue(filter, city.getRuleset())) { + amount += city.cityConstructions.getBuiltBuildings() + .filter { it.isStatRelated(stat) && it.matchesFilter(filter, city.state) } + .sumOf { it.getStats(city)[stat].toDouble() } + } + + // Improvement Filter + if (UniqueParameterType.ImprovementFilter.isKnownValue(filter, city.getRuleset())) { + amount += city.getWorkedTiles() + .mapNotNull { it.getUnpillagedTileImprovement() } + .filter { it[stat] > 0f && it.matchesFilter(filter, city.state) } + .sumOf { it[stat].toDouble() } + } + + if (amount > 0.0) { + amount *= unique.params[0].toDouble() / 100.0 * (resourceModifers[resource.name] ?: 1f).toDouble() + buildingResources.add(resource, unique.getSourceNameForUser(), amount.toInt()) + } + } + + return buildingResources } @Readonly diff --git a/core/src/com/unciv/models/ruleset/tile/TileResource.kt b/core/src/com/unciv/models/ruleset/tile/TileResource.kt index 39076b0e1b..6989c5eaa5 100644 --- a/core/src/com/unciv/models/ruleset/tile/TileResource.kt +++ b/core/src/com/unciv/models/ruleset/tile/TileResource.kt @@ -143,7 +143,11 @@ class TileResource : RulesetStatsObject(), GameResource { val buildingsThatProvideThis = ruleset.buildings.values .filter { building -> building.uniqueObjects.any { unique -> - unique.type == UniqueType.ProvidesResources && unique.params[1] == name + when (unique.type) { + UniqueType.ProvidesResources -> unique.params[1] == name + UniqueType.StatPercentFromObjectToResource -> unique.params[3] == name + else -> false + } } } if (buildingsThatProvideThis.isNotEmpty()) { diff --git a/core/src/com/unciv/models/ruleset/unique/UniqueTriggerActivation.kt b/core/src/com/unciv/models/ruleset/unique/UniqueTriggerActivation.kt index ad37199b3c..55beac4381 100644 --- a/core/src/com/unciv/models/ruleset/unique/UniqueTriggerActivation.kt +++ b/core/src/com/unciv/models/ruleset/unique/UniqueTriggerActivation.kt @@ -102,7 +102,7 @@ object UniqueTriggerActivation { if (timingConditional != null) { return { civInfo.temporaryUniques.add(TemporaryUnique(unique, timingConditional.params[0].toInt())) - if (unique.type in setOf(UniqueType.ProvidesResources, UniqueType.ConsumesResources)) + if (unique.type in setOf(UniqueType.ProvidesResources, UniqueType.ConsumesResources, UniqueType.StatPercentFromObjectToResource)) civInfo.cache.updateCivResources() true } diff --git a/core/src/com/unciv/models/ruleset/unique/UniqueType.kt b/core/src/com/unciv/models/ruleset/unique/UniqueType.kt index 600e957430..b4e0704def 100644 --- a/core/src/com/unciv/models/ruleset/unique/UniqueType.kt +++ b/core/src/com/unciv/models/ruleset/unique/UniqueType.kt @@ -47,6 +47,7 @@ enum class UniqueType( StatPercentBonus("[relativeAmount]% [stat]", UniqueTarget.Global, UniqueTarget.FollowerBelief), StatPercentBonusCities("[relativeAmount]% [stat] [cityFilter]", UniqueTarget.Global, UniqueTarget.FollowerBelief), StatPercentFromObject("[relativeAmount]% [stat] from every [tileFilter/buildingFilter]", UniqueTarget.Global, UniqueTarget.FollowerBelief), + StatPercentFromObjectToResource("[positiveAmount]% of [stat] from every [improvementFilter/buildingFilter] in the city added to [resource]", UniqueTarget.Building), AllStatsPercentFromObject("[relativeAmount]% Yield from every [tileFilter/buildingFilter]", UniqueTarget.Global, UniqueTarget.FollowerBelief), StatPercentFromReligionFollowers("[relativeAmount]% [stat] from every follower, up to [relativeAmount]%", UniqueTarget.FollowerBelief, UniqueTarget.FounderBelief), BonusStatsFromCityStates("[relativeAmount]% [stat] from City-States", UniqueTarget.Global), diff --git a/core/src/com/unciv/models/ruleset/validation/UniqueValidator.kt b/core/src/com/unciv/models/ruleset/validation/UniqueValidator.kt index 406cf529f4..ff3cfa0120 100644 --- a/core/src/com/unciv/models/ruleset/validation/UniqueValidator.kt +++ b/core/src/com/unciv/models/ruleset/validation/UniqueValidator.kt @@ -183,7 +183,7 @@ class UniqueValidator(val ruleset: Ruleset) { } private val resourceUniques = setOf(UniqueType.ProvidesResources, UniqueType.ConsumesResources, - UniqueType.PercentResourceProduction) + UniqueType.PercentResourceProduction, UniqueType.StatPercentFromObjectToResource) private val resourceConditionals = setOf( UniqueType.ConditionalWithResource, UniqueType.ConditionalWithoutResource, diff --git a/docs/Modders/uniques.md b/docs/Modders/uniques.md index 3bfc045905..280517fb68 100644 --- a/docs/Modders/uniques.md +++ b/docs/Modders/uniques.md @@ -1523,6 +1523,11 @@ Simple unique parameters are explained by mouseover. Complex parameters are expl Applicable to: Nation, Tech, Policy, FounderBelief, FollowerBelief, Building, Unit, UnitType, Promotion, Terrain, Improvement, Resource, Ruins, Speed, Difficulty, EventChoice ## Building uniques +??? example "[positiveAmount]% of [stat] from every [improvementFilter/buildingFilter] in the city added to [resource]" + Example: "[3]% of [Culture] from every [All Road] in the city added to [Iron]" + + Applicable to: Building + ??? example "Consumes [amount] [resource]" Example: "Consumes [3] [Iron]" diff --git a/tests/src/com/unciv/uniques/ResourceTests.kt b/tests/src/com/unciv/uniques/ResourceTests.kt index f16c998049..214ea82b30 100644 --- a/tests/src/com/unciv/uniques/ResourceTests.kt +++ b/tests/src/com/unciv/uniques/ResourceTests.kt @@ -166,6 +166,26 @@ class ResourceTests { assertEquals("4 Iron from Buildings", resources[0].toString()) } + @Test + fun `should handle StatPercentFromObjectToResource with a buildingFilter`() { + city.cityConstructions.addBuilding("Monument") + var building = game.createBuilding("[300]% of [Culture] from every [Monument] in the city added to [Iron]") + city.cityConstructions.addBuilding(building) + assertEquals(6, city.getAvailableResourceAmount("Iron")) // 2 Culture * 3 + } + + @Test + fun `should handle StatPercentFromObjectToResource with a improvementFilter`() { + val tile = game.tileMap[1,1] + tile.resource = "Wheat" + tile.resourceAmount = 1 + tile.setImprovement("Farm") + city.population.addPopulation(5) // Add population, since the tile needs to be worked + var building = game.createBuilding("[300]% of [Food] from every [Farm] in the city added to [Iron]") + city.cityConstructions.addBuilding(building) + assertEquals(3, city.getAvailableResourceAmount("Iron")) + } + @Test fun `should reduce resources due to buildings`() { // given From 33c4d9eb128d428b6179b63d1cff7b058363b69d Mon Sep 17 00:00:00 2001 From: yairm210 <8366208+yairm210@users.noreply.github.com> Date: Wed, 27 Aug 2025 10:03:36 +0000 Subject: [PATCH 2/5] 4.17.17-patch1 --- buildSrc/src/main/kotlin/BuildConfig.kt | 4 ++-- core/src/com/unciv/UncivGame.kt | 2 +- 2 files changed, 3 insertions(+), 3 deletions(-) diff --git a/buildSrc/src/main/kotlin/BuildConfig.kt b/buildSrc/src/main/kotlin/BuildConfig.kt index 31cac66e91..8ca7a2b6ef 100644 --- a/buildSrc/src/main/kotlin/BuildConfig.kt +++ b/buildSrc/src/main/kotlin/BuildConfig.kt @@ -3,7 +3,7 @@ package com.unciv.build object BuildConfig { const val appName = "Unciv" - const val appCodeNumber = 1158 - const val appVersion = "4.17.17" + const val appCodeNumber = 1159 + const val appVersion = "4.17.17-patch1" const val identifier = "com.unciv.app" } diff --git a/core/src/com/unciv/UncivGame.kt b/core/src/com/unciv/UncivGame.kt index d4976e7b96..a6401fe142 100644 --- a/core/src/com/unciv/UncivGame.kt +++ b/core/src/com/unciv/UncivGame.kt @@ -494,7 +494,7 @@ open class UncivGame(val isConsoleMode: Boolean = false) : Game(), PlatformSpeci companion object { //region AUTOMATICALLY GENERATED VERSION DATA - DO NOT CHANGE THIS REGION, INCLUDING THIS COMMENT - val VERSION = Version("4.17.17", 1158) + val VERSION = Version("4.17.17-patch1", 1159) //endregion /** Global reference to the one Gdx.Game instance created by the platform launchers - do not use without checking [isCurrentInitialized] first. */ From f9c15afbb0c76c8a2e7787c05ae60eb6f7c63f63 Mon Sep 17 00:00:00 2001 From: yairm210 Date: Wed, 27 Aug 2025 18:18:49 +0300 Subject: [PATCH 3/5] Resolved #13863 - Inquisitors disrupt religion in other civs as well --- .../unit/ReligiousUnitAutomation.kt | 21 ++++++++++++++----- .../city/managers/CityReligionManager.kt | 3 ++- 2 files changed, 18 insertions(+), 6 deletions(-) diff --git a/core/src/com/unciv/logic/automation/unit/ReligiousUnitAutomation.kt b/core/src/com/unciv/logic/automation/unit/ReligiousUnitAutomation.kt index e3bf43b9cd..6eebf17570 100644 --- a/core/src/com/unciv/logic/automation/unit/ReligiousUnitAutomation.kt +++ b/core/src/com/unciv/logic/automation/unit/ReligiousUnitAutomation.kt @@ -130,6 +130,7 @@ object ReligiousUnitAutomation { return null val holyCity = unit.civ.religionManager.getHolyCity() + // Our own holy city was taken over! if (holyCity != null && holyCity.religion.getMajorityReligion() != unit.civ.religionManager.religion!!) return holyCity @@ -137,12 +138,22 @@ object ReligiousUnitAutomation { if (blockedHolyCity != null) return blockedHolyCity - return unit.civ.cities.asSequence() - .filter { it.religion.getMajorityReligion() != null } - .filter { it.religion.getMajorityReligion()!! != unit.civ.religionManager.religion } - // Don't go if it takes too long + // Find cities + val relevantCities = unit.civ.gameInfo.getCities() + .filter { it.getCenterTile().isExplored(unit.civ) } // Cities we know about + // Someone else is controlling this city + .filter { + val majorityReligion = it.religion.getMajorityReligion() + majorityReligion != null && majorityReligion != unit.civ.religionManager.religion + } + + val closeCity = relevantCities .filter { it.getCenterTile().aerialDistanceTo(unit.currentTile) <= 20 } - .maxByOrNull { it.religion.getPressureDeficit(unit.civ.religionManager.religion?.name) } + // Find the city that we're the closest to converting + .minByOrNull { it.religion.getPressureDeficit(unit.civ.religionManager.religion?.name) } + if (closeCity != null) return closeCity + + return relevantCities.minByOrNull { it.religion.getPressureDeficit(unit.civ.religionManager.religion?.name) } } diff --git a/core/src/com/unciv/logic/city/managers/CityReligionManager.kt b/core/src/com/unciv/logic/city/managers/CityReligionManager.kt index 11bc61feec..6e6a0a1bf5 100644 --- a/core/src/com/unciv/logic/city/managers/CityReligionManager.kt +++ b/core/src/com/unciv/logic/city/managers/CityReligionManager.kt @@ -330,7 +330,8 @@ class CityReligionManager : IsPartOfGameInfoSerialization { return pressure.toInt() } - /** Calculates how much pressure this religion is lacking compared to the majority religion */ + /** Calculates how much pressure this religion is lacking compared to the majority religion + * That is, if we gain more than this, we'll be the majority */ @Readonly fun getPressureDeficit(otherReligion: String?): Int { val pressures = getPressures() From 5e3beb302f3f34c549d7d5d59315b5e0a4d1dae0 Mon Sep 17 00:00:00 2001 From: Rob Loach Date: Thu, 28 Aug 2025 15:52:47 -0400 Subject: [PATCH 4/5] docs: Update unique parameters documentation (#13866) --- .../ruleset/unique/UniqueParameterType.kt | 2 +- docs/Modders/Unique-parameters.md | 40 ++++++++++++------- 2 files changed, 26 insertions(+), 16 deletions(-) diff --git a/core/src/com/unciv/models/ruleset/unique/UniqueParameterType.kt b/core/src/com/unciv/models/ruleset/unique/UniqueParameterType.kt index c39cd21083..70ba5580b5 100644 --- a/core/src/com/unciv/models/ruleset/unique/UniqueParameterType.kt +++ b/core/src/com/unciv/models/ruleset/unique/UniqueParameterType.kt @@ -506,7 +506,7 @@ enum class UniqueParameterType( /**Used by [UniqueType.ConditionalCityReligion]*/ ReligionFilter("religionFilter", "major") { - override val staticKnownValues = setOf("any", "major", "enhanced", "your", "foreign","enemy") + override val staticKnownValues = setOf("any", "major", "enhanced", "your", "foreign", "enemy") override fun isKnownValue(parameterText: String, ruleset: Ruleset): Boolean { return when (parameterText) { in staticKnownValues -> true diff --git a/docs/Modders/Unique-parameters.md b/docs/Modders/Unique-parameters.md index 6fbc9123f8..ed1f5e8d9b 100644 --- a/docs/Modders/Unique-parameters.md +++ b/docs/Modders/Unique-parameters.md @@ -46,7 +46,7 @@ Allows filtering for specific nations. Used by [ModOptions.nationsToRemove](Mod- Allowed values: -- `All` +- `All`, `all` - `City-States`, `City-State` - `Major` - Nation name @@ -68,11 +68,11 @@ Allowed values: - `non-air` for non-air non-missile units - `Military`, `military units` - `Civilian`, `civilian units` -- `All` +- `All`, `all` - `Melee` - `Ranged` - `Nuclear Weapon` -- `Great Person`, `Great` +- `Great Person` - `Embarked` - Matching [technologyfilter](#technologyfilter) for the tech this unit requires - e.g. `Modern Era` - Any exact unique the unit has @@ -88,11 +88,12 @@ Allowed values: - Any matching [baseUnitFilter](#baseunitfilter) - Any [civFilter](#civfilter) matching the owner - Any unique the unit has - also includes uniques not caught by the [baseUnitFilter](#baseunitfilter), for example promotions -- Any promotion name +- Any promotion name, or an exact unique a promotion has - `Wounded` - `Embarked` - `City-State` - `Barbarians`, `Barbarian` +- `Non-City` - Again, any combination of the above is also allowed, e.g. `[{Wounded} {Water}]` units. You can check this in-game using the console with the `unit checkfilter ` command @@ -103,7 +104,7 @@ Allows to only activate a unique for certain buildings. Allowed values: -- `All` +- `All`, `all` - `Buildings`, `Building` - `Wonder`, `Wonders` - `National Wonder`, `National` @@ -124,7 +125,7 @@ Allowed values: cityFilters allow us to choose the range of cities affected by this unique: - `in this city` -- `in all cities` +- `in all cities`, `All`, `all` - Generally applies to all cities owned by the relevant civ - `in your cities`, `Your` - `in all coastal cities`, `Coastal` - `in capital`, `Capital` @@ -137,6 +138,7 @@ cityFilters allow us to choose the range of cities affected by this unique: - `in foreign cities`, `Foreign` - `in annexed cities`, `Annexed` - `in puppeted cities`, `Puppeted` +- `in resisting cities`, `Resisting` - `in cities being razed`, `Razing` - `in holy cities`, `Holy` - `in City-State cities` @@ -155,8 +157,10 @@ For filtering a specific improvement. Allowed values: - improvement name -- `All` -- `Great Improvements`, `Great` +- An exact unique the improvement has (e.g.: `spaceship improvement`) +- `Improvement` +- `All`, `all` +- `Great Improvement`, `Great` - `All Road` - for Roads & Railroads ## populationFilter @@ -189,7 +193,7 @@ For filtering specific relgions Allowed values: -- `All` or `all` +- `All`, `all` - `[policyBranchName] branch` - The name of the policy - A unique the Policy has (verbatim, no placeholders) @@ -238,7 +242,8 @@ These can be strung together with ", " between them, for example: `+2 Production Allowed values: - Resource name -- `any`, `all` +- `any` +- `All`, `all` - Resource type: `Strategic`, `Luxury`, `Bonus` - Stat provided by the resource when improved (e.g. `Food`) @@ -270,7 +275,7 @@ At the moment only implemented for [ModOptions.techsToRemove](Mod-file-structure Allowed values: -- `All` +- `All`, `all` - The name of an Era - The name of a Technology - A unique a Technology has (verbatim, no placeholders) @@ -290,19 +295,23 @@ Allowed values: - Natural wonder - A [nationFilter](#nationfilter) matching the tile owner - Or the filter is a constant string choosing a derived test: - - `All` + - `All`, `all` - `Terrain` - `Water`, `Land` - `Coastal` (at least one direct neighbor is a coast) - `River` (as in all 'river on tile' contexts, it means 'adjacent to a river on at least one side') - `Open terrain`, `Rough terrain` (note all terrain not having the rough unique is counted as open) - - `Friendly Land` - land belonging to you, or other civs with open borders to you + - `Friendly Land`, `Friendly` - land belonging to you, or other civs with open borders to you - `Foreign Land` - any land that isn't friendly land - - `Enemy Land` - any land belonging to a civ you are at war with + - `Enemy Land`, `Enemy` - any land belonging to a civ you are at war with - `your` - land belonging to you - - `unowned` - land that is not owned by any civ + - `Unowned` - land that is not owned by any civ - `Water resource`, `Strategic resource`, `Luxury resource`, `Bonus resource`, `resource` - `Natural Wonder` (as opposed to above which means testing for a specific Natural Wonder by name, this tests for any of them) + - `Featureless` + - `Fresh Water` + - `non-fresh water` + - `Impassible` Please note all of these are _case-sensitive_. @@ -316,6 +325,7 @@ Allowed values: - [terrainFilter](#terrainfilter) for this tile - [improvementFilter](#improvementfilter) for this tile +- [civFilter](#civfilter) of the civilization who owns this tile - `Improvement` or `improved` for tiles with any improvements - `unimproved` for tiles with no improvement - `pillaged` for pillaged tiles From a7de6744ae4e4a83128656d3e888621570aa86b3 Mon Sep 17 00:00:00 2001 From: yairm210 Date: Thu, 28 Aug 2025 23:31:30 +0300 Subject: [PATCH 5/5] chore: Remove unused distanceToTiles cache --- .../map/mapunit/movement/UnitMovement.kt | 30 +------------------ 1 file changed, 1 insertion(+), 29 deletions(-) diff --git a/core/src/com/unciv/logic/map/mapunit/movement/UnitMovement.kt b/core/src/com/unciv/logic/map/mapunit/movement/UnitMovement.kt index b975de775b..4eb7638cd0 100644 --- a/core/src/com/unciv/logic/map/mapunit/movement/UnitMovement.kt +++ b/core/src/com/unciv/logic/map/mapunit/movement/UnitMovement.kt @@ -267,13 +267,8 @@ class UnitMovement(val unit: MapUnit) { * @return The tile that we reached this turn */ fun headTowards(destination: Tile): Tile { - val escortUnit = if (unit.isEscorting()) unit.getOtherEscortUnit() else null - val startTile = unit.getTile() val destinationTileThisTurn = getTileToMoveToThisTurn(destination) moveToTile(destinationTileThisTurn) - if (startTile != unit.getTile() && escortUnit != null) { - escortUnit.movement.headTowards(unit.getTile()) - } return unit.currentTile } @@ -748,10 +743,6 @@ class UnitMovement(val unit: MapUnit) { movementCostCache: HashMap, Float> = HashMap(), includeOtherEscortUnit: Boolean = true ): PathsToTilesWithinTurn { -// val cacheResults = pathfindingCache.getDistanceToTiles(considerZoneOfControl) -// if (cacheResults != null) { -// return cacheResults -// } val distanceToTiles = getMovementToTilesAtPosition( unit.currentTile.position, unit.currentMovement, @@ -762,8 +753,6 @@ class UnitMovement(val unit: MapUnit) { includeOtherEscortUnit ) - pathfindingCache.setDistanceToTiles(considerZoneOfControl, distanceToTiles) - return distanceToTiles } @@ -838,14 +827,13 @@ class UnitMovement(val unit: MapUnit) { class PathfindingCache(private val unit: MapUnit) { private var shortestPathCache = listOf() private var destination: Tile? = null - private val distanceToTilesCache = mutableMapOf() private var movement = -1f private var currentTile: Tile? = null /** Check if the caches are valid (only checking if the unit has moved or consumed movement points; * the isPlayerCivilization check is performed in the functions because we want isValid() == false * to have a specific behavior) */ - private fun isValid(): Boolean = (movement == unit.currentMovement) && (unit.getTile() == currentTile) + @Readonly private fun isValid(): Boolean = (movement == unit.currentMovement) && (unit.getTile() == currentTile) fun getShortestPathCache(destination: Tile): List { if (unit.civ.isHuman()) return listOf() @@ -863,23 +851,7 @@ class PathfindingCache(private val unit: MapUnit) { } } - fun getDistanceToTiles(zoneOfControl: Boolean): PathsToTilesWithinTurn? { - if (unit.civ.isHuman()) return null - if (isValid()) - return distanceToTilesCache[zoneOfControl] - return null - } - - fun setDistanceToTiles(zoneOfControl: Boolean, paths: PathsToTilesWithinTurn) { - if (unit.civ.isHuman()) return - if (!isValid()) { - clear() // we want to reset the entire cache at this point - } - distanceToTilesCache[zoneOfControl] = paths - } - fun clear() { - distanceToTilesCache.clear() movement = unit.currentMovement currentTile = unit.getTile() destination = null