Regions part 3 - resource placement, resource settings (#5690)

* placeLuxuries

* map resource settings

* strategic and bonus resources

* terrain fixes

* slight optimizations

* vanilla jsons

* fix luxury terrain distribution

* also for vanilla

* fix ruleset bug

* terrainfilter
This commit is contained in:
SimonCeder
2021-12-07 06:25:16 +01:00
committed by GitHub
parent 4bc8c83555
commit 24bd2b66b0
14 changed files with 1204 additions and 572 deletions

View File

@ -15,7 +15,8 @@
"movementCost": 1,
"RGB": [107,167,193],
"uniques": ["[+2] to Fertility for Map Generation",
"Considered [Desirable] when determining start locations <on water maps>"]
"Considered [Desirable] when determining start locations <on water maps>",
"Every [60] tiles with this terrain will receive a major deposit of a strategic resource."]
},
{
"name": "Grassland",
@ -39,7 +40,8 @@
"Considered [Food] when determining start locations <in [Forest] Regions>",
"Considered [Food] when determining start locations <in [Hill] Regions>",
"Considered [Food] when determining start locations <in [Grassland] Regions>",
"Considered [Food] when determining start locations <in [Hybrid] Regions>"]
"Considered [Food] when determining start locations <in [Hybrid] Regions>",
"Every [33] tiles with this terrain will receive a major deposit of a strategic resource."]
},
{
"name": "Plains",
@ -67,7 +69,8 @@
"Considered [Food] when determining start locations <in [Desert] Regions>",
"Considered [Food] when determining start locations <in [Hill] Regions>",
"Considered [Food] when determining start locations <in [Plains] Regions>",
"Considered [Food] when determining start locations <in [Hybrid] Regions>"]
"Considered [Food] when determining start locations <in [Hybrid] Regions>",
"Every [33] tiles with this terrain will receive a major deposit of a strategic resource."]
},
{
"name": "Tundra",
@ -83,7 +86,8 @@
"[+2] to Fertility for Map Generation",
"A Region is formed with at least [30]% [Tundra] tiles and [Snow] tiles, with priority [1]",
"Considered [Food] when determining start locations <in [Tundra] Regions>",
"Considered [Desirable] when determining start locations <in [Tundra] Regions>"]
"Considered [Desirable] when determining start locations <in [Tundra] Regions>",
"Every [16] tiles with this terrain will receive a major deposit of a strategic resource."]
},
{
"name": "Desert",
@ -97,7 +101,8 @@
"Occurs at temperature between [0.5] and [0.6] and humidity between [0.5] and [0.7]",
"[+1] to Fertility for Map Generation",
"A Region is formed with at least [25]% [Desert] tiles, with priority [4]",
"Considered [Undesirable] when determining start locations <in all except [Desert] Regions>"]
"Considered [Undesirable] when determining start locations <in all except [Desert] Regions>",
"Every [13] tiles with this terrain will receive a major deposit of a strategic resource."]
},
{
"name": "Lakes",
@ -133,7 +138,9 @@
"Occurs at temperature between [-0.7] and [-0.6] and humidity between [0] and [0.4]",
"Occurs at temperature between [-0.6] and [-0.5] and humidity between [0] and [0.2]",
"Always Fertility [-1] for Map Generation",
"Considered [Undesirable] when determining start locations"]
"Considered [Undesirable] when determining start locations",
"Every [17] tiles with this terrain will receive a major deposit of a strategic resource.",
"Never receives any resources <in [Hill] tiles>"]
},
// Terrain features
@ -153,8 +160,10 @@
"[+1] to Fertility for Map Generation",
"A Region is formed with at least [40]% [Hill] tiles, with priority [5]",
"Base Terrain on this tile is not counted for Region determination",
"Starts in regions of this type receive an extra [Sheep]",
"Considered [Desirable] when determining start locations",
"Considered [Production] when determining start locations"]
"Considered [Production] when determining start locations",
"Every [22] tiles with this terrain will receive a major deposit of a strategic resource."]
},
{
"name": "Forest",
@ -176,7 +185,8 @@
"Considered [Desirable] when determining start locations",
"Considered [Production] when determining start locations",
"Considered [Food] when determining start locations <in [Forest] Regions>",
"Considered [Food] when determining start locations <in [Tundra] Regions>"],
"Considered [Food] when determining start locations <in [Tundra] Regions>",
"Every [39] tiles with this terrain will receive a major deposit of a strategic resource."],
"civilopediaText": [{"text":"A Camp can be built here without cutting it down", "link":"Improvement/Camp"}]
},
{
@ -196,7 +206,8 @@
"A Region is formed with at least [35]% [Jungle] tiles and [Forest] tiles, with priority [2]",
"A Region can not contain more [Forest] tiles than [Jungle] tiles",
"Considered [Food] when determining start locations <in all except [Grassland] Regions>",
"Considered [Desirable] when determining start locations <in all except [Grassland] Regions>"]
"Considered [Desirable] when determining start locations <in all except [Grassland] Regions>",
"Every [33] tiles with this terrain will receive a major deposit of a strategic resource."]
},
{
"name": "Marsh",
@ -207,7 +218,8 @@
"defenceBonus": -0.15,
"occursOn": ["Grassland"],
"uniques": ["Rare feature",
"[-2] to Fertility for Map Generation"],
"[-2] to Fertility for Map Generation",
"Every [9] tiles with this terrain will receive a major deposit of a strategic resource."],
"civilopediaText": [{"text":"Only Polders can be built here", "link":"Improvement/Polder"}]
},
{

View File

@ -6,23 +6,33 @@
"terrainsCanBeFoundOn": ["Grassland"],
"food": 1,
"improvement": "Pasture",
"improvementStats": {"production": 1}
"improvementStats": {"production": 1},
"uniques": ["Generated on every [18] tiles <in [Featureless] [Grassland] tiles>",
"Generated on every [22] tiles <in [Featureless] [Grassland] tiles> <in [Hill] Regions>"]
},
{
"name": "Sheep",
"resourceType": "Bonus",
"terrainsCanBeFoundOn": ["Plains","Hill"],
"terrainsCanBeFoundOn": ["Hill"],
"food": 1,
"improvement": "Pasture",
"improvementStats": {"food": 1}
"improvementStats": {"food": 1},
"uniques": ["Generated on every [13] tiles <in [Hill] tiles> <in tiles without [Forest]> <in tiles without [Jungle]>",
"Generated on every [10] tiles <in [Hill] tiles> <in tiles without [Forest]> <in tiles without [Jungle]> <in tiles without [Fresh Water]> <in [Hill] Regions>"]
},
{
"name": "Deer",
"resourceType": "Bonus",
"terrainsCanBeFoundOn": ["Forest","Tundra"],
"terrainsCanBeFoundOn": ["Forest","Tundra"], // Tundra only if lowland
"food": 1,
"improvement": "Camp",
"improvementStats": {"production": 1}
"improvementStats": {"production": 1},
"uniques": ["Generated on every [8] tiles <in [Tundra] [Forest] tiles>",
"Generated on every [12] tiles <in [Featureless] [Tundra] tiles>",
"Generated on every [25] tiles <in [Plains] [Forest] tiles> <in tiles without [Hill]>",
"Generated on every [25] tiles <in [Grassland] [Forest] tiles> <in tiles without [Hill]>",
"Generated on every [16] tiles <in [Featureless] [Tundra] tiles> <in [Hill] Regions>",
"Generated on every [28] tiles <in [Forest] tiles> <in [Hill] Regions>"]
},
{
"name": "Bananas",
@ -30,23 +40,32 @@
"terrainsCanBeFoundOn": ["Jungle"],
"food": 1,
"improvement": "Plantation",
"improvementStats": {"food": 2,"production": -1}
"improvementStats": {"food": 2,"production": -1},
"uniques": ["Generated on every [14] tiles <in [Jungle] tiles>",
"Generated on every [16] tiles <in [Jungle] tiles> <in [Hill] Regions>"]
},
{
"name": "Wheat",
"resourceType": "Bonus",
"terrainsCanBeFoundOn": ["Plains","Flood plains","Desert"],
"terrainsCanBeFoundOn": ["Plains","Flood plains","Desert"], // Desert only if fresh water
"food": 1,
"improvement": "Farm",
"improvementStats": {"food": 1}
"improvementStats": {"food": 1},
"uniques": ["Generated on every [27] tiles <in [Featureless] [Plains] tiles>",
"Generated on every [10] tiles <in [Desert] [Fresh Water] tiles> <in tiles without [Hill]>",
"Generated on every [20] tiles <in [Featureless] [Plains] tiles> <in [Hill] Regions>",
"Generated on every [20] tiles <in [Fresh Water] [Desert] tiles> <in tiles without [Hill]> <in [Hill] Regions>"]
},
{
"name": "Stone",
"resourceType": "Bonus",
"terrainsCanBeFoundOn": ["Plains","Desert","Snow"],
"terrainsCanBeFoundOn": ["Grassland","Desert","Tundra"],
"production": 1,
"improvement": "Quarry",
"improvementStats": {"production": 1},
"uniques": ["Generated on every [20] tiles <in [Featureless] [Grassland] tiles> <in tiles without [Fresh Water]>",
"Generated on every [15] tiles <in [Featureless] [Tundra] tiles>",
"Generated on every [19] tiles <in [Featureless] [Desert] tiles>"]
},
{
"name": "Fish",
@ -54,7 +73,8 @@
"terrainsCanBeFoundOn": ["Coast"],
"food": 1,
"improvement": "Fishing Boats",
"improvementStats": {"food": 1}
"improvementStats": {"food": 1},
"uniques": ["Generated on every [10] tiles <in [Featureless] [Coast] tiles>"]
},
/*
{
@ -72,10 +92,18 @@
"name": "Horses",
"resourceType": "Strategic",
"revealedBy": "Animal Husbandry",
"terrainsCanBeFoundOn": ["Plains","Grassland","Hill","Desert"],
"terrainsCanBeFoundOn": ["Plains","Grassland","Hill"], // Hill only if plains or grassland
"production": 1,
"improvement": "Pasture",
"improvementStats": {"production": 1},
"uniques": ["Guaranteed with Strategic Balance resource option",
"Generated with weight [100] <in [Featureless] [Grassland] tiles>",
"Generated with weight [100] <in [Featureless] [Plains] tiles>",
"Minor deposits generated with weight [10] <in [Grassland] [Hill] tiles> <in tiles without [Forest]> <in tiles without [Jungle]>",
"Minor deposits generated with weight [10] <in [Plains] [Hill] tiles> <in tiles without [Forest]> <in tiles without [Jungle]>",
"Minor deposits generated with weight [100] <in [Featureless] [Grassland] tiles> <in [Fresh Water] tiles>",
"Minor deposits generated with weight [20] <in [Featureless] [Grassland] tiles> <in tiles without [Fresh Water]>",
"Minor deposits generated with weight [30] <in [Featureless] [Plains] tiles>"],
"majorDepositAmount": {"sparse": 4, "default": 4, "abundant": 6},
"minorDepositAmount": {"sparse": 1, "default": 2, "abundant": 3}
},
@ -83,21 +111,46 @@
"name": "Iron",
"resourceType": "Strategic",
"revealedBy": "Iron Working",
"terrainsCanBeFoundOn": ["Grassland","Plains","Desert","Tundra","Snow","Hill"],
"terrainsCanBeFoundOn": ["Grassland","Plains","Desert","Tundra","Snow","Hill","Marsh"],
"production": 1,
"improvement": "Mine",
"improvementStats": {"production": 1},
"uniques": ["Guaranteed with Strategic Balance resource option",
"Generated with weight [45] <in [Featureless] [Tundra] tiles>",
"Generated with weight [25] <in [Featureless] [Snow] tiles>",
"Generated with weight [35] <in [Featureless] [Desert] tiles>",
"Generated with weight [26] <in [Hill] tiles>",
"Minor deposits generated with weight [10] <in [Marsh] tiles> <in tiles without [Hill]>",
"Minor deposits generated with weight [10] <in [Jungle] [Hill] tiles>",
"Minor deposits generated with weight [20] <in [Forest] tiles>",
"Minor deposits generated with weight [20] <in [Hill] tiles> <in tiles without [Forest]> <in tiles without [Jungle]>",
"Minor deposits generated with weight [30] <in [Featureless] [Grassland] tiles> <in tiles without [Fresh Water]>",
"Minor deposits generated with weight [20] <in [Featureless] [Plains] tiles>",
"Minor deposits generated with weight [10] <in [Featureless] [Desert] tiles>",
"Minor deposits generated with weight [10] <in [Featureless] [Tundra] tiles>",
"Minor deposits generated with weight [10] <in [Featureless] [Snow] tiles>"],
"majorDepositAmount": {"sparse": 4, "default": 6, "abundant": 9},
"minorDepositAmount": {"sparse": 1, "default": 2, "abundant": 3}
},
{
"name": "Coal",
"resourceType": "Strategic",
"revealedBy": "Industrialization",
"terrainsCanBeFoundOn": ["Grassland","Plains","Hill"],
"revealedBy": "Scientific Theory",
"terrainsCanBeFoundOn": ["Grassland","Plains","Hill","Jungle","Forest","Marsh"],
"production": 1,
"improvement": "Mine",
"improvementStats": {"production": 2},
"uniques": ["Generated with weight [35] <in [Hill] tiles>",
"Generated with weight [30] <in [Jungle] tiles> <in tiles without [Hill]>",
"Generated with weight [30] <in [Forest] tiles> <in tiles without [Hill]>",
"Minor deposits generated with weight [10] <in [Marsh] tiles> <in tiles without [Hill]>",
"Minor deposits generated with weight [10] <in [Jungle] tiles>",
"Minor deposits generated with weight [10] <in [Forest] tiles>",
"Minor deposits generated with weight [20] <in [Grassland] [Hill] tiles>",
"Minor deposits generated with weight [20] <in [Plains] [Hill] tiles>",
"Minor deposits generated with weight [30] <in [Desert] [Hill] tiles>",
"Minor deposits generated with weight [30] <in [Tundra] [Hill] tiles>",
"Minor deposits generated with weight [30] <in [Snow] [Hill] tiles>"],
"majorDepositAmount": {"sparse": 5, "default": 7, "abundant": 10},
"minorDepositAmount": {"sparse": 2, "default": 3, "abundant": 3}
},
@ -109,7 +162,18 @@
"production": 1,
"improvement": "Oil well",
"improvementStats": {"production": 3},
"uniques": ["Deposits in [Water] tiles always provide [4] resources"],
"uniques": ["Deposits in [Coast] tiles always provide [4] resources",
"Guaranteed with Strategic Balance resource option",
"Generated with weight [65] <in [Marsh] tiles> <in tiles without [Hill]>",
"Generated with weight [40] <in [Featureless] [Tundra] tiles>",
"Generated with weight [60] <in [Featureless] [Snow] tiles>",
"Generated with weight [65] <in [Featureless] [Desert] tiles>",
"Generated with weight [100] <in [Featureless] [Coast] tiles>",
"Minor deposits generated with weight [20] <in [Marsh] tiles> <in tiles without [Hill]>",
"Minor deposits generated with weight [10] <in [Jungle] tiles> <in tiles without [Hill]>",
"Minor deposits generated with weight [10] <in [Featureless] [Desert] tiles>",
"Minor deposits generated with weight [20] <in [Featureless] [Tundra] tiles>",
"Minor deposits generated with weight [20] <in [Featureless] [Snow] tiles>"],
"majorDepositAmount": {"sparse": 5, "default": 7, "abundant": 9},
"minorDepositAmount": {"sparse": 2, "default": 3, "abundant": 3}
},
@ -117,10 +181,15 @@
"name": "Aluminum",
"resourceType": "Strategic",
"revealedBy": "Electricity",
"terrainsCanBeFoundOn": ["Plains","Desert","Tundra","Hill"],
"terrainsCanBeFoundOn": ["Desert","Tundra","Hill","Snow","Jungle"],
"production": 1,
"improvement": "Mine",
"improvementStats": {"production": 2},
"uniques": ["Generated with weight [15] <in [Featureless] [Tundra] tiles>",
"Generated with weight [15] <in [Featureless] [Snow] tiles>",
"Generated with weight [39] <in [Hill] tiles>",
"Minor deposits generated with weight [20] <in [Jungle] tiles>",
"Minor deposits generated with weight [10] <in [Featureless] [Desert] tiles>"],
"majorDepositAmount": {"sparse": 5, "default": 8, "abundant": 10},
"minorDepositAmount": {"sparse": 2, "default": 3, "abundant": 3}
},
@ -128,10 +197,16 @@
"name": "Uranium",
"resourceType": "Strategic",
"revealedBy": "Atomic Theory",
"terrainsCanBeFoundOn": ["Plains","Desert","Tundra","Hill","Snow","Forest","Desert","Marsh","Grassland"],
"terrainsCanBeFoundOn": ["Marsh","Jungle","Forest","Tundra","Snow"],
"production": 1,
"improvement": "Mine",
"improvementStats": {"production": 2},
"uniques": ["Generated with weight [35] <in [Marsh] tiles> <in tiles without [Hill]>",
"Generated with weight [70] <in [Jungle] tiles> <in tiles without [Hill]>",
"Generated with weight [70] <in [Forest] tiles> <in tiles without [Hill]>",
"Minor deposits generated with weight [10] <in [Forest] tiles>",
"Minor deposits generated with weight [10] <in [Featureless] [Tundra] tiles>",
"Minor deposits generated with weight [10] <in [Featureless] [Snow] tiles>"],
"majorDepositAmount": {"sparse": 2, "default": 4, "abundant": 4},
"minorDepositAmount": {"sparse": 1, "default": 2, "abundant": 3}
},
@ -144,122 +219,137 @@
"gold": 2,
"improvement": "Camp",
"improvementStats": {"gold": 1},
"uniques": ["Appears in [Tundra] regions with weight [40]",
"Appears in [Forest] regions with weight [10]",
"Appears near City States with weight [15]"]
"uniques": ["Generated with weight [40] <in [Tundra] Regions>",
"Generated with weight [10] <in [Forest] Regions>",
"Generated near City States with weight [15]"]
},
{
"name": "Cotton",
"resourceType": "Luxury",
"terrainsCanBeFoundOn": ["Grassland","Plains","Desert"],
"terrainsCanBeFoundOn": ["Grassland","Flood plains"],
"gold": 2,
"improvement": "Plantation",
"improvementStats": {"gold": 1},
"uniques": ["Appears in [Desert] regions with weight [15]",
"Appears in [Grassland] regions with weight [30]",
"Appears in [Hybrid] regions with weight [15]",
"Appears near City States with weight [10]"]
"uniques": ["Generated with weight [15] <in [Desert] Regions>",
"Generated with weight [30] <in [Grassland] Regions>",
"Generated with weight [15] <in [Hybrid] Regions>",
"Generated near City States with weight [10]",
"Doesn't generate naturally <in [Hill] tiles>"]
},
{
"name": "Dyes",
"resourceType": "Luxury",
"terrainsCanBeFoundOn": ["Jungle","Forest"],
"terrainsCanBeFoundOn": ["Jungle","Forest","Marsh"],
"gold": 2,
"improvement": "Plantation",
"improvementStats": {"gold": 1},
"uniques": ["Appears in [Tundra] regions with weight [5]",
"Appears in [Jungle] regions with weight [5]",
"Appears in [Forest] regions with weight [30]",
"Appears near City States with weight [10]"]
"uniques": ["Generated with weight [5] <in [Tundra] Regions>",
"Generated with weight [5] <in [Jungle] Regions>",
"Generated with weight [30] <in [Forest] Regions>",
"Generated near City States with weight [10]",
"Doesn't generate naturally <in [Hill] tiles>"]
},
{
"name": "Gems",
"resourceType": "Luxury",
"terrainsCanBeFoundOn": ["Jungle","Grassland","Plains","Desert","Tundra","Hill"],
"terrainsCanBeFoundOn": ["Jungle","Forest","Hill"],
"gold": 3,
"improvement": "Mine",
"improvementStats": {"production": 1},
"uniques": ["Appears in [Tundra] regions with weight [5]",
"Appears in [Jungle] regions with weight [20]",
"Appears in [Hill] regions with weight [15]",
"Appears in [Grassland] regions with weight [5]",
"Appears in [Hybrid] regions with weight [5]",
"Appears near City States with weight [10]"]
"uniques": ["Generated with weight [5] <in [Tundra] Regions>",
"Generated with weight [20] <in [Jungle] Regions>",
"Generated with weight [15] <in [Hill] Regions>",
"Generated with weight [5] <in [Grassland] Regions>",
"Generated with weight [5] <in [Hybrid] Regions>",
"Generated near City States with weight [10]",
"Doesn't generate naturally <in [Forest] tiles> <in tiles without [Hill]>"]
},
{
"name": "Gold Ore", // Not called "Gold" in order to not conflict with siege type units for translations
"resourceType": "Luxury",
"terrainsCanBeFoundOn": ["Grassland","Plains","Desert","Hill"],
"terrainsCanBeFoundOn": ["Desert","Hill","Forest","Jungle"],
"gold": 2,
"improvement": "Mine",
"improvementStats": {"production": 1},
"uniques": ["Appears in [Desert] regions with weight [25]",
"Appears in [Hill] regions with weight [30]",
"Appears in [Plains] regions with weight [5]",
"Appears in [Hybrid] regions with weight [5]",
"Appears near City States with weight [10]"]
"uniques": ["Generated with weight [25] <in [Desert] Regions>",
"Generated with weight [30] <in [Hill] Regions>",
"Generated with weight [5] <in [Plains] Regions>",
"Generated with weight [5] <in [Hybrid] Regions>",
"Generated near City States with weight [10]",
"Doesn't generate naturally <in [Forest] tiles> <in tiles without [Hill]>",
"Doesn't generate naturally <in [Jungle] tiles> <in tiles without [Hill]>"]
},
{
"name": "Silver",
"resourceType": "Luxury",
"terrainsCanBeFoundOn": ["Desert","Tundra","Hill"],
"terrainsCanBeFoundOn": ["Hill","Forest","Jungle","Tundra","Grassland"],
"gold": 2,
"improvement": "Mine",
"improvementStats": {"production": 1},
"uniques": ["Appears in [Tundra] regions with weight [25]",
"Appears in [Hill] regions with weight [30]",
"Appears in [Grassland] regions with weight [20]",
"Appears in [Hybrid] regions with weight [10]",
"Appears near City States with weight [10]"]
"uniques": ["Generated with weight [25] <in [Tundra] Regions>",
"Generated with weight [30] <in [Hill] Regions>",
"Generated with weight [20] <in [Grassland] Regions>",
"Generated with weight [10] <in [Hybrid] Regions>",
"Generated near City States with weight [10]",
"Doesn't generate naturally <in [Forest] tiles> <in tiles without [Hill]>",
"Doesn't generate naturally <in [Jungle] tiles> <in tiles without [Hill]>",
"Doesn't generate naturally <in [Tundra] [Hill] tiles>",
"Doesn't generate naturally <in [Grassland] [Fresh Water] tiles>",
"Doesn't generate naturally <in [Grassland] [Hill] tiles>"
]
},
{
"name": "Incense",
"resourceType": "Luxury",
"terrainsCanBeFoundOn": ["Plains","Desert"],
"terrainsCanBeFoundOn": ["Plains","Desert","Flood plains"],
"gold": 2,
"improvement": "Plantation",
"improvementStats": {"gold": 1},
"uniques": ["Appears in [Desert] regions with weight [35]",
"Appears in [Plains] regions with weight [10]",
"Appears in [Hybrid] regions with weight [5]",
"Appears near City States with weight [15]"]
"uniques": ["Generated with weight [35] <in [Desert] Regions>",
"Generated with weight [10] <in [Plains] Regions>",
"Generated with weight [5] <in [Hybrid] Regions>",
"Generated near City States with weight [15]"]
},
{
"name": "Ivory",
"resourceType": "Luxury",
"terrainsCanBeFoundOn": ["Plains"],
"terrainsCanBeFoundOn": ["Plains","Grassland"],
"gold": 2,
"improvement": "Camp",
"improvementStats": {"gold": 1},
"uniques": ["Appears in [Plains] regions with weight [35]",
"Appears in [Hybrid] regions with weight [15]",
"Appears near City States with weight [10]"]
"uniques": ["Generated with weight [35] <in [Plains] Regions>",
"Generated with weight [15] <in [Hybrid] Regions>",
"Generated near City States with weight [10]",
"Doesn't generate naturally <in [Grassland] [Fresh Water] tiles>"]
},
{
"name": "Silk",
"resourceType": "Luxury",
"terrainsCanBeFoundOn": ["Forest"],
"terrainsCanBeFoundOn": ["Forest","Jungle"],
"gold": 2,
"improvement": "Plantation",
"improvementStats": {"gold": 1},
"uniques": ["Appears in [Jungle] regions with weight [5]",
"Appears in [Forest] regions with weight [30]",
"Appears in [Hybrid] regions with weight [5]",
"Appears near City States with weight [15]"]
"uniques": ["Generated with weight [5] <in [Jungle] Regions>",
"Generated with weight [30] <in [Forest] Regions>",
"Generated with weight [5] <in [Hybrid] Regions>",
"Generated near City States with weight [15]",
"Doesn't generate naturally <in [Hill] tiles>"]
},
{
"name": "Spices",
"resourceType": "Luxury",
"terrainsCanBeFoundOn": ["Jungle","Forest"],
"terrainsCanBeFoundOn": ["Jungle","Forest","Marsh"],
"gold": 2,
"improvement": "Plantation",
"improvementStats": {"gold": 1},
"uniques": ["Appears in [Jungle] regions with weight [30]",
"Appears in [Forest] regions with weight [10]",
"Appears in [Plains] regions with weight [5]",
"Appears in [Grassland] regions with weight [5]",
"Appears in [Hybrid] regions with weight [5]",
"Appears near City States with weight [15]"]
"uniques": ["Generated with weight [30] <in [Jungle] Regions>",
"Generated with weight [10] <in [Forest] Regions>",
"Generated with weight [5] <in [Plains] Regions>",
"Generated with weight [5] <in [Grassland] Regions>",
"Generated with weight [5] <in [Hybrid] Regions>",
"Generated near City States with weight [15]",
"Doesn't generate naturally <in [Hill] tiles>",
"Doesn't generate naturally <in [Tundra] [Forest] tiles>"]
},
{
"name": "Wine",
@ -268,32 +358,35 @@
"gold": 2,
"improvement": "Plantation",
"improvementStats": {"gold": 1},
"uniques": ["Appears in [Plains] regions with weight [35]",
"Appears in [Hybrid] regions with weight [15]",
"Appears near City States with weight [10]"]
"uniques": ["Generated with weight [35] <in [Plains] Regions>",
"Generated with weight [15] <in [Hybrid] Regions>",
"Generated near City States with weight [10]"]
},
{
"name": "Sugar",
"resourceType": "Luxury",
"terrainsCanBeFoundOn": ["Plains","Flood plains","Grassland","Marsh"],
"terrainsCanBeFoundOn": ["Flood plains","Grassland","Marsh"],
// Technically sugar can also be placed on lowland jungles which then *turn* into marsh.
"gold": 2,
"improvement": "Plantation",
"improvementStats": {"gold": 1},
"uniques": ["Appears in [Jungle] regions with weight [20]",
"Appears in [Desert] regions with weight [15]",
"Appears in [Grassland] regions with weight [20]",
"Appears in [Hybrid] regions with weight [5]",
"Appears near City States with weight [10]"]
"uniques": ["Generated with weight [20] <in [Jungle] Regions>",
"Generated with weight [15] <in [Desert] Regions>",
"Generated with weight [20] <in [Grassland] Regions>",
"Generated with weight [5] <in [Hybrid] Regions>",
"Generated near City States with weight [10]",
"Doesn't generate naturally <in [Grassland] tiles> <in tiles without [Fresh Water]>"]
},
{
"name": "Marble",
"resourceType": "Luxury",
"terrainsCanBeFoundOn": ["Desert","Plains","Tundra","Hill","Grassland"],
"terrainsCanBeFoundOn": ["Desert","Plains","Hill","Grassland"],
"gold": 2,
"improvement": "Quarry",
"improvementStats": {"production": 1},
"uniques": ["[+15]% Production when constructing [All] wonders [in all cities]",
"Special placement during map generation"]
"Special placement during map generation",
"Doesn't generate naturally <in [Grassland] [Fresh Water] tiles>"]
},
{
"name": "Whales",
@ -303,13 +396,13 @@
"gold": 1,
"improvement": "Fishing Boats",
"improvementStats": {"food": 1},
"uniques": ["Appears in [Tundra] regions with weight [35]",
"Appears in [Forest] regions with weight [10]",
"Appears in [Hill] regions with weight [10]",
"Appears in [Plains] regions with weight [5]",
"Appears in [Grassland] regions with weight [10]",
"Appears in [Hybrid] regions with weight [20]",
"Appears near City States with weight [10]"]
"uniques": ["Generated with weight [35] <in [Tundra] Regions>",
"Generated with weight [10] <in [Forest] Regions>",
"Generated with weight [10] <in [Hill] Regions>",
"Generated with weight [5] <in [Plains] Regions>",
"Generated with weight [10] <in [Grassland] Regions>",
"Generated with weight [20] <in [Hybrid] Regions>",
"Generated near City States with weight [10]"]
},
{
"name": "Pearls",
@ -318,14 +411,14 @@
"gold": 2,
"improvement": "Fishing Boats",
"improvementStats": {"food": 1},
"uniques": ["Appears in [Jungle] regions with weight [20]",
"Appears in [Forest] regions with weight [10]",
"Appears in [Desert] regions with weight [5]",
"Appears in [Hill] regions with weight [15]",
"Appears in [Plains] regions with weight [5]",
"Appears in [Grassland] regions with weight [10]",
"Appears in [Hybrid] regions with weight [20]",
"Appears near City States with weight [15]"]
"uniques": ["Generated with weight [20] <in [Jungle] Regions>",
"Generated with weight [10] <in [Forest] Regions>",
"Generated with weight [5] <in [Desert] Regions>",
"Generated with weight [15] <in [Hill] Regions>",
"Generated with weight [5] <in [Plains] Regions>",
"Generated with weight [10] <in [Grassland] Regions>",
"Generated with weight [20] <in [Hybrid] Regions>",
"Generated near City States with weight [15]"]
},
{
"name": "Jewelry",
@ -338,42 +431,46 @@
"resourceType": "Luxury",
"gold": 2,
"uniques": ["Can only be created by Mercantile City-States"]
}
},
{
"name": "Citrus",
"resourceType": "Luxury",
"terrainsCanBeFoundOn": ["Jungle","Forest"],
"terrainsCanBeFoundOn": ["Jungle","Forest","Flood plains"],
"food": 1,
"gold": 1,
"improvement": "Plantation",
"improvementStats": {"gold": 1},
"uniques": ["Appears in [Jungle] regions with weight [35]",
"Appears in [Forest] regions with weight [5]",
"Appears in [Desert] regions with weight [5]",
"Appears in [Hybrid] regions with weight [5]",
"Appears near City States with weight [15]"]
"uniques": ["Generated with weight [35] <in [Jungle] Regions>",
"Generated with weight [5] <in [Forest] Regions>",
"Generated with weight [5] <in [Desert] Regions>",
"Generated with weight [5] <in [Hybrid] Regions>",
"Generated near City States with weight [15]",
"Doesn't generate naturally <in [Tundra] tiles>"]
},
{
"name": "Copper",
"resourceType": "Luxury",
"terrainsCanBeFoundOn": ["Plains","Grassland","Desert","Tundra","Snow"],
"terrainsCanBeFoundOn": ["Hill","Forest","Jungle","Grassland","Tundra"],
"gold": 2,
"improvement": "Mine",
"improvementStats": {"production": 2},
"uniques": ["Appears in [Tundra] regions with weight [15]",
"Appears in [Jungle] regions with weight [5]",
"Appears in [Forest] regions with weight [5]",
"Appears in [Desert] regions with weight [10]",
"Appears in [Hill] regions with weight [30]",
"Appears in [Grassland] regions with weight [20]",
"Appears in [Hybrid] regions with weight [20]",
"Appears near City States with weight [10]"]
"uniques": ["Generated with weight [15] <in [Tundra] Regions>",
"Generated with weight [5] <in [Jungle] Regions>",
"Generated with weight [5] <in [Forest] Regions>",
"Generated with weight [10] <in [Desert] Regions>",
"Generated with weight [30] <in [Hill] Regions>",
"Generated with weight [20] <in [Grassland] Regions>",
"Generated with weight [20] <in [Hybrid] Regions>",
"Generated near City States with weight [10]",
"Doesn't generate naturally <in [Grassland] [Fresh Water] tiles>",
"Doesn't generate naturally <in [Jungle] tiles> <in tiles without [Hill]>",
"Doesn't generate naturally <in [Forest] tiles> <in tiles without [Hill]> <in tiles without [Tundra]>"]
},
/*
{
"name": "Cocoa",
"resourceType": "Luxury",
"terrainsCanBeFoundOn": ["Jungle"],
"terrainsCanBeFoundOn": ["Jungle","Forest"], // Forest only if flat, non-tundra
"food": 1,
"gold": 1,
"improvement": "Plantation",
@ -388,30 +485,31 @@
"gold": 1,
"improvement": "Fishing Boats",
"improvementStats": {"food": 1},
"uniques": ["Appears in [Tundra] regions with weight [30]",
"Appears in [Jungle] regions with weight [5]",
"Appears in [Forest] regions with weight [10]",
"Appears in [Hill] regions with weight [10]",
"Appears in [Plains] regions with weight [5]",
"Appears in [Grassland] regions with weight [20]",
"Appears in [Hybrid] regions with weight [20]",
"Appears near City States with weight [15]"]
"uniques": ["Generated with weight [30] <in [Tundra] Regions>",
"Generated with weight [5] <in [Jungle] Regions>",
"Generated with weight [10] <in [Forest] Regions>",
"Generated with weight [10] <in [Hill] Regions>",
"Generated with weight [5] <in [Plains] Regions>",
"Generated with weight [20] <in [Grassland] Regions>",
"Generated with weight [20] <in [Hybrid] Regions>",
"Generated near City States with weight [15]"]
},
{
"name": "Salt",
"resourceType": "Luxury",
"terrainsCanBeFoundOn": ["Desert","Tundra","Plains"],
"terrainsCanBeFoundOn": ["Desert","Tundra","Plains","Forest"],
"gold": 1,
"food": 1,
"improvement": "Mine",
"improvementStats": {"food": 1,"production":1},
"uniques": ["Appears in [Tundra] regions with weight [15]",
"Appears in [Forest] regions with weight [5]",
"Appears in [Desert] regions with weight [15]",
"Appears in [Hill] regions with weight [10]",
"Appears in [Plains] regions with weight [25]",
"Appears in [Hybrid] regions with weight [15]",
"Appears near City States with weight [10]"]
"uniques": ["Generated with weight [15] <in [Tundra] Regions>",
"Generated with weight [5] <in [Forest] Regions>",
"Generated with weight [15] <in [Desert] Regions>",
"Generated with weight [10] <in [Hill] Regions>",
"Generated with weight [25] <in [Plains] Regions>",
"Generated with weight [15] <in [Hybrid] Regions>",
"Generated near City States with weight [10]",
"Doesn't generate naturally <in [Forest] [Hill] tiles>"]
},
{
"name": "Truffles",
@ -420,11 +518,13 @@
"gold": 2,
"improvement": "Camp",
"improvementStats": {"gold": 1},
"uniques": ["Appears in [Jungle] regions with weight [5]",
"Appears in [Forest] regions with weight [30]",
"Appears in [Plains] regions with weight [5]",
"Appears in [Grassland] regions with weight [5]",
"Appears in [Hybrid] regions with weight [10]",
"Appears near City States with weight [15]"]
"uniques": ["Generated with weight [5] <in [Jungle] Regions>",
"Generated with weight [30] <in [Forest] Regions>",
"Generated with weight [5] <in [Plains] Regions>",
"Generated with weight [5] <in [Grassland] Regions>",
"Generated with weight [10] <in [Hybrid] Regions>",
"Generated near City States with weight [15]",
"Doesn't generate naturally <in [Forest] [Hill] tiles>",
"Doesn't generate naturally <in [Tundra] [Forest] tiles>"]
}
]

View File

@ -15,7 +15,8 @@
"movementCost": 1,
"RGB": [107,167,193],
"uniques": ["[+2] to Fertility for Map Generation",
"Considered [Desirable] when determining start locations <on water maps>"]
"Considered [Desirable] when determining start locations <on water maps>",
"Every [60] tiles with this terrain will receive a major deposit of a strategic resource."]
},
{
"name": "Grassland",
@ -24,13 +25,13 @@
"movementCost": 1,
"RGB": [97,171,58],
"uniques": ["Occurs at temperature between [-0.4] and [0.1] and humidity between [0.2] and [0.4]",
"Occurs at temperature between [0.1] and [0.2] and humidity between [0.3] and [0.4]",
"Occurs at temperature between [-0.5] and [0.5] and humidity between [0.6] and [0.8]",
"Occurs at temperature between [-0.5] and [1] and humidity between [0.9] and [1]",
"Occurs at temperature between [0.9] and [1] and humidity between [0.2] and [0.9]",
"Occurs at temperature between [0.8] and [0.9] and humidity between [0.6] and [0.9]",
"Occurs at temperature between [0.7] and [0.8] and humidity between [0.7] and [0.9]",
"Occurs at temperature between [0.6] and [0.8] and humidity between [0.4] and [0.6]",
"Occurs at temperature between [0.1] and [0.2] and humidity between [0.3] and [0.4]",
"Occurs at temperature between [-0.5] and [0.5] and humidity between [0.6] and [0.8]",
"Occurs at temperature between [-0.5] and [1] and humidity between [0.9] and [1]",
"Occurs at temperature between [0.9] and [1] and humidity between [0.2] and [0.9]",
"Occurs at temperature between [0.8] and [0.9] and humidity between [0.6] and [0.9]",
"Occurs at temperature between [0.7] and [0.8] and humidity between [0.7] and [0.9]",
"Occurs at temperature between [0.6] and [0.8] and humidity between [0.4] and [0.6]",
"[+3] to Fertility for Map Generation",
"A Region is formed with at least [30]% [Grassland] tiles, with priority [7]",
"A Region can not contain more [Plains] tiles than [Grassland] tiles",
@ -39,7 +40,8 @@
"Considered [Food] when determining start locations <in [Forest] Regions>",
"Considered [Food] when determining start locations <in [Hill] Regions>",
"Considered [Food] when determining start locations <in [Grassland] Regions>",
"Considered [Food] when determining start locations <in [Hybrid] Regions>"]
"Considered [Food] when determining start locations <in [Hybrid] Regions>",
"Every [33] tiles with this terrain will receive a major deposit of a strategic resource."]
},
{
"name": "Plains",
@ -49,16 +51,16 @@
"movementCost": 1,
"RGB": [168,185,102],
"uniques": ["Occurs at temperature between [-0.4] and [-0.1] and humidity between [0] and [0.2]",
"Occurs at temperature between [-0.4] and [0.4] and humidity between [0.4] and [0.6]",
"Occurs at temperature between [0.4] and [0.5] and humidity between [0.5] and [0.6]",
"Occurs at temperature between [-0.6] and [0.7] and humidity between [0.8] and [0.9]",
"Occurs at temperature between [-0.6] and [-0.5] and humidity between [0.9] and [1]",
"Occurs at temperature between [0.5] and [0.7] and humidity between [0.7] and [0.8]",
"Occurs at temperature between [0.9] and [1] and humidity between [0] and [0.2]",
"Occurs at temperature between [0.8] and [0.9] and humidity between [0.2] and [0.6]",
"Occurs at temperature between [0.7] and [0.8] and humidity between [0.3] and [0.4]",
"Occurs at temperature between [0.6] and [0.8] and humidity between [0.6] and [0.7]",
"Occurs at temperature between [0.5] and [0.7] and humidity between [0.7] and [0.8]",
"Occurs at temperature between [-0.4] and [0.4] and humidity between [0.4] and [0.6]",
"Occurs at temperature between [0.4] and [0.5] and humidity between [0.5] and [0.6]",
"Occurs at temperature between [-0.6] and [0.7] and humidity between [0.8] and [0.9]",
"Occurs at temperature between [-0.6] and [-0.5] and humidity between [0.9] and [1]",
"Occurs at temperature between [0.5] and [0.7] and humidity between [0.7] and [0.8]",
"Occurs at temperature between [0.9] and [1] and humidity between [0] and [0.2]",
"Occurs at temperature between [0.8] and [0.9] and humidity between [0.2] and [0.6]",
"Occurs at temperature between [0.7] and [0.8] and humidity between [0.3] and [0.4]",
"Occurs at temperature between [0.6] and [0.8] and humidity between [0.6] and [0.7]",
"Occurs at temperature between [0.5] and [0.7] and humidity between [0.7] and [0.8]",
"[+4] to Fertility for Map Generation",
"A Region is formed with at least [30]% [Plains] tiles, with priority [6]",
"A Region can not contain more [Grassland] tiles than [Plains] tiles",
@ -67,7 +69,8 @@
"Considered [Food] when determining start locations <in [Desert] Regions>",
"Considered [Food] when determining start locations <in [Hill] Regions>",
"Considered [Food] when determining start locations <in [Plains] Regions>",
"Considered [Food] when determining start locations <in [Hybrid] Regions>"]
"Considered [Food] when determining start locations <in [Hybrid] Regions>",
"Every [33] tiles with this terrain will receive a major deposit of a strategic resource."]
},
{
"name": "Tundra",
@ -76,14 +79,15 @@
"movementCost": 1,
"RGB": [189,204,191],
"uniques": ["Occurs at temperature between [-0.9] and [-0.6] and humidity between [0.8] and [1]",
"Occurs at temperature between [-0.8] and [-0.5] and humidity between [0.6] and [0.8]",
"Occurs at temperature between [-0.7] and [-0.4] and humidity between [0.4] and [0.6]",
"Occurs at temperature between [-0.6] and [-0.4] and humidity between [0.2] and [0.4]",
"Occurs at temperature between [-0.5] and [-0.4] and humidity between [0] and [0.2]",
"Occurs at temperature between [-0.8] and [-0.5] and humidity between [0.6] and [0.8]",
"Occurs at temperature between [-0.7] and [-0.4] and humidity between [0.4] and [0.6]",
"Occurs at temperature between [-0.6] and [-0.4] and humidity between [0.2] and [0.4]",
"Occurs at temperature between [-0.5] and [-0.4] and humidity between [0] and [0.2]",
"[+2] to Fertility for Map Generation",
"A Region is formed with at least [30]% [Tundra] tiles and [Snow] tiles, with priority [1]",
"Considered [Food] when determining start locations <in [Tundra] Regions>",
"Considered [Desirable] when determining start locations <in [Tundra] Regions>"]
"Considered [Desirable] when determining start locations <in [Tundra] Regions>",
"Every [16] tiles with this terrain will receive a major deposit of a strategic resource."]
},
{
"name": "Desert",
@ -91,13 +95,14 @@
"movementCost": 1,
"RGB": [ 230, 230, 113],
"uniques": ["Occurs at temperature between [-0.1] and [0.9] and humidity between [0] and [0.2]",
"Occurs at temperature between [0.1] and [0.8] and humidity between [0.2] and [0.3]",
"Occurs at temperature between [0.2] and [0.7] and humidity between [0.3] and [0.4]",
"Occurs at temperature between [0.4] and [0.6] and humidity between [0.4] and [0.5]",
"Occurs at temperature between [0.5] and [0.6] and humidity between [0.5] and [0.7]",
"Occurs at temperature between [0.1] and [0.8] and humidity between [0.2] and [0.3]",
"Occurs at temperature between [0.2] and [0.7] and humidity between [0.3] and [0.4]",
"Occurs at temperature between [0.4] and [0.6] and humidity between [0.4] and [0.5]",
"Occurs at temperature between [0.5] and [0.6] and humidity between [0.5] and [0.7]",
"[+1] to Fertility for Map Generation",
"A Region is formed with at least [25]% [Desert] tiles, with priority [4]",
"Considered [Undesirable] when determining start locations <in all except [Desert] Regions>"]
"Considered [Undesirable] when determining start locations <in all except [Desert] Regions>",
"Every [13] tiles with this terrain will receive a major deposit of a strategic resource."]
},
{
"name": "Lakes",
@ -106,8 +111,8 @@
"gold": 1,
"RGB": [ 123, 202, 226],
"uniques": ["Fresh water",
"Considered [Food] when determining start locations",
"Considered [Desirable] when determining start locations"]
"Considered [Food] when determining start locations",
"Considered [Desirable] when determining start locations"]
},
{
"name": "Mountain",
@ -116,11 +121,11 @@
"defenceBonus": 0.25,
"RGB": [120, 120, 120],
"uniques": ["Rough terrain",
"Has an elevation of [4] for visibility calculations",
"Occurs in chains at high elevations",
"Units ending their turn on this terrain take [50] damage",
"Always Fertility [-2] for Map Generation",
"Considered [Undesirable] when determining start locations"]
"Has an elevation of [4] for visibility calculations",
"Occurs in chains at high elevations",
"Units ending their turn on this terrain take [50] damage",
"Always Fertility [-2] for Map Generation",
"Considered [Undesirable] when determining start locations"]
},
{
"name": "Snow",
@ -128,12 +133,14 @@
"movementCost": 1,
"RGB": [231, 242, 249],
"uniques": ["Occurs at temperature between [-1] and [-0.9] and humidity between [0] and [1]",
"Occurs at temperature between [-0.9] and [-0.8] and humidity between [0] and [0.8]",
"Occurs at temperature between [-0.8] and [-0.7] and humidity between [0] and [0.6]",
"Occurs at temperature between [-0.7] and [-0.6] and humidity between [0] and [0.4]",
"Occurs at temperature between [-0.6] and [-0.5] and humidity between [0] and [0.2]",
"Occurs at temperature between [-0.9] and [-0.8] and humidity between [0] and [0.8]",
"Occurs at temperature between [-0.8] and [-0.7] and humidity between [0] and [0.6]",
"Occurs at temperature between [-0.7] and [-0.6] and humidity between [0] and [0.4]",
"Occurs at temperature between [-0.6] and [-0.5] and humidity between [0] and [0.2]",
"Always Fertility [-1] for Map Generation",
"Considered [Undesirable] when determining start locations"]
"Considered [Undesirable] when determining start locations",
"Every [17] tiles with this terrain will receive a major deposit of a strategic resource.",
"Never receives any resources <in [Hill] tiles>"]
},
// Terrain features
@ -147,14 +154,16 @@
"RGB": [105,125,72],
"occursOn": ["Tundra","Plains","Grassland","Desert","Snow"],
"uniques": ["Rough terrain",
"[+5] Strength for cities built on this terrain",
"Has an elevation of [2] for visibility calculations",
"Occurs in groups around high elevations",
"[+1] to Fertility for Map Generation",
"A Region is formed with at least [40]% [Hill] tiles, with priority [5]",
"Base Terrain on this tile is not counted for Region determination",
"Considered [Desirable] when determining start locations",
"Considered [Production] when determining start locations"]
"[+5] Strength for cities built on this terrain",
"Has an elevation of [2] for visibility calculations",
"Occurs in groups around high elevations",
"[+1] to Fertility for Map Generation",
"A Region is formed with at least [40]% [Hill] tiles, with priority [5]",
"Base Terrain on this tile is not counted for Region determination",
"Starts in regions of this type receive an extra [Sheep]",
"Considered [Desirable] when determining start locations",
"Considered [Production] when determining start locations",
"Every [22] tiles with this terrain will receive a major deposit of a strategic resource."]
},
{
"name": "Forest",
@ -167,16 +176,17 @@
"defenceBonus": 0.25,
"occursOn": ["Tundra","Plains","Grassland","Hill"],
"uniques": ["Rough terrain",
"Provides a one-time Production bonus to the closest city when cut down",
"Blocks line-of-sight from tiles at same elevation",
"Resistant to nukes", "Can be destroyed by nukes",
"A Region is formed with at least [30]% [Forest] tiles, with priority [3]",
"A Region is formed with at least [35]% [Forest] tiles and [Jungle] tiles, with priority [3]",
"A Region can not contain more [Jungle] tiles than [Forest] tiles",
"Considered [Desirable] when determining start locations",
"Considered [Production] when determining start locations",
"Considered [Food] when determining start locations <in [Forest] Regions>",
"Considered [Food] when determining start locations <in [Tundra] Regions>"],
"Provides a one-time Production bonus to the closest city when cut down",
"Blocks line-of-sight from tiles at same elevation",
"Resistant to nukes", "Can be destroyed by nukes",
"A Region is formed with at least [30]% [Forest] tiles, with priority [3]",
"A Region is formed with at least [35]% [Forest] tiles and [Jungle] tiles, with priority [3]",
"A Region can not contain more [Jungle] tiles than [Forest] tiles",
"Considered [Desirable] when determining start locations",
"Considered [Production] when determining start locations",
"Considered [Food] when determining start locations <in [Forest] Regions>",
"Considered [Food] when determining start locations <in [Tundra] Regions>",
"Every [39] tiles with this terrain will receive a major deposit of a strategic resource."],
"civilopediaText": [{"text":"A Camp can be built here without cutting it down", "link":"Improvement/Camp"}]
},
{
@ -189,14 +199,15 @@
"defenceBonus": 0.25,
"occursOn": ["Plains","Grassland"],
"uniques": ["Rough terrain",
"Blocks line-of-sight from tiles at same elevation",
"Resistant to nukes", "Can be destroyed by nukes",
"[-1] to Fertility for Map Generation",
"A Region is formed with at least [30]% [Jungle] tiles, with priority [2]",
"A Region is formed with at least [35]% [Jungle] tiles and [Forest] tiles, with priority [2]",
"A Region can not contain more [Forest] tiles than [Jungle] tiles",
"Considered [Food] when determining start locations <in all except [Grassland] Regions>",
"Considered [Desirable] when determining start locations <in all except [Grassland] Regions>"]
"Blocks line-of-sight from tiles at same elevation",
"Resistant to nukes", "Can be destroyed by nukes",
"[-1] to Fertility for Map Generation",
"A Region is formed with at least [30]% [Jungle] tiles, with priority [2]",
"A Region is formed with at least [35]% [Jungle] tiles and [Forest] tiles, with priority [2]",
"A Region can not contain more [Forest] tiles than [Jungle] tiles",
"Considered [Food] when determining start locations <in all except [Grassland] Regions>",
"Considered [Desirable] when determining start locations <in all except [Grassland] Regions>",
"Every [33] tiles with this terrain will receive a major deposit of a strategic resource."]
},
{
"name": "Marsh",
@ -207,7 +218,8 @@
"defenceBonus": -0.15,
"occursOn": ["Grassland"],
"uniques": ["Rare feature",
"[-2] to Fertility for Map Generation"],
"[-2] to Fertility for Map Generation",
"Every [9] tiles with this terrain will receive a major deposit of a strategic resource."],
"civilopediaText": [{"text":"Only Polders can be built here", "link":"Improvement/Polder"}]
},
{
@ -231,10 +243,10 @@
"defenceBonus": -0.1,
"occursOn": ["Desert"],
"uniques": ["Fresh water", "Rare feature",
"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"]
"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"]
},
{
"name": "Flood plains",
@ -244,8 +256,8 @@
"defenceBonus": -0.1,
"occursOn": ["Desert"],
"uniques": ["Always Fertility [5] for Map Generation",
"Considered [Food] when determining start locations",
"Considered [Desirable] when determining start locations"]
"Considered [Food] when determining start locations",
"Considered [Desirable] when determining start locations"]
},
{
"name": "Ice",
@ -254,7 +266,7 @@
"overrideStats": true,
"occursOn": ["Ocean", "Coast"],
"uniques": ["[-1] to Fertility for Map Generation",
"Considered [Undesirable] when determining start locations"]
"Considered [Undesirable] when determining start locations"]
},
{
"name": "Atoll",
@ -479,46 +491,46 @@
"unbuildable": true,
"weight": 10
},
/*
// BNW wonders
{
"name": "King Solomon's Mines",
"type": "NaturalWonder",
"production": 6,
"overrideStats": true,
"occursOn": ["Plains","Desert"],
"uniques": ["Must be adjacent to [0] [Coast] tiles",
"Must be adjacent to [0] to [2] [Mountain] tiles"],
"turnsInto": "Plains",
"impassable": true,
"unbuildable": true,
"weight": 4
},
{// Will be introduced in Brave New World. Despite being a lake, it cannot be sailed on and it blocks line of sight like a mountain.
"name": "Lake Victoria",
"type": "NaturalWonder",
"food": 6,
"occursOn": ["Plains"],
"turnsInto": "Mountain",
"impassable": true,
"unbuildable": true,
"uniques": ["Fresh water","Must be adjacent to [0] [Coast] tiles"],
"weight": 10
},
{
"name": "Mount Kilimanjaro",
"type": "NaturalWonder",
"food": 3,
"culture": 2,
"occursOn": ["Plains","Grassland"],
"turnsInto": "Mountain",
"impassable": true,
"unbuildable": true,
"uniques": ["Must be adjacent to [0] [Coast] tiles",
"Must be adjacent to [2] to [6] [Hill] tiles",
"Must be adjacent to [0] to [2] [Mountain] tiles",
"Grants [Altitude Training] ([double movement and +10% Strength in hills]) to adjacent [Land] units for the rest of the game"],
"weight": 10
}
*/
/*
// BNW wonders
{
"name": "King Solomon's Mines",
"type": "NaturalWonder",
"production": 6,
"overrideStats": true,
"occursOn": ["Plains","Desert"],
"uniques": ["Must be adjacent to [0] [Coast] tiles",
"Must be adjacent to [0] to [2] [Mountain] tiles"],
"turnsInto": "Plains",
"impassable": true,
"unbuildable": true,
"weight": 4
},
{// Will be introduced in Brave New World. Despite being a lake, it cannot be sailed on and it blocks line of sight like a mountain.
"name": "Lake Victoria",
"type": "NaturalWonder",
"food": 6,
"occursOn": ["Plains"],
"turnsInto": "Mountain",
"impassable": true,
"unbuildable": true,
"uniques": ["Fresh water","Must be adjacent to [0] [Coast] tiles"],
"weight": 10
},
{
"name": "Mount Kilimanjaro",
"type": "NaturalWonder",
"food": 3,
"culture": 2,
"occursOn": ["Plains","Grassland"],
"turnsInto": "Mountain",
"impassable": true,
"unbuildable": true,
"uniques": ["Must be adjacent to [0] [Coast] tiles",
"Must be adjacent to [2] to [6] [Hill] tiles",
"Must be adjacent to [0] to [2] [Mountain] tiles",
"Grants [Altitude Training] ([double movement and +10% Strength in hills]) to adjacent [Land] units for the rest of the game"],
"weight": 10
}
*/
]

View File

@ -6,15 +6,19 @@
"terrainsCanBeFoundOn": ["Grassland"],
"food": 1,
"improvement": "Pasture",
"improvementStats": {"production": 1}
"improvementStats": {"production": 1},
"uniques": ["Generated on every [18] tiles <in [Featureless] [Grassland] tiles>",
"Generated on every [22] tiles <in [Featureless] [Grassland] tiles> <in [Hill] Regions>"]
},
{
"name": "Sheep",
"resourceType": "Bonus",
"terrainsCanBeFoundOn": ["Plains","Hill"],
"terrainsCanBeFoundOn": ["Hill"],
"food": 1,
"improvement": "Pasture",
"improvementStats": {"food": 1}
"improvementStats": {"food": 1},
"uniques": ["Generated on every [13] tiles <in [Hill] tiles> <in tiles without [Forest]> <in tiles without [Jungle]>",
"Generated on every [10] tiles <in [Hill] tiles> <in tiles without [Forest]> <in tiles without [Jungle]> <in tiles without [Fresh Water]> <in [Hill] Regions>"]
},
{
"name": "Deer",
@ -22,7 +26,13 @@
"terrainsCanBeFoundOn": ["Forest","Tundra"],
"food": 1,
"improvement": "Camp",
"improvementStats": {"production": 1}
"improvementStats": {"production": 1},
"uniques": ["Generated on every [8] tiles <in [Tundra] [Forest] tiles>",
"Generated on every [12] tiles <in [Featureless] [Tundra] tiles>",
"Generated on every [25] tiles <in [Plains] [Forest] tiles> <in tiles without [Hill]>",
"Generated on every [25] tiles <in [Grassland] [Forest] tiles> <in tiles without [Hill]>",
"Generated on every [16] tiles <in [Featureless] [Tundra] tiles> <in [Hill] Regions>",
"Generated on every [28] tiles <in [Forest] tiles> <in [Hill] Regions>"]
},
{
"name": "Bananas",
@ -30,7 +40,9 @@
"terrainsCanBeFoundOn": ["Jungle"],
"food": 1,
"improvement": "Plantation",
"improvementStats": {"food": 2,"production": -1}
"improvementStats": {"food": 2,"production": -1},
"uniques": ["Generated on every [14] tiles <in [Jungle] tiles>",
"Generated on every [16] tiles <in [Jungle] tiles> <in [Hill] Regions>"]
},
{
"name": "Wheat",
@ -38,15 +50,22 @@
"terrainsCanBeFoundOn": ["Plains","Flood plains","Desert"],
"food": 1,
"improvement": "Farm",
"improvementStats": {"food": 1}
"improvementStats": {"food": 1},
"uniques": ["Generated on every [27] tiles <in [Featureless] [Plains] tiles>",
"Generated on every [10] tiles <in [Desert] [Fresh Water] tiles> <in tiles without [Hill]>",
"Generated on every [20] tiles <in [Featureless] [Plains] tiles> <in [Hill] Regions>",
"Generated on every [20] tiles <in [Fresh Water] [Desert] tiles> <in tiles without [Hill]> <in [Hill] Regions>"]
},
{
"name": "Stone",
"resourceType": "Bonus",
"terrainsCanBeFoundOn": ["Plains","Desert","Snow"],
"terrainsCanBeFoundOn": ["Grassland","Desert","Tundra"],
"production": 1,
"improvement": "Quarry",
"improvementStats": {"production": 1},
"uniques": ["Generated on every [20] tiles <in [Featureless] [Grassland] tiles> <in tiles without [Fresh Water]>",
"Generated on every [15] tiles <in [Featureless] [Tundra] tiles>",
"Generated on every [19] tiles <in [Featureless] [Desert] tiles>"]
},
{
"name": "Fish",
@ -54,7 +73,8 @@
"terrainsCanBeFoundOn": ["Coast"],
"food": 1,
"improvement": "Fishing Boats",
"improvementStats": {"food": 1}
"improvementStats": {"food": 1},
"uniques": ["Generated on every [10] tiles <in [Featureless] [Coast] tiles>"]
},
/*
{
@ -72,10 +92,18 @@
"name": "Horses",
"resourceType": "Strategic",
"revealedBy": "Animal Husbandry",
"terrainsCanBeFoundOn": ["Plains","Grassland","Hill","Desert"],
"terrainsCanBeFoundOn": ["Plains","Grassland","Hill"],
"production": 1,
"improvement": "Pasture",
"improvementStats": {"production": 1},
"uniques": ["Guaranteed with Strategic Balance resource option",
"Generated with weight [100] <in [Featureless] [Grassland] tiles>",
"Generated with weight [100] <in [Featureless] [Plains] tiles>",
"Minor deposits generated with weight [10] <in [Grassland] [Hill] tiles> <in tiles without [Forest]> <in tiles without [Jungle]>",
"Minor deposits generated with weight [10] <in [Plains] [Hill] tiles> <in tiles without [Forest]> <in tiles without [Jungle]>",
"Minor deposits generated with weight [100] <in [Featureless] [Grassland] tiles> <in [Fresh Water] tiles>",
"Minor deposits generated with weight [20] <in [Featureless] [Grassland] tiles> <in tiles without [Fresh Water]>",
"Minor deposits generated with weight [30] <in [Featureless] [Plains] tiles>"],
"majorDepositAmount": {"sparse": 4, "default": 4, "abundant": 6},
"minorDepositAmount": {"sparse": 1, "default": 2, "abundant": 3}
},
@ -83,10 +111,24 @@
"name": "Iron",
"resourceType": "Strategic",
"revealedBy": "Iron Working",
"terrainsCanBeFoundOn": ["Grassland","Plains","Desert","Tundra","Snow","Hill"],
"terrainsCanBeFoundOn": ["Grassland","Plains","Desert","Tundra","Snow","Hill","Marsh"],
"production": 1,
"improvement": "Mine",
"improvementStats": {"production": 1},
"uniques": ["Guaranteed with Strategic Balance resource option",
"Generated with weight [45] <in [Featureless] [Tundra] tiles>",
"Generated with weight [25] <in [Featureless] [Snow] tiles>",
"Generated with weight [35] <in [Featureless] [Desert] tiles>",
"Generated with weight [26] <in [Hill] tiles>",
"Minor deposits generated with weight [10] <in [Marsh] tiles> <in tiles without [Hill]>",
"Minor deposits generated with weight [10] <in [Jungle] [Hill] tiles>",
"Minor deposits generated with weight [20] <in [Forest] tiles>",
"Minor deposits generated with weight [20] <in [Hill] tiles> <in tiles without [Forest]> <in tiles without [Jungle]>",
"Minor deposits generated with weight [30] <in [Featureless] [Grassland] tiles> <in tiles without [Fresh Water]>",
"Minor deposits generated with weight [20] <in [Featureless] [Plains] tiles>",
"Minor deposits generated with weight [10] <in [Featureless] [Desert] tiles>",
"Minor deposits generated with weight [10] <in [Featureless] [Tundra] tiles>",
"Minor deposits generated with weight [10] <in [Featureless] [Snow] tiles>"],
"majorDepositAmount": {"sparse": 4, "default": 6, "abundant": 9},
"minorDepositAmount": {"sparse": 1, "default": 2, "abundant": 3}
},
@ -94,10 +136,21 @@
"name": "Coal",
"resourceType": "Strategic",
"revealedBy": "Scientific Theory",
"terrainsCanBeFoundOn": ["Grassland","Plains","Hill"],
"terrainsCanBeFoundOn": ["Grassland","Plains","Hill","Jungle","Forest","Marsh"],
"production": 1,
"improvement": "Mine",
"improvementStats": {"production": 2},
"uniques": ["Generated with weight [35] <in [Hill] tiles>",
"Generated with weight [30] <in [Jungle] tiles> <in tiles without [Hill]>",
"Generated with weight [30] <in [Forest] tiles> <in tiles without [Hill]>",
"Minor deposits generated with weight [10] <in [Marsh] tiles> <in tiles without [Hill]>",
"Minor deposits generated with weight [10] <in [Jungle] tiles>",
"Minor deposits generated with weight [10] <in [Forest] tiles>",
"Minor deposits generated with weight [20] <in [Grassland] [Hill] tiles>",
"Minor deposits generated with weight [20] <in [Plains] [Hill] tiles>",
"Minor deposits generated with weight [30] <in [Desert] [Hill] tiles>",
"Minor deposits generated with weight [30] <in [Tundra] [Hill] tiles>",
"Minor deposits generated with weight [30] <in [Snow] [Hill] tiles>"],
"majorDepositAmount": {"sparse": 5, "default": 7, "abundant": 10},
"minorDepositAmount": {"sparse": 2, "default": 3, "abundant": 3}
},
@ -109,7 +162,18 @@
"production": 1,
"improvement": "Oil well",
"improvementStats": {"production": 3},
"uniques": ["Deposits in [Water] tiles always provide [4] resources"],
"uniques": ["Deposits in [Coast] tiles always provide [4] resources",
"Guaranteed with Strategic Balance resource option",
"Generated with weight [65] <in [Marsh] tiles> <in tiles without [Hill]>",
"Generated with weight [40] <in [Featureless] [Tundra] tiles>",
"Generated with weight [60] <in [Featureless] [Snow] tiles>",
"Generated with weight [65] <in [Featureless] [Desert] tiles>",
"Generated with weight [100] <in [Featureless] [Coast] tiles>",
"Minor deposits generated with weight [20] <in [Marsh] tiles> <in tiles without [Hill]>",
"Minor deposits generated with weight [10] <in [Jungle] tiles> <in tiles without [Hill]>",
"Minor deposits generated with weight [10] <in [Featureless] [Desert] tiles>",
"Minor deposits generated with weight [20] <in [Featureless] [Tundra] tiles>",
"Minor deposits generated with weight [20] <in [Featureless] [Snow] tiles>"],
"majorDepositAmount": {"sparse": 5, "default": 7, "abundant": 9},
"minorDepositAmount": {"sparse": 2, "default": 3, "abundant": 3}
},
@ -117,10 +181,15 @@
"name": "Aluminum",
"resourceType": "Strategic",
"revealedBy": "Electricity",
"terrainsCanBeFoundOn": ["Plains","Desert","Tundra","Hill"],
"terrainsCanBeFoundOn": ["Desert","Tundra","Hill","Snow","Jungle"],
"production": 1,
"improvement": "Mine",
"improvementStats": {"production": 2},
"uniques": ["Generated with weight [15] <in [Featureless] [Tundra] tiles>",
"Generated with weight [15] <in [Featureless] [Snow] tiles>",
"Generated with weight [39] <in [Hill] tiles>",
"Minor deposits generated with weight [20] <in [Jungle] tiles>",
"Minor deposits generated with weight [10] <in [Featureless] [Desert] tiles>"],
"majorDepositAmount": {"sparse": 5, "default": 8, "abundant": 10},
"minorDepositAmount": {"sparse": 2, "default": 3, "abundant": 3}
},
@ -128,14 +197,20 @@
"name": "Uranium",
"resourceType": "Strategic",
"revealedBy": "Atomic Theory",
"terrainsCanBeFoundOn": ["Plains","Desert","Tundra","Hill","Snow","Forest","Desert","Marsh","Grassland"],
"terrainsCanBeFoundOn": ["Marsh","Jungle","Forest","Tundra","Snow"],
"production": 1,
"improvement": "Mine",
"improvementStats": {"production": 2},
"uniques": ["Generated with weight [35] <in [Marsh] tiles> <in tiles without [Hill]>",
"Generated with weight [70] <in [Jungle] tiles> <in tiles without [Hill]>",
"Generated with weight [70] <in [Forest] tiles> <in tiles without [Hill]>",
"Minor deposits generated with weight [10] <in [Forest] tiles>",
"Minor deposits generated with weight [10] <in [Featureless] [Tundra] tiles>",
"Minor deposits generated with weight [10] <in [Featureless] [Snow] tiles>"],
"majorDepositAmount": {"sparse": 2, "default": 4, "abundant": 4},
"minorDepositAmount": {"sparse": 1, "default": 2, "abundant": 3}
},
// Luxury resources
{
"name": "Furs",
@ -144,122 +219,137 @@
"gold": 2,
"improvement": "Camp",
"improvementStats": {"gold": 1},
"uniques": ["Appears in [Tundra] regions with weight [40]",
"Appears in [Forest] regions with weight [10]",
"Appears near City States with weight [15]"]
"uniques": ["Generated with weight [40] <in [Tundra] Regions>",
"Generated with weight [10] <in [Forest] Regions>",
"Generated near City States with weight [15]"]
},
{
"name": "Cotton",
"resourceType": "Luxury",
"terrainsCanBeFoundOn": ["Grassland","Plains","Desert"],
"terrainsCanBeFoundOn": ["Grassland","Flood plains"],
"gold": 2,
"improvement": "Plantation",
"improvementStats": {"gold": 1},
"uniques": ["Appears in [Desert] regions with weight [15]",
"Appears in [Grassland] regions with weight [30]",
"Appears in [Hybrid] regions with weight [15]",
"Appears near City States with weight [10]"]
"uniques": ["Generated with weight [15] <in [Desert] Regions>",
"Generated with weight [30] <in [Grassland] Regions>",
"Generated with weight [15] <in [Hybrid] Regions>",
"Generated near City States with weight [10]",
"Doesn't generate naturally <in [Hill] tiles>"]
},
{
"name": "Dyes",
"resourceType": "Luxury",
"terrainsCanBeFoundOn": ["Jungle","Forest"],
"terrainsCanBeFoundOn": ["Jungle","Forest","Marsh"],
"gold": 2,
"improvement": "Plantation",
"improvementStats": {"gold": 1},
"uniques": ["Appears in [Tundra] regions with weight [5]",
"Appears in [Jungle] regions with weight [5]",
"Appears in [Forest] regions with weight [30]",
"Appears near City States with weight [10]"]
"uniques": ["Generated with weight [5] <in [Tundra] Regions>",
"Generated with weight [5] <in [Jungle] Regions>",
"Generated with weight [30] <in [Forest] Regions>",
"Generated near City States with weight [10]",
"Doesn't generate naturally <in [Hill] tiles>"]
},
{
"name": "Gems",
"resourceType": "Luxury",
"terrainsCanBeFoundOn": ["Jungle","Grassland","Plains","Desert","Tundra","Hill"],
"terrainsCanBeFoundOn": ["Jungle","Forest","Hill"],
"gold": 3,
"improvement": "Mine",
"improvementStats": {"production": 1},
"uniques": ["Appears in [Tundra] regions with weight [5]",
"Appears in [Jungle] regions with weight [20]",
"Appears in [Hill] regions with weight [15]",
"Appears in [Grassland] regions with weight [5]",
"Appears in [Hybrid] regions with weight [5]",
"Appears near City States with weight [10]"]
"uniques": ["Generated with weight [5] <in [Tundra] Regions>",
"Generated with weight [20] <in [Jungle] Regions>",
"Generated with weight [15] <in [Hill] Regions>",
"Generated with weight [5] <in [Grassland] Regions>",
"Generated with weight [5] <in [Hybrid] Regions>",
"Generated near City States with weight [10]",
"Doesn't generate naturally <in [Forest] tiles> <in tiles without [Hill]>"]
},
{
"name": "Gold Ore", // Not called "Gold" in order to not conflict with siege type units for translations
"resourceType": "Luxury",
"terrainsCanBeFoundOn": ["Grassland","Plains","Desert","Hill"],
"terrainsCanBeFoundOn": ["Desert","Hill","Forest","Jungle"],
"gold": 2,
"improvement": "Mine",
"improvementStats": {"production": 1},
"uniques": ["Appears in [Desert] regions with weight [25]",
"Appears in [Hill] regions with weight [30]",
"Appears in [Plains] regions with weight [5]",
"Appears in [Hybrid] regions with weight [5]",
"Appears near City States with weight [10]"]
"uniques": ["Generated with weight [25] <in [Desert] Regions>",
"Generated with weight [30] <in [Hill] Regions>",
"Generated with weight [5] <in [Plains] Regions>",
"Generated with weight [5] <in [Hybrid] Regions>",
"Generated near City States with weight [10]",
"Doesn't generate naturally <in [Forest] tiles> <in tiles without [Hill]>",
"Doesn't generate naturally <in [Jungle] tiles> <in tiles without [Hill]>"]
},
{
"name": "Silver",
"resourceType": "Luxury",
"terrainsCanBeFoundOn": ["Desert","Tundra","Hill"],
"terrainsCanBeFoundOn": ["Hill","Forest","Jungle","Tundra","Grassland"],
"gold": 2,
"improvement": "Mine",
"improvementStats": {"production": 1},
"uniques": ["Appears in [Tundra] regions with weight [25]",
"Appears in [Hill] regions with weight [30]",
"Appears in [Grassland] regions with weight [20]",
"Appears in [Hybrid] regions with weight [10]",
"Appears near City States with weight [10]"]
"uniques": ["Generated with weight [25] <in [Tundra] Regions>",
"Generated with weight [30] <in [Hill] Regions>",
"Generated with weight [20] <in [Grassland] Regions>",
"Generated with weight [10] <in [Hybrid] Regions>",
"Generated near City States with weight [10]",
"Doesn't generate naturally <in [Forest] tiles> <in tiles without [Hill]>",
"Doesn't generate naturally <in [Jungle] tiles> <in tiles without [Hill]>",
"Doesn't generate naturally <in [Tundra] [Hill] tiles>",
"Doesn't generate naturally <in [Grassland] [Fresh Water] tiles>",
"Doesn't generate naturally <in [Grassland] [Hill] tiles>"
]
},
{
"name": "Incense",
"resourceType": "Luxury",
"terrainsCanBeFoundOn": ["Plains","Desert"],
"terrainsCanBeFoundOn": ["Plains","Desert","Flood plains"],
"gold": 2,
"improvement": "Plantation",
"improvementStats": {"gold": 1},
"uniques": ["Appears in [Desert] regions with weight [35]",
"Appears in [Plains] regions with weight [10]",
"Appears in [Hybrid] regions with weight [5]",
"Appears near City States with weight [15]"]
"uniques": ["Generated with weight [35] <in [Desert] Regions>",
"Generated with weight [10] <in [Plains] Regions>",
"Generated with weight [5] <in [Hybrid] Regions>",
"Generated near City States with weight [15]"]
},
{
"name": "Ivory",
"resourceType": "Luxury",
"terrainsCanBeFoundOn": ["Plains"],
"terrainsCanBeFoundOn": ["Plains","Grassland"],
"gold": 2,
"improvement": "Camp",
"improvementStats": {"gold": 1},
"uniques": ["Appears in [Plains] regions with weight [35]",
"Appears in [Hybrid] regions with weight [15]",
"Appears near City States with weight [10]"]
"uniques": ["Generated with weight [35] <in [Plains] Regions>",
"Generated with weight [15] <in [Hybrid] Regions>",
"Generated near City States with weight [10]",
"Doesn't generate naturally <in [Grassland] [Fresh Water] tiles>"]
},
{
"name": "Silk",
"resourceType": "Luxury",
"terrainsCanBeFoundOn": ["Forest"],
"terrainsCanBeFoundOn": ["Forest","Jungle"],
"gold": 2,
"improvement": "Plantation",
"improvementStats": {"gold": 1},
"uniques": ["Appears in [Jungle] regions with weight [5]",
"Appears in [Forest] regions with weight [30]",
"Appears in [Hybrid] regions with weight [5]",
"Appears near City States with weight [15]"]
"uniques": ["Generated with weight [5] <in [Jungle] Regions>",
"Generated with weight [30] <in [Forest] Regions>",
"Generated with weight [5] <in [Hybrid] Regions>",
"Generated near City States with weight [15]",
"Doesn't generate naturally <in [Hill] tiles>"]
},
{
"name": "Spices",
"resourceType": "Luxury",
"terrainsCanBeFoundOn": ["Jungle","Forest"],
"terrainsCanBeFoundOn": ["Jungle","Forest","Marsh"],
"gold": 2,
"improvement": "Plantation",
"improvementStats": {"gold": 1},
"uniques": ["Appears in [Jungle] regions with weight [30]",
"Appears in [Forest] regions with weight [10]",
"Appears in [Plains] regions with weight [5]",
"Appears in [Grassland] regions with weight [5]",
"Appears in [Hybrid] regions with weight [5]",
"Appears near City States with weight [15]"]
"uniques": ["Generated with weight [30] <in [Jungle] Regions>",
"Generated with weight [10] <in [Forest] Regions>",
"Generated with weight [5] <in [Plains] Regions>",
"Generated with weight [5] <in [Grassland] Regions>",
"Generated with weight [5] <in [Hybrid] Regions>",
"Generated near City States with weight [15]",
"Doesn't generate naturally <in [Hill] tiles>",
"Doesn't generate naturally <in [Tundra] [Forest] tiles>"]
},
{
"name": "Wine",
@ -268,32 +358,35 @@
"gold": 2,
"improvement": "Plantation",
"improvementStats": {"gold": 1},
"uniques": ["Appears in [Plains] regions with weight [35]",
"Appears in [Hybrid] regions with weight [15]",
"Appears near City States with weight [10]"]
"uniques": ["Generated with weight [35] <in [Plains] Regions>",
"Generated with weight [15] <in [Hybrid] Regions>",
"Generated near City States with weight [10]"]
},
{
"name": "Sugar",
"resourceType": "Luxury",
"terrainsCanBeFoundOn": ["Plains","Flood plains","Grassland","Marsh"],
"terrainsCanBeFoundOn": ["Flood plains","Grassland","Marsh"],
// Technically sugar can also be placed on lowland jungles which then *turn* into marsh.
"gold": 2,
"improvement": "Plantation",
"improvementStats": {"gold": 1},
"uniques": ["Appears in [Jungle] regions with weight [20]",
"Appears in [Desert] regions with weight [15]",
"Appears in [Grassland] regions with weight [20]",
"Appears in [Hybrid] regions with weight [5]",
"Appears near City States with weight [10]"]
"uniques": ["Generated with weight [20] <in [Jungle] Regions>",
"Generated with weight [15] <in [Desert] Regions>",
"Generated with weight [20] <in [Grassland] Regions>",
"Generated with weight [5] <in [Hybrid] Regions>",
"Generated near City States with weight [10]",
"Doesn't generate naturally <in [Grassland] tiles> <in tiles without [Fresh Water]>"]
},
{
"name": "Marble",
"resourceType": "Luxury",
"terrainsCanBeFoundOn": ["Desert","Plains","Tundra","Hill","Grassland"],
"terrainsCanBeFoundOn": ["Desert","Plains","Hill","Grassland"],
"gold": 2,
"improvement": "Quarry",
"improvementStats": {"production": 1},
"uniques": ["[+15]% Production when constructing [All] wonders [in all cities]",
"Special placement during map generation"]
"Special placement during map generation",
"Doesn't generate naturally <in [Grassland] [Fresh Water] tiles>"]
},
{
"name": "Whales",
@ -303,13 +396,13 @@
"gold": 1,
"improvement": "Fishing Boats",
"improvementStats": {"food": 1},
"uniques": ["Appears in [Tundra] regions with weight [35]",
"Appears in [Forest] regions with weight [10]",
"Appears in [Hill] regions with weight [10]",
"Appears in [Plains] regions with weight [5]",
"Appears in [Grassland] regions with weight [10]",
"Appears in [Hybrid] regions with weight [20]",
"Appears near City States with weight [10]"]
"uniques": ["Generated with weight [35] <in [Tundra] Regions>",
"Generated with weight [10] <in [Forest] Regions>",
"Generated with weight [10] <in [Hill] Regions>",
"Generated with weight [5] <in [Plains] Regions>",
"Generated with weight [10] <in [Grassland] Regions>",
"Generated with weight [20] <in [Hybrid] Regions>",
"Generated near City States with weight [10]"]
},
{
"name": "Pearls",
@ -318,14 +411,14 @@
"gold": 2,
"improvement": "Fishing Boats",
"improvementStats": {"food": 1},
"uniques": ["Appears in [Jungle] regions with weight [20]",
"Appears in [Forest] regions with weight [10]",
"Appears in [Desert] regions with weight [5]",
"Appears in [Hill] regions with weight [15]",
"Appears in [Plains] regions with weight [5]",
"Appears in [Grassland] regions with weight [10]",
"Appears in [Hybrid] regions with weight [20]",
"Appears near City States with weight [15]"]
"uniques": ["Generated with weight [20] <in [Jungle] Regions>",
"Generated with weight [10] <in [Forest] Regions>",
"Generated with weight [5] <in [Desert] Regions>",
"Generated with weight [15] <in [Hill] Regions>",
"Generated with weight [5] <in [Plains] Regions>",
"Generated with weight [10] <in [Grassland] Regions>",
"Generated with weight [20] <in [Hybrid] Regions>",
"Generated near City States with weight [15]"]
},
{
"name": "Jewelry",
@ -339,92 +432,4 @@
"gold": 2,
"uniques": ["Can only be created by Mercantile City-States"]
}
{
"name": "Citrus",
"resourceType": "Luxury",
"terrainsCanBeFoundOn": ["Jungle","Forest"],
"food": 1,
"gold": 1,
"improvement": "Plantation",
"improvementStats": {"gold": 1},
"uniques": ["Appears in [Jungle] regions with weight [35]",
"Appears in [Forest] regions with weight [5]",
"Appears in [Desert] regions with weight [5]",
"Appears in [Hybrid] regions with weight [5]",
"Appears near City States with weight [15]"]
},
{
"name": "Copper",
"resourceType": "Luxury",
"terrainsCanBeFoundOn": ["Plains","Grassland","Desert","Tundra","Snow"],
"gold": 2,
"improvement": "Mine",
"improvementStats": {"production": 2},
"uniques": ["Appears in [Tundra] regions with weight [15]",
"Appears in [Jungle] regions with weight [5]",
"Appears in [Forest] regions with weight [5]",
"Appears in [Desert] regions with weight [10]",
"Appears in [Hill] regions with weight [30]",
"Appears in [Grassland] regions with weight [20]",
"Appears in [Hybrid] regions with weight [20]",
"Appears near City States with weight [10]"]
},
/*
{
"name": "Cocoa",
"resourceType": "Luxury",
"terrainsCanBeFoundOn": ["Jungle"],
"food": 1,
"gold": 1,
"improvement": "Plantation",
"improvementStats": {"food": 1,"gold": 1}
},
*/
{
"name": "Crab",
"resourceType": "Luxury",
"terrainsCanBeFoundOn": ["Coast"],
"food": 1,
"gold": 1,
"improvement": "Fishing Boats",
"improvementStats": {"food": 1},
"uniques": ["Appears in [Tundra] regions with weight [30]",
"Appears in [Jungle] regions with weight [5]",
"Appears in [Forest] regions with weight [10]",
"Appears in [Hill] regions with weight [10]",
"Appears in [Plains] regions with weight [5]",
"Appears in [Grassland] regions with weight [20]",
"Appears in [Hybrid] regions with weight [20]",
"Appears near City States with weight [15]"]
},
{
"name": "Salt",
"resourceType": "Luxury",
"terrainsCanBeFoundOn": ["Desert","Tundra","Plains"],
"gold": 1,
"food": 1,
"improvement": "Mine",
"improvementStats": {"food": 1,"production":1},
"uniques": ["Appears in [Tundra] regions with weight [15]",
"Appears in [Forest] regions with weight [5]",
"Appears in [Desert] regions with weight [15]",
"Appears in [Hill] regions with weight [10]",
"Appears in [Plains] regions with weight [25]",
"Appears in [Hybrid] regions with weight [15]",
"Appears near City States with weight [10]"]
},
{
"name": "Truffles",
"resourceType": "Luxury",
"terrainsCanBeFoundOn": ["Forest","Marsh","Jungle"],
"gold": 2,
"improvement": "Camp",
"improvementStats": {"gold": 1},
"uniques": ["Appears in [Jungle] regions with weight [5]",
"Appears in [Forest] regions with weight [30]",
"Appears in [Plains] regions with weight [5]",
"Appears in [Grassland] regions with weight [5]",
"Appears in [Hybrid] regions with weight [10]",
"Appears near City States with weight [15]"]
}
]

View File

@ -278,9 +278,6 @@ object GameStarter {
for (civ in gameInfo.civilizations.filter { !it.isBarbarian() && !it.isSpectator() }) {
val startingLocation = startingLocations[civ]!!
if(civ.isCityState())
addCityStateLuxury(gameInfo, startingLocation)
for (tile in startingLocation.getTilesInDistance(3)) {
if (tile.improvement != null
&& tile.getTileImprovement()!!.isAncientRuinsEquivalent()
@ -451,28 +448,4 @@ object GameStarter {
}
return preferredTiles.lastOrNull() ?: freeTiles.last()
}
private fun addCityStateLuxury(gameInfo: GameInfo, spawn: TileInfo) {
// Every city state should have at least one luxury to trade
val relevantTiles = spawn.getTilesInDistance(2).shuffled()
for (tile in relevantTiles) {
if(tile.resource != null && tile.tileResource.resourceType == ResourceType.Luxury)
return // At least one luxury; all set
}
for (tile in relevantTiles) {
// Add a luxury to the first eligible tile
if (tile.resource != null)
continue
val luxuryToAdd = gameInfo.ruleSet.tileResources.values
.filter { it.terrainsCanBeFoundOn.contains(tile.getLastTerrain().name) && it.resourceType == ResourceType.Luxury }
.randomOrNull()
if (luxuryToAdd != null) {
tile.resource = luxuryToAdd.name
return
}
}
}
}

View File

@ -131,11 +131,20 @@ object MapType {
const val empty = "Empty"
}
object MapResources {
const val sparse = "Sparse"
const val default = "Default"
const val abundant = "Abundant"
const val strategicBalance = "Strategic Balance"
const val legendaryStart = "Legendary Start"
}
class MapParameters {
var name = ""
var type = MapType.pangaea
var shape = MapShape.hexagonal
var mapSize = MapSizeNew(MapSize.Medium)
var mapResources = MapResources.default
var noRuins = false
var noNaturalWonders = false
var worldWrap = false
@ -162,6 +171,7 @@ class MapParameters {
it.type = type
it.shape = shape
it.mapSize = mapSize.clone()
it.mapResources = mapResources
it.noRuins = noRuins
it.noNaturalWonders = noNaturalWonders
it.worldWrap = worldWrap
@ -213,6 +223,7 @@ class MapParameters {
if (worldWrap) yield("wrapped ")
yield(shape)
yield(" " + displayMapDimensions())
yield(mapResources)
if (name.isEmpty()) return@sequence
yield(", $type, Seed $seed, ")
yield("$elevationExponent/$temperatureExtremeness/$resourceRichness/$vegetationRichness/")

View File

@ -530,6 +530,8 @@ open class TileInfo {
resource -> observingCiv != null && hasViewableResource(observingCiv)
"Water resource" -> isWater && observingCiv != null && hasViewableResource(observingCiv)
"Natural Wonder" -> naturalWonder != null
"Featureless" -> terrainFeatures.isEmpty()
"Fresh Water" -> isAdjacentToFreshwater
else -> {
if (terrainFeatures.contains(filter)) return true
if (hasUnique(filter)) return true
@ -795,21 +797,30 @@ open class TileInfo {
fun setTileResource(newResource: TileResource, majorDeposit: Boolean = false) {
resource = newResource.name
if (newResource.resourceType != ResourceType.Strategic) return
for (unique in newResource.getMatchingUniques(UniqueType.ResourceAmountOnTiles)) {
if (matchesTerrainFilter(unique.params[0])) {
resourceAmount = unique.params[1].toInt()
return
}
}
// Stick to default for now
resourceAmount = if (majorDeposit)
newResource.majorDepositAmount.default
else
newResource.minorDepositAmount.default
resourceAmount = when (tileMap.mapParameters.mapResources) {
MapResources.sparse -> {
if (majorDeposit) newResource.majorDepositAmount.sparse
else newResource.minorDepositAmount.sparse
}
MapResources.abundant -> {
if (majorDeposit) newResource.majorDepositAmount.abundant
else newResource.minorDepositAmount.abundant
}
else -> {
if (majorDeposit) newResource.majorDepositAmount.default
else newResource.minorDepositAmount.default
}
}
}

View File

@ -78,7 +78,7 @@ class MapGenerator(val ruleset: Ruleset) {
runAndMeasure("RiverGenerator") {
RiverGenerator(map, randomness).spawnRivers()
}
// Region based map generation - not used when generating maps in worldbuilder
// Region based map generation - not used when generating maps in map editor
if (civilizations.isNotEmpty()) {
val regions = MapRegions(ruleset)
runAndMeasure("generateRegions") {
@ -90,13 +90,15 @@ class MapGenerator(val ruleset: Ruleset) {
runAndMeasure("placeResourcesAndMinorCivs") {
regions.placeResourcesAndMinorCivs(map, civilizations.filter { ruleset.nations[it.civName]!!.isCityState() })
}
} else {
// Fallback spread resources function - used when generating maps in map editor
runAndMeasure("spreadResources") {
spreadResources(map)
}
}
runAndMeasure("NaturalWonderGenerator") {
NaturalWonderGenerator(ruleset, randomness).spawnNaturalWonders(map)
}
runAndMeasure("spreadResources") {
spreadResources(map)
}
runAndMeasure("spreadAncientRuins") {
spreadAncientRuins(map)
}
@ -175,10 +177,8 @@ class MapGenerator(val ruleset: Ruleset) {
private fun spreadResources(tileMap: TileMap) {
val mapRadius = tileMap.mapParameters.mapSize.radius
// Commenting this out for now not to interfere with start normalization - will be restored when
// region-based resource placement is implemented, then this function will be map editor only.
/*for (tile in tileMap.values)
tile.resource = null*/
for (tile in tileMap.values)
tile.resource = null
spreadStrategicResources(tileMap, mapRadius)
spreadResources(tileMap, mapRadius, ResourceType.Luxury)

View File

@ -2,24 +2,23 @@ package com.unciv.logic.map.mapgenerator
import com.badlogic.gdx.math.Rectangle
import com.badlogic.gdx.math.Vector2
import com.unciv.Constants
import com.unciv.logic.HexMath
import com.unciv.logic.civilization.CivilizationInfo
import com.unciv.logic.map.MapShape
import com.unciv.logic.map.TileInfo
import com.unciv.logic.map.TileMap
import com.unciv.logic.map.*
import com.unciv.models.ruleset.Ruleset
import com.unciv.models.ruleset.tile.ResourceType
import com.unciv.models.ruleset.tile.Terrain
import com.unciv.models.ruleset.tile.TerrainType
import com.unciv.models.ruleset.tile.TileResource
import com.unciv.models.ruleset.unique.StateForConditionals
import com.unciv.models.ruleset.unique.Unique
import com.unciv.models.ruleset.unique.UniqueType
import com.unciv.models.stats.Stat
import com.unciv.models.translations.equalsPlaceholderText
import com.unciv.models.translations.getPlaceholderParameters
import com.unciv.ui.utils.randomWeighted
import kotlin.math.*
import kotlin.random.Random
class MapRegions (val ruleset: Ruleset){
companion object {
@ -33,10 +32,26 @@ class MapRegions (val ruleset: Ruleset){
val secondRingFoodScores = listOf(0, 2, 5, 10, 20, 25, 28, 30, 32, 34, 35)
val secondRingProdScores = listOf(0, 10, 20, 25, 30, 35)
val closeStartPenaltyForRing =
mapOf( 0 to 99, 1 to 97, 2 to 95,
3 to 92, 4 to 89, 5 to 69,
6 to 57, 7 to 24, 8 to 15 )
val closeStartPenaltyForRing = mapOf(
0 to 99, 1 to 97, 2 to 95,
3 to 92, 4 to 89, 5 to 69,
6 to 57, 7 to 24, 8 to 15 )
val randomLuxuryRatios = mapOf(
1 to listOf(1f),
2 to listOf(0.55f, 0.44f),
3 to listOf(0.40f, 0.33f, 0.27f),
4 to listOf(0.35f, 0.25f, 0.25f, 0.15f),
5 to listOf(0.25f, 0.25f, 0.20f, 0.15f, 0.15f),
6 to listOf(0.20f, 0.20f, 0.20f, 0.15f, 0.15f, 0.10f),
7 to listOf(0.20f, 0.20f, 0.15f, 0.15f, 0.10f, 0.10f, 0.10f),
8 to listOf(0.20f, 0.15f, 0.15f, 0.10f, 0.10f, 0.10f, 0.10f, 0.10f)
)
// This number is 23 in G&K, but there's a bug where hills are exempt so this number brings
// the result closer to the density and distribution that was probably intended.
const val baseMinorDepositFrequency = 30
}
private val regions = ArrayList<Region>()
@ -224,7 +239,7 @@ class MapRegions (val ruleset: Ruleset){
}
// Normalize starts
for (region in regions) {
normalizeStart(tileMap[region.startPosition!!], minorCiv = false)
normalizeStart(tileMap[region.startPosition!!], tileMap, minorCiv = false)
}
val coastBiasCivs = civilizations.filter { ruleset.nations[it.civName]!!.startBias.contains("Coast") }
@ -340,13 +355,9 @@ class MapRegions (val ruleset: Ruleset){
// Place impacts to keep city states etc at appropriate distance
placeImpact(ImpactType.MinorCiv,tile, 6)
/* lets leave these commented until resource placement is actually implemented
placeImpact(ImpactType.Luxury, tile, 3)
placeImpact(ImpactType.Strategic,tile, 0)
placeImpact(ImpactType.Bonus, tile, 3)
placeImpact(ImpactType.Fish, tile, 3)
placeImpact(ImpactType.NaturalWonder, tile, 4)
*/
}
/** Attempts to find a good start close to the center of [region]. Calls setRegionStart with the position*/
@ -466,7 +477,7 @@ class MapRegions (val ruleset: Ruleset){
* Relies on startPosition having been set previously.
* Assumes unchanged baseline values ie citizens eat 2 food each, similar production costs
* If [minorCiv] is true, different weightings will be used. */
private fun normalizeStart(startTile: TileInfo, minorCiv: Boolean) {
private fun normalizeStart(startTile: TileInfo, tileMap: TileMap, minorCiv: Boolean) {
// Remove ice-like features adjacent to start
for (tile in startTile.neighbors) {
val lastTerrain = tile.getTerrainFeatures().lastOrNull { it.impassable }
@ -495,7 +506,20 @@ class MapRegions (val ruleset: Ruleset){
}
}
// TODO: Strategic Balance Resources
// Place Strategic Balance Resources
if (tileMap.mapParameters.mapResources == MapResources.strategicBalance) {
val candidateTiles = startTile.getTilesInDistanceRange(1..2).shuffled() + startTile.getTilesAtDistance(3).shuffled()
for (resource in ruleset.tileResources.values.filter { it.hasUnique(UniqueType.StrategicBalanceResource) }) {
if (tryAddingResourceToTiles(resource, 1, candidateTiles, majorDeposit = true) == 0) {
// Fallback mode - force placement, even on an otherwise inappropriate terrain. Do still respect water and impassible tiles!
if (isWaterOnlyResource(resource))
placeResourcesInTiles(999, candidateTiles.filter { it.isWater && !it.isImpassible() }.toList(), listOf(resource), majorDeposit = true, forcePlacement = true)
else
placeResourcesInTiles(999, candidateTiles.filter { it.isLand && !it.isImpassible() }.toList(), listOf(resource), majorDeposit = true, forcePlacement = true)
}
}
}
// If bad early production, add a small strategic resource to SECOND ring (not for minors)
if (!minorCiv && innerProduction < 3 && earlyProduction < 6) {
@ -505,16 +529,11 @@ class MapRegions (val ruleset: Ruleset){
it.resourceType == ResourceType.Strategic &&
(it.revealedBy == null ||
ruleset.technologies[it.revealedBy]!!.era() in earlyEras)
}
if (validResources.isNotEmpty()) {
for (tile in startTile.getTilesAtDistance(2).shuffled()) {
val resourceToPlace = validResources.filter { tile.getLastTerrain().name in it.terrainsCanBeFoundOn }.randomOrNull()
if (resourceToPlace != null) {
tile.setTileResource(resourceToPlace, majorDeposit = false)
break
}
}
}.shuffled()
val candidateTiles = startTile.getTilesAtDistance(2).shuffled()
for (resource in validResources) {
if (tryAddingResourceToTiles(resource, 1, candidateTiles, majorDeposit = false) > 0)
break
}
}
@ -551,8 +570,8 @@ class MapRegions (val ruleset: Ruleset){
else -> 0
}
}
// TODO: Legendary start? +2
if (tileMap.mapParameters.mapResources == MapResources.legendaryStart)
bonusesNeeded += 2
// Attempt to place one grassland at a plains-only spot (nor for minors)
if (!minorCiv && bonusesNeeded < 3 && totalNativeTwoFood == 0) {
@ -589,6 +608,8 @@ class MapRegions (val ruleset: Ruleset){
while (bonusesNeeded > 0 && candidatePlots.isNotEmpty()) {
val plot = candidatePlots.first()
candidatePlots.remove(plot) // remove the plot as it has now been tried, whether successfully or not
if (plot.getBaseTerrain().hasUnique(UniqueType.BlocksResources, StateForConditionals(attackedTile = plot)))
continue // Don't put bonuses on snow hills
val validBonuses = ruleset.tileResources.values.filter {
it.resourceType == ResourceType.Bonus &&
@ -776,8 +797,8 @@ class MapRegions (val ruleset: Ruleset){
fun placeResourcesAndMinorCivs(tileMap: TileMap, minorCivs: List<CivilizationInfo>) {
assignLuxuries()
placeMinorCivs(tileMap, minorCivs)
// TODO: place luxuries
// TODO: place strategic and bonus resources
placeLuxuries(tileMap)
placeStrategicAndBonuses(tileMap)
}
/** Assigns a luxury to each region. No luxury can be assigned to too many regions.
@ -787,26 +808,33 @@ class MapRegions (val ruleset: Ruleset){
// If there are any weightings defined in json, assume they are complete. If there are none, use flat weightings instead
val fallbackWeightings = ruleset.tileResources.values.none {
it.resourceType == ResourceType.Luxury &&
(it.hasUnique(UniqueType.LuxuryWeighting) || it.hasUnique(UniqueType.LuxuryWeightingForCityStates)) }
(it.uniqueObjects.any { unique -> unique.isOfType(UniqueType.ResourceWeighting) } || it.hasUnique(UniqueType.LuxuryWeightingForCityStates)) }
val maxRegionsWithLuxury = if (regions.count() > 12) 3 else 2
val maxRegionsWithLuxury = when {
regions.count() > 12 -> 3
regions.count() > 8 -> 2
else -> 1
}
val targetCityStateLuxuries = 3 // was probably intended to be "if (tileData.size > 5000) 4 else 3"
val disabledPercent = 100 - min(tileData.size.toFloat().pow(0.2f) * 16, 100f).toInt() // Approximately
val targetDisabledLuxuries = (ruleset.tileResources.values
.count { it.resourceType == ResourceType.Luxury } * disabledPercent) / 100
val assignableLuxuries = ruleset.tileResources.values.filter {
it.resourceType == ResourceType.Luxury &&
!it.hasUnique(UniqueType.LuxurySpecialPlacement) &&
!it.hasUnique(UniqueType.CityStateOnlyResource) }
val amountRegionsWithLuxury = HashMap<String, Int>()
// Init map
ruleset.tileResources.values
.forEach { amountRegionsWithLuxury[it.name] = 0 }
for (region in regions.sortedBy { getRegionPriority(ruleset.terrains[it.type]) } ) {
var candidateLuxuries = ruleset.tileResources.values.filter {
it.resourceType == ResourceType.Luxury &&
val regionConditional = StateForConditionals(region = region)
var candidateLuxuries = assignableLuxuries.filter {
amountRegionsWithLuxury[it.name]!! < maxRegionsWithLuxury &&
// Check that it has a weight for this region type
(fallbackWeightings ||
it.getMatchingUniques(UniqueType.LuxuryWeighting).any { unique -> unique.params[0] == region.type } ) &&
it.hasUnique(UniqueType.ResourceWeighting, regionConditional)) &&
// Check that there is enough coast if it is a water based resource
((region.terrainCounts["Coastal"] ?: 0) >= 12 ||
it.terrainsCanBeFoundOn.any { terrain -> ruleset.terrains[terrain]!!.type != TerrainType.Water } )
@ -814,8 +842,7 @@ class MapRegions (val ruleset: Ruleset){
// If we couldn't find any options, pick from all luxuries. First try to not pick water luxuries on land regions
if (candidateLuxuries.isEmpty()) {
candidateLuxuries = ruleset.tileResources.values.filter {
it.resourceType == ResourceType.Luxury &&
candidateLuxuries = assignableLuxuries.filter {
amountRegionsWithLuxury[it.name]!! < maxRegionsWithLuxury &&
// Ignore weightings for this pass
// Check that there is enough coast if it is a water based resource
@ -825,8 +852,7 @@ class MapRegions (val ruleset: Ruleset){
}
// If there are still no candidates, ignore water restrictions
if (candidateLuxuries.isEmpty()) {
candidateLuxuries = ruleset.tileResources.values.filter {
it.resourceType == ResourceType.Luxury &&
candidateLuxuries = assignableLuxuries.filter {
amountRegionsWithLuxury[it.name]!! < maxRegionsWithLuxury
// Ignore weightings and water for this pass
}
@ -836,12 +862,11 @@ class MapRegions (val ruleset: Ruleset){
// Pick a luxury at random. Weight is reduced if the luxury has been picked before
val modifiedWeights = candidateLuxuries.map {
val weightingUnique = it.getMatchingUniques(UniqueType.LuxuryWeighting)
.filter { unique -> unique.params[0] == region.type }.firstOrNull()
val weightingUnique = it.getMatchingUniques(UniqueType.ResourceWeighting, regionConditional).firstOrNull()
if (weightingUnique == null)
1f / (1f + amountRegionsWithLuxury[it.name]!!)
else
weightingUnique.params[1].toFloat() / (1f + amountRegionsWithLuxury[it.name]!!)
weightingUnique.params[0].toFloat() / (1f + amountRegionsWithLuxury[it.name]!!)
}
region.luxury = candidateLuxuries.randomWeighted(modifiedWeights).name
amountRegionsWithLuxury[region.luxury!!] = amountRegionsWithLuxury[region.luxury]!! + 1
@ -849,8 +874,7 @@ class MapRegions (val ruleset: Ruleset){
// Assign luxuries to City States
for (i in 1..targetCityStateLuxuries) {
val candidateLuxuries = ruleset.tileResources.values.filter {
it.resourceType == ResourceType.Luxury &&
val candidateLuxuries = assignableLuxuries.filter {
amountRegionsWithLuxury[it.name] == 0 &&
(fallbackWeightings || it.hasUnique(UniqueType.LuxuryWeightingForCityStates))
}
@ -868,11 +892,9 @@ class MapRegions (val ruleset: Ruleset){
amountRegionsWithLuxury[luxury] = 1
}
// Assign some resources as random placement. Marble is never random.
val remainingLuxuries = ruleset.tileResources.values.filter {
it.resourceType == ResourceType.Luxury &&
amountRegionsWithLuxury[it.name] == 0 &&
!it.hasUnique(UniqueType.LuxurySpecialPlacement)
// Assign some resources as random placement.
val remainingLuxuries = assignableLuxuries.filter {
amountRegionsWithLuxury[it.name] == 0
}.map { it.name }.shuffled()
randomLuxuries.addAll(remainingLuxuries.drop(targetDisabledLuxuries))
}
@ -1096,57 +1118,508 @@ class MapRegions (val ruleset: Ruleset){
private fun placeMinorCiv(civ: CivilizationInfo, tileMap: TileMap, tile: TileInfo) {
tileMap.addStartingLocation(civ.civName, tile)
placeImpact(ImpactType.MinorCiv,tile, 4)
/* lets leave these commented until resource placement is actually implemented
placeImpact(ImpactType.Luxury, tile, 3)
placeImpact(ImpactType.Strategic,tile, 0)
placeImpact(ImpactType.Bonus, tile, 3)
placeImpact(ImpactType.Fish, tile, 3)
placeImpact(ImpactType.Marble, tile, 4) */
normalizeStart(tile, minorCiv = true)
normalizeStart(tile, tileMap, minorCiv = true)
}
/** Places all Luxuries onto [tileMap]. Assumes that assignLuxuries and placeMinorCivs have been called. */
private fun placeLuxuries(tileMap: TileMap) {
// First place luxuries at major civ start locations
val averageFertilityDensity = regions.sumOf { it.totalFertility } / regions.sumOf { it.tiles.count() }.toFloat()
for (region in regions) {
var targetLuxuries = 1
if (tileMap.mapParameters.mapResources == MapResources.legendaryStart)
targetLuxuries++
if (region.totalFertility / region.tiles.count().toFloat() < averageFertilityDensity) {
targetLuxuries++
}
val luxuryToPlace = ruleset.tileResources[region.luxury]!!
// First check 2 inner rings
val firstPass = tileMap[region.startPosition!!].getTilesInDistanceRange(1..2)
.shuffled().sortedBy { it.getTileFertility(false) } // Check bad tiles first
targetLuxuries -= tryAddingResourceToTiles(luxuryToPlace, targetLuxuries, firstPass, 0.5f) // Skip every 2nd tile on first pass
if (targetLuxuries > 0) {
val secondPass = firstPass + tileMap[region.startPosition!!].getTilesAtDistance(3)
.shuffled().sortedBy { it.getTileFertility(false) } // Check bad tiles first
targetLuxuries -= tryAddingResourceToTiles(luxuryToPlace, targetLuxuries, secondPass)
}
if (targetLuxuries > 0) {
// Try adding in 1 luxury from the random rotation as compensation
for (luxury in randomLuxuries) {
if (tryAddingResourceToTiles(ruleset.tileResources[luxury]!!, 1, firstPass) > 0) break
}
}
}
// Second place one (1) luxury at minor civ start locations
// Check only ones that got a start location
for (startLocation in tileMap.startingLocationsByNation
.filterKeys { ruleset.nations[it]!!.isCityState() }.map { it.value.first() }) {
val region = regions.firstOrNull { startLocation in it.tiles }
val tilesToCheck = startLocation.getTilesInDistanceRange(1..2)
// 75% probability that we first attempt to place a "city state" luxury, then a random or regional one
// 25% probability of going the other way around
val globalLuxuries = if (region?.luxury != null) randomLuxuries + listOf(region.luxury) else randomLuxuries
val candidateLuxuries = if (Random.nextInt(100) >= 25)
cityStateLuxuries.shuffled() + globalLuxuries.shuffled()
else
globalLuxuries.shuffled() + cityStateLuxuries.shuffled()
// Now try adding one until we are successful
for (luxury in candidateLuxuries) {
if (tryAddingResourceToTiles(ruleset.tileResources[luxury]!!, 1, tilesToCheck) > 0) break
}
}
// Third add regional luxuries
// The target number depends on map size and how close we are to an "ideal number" of civs for the map
val idealCivs = max(2, tileData.size / 500)
var regionTargetNumber = (tileData.size / 600) - (0.3f * abs(regions.count() - idealCivs)).toInt()
regionTargetNumber += when (tileMap.mapParameters.mapResources) {
MapResources.abundant -> 1
MapResources.sparse -> -1
else -> 0
}
regionTargetNumber = max(1, regionTargetNumber)
for (region in regions) {
val resource = ruleset.tileResources[region.luxury]!!
if (isWaterOnlyResource(resource))
tryAddingResourceToTiles(resource, regionTargetNumber,
tileMap.getTilesInRectangle(region.rect).filter { it.isWater && it.neighbors.any { neighbor -> neighbor.getContinent() == region.continentID } }.shuffled(),
0.4f, true, 4, 2)
else
tryAddingResourceToTiles(resource, regionTargetNumber, region.tiles.asSequence().shuffled(), 0.4f,
true, 4, 2)
}
// Fourth add random luxuries
if (randomLuxuries.isNotEmpty()) {
var targetRandomLuxuries = tileData.size.toFloat().pow(0.45f).toInt() // Approximately
targetRandomLuxuries *= when (tileMap.mapParameters.mapResources) {
MapResources.sparse -> 80
MapResources.abundant -> 133
else -> 100
}
targetRandomLuxuries /= 100
targetRandomLuxuries += Random.nextInt(regions.count()) // Add random number based on number of civs
val minimumRandomLuxuries = tileData.size.toFloat().pow(0.2f).toInt() // Approximately
val worldTiles = tileMap.values.asSequence().shuffled()
for ((index, luxury) in randomLuxuries.shuffled().withIndex()) {
val targetForThisLuxury = if (randomLuxuries.count() > 8) targetRandomLuxuries / 10
else {
val minimum = max(3, minimumRandomLuxuries - index)
max(minimum, (targetRandomLuxuries * randomLuxuryRatios[randomLuxuries.count()]!![index] + 0.5f).toInt())
}
tryAddingResourceToTiles(ruleset.tileResources[luxury]!!, targetForThisLuxury, worldTiles, 0.25f,
true, 4, 2)
}
}
val specialLuxuries = ruleset.tileResources.values.filter {
it.resourceType == ResourceType.Luxury &&
it.hasUnique(UniqueType.LuxurySpecialPlacement)
}
val placedSpecials = HashMap<String, Int>()
specialLuxuries.forEach { placedSpecials[it.name] = 0 } // init map
// Fifth, on resource settings other than sparse, add an extra luxury to starts
if (tileMap.mapParameters.mapResources != MapResources.sparse) {
for (region in regions) {
val tilesToCheck = tileMap[region.startPosition!!].getTilesInDistanceRange(1..2)
val candidateLuxuries = randomLuxuries.shuffled().toMutableList()
if (tileMap.mapParameters.mapResources != MapResources.strategicBalance)
candidateLuxuries += specialLuxuries.shuffled().map { it.name } // Include marble!
candidateLuxuries += cityStateLuxuries.shuffled()
candidateLuxuries += regions.mapNotNull { it.luxury }.shuffled()
for (luxury in candidateLuxuries) {
if (tryAddingResourceToTiles(ruleset.tileResources[luxury]!!, 1, tilesToCheck) > 0) {
if (placedSpecials.containsKey(luxury)) // Keep track of marble-type specials as they may be placed now.
placedSpecials[luxury] = placedSpecials[luxury]!! + 1
break
}
}
}
}
// Sixth, top up marble-type specials if needed
for (special in specialLuxuries) {
val targetNumber = when (tileMap.mapParameters.mapResources) {
MapResources.sparse -> (regions.count() * 0.5f).toInt()
MapResources.abundant -> (regions.count() * 0.9f).toInt()
else -> (regions.count() * 0.75f).toInt()
}
val numberToPlace = max(2, targetNumber - placedSpecials[special.name]!!)
tryAddingResourceToTiles(special, numberToPlace, tileMap.values.asSequence().shuffled(), 1f,
true, 6, 0)
}
}
private fun placeStrategicAndBonuses(tileMap: TileMap) {
val strategicResources = ruleset.tileResources.values.filter { it.resourceType == ResourceType.Strategic }
// As usual, if there are any relevant json definitions, assume they are complete
val fallbackStrategic = ruleset.tileResources.values.none {
it.resourceType == ResourceType.Strategic &&
it.uniqueObjects.any { unique -> unique.isOfType(UniqueType.ResourceWeighting) } ||
it.uniqueObjects.any { unique -> unique.isOfType(UniqueType.MinorDepositWeighting) }
}
/* There are a couple competing/complementary distribution systems at work here. First, major
deposits are placed according to a frequency defined in the terrains themselves, for each
tile that is eligible to get a major deposit, there is a weighted random choice between
resource types.
Minor deposits are placed by randomly picking a number of land tiles from anywhere on the
map (so not stratified by terrain type) and assigning a weighted randomly picked resource.
Bonuses are placed according to a frequency for a rule like "every 8 jungle hills", here
implemented as a conditional.
We need to build lists of all tiles following a given rule to place these, which is BY FAR
the most expensive calculation in this entire class. To save some time we anonymize the
uniques so we only have to make one list for each set of conditionals, so eg Wheat and
Horses can share a list since they are both interested in Featureless Plains.
We also save a list of all land tiles for minor deposit generation. */
// Determines number tiles per resource
val bonusMultiplier = when (tileMap.mapParameters.mapResources) {
MapResources.sparse -> 1.5f
MapResources.abundant -> 0.6667f
else -> 1f
}
val landList = ArrayList<TileInfo>() // For minor deposits
val ruleLists = HashMap<Unique, MutableList<TileInfo>>() // For rule-based generation
// Figure out which rules (sets of conditionals) need lists built
for (resource in ruleset.tileResources.values.filter {
it.resourceType == ResourceType.Strategic ||
it.resourceType == ResourceType.Bonus }) {
for (rule in resource.uniqueObjects.filter { unique ->
unique.isOfType(UniqueType.ResourceFrequency) ||
unique.isOfType(UniqueType.ResourceWeighting) ||
unique.isOfType(UniqueType.MinorDepositWeighting) }) {
// Weed out some clearly impossible rules straight away to save time later
if (rule.conditionals.any { conditional ->
(conditional.isOfType(UniqueType.ConditionalOnWaterMaps) && !usingArchipelagoRegions) ||
(conditional.isOfType(UniqueType.ConditionalInRegionOfType) && regions.none { region -> region.type == conditional.params[0] }) ||
(conditional.isOfType(UniqueType.ConditionalInRegionExceptOfType) && regions.all { region -> region.type == conditional.params[0] })
} )
continue
val simpleRule = anonymizeUnique(rule)
if (ruleLists.keys.none { it.text == simpleRule.text }) // Need to do text comparison since the uniques will not be equal otherwise
ruleLists[simpleRule] = ArrayList()
}
}
// Make up some rules for placing strategics in a fallback situation
if (fallbackStrategic) {
val interestingTerrains = strategicResources.flatMap { it.terrainsCanBeFoundOn }.map { ruleset.terrains[it]!! }.toSet()
for (terrain in interestingTerrains) {
val fallbackRule = if (terrain.type == TerrainType.TerrainFeature)
Unique("RULE <in [${terrain.name}] tiles>")
else
Unique("RULE <in [Featureless] [${terrain.name}] tiles>")
if (ruleLists.keys.none { it.text == fallbackRule.text }) // Need to do text comparison since the uniques will not be equal otherwise
ruleLists[fallbackRule] = ArrayList()
}
}
// Now go through the entire map to build lists
for (tile in tileMap.values.asSequence().shuffled()) {
val terrainCondition = StateForConditionals(attackedTile = tile, region = regions.firstOrNull { tile in it.tiles })
if (tile.getBaseTerrain().hasUnique(UniqueType.BlocksResources, terrainCondition))
continue // Don't count snow hills
if (tile.isLand)
landList.add(tile)
for ((rule, list) in ruleLists) {
if (rule.conditionalsApply(terrainCondition)) {
list.add(tile)
}
}
}
// Keep track of total placed strategic resources in case we need to top them up later
val totalPlaced = HashMap<TileResource, Int>()
strategicResources.forEach { totalPlaced[it] = 0 }
// First place major deposits on land
for (terrain in ruleset.terrains.values.filter { it.type != TerrainType.Water }) {
// Figure out if we generated a list for this terrain
val list = ruleLists.filterKeys { it.text == getTerrainRule(terrain).text }.values.firstOrNull()
if (list == null) {
// If not the terrain can be safely skipped
continue
}
totalPlaced += placeMajorDeposits(list, terrain, fallbackStrategic, 2, 2)
}
// Second add some small deposits of modern strategic resources to city states
val lastEra = ruleset.eras.values.maxOf { it.eraNumber }
val modernOptions = strategicResources.filter {
it.revealedBy != null &&
ruleset.eras[ruleset.technologies[it.revealedBy]!!.era()]!!.eraNumber >= lastEra / 2
}
for (cityStateLocation in tileMap.startingLocationsByNation.filterKeys { ruleset.nations[it]!!.isCityState() }.values.map { it.first() }) {
val resourceToPlace = modernOptions.random()
totalPlaced[resourceToPlace] =
totalPlaced[resourceToPlace]!! + tryAddingResourceToTiles(resourceToPlace, 1, cityStateLocation.getTilesInDistanceRange(1..3))
}
// Third add some minor deposits to land tiles
// Note: In G&K there is a bug where minor deposits are never placed on hills. We're not replicating that.
val frequency = (baseMinorDepositFrequency * bonusMultiplier).toInt()
val minorDepositsToAdd = (landList.count() / frequency) + 1
var minorDepositsAdded = 0
for (tile in landList) {
if (tile.resource != null || tileData[tile.position]!!.impacts.containsKey(ImpactType.Strategic))
continue
val conditionalTerrain = StateForConditionals(attackedTile = tile)
if (tile.getBaseTerrain().hasUnique(UniqueType.BlocksResources, conditionalTerrain))
continue
val weightings = strategicResources.map {
if (fallbackStrategic) {
if (tile.getLastTerrain().name in it.terrainsCanBeFoundOn) 1f else 0f
} else {
val uniques = it.getMatchingUniques(UniqueType.MinorDepositWeighting, conditionalTerrain).toList()
uniques.sumOf { unique -> unique.params[0].toInt() }.toFloat()
}
}
if (weightings.sum() <= 0) {
continue
}
val resourceToPlace = strategicResources.randomWeighted(weightings)
tile.setTileResource(resourceToPlace, majorDeposit = false)
placeImpact(ImpactType.Strategic, tile, Random.nextInt(2) + Random.nextInt(2))
totalPlaced[resourceToPlace] = totalPlaced[resourceToPlace]!! + 1
minorDepositsAdded++
if (minorDepositsAdded >= minorDepositsToAdd)
break
}
// Fourth add water-based major deposits. Extra impact because we don't want them too clustered and there is usually lots to go around
for (terrain in ruleset.terrains.values.filter { it.type == TerrainType.Water }) {
// Figure out if we generated a list for this terrain
val list = ruleLists.filterKeys { it.text == getTerrainRule(terrain).text }.values.firstOrNull()
if (list == null) {
// If not the terrain can be safely skipped
continue
}
totalPlaced += placeMajorDeposits(list, terrain, fallbackStrategic, 4, 3)
}
// Fifth place up to 2 extra deposits of each resource type if there is < 1 per civ
for (resource in strategicResources) {
val extraNeeded = min(2, regions.count() - totalPlaced[resource]!!)
if (extraNeeded > 0) {
if (isWaterOnlyResource(resource))
tryAddingResourceToTiles(resource, extraNeeded, tileMap.values.asSequence().filter { it.isWater }.shuffled(), respectImpacts = true)
else
tryAddingResourceToTiles(resource, extraNeeded, landList.asSequence(), respectImpacts = true)
}
}
// Figure out if bonus generation rates are defined in json. Assume that if there are any, the definitions are complete.
val fallbackBonuses = ruleset.tileResources.values.none { it.uniqueObjects.any { unique -> unique.type == UniqueType.ResourceFrequency } }
// Sixth place bonus resources (and other resources that might have been assigned frequency-based generation).
// Water-based bonuses go last and have extra impact, because coasts are very common and we don't want too much clustering
val sortedResourceList = ruleset.tileResources.values.sortedBy { isWaterOnlyResource(it) }
for (resource in sortedResourceList) {
val extraImpact = if (isWaterOnlyResource(resource)) 1 else 0
for (rule in resource.uniqueObjects.filter { it.type == UniqueType.ResourceFrequency }) {
// Figure out which list applies, if any
val simpleRule = anonymizeUnique(rule)
val list = ruleLists.filterKeys { it.text == simpleRule.text }.values.firstOrNull()
// If there is no matching list, it is because the rule was determined to be impossible and so can be safely skipped
if (list == null) continue
// Place the resources
placeResourcesInTiles((rule.params[0].toFloat() * bonusMultiplier).toInt(), list, listOf(resource), 0 + extraImpact, 2 + extraImpact, false)
}
if(fallbackBonuses && resource.resourceType == ResourceType.Bonus) {
// Since we haven't been able to generate any rule-based lists, just generate new ones on the fly
// Increase impact to avoid clustering since there is no terrain type stratification.
val fallbackList = tileMap.values.filter { it.getLastTerrain().name in resource.terrainsCanBeFoundOn }.shuffled()
placeResourcesInTiles((20 * bonusMultiplier).toInt(), fallbackList, listOf(resource), 2 + extraImpact, 2 + extraImpact, false)
}
}
// Seventh (and finally!) place an extra bonus in the THIRD ring of each start to make it slightly more attractive
for (region in regions) {
val terrain = if (region.type == "Hybrid") region.terrainCounts.filterNot { it.key == "Coastal" }.maxByOrNull { it.value }!!.key
else region.type
val resourceUnique = ruleset.terrains[terrain]!!.getMatchingUniques(UniqueType.RegionExtraResource).firstOrNull()
// If this region has an explicit "this is the bonus" unique go with that, else random appropriate
val resource = if (resourceUnique != null) ruleset.tileResources[resourceUnique.params[0]]!!
else ruleset.tileResources.values.filter { it.resourceType == ResourceType.Bonus && terrain in it.terrainsCanBeFoundOn }.random()
val candidateTiles = tileMap[region.startPosition!!].getTilesAtDistance(3).shuffled()
val amount = if (resourceUnique != null) 2 else 1 // Place an extra if the region type requests it
if (tryAddingResourceToTiles(resource, amount, candidateTiles) == 0) {
// We couldn't place any, try adding a fish instead
val fishyBonus = ruleset.tileResources.values.filter { it.resourceType == ResourceType.Bonus &&
it.terrainsCanBeFoundOn.any { terrainName -> ruleset.terrains[terrainName]!!.type == TerrainType.Water } }
.randomOrNull()
if (fishyBonus != null)
tryAddingResourceToTiles(fishyBonus, 1, candidateTiles)
}
}
}
/** Attempts to place [amount] [resource] on [tiles], checking tiles in order. A [ratio] below 1 means skipping
* some tiles, ie ratio = 0.25 will put a resource on every 4th eligible tile. Can optionally respect impact flags,
* and places impact if [baseImpact] >= 0. Returns number of placed resources. */
private fun tryAddingResourceToTiles(resource: TileResource, amount: Int, tiles: Sequence<TileInfo>, ratio: Float = 1f,
respectImpacts: Boolean = false, baseImpact: Int = -1, randomImpact: Int = 0,
majorDeposit: Boolean = false): Int {
if (amount <= 0) return 0
var amountAdded = 0
var ratioProgress = 1f
val impactType = when (resource.resourceType) {
ResourceType.Luxury -> ImpactType.Luxury
ResourceType.Strategic -> ImpactType.Strategic
ResourceType.Bonus -> ImpactType.Bonus
}
for (tile in tiles) {
val conditionalTerrain = StateForConditionals(attackedTile = tile)
if (tile.resource == null &&
tile.getLastTerrain().name in resource.terrainsCanBeFoundOn &&
!tile.getBaseTerrain().hasUnique(UniqueType.BlocksResources, conditionalTerrain) &&
!resource.hasUnique(UniqueType.NoNaturalGeneration, conditionalTerrain)) {
if (ratioProgress >= 1f &&
!(respectImpacts && tileData[tile.position]!!.impacts.containsKey(impactType))) {
tile.setTileResource(resource, majorDeposit)
ratioProgress -= 1f
amountAdded++
if (baseImpact + randomImpact >= 0)
placeImpact(impactType, tile, baseImpact + Random.nextInt(randomImpact + 1))
if (amountAdded >= amount) break
}
ratioProgress += ratio
}
}
return amountAdded
}
/** Attempts to place major deposits in a [tileList] consisting exclusively of [terrain] tiles.
* Lifted out of the main function to allow postponing water resources.
* @return a map of resource types to placed deposits. */
private fun placeMajorDeposits(tileList: List<TileInfo>, terrain: Terrain, fallbackWeightings: Boolean, baseImpact: Int, randomImpact: Int): Map<TileResource, Int> {
if (tileList.isEmpty())
return mapOf()
val frequency = if (terrain.hasUnique(UniqueType.MajorStrategicFrequency))
terrain.getMatchingUniques(UniqueType.MajorStrategicFrequency).first().params[0].toInt()
else 25
val resourceOptions = ruleset.tileResources.values.filter {
it.resourceType == ResourceType.Strategic &&
((fallbackWeightings && terrain.name in it.terrainsCanBeFoundOn) ||
it.uniqueObjects.any { unique -> anonymizeUnique(unique).text == getTerrainRule(terrain).text })
}
return if (resourceOptions.isNotEmpty())
placeResourcesInTiles(frequency, tileList, resourceOptions, baseImpact, randomImpact, true)
else
mapOf()
}
/** Given a [tileList] and possible [resourceOptions], will place a resource on every [frequency] tiles.
* Tries to avoid impacts, but falls back to lowest impact otherwise.
* Goes through the list in order, so pre-shuffle it!
* Assumes all tiles in the list are of the same terrain type when generating weightings, irrelevant if only one option.
* Respects terrainsCanBeFoundOn when there is only one option, unless [forcePlacement] is true.
* @return a map of the resources in the options list to number placed. */
private fun placeResourcesInTiles(frequency: Int, tileList: List<TileInfo>, resourceOptions: List<TileResource>,
baseImpact: Int = 0, randomImpact: Int = 0, majorDeposit: Boolean = false, forcePlacement: Boolean = false): Map<TileResource, Int> {
if (tileList.isEmpty() || resourceOptions.isEmpty()) return mapOf()
val impactType = when (resourceOptions.first().resourceType) {
ResourceType.Strategic -> ImpactType.Strategic
ResourceType.Bonus -> ImpactType.Bonus
ResourceType.Luxury -> ImpactType.Luxury
}
val conditionalTerrain = StateForConditionals(attackedTile = tileList.firstOrNull())
val weightings = resourceOptions.map {
val unique = it.getMatchingUniques(UniqueType.ResourceWeighting, conditionalTerrain).firstOrNull()
if (unique != null)
unique.params[0].toFloat()
else
1f
}
val testTerrains = (resourceOptions.count() == 1) && !forcePlacement
val amountToPlace = (tileList.count() / frequency) + 1
var amountPlaced = 0
val detailedPlaced = HashMap<TileResource, Int>()
resourceOptions.forEach { detailedPlaced[it] = 0 }
val fallbackTiles = ArrayList<TileInfo>()
// First pass - avoid impacts entirely
for (tile in tileList) {
if (tile.resource != null ||
(testTerrains &&
(tile.getLastTerrain().name !in resourceOptions.first().terrainsCanBeFoundOn ||
resourceOptions.first().hasUnique(UniqueType.NoNaturalGeneration, conditionalTerrain)) ) ||
tile.getBaseTerrain().hasUnique(UniqueType.BlocksResources, conditionalTerrain))
continue // Can't place here, can't be a fallback tile
if (tileData[tile.position]!!.impacts.containsKey(impactType)) {
fallbackTiles.add(tile) // Taken but might be a viable fallback tile
} else {
// Add a resource to the tile
val resourceToPlace = resourceOptions.randomWeighted(weightings)
tile.setTileResource(resourceToPlace, majorDeposit)
placeImpact(impactType, tile, baseImpact + Random.nextInt(randomImpact + 1))
amountPlaced++
detailedPlaced[resourceToPlace] = detailedPlaced[resourceToPlace]!! + 1
if (amountPlaced >= amountToPlace) {
return detailedPlaced
}
}
}
// Second pass - place on least impacted tiles
while (amountPlaced < amountToPlace && fallbackTiles.isNotEmpty()) {
// Sorry, we do need to re-sort the list for every pass since new impacts are made with every placement
val bestTile = fallbackTiles.minByOrNull { tileData[it.position]!!.impacts[impactType]!! }!!
fallbackTiles.remove(bestTile)
val resourceToPlace = resourceOptions.randomWeighted(weightings)
bestTile.setTileResource(resourceToPlace, majorDeposit)
placeImpact(impactType, bestTile, baseImpact + Random.nextInt(randomImpact + 1))
amountPlaced++
detailedPlaced[resourceToPlace] = detailedPlaced[resourceToPlace]!! + 1
}
return detailedPlaced
}
/** Adds numbers to tileData in a similar way to closeStartPenalty, but for different types */
private fun placeImpact(type: ImpactType, tile: TileInfo, radius: Int) {
// Epicenter
if (type == ImpactType.Fish || type == ImpactType.Marble)
tileData[tile.position]!!.impacts[type] = 1 // These use different values
else
tileData[tile.position]!!.impacts[type] = 99
tileData[tile.position]!!.impacts[type] = 99
if (radius <= 0) return
for (ring in 1..radius) {
val ringValue = radius - ring + 1
for (outerTile in tile.getTilesAtDistance(ring)) {
val data = tileData[outerTile.position]!!
when (type) {
ImpactType.Marble,
ImpactType.MinorCiv -> data.impacts[type] = 1
ImpactType.Fish -> {
if (data.impacts.containsKey(type))
data.impacts[type] = min(10, max(ringValue, data.impacts[type]!!) + 1)
else
data.impacts[type] = ringValue
}
else -> {
if (data.impacts.containsKey(type))
data.impacts[type] = min(50, max(ringValue, data.impacts[type]!!) + 2)
else
data.impacts[type] = ringValue
}
}
if (data.impacts.containsKey(type))
data.impacts[type] = min(50, max(ringValue, data.impacts[type]!!) + 2)
else
data.impacts[type] = ringValue
}
}
}
/** @return a fake unique with the same conditionals, but sorted alphabetically.
* Used to save some memory and time when building resource lists. */
private fun anonymizeUnique(unique: Unique) = Unique(
"RULE" + unique.conditionals.sortedBy { it.text }.joinToString(prefix = " ", separator = " ") { "<" + it.text + ">" })
/** @return a fake unique with conditionals that will satisfy the same conditions as terrainsCanBeFoundOn */
private fun getTerrainRule(terrain: Terrain): Unique {
return if (terrain.type == TerrainType.TerrainFeature) {
if (terrain.hasUnique(UniqueType.VisibilityElevation))
Unique("RULE <in [${terrain.name}] tiles>")
else
Unique("RULE <in [${terrain.name}] tiles> " + ruleset.terrains.values
.filter { it.type == TerrainType.TerrainFeature && it.hasUnique(UniqueType.VisibilityElevation) }
.joinToString(separator = " ") { "<in tiles without [${it.name}]>" })
} else
Unique("RULE <in [Featureless] [${terrain.name}] tiles>")
}
private fun isWaterOnlyResource(resource: TileResource) = resource.terrainsCanBeFoundOn
.all { terrainName -> ruleset.terrains[terrainName]!!.type == TerrainType.Water }
enum class ImpactType {
Strategic,
Luxury,
Bonus,
Fish,
MinorCiv,
NaturalWonder,
Marble,
}
// Holds a bunch of tile info that is only interesting during map gen

View File

@ -87,8 +87,13 @@ class Unique(val text: String, val sourceObjectType: UniqueTarget? = null, val s
state.ourCombatant != null && state.ourCombatant.getHealth() > condition.params[0].toInt()
UniqueType.ConditionalBelowHP ->
state.ourCombatant != null && state.ourCombatant.getHealth() < condition.params[0].toInt()
UniqueType.ConditionalInTiles ->
UniqueType.ConditionalInTiles,
UniqueType.ConditionalFightingInTiles ->
state.attackedTile != null && state.attackedTile.matchesFilter(condition.params[0])
UniqueType.ConditionalInTilesAnd ->
state.attackedTile != null && state.attackedTile.matchesFilter(condition.params[0]) && state.attackedTile.matchesFilter(condition.params[1])
UniqueType.ConditionalInTilesNot ->
state.attackedTile != null && !state.attackedTile.matchesFilter(condition.params[0])
UniqueType.ConditionalVsLargerCiv -> {
val yourCities = state.civInfo?.cities?.size ?: 1
val theirCities = state.theirCombatant?.getCivInfo()?.cities?.size ?: 0

View File

@ -118,7 +118,8 @@ enum class UniqueParameterType(val parameterName:String) {
TerrainFilter("terrainFilter") {
private val knownValues = setOf("All",
"Coastal", "River", "Open terrain", "Rough terrain", "Water resource",
"Foreign Land", "Foreign", "Friendly Land", "Friendly", "Enemy Land", "Enemy")
"Foreign Land", "Foreign", "Friendly Land", "Friendly", "Enemy Land", "Enemy",
"Featureless", "Fresh Water")
override fun getErrorSeverity(parameterText: String, ruleset: Ruleset):
UniqueType.UniqueComplianceErrorSeverity? {
if (parameterText in knownValues) return null

View File

@ -299,19 +299,24 @@ enum class UniqueType(val text:String, vararg targets: UniqueTarget, val flags:
UniqueTarget.Terrain, flags = listOf(UniqueFlag.HideInCivilopedia)),
RegionRequireFirstLessThanSecond("A Region can not contain more [simpleTerrain] tiles than [simpleTerrain] tiles", UniqueTarget.Terrain, flags = listOf(UniqueFlag.HideInCivilopedia)),
IgnoreBaseTerrainForRegion("Base Terrain on this tile is not counted for Region determination", UniqueTarget.Terrain, flags = listOf(UniqueFlag.HideInCivilopedia)),
RegionExtraResource("Starts in regions of this type receive an extra [resource]", UniqueTarget.Terrain, flags = listOf(UniqueFlag.HideInCivilopedia)),
BlocksResources("Never receives any resources", UniqueTarget.Terrain, flags = listOf(UniqueFlag.HideInCivilopedia)),
HasQuality("Considered [terrainQuality] when determining start locations", UniqueTarget.Terrain, flags = listOf(UniqueFlag.HideInCivilopedia)),
LuxuryWeighting("Appears in [regionType] regions with weight [amount]", UniqueTarget.Resource, flags = listOf(UniqueFlag.HideInCivilopedia)),
LuxuryWeightingForCityStates("Appears near City States with weight [amount]", UniqueTarget.Resource, flags = listOf(UniqueFlag.HideInCivilopedia)),
ResourceWeighting("Generated with weight [amount]", UniqueTarget.Resource, flags = listOf(UniqueFlag.HideInCivilopedia)),
MinorDepositWeighting("Minor deposits generated with weight [amount]", UniqueTarget.Resource, flags = listOf(UniqueFlag.HideInCivilopedia)),
LuxuryWeightingForCityStates("Generated near City States with weight [amount]", UniqueTarget.Resource, flags = listOf(UniqueFlag.HideInCivilopedia)),
LuxurySpecialPlacement("Special placement during map generation", UniqueTarget.Resource, flags = listOf(UniqueFlag.HideInCivilopedia)),
ResourceFrequency("Generated on every [amount] tiles", UniqueTarget.Resource, flags = listOf(UniqueFlag.HideInCivilopedia)),
OverrideDepositAmountOnTileFilter("Deposits in [tileFilter] tiles always provide [amount] resources", UniqueTarget.Resource),
StrategicBalanceResource("Guaranteed with Strategic Balance resource option", UniqueTarget.Resource),
NoNaturalGeneration("Doesn't generate naturally", UniqueTarget.Terrain, flags = listOf(UniqueFlag.HideInCivilopedia)),
NoNaturalGeneration("Doesn't generate naturally", UniqueTarget.Terrain, UniqueTarget.Resource, flags = listOf(UniqueFlag.HideInCivilopedia)),
TileGenerationConditions("Occurs at temperature between [amount] and [amount] and humidity between [amount] and [amount]", UniqueTarget.Terrain, flags = listOf(UniqueFlag.HideInCivilopedia)),
OccursInChains("Occurs in chains at high elevations", UniqueTarget.Terrain, flags = listOf(UniqueFlag.HideInCivilopedia)),
OccursInGroups("Occurs in groups around high elevations", UniqueTarget.Terrain, flags = listOf(UniqueFlag.HideInCivilopedia)),
MajorStrategicFrequency("Every [amount] tiles with this terrain will receive a major deposit of a strategic resource.", UniqueTarget.Terrain, flags = listOf(UniqueFlag.HideInCivilopedia)),
RareFeature("Rare feature", UniqueTarget.Terrain),
@ -384,7 +389,7 @@ enum class UniqueType(val text:String, vararg targets: UniqueTarget, val flags:
ConditionalVsLargerCiv("when fighting units from a Civilization with more Cities than you", UniqueTarget.Conditional),
ConditionalAttacking("when attacking", UniqueTarget.Conditional),
ConditionalDefending("when defending", UniqueTarget.Conditional),
ConditionalInTiles("when fighting in [tileFilter] tiles", UniqueTarget.Conditional),
ConditionalFightingInTiles("when fighting in [tileFilter] tiles", UniqueTarget.Conditional),
ConditionalForeignContinent("on foreign continents", UniqueTarget.Conditional),
ConditionalAboveHP("when above [amount] HP", UniqueTarget.Conditional),
ConditionalBelowHP("when below [amount] HP", UniqueTarget.Conditional),
@ -392,6 +397,9 @@ enum class UniqueType(val text:String, vararg targets: UniqueTarget, val flags:
/////// tile conditionals
ConditionalNeighborTiles("with [amount] to [amount] neighboring [tileFilter] tiles", UniqueTarget.Conditional),
ConditionalNeighborTilesAnd("with [amount] to [amount] neighboring [tileFilter] [tileFilter] tiles", UniqueTarget.Conditional),
ConditionalInTiles("in [tileFilter] tiles", UniqueTarget.Conditional),
ConditionalInTilesAnd("in [tileFilter] [tileFilter] tiles", UniqueTarget.Conditional),
ConditionalInTilesNot("in tiles without [tileFilter]", UniqueTarget.Conditional),
/////// area conditionals
ConditionalOnWaterMaps("on water maps", UniqueTarget.Conditional),

View File

@ -657,7 +657,7 @@ class BaseUnit : RulesetObject(), INonPerpetualConstruction {
it.isOfType(UniqueType.ConditionalVsCity) // City Attack - half the bonus
|| it.isOfType(UniqueType.ConditionalAttacking) // Attack - half the bonus
|| it.isOfType(UniqueType.ConditionalDefending) // Defense - half the bonus
|| it.isOfType(UniqueType.ConditionalInTiles) } // Bonus in terrain or feature - half the bonus
|| it.isOfType(UniqueType.ConditionalFightingInTiles) } // Bonus in terrain or feature - half the bonus
) {
power *= (unique.params[0].toInt() / 2f).toPercent()
}

View File

@ -31,6 +31,7 @@ class MapParametersTable(
private var customWorldSizeTable = Table ()
private var hexagonalSizeTable = Table()
private var rectangularSizeTable = Table()
lateinit var resourceSelectBox: TranslatedSelectBox
private lateinit var noRuinsCheckbox: CheckBox
private lateinit var noNaturalWondersCheckbox: CheckBox
private lateinit var worldWrapCheckbox: CheckBox
@ -47,6 +48,7 @@ class MapParametersTable(
addMapShapeSelectBox()
addMapTypeSelectBox()
addWorldSizeTable()
addResourceSelectBox()
addWrappedCheckBoxes()
addAdvancedSettings()
}
@ -161,6 +163,25 @@ class MapParametersTable(
mapParameters.mapSize = MapSizeNew(worldSizeSelectBox.selected.value)
}
private fun addResourceSelectBox() {
val mapTypes = listOfNotNull(
MapResources.sparse,
MapResources.default,
MapResources.abundant,
MapResources.strategicBalance,
MapResources.legendaryStart
)
resourceSelectBox = TranslatedSelectBox(mapTypes, mapParameters.mapResources, skin)
resourceSelectBox.onChange {
mapParameters.mapResources = resourceSelectBox.selected.value
}
add("{Resource Setting}:".toLabel()).left()
add(resourceSelectBox).fillX().row()
}
private fun Table.addNoRuinsCheckbox() {
noRuinsCheckbox = "No Ancient Ruins".toCheckBox(mapParameters.noRuins) {
mapParameters.noRuins = it