From 298dbcb3ee7e1ff65afb0b48344315831382e0a9 Mon Sep 17 00:00:00 2001
From: SomeTroglodyte <63000004+SomeTroglodyte@users.noreply.github.com>
Date: Sun, 6 Jun 2021 11:40:02 +0200
Subject: [PATCH] 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
---
.../Civ V - Vanilla/TileImprovements.json | 3 +--
.../jsons/translations/German.properties | 8 ++++++++
.../jsons/translations/template.properties | 7 +++++++
.../logic/automation/WorkerAutomation.kt | 2 +-
core/src/com/unciv/logic/map/TileInfo.kt | 18 +++++++++++++++--
.../com/unciv/models/ruleset/tile/Terrain.kt | 2 +-
.../models/ruleset/tile/TileImprovement.kt | 20 +++++++++++++++++++
7 files changed, 54 insertions(+), 6 deletions(-)
diff --git a/android/assets/jsons/Civ V - Vanilla/TileImprovements.json b/android/assets/jsons/Civ V - Vanilla/TileImprovements.json
index 4ebdde436b..6087ce72d6 100644
--- a/android/assets/jsons/Civ V - Vanilla/TileImprovements.json
+++ b/android/assets/jsons/Civ V - Vanilla/TileImprovements.json
@@ -42,10 +42,9 @@
// Resource-specific
{
"name": "Camp",
- "resourceTerrainAllow": ["Forest"],
"turnsToBuild": 7,
"techRequired": "Trapping",
- "uniques": ["[+1 Gold] once [Economics] is discovered"],
+ "uniques": ["Does not need removal of [Forest]","[+1 Gold] once [Economics] is discovered"],
"shortcutKey": "C"
},
{
diff --git a/android/assets/jsons/translations/German.properties b/android/assets/jsons/translations/German.properties
index 2e89d55a68..2d2ef5b36b 100644
--- a/android/assets/jsons/translations/German.properties
+++ b/android/assets/jsons/translations/German.properties
@@ -680,6 +680,10 @@ Water resource = Wasser-Ressource
River = Fluss
Fresh water = Frischwasser
non-fresh water = nicht frisches Wasser
+Coastal = Küsten
+Bonus resource = Bonus-ressource
+Strategic resource = Strategische Ressource
+Luxury resource = Luxus-ressource
Wonders = Wunder
Base values = Grundwerte
@@ -988,6 +992,9 @@ Must be on [terrain] = Muss sich auf [terrain] befinden
+[amount]% vs [unitType] = +[amount]% vs [unitType]
+[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]
+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
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
Can only be built on Coastal tiles = Kann nur entlang der Küstenlinie gebaut werden
+
Moai = Moai
Cannot be built on bonus resource = Darf nicht auf Bonus-Ressourcen gebaut werden
diff --git a/android/assets/jsons/translations/template.properties b/android/assets/jsons/translations/template.properties
index 4b3aeed928..0dc4f2f662 100644
--- a/android/assets/jsons/translations/template.properties
+++ b/android/assets/jsons/translations/template.properties
@@ -674,6 +674,10 @@ Water resource =
River =
Fresh water =
non-fresh water =
+Coastal =
+Bonus resource =
+Strategic resource =
+Luxury resource =
Wonders =
Base values =
@@ -979,6 +983,9 @@ Must be on [terrain] =
+[amount]% vs [unitType] =
+[amount] Movement for all [unitType] units =
+[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
in this city =
diff --git a/core/src/com/unciv/logic/automation/WorkerAutomation.kt b/core/src/com/unciv/logic/automation/WorkerAutomation.kt
index 936de404dc..9369a44b44 100644
--- a/core/src/com/unciv/logic/automation/WorkerAutomation.kt
+++ b/core/src/com/unciv/logic/automation/WorkerAutomation.kt
@@ -227,7 +227,7 @@ class WorkerAutomation(val unit: MapUnit) {
?: return false
val resourceImprovement = civInfo.gameInfo.ruleSet.tileImprovements[resourceImprovementName]
?: 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 {
diff --git a/core/src/com/unciv/logic/map/TileInfo.kt b/core/src/com/unciv/logic/map/TileInfo.kt
index 84fccb19d9..93da2d2bcc 100644
--- a/core/src/com/unciv/logic/map/TileInfo.kt
+++ b/core/src/com/unciv/logic/map/TileInfo.kt
@@ -356,6 +356,9 @@ open class TileInfo {
isCityCenter() -> false
"Cannot be built on bonus resource" in improvement.uniques && resource != null
&& 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.
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 == "Remove Road" && this.roadStatus == RoadStatus.Road -> 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.
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
+ improvement.uniqueObjects.filter { it.placeholderText == "Can only be built on [] tiles" }.any {
+ unique -> !matchesUniqueFilter(unique.params[0])
+ } -> false
else -> resourceIsVisible && getTileResource().improvement == improvement.name
}
}
+ /**
+ * Implementation of _`tileFilter`_
+ * @see tileFilter
+ */
fun matchesUniqueFilter(filter: String, civInfo: CivilizationInfo? = null): Boolean {
- return filter == baseTerrain
+ return filter == "All"
+ || filter == baseTerrain
|| filter == "River" && isAdjacentToRiver()
|| terrainFeatures.contains(filter)
|| baseTerrainObject.uniques.contains(filter)
|| improvement == filter
+ || resource == filter
+ || (resource != null && getTileResource().resourceType.name + " resource" == filter)
|| filter == "Water" && isWater
|| filter == "Land" && isLand
+ || filter == "Coastal" && isCoastalTile()
|| filter == naturalWonder
|| terrainFeatures.isNotEmpty() && getTerrainFeatures().last().uniques.contains(filter)
|| civInfo != null && hasViewableResource(civInfo) && resource == filter
diff --git a/core/src/com/unciv/models/ruleset/tile/Terrain.kt b/core/src/com/unciv/models/ruleset/tile/Terrain.kt
index 4d83370ab4..987f208c61 100644
--- a/core/src/com/unciv/models/ruleset/tile/Terrain.kt
+++ b/core/src/com/unciv/models/ruleset/tile/Terrain.kt
@@ -23,7 +23,7 @@ class Terrain : NamedStats() {
/** Used by Natural Wonders: it is the baseTerrain on top of which the Natural Wonder is placed */
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()
val uniqueObjects: List by lazy { uniques.map { Unique(it) } }
diff --git a/core/src/com/unciv/models/ruleset/tile/TileImprovement.kt b/core/src/com/unciv/models/ruleset/tile/TileImprovement.kt
index a6cb886b95..83d44358ac 100644
--- a/core/src/com/unciv/models/ruleset/tile/TileImprovement.kt
+++ b/core/src/com/unciv/models/ruleset/tile/TileImprovement.kt
@@ -14,6 +14,7 @@ class TileImprovement : NamedStats() {
// Used only for Camp - but avoid hardcoded comparison and *allow modding*
// Terrain Features that need not be cleared if the improvement enables a resource
+ @Deprecated("As of 3.14.15")
var resourceTerrainAllow: Collection = ArrayList()
var techRequired: String? = null
@@ -68,5 +69,24 @@ class TileImprovement : NamedStats() {
fun hasUnique(unique: String) = uniques.contains(unique)
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()
+ }
}