mirror of
https://github.com/yairm210/Unciv.git
synced 2025-09-24 03:53:12 -04:00
Rivers... Moddable Stats and Civilopedia (#10424)
* River yields moddable and Civilopedia entry * Improve text and better fresh water explanations * Map editor exclusion as Unique, for River and previously hardcoded Improvements * Map editor brush to Civilopedia link, starting locations cleaned * Some SeventhM input applied * Reword River/Lakes/Oasis civilopediaText and comments again
This commit is contained in:
parent
22a50c7d2d
commit
2847f7a8c1
@ -1,5 +1,6 @@
|
||||
[
|
||||
//Spectator
|
||||
//Not "Excluded from map editor" as it serves as placeholder for "Any Civ" starting locations
|
||||
{
|
||||
"name": "Spectator",
|
||||
"outerColor": [255,255,255],
|
||||
@ -1348,7 +1349,7 @@
|
||||
"outerColor": [0, 0, 0],
|
||||
"innerColor": [211,180,113],
|
||||
"cities": ["Dublin"],
|
||||
"uniques": ["Will not be displayed in Civilopedia", "Will not be chosen for new games"]
|
||||
"uniques": ["Will not be displayed in Civilopedia", "Will not be chosen for new games", "Excluded from map editor"]
|
||||
},
|
||||
{
|
||||
"name": "Edinburgh",
|
||||
@ -1361,7 +1362,7 @@
|
||||
"outerColor": [0, 0, 0],
|
||||
"innerColor": [0,102,102],
|
||||
"cities": ["Edinburgh"],
|
||||
"uniques": ["Will not be displayed in Civilopedia", "Will not be chosen for new games"]
|
||||
"uniques": ["Will not be displayed in Civilopedia", "Will not be chosen for new games", "Excluded from map editor"]
|
||||
},
|
||||
{
|
||||
"name": "M'Banza-Kongo",
|
||||
@ -1444,7 +1445,7 @@
|
||||
"name": "Barbarians",
|
||||
"outerColor": [0,0,0],
|
||||
"innerColor": [185,12,12],
|
||||
"uniques": ["Can only heal by pillaging"]
|
||||
"uniques": ["Can only heal by pillaging", "Excluded from map editor"]
|
||||
}
|
||||
|
||||
]
|
||||
|
@ -113,7 +113,15 @@
|
||||
"RGB": [0, 171, 169],
|
||||
"uniques": ["Fresh water",
|
||||
"Considered [Food] when determining start locations",
|
||||
"Considered [Desirable] when determining start locations"]
|
||||
"Considered [Desirable] when determining start locations"],
|
||||
"civilopediaText": [
|
||||
{"text": "Lakes provide fresh water to adjacent tiles, allowing farming where it would otherwise not be possible (similar to Rivers and Oases)."},
|
||||
{"text": "Rivers", "link":"Terrain/River"},
|
||||
{"text": "Oasis", "link":"Terrain/Oasis"},
|
||||
{"text": "Farm", "link":"Improvement/Farm"},
|
||||
{"text": "Civil Service", "link":"Technology/Civil Service"},
|
||||
{"text": "Fertilizer", "link":"Technology/Fertilizer"}
|
||||
]
|
||||
},
|
||||
{
|
||||
"name": "Mountain",
|
||||
@ -251,7 +259,15 @@
|
||||
"Only [All Road] improvements may be built on this tile",
|
||||
"Always Fertility [4] for Map Generation",
|
||||
"Considered [Food] when determining start locations",
|
||||
"Considered [Desirable] when determining start locations"]
|
||||
"Considered [Desirable] when determining start locations"],
|
||||
"civilopediaText": [
|
||||
{"text": "Oases provide fresh water to adjacent tiles, allowing farming where it would otherwise not be possible (similar to Rivers and Lakes)."},
|
||||
{"text": "Rivers", "link":"Terrain/River"},
|
||||
{"text": "Lakes", "link":"Terrain/Lakes"},
|
||||
{"text": "Farm", "link":"Improvement/Farm"},
|
||||
{"text": "Civil Service", "link":"Technology/Civil Service"},
|
||||
{"text": "Fertilizer", "link":"Technology/Fertilizer"}
|
||||
]
|
||||
},
|
||||
{
|
||||
"name": "Flood plains",
|
||||
@ -284,7 +300,37 @@
|
||||
"uniques": ["Rare feature"]
|
||||
},
|
||||
|
||||
// Natural Wonders
|
||||
// Virtual River entry, used for stats, Uniques and Civilopedia
|
||||
// Modders take heed:
|
||||
// * This never exists on the map, it's a placeholder to allow you to mod the actual river's stats.
|
||||
// * The name is hardcoded to apply stats and the Stats Unique when a tile has one or more edges with an actual river.
|
||||
// * No other Unique is implemented and will work - for now.
|
||||
{
|
||||
"name": "River",
|
||||
"type": "TerrainFeature",
|
||||
"gold": 1,
|
||||
"movementCost": 0, // So Civilopedia won't display a cost of 1
|
||||
"uniques": ["Doesn't generate naturally", "Excluded from map editor"],
|
||||
"civilopediaText": [
|
||||
{"text": "Rivers exist on tile edges, not as terrain feature per se."},
|
||||
{"text": "Tiles on both sides gain its benefits. These benefits do not stack."},
|
||||
{"text": "The tile has access to fresh water, allowing farming where it would otherwise not be possible (similar to Oases and Lakes)."},
|
||||
{"text": "Movement across rivers takes all remaining movement points of a unit unless there is a bridge."},
|
||||
// See BattleConstants.ATTACKING_ACROSS_RIVER_MALUS:
|
||||
{"text": "When attacking across a river, the attacker gets a -20% strength malus."},
|
||||
// Related Buildings and Beliefs are automatically linked
|
||||
{"text": "Lakes", "link":"Terrain/Lakes"},
|
||||
{"text": "Oasis", "link":"Terrain/Oasis"},
|
||||
{"text": "Farm", "link":"Improvement/Farm"},
|
||||
{"text": "Road", "link":"Improvement/Road"},
|
||||
{"text": "Engineering", "link":"Technology/Engineering"},
|
||||
{"text": "Civil Service", "link":"Technology/Civil Service"},
|
||||
{"text": "Fertilizer", "link":"Technology/Fertilizer"},
|
||||
{"text": "Amphibious", "link":"Promotion/Amphibious"}
|
||||
]
|
||||
},
|
||||
|
||||
// Natural Wonders
|
||||
{
|
||||
"name": "Great Barrier Reef",
|
||||
"type": "NaturalWonder",
|
||||
|
@ -133,7 +133,7 @@
|
||||
"name": "Remove Forest",
|
||||
"turnsToBuild": 4,
|
||||
"techRequired": "Mining",
|
||||
"uniques": ["Can be built outside your borders"],
|
||||
"uniques": ["Can be built outside your borders", "Excluded from map editor"],
|
||||
"shortcutKey": "X",
|
||||
"civilopediaText": [{"text":"Provides a one-time Production bonus depending on distance to the closest city once finished"}]
|
||||
},
|
||||
@ -141,21 +141,21 @@
|
||||
"name": "Remove Jungle",
|
||||
"turnsToBuild": 7,
|
||||
"techRequired": "Bronze Working",
|
||||
"uniques": ["Can be built outside your borders"],
|
||||
"uniques": ["Can be built outside your borders", "Excluded from map editor"],
|
||||
"shortcutKey": "X"
|
||||
},
|
||||
{
|
||||
"name": "Remove Fallout",
|
||||
"turnsToBuild": 2,
|
||||
// Has no tech requirements as it can always be built
|
||||
"uniques": ["Can be built outside your borders"],
|
||||
"uniques": ["Can be built outside your borders", "Excluded from map editor"],
|
||||
"shortcutKey": "X"
|
||||
},
|
||||
{
|
||||
"name": "Remove Marsh",
|
||||
"turnsToBuild": 6,
|
||||
"techRequired": "Masonry",
|
||||
"uniques": ["Can be built outside your borders"],
|
||||
"uniques": ["Can be built outside your borders", "Excluded from map editor"],
|
||||
"shortcutKey": "X"
|
||||
},
|
||||
|
||||
@ -163,16 +163,16 @@
|
||||
{
|
||||
"name": "Remove Road",
|
||||
"turnsToBuild": 2,
|
||||
"uniques": ["Can be built outside your borders"]
|
||||
"uniques": ["Can be built outside your borders", "Excluded from map editor"]
|
||||
},
|
||||
{
|
||||
"name": "Remove Railroad",
|
||||
"turnsToBuild": 2,
|
||||
"uniques": ["Can be built outside your borders"]
|
||||
"uniques": ["Can be built outside your borders", "Excluded from map editor"]
|
||||
},
|
||||
{
|
||||
"name": "Cancel improvement order",
|
||||
"uniques": ["Can be built outside your borders"],
|
||||
"uniques": ["Can be built outside your borders", "Excluded from map editor"],
|
||||
"shortcutKey": "."
|
||||
},
|
||||
// Purely for turnsToBuild and civilopediaText. Unbuildable so it doesn't show in ImprovementPicker
|
||||
@ -181,7 +181,7 @@
|
||||
"terrainsCanBeBuiltOn": ["Land"],
|
||||
"turnsToBuild": 2,
|
||||
"shortcutKey": "E",
|
||||
"uniques": ["Unbuildable"],
|
||||
"uniques": ["Unbuildable", "Excluded from map editor"],
|
||||
"civilopediaText": [{"text":"Repairs a pillaged Improvement or Route"}]
|
||||
},
|
||||
|
||||
@ -282,7 +282,7 @@
|
||||
"name": "City center",
|
||||
"terrainsCanBeBuiltOn": ["Land"],
|
||||
"uniques": ["Ensures a minimum tile yield of [+2 Food, +1 Production]",
|
||||
"Unpillagable", "Irremovable", "Unbuildable"],
|
||||
"Unpillagable", "Irremovable", "Unbuildable", "Excluded from map editor"],
|
||||
"civilopediaText": [
|
||||
{"text":"Marks the center of a city"},
|
||||
{"text":"Appearance changes with the technological era of the owning civilization"}
|
||||
@ -291,7 +291,7 @@
|
||||
{
|
||||
"name": "Barbarian encampment",
|
||||
"terrainsCanBeBuiltOn": ["Land"],
|
||||
"uniques": ["Unpillagable", "Unbuildable"],
|
||||
"uniques": ["Unpillagable", "Unbuildable", "Excluded from map editor"],
|
||||
"civilopediaText": [{"text":"Home to uncivilized barbarians, will spawn a hostile unit from time to time"}]
|
||||
}
|
||||
]
|
||||
|
@ -1,5 +1,6 @@
|
||||
[
|
||||
//Spectator
|
||||
//Not "Excluded from map editor" as it serves as placeholder for "Any Civ" starting locations
|
||||
{
|
||||
"name": "Spectator",
|
||||
"outerColor": [255,255,255]
|
||||
@ -1026,7 +1027,7 @@
|
||||
"outerColor": [0, 0, 0],
|
||||
"innerColor": [211,180,113],
|
||||
"cities": ["Dublin"],
|
||||
"uniques": ["Will not be displayed in Civilopedia", "Will not be chosen for new games"]
|
||||
"uniques": ["Will not be displayed in Civilopedia", "Will not be chosen for new games", "Excluded from map editor"]
|
||||
},
|
||||
{
|
||||
"name": "Edinburgh",
|
||||
@ -1039,7 +1040,7 @@
|
||||
"outerColor": [0, 0, 0],
|
||||
"innerColor": [0,102,102],
|
||||
"cities": ["Edinburgh"],
|
||||
"uniques": ["Will not be displayed in Civilopedia", "Will not be chosen for new games"]
|
||||
"uniques": ["Will not be displayed in Civilopedia", "Will not be chosen for new games", "Excluded from map editor"]
|
||||
},
|
||||
{
|
||||
"name": "M'Banza-Kongo",
|
||||
@ -1084,7 +1085,7 @@
|
||||
"name": "Barbarians",
|
||||
"outerColor": [0,0,0],
|
||||
"innerColor": [185,12,12],
|
||||
"uniques": ["Can only heal by pillaging"]
|
||||
"uniques": ["Can only heal by pillaging", "Excluded from map editor"]
|
||||
}
|
||||
|
||||
]
|
||||
|
@ -113,7 +113,15 @@
|
||||
"RGB": [0, 171, 169],
|
||||
"uniques": ["Fresh water",
|
||||
"Considered [Food] when determining start locations",
|
||||
"Considered [Desirable] when determining start locations"]
|
||||
"Considered [Desirable] when determining start locations"],
|
||||
"civilopediaText": [
|
||||
{"text": "Lakes provide fresh water to adjacent tiles, allowing farming where it would otherwise not be possible (similar to Rivers and Oases)."},
|
||||
{"text": "Rivers", "link":"Terrain/River"},
|
||||
{"text": "Oasis", "link":"Terrain/Oasis"},
|
||||
{"text": "Farm", "link":"Improvement/Farm"},
|
||||
{"text": "Civil Service", "link":"Technology/Civil Service"},
|
||||
{"text": "Fertilizer", "link":"Technology/Fertilizer"}
|
||||
]
|
||||
},
|
||||
{
|
||||
"name": "Mountain",
|
||||
@ -252,7 +260,15 @@
|
||||
"Only [All Road] improvements may be built on this tile",
|
||||
"Always Fertility [4] for Map Generation",
|
||||
"Considered [Food] when determining start locations",
|
||||
"Considered [Desirable] when determining start locations"]
|
||||
"Considered [Desirable] when determining start locations"],
|
||||
"civilopediaText": [
|
||||
{"text": "Oases provide fresh water to adjacent tiles, allowing farming where it would otherwise not be possible (similar to Rivers and Lakes)."},
|
||||
{"text": "Rivers", "link":"Terrain/River"},
|
||||
{"text": "Lakes", "link":"Terrain/Lakes"},
|
||||
{"text": "Farm", "link":"Improvement/Farm"},
|
||||
{"text": "Civil Service", "link":"Technology/Civil Service"},
|
||||
{"text": "Fertilizer", "link":"Technology/Fertilizer"}
|
||||
]
|
||||
},
|
||||
{
|
||||
"name": "Flood plains",
|
||||
@ -285,7 +301,37 @@
|
||||
"uniques": ["Rare feature"]
|
||||
},
|
||||
|
||||
// Natural Wonders
|
||||
// Virtual River entry, used for stats, Uniques and Civilopedia
|
||||
// Modders take heed:
|
||||
// * This never exists on the map, it's a placeholder to allow you to mod the actual river's stats.
|
||||
// * The name is hardcoded to apply stats and the Stats Unique when a tile has one or more edges with an actual river.
|
||||
// * No other Unique is implemented and will work - for now.
|
||||
{
|
||||
"name": "River",
|
||||
"type": "TerrainFeature",
|
||||
"gold": 1,
|
||||
"movementCost": 0, // So Civilopedia won't display a cost of 1
|
||||
"uniques": ["Doesn't generate naturally", "Excluded from map editor"],
|
||||
"civilopediaText": [
|
||||
{"text": "Rivers exist on tile edges, not as terrain feature per se."},
|
||||
{"text": "Tiles on both sides gain its benefits. These benefits do not stack."},
|
||||
{"text": "The tile has access to fresh water, allowing farming where it would otherwise not be possible (similar to Oases and Lakes)."},
|
||||
{"text": "Movement across rivers takes all remaining movement points of a unit unless there is a bridge."},
|
||||
// See BattleConstants.ATTACKING_ACROSS_RIVER_MALUS:
|
||||
{"text": "When attacking across a river, the attacker gets a -20% strength malus."},
|
||||
// Related Buildings are automatically linked
|
||||
{"text": "Lakes", "link":"Terrain/Lakes"},
|
||||
{"text": "Oasis", "link":"Terrain/Oasis"},
|
||||
{"text": "Farm", "link":"Improvement/Farm"},
|
||||
{"text": "Road", "link":"Improvement/Road"},
|
||||
{"text": "Engineering", "link":"Technology/Engineering"},
|
||||
{"text": "Civil Service", "link":"Technology/Civil Service"},
|
||||
{"text": "Fertilizer", "link":"Technology/Fertilizer"},
|
||||
{"text": "Amphibious", "link":"Promotion/Amphibious"}
|
||||
]
|
||||
},
|
||||
|
||||
// Natural Wonders
|
||||
{
|
||||
"name": "Great Barrier Reef",
|
||||
"type": "NaturalWonder",
|
||||
|
@ -133,7 +133,7 @@
|
||||
"name": "Remove Forest",
|
||||
"turnsToBuild": 4,
|
||||
"techRequired": "Mining",
|
||||
"uniques": ["Can be built outside your borders"],
|
||||
"uniques": ["Can be built outside your borders", "Excluded from map editor"],
|
||||
"shortcutKey": "X",
|
||||
"civilopediaText": [{"text":"Provides a one-time Production bonus depending on distance to the closest city once finished"}]
|
||||
},
|
||||
@ -141,21 +141,21 @@
|
||||
"name": "Remove Jungle",
|
||||
"turnsToBuild": 7,
|
||||
"techRequired": "Bronze Working",
|
||||
"uniques": ["Can be built outside your borders"],
|
||||
"uniques": ["Can be built outside your borders", "Excluded from map editor"],
|
||||
"shortcutKey": "X"
|
||||
},
|
||||
{
|
||||
"name": "Remove Fallout",
|
||||
"turnsToBuild": 2,
|
||||
// Has no tech requirements as it can always be built
|
||||
"uniques": ["Can be built outside your borders"],
|
||||
"uniques": ["Can be built outside your borders", "Excluded from map editor"],
|
||||
"shortcutKey": "X"
|
||||
},
|
||||
{
|
||||
"name": "Remove Marsh",
|
||||
"turnsToBuild": 6,
|
||||
"techRequired": "Masonry",
|
||||
"uniques": ["Can be built outside your borders"],
|
||||
"uniques": ["Can be built outside your borders", "Excluded from map editor"],
|
||||
"shortcutKey": "X"
|
||||
},
|
||||
|
||||
@ -163,16 +163,16 @@
|
||||
{
|
||||
"name": "Remove Road",
|
||||
"turnsToBuild": 2,
|
||||
"uniques": ["Can be built outside your borders"]
|
||||
"uniques": ["Can be built outside your borders", "Excluded from map editor"]
|
||||
},
|
||||
{
|
||||
"name": "Remove Railroad",
|
||||
"turnsToBuild": 2,
|
||||
"uniques": ["Can be built outside your borders"]
|
||||
"uniques": ["Can be built outside your borders", "Excluded from map editor"]
|
||||
},
|
||||
{
|
||||
"name": "Cancel improvement order",
|
||||
"uniques": ["Can be built outside your borders"],
|
||||
"uniques": ["Can be built outside your borders", "Excluded from map editor"],
|
||||
"shortcutKey": "."
|
||||
},
|
||||
// Purely for turnsToBuild and civilopediaText. Unbuildable so it doesn't show in ImprovementPicker
|
||||
@ -180,7 +180,7 @@
|
||||
"name": "Repair",
|
||||
"terrainsCanBeBuiltOn": ["Land"],
|
||||
"turnsToBuild": 2,
|
||||
"uniques": ["Unbuildable"],
|
||||
"uniques": ["Unbuildable", "Excluded from map editor"],
|
||||
"shortcutKey": "E",
|
||||
"civilopediaText": [{"text":"Repairs a pillaged Improvement or Route"}]
|
||||
},
|
||||
@ -271,7 +271,7 @@
|
||||
"name": "City center",
|
||||
"terrainsCanBeBuiltOn": ["Land"],
|
||||
"uniques": ["Ensures a minimum tile yield of [+2 Food, +1 Production]",
|
||||
"Unpillagable", "Irremovable", "Unbuildable"],
|
||||
"Unpillagable", "Irremovable", "Unbuildable", "Excluded from map editor"],
|
||||
"civilopediaText": [
|
||||
{"text":"Marks the center of a city"},
|
||||
{"text":"Appearance changes with the technological era of the owning civilization"}
|
||||
@ -280,7 +280,7 @@
|
||||
{
|
||||
"name": "Barbarian encampment",
|
||||
"terrainsCanBeBuiltOn": ["Land"],
|
||||
"uniques": ["Unpillagable", "Unbuildable"],
|
||||
"uniques": ["Unpillagable", "Unbuildable", "Excluded from map editor"],
|
||||
"civilopediaText": [{"text":"Home to uncivilized barbarians, will spawn a hostile unit from time to time"}]
|
||||
}
|
||||
]
|
||||
|
@ -2,6 +2,9 @@
|
||||
"useColorAsBaseTerrain": "false",
|
||||
"fallbackTileSet": null,
|
||||
"ruleVariants": {
|
||||
// River pseudo-tile used in Civilopedia display only
|
||||
"Grassland+River": ["Plains","River-BottomLeft","River-Bottom","River-BottomRight"],
|
||||
|
||||
//Legacy hill support
|
||||
"Hill": ["Grassland","Hill"],
|
||||
"Hill+Forest+Uranium": ["Grassland","Hill","Uranium","Forest"],
|
||||
|
@ -3,6 +3,9 @@
|
||||
"fallbackTileSet": "FantasyHex",
|
||||
"ruleVariants": {
|
||||
|
||||
// River pseudo-tile used in Civilopedia display only
|
||||
"Grassland+River": ["Plains","River-BottomLeft","River-Bottom","River-BottomRight"],
|
||||
|
||||
//forest and jungle
|
||||
"Grassland+Forest": ["Grassland","ForestG"],
|
||||
"Grassland+Jungle": ["Grassland","JungleG"],
|
||||
|
@ -551,7 +551,6 @@ Spread Resources =
|
||||
Create ancient ruins =
|
||||
Floodfill =
|
||||
[nation] starting location =
|
||||
Any Civ starting locations =
|
||||
Any Civ =
|
||||
Remove features =
|
||||
Remove improvement =
|
||||
|
@ -16,6 +16,9 @@ object Constants {
|
||||
/** The "Coastal" terrain _filter_ */
|
||||
const val coastal = "Coastal"
|
||||
|
||||
/** Used as filter and the name of the pseudo-TerrainFeature defining river Stats */
|
||||
const val river = "River"
|
||||
|
||||
const val mountain = "Mountain"
|
||||
const val hill = "Hill"
|
||||
const val plains = "Plains"
|
||||
|
@ -465,7 +465,7 @@ open class Tile : IsPartOfGameInfoSerialization {
|
||||
// This should be the only adjacency function
|
||||
fun isAdjacentTo(terrainFilter:String): Boolean {
|
||||
// Rivers are odd, as they aren't technically part of any specific tile but still count towards adjacency
|
||||
if (terrainFilter == "River") return isAdjacentToRiver()
|
||||
if (terrainFilter == Constants.river) return isAdjacentToRiver()
|
||||
if (terrainFilter == Constants.freshWater && isAdjacentToRiver()) return true
|
||||
return (neighbors + this).any { neighbor -> neighbor.matchesFilter(terrainFilter) }
|
||||
}
|
||||
@ -485,7 +485,7 @@ open class Tile : IsPartOfGameInfoSerialization {
|
||||
"Water" -> isWater
|
||||
"Land" -> isLand
|
||||
Constants.coastal -> isCoastalTile()
|
||||
"River" -> isAdjacentToRiver()
|
||||
Constants.river -> isAdjacentToRiver()
|
||||
naturalWonder -> true
|
||||
"Open terrain" -> !isRoughTerrain()
|
||||
"Rough terrain" -> isRoughTerrain()
|
||||
|
@ -3,6 +3,7 @@ package com.unciv.logic.map.tile
|
||||
import com.unciv.Constants
|
||||
import com.unciv.logic.city.City
|
||||
import com.unciv.logic.civilization.Civilization
|
||||
import com.unciv.models.ruleset.tile.Terrain
|
||||
import com.unciv.models.ruleset.tile.TileImprovement
|
||||
import com.unciv.models.ruleset.unique.LocalUniqueCache
|
||||
import com.unciv.models.ruleset.unique.StateForConditionals
|
||||
@ -12,6 +13,7 @@ import com.unciv.models.stats.Stats
|
||||
import com.unciv.ui.components.extensions.toPercent
|
||||
|
||||
class TileStatFunctions(val tile: Tile) {
|
||||
private val riverTerrain by lazy { tile.ruleset.terrains[Constants.river] }
|
||||
|
||||
fun getTileStats(
|
||||
observingCiv: Civilization?,
|
||||
@ -53,7 +55,15 @@ class TileStatFunctions(val tile: Tile) {
|
||||
}
|
||||
}
|
||||
|
||||
if (tile.isAdjacentToRiver()) stats.gold++
|
||||
if (tile.isAdjacentToRiver()) {
|
||||
if (riverTerrain == null)
|
||||
stats.gold++ // Fallback for legacy mods
|
||||
else
|
||||
//TODO this is one approach to get these stats in - supporting only the Stats UniqueType.
|
||||
// Alternatives: append riverTerrain to allTerrains, or append riverTerrain.uniques to
|
||||
// the Tile's UniqueObjects/UniqueMap (while copying onl<e> base Stats directly here)
|
||||
stats.add(getSingleTerrainStats(riverTerrain!!, stateForConditionals))
|
||||
}
|
||||
|
||||
if (observingCiv != null) {
|
||||
// resource base
|
||||
@ -92,28 +102,37 @@ class TileStatFunctions(val tile: Tile) {
|
||||
}
|
||||
}
|
||||
|
||||
/** Gets stats of a single Terrain, unifying the Stats class a Terrain inherits and the Stats Unique
|
||||
* @return A Stats reference, must not be mutated
|
||||
*/
|
||||
private fun getSingleTerrainStats(terrain: Terrain, stateForConditionals: StateForConditionals): Stats {
|
||||
var stats: Stats = terrain
|
||||
|
||||
for (unique in terrain.getMatchingUniques(UniqueType.Stats, stateForConditionals)) {
|
||||
if (stats === terrain)
|
||||
stats = stats.clone()
|
||||
stats.add(unique.stats)
|
||||
}
|
||||
return stats
|
||||
}
|
||||
|
||||
/** Gets basic stats to start off [getTileStats] or [getTileStartYield], independently mutable result */
|
||||
private fun getTerrainStats(stateForConditionals: StateForConditionals = StateForConditionals()): Stats {
|
||||
var stats: Stats? = null
|
||||
var stats = Stats()
|
||||
|
||||
// allTerrains iterates over base, natural wonder, then features
|
||||
for (terrain in tile.allTerrains) {
|
||||
for (unique in terrain.getMatchingUniques(UniqueType.Stats, stateForConditionals)) {
|
||||
if (stats == null) {
|
||||
stats = unique.stats.clone()
|
||||
}
|
||||
else stats.add(unique.stats)
|
||||
}
|
||||
val terrainStats = getSingleTerrainStats(terrain, stateForConditionals)
|
||||
when {
|
||||
terrain.hasUnique(UniqueType.NullifyYields, stateForConditionals) ->
|
||||
return terrain.cloneStats()
|
||||
terrain.overrideStats || stats == null ->
|
||||
stats = terrain.cloneStats()
|
||||
return terrainStats.clone()
|
||||
terrain.overrideStats ->
|
||||
stats = terrainStats.clone()
|
||||
else ->
|
||||
stats.add(terrain)
|
||||
stats.add(terrainStats)
|
||||
}
|
||||
}
|
||||
return stats ?: Stats.ZERO // For tests
|
||||
return stats
|
||||
}
|
||||
|
||||
// Only gets the tile percentage bonus, not the improvement percentage bonus
|
||||
|
@ -121,8 +121,8 @@ class Terrain : RulesetStatsObject() {
|
||||
uniquesToCivilopediaTextLines(textList, leadingSeparator = null)
|
||||
|
||||
textList += FormattedLine()
|
||||
textList += if (impassable) FormattedLine(Constants.impassable, color="#A00")
|
||||
else FormattedLine("{Movement cost}: $movementCost")
|
||||
if (impassable) textList += FormattedLine(Constants.impassable, color="#A00")
|
||||
else if (movementCost > 0) textList += FormattedLine("{Movement cost}: $movementCost")
|
||||
|
||||
if (defenceBonus != 0f)
|
||||
textList += FormattedLine("{Defence bonus}: ${(defenceBonus * 100).toInt()}%")
|
||||
|
@ -285,7 +285,7 @@ enum class UniqueParameterType(
|
||||
/** Implemented by [Tile.matchesTerrainFilter][com.unciv.logic.map.tile.Tile.matchesTerrainFilter] */
|
||||
TerrainFilter("terrainFilter", Constants.freshWaterFilter, null, "Terrain Filters") {
|
||||
private val knownValues = setOf("All",
|
||||
Constants.coastal, "River", "Open terrain", "Rough terrain", "Water resource",
|
||||
Constants.coastal, Constants.river, "Open terrain", "Rough terrain", "Water resource",
|
||||
"Foreign Land", "Foreign", "Friendly Land", "Friendly", "Enemy Land", "Enemy",
|
||||
"Featureless", Constants.freshWaterFilter, "non-fresh water", "Natural Wonder",
|
||||
"Impassable", "Land", "Water") +
|
||||
|
@ -541,6 +541,8 @@ enum class UniqueType(val text: String, vararg targets: UniqueTarget, val flags:
|
||||
FreshWater(Constants.freshWater, UniqueTarget.Terrain),
|
||||
RoughTerrain("Rough terrain", UniqueTarget.Terrain),
|
||||
|
||||
ExcludedFromMapEditor("Excluded from map editor", UniqueTarget.Terrain, UniqueTarget.Improvement, UniqueTarget.Resource, UniqueTarget.Nation, flags = UniqueFlag.setOfHiddenToUsers),
|
||||
|
||||
/////// Resource uniques
|
||||
ResourceAmountOnTiles("Deposits in [tileFilter] tiles always provide [amount] resources", UniqueTarget.Resource),
|
||||
CityStateOnlyResource("Can only be created by Mercantile City-States", UniqueTarget.Resource),
|
||||
|
@ -14,16 +14,17 @@ import com.unciv.models.ruleset.tile.Terrain
|
||||
import com.unciv.models.ruleset.tile.TerrainType
|
||||
import com.unciv.models.ruleset.tile.TileImprovement
|
||||
import com.unciv.models.ruleset.tile.TileResource
|
||||
import com.unciv.models.ruleset.unique.StateForConditionals
|
||||
import com.unciv.models.ruleset.unique.UniqueType
|
||||
import com.unciv.models.translations.tr
|
||||
import com.unciv.ui.audio.MusicMood
|
||||
import com.unciv.ui.audio.MusicTrackChooserFlags
|
||||
import com.unciv.ui.components.widgets.TabbedPager
|
||||
import com.unciv.ui.components.extensions.center
|
||||
import com.unciv.ui.components.extensions.toLabel
|
||||
import com.unciv.ui.components.input.onClick
|
||||
import com.unciv.ui.components.tilegroups.TileGroup
|
||||
import com.unciv.ui.components.tilegroups.TileSetStrings
|
||||
import com.unciv.ui.components.widgets.TabbedPager
|
||||
import com.unciv.ui.images.ImageGetter
|
||||
import com.unciv.ui.screens.basescreen.BaseScreen
|
||||
import com.unciv.ui.screens.civilopediascreen.FormattedLine
|
||||
@ -57,6 +58,7 @@ class MapEditorEditTerrainTab(
|
||||
|
||||
private fun allTerrains() = ruleset.terrains.values.asSequence()
|
||||
.filter { it.type.isBaseTerrain }
|
||||
.filterNot { it.hasUnique(UniqueType.ExcludedFromMapEditor, StateForConditionals.IgnoreConditionals) }
|
||||
private fun getTerrains() = allTerrains()
|
||||
.map { FormattedLine(it.name, it.name, "Terrain/${it.name}", size = 32) }
|
||||
.asIterable()
|
||||
@ -80,7 +82,7 @@ class MapEditorEditFeaturesTab(
|
||||
val eraserIcon = "Terrain/${firstFeature.name}"
|
||||
val eraser = FormattedLine("Remove features", icon = eraserIcon, size = 32, iconCrossed = true)
|
||||
add(eraser.render(0f).apply { onClick {
|
||||
editTab.setBrush("Remove features", eraserIcon, true) { tile ->
|
||||
editTab.setBrush("Remove features", eraserIcon, pediaLink = "", isRemove = true) { tile ->
|
||||
tile.removeTerrainFeatures()
|
||||
}
|
||||
} }).padBottom(0f).row()
|
||||
@ -98,6 +100,7 @@ class MapEditorEditFeaturesTab(
|
||||
|
||||
private fun allowedFeatures() = ruleset.terrains.values.asSequence()
|
||||
.filter { it.type == TerrainType.TerrainFeature }
|
||||
.filterNot { it.hasUnique(UniqueType.ExcludedFromMapEditor, StateForConditionals.IgnoreConditionals) }
|
||||
private fun getFeatures() = allowedFeatures()
|
||||
.map { FormattedLine(it.name, it.name, "Terrain/${it.name}", size = 32) }
|
||||
.asIterable()
|
||||
@ -131,6 +134,7 @@ class MapEditorEditWondersTab(
|
||||
|
||||
private fun allowedWonders() = ruleset.terrains.values.asSequence()
|
||||
.filter { it.type == TerrainType.NaturalWonder }
|
||||
.filterNot { it.hasUnique(UniqueType.ExcludedFromMapEditor, StateForConditionals.IgnoreConditionals) }
|
||||
private fun getWonders() = allowedWonders()
|
||||
.map { FormattedLine(it.name, it.name, "Terrain/${it.name}", size = 32) }
|
||||
.asIterable()
|
||||
@ -154,7 +158,7 @@ class MapEditorEditResourcesTab(
|
||||
val eraserIcon = "Resource/${firstResource.name}"
|
||||
val eraser = FormattedLine("Remove resource", icon = eraserIcon, size = 32, iconCrossed = true)
|
||||
add(eraser.render(0f).apply { onClick {
|
||||
editTab.setBrush("Remove resource", eraserIcon, true) { tile ->
|
||||
editTab.setBrush("Remove resource", eraserIcon, pediaLink = "", isRemove = true) { tile ->
|
||||
tile.resource = null
|
||||
tile.resourceAmount = 0
|
||||
}
|
||||
@ -175,7 +179,8 @@ class MapEditorEditResourcesTab(
|
||||
}
|
||||
|
||||
private fun allowedResources() = ruleset.tileResources.values.asSequence()
|
||||
.filter { !it.hasUnique(UniqueType.CityStateOnlyResource) }
|
||||
.filterNot { it.hasUnique(UniqueType.CityStateOnlyResource) }
|
||||
.filterNot { it.hasUnique(UniqueType.ExcludedFromMapEditor, StateForConditionals.IgnoreConditionals) }
|
||||
private fun getResources(): Iterable<FormattedLine> = sequence {
|
||||
var lastGroup = ResourceType.Bonus
|
||||
for (resource in allowedResources()) {
|
||||
@ -207,7 +212,7 @@ class MapEditorEditImprovementsTab(
|
||||
val eraserIcon = "Improvement/${firstImprovement.name}"
|
||||
val eraser = FormattedLine("Remove improvement", icon = eraserIcon, size = 32, iconCrossed = true)
|
||||
add(eraser.render(0f).apply { onClick {
|
||||
editTab.setBrush("Remove improvement", eraserIcon, true) { tile ->
|
||||
editTab.setBrush("Remove improvement", eraserIcon, pediaLink = "", isRemove = true) { tile ->
|
||||
tile.removeImprovement()
|
||||
tile.removeRoad()
|
||||
}
|
||||
@ -230,9 +235,7 @@ class MapEditorEditImprovementsTab(
|
||||
}
|
||||
|
||||
private fun allowedImprovements() = ruleset.tileImprovements.values.asSequence()
|
||||
.filter { improvement ->
|
||||
disallowImprovements.none { improvement.name.startsWith(it) }
|
||||
}
|
||||
.filterNot { it.hasUnique(UniqueType.ExcludedFromMapEditor, StateForConditionals.IgnoreConditionals) }
|
||||
private fun getImprovements(): Iterable<FormattedLine> = sequence {
|
||||
var lastGroup = 0
|
||||
for (improvement in allowedImprovements()) {
|
||||
@ -249,10 +252,6 @@ class MapEditorEditImprovementsTab(
|
||||
override fun isDisabled() = allowedImprovements().none()
|
||||
|
||||
companion object {
|
||||
//todo This should really be easier, the attributes should allow such a test in one go
|
||||
private val disallowImprovements = listOf(
|
||||
Constants.cityCenter, Constants.repair, Constants.remove, Constants.cancelImprovementOrder
|
||||
)
|
||||
private fun TileImprovement.group() = when {
|
||||
RoadStatus.values().any { it.name == name } -> 2
|
||||
"Great Improvement" in uniques -> 3
|
||||
@ -277,48 +276,49 @@ class MapEditorEditStartsTab(
|
||||
allowedNations().firstOrNull()?.let { addNations(it) }
|
||||
}
|
||||
|
||||
private fun String.spectatorToAnyCiv() = if (this == Constants.spectator) "Any Civ" else this
|
||||
|
||||
private fun addNations(firstNation: Nation) {
|
||||
val eraserIcon = "Nation/${firstNation.name}"
|
||||
val eraser = FormattedLine("Remove starting locations", icon = eraserIcon, size = 24, iconCrossed = true)
|
||||
add(eraser.render(0f).apply { onClick {
|
||||
editTab.setBrush(BrushHandlerType.Direct, "Remove", eraserIcon, true) { tile ->
|
||||
editTab.setBrush(BrushHandlerType.Direct, "Remove", eraserIcon, pediaLink = "", isRemove = true) { tile ->
|
||||
tile.tileMap.removeStartingLocations(tile.position)
|
||||
}
|
||||
} }).padBottom(0f).row()
|
||||
// Create the nation list with the spectator nation included
|
||||
|
||||
// Create the nation list with the spectator nation included, and shown/interpreted as "Any Civ" starting location.
|
||||
// We use Nation/Spectator because it hasn't been used yet and we need an icon within the Nation.
|
||||
val anyCiv = FormattedLine("Any Civ starting location", Constants.spectator, "Nation/Spectator", size = 24)
|
||||
val nations = getNations().toList()
|
||||
val nationsToAdd = ArrayList<FormattedLine>(1 + nations.count())
|
||||
nationsToAdd.add((anyCiv)) // An Civ starting location should be first
|
||||
nationsToAdd.addAll(nations)
|
||||
add(
|
||||
MarkupRenderer.render(
|
||||
nationsToAdd,
|
||||
iconDisplay = FormattedLine.IconDisplay.NoLink
|
||||
) {
|
||||
UncivGame.Current.musicController.chooseTrack(it, MusicMood.Theme, MusicTrackChooserFlags.setSpecific)
|
||||
editTab.setBrush(BrushHandlerType.Direct, if (it ==Constants.spectator) "Any Civ" else it, "Nation/$it") { tile ->
|
||||
// toggle the starting location here, note this allows
|
||||
// both multiple locations per nation and multiple nations per tile
|
||||
if (!tile.tileMap.addStartingLocation(it, tile))
|
||||
tile.tileMap.removeStartingLocation(it, tile)
|
||||
getNations(),
|
||||
iconDisplay = FormattedLine.IconDisplay.NoLink
|
||||
) {
|
||||
UncivGame.Current.musicController.chooseTrack(it, MusicMood.Theme, MusicTrackChooserFlags.setSpecific)
|
||||
val icon = "Nation/$it"
|
||||
val pediaLink = if (it == Constants.spectator) "" else icon
|
||||
editTab.setBrush(BrushHandlerType.Direct, it.spectatorToAnyCiv(), icon, pediaLink) { tile ->
|
||||
// toggle the starting location here, note this allows
|
||||
// both multiple locations per nation and multiple nations per tile
|
||||
if (!tile.tileMap.addStartingLocation(it, tile))
|
||||
tile.tileMap.removeStartingLocation(it, tile)
|
||||
}
|
||||
}
|
||||
}).padTop(0f).row()
|
||||
).padTop(0f).row()
|
||||
}
|
||||
|
||||
private fun allowedNations() = ruleset.nations.values.asSequence()
|
||||
.filter { it.name !in disallowNations && !it.hasUnique(UniqueType.CityStateDeprecated) }
|
||||
.filterNot { it.hasUnique(UniqueType.ExcludedFromMapEditor) }
|
||||
private fun getNations() = allowedNations()
|
||||
.sortedWith(compareBy<Nation>{ it.isCityState }.thenBy(collator) { it.name.tr(hideIcons = true) })
|
||||
.map { FormattedLine("[${it.name}] starting location", it.name, "Nation/${it.name}", size = 24) }
|
||||
.asIterable()
|
||||
.sortedWith(
|
||||
compareBy<Nation> { !it.isSpectator }
|
||||
.thenBy { it.isCityState }
|
||||
.thenBy(collator) { it.name.tr(hideIcons = true) }
|
||||
).map {
|
||||
FormattedLine("[${it.name.spectatorToAnyCiv()}] starting location", link = it.name, icon = "Nation/${it.name}", size = 24)
|
||||
}.asIterable()
|
||||
|
||||
override fun isDisabled() = allowedNations().none()
|
||||
|
||||
companion object {
|
||||
private val disallowNations = setOf(Constants.spectator, Constants.barbarians)
|
||||
}
|
||||
}
|
||||
|
||||
|
||||
@ -336,13 +336,15 @@ class MapEditorEditRiversTab(
|
||||
?: ruleset.terrains.values.first()
|
||||
|
||||
init {
|
||||
val pediaLink = "Terrain/River"
|
||||
|
||||
top()
|
||||
defaults().pad(10f).left()
|
||||
val removeLine = Table().apply {
|
||||
add(getRemoveRiverIcon()).padRight(10f)
|
||||
add("Remove rivers".toLabel(fontSize = 32))
|
||||
onClick {
|
||||
editTab.setBrush(BrushHandlerType.River,"Remove rivers", getRemoveRiverIcon()) { tile ->
|
||||
editTab.setBrush(BrushHandlerType.River,"Remove rivers", getRemoveRiverIcon(), pediaLink) { tile ->
|
||||
tile.hasBottomLeftRiver = false
|
||||
tile.hasBottomRightRiver = false
|
||||
tile.hasBottomRiver = false
|
||||
@ -363,7 +365,7 @@ class MapEditorEditRiversTab(
|
||||
onClick {
|
||||
editTab.setBrush(BrushHandlerType.Direct,"Bottom left river", getTileGroupWithRivers(
|
||||
RiverEdge.Left
|
||||
)) { tile ->
|
||||
), pediaLink) { tile ->
|
||||
tile.hasBottomLeftRiver = !tile.hasBottomLeftRiver
|
||||
}
|
||||
}
|
||||
@ -376,7 +378,7 @@ class MapEditorEditRiversTab(
|
||||
onClick {
|
||||
editTab.setBrush(BrushHandlerType.Direct,"Bottom river", getTileGroupWithRivers(
|
||||
RiverEdge.Bottom
|
||||
)) { tile ->
|
||||
), pediaLink) { tile ->
|
||||
tile.hasBottomRiver = !tile.hasBottomRiver
|
||||
}
|
||||
}
|
||||
@ -389,7 +391,7 @@ class MapEditorEditRiversTab(
|
||||
onClick {
|
||||
editTab.setBrush(BrushHandlerType.Direct,"Bottom right river", getTileGroupWithRivers(
|
||||
RiverEdge.Right
|
||||
)) { tile ->
|
||||
), pediaLink) { tile ->
|
||||
tile.hasBottomRightRiver = !tile.hasBottomRightRiver
|
||||
}
|
||||
}
|
||||
@ -405,6 +407,7 @@ class MapEditorEditRiversTab(
|
||||
BrushHandlerType.RiverFromTo,
|
||||
name = "Spawn river from/to",
|
||||
icon = getTileGroupWithRivers(RiverEdge.All),
|
||||
pediaLink = pediaLink,
|
||||
applyAction = {} // Actual effect done via BrushHandlerType
|
||||
)
|
||||
}
|
||||
|
@ -3,6 +3,7 @@ package com.unciv.ui.screens.mapeditorscreen.tabs
|
||||
import com.badlogic.gdx.graphics.Color
|
||||
import com.badlogic.gdx.scenes.scene2d.Actor
|
||||
import com.badlogic.gdx.scenes.scene2d.Group
|
||||
import com.badlogic.gdx.scenes.scene2d.Touchable
|
||||
import com.badlogic.gdx.scenes.scene2d.ui.Cell
|
||||
import com.badlogic.gdx.scenes.scene2d.ui.Table
|
||||
import com.unciv.logic.map.BFS
|
||||
@ -12,15 +13,18 @@ import com.unciv.logic.map.mapgenerator.RiverGenerator
|
||||
import com.unciv.logic.map.tile.Tile
|
||||
import com.unciv.models.ruleset.Ruleset
|
||||
import com.unciv.models.translations.tr
|
||||
import com.unciv.ui.components.widgets.TabbedPager
|
||||
import com.unciv.ui.components.widgets.UncivSlider
|
||||
import com.unciv.ui.components.extensions.addSeparator
|
||||
import com.unciv.ui.components.extensions.toLabel
|
||||
import com.unciv.ui.components.input.KeyCharAndCode
|
||||
import com.unciv.ui.components.input.KeyboardBinding
|
||||
import com.unciv.ui.components.input.keyShortcuts
|
||||
import com.unciv.ui.components.input.onActivation
|
||||
import com.unciv.ui.components.widgets.TabbedPager
|
||||
import com.unciv.ui.components.widgets.UncivSlider
|
||||
import com.unciv.ui.images.ImageGetter
|
||||
import com.unciv.ui.popups.ToastPopup
|
||||
import com.unciv.ui.screens.basescreen.BaseScreen
|
||||
import com.unciv.ui.screens.civilopediascreen.CivilopediaScreen
|
||||
import com.unciv.ui.screens.civilopediascreen.FormattedLine
|
||||
import com.unciv.ui.screens.mapeditorscreen.MapEditorScreen
|
||||
import com.unciv.ui.screens.mapeditorscreen.TileInfoNormalizer
|
||||
@ -136,27 +140,43 @@ class MapEditorEditTab(
|
||||
|
||||
private fun selectPage(index: Int) = subTabs.selectPage(index)
|
||||
|
||||
fun setBrush(name: String, icon: String, isRemove: Boolean = false, applyAction: (Tile)->Unit) {
|
||||
private fun linkCivilopedia(brushActor: Actor, link: String) {
|
||||
if (link.isEmpty()) return
|
||||
brushActor.touchable = Touchable.enabled
|
||||
// As so often, doing the binding separately to avoid the tooltip
|
||||
brushActor.onActivation {
|
||||
editorScreen.game.pushScreen(CivilopediaScreen(ruleset, link = link))
|
||||
}
|
||||
brushActor.keyShortcuts.add(KeyboardBinding.Civilopedia)
|
||||
}
|
||||
|
||||
// "Normal" setBrush overload, using named RulesetObject icon
|
||||
fun setBrush(name: String, icon: String, pediaLink: String = icon, isRemove: Boolean = false, applyAction: (Tile)->Unit) {
|
||||
brushHandlerType = BrushHandlerType.Tile
|
||||
brushCell.setActor(FormattedLine(name, icon = icon, iconCrossed = isRemove).render(0f))
|
||||
val brushActor = FormattedLine(name, icon = icon, iconCrossed = isRemove).render(0f)
|
||||
linkCivilopedia(brushActor, pediaLink)
|
||||
brushCell.setActor(brushActor)
|
||||
brushAction = applyAction
|
||||
}
|
||||
private fun setBrush(name: String, icon: Actor, applyAction: (Tile)->Unit) {
|
||||
// Helper overload for brushes using icons not existing as RulesetObject
|
||||
private fun setBrush(name: String, icon: Actor, pediaLink: String, applyAction: (Tile)->Unit) {
|
||||
brushHandlerType = BrushHandlerType.Tile
|
||||
val line = Table().apply {
|
||||
add(icon).padRight(10f)
|
||||
add(name.toLabel())
|
||||
}
|
||||
linkCivilopedia(line, pediaLink)
|
||||
brushCell.setActor(line)
|
||||
brushAction = applyAction
|
||||
}
|
||||
fun setBrush(handlerType: BrushHandlerType, name: String, icon: String,
|
||||
isRemove: Boolean = false, applyAction: (Tile)->Unit) {
|
||||
setBrush(name, icon, isRemove, applyAction)
|
||||
// This overload is used by Roads and Starting locations
|
||||
fun setBrush(handlerType: BrushHandlerType, name: String, icon: String, pediaLink: String = icon, isRemove: Boolean = false, applyAction: (Tile)->Unit) {
|
||||
setBrush(name, icon, pediaLink, isRemove, applyAction)
|
||||
brushHandlerType = handlerType
|
||||
}
|
||||
fun setBrush(handlerType: BrushHandlerType, name: String, icon: Actor, applyAction: (Tile)->Unit) {
|
||||
setBrush(name, icon, applyAction)
|
||||
// This overload is used by Rivers
|
||||
fun setBrush(handlerType: BrushHandlerType, name: String, icon: Actor, pediaLink: String, applyAction: (Tile)->Unit) {
|
||||
setBrush(name, icon, pediaLink, applyAction)
|
||||
brushHandlerType = handlerType
|
||||
}
|
||||
|
||||
|
@ -899,6 +899,9 @@ Simple unique parameters are explained by mouseover. Complex parameters are expl
|
||||
??? example "Units ignore terrain costs when moving into any tile with Hills"
|
||||
Applicable to: Nation
|
||||
|
||||
??? example "Excluded from map editor"
|
||||
Applicable to: Nation, Terrain, Improvement, Resource
|
||||
|
||||
??? example "Will not be displayed in Civilopedia"
|
||||
Applicable to: Nation, Tech, Policy, Building, Unit, UnitType, Promotion, Terrain, Improvement, Resource, Ruins
|
||||
|
||||
|
Loading…
x
Reference in New Issue
Block a user