1 Engine.LoadLibrary("rmgen");
3 const WATER_WIDTH = 0.1;
5 const tOceanDepths = "medit_sea_depths";
6 const tOceanRockDeep = "medit_sea_coral_deep";
7 const tOceanRockShallow = "medit_rocks_wet";
8 const tOceanCoral = "medit_sea_coral_plants";
9 const tBeachWet = "medit_sand_wet";
10 const tBeachDry = "medit_sand";
11 const tBeachGrass = "medit_rocks_grass";
12 const tBeachCliff = "medit_dirt";
13 const tCity = "medit_city_tile";
14 const tGrassDry = ["medit_grass_field_brown", "medit_grass_field_dry", "medit_grass_field_b"];
15 const tGrass = ["medit_grass_field_dry", "medit_grass_field_brown", "medit_grass_field_b"];
16 const tGrassShrubs = ["medit_grass_shrubs", "medit_grass_flowers"];
17 const tGrassRock = ["medit_rocks_grass"];
18 const tDirt = "medit_dirt";
19 const tDirtCliff = "medit_cliff_italia";
20 const tGrassCliff = "medit_cliff_italia_grass";
21 const tCliff = ["medit_cliff_italia", "medit_cliff_italia", "medit_cliff_italia_grass"];
22 const tForestFloor = "medit_grass_wild";
24 const oBeech = "gaia/flora_tree_euro_beech";
25 const oBerryBush = "gaia/flora_bush_berry";
26 const oCarob = "gaia/flora_tree_carob";
27 const oCypress1 = "gaia/flora_tree_cypress";
28 const oCypress2 = "gaia/flora_tree_cypress";
29 const oLombardyPoplar = "gaia/flora_tree_poplar_lombardy";
30 const oPalm = "gaia/flora_tree_medit_fan_palm";
31 const oPine = "gaia/flora_tree_aleppo_pine";
32 const oDeer = "gaia/fauna_deer";
33 const oFish = "gaia/fauna_fish";
34 const oSheep = "gaia/fauna_sheep";
35 const oStoneLarge = "gaia/geology_stonemine_medit_quarry";
36 const oStoneSmall = "gaia/geology_stone_mediterranean";
37 const oMetalLarge = "gaia/geology_metal_mediterranean_slabs";
39 const aBushMedDry = "actor|props/flora/bush_medit_me_dry.xml";
40 const aBushMed = "actor|props/flora/bush_medit_me.xml";
41 const aBushSmall = "actor|props/flora/bush_medit_sm.xml";
42 const aBushSmallDry = "actor|props/flora/bush_medit_sm_dry.xml";
43 const aGrass = "actor|props/flora/grass_soft_large_tall.xml";
44 const aGrassDry = "actor|props/flora/grass_soft_dry_large_tall.xml";
45 const aRockLarge = "actor|geology/stone_granite_large.xml";
46 const aRockMed = "actor|geology/stone_granite_med.xml";
47 const aRockSmall = "actor|geology/stone_granite_small.xml";
49 const pPalmForest = [tForestFloor+TERRAIN_SEPARATOR+oPalm, tGrass];
50 const pPineForest = [tForestFloor+TERRAIN_SEPARATOR+oPine, tGrass];
51 const pPoplarForest = [tForestFloor+TERRAIN_SEPARATOR+oLombardyPoplar, tGrass];
52 const pMainForest = [tForestFloor+TERRAIN_SEPARATOR+oCarob, tForestFloor+TERRAIN_SEPARATOR+oBeech, tGrass, tGrass];
56 const numPlayers = getNumPlayers();
57 const mapSize = getMapSize();
60 var clWater = createTileClass();
61 var clCliff = createTileClass();
62 var clForest = createTileClass();
63 var clMetal = createTileClass();
64 var clRock = createTileClass();
65 var clFood = createTileClass();
66 var clPlayer = createTileClass();
67 var clBaseResource = createTileClass();
69 log("Creating players...");
71 var [playerIDs, playerX, playerZ] = playerPlacementLine(false, 0.5, randFloat(0.42, 0.46));
73 function distanceToPlayers(x, z)
76 for (let i = 0; i < numPlayers; ++i)
78 var dx = x - playerX[i];
79 var dz = z - playerZ[i];
80 r = Math.min(r, Math.square(dx) + Math.square(dz));
85 function playerNearness(x, z)
87 var d = fractionToTiles(distanceToPlayers(x,z));
93 return (d-13)/(19-13);
98 log("Painting elevation...");
100 var noise0 = new Noise2D(scaleByMapSize(4, 16));
101 var noise1 = new Noise2D(scaleByMapSize(8, 32));
102 var noise2 = new Noise2D(scaleByMapSize(15, 60));
104 var noise2a = new Noise2D(scaleByMapSize(20, 80));
105 var noise2b = new Noise2D(scaleByMapSize(35, 140));
107 var noise3 = new Noise2D(scaleByMapSize(4, 16));
108 var noise4 = new Noise2D(scaleByMapSize(6, 24));
109 var noise5 = new Noise2D(scaleByMapSize(11, 44));
111 for (var ix = 0; ix <= mapSize; ix++)
112 for (var iz = 0; iz <= mapSize; iz++)
114 var x = ix / (mapSize + 1.0);
115 var z = iz / (mapSize + 1.0);
116 var pn = playerNearness(x, z);
123 // add the rough shape of the water
125 h = Math.max(-16, -28 * (WATER_WIDTH - x) / WATER_WIDTH);
126 else if (x > 1.0-WATER_WIDTH)
127 h = Math.max(-16, -28 * (x - (1 - WATER_WIDTH)) / WATER_WIDTH);
130 distToWater = (0.5 - WATER_WIDTH - Math.abs(x - 0.5));
131 var u = 1 - Math.abs(x - 0.5) / (0.5 - WATER_WIDTH);
135 // add some base noise
136 var baseNoise = 16*noise0.get(x,z) + 8*noise1.get(x,z) + 4*noise2.get(x,z) - (16+8+4)/2;
140 baseNoise *= Math.max(0.1, distToWater / (0.5 - WATER_WIDTH));
145 // add some higher-frequency noise on land
147 h += (0.4 * noise2a.get(x,z) + 0.2 * noise2b.get(x,z)) * Math.min(oldH / 10, 1);
149 // create cliff noise
152 var cliffNoise = (noise3.get(x,z) + 0.5*noise4.get(x,z)) / 1.5;
155 var u = 1 - 0.3*((h-1)/-10);
158 cliffNoise += 0.05 * distToWater / (0.5 - WATER_WIDTH);
159 if (cliffNoise > 0.6)
161 var u = 0.8 * (cliffNoise - 0.6);
162 cliffNoise += u * noise5.get(x,z);
163 cliffNoise /= (1 + u);
168 h += 19 * Math.min(cliffNoise, 0.045) / 0.045;
170 setHeight(ix, iz, h);
172 Engine.SetProgress(15);
174 log("Painting terrain...");
175 var noise6 = new Noise2D(scaleByMapSize(10, 40));
176 var noise7 = new Noise2D(scaleByMapSize(20, 80));
177 var noise8 = new Noise2D(scaleByMapSize(13, 52));
178 var noise9 = new Noise2D(scaleByMapSize(26, 104));
179 var noise10 = new Noise2D(scaleByMapSize(50, 200));
181 for (var ix = 0; ix < mapSize; ix++)
182 for (var iz = 0; iz < mapSize; iz++)
184 var x = ix / (mapSize + 1.0);
185 var z = iz / (mapSize + 1.0);
186 var pn = playerNearness(x, z);
188 // get heights of surrounding vertices
189 var h00 = getHeight(ix, iz);
190 var h01 = getHeight(ix, iz+1);
191 var h10 = getHeight(ix+1, iz);
192 var h11 = getHeight(ix+1, iz+1);
194 // find min and max height
195 var maxH = Math.max(h00, h01, h10, h11);
196 var minH = Math.min(h00, h01, h10, h11);
197 var diffH = maxH - minH;
199 // figure out if we're at the top of a cliff using min adjacent height
200 var minAdjHeight = minH;
203 var maxNx = Math.min(ix + 2, mapSize);
204 var maxNz = Math.min(iz + 2, mapSize);
205 for (let nx = Math.max(ix - 1, 0); nx <= maxNx; ++nx)
206 for (let nz = Math.max(iz - 1, 0); nz <= maxNz; ++nz)
207 minAdjHeight = Math.min(minAdjHeight, getHeight(nx, nz));
210 // choose a terrain based on elevation
216 else if (maxH < -8.8)
218 else if (maxH < -4.7)
220 else if (maxH < -2.8)
221 t = tOceanRockShallow;
222 else if (maxH < 0.9 && minH < 0.35)
224 else if (maxH < 1.5 && minH < 0.9)
226 else if (maxH < 2.3 && minH < 1.3)
230 addToClass(ix, iz, clWater);
233 if (diffH > 2.9 && minH > -7)
236 addToClass(ix, iz, clCliff);
238 else if (diffH > 2.5 && minH > -5 || maxH - minAdjHeight > 2.9 && minH > 0)
245 t = [tDirtCliff, tGrassCliff, tGrassCliff, tGrassRock, tCliff];
247 addToClass(ix, iz, clCliff);
250 // Don't place resources onto potentially impassable mountains
252 addToClass(ix, iz, clCliff);
255 if (getHeight(ix, iz) < 11 && diffH < 2 && minH > 1)
257 var forestNoise = (noise6.get(x,z) + 0.5*noise7.get(x,z)) / 1.5 * pn - 0.59;
259 // Thin out trees a bit
260 if (forestNoise > 0 && randBool())
262 if (minH < 11 && minH >= 4)
264 var typeNoise = noise10.get(x,z);
266 if (typeNoise < 0.43 && forestNoise < 0.05)
268 else if (typeNoise < 0.63)
273 addToClass(ix, iz, clForest);
278 addToClass(ix, iz, clForest);
286 var grassNoise = (noise8.get(x,z) + 0.6*noise9.get(x,z)) / 1.6;
287 if (grassNoise < 0.3)
288 t = (diffH > 1.2) ? tDirtCliff : tDirt;
289 else if (grassNoise < 0.34)
291 t = (diffH > 1.2) ? tGrassCliff : tGrassDry;
292 if (diffH < 0.5 && randBool(0.02))
293 placeObject(randFloat(ix, ix + 1), randFloat(iz, iz + 1), aGrassDry, 0, randFloat(0, 2 * Math.PI));
295 else if (grassNoise > 0.61)
297 t = (diffH > 1.2 ? tGrassRock : tGrassShrubs);
299 else if (diffH < 0.5 && randBool(0.02))
300 placeObject(randFloat(ix, ix + 1), randFloat(iz, iz + 1), aGrass, 0, randFloat(0, 2 * Math.PI));
303 placeTerrain(ix, iz, t);
306 Engine.SetProgress(30);
309 "PlayerPlacement": [playerIDs, playerX, playerZ],
310 "PlayerTileClass": clPlayer,
311 "BaseResourceClass": clBaseResource,
312 "baseResourceConstraint": avoidClasses(clCliff, 4),
315 "outerTerrain": tGrass,
316 "innerTerrain": tCity,
319 new SmoothElevationPainter(ELEVATION_SET, 5, 2)
325 "template": oBerryBush,
330 { "template": oMetalLarge },
331 { "template": oStoneLarge }
342 Engine.SetProgress(40);
344 log("Creating bushes...");
345 var group = new SimpleGroup(
346 [new SimpleObject(aBushSmall, 0,2, 0,2), new SimpleObject(aBushSmallDry, 0,2, 0,2),
347 new SimpleObject(aBushMed, 0,1, 0,2), new SimpleObject(aBushMedDry, 0,1, 0,2)]
349 createObjectGroupsDeprecated(group, 0,
350 avoidClasses(clWater, 4, clCliff, 2),
351 scaleByMapSize(9, 146), 50
353 Engine.SetProgress(45);
355 log("Creating rocks...");
356 group = new SimpleGroup(
357 [new SimpleObject(aRockSmall, 0,3, 0,2), new SimpleObject(aRockMed, 0,2, 0,2),
358 new SimpleObject(aRockLarge, 0,1, 0,2)]
360 createObjectGroupsDeprecated(group, 0,
361 avoidClasses(clWater, 2, clCliff, 1),
362 scaleByMapSize(9, 146), 50
364 Engine.SetProgress(50);
366 log("Creating large stone mines...");
367 group = new SimpleGroup([new SimpleObject(oStoneSmall, 0,2, 0,4), new SimpleObject(oStoneLarge, 1,1, 0,4)], true, clRock);
368 createObjectGroupsDeprecated(group, 0,
369 avoidClasses(clWater, 1, clForest, 4, clPlayer, 40, clRock, 60, clMetal, 10, clCliff, 3),
370 scaleByMapSize(4,16), 100
373 log("Creating small stone mines...");
374 group = new SimpleGroup([new SimpleObject(oStoneSmall, 2,5, 1,3)], true, clRock);
375 createObjectGroups(group, 0,
376 avoidClasses(clForest, 4, clWater, 1, clPlayer, 40, clRock, 30, clMetal, 10, clCliff, 3),
377 scaleByMapSize(4,16), 100
379 log("Creating metal mines...");
380 group = new SimpleGroup([new SimpleObject(oMetalLarge, 1,1, 0,2)], true, clMetal);
381 createObjectGroups(group, 0,
382 avoidClasses(clForest, 4, clWater, 1, clPlayer, 40, clMetal, 50, clCliff, 3),
383 scaleByMapSize(4,16), 100
385 Engine.SetProgress(60);
387 createStragglerTrees(
388 [oCarob, oBeech, oLombardyPoplar, oLombardyPoplar, oPine],
389 avoidClasses(clWater, 5, clCliff, 4, clForest, 2, clPlayer, 15, clMetal, 6, clRock, 6),
391 scaleByMapSize(10, 190));
393 Engine.SetProgress(70);
395 log("Creating straggler cypresses...");
396 group = new SimpleGroup(
397 [new SimpleObject(oCypress2, 1,3, 0,3), new SimpleObject(oCypress1, 0,2, 0,2)],
400 createObjectGroupsDeprecated(group, 0,
401 avoidClasses(clWater, 5, clCliff, 4, clForest, 2, clPlayer, 15, clMetal, 6, clRock, 6),
402 scaleByMapSize(5, 75), 50
404 Engine.SetProgress(80);
406 log("Creating sheep...");
407 group = new SimpleGroup([new SimpleObject(oSheep, 2,4, 0,2)], true, clFood);
408 createObjectGroupsDeprecated(group, 0,
409 avoidClasses(clWater, 5, clForest, 2, clCliff, 1, clPlayer, 20, clMetal, 6, clRock, 6, clFood, 8),
412 Engine.SetProgress(85);
414 log("Creating fish...");
415 var num = scaleByMapSize(4, 16);
416 var offsetX = mapSize * WATER_WIDTH/2;
417 for (let i = 0; i < num; ++i)
420 [new SimpleObject(oFish, 1, 1, 0, 1)],
423 randIntInclusive(offsetX / 2, offsetX * 3/2),
424 Math.round((i + 0.5) * mapSize / num)),
427 for (let i = 0; i < num; ++i)
430 [new SimpleObject(oFish, 1, 1, 0, 1)],
433 randIntInclusive(mapSize - offsetX * 3/2, mapSize - offsetX / 2),
434 Math.round((i + 0.5) * mapSize / num)),
437 Engine.SetProgress(90);
439 log("Creating deer...");
440 group = new SimpleGroup(
441 [new SimpleObject(oDeer, 5,7, 0,4)],
444 createObjectGroupsDeprecated(group, 0,
445 avoidClasses(clWater, 5, clForest, 2, clCliff, 1, clPlayer, 20, clMetal, 6, clRock, 6, clFood, 8),
448 Engine.SetProgress(95);
450 log("Creating berry bushes...");
451 group = new SimpleGroup([new SimpleObject(oBerryBush, 5,7, 0,3)], true, clFood);
452 createObjectGroupsDeprecated(group, 0,
453 avoidClasses(clWater, 5, clForest, 2, clCliff, 1, clPlayer, 20, clMetal, 6, clRock, 6, clFood, 8),
454 1.5 * numPlayers, 100
457 placePlayersNomad(clPlayer, avoidClasses(clWater, 4, clCliff, 2, clForest, 1, clMetal, 4, clRock, 4, clFood, 2));
460 setWaterColor(0.024,0.262,0.224);
461 setWaterTint(0.133, 0.325,0.255);
462 setWaterWaviness(2.5);
463 setWaterType("ocean");
464 setWaterMurkiness(0.8);