Remove rmgen euclidian distance helper function, refs rP20328 / D969.
[0ad.git] / binaries / data / mods / public / maps / random / snowflake_searocks.js
blob01cc34427a8e5845f949def8cff11145e2f05dbc
1 RMS.LoadLibrary("rmgen");
2 RMS.LoadLibrary("rmbiome");
4 setSelectedBiome();
6 const tMainTerrain = g_Terrains.mainTerrain;
7 const tForestFloor1 = g_Terrains.forestFloor1;
8 const tForestFloor2 = g_Terrains.forestFloor2;
9 const tCliff = g_Terrains.cliff;
10 const tTier1Terrain = g_Terrains.tier1Terrain;
11 const tTier2Terrain = g_Terrains.tier2Terrain;
12 const tTier3Terrain = g_Terrains.tier3Terrain;
13 const tHill = g_Terrains.mainTerrain;
14 const tRoad = g_Terrains.road;
15 const tRoadWild = g_Terrains.roadWild;
16 const tTier4Terrain = g_Terrains.tier4Terrain;
17 const tWater = g_Terrains.water;
19 const oTree1 = g_Gaia.tree1;
20 const oTree2 = g_Gaia.tree2;
21 const oTree3 = g_Gaia.tree3;
22 const oTree4 = g_Gaia.tree4;
23 const oTree5 = g_Gaia.tree5;
24 const oFruitBush = g_Gaia.fruitBush;
25 const oMainHuntableAnimal = g_Gaia.mainHuntableAnimal;
26 const oSecondaryHuntableAnimal = g_Gaia.secondaryHuntableAnimal;
27 const oStoneLarge = g_Gaia.stoneLarge;
28 const oStoneSmall = g_Gaia.stoneSmall;
29 const oMetalLarge = g_Gaia.metalLarge;
31 const aGrass = g_Decoratives.grass;
32 const aGrassShort = g_Decoratives.grassShort;
33 const aRockLarge = g_Decoratives.rockLarge;
34 const aRockMedium = g_Decoratives.rockMedium;
35 const aBushMedium = g_Decoratives.bushMedium;
36 const aBushSmall = g_Decoratives.bushSmall;
38 const pForest1 = [tForestFloor2 + TERRAIN_SEPARATOR + oTree1, tForestFloor2 + TERRAIN_SEPARATOR + oTree2, tForestFloor2];
39 const pForest2 = [tForestFloor1 + TERRAIN_SEPARATOR + oTree4, tForestFloor1 + TERRAIN_SEPARATOR + oTree5, tForestFloor1];
41 InitMap();
43 const numPlayers = getNumPlayers();
44 const mapSize = getMapSize();
46 var clPlayer = createTileClass();
47 var clHill = createTileClass();
48 var clForest = createTileClass();
49 var clDirt = createTileClass();
50 var clRock = createTileClass();
51 var clMetal = createTileClass();
52 var clFood = createTileClass();
53 var clBaseResource = createTileClass();
54 var clLand = createTileClass();
56 const playerIslandRadius = scaleByMapSize(15, 30);
57 const islandHeight = 20;
59 const islandBetweenPlayerAndCenterDist = 0.16;
60 const islandBetweenPlayerAndCenterRadius = 0.81;
61 const centralIslandRadius = 0.36;
63 var [playerIDs, playerX, playerZ, playerAngle, startAngle] = radialPlayerPlacement();
65 var numIslands = 0;
66 var isConnected = [];
67 var islandX = [];
68 var islandZ = [];
70 function initIsConnected()
72         for (let m = 0; m < numIslands; ++m)
73         {
74                 isConnected[m] = [];
75                 for (let n = 0; n < numIslands; ++n)
76                         isConnected[m][n] = 0;
77         }
80 function createIsland(islandID, size, tileClass)
82         let hillSize = Math.PI * Math.pow(playerIslandRadius, 2) * size;
83         createArea(
84                 new ClumpPlacer(hillSize, 0.95, 0.6, 10, islandX[islandID], islandZ[islandID]),
85                 [
86                         new LayeredPainter([tCliff, tHill], [2]),
87                         new SmoothElevationPainter(ELEVATION_SET, islandHeight, 2),
88                         paintClass(tileClass)
89                 ],
90                 null);
91         return hillSize;
94 function createIslandAtRadialLocation(playerID, islandID, playerIDOffset, distFromCenter, islandRadius)
96         let angle = startAngle + (playerID * 2 + playerIDOffset) * Math.PI / numPlayers;
97         islandX[islandID] = Math.round(fractionToTiles(0.5 + distFromCenter * Math.cos(angle)));
98         islandZ[islandID] = Math.round(fractionToTiles(0.5 + distFromCenter * Math.sin(angle)));
99         createIsland(islandID, islandRadius, clLand);
102 function createSnowflakeSearockWithCenter(sizeID)
104         let [tertiaryIslandDist, tertiaryIslandRadius, islandBetweenPlayersDist, islandBetweenPlayersRadius] = islandSizes[sizeID];
106         let islandID_center = 4 * numPlayers;
107         numIslands = islandID_center + 1;
108         initIsConnected();
110         log("Creating central island...");
111         islandX[islandID_center] = fractionToTiles(0.5);
112         islandZ[islandID_center] = fractionToTiles(0.5);
113         createIsland(islandID_center, centralIslandRadius, clLand);
115         for (let playerID = 0; playerID < numPlayers; ++playerID)
116         {
117                 let playerID_neighbor = playerID + 1 < numPlayers ? playerID + 1 : 0;
119                 let islandID_player = playerID;
120                 let islandID_playerNeighbor = playerID_neighbor;
121                 let islandID_betweenPlayers = playerID + numPlayers;
122                 let islandID_betweenPlayerAndCenter = playerID + 2 * numPlayers;
123                 let islandID_betweenPlayerAndCenterNeighbor = playerID_neighbor + 2 * numPlayers;
124                 let islandID_tertiary = playerID + 3 * numPlayers;
126                 log("Creating island between the player and their neighbor...");
127                 isConnected[islandID_betweenPlayers][islandID_player] = 1;
128                 isConnected[islandID_betweenPlayers][islandID_playerNeighbor] = 1;
129                 createIslandAtRadialLocation(playerID, islandID_betweenPlayers, 1, islandBetweenPlayersDist, islandBetweenPlayersRadius);
131                 log("Creating an island between the player and the center...");
132                 isConnected[islandID_betweenPlayerAndCenter][islandID_player] = 1;
133                 isConnected[islandID_betweenPlayerAndCenter][islandID_center] = 1;
134                 isConnected[islandID_betweenPlayerAndCenter][islandID_betweenPlayerAndCenterNeighbor] = 1;
135                 createIslandAtRadialLocation(playerID, islandID_betweenPlayerAndCenter, 0, islandBetweenPlayerAndCenterDist, islandBetweenPlayerAndCenterRadius);
137                 log("Creating tertiary island, at the map border...");
138                 isConnected[islandID_tertiary][islandID_betweenPlayers] = 1;
139                 createIslandAtRadialLocation(playerID, islandID_tertiary, 1, tertiaryIslandDist, tertiaryIslandRadius);
140         }
144  * Creates one island in front of every player and connects it with the neighbors.
145  */
146 function createSnowflakeSearockWithoutCenter()
148         numIslands = 2 * numPlayers;
149         initIsConnected();
151         for (let playerID = 0; playerID < numPlayers; ++playerID)
152         {
153                 let playerID_neighbor = playerID + 1 < numPlayers ? playerID + 1 : 0;
155                 let islandID_player = playerID;
156                 let islandID_playerNeighbor = playerID_neighbor;
157                 let islandID_inFrontOfPlayer = playerID + numPlayers;
158                 let islandID_inFrontOfPlayerNeighbor = playerID_neighbor + numPlayers;
160                 isConnected[islandID_player][islandID_playerNeighbor] = 1;
161                 isConnected[islandID_player][islandID_inFrontOfPlayer] = 1;
162                 isConnected[islandID_inFrontOfPlayer][islandID_inFrontOfPlayerNeighbor] = 1;
164                 createIslandAtRadialLocation(playerID, islandID_inFrontOfPlayer, 0, islandBetweenPlayerAndCenterDist, islandBetweenPlayerAndCenterRadius);
165         }
168 function createSnowflakeSearockTiny()
170         numIslands = numPlayers + 1;
171         initIsConnected();
173         let islandID_center = numPlayers;
175         log("Creating central island...");
176         islandX[islandID_center] = fractionToTiles(0.5);
177         islandZ[islandID_center] = fractionToTiles(0.5);
178         createIsland(numPlayers, 1, clLand);
180         for (let playerID = 0; playerID < numPlayers; ++playerID)
181         {
182                 let islandID_player = playerID;
183                 isConnected[islandID_player][islandID_center] = 1;
184         }
187 initTerrain(tWater);
189 const islandSizes = {
190         "medium":  [0.41, 0.49, 0.26, 1],
191         "large1":  [0.41, 0.49, 0.24, 1],
192         "large2":  [0.41, 0.36, 0.28, 0.81]
195 if (mapSize <= 128)
197         createSnowflakeSearockTiny();
199 else if (mapSize <= 192)
201         createSnowflakeSearockWithoutCenter();
203 else if (mapSize <= 256)
205         if (numPlayers < 6)
206                 createSnowflakeSearockWithCenter("medium");
207         else
208                 createSnowflakeSearockWithoutCenter();
210 else if (mapSize <= 320)
212         if (numPlayers < 8)
213                 createSnowflakeSearockWithCenter("medium");
214         else
215                 createSnowflakeSearockWithoutCenter();
217 else
218         createSnowflakeSearockWithCenter(numPlayers < 6 ? "large1" : "large2");
220 for (var i = 0; i < numPlayers; ++i)
222         var id = playerIDs[i];
223         log("Creating base for player " + id + "...");
225         // get the x and z in tiles
226         var fx = fractionToTiles(playerX[i]);
227         var fz = fractionToTiles(playerZ[i]);
228         var ix = round(fx);
229         var iz = round(fz);
231         islandX[i] = ix;
232         islandZ[i] = iz;
234         let hillSize = createIsland(i, 1, clPlayer);
236         // create the city patch
237         var cityRadius = playerIslandRadius/3;
238         var placer = new ClumpPlacer(PI*cityRadius*cityRadius, 0.6, 0.3, 10, ix, iz);
239         var painter = new LayeredPainter([tRoadWild, tRoad], [1]);
240         createArea(placer, painter, null);
242         placeCivDefaultEntities(fx, fz, id, { 'iberWall': 'towers' });
244         placeDefaultChicken(fx, fz, clBaseResource);
246         // create berry bushes
247         var bbAngle = randFloat(0, TWO_PI);
248         var bbDist = 10;
249         var bbX = round(fx + bbDist * cos(bbAngle));
250         var bbZ = round(fz + bbDist * sin(bbAngle));
251         var group = new SimpleGroup(
252                 [new SimpleObject(oFruitBush, 5,5, 0,3)],
253                 true, clBaseResource, bbX, bbZ
254         );
255         createObjectGroup(group, 0);
257         // create metal mine
258         var mAngle = bbAngle;
259         while(abs(mAngle - bbAngle) < PI/3)
260                 mAngle = randFloat(0, TWO_PI);
262         var mDist = playerIslandRadius - 4;
263         var mX = round(fx + mDist * cos(mAngle));
264         var mZ = round(fz + mDist * sin(mAngle));
265         group = new SimpleGroup(
266                 [new SimpleObject(oMetalLarge, 1,1, 0,0)],
267                 true, clBaseResource, mX, mZ
268         );
269         createObjectGroup(group, 0);
271         // create stone mines
272         mAngle += randFloat(PI/8, PI/4);
273         mX = round(fx + mDist * cos(mAngle));
274         mZ = round(fz + mDist * sin(mAngle));
275         group = new SimpleGroup(
276                 [new SimpleObject(oStoneLarge, 1,1, 0,2)],
277                 true, clBaseResource, mX, mZ
278         );
279         createObjectGroup(group, 0);
281         // create starting trees
282         var num = floor(hillSize / 60);
283         var tAngle = randFloat(-PI/3, 4*PI/3);
284         var tDist = 11;
285         var tX = round(fx + tDist * cos(tAngle));
286         var tZ = round(fz + tDist * sin(tAngle));
287         group = new SimpleGroup(
288                 [new SimpleObject(oTree1, num, num, 0,4)],
289                 false, clBaseResource, tX, tZ
290         );
291         createObjectGroup(group, 0, [avoidClasses(clBaseResource,2), stayClasses(clPlayer, 3)]);
293         placeDefaultDecoratives(fx, fz, aGrassShort, clBaseResource, playerIslandRadius);
295 RMS.SetProgress(30);
297 log("Creating connectors...");
298 for (let ix = 0; ix < mapSize; ++ix)
299         for (let iz = 0; iz < mapSize; ++iz)
300                 for (let m = 0; m < numIslands; ++m)
301                         for (let n = 0; n < numIslands; ++n)
302                         {
303                                 if (isConnected[m][n] != 1)
304                                         continue;
306                                 let islandDistX = islandX[n] - islandX[m];
307                                 let islandDistZ = islandZ[m] - islandZ[n];
309                                 let d1 = islandDistX * (iz - islandZ[m]) + islandDistZ * (ix - islandX[m]);
310                                 let d2 = Math.square(islandDistX) + Math.square(islandDistZ);
312                                 let dis = Math.abs(d1) / Math.sqrt(d2);
313                                 let z = iz - islandDistX * d1 / d2;
315                                 if (dis >= 5 || z < Math.min(islandZ[m], islandZ[n]) || z > Math.max(islandZ[m], islandZ[n]))
316                                         continue;
318                                 addToClass(ix, iz, clLand);
320                                 let height;
321                                 let tileClass;
323                                 let f = 3 - dis;
324                                 if (f > 0)
325                                 {
326                                         height = islandHeight;
327                                         tileClass = dis < 2 ? tHill : tCliff;
328                                 }
329                                 else
330                                 {
331                                         height = islandHeight + 10 * f;
332                                         tileClass = tCliff;
333                                 }
335                                 if (getHeight(ix, iz) < height)
336                                 {
337                                         placeTerrain(ix, iz, tileClass);
338                                         setHeight(ix, iz, height);
339                                 }
340                         }
342 if (currentBiome() == "savanna")
344         var MIN_TREES = 200;
345         var MAX_TREES = 1250;
346         var P_FOREST = 0.02;
348 else if (currentBiome() == "tropic")
350         var MIN_TREES = 1000;
351         var MAX_TREES = 6000;
352         var P_FOREST = 0.6;
354 else
356         var MIN_TREES = 500;
357         var MAX_TREES = 3000;
358         var P_FOREST = 0.7;
361 var totalTrees = scaleByMapSize(MIN_TREES, MAX_TREES);
362 var numForest = totalTrees * P_FOREST;
363 var numStragglers = totalTrees * (1.0 - P_FOREST);
365 log("Creating forests...");
366 var types = [
367         [[tForestFloor2, tMainTerrain, pForest1], [tForestFloor2, pForest1]],
368         [[tForestFloor1, tMainTerrain, pForest2], [tForestFloor1, pForest2]]
371 var size = numForest / (scaleByMapSize(2, 8) * numPlayers) * (currentBiome() == "savanna" ? 2 : 1);
372 var num = floor(size / types.length);
373 for (let type of types)
374         createAreas(
375                 new ClumpPlacer(numForest / num, 0.1, 0.1, 1),
376                 [
377                         new LayeredPainter(type, [2]),
378                         paintClass(clForest)
379                 ],
380                 [avoidClasses(clPlayer, 6, clForest, 10, clHill, 0), stayClasses(clLand, 4)],
381                 num);
382 RMS.SetProgress(55);
384 log("Creating stone mines...");
385 group = new SimpleGroup([new SimpleObject(oStoneSmall, 0,2, 0,4), new SimpleObject(oStoneLarge, 1,1, 0,4)], true, clRock);
386 createObjectGroupsDeprecated(group, 0,
387         [avoidClasses(clForest, 1, clPlayer, 10, clRock, 10, clHill, 1), stayClasses(clLand, 5)],
388         5*scaleByMapSize(4,16), 100
391 log("Creating small stone quarries...");
392 group = new SimpleGroup([new SimpleObject(oStoneSmall, 2,5, 1,3)], true, clRock);
393 createObjectGroupsDeprecated(group, 0,
394         [avoidClasses(clForest, 1, clPlayer, 10, clRock, 10, clHill, 1), stayClasses(clLand, 5)],
395         5*scaleByMapSize(4,16), 100
398 log("Creating metal mines...");
399 group = new SimpleGroup([new SimpleObject(oMetalLarge, 1,1, 0,4)], true, clMetal);
400 createObjectGroupsDeprecated(group, 0,
401         [avoidClasses(clForest, 1, clPlayer, 10, clMetal, 10, clRock, 5, clHill, 1), stayClasses(clLand, 5)],
402         5*scaleByMapSize(4,16), 100
405 RMS.SetProgress(65);
406 log("Creating dirt patches...");
407 for (let size of [scaleByMapSize(3, 48), scaleByMapSize(5, 84), scaleByMapSize(8, 128)])
408         createAreas(
409                 new ClumpPlacer(size, 0.3, 0.06, 0.5),
410                 [
411                         new LayeredPainter([[tMainTerrain, tTier1Terrain],[tTier1Terrain, tTier2Terrain], [tTier2Terrain, tTier3Terrain]], [1, 1]),
412                         paintClass(clDirt)
413                 ],
414                 [avoidClasses(clForest, 0, clHill, 0, clDirt, 5, clPlayer, 12), stayClasses(clLand, 5)],
415                 scaleByMapSize(15, 45));
417 log("Creating grass patches...");
418 for (let size of [scaleByMapSize(2, 32), scaleByMapSize(3, 48), scaleByMapSize(5, 80)])
419         createAreas(
420                 new ClumpPlacer(size, 0.3, 0.06, 0.5),
421                 new TerrainPainter(tTier4Terrain),
422                 [avoidClasses(clForest, 0, clHill, 0, clDirt, 5, clPlayer, 12), stayClasses(clLand, 5)],
423                 scaleByMapSize(15, 45));
425 log("Creating small decorative rocks...");
426 group = new SimpleGroup(
427         [new SimpleObject(aRockMedium, 1,3, 0,1)],
428         true
430 createObjectGroupsDeprecated(
431         group, 0,
432         [avoidClasses(clForest, 0, clPlayer, 0, clHill, 0), stayClasses(clLand, 4)],
433         scaleByMapSize(16, 262), 50
436 log("Creating large decorative rocks...");
437 group = new SimpleGroup(
438         [new SimpleObject(aRockLarge, 1,2, 0,1), new SimpleObject(aRockMedium, 1,3, 0,2)],
439         true
441 createObjectGroupsDeprecated(
442         group, 0,
443         [avoidClasses(clForest, 0, clPlayer, 0, clHill, 0), stayClasses(clLand, 4)],
444         scaleByMapSize(8, 131), 50
447 RMS.SetProgress(70);
449 log("Creating deer...");
450 group = new SimpleGroup(
451         [new SimpleObject(oMainHuntableAnimal, 5,7, 0,4)],
452         true, clFood
454 createObjectGroupsDeprecated(group, 0,
455         [avoidClasses(clForest, 0, clPlayer, 10, clHill, 1, clFood, 20), stayClasses(clLand, 4)],
456         3 * numPlayers, 50
459 RMS.SetProgress(75);
461 log("Creating sheep...");
462 group = new SimpleGroup(
463         [new SimpleObject(oSecondaryHuntableAnimal, 2,3, 0,2)],
464         true, clFood
466 createObjectGroupsDeprecated(group, 0,
467         [avoidClasses(clForest, 0, clPlayer, 10, clHill, 1, clFood, 20), stayClasses(clLand, 4)],
468         3 * numPlayers, 50
471 log("Creating fruits...");
472 group = new SimpleGroup(
473         [new SimpleObject(oFruitBush, 5,7, 0,4)],
474         true, clFood
476 createObjectGroupsDeprecated(group, 0,
477         [avoidClasses(clForest, 0, clPlayer, 10, clHill, 1, clFood, 20), stayClasses(clLand, 4)],
478         3 * numPlayers, 50
480 RMS.SetProgress(85);
482 log("Creating straggler trees...");
483 var types = [oTree1, oTree2, oTree4, oTree3];
484 var num = floor(numStragglers / types.length);
485 for (let type of types)
486         createObjectGroupsDeprecated(
487                 new SimpleGroup([new SimpleObject(type, 1, 1, 0, 3)], true, clForest),
488                 0,
489                 [avoidClasses(clForest, 1, clHill, 1, clPlayer, 9, clMetal, 6, clRock, 6), stayClasses(clLand, 4)],
490                 num);
492 var planetm = 1;
493 if (currentBiome() == "tropic")
494         planetm = 8;
496 log("Creating small grass tufts...");
497 group = new SimpleGroup(
498         [new SimpleObject(aGrassShort, 1,2, 0,1, -PI/8,PI/8)]
500 createObjectGroupsDeprecated(group, 0,
501         [avoidClasses(clHill, 2, clPlayer, 2, clDirt, 0), stayClasses(clLand, 4)],
502         planetm * scaleByMapSize(13, 200)
505 RMS.SetProgress(90);
507 log("Creating large grass tufts...");
508 group = new SimpleGroup(
509         [new SimpleObject(aGrass, 2,4, 0,1.8, -PI/8,PI/8), new SimpleObject(aGrassShort, 3,6, 1.2,2.5, -PI/8,PI/8)]
511 createObjectGroupsDeprecated(group, 0,
512         [avoidClasses(clHill, 2, clPlayer, 2, clDirt, 1, clForest, 0), stayClasses(clLand, 4)],
513         planetm * scaleByMapSize(13, 200)
515 RMS.SetProgress(95);
517 log("Creating bushes...");
518 group = new SimpleGroup(
519         [new SimpleObject(aBushMedium, 1,2, 0,2), new SimpleObject(aBushSmall, 2,4, 0,2)]
521 createObjectGroupsDeprecated(group, 0,
522         [avoidClasses(clHill, 1, clPlayer, 1, clDirt, 1), stayClasses(clLand, 4)],
523         planetm * scaleByMapSize(13, 200), 50
526 setSkySet(pickRandom(["cirrus", "cumulus", "sunny"]));
527 setSunRotation(randFloat(0, TWO_PI));
528 setSunElevation(randFloat(PI/ 5, PI / 3));
530 ExportMap();