Lower Nubia random map, refs #5040.

Composes the NASA heightmap with the NASA composite photography to
reduce the ahistorical Lake Nasser and avoid having huge lakes in the
valleys to the west of the Nile,
as the heightmap does not correlate with water distribution in this arid
climate at all.
I.e. places riverbed elevation where composite and heightmap intersect,
elsewhere uses the elevation model by NASA.

Bounding box chosen by Hannibal Barca
Geographic and biome consulting by Sundiata

This was SVN commit r21377.
This commit is contained in:
elexis 2018-02-25 22:08:26 +00:00
parent 3d54e697e7
commit 9d681ff3e3
6 changed files with 406 additions and 1 deletions

View file

@ -0,0 +1,3 @@
version https://git-lfs.github.com/spec/v1
oid sha256:e94c777a9fa931dabf70a3705f1267bb2f57967f762d19953e3a971dcfa026fc
size 151028

View file

@ -2,8 +2,12 @@ The JSON and JS files in this directory are created by Wildfire Games and availa
This directory contains topography images of the NASA Blue Marble series. This material is in the public domain.
Credit: Imagery by Jesse Allen, NASA's Earth Observatory, using data from the General Bathymetric Chart of the Oceans (GEBCO) produced by the British Oceanographic Data Centre.
Imagery by Jesse Allen, NASA's Earth Observatory, using data from the General Bathymetric Chart of the Oceans (GEBCO) produced by the British Oceanographic Data Centre.
https://visibleearth.nasa.gov/view.php?id=73934
Reto Stöckli, NASA Earth Observatory
https://visibleearth.nasa.gov/view.php?id=74393
> General Terms of Use Information
> Most images published in Visible Earth are freely available for re-publication or re-use, including commercial purposes, except for where copyright is indicated. In those cases you must obtain the copyright holders permission; we usually provide links to the organization that holds the copyright.
> We ask that you use the credit statement attached with each image or else credit Visible Earth; the only mandatory credit is NASA.

View file

@ -0,0 +1,382 @@
/**
* Heightmap image source:
* Imagery by Jesse Allen, NASA's Earth Observatory,
* using data from the General Bathymetric Chart of the Oceans (GEBCO)
* produced by the British Oceanographic Data Centre.
* https://visibleearth.nasa.gov/view.php?id=73934
* https://visibleearth.nasa.gov/view.php?id=74393
* Licensing: Public Domain, https://visibleearth.nasa.gov/useterms.php
*
* Since the elevation does not correlate with water distribution in lower_nubia,
* this map additionally uses composite photography to paint the water correctly.
*
* To reproduce the heightmaps, first set the coordinates:
* lat=23.25; lon=31.75; width=6;
* lat1=$(bc <<< ";scale=5;$lat-$width/2"); lon1=$(bc <<< ";scale=5;$lon+$width/2"); lat2=$(bc <<< ";scale=5;$lat+$width/2"); lon2=$(bc <<< ";scale=5;$lon-$width/2")
*
* The land heightmap image is reproduced using:
* wget https://eoimages.gsfc.nasa.gov/images/imagerecords/73000/73934/gebco_08_rev_elev_C1_grey_geo.tif
* gdal_translate -projwin $lon2 $lat2 $lon1 $lat1 gebco_08_rev_elev_C1_grey_geo.tif lower_nubia.tif
* convert lower_nubia.tif -resize 512 -contrast-stretch 0 lower_nubia_heightmap.png
* convert lower_nubia_heightmap.png -threshold 25% lower_nubia_land_threshold.png
*
* The watermap image is reproduced using:
* wget https://eoimages.gsfc.nasa.gov/images/imagerecords/74000/74393/world.topo.200407.3x21600x21600.C1.jpg
* gdal_translate -a_srs EPSG:4326 -a_ullr 0 90 90 0 world.topo.200407.3x21600x21600.C1.jpg world.topo.200407.3x21600x21600.C1.jpg.tif
* gdal_translate -projwin $lon2 $lat2 $lon1 $lat1 world.topo.200407.3x21600x21600.C1.jpg.tif lower_nubia_water.tif
* convert lower_nubia_water.tif -set colorspace Gray -resize 512 -separate -average -threshold 51% lower_nubia_water_threshold.png
*
* No further changes should be applied to the images to keep them easily interchangeable.
*/
Engine.LoadLibrary("rmgen");
Engine.LoadLibrary("rmgen-common");
TILE_CENTERED_HEIGHT_MAP = true;
const tSand = "desert_sand_dunes_100";
const tPlateau = ["savanna_dirt_a", "savanna_dirt_b"];
const tNilePlants = "desert_plants_a";
const tCliffUpper = ["medit_cliff_italia", "medit_cliff_italia", "medit_cliff_italia_grass"];
const tRoad = "savanna_tile_a";
const tWater = "desert_sand_wet";
const oAcacia = "gaia/flora_tree_acacia";
const oTreeDead = "gaia/flora_tree_dead";
const oBerryBush = "gaia/flora_bush_berry_desert";
const oPalms = [
"gaia/flora_tree_cretan_date_palm_tall",
"gaia/flora_tree_cretan_date_palm_short",
"gaia/flora_tree_palm_tropic",
"gaia/flora_tree_date_palm",
"gaia/flora_tree_senegal_date_palm",
"gaia/flora_tree_medit_fan_palm"
];
const oStoneLarge = "gaia/geology_stonemine_savanna_quarry";
const oStoneSmall = "gaia/geology_stone_desert_small";
const oMetalLarge = "gaia/geology_metal_savanna_slabs";
const oMetalSmall = "gaia/geology_metal_desert_small";
const oWoodTreasure = "gaia/treasure/wood";
const oGazelle = "gaia/fauna_gazelle";
const oElephant = "gaia/fauna_elephant_african_bush";
const oElephantInfant = "gaia/fauna_elephant_african_infant";
const oLion = "gaia/fauna_lion";
const oLioness = "gaia/fauna_lioness";
const oHawk = "gaia/fauna_hawk";
const aRock = actorTemplate("geology/stone_savanna_med");
const aBushes = [
"props/flora/bush_dry_a",
"props/flora/bush_medit_la_dry",
"props/flora/bush_medit_me_dry",
"props/flora/bush_medit_sm",
"props/flora/bush_medit_sm_dry",
"props/flora/bush_tempe_me_dry",
"props/flora/grass_soft_dry_large_tall",
"props/flora/grass_soft_dry_small_tall"
].map(actorTemplate);
const heightScale = num => num * g_MapSettings.Size / 320;
const heightSeaGround = heightScale(-3);
const heightWaterLevel = heightScale(0);
const heightNileForests = heightScale(15);
const heightPlateau2 = heightScale(38);
const minHeight = -3;
const maxHeight = 150;
const g_Map = new RandomMap(0, tSand);
const mapCenter = g_Map.getCenter();
const mapBounds = g_Map.getBounds();
const clWater = g_Map.createTileClass();
const clCliff = g_Map.createTileClass();
const clPlayer = g_Map.createTileClass();
const clBaseResource = g_Map.createTileClass();
const clForest = g_Map.createTileClass();
const clRock = g_Map.createTileClass();
const clMetal = g_Map.createTileClass();
const clFood = g_Map.createTileClass();
g_Map.log("Loading heightmaps");
const heightmapLand = convertHeightmap1Dto2D(Engine.LoadHeightmapImage("maps/random/lower_nubia_heightmap.png"));
const heightmapLandThreshold = convertHeightmap1Dto2D(Engine.LoadHeightmapImage("maps/random/lower_nubia_land_threshold.png"));
const heightmapWaterThreshold = convertHeightmap1Dto2D(Engine.LoadHeightmapImage("maps/random/lower_nubia_water_threshold.png"));
var heightmapCombined = [];
for (let x = 0; x < heightmapLand.length; ++x)
{
heightmapCombined[x] = new Float32Array(heightmapLand.length);
for (let y = 0; y < heightmapLand.length; ++y)
heightmapCombined[x][y] = heightmapLandThreshold[x][y] || heightmapWaterThreshold[x][y] ? heightmapLand[x][y] : minHeight;
}
g_Map.log("Copying heightmap");
createArea(
new MapBoundsPlacer(),
new HeightmapPainter(heightmapCombined, minHeight, maxHeight));
g_Map.log("Lowering sea ground");
createArea(
new MapBoundsPlacer(),
[
new SmoothElevationPainter(ELEVATION_SET, heightSeaGround, 3),
new TileClassPainter(clWater)
],
new HeightConstraint(-Infinity, heightSeaGround));
g_Map.log("Creating shallows...");
const riverAngle = Math.PI * 3 / 4;
for (let i = 0; i < scaleByMapSize(3, 8); ++i)
{
let x = fractionToTiles(randFloat(0, 1));
createPassage({
"start": new Vector2D(x, mapBounds.bottom).rotateAround(riverAngle, mapCenter),
"end": new Vector2D(x, mapBounds.top).rotateAround(riverAngle, mapCenter),
"startWidth": scaleByMapSize(4, 6),
"endWidth": scaleByMapSize(4, 6),
"smoothWidth": 1,
"startHeight": heightNileForests,
"endHeight": heightNileForests,
"constraint": new NearTileClassConstraint(clWater, 2)
});
}
g_Map.log("Smoothing heightmap");
createArea(
new MapBoundsPlacer(),
new SmoothingPainter(1, scaleByMapSize(0.5, 1), 1));
g_Map.log("Smoothing plateau passage");
const passageStart = new Vector2D(263, 189).div(heightmapLand.length);
const passageEnd = new Vector2D(110, 350).div(heightmapLand.length);
createArea(
new PathPlacer(
new Vector2D(fractionToTiles(passageStart.x), mapBounds.top - fractionToTiles(passageStart.y)),
new Vector2D(fractionToTiles(passageEnd.x), mapBounds.top - fractionToTiles(passageEnd.y)),
scaleByMapSize(10, 40),
0,
scaleByMapSize(3, 9),
0.2,
0.05),
new SmoothingPainter(4, 1, 1));
g_Map.log("Marking water");
createArea(
new MapBoundsPlacer(),
new TileClassPainter(clWater),
new HeightConstraint(-Infinity, heightSeaGround));
g_Map.log("Marking cliffs");
createArea(
new MapBoundsPlacer(),
new TileClassPainter(clCliff),
new SlopeConstraint(2, Infinity));
g_Map.log("Painting water and shoreline");
createArea(
new MapBoundsPlacer(),
new TerrainPainter(tWater),
new HeightConstraint(-Infinity, heightWaterLevel));
g_Map.log("Painting plateau");
createArea(
new MapBoundsPlacer(),
new TerrainPainter(tPlateau),
new HeightConstraint(heightPlateau2, Infinity));
var playerIDs = [];
var playerPosition = [];
if (!isNomad())
{
g_Map.log("Finding player locations...");
[playerIDs, playerPosition] = playerPlacementRandom(sortAllPlayers(), avoidClasses(clWater, scaleByMapSize(8, 12), clCliff, scaleByMapSize(8, 12)));
g_Map.log("Flatten the initial CC area...");
for (let position of playerPosition)
createArea(
new ClumpPlacer(diskArea(defaultPlayerBaseRadius() * 0.8), 0.95, 0.6, Infinity, position),
new SmoothElevationPainter(ELEVATION_SET, g_Map.getHeight(position), 6));
}
placePlayerBases({
"PlayerPlacement": [playerIDs, playerPosition],
"PlayerTileClass": clPlayer,
"BaseResourceClass": clBaseResource,
"baseResourceConstraint": avoidClasses(clCliff, 0, clWater, 0),
"CityPatch": {
"outerTerrain": tRoad,
"innerTerrain": tRoad
},
"Chicken": {
"template": oGazelle,
"distance": 18,
"minGroupDistance": 2,
"maxGroupDistance": 4,
"minGroupCount": 2,
"maxGroupCount": 3
},
"Berries": {
"template": oBerryBush
},
"Mines": {
"types": [
{ "template": oMetalLarge },
{ "template": oStoneLarge }
]
},
"Trees": {
"template": oAcacia,
"count": scaleByMapSize(3, 12),
"minDistGroup": 2,
"maxDistGroup": 6,
"minDist": 15,
"maxDist": 16
},
"Treasures": {
"types": [
{
"template": oWoodTreasure,
"count": 14
}
]
},
"Decoratives": {
"template": pickRandom(aBushes)
}
});
g_Map.log("Painting lower cliffs");
createArea(
new MapBoundsPlacer(),
new TerrainPainter(tNilePlants),
[
new SlopeConstraint(2, Infinity),
new NearTileClassConstraint(clWater, 2)
]);
g_Map.log("Painting upper cliffs");
createArea(
new MapBoundsPlacer(),
new TerrainPainter(tCliffUpper),
[
avoidClasses(clWater, 2),
new SlopeConstraint(2, Infinity)
]);
g_Map.log("Creating stone mines");
createMines(
[
[new SimpleObject(oStoneSmall, 0, 2, 0, 4, 0, 2 * Math.PI, 1), new SimpleObject(oStoneLarge, 1, 1, 0, 4, 0, 2 * Math.PI, 4)],
[new SimpleObject(oStoneSmall, 3, 6, 1, 3, 0, 2 * Math.PI, 1)]
],
avoidClasses(clWater, 4, clCliff, 4, clPlayer, 20, clRock, 10),
clRock,
scaleByMapSize(10, 30));
g_Map.log("Creating metal mines");
createMines(
[
[new SimpleObject(oMetalSmall, 0, 2, 0, 4, 0, 2 * Math.PI, 1), new SimpleObject(oMetalLarge, 1, 1, 0, 4, 0, 2 * Math.PI, 4)],
[new SimpleObject(oMetalSmall, 3, 6, 1, 3, 0, 2 * Math.PI, 1)]
],
avoidClasses(clWater, 4, clCliff, 4, clPlayer, 20, clMetal, 10, clRock, 5),
clMetal,
scaleByMapSize(10, 30));
g_Map.log("Creating forests");
createObjectGroups(
new SimpleGroup([new RandomObject(oPalms, 1, 2, 1, 1)], true, clForest),
0,
[
new NearTileClassConstraint(clWater, scaleByMapSize(1, 8)),
new HeightConstraint(heightNileForests, Infinity),
avoidClasses(clWater, 0, clCliff, 0, clForest, 1, clPlayer, 12, clBaseResource, 5)
],
scaleByMapSize(100, 1000),
200);
createStragglerTrees(
[oAcacia, oTreeDead],
avoidClasses(clWater, 10, clCliff, 1, clPlayer, 12, clBaseResource, 5),
clForest,
scaleByMapSize(15, 400),
200);
const avoidCollisions = avoidClasses(clPlayer, 12, clBaseResource, 5, clWater, 1, clForest, 1, clRock, 4, clMetal, 4, clFood, 6, clCliff, 0);
g_Map.log("Creating gazelles");
createObjectGroups(
new SimpleGroup([new SimpleObject(oGazelle, 5, 7, 2, 4)], true, clFood),
0,
avoidCollisions,
scaleByMapSize(2, 10),
50);
if (!isNomad())
{
g_Map.log("Creating lions");
createObjectGroups(
new SimpleGroup([new SimpleObject(oLion, 1, 2, 2, 4), new SimpleObject(oLioness, 2, 3, 2, 4)], true, clFood),
0,
avoidCollisions,
scaleByMapSize(2, 10),
50);
}
g_Map.log("Creating elephants");
createObjectGroups(
new SimpleGroup([new SimpleObject(oElephant, 2, 3, 2, 4), new SimpleObject(oElephantInfant, 2, 3, 2, 4)], true, clFood),
0,
avoidCollisions,
scaleByMapSize(2, 10),
50);
placePlayersNomad(clPlayer, avoidClasses(clWater, 4, clForest, 2, clRock, 4, clMetal, 4, clFood, 2, clCliff, 2));
g_Map.log("Creating hawk");
for (let i = 0; i < scaleByMapSize(0, 2); ++i)
g_Map.placeEntityAnywhere(oHawk, 0, mapCenter, randomAngle());
createDecoration(
aBushes.map(bush => [new SimpleObject(bush, 0, 3, 2, 4)]),
aBushes.map(bush => scaleByMapSize(200, 800) * randIntInclusive(1, 3)),
[
new NearTileClassConstraint(clWater, 2),
new HeightConstraint(heightWaterLevel, Infinity),
avoidClasses(clForest, 0)
]);
createDecoration(
[[new SimpleObject(aRock, 0, 4, 2, 4)]],
[[scaleByMapSize(100, 600)]],
avoidClasses(clWater, 0));
setWindAngle(-0.43);
setWaterTint(0.161, 0.286, 0.353);
setWaterColor(0.129, 0.176, 0.259);
setWaterWaviness(8);
setWaterMurkiness(0.87);
setWaterType("lake");
setTerrainAmbientColor(0.58, 0.443, 0.353);
setSunColor(0.733, 0.746, 0.574);
setSunRotation(Math.PI * 1.1);
setSunElevation(Math.PI / 7);
setFogFactor(0);
setFogThickness(0);
setFogColor(0.69, 0.616, 0.541);
setPPEffect("hdr");
setPPContrast(0.67);
setPPSaturation(0.42);
setPPBloom(0.23);
if (false)
createArea(
new MapBoundsPlacer(),
new TerrainPainter("blue"),
new NearTileClassConstraint(clWater, 0));
g_Map.ExportMap();

View file

@ -0,0 +1,10 @@
{
"settings" : {
"Name" : "Lower Nubia",
"Script" : "lower_nubia.js",
"Description" : "The unknown.",
"Preview" : "lower_nubia.png",
"Keywords": ["new"],
"CircularMap": true
}
}

View file

@ -0,0 +1,3 @@
version https://git-lfs.github.com/spec/v1
oid sha256:1b63f1e88fec880644ad5ce2fa1e93974c578761653d0be883fe88f5391ba5ed
size 8678

View file

@ -0,0 +1,3 @@
version https://git-lfs.github.com/spec/v1
oid sha256:69f95c88608aa81a5308cc48d6f246280ab2f4942616d460b8543b42f0325a53
size 8078