More power to improvement uniques (resourceTerrainAllow-be-gone) (#4024)

* More flexibility for modding improvements (tileFilter), deprecate resourceTerrainAllow

* More tileFilter and improvement uniques - Translations

* Update template.properties

* More tileFilter and improvement uniques - Revert and/or inside unique parameter
This commit is contained in:
SomeTroglodyte
2021-06-06 11:40:02 +02:00
committed by GitHub
parent dc8657dc02
commit 298dbcb3ee
7 changed files with 54 additions and 6 deletions

View File

@ -42,10 +42,9 @@
// Resource-specific // Resource-specific
{ {
"name": "Camp", "name": "Camp",
"resourceTerrainAllow": ["Forest"],
"turnsToBuild": 7, "turnsToBuild": 7,
"techRequired": "Trapping", "techRequired": "Trapping",
"uniques": ["[+1 Gold] once [Economics] is discovered"], "uniques": ["Does not need removal of [Forest]","[+1 Gold] once [Economics] is discovered"],
"shortcutKey": "C" "shortcutKey": "C"
}, },
{ {

View File

@ -680,6 +680,10 @@ Water resource = Wasser-Ressource
River = Fluss River = Fluss
Fresh water = Frischwasser Fresh water = Frischwasser
non-fresh water = nicht frisches Wasser non-fresh water = nicht frisches Wasser
Coastal = Küsten
Bonus resource = Bonus-ressource
Strategic resource = Strategische Ressource
Luxury resource = Luxus-ressource
Wonders = Wunder Wonders = Wunder
Base values = Grundwerte Base values = Grundwerte
@ -988,6 +992,9 @@ Must be on [terrain] = Muss sich auf [terrain] befinden
+[amount]% vs [unitType] = +[amount]% vs [unitType] +[amount]% vs [unitType] = +[amount]% vs [unitType]
+[amount] Movement for all [unitType] units = +[amount] Bewegung für alle "[unitType]"-Einheiten +[amount] Movement for all [unitType] units = +[amount] Bewegung für alle "[unitType]"-Einheiten
+[amount]% Production when constructing [param] = +[amount]% Produktion, für alle Bauten vom Typ: [param] +[amount]% Production when constructing [param] = +[amount]% Produktion, für alle Bauten vom Typ: [param]
Can only be built on [tileFilter] tiles = Kann nur auf [tileFilter]-Feldern gebaut werden
Cannot be built on [tileFilter] tiles = Kann nicht auf [tileFilter]-Feldern gebaut werden
Does not need removal of [feature] = Hierfür muß [feature] nicht entfernt werden
# City filters # City filters
in this city = in dieser Stadt in this city = in dieser Stadt
@ -3151,6 +3158,7 @@ Can be built just outside your borders = Kann, auch ein Feld weit, außerhalb De
Citadel = Zitadelle Citadel = Zitadelle
Can only be built on Coastal tiles = Kann nur entlang der Küstenlinie gebaut werden Can only be built on Coastal tiles = Kann nur entlang der Küstenlinie gebaut werden
Moai = Moai Moai = Moai
Cannot be built on bonus resource = Darf nicht auf Bonus-Ressourcen gebaut werden Cannot be built on bonus resource = Darf nicht auf Bonus-Ressourcen gebaut werden

View File

@ -674,6 +674,10 @@ Water resource =
River = River =
Fresh water = Fresh water =
non-fresh water = non-fresh water =
Coastal =
Bonus resource =
Strategic resource =
Luxury resource =
Wonders = Wonders =
Base values = Base values =
@ -979,6 +983,9 @@ Must be on [terrain] =
+[amount]% vs [unitType] = +[amount]% vs [unitType] =
+[amount] Movement for all [unitType] units = +[amount] Movement for all [unitType] units =
+[amount]% Production when constructing [param] = +[amount]% Production when constructing [param] =
Can only be built on [tileFilter] tiles =
Cannot be built on [tileFilter] tiles =
Does not need removal of [feature] =
# City filters # City filters
in this city = in this city =

View File

@ -227,7 +227,7 @@ class WorkerAutomation(val unit: MapUnit) {
?: return false ?: return false
val resourceImprovement = civInfo.gameInfo.ruleSet.tileImprovements[resourceImprovementName] val resourceImprovement = civInfo.gameInfo.ruleSet.tileImprovements[resourceImprovementName]
?: return false ?: return false
return tile.terrainFeatures.any { resourceImprovement.resourceTerrainAllow.contains(it) } return tile.terrainFeatures.any { resourceImprovement.isAllowedOnFeature(it) }
} }
private fun isAcceptableTileForFort(tile: TileInfo, civInfo: CivilizationInfo): Boolean { private fun isAcceptableTileForFort(tile: TileInfo, civInfo: CivilizationInfo): Boolean {

View File

@ -356,6 +356,9 @@ open class TileInfo {
isCityCenter() -> false isCityCenter() -> false
"Cannot be built on bonus resource" in improvement.uniques && resource != null "Cannot be built on bonus resource" in improvement.uniques && resource != null
&& getTileResource().resourceType == ResourceType.Bonus -> false && getTileResource().resourceType == ResourceType.Bonus -> false
improvement.uniqueObjects.filter { it.placeholderText == "Cannot be built on [] tiles" }.any {
unique -> matchesUniqueFilter(unique.params[0])
} -> false
// Road improvements can change on tiles with irremovable improvements - nothing else can, though. // Road improvements can change on tiles with irremovable improvements - nothing else can, though.
improvement.name != RoadStatus.Railroad.name && improvement.name != RoadStatus.Railroad.name improvement.name != RoadStatus.Railroad.name && improvement.name != RoadStatus.Railroad.name
@ -376,22 +379,33 @@ open class TileInfo {
improvement.name == "Railroad" && this.roadStatus != RoadStatus.Railroad && !isWater -> true improvement.name == "Railroad" && this.roadStatus != RoadStatus.Railroad && !isWater -> true
improvement.name == "Remove Road" && this.roadStatus == RoadStatus.Road -> true improvement.name == "Remove Road" && this.roadStatus == RoadStatus.Road -> true
improvement.name == "Remove Railroad" && this.roadStatus == RoadStatus.Railroad -> true improvement.name == "Remove Railroad" && this.roadStatus == RoadStatus.Railroad -> true
topTerrain.unbuildable && (topTerrain.name !in improvement.resourceTerrainAllow) -> false topTerrain.unbuildable && !improvement.isAllowedOnFeature(topTerrain.name) -> false
// DO NOT reverse this &&. isAdjacentToFreshwater() is a lazy which calls a function, and reversing it breaks the tests. // DO NOT reverse this &&. isAdjacentToFreshwater() is a lazy which calls a function, and reversing it breaks the tests.
improvement.hasUnique("Can also be built on tiles adjacent to fresh water") && isAdjacentToFreshwater -> true improvement.hasUnique("Can also be built on tiles adjacent to fresh water") && isAdjacentToFreshwater -> true
"Can only be built on Coastal tiles" in improvement.uniques && isCoastalTile() -> true "Can only be built on Coastal tiles" in improvement.uniques && isCoastalTile() -> true
improvement.uniqueObjects.filter { it.placeholderText == "Can only be built on [] tiles" }.any {
unique -> !matchesUniqueFilter(unique.params[0])
} -> false
else -> resourceIsVisible && getTileResource().improvement == improvement.name else -> resourceIsVisible && getTileResource().improvement == improvement.name
} }
} }
/**
* Implementation of _`tileFilter`_
* @see <a href="https://github.com/yairm210/Unciv/wiki/uniques#user-content-tilefilter">tileFilter</a>
*/
fun matchesUniqueFilter(filter: String, civInfo: CivilizationInfo? = null): Boolean { fun matchesUniqueFilter(filter: String, civInfo: CivilizationInfo? = null): Boolean {
return filter == baseTerrain return filter == "All"
|| filter == baseTerrain
|| filter == "River" && isAdjacentToRiver() || filter == "River" && isAdjacentToRiver()
|| terrainFeatures.contains(filter) || terrainFeatures.contains(filter)
|| baseTerrainObject.uniques.contains(filter) || baseTerrainObject.uniques.contains(filter)
|| improvement == filter || improvement == filter
|| resource == filter
|| (resource != null && getTileResource().resourceType.name + " resource" == filter)
|| filter == "Water" && isWater || filter == "Water" && isWater
|| filter == "Land" && isLand || filter == "Land" && isLand
|| filter == "Coastal" && isCoastalTile()
|| filter == naturalWonder || filter == naturalWonder
|| terrainFeatures.isNotEmpty() && getTerrainFeatures().last().uniques.contains(filter) || terrainFeatures.isNotEmpty() && getTerrainFeatures().last().uniques.contains(filter)
|| civInfo != null && hasViewableResource(civInfo) && resource == filter || civInfo != null && hasViewableResource(civInfo) && resource == filter

View File

@ -23,7 +23,7 @@ class Terrain : NamedStats() {
/** Used by Natural Wonders: it is the baseTerrain on top of which the Natural Wonder is placed */ /** Used by Natural Wonders: it is the baseTerrain on top of which the Natural Wonder is placed */
val turnsInto: String? = null val turnsInto: String? = null
/** Uniques (currently used only for Natural Wonders) */ /** Uniques (Properties such as Temp/humidity, Fresh water, elevation, rough, defense, Natural Wonder specials) */
val uniques = ArrayList<String>() val uniques = ArrayList<String>()
val uniqueObjects: List<Unique> by lazy { uniques.map { Unique(it) } } val uniqueObjects: List<Unique> by lazy { uniques.map { Unique(it) } }

View File

@ -14,6 +14,7 @@ class TileImprovement : NamedStats() {
// Used only for Camp - but avoid hardcoded comparison and *allow modding* // Used only for Camp - but avoid hardcoded comparison and *allow modding*
// Terrain Features that need not be cleared if the improvement enables a resource // Terrain Features that need not be cleared if the improvement enables a resource
@Deprecated("As of 3.14.15")
var resourceTerrainAllow: Collection<String> = ArrayList() var resourceTerrainAllow: Collection<String> = ArrayList()
var techRequired: String? = null var techRequired: String? = null
@ -68,5 +69,24 @@ class TileImprovement : NamedStats() {
fun hasUnique(unique: String) = uniques.contains(unique) fun hasUnique(unique: String) = uniques.contains(unique)
fun isGreatImprovement() = hasUnique("Great Improvement") fun isGreatImprovement() = hasUnique("Great Improvement")
/**
* Check: Is this improvement allowed on a [given][name] terrain feature?
*
* Uses both _legacy_ [resourceTerrainAllow] and unique "Does not need removal of []"
*
* Background: This not used for e.g. a lumbermill - it derives the right to be placed on forest
* from [terrainsCanBeBuiltOn]. Other improvements may be candidates without fulfilling the
* [terrainsCanBeBuiltOn] check - e.g. they are listed by a resource as 'their' improvement.
* I such cases, the 'unbuildable' property of the Terrain feature might prevent the improvement,
* so this check is done in conjunction - for the user, success means he does not need to remove
* a terrain feature, thus the unique name.
*/
fun isAllowedOnFeature(name: String): Boolean {
if (name in resourceTerrainAllow) return true
return uniqueObjects.filter { it.placeholderText == "Does not need removal of []"
&& it.params[0] == name
}.any()
}
} }