Nomad mode on all random map scripts (except Survival of the Fittest), fixes #3591.
[0ad.git] / binaries / data / mods / public / maps / random / latium.js
blob37dd30e40d806e95d17704786705e3ef9ef26628
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];
54 InitMap();
56 const numPlayers = getNumPlayers();
57 const mapSize = getMapSize();
59 // Create classes
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)
75         var r = 10000;
76         for (let i = 0; i < numPlayers; ++i)
77         {
78                 var dx = x - playerX[i];
79                 var dz = z - playerZ[i];
80                 r = Math.min(r, Math.square(dx) + Math.square(dz));
81         }
82         return Math.sqrt(r);
85 function playerNearness(x, z)
87         var d = fractionToTiles(distanceToPlayers(x,z));
89         if (d < 13)
90                 return 0;
92         if (d < 19)
93                 return (d-13)/(19-13);
95         return 1;
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++)
113         {
114                 var x = ix / (mapSize + 1.0);
115                 var z = iz / (mapSize + 1.0);
116                 var pn = playerNearness(x, z);
118                 var h = 0;
119                 var distToWater = 0;
121                 h = 32 * (x - 0.5);
123                 // add the rough shape of the water
124                 if (x < WATER_WIDTH)
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);
128                 else
129                 {
130                         distToWater = (0.5 - WATER_WIDTH - Math.abs(x - 0.5));
131                         var u = 1 - Math.abs(x - 0.5) / (0.5 - WATER_WIDTH);
132                         h = 12*u;
133                 }
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;
137                 if ( baseNoise < 0 )
138                 {
139                         baseNoise *= pn;
140                         baseNoise *= Math.max(0.1, distToWater / (0.5 - WATER_WIDTH));
141                 }
142                 var oldH = h;
143                 h += baseNoise;
145                 // add some higher-frequency noise on land
146                 if ( oldH > 0 )
147                         h += (0.4 * noise2a.get(x,z) + 0.2 * noise2b.get(x,z)) * Math.min(oldH / 10, 1);
149                 // create cliff noise
150                 if ( h > -10 )
151                 {
152                         var cliffNoise = (noise3.get(x,z) + 0.5*noise4.get(x,z)) / 1.5;
153                         if (h < 1)
154                         {
155                                 var u = 1 - 0.3*((h-1)/-10);
156                                 cliffNoise *= u;
157                         }
158                         cliffNoise += 0.05 * distToWater / (0.5 - WATER_WIDTH);
159                         if (cliffNoise > 0.6)
160                         {
161                                 var u = 0.8 * (cliffNoise - 0.6);
162                                 cliffNoise += u * noise5.get(x,z);
163                                 cliffNoise /= (1 + u);
164                         }
165                         cliffNoise -= 0.59;
166                         cliffNoise *= pn;
167                         if (cliffNoise > 0)
168                                 h += 19 * Math.min(cliffNoise, 0.045) / 0.045;
169                 }
170                 setHeight(ix, iz, h);
171         }
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++)
183         {
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;
201                 if (maxH > 15)
202                 {
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));
208                 }
210                 // choose a terrain based on elevation
211                 var t = tGrass;
213                 // water
214                 if (maxH < -12)
215                         t = tOceanDepths;
216                 else if (maxH < -8.8)
217                         t = tOceanRockDeep;
218                 else if (maxH < -4.7)
219                         t = tOceanCoral;
220                 else if (maxH < -2.8)
221                         t = tOceanRockShallow;
222                 else if (maxH < 0.9 && minH < 0.35)
223                         t = tBeachWet;
224                 else if (maxH < 1.5 && minH < 0.9)
225                         t = tBeachDry;
226                 else if (maxH < 2.3 && minH < 1.3)
227                         t = tBeachGrass;
229                 if (minH < 0)
230                         addToClass(ix, iz, clWater);
232                 // cliffs
233                 if (diffH > 2.9 && minH > -7)
234                 {
235                         t = tCliff;
236                         addToClass(ix, iz, clCliff);
237                 }
238                 else if (diffH > 2.5 && minH > -5 || maxH - minAdjHeight > 2.9 && minH > 0)
239                 {
240                         if (minH < -1)
241                                 t = tCliff;
242                         else if (minH < 0.5)
243                                 t = tBeachCliff;
244                         else
245                                 t = [tDirtCliff, tGrassCliff, tGrassCliff, tGrassRock, tCliff];
247                         addToClass(ix, iz, clCliff);
248                 }
250                 // Don't place resources onto potentially impassable mountains
251                 if (minH >= 20)
252                         addToClass(ix, iz, clCliff);
254                 // forests
255                 if (getHeight(ix, iz) < 11 && diffH < 2 && minH > 1)
256                 {
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())
261                         {
262                                 if (minH < 11 && minH >= 4)
263                                 {
264                                         var typeNoise = noise10.get(x,z);
266                                         if (typeNoise < 0.43 && forestNoise < 0.05)
267                                                 t = pPoplarForest;
268                                         else if (typeNoise < 0.63)
269                                                 t = pMainForest;
270                                         else
271                                                 t = pPineForest;
273                                         addToClass(ix, iz, clForest);
274                                 }
275                                 else if (minH < 4)
276                                 {
277                                         t = pPalmForest;
278                                         addToClass(ix, iz, clForest);
279                                 }
280                         }
281                 }
283                 // grass variations
284                 if (t == tGrass)
285                 {
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)
290                         {
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));
294                         }
295                         else if (grassNoise > 0.61)
296                         {
297                                 t = (diffH > 1.2 ? tGrassRock : tGrassShrubs);
298                         }
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));
301                 }
303                 placeTerrain(ix, iz, t);
304         }
306 Engine.SetProgress(30);
308 placePlayerBases({
309         "PlayerPlacement": [playerIDs, playerX, playerZ],
310         "PlayerTileClass": clPlayer,
311         "BaseResourceClass": clBaseResource,
312         "baseResourceConstraint": avoidClasses(clCliff, 4),
313         "CityPatch": {
314                 "radius": 11,
315                 "outerTerrain": tGrass,
316                 "innerTerrain": tCity,
317                 "width": 4,
318                 "painters": [
319                         new SmoothElevationPainter(ELEVATION_SET, 5, 2)
320                 ]
321         },
322         "Chicken": {
323         },
324         "Berries": {
325                 "template": oBerryBush,
326                 "distance": 9
327         },
328         "Mines": {
329                 "types": [
330                         { "template": oMetalLarge },
331                         { "template": oStoneLarge }
332                 ]
333         },
334         "Trees": {
335                 "template": oPalm,
336                 "count": 5,
337                 "minDist": 10,
338                 "maxDist": 11
339         }
340         // No decoratives
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),
390         clForest,
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)],
398         true
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),
410         3 * numPlayers, 50
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)
418         createObjectGroup(
419                 new SimpleGroup(
420                         [new SimpleObject(oFish, 1, 1, 0, 1)],
421                         true,
422                         clFood,
423                         randIntInclusive(offsetX / 2, offsetX * 3/2),
424                         Math.round((i + 0.5) * mapSize / num)),
425                 0);
427 for (let i = 0; i < num; ++i)
428         createObjectGroup(
429                 new SimpleGroup(
430                         [new SimpleObject(oFish, 1, 1, 0, 1)],
431                         true,
432                         clFood,
433                         randIntInclusive(mapSize - offsetX * 3/2, mapSize - offsetX / 2),
434                         Math.round((i + 0.5) * mapSize / num)),
435                 0);
437 Engine.SetProgress(90);
439 log("Creating deer...");
440 group = new SimpleGroup(
441         [new SimpleObject(oDeer, 5,7, 0,4)],
442         true, clFood
444 createObjectGroupsDeprecated(group, 0,
445         avoidClasses(clWater, 5, clForest, 2, clCliff, 1, clPlayer, 20, clMetal, 6, clRock, 6, clFood, 8),
446         3 * numPlayers, 50
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));
459 setSkySet("sunny");
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);
466 ExportMap();