2 * @file This library is used to generate different map variations on the map Unknown, Unknown Land and Unknown Nomad.
6 * True if city centers should be placed or false for nomad.
11 * True if all players should be connected via land and false if river or islands can split some if not all the players.
15 TILE_CENTERED_HEIGHT_MAP = true;
19 const tMainTerrain = g_Terrains.mainTerrain;
20 const tForestFloor1 = g_Terrains.forestFloor1;
21 const tForestFloor2 = g_Terrains.forestFloor2;
22 const tCliff = g_Terrains.cliff;
23 const tTier1Terrain = g_Terrains.tier1Terrain;
24 const tTier2Terrain = g_Terrains.tier2Terrain;
25 const tTier3Terrain = g_Terrains.tier3Terrain;
26 const tHill = g_Terrains.hill;
27 const tRoad = g_Terrains.road;
28 const tRoadWild = g_Terrains.roadWild;
29 const tTier4Terrain = g_Terrains.tier4Terrain;
30 const tShore = g_Terrains.shore;
31 const tWater = g_Terrains.water;
33 const oTree1 = g_Gaia.tree1;
34 const oTree2 = g_Gaia.tree2;
35 const oTree4 = g_Gaia.tree4;
36 const oTree5 = g_Gaia.tree5;
37 const oFruitBush = g_Gaia.fruitBush;
38 const oMainHuntableAnimal = g_Gaia.mainHuntableAnimal;
39 const oSecondaryHuntableAnimal = g_Gaia.secondaryHuntableAnimal;
40 const oFish = g_Gaia.fish;
41 const oStoneLarge = g_Gaia.stoneLarge;
42 const oStoneSmall = g_Gaia.stoneSmall;
43 const oMetalLarge = g_Gaia.metalLarge;
44 const oWoodTreasure = "gaia/special_treasure_wood";
46 const aGrass = g_Decoratives.grass;
47 const aGrassShort = g_Decoratives.grassShort;
48 const aReeds = g_Decoratives.reeds;
49 const aLillies = g_Decoratives.lillies;
50 const aRockLarge = g_Decoratives.rockLarge;
51 const aRockMedium = g_Decoratives.rockMedium;
52 const aBushMedium = g_Decoratives.bushMedium;
53 const aBushSmall = g_Decoratives.bushSmall;
55 const pForest1 = [tForestFloor2 + TERRAIN_SEPARATOR + oTree1, tForestFloor2 + TERRAIN_SEPARATOR + oTree2, tForestFloor2];
56 const pForest2 = [tForestFloor1 + TERRAIN_SEPARATOR + oTree4, tForestFloor1 + TERRAIN_SEPARATOR + oTree5, tForestFloor1];
60 const numPlayers = getNumPlayers();
61 const mapSize = getMapSize();
62 const mapArea = getMapArea();
63 const lSize = Math.pow(scaleByMapSize(1, 6), 1/8);
65 var clPlayer = createTileClass();
66 var clPlayerTerritory = createTileClass();
67 var clHill = createTileClass();
68 var clForest = createTileClass();
69 var clWater = createTileClass();
70 var clDirt = createTileClass();
71 var clRock = createTileClass();
72 var clMetal = createTileClass();
73 var clFood = createTileClass();
74 var clPeninsulaSteam = createTileClass();
75 var clBaseResource = createTileClass();
76 var clLand = createTileClass();
77 var clShallow = createTileClass();
80 var cliffHeight = 3.12;
81 var landElevationPainter = new SmoothElevationPainter(ELEVATION_SET, landHeight, 4);
83 var unknownMapFunctions = {
102 * The player IDs and locations shall only be determined by the landscape functions if it's not a nomad game,
103 * because nomad maps randomize the locations after the terrain generation.
104 * The locations should only determined by the landscape functions to avoid placing bodies of water and resources into civic centers and the starting resources.
106 var playerIDs = sortAllPlayers();
110 var g_StartingTreasures = false;
111 var g_IberianWalls = "walls";
113 function createUnknownMap()
115 let funcs = unknownMapFunctions.land;
118 funcs = funcs.concat(unknownMapFunctions.naval);
120 global["unknown" + pickRandom(funcs)]();
122 paintUnknownMapBasedOnHeight();
125 createUnknownPlayerBases();
129 * Chain of islands or many disconnected islands.
131 function unknownArchipelago()
133 g_IberianWalls = "towers";
134 g_StartingTreasures = true;
136 let [pIDs, islandX, islandZ] = radialPlayerPlacement();
139 [playerIDs, playerX, playerZ] = [pIDs, islandX, islandZ];
140 markPlayerArea("large");
143 log("Creating islands...");
144 let islandSize = diskArea(scaleByMapSize(17, 29));
145 for (let i = 0; i < numPlayers; ++i)
147 new ClumpPlacer(islandSize, 0.8, 0.1, 10, fractionToTiles(islandX[i]), fractionToTiles(islandZ[i])),
148 landElevationPainter,
151 let type = randIntInclusive(1, 3);
154 log("Creating archipelago...");
156 new ClumpPlacer(Math.floor(islandSize * randFloat(0.8, 1.2)), 0.8, 0.1, 10),
158 landElevationPainter,
162 scaleByMapSize(2, 5) * randIntInclusive(8, 14));
164 log("Creating shore jaggedness with small puddles...");
166 new ClumpPlacer(scaleByMapSize(15, 80), 0.2, 0.1, 1),
168 new SmoothElevationPainter(ELEVATION_SET, landHeight, 4),
171 borderClasses(clLand, 6, 3),
172 scaleByMapSize(12, 130) * 2,
177 log("Creating islands...");
179 new ClumpPlacer(Math.floor(islandSize * randFloat(0.6, 1.4)), 0.8, 0.1, randFloat(0.0, 0.2)),
181 landElevationPainter,
184 avoidClasses(clLand, 3, clPlayerTerritory, 3),
185 scaleByMapSize(6, 10) * randIntInclusive(8, 14));
187 log("Creating small islands...");
189 new ClumpPlacer(Math.floor(islandSize * randFloat(0.3, 0.7)), 0.8, 0.1, 0.07),
191 new SmoothElevationPainter(ELEVATION_SET, landHeight, 6),
194 avoidClasses(clLand, 3, clPlayerTerritory, 3),
195 scaleByMapSize(2, 6) * randIntInclusive(6, 15),
200 log("Creating tight islands...");
202 new ClumpPlacer(Math.floor(islandSize * randFloat(0.8, 1.2)), 0.8, 0.1, 10),
204 landElevationPainter,
207 avoidClasses(clLand, randIntInclusive(8, 16), clPlayerTerritory, 3),
208 scaleByMapSize(2, 5) * randIntInclusive(8, 14));
213 * Disk shaped mainland with water on the edge.
215 function unknownContinent()
217 let waterHeight = -5;
221 log("Ensuring player area...");
222 [playerIDs, playerX, playerZ] = radialPlayerPlacement(0.25);
223 markPlayerArea("small");
225 for (let i = 0; i < numPlayers; ++i)
229 Math.floor(scaleByMapSize(5, 9)),
230 Math.floor(scaleByMapSize(5, 20)),
232 Math.round(fractionToTiles(playerX[i])),
233 Math.round(fractionToTiles(playerZ[i])),
235 [Math.floor(scaleByMapSize(23, 50))]),
237 landElevationPainter,
243 log("Creating continent...");
245 new ClumpPlacer(mapArea * 0.45, 0.9, 0.09, 10, Math.round(fractionToTiles(0.5)), Math.round(fractionToTiles(0.5))),
247 landElevationPainter,
254 log("Creating peninsula (i.e. half the map not being surrounded by water)...");
255 let angle = randFloat(0, 2 * Math.PI);
262 Math.round(fractionToTiles(0.5 + 0.25 * Math.cos(angle))),
263 Math.round(fractionToTiles(0.5 + 0.25 * Math.sin(angle)))),
265 landElevationPainter,
270 log("Remembering to not paint shorelines into the peninsula...");
277 Math.round(fractionToTiles(0.5 + 0.35 * Math.cos(angle))),
278 Math.round(fractionToTiles(0.5 + 0.35 * Math.sin(angle)))),
279 paintClass(clPeninsulaSteam),
283 createShoreJaggedness(waterHeight, clLand, 7);
287 * Creates a huge central river, possibly connecting the riversides with a narrow piece of land.
289 function unknownCentralSea()
291 let waterHeight = -3;
292 let horizontal = randBool();
294 let [start, end] = centralRiverCoordinates(horizontal);
297 "startX": tilesToFraction(start[0]),
298 "startZ": tilesToFraction(start[1]),
299 "endX": tilesToFraction(end[0]),
300 "endZ": tilesToFraction(end[1]),
301 "width": randFloat(0.22, 0.3) + scaleByMapSize(0.05, 0.2),
304 "waterHeight": waterHeight,
305 "landHeight": landHeight,
308 "waterFunc": (ix, iz, height, riverFraction) => {
310 addToClass(ix, iz, clWater);
312 "landFunc": (ix, iz, shoreDist1, shoreDist2) => {
313 setHeight(ix, iz, 3.1);
314 addToClass(ix, iz, clLand);
320 [playerIDs, playerX, playerZ] = playerPlacementRiver(horizontal ? Math.PI / 2 : 0, 0.6);
321 markPlayerArea("small");
324 if (!g_AllowNaval || randBool())
326 log("Creating isthmus (i.e. connecting the two riversides with a big land passage)...");
327 let [coord1, coord2] = centralRiverCoordinates(!horizontal);
332 scaleByMapSize(randIntInclusive(16, 24),
333 randIntInclusive(100, 140)),
335 3 * scaleByMapSize(1, 4),
339 landElevationPainter,
341 unPaintClass(clWater)
346 createExtensionsOrIslands();
347 // Don't createShoreJaggedness since it doesn't fit artistically here
351 * Creates a very small central river.
353 function unknownCentralRiver()
355 let waterHeight = -4;
357 initHeight(landHeight);
359 let horizontal = randBool();
363 [playerIDs, playerX, playerZ] = playerPlacementRiver(horizontal ? Math.PI / 2 : 0, 0.5);
364 markPlayerArea("large");
367 log("Creating the main river...");
368 let [coord1, coord2] = centralRiverCoordinates(horizontal);
370 new PathPlacer(...coord1, ...coord2, scaleByMapSize(14, 24), 0.5, scaleByMapSize(3, 12), 0.1, 0.01),
371 new SmoothElevationPainter(ELEVATION_SET, waterHeight, 4),
372 avoidClasses(clPlayerTerritory, 4));
374 log("Creating small water spots at the map border to ensure separation of players...");
375 for (let coord of [coord1, coord2])
377 new ClumpPlacer(Math.floor(diskArea(scaleByMapSize(5, 10))), 0.95, 0.6, 10, ...coord),
378 new SmoothElevationPainter(ELEVATION_SET, waterHeight, 2),
379 avoidClasses(clPlayerTerritory, 8));
381 if (!g_AllowNaval || randBool())
383 log("Creating the shallows of the main river...");
384 for (let i = 0; i <= randIntInclusive(1, scaleByMapSize(4, 8)); ++i)
386 let cLocation = randFloat(0.15, 0.85);
387 let x1 = [fractionToTiles(cLocation), fractionToTiles(0.35)];
388 let x2 = [fractionToTiles(cLocation), fractionToTiles(0.65)];
394 createShallowsPassage(...x1, ...x2, scaleByMapSize(4, 8), -2, -2, 2, clShallow, undefined, waterHeight);
399 createTributaryRivers(
401 randIntInclusive(8, scaleByMapSize(12, 16)),
402 scaleByMapSize(10, 20),
408 avoidClasses(clPlayerTerritory, 3));
412 * Creates a circular lake in the middle and possibly a river between each player ("pizza slices").
414 function unknownRiversAndLake()
416 let waterHeight = -4;
417 initHeight(landHeight);
423 [playerIDs, playerX, playerZ, playerAngle, startAngle] = radialPlayerPlacement();
424 markPlayerArea("small");
427 let mid = Math.round(fractionToTiles(0.5));
428 let lake = randBool(3/4);
431 log("Creating lake...");
433 new ClumpPlacer(mapArea * 0.09 * lSize, 0.7, 0.1, 10, mid, mid),
435 new SmoothElevationPainter(ELEVATION_SET, waterHeight, 4),
440 createShoreJaggedness(waterHeight, clWater, 3);
443 // Don't do this on nomad because the imbalances on the different islands are too drastic
444 if (g_PlayerBases && (!lake || randBool(1/3)))
446 log("Creating small rivers separating players...");
447 let [riverX, riverZ, riverAngle] = distributePointsOnCircle(numPlayers, startAngle + Math.PI / numPlayers, 0.5, 0.5, 0.5);
449 for (let i = 0; i < numPlayers; ++i)
452 new PathPlacer(mid, mid, fractionToTiles(riverX[i]), fractionToTiles(riverZ[i]), scaleByMapSize(14, 24), 0.4, 3 * scaleByMapSize(1, 3), 0.2, 0.05),
454 new SmoothElevationPainter(ELEVATION_SET, waterHeight, 4),
457 avoidClasses(clPlayer, 5));
460 new ClumpPlacer(Math.floor(diskArea(scaleByMapSize(10, 50)) / 5), 0.95, 0.6, 10, fractionToTiles(riverX[i]), fractionToTiles(riverZ[i])),
462 new SmoothElevationPainter(ELEVATION_SET, waterHeight, 0),
465 avoidClasses(clPlayer, 5));
468 log("Creating lake...");
470 new ClumpPlacer(mapArea * 0.005, 0.7, 0.1, 10, mid, mid),
472 new SmoothElevationPainter(ELEVATION_SET, waterHeight, 4),
478 if (lake && randBool())
480 log("Creating small central island...");
482 new ClumpPlacer(mapArea * 0.006 * lSize, 0.7, 0.1, 10, mid, mid),
484 landElevationPainter,
492 * Align players on a land strip with seas bordering on one or both sides that can hold islands.
494 function unknownEdgeSeas()
496 let waterHeight = -4;
497 initHeight(landHeight);
499 let horizontal = randBool();
502 [playerIDs, playerX, playerZ] = playerPlacementLine(horizontal, 0.5, 0.2);
503 // Don't place the shoreline inside the CC, but possibly into the players territory
504 markPlayerArea("small");
507 for (let location of pickRandom([["first"], ["second"], ["first", "second"]]))
509 let positionX = location == "first" ? [0, 0] : [1, 1];
510 let positionZ = [0, 1];
513 [positionX, positionZ] = [positionZ, positionX];
517 "startX": positionX[0],
518 "startZ": positionZ[0],
519 "endX": positionX[1],
520 "endZ": positionZ[1],
521 "width": 0.62 - randFloat(0, scaleByMapSize(0, 0.1)),
524 "waterHeight": waterHeight,
525 "landHeight": landHeight,
531 createExtensionsOrIslands();
532 paintTileClassBasedOnHeight(0, cliffHeight, 1, clLand);
533 createShoreJaggedness(waterHeight, clLand, 7, false);
537 * Land shaped like a concrescent moon around a central lake.
539 function unknownGulf()
541 let waterHeight = -3;
542 initHeight(landHeight);
544 let startAngle = randFloat(0, 2) * Math.PI;
547 log("Determining player locations...");
548 for (let i = 0; i < numPlayers; ++i)
550 let playerAngle = startAngle + 2/3 * Math.PI * (-1 + (numPlayers == 1 ? 1 : 2 * i / (numPlayers - 1)));
551 playerX[i] = 0.5 + 0.35 * Math.cos(playerAngle);
552 playerZ[i] = 0.5 + 0.35 * Math.sin(playerAngle);
554 markPlayerArea("large");
558 new ClumpPlacer(mapArea * 0.08, 0.7, 0.05, 10, Math.round(fractionToTiles(0.5)), Math.round(fractionToTiles(0.5))),
559 new ClumpPlacer(mapArea * 0.13 * lSize, 0.7, 0.05, 10, Math.round(fractionToTiles(0.5 - 0.2 * Math.cos(startAngle))), Math.round(fractionToTiles(0.5 - 0.2 * Math.sin(startAngle)))),
560 new ClumpPlacer(mapArea * 0.15 * lSize, 0.7, 0.05, 10, Math.round(fractionToTiles(0.5 - 0.49 * Math.cos(startAngle))), Math.round(fractionToTiles(0.5 - 0.49 * Math.sin(startAngle)))),
563 for (let placer of placers)
567 new SmoothElevationPainter(ELEVATION_SET, waterHeight, 4),
570 avoidClasses(clPlayerTerritory, scaleByMapSize(15, 25)));
574 * Mainland style with some small random lakes.
576 function unknownLakes()
578 let waterHeight = -5;
580 initHeight(landHeight);
584 [playerIDs, playerX, playerZ] = radialPlayerPlacement();
585 markPlayerArea("large");
588 log("Creating lakes...");
590 new ClumpPlacer(scaleByMapSize(160, 700), 0.2, 0.1, 1),
592 new SmoothElevationPainter(ELEVATION_SET, waterHeight, 5),
595 [avoidClasses(clPlayerTerritory, 12), randBool() ? avoidClasses(clWater, 8) : new NullConstraint()],
596 scaleByMapSize(5, 16));
600 * A large hill leaving players only a small passage to each of the the two neighboring players.
602 function unknownPasses()
604 let mountainHeight = 24;
605 let waterHeight = -4;
606 initHeight(landHeight);
612 [playerIDs, playerX, playerZ, playerAngle, startAngle] = radialPlayerPlacement();
613 markPlayerArea("small");
616 startAngle = Math.random(0, 2 * Math.PI);
618 let mid = Math.round(fractionToTiles(0.5));
619 let [mountainX, mountainZ] = distributePointsOnCircle(numPlayers, startAngle + Math.PI / numPlayers, fractionToTiles(0.5), mid, mid);
620 let [passesX, passesZ] = distributePointsOnCircle(numPlayers * 2, startAngle, fractionToTiles(0.35), mid, mid);
622 for (let i = 0; i < numPlayers; ++i)
624 log("Creating a mountain range between neighboring players...");
626 new PathPlacer(mid, mid, mountainX[i], mountainZ[i], scaleByMapSize(14, 24), 0.4, 3 * scaleByMapSize(1, 3), 0.2, 0.05),
628 // More smoothing than this often results in the mountainrange becoming passable to one player.
629 new SmoothElevationPainter(ELEVATION_SET, mountainHeight, 1),
632 avoidClasses(clPlayer, 5));
634 log("Creating small mountain at the map border between the players to ensure separation of players...");
636 new ClumpPlacer(Math.floor(diskArea(scaleByMapSize(10, 50)) / 5), 0.95, 0.6, 10, mountainX[i], mountainZ[i]),
637 new SmoothElevationPainter(ELEVATION_SET, mountainHeight, 0),
638 avoidClasses(clPlayer, 5));
640 log("Create passages between neighboring players...");
645 passesX[2 * ((i + 1) % numPlayers)],
646 passesZ[2 * ((i + 1) % numPlayers)],
647 scaleByMapSize(14, 24),
649 3 * scaleByMapSize(1, 3),
652 new SmoothElevationPainter(ELEVATION_SET, landHeight, 2),
658 log("Create central lake...");
660 new ClumpPlacer(mapArea * 0.03 * lSize, 0.7, 0.1, 10, mid, mid),
662 new SmoothElevationPainter(ELEVATION_SET, waterHeight, 3),
669 log("Fill area between the paths...");
671 new ClumpPlacer(mapArea * 0.005, 0.7, 0.1, 10, mid, mid),
673 new SmoothElevationPainter(ELEVATION_SET, mountainHeight, 4),
681 * Land enclosed by a hill that leaves small areas for civic centers and large central place.
683 function unknownLowlands()
685 let mountainHeight = 30;
687 log("Creating mountain that is going to separate players...");
688 initHeight(mountainHeight);
694 [playerIDs, playerX, playerZ, playerAngle, startAngle] = radialPlayerPlacement();
695 markPlayerArea("small");
698 startAngle = Math.random(0, 2 * Math.PI);
700 log("Creating valleys enclosed by the mountain...");
701 let valleys = numPlayers;
702 if (mapSize <= 128 && numPlayers <= 2 ||
703 mapSize <= 192 && numPlayers <= 3 ||
704 mapSize <= 320 && numPlayers <= 4 ||
705 mapSize <= 384 && numPlayers <= 5 ||
706 mapSize <= 448 && numPlayers <= 6)
709 let mid = Math.round(fractionToTiles(0.5));
710 let [valleyX, valleyZ] = distributePointsOnCircle(valleys, startAngle, fractionToTiles(0.35), mid, mid);
711 for (let i = 0; i < valleys; ++i)
713 new ClumpPlacer(diskArea(scaleByMapSize(18, 32)), 0.65, 0.1, 10, valleyX[i], valleyZ[i]),
715 new SmoothElevationPainter(ELEVATION_SET, landHeight, 2),
720 log("Creating the big central area...");
722 new ClumpPlacer(mapArea * 0.091 * lSize, 0.7, 0.1, 10, mid, mid),
724 landElevationPainter,
729 log("Creating passes from player areas to the center...");
730 for (let i = 0; i < valleys; ++i)
732 new PathPlacer(mid, mid, valleyX[i], valleyZ[i], scaleByMapSize(14, 24), 0.4, 3 * scaleByMapSize(1, 3), 0.2, 0.05),
734 landElevationPainter,
741 * No water, no hills.
743 function unknownMainland()
749 [playerIDs, playerX, playerZ] = radialPlayerPlacement();
750 markPlayerArea("small");
754 function centralRiverCoordinates(horizontal)
756 let coord1 = [0, fractionToTiles(0.5)];
757 let coord2 = [fractionToTiles(1), fractionToTiles(0.5)];
765 return [coord1, coord2];
768 function createShoreJaggedness(waterHeight, borderClass, shoreDist, inwards = true)
770 log("Creating shore jaggedness...");
771 for (let i = 0; i < 2; ++i)
774 new ChainPlacer(2, Math.floor(scaleByMapSize(4, 6)), 15, 1),
776 new SmoothElevationPainter(ELEVATION_SET, i ? landHeight : waterHeight, 4),
777 i ? paintClass(clLand) : unPaintClass(clLand)
780 avoidClasses(clPlayer, 20, clPeninsulaSteam, 20),
781 borderClasses(borderClass, shoreDist, shoreDist)
783 scaleByMapSize(7, 130) * 2,
787 function createExtensionsOrIslands()
789 let rnd = randIntInclusive(1, 3);
793 log("Creating islands...");
795 new ClumpPlacer(Math.square(randIntInclusive(scaleByMapSize(8, 15), scaleByMapSize(15, 23))), 0.8, 0.1, randFloat(0, 0.2)),
797 landElevationPainter,
800 avoidClasses(clLand, 3, clPlayer, 3),
801 scaleByMapSize(2, 5) * randIntInclusive(8, 14));
805 log("Creating extentions...");
807 new ChainPlacer(Math.floor(scaleByMapSize(4, 7)), Math.floor(scaleByMapSize(7, 10)), Math.floor(scaleByMapSize(16, 40)), 0.07),
809 landElevationPainter,
813 scaleByMapSize(2, 5) * randIntInclusive(8, 14));
818 * Prevent impassable terrain and resource collisions at the the civic center and starting resources.
820 function markPlayerArea(size)
822 for (let i = 0; i < numPlayers; ++i)
824 addCivicCenterAreaToClass(
825 Math.round(fractionToTiles(playerX[i])),
826 Math.round(fractionToTiles(playerZ[i])),
831 new ClumpPlacer(diskArea(scaleByMapSize(17, 29) / 3), 0.6, 0.3, 10, fractionToTiles(playerX[i]), fractionToTiles(playerZ[i])),
832 paintClass(clPlayerTerritory),
837 function paintUnknownMapBasedOnHeight()
839 paintTerrainBasedOnHeight(cliffHeight, 40, 1, tCliff);
840 paintTerrainBasedOnHeight(3, cliffHeight, 1, tMainTerrain);
841 paintTerrainBasedOnHeight(1, 3, 1, tShore);
842 paintTerrainBasedOnHeight(-8, 1, 2, tWater);
844 unPaintTileClassBasedOnHeight(0, cliffHeight, 1, clWater);
845 unPaintTileClassBasedOnHeight(-6, 0, 1, clLand);
847 paintTileClassBasedOnHeight(-6, 0, 1, clWater);
848 paintTileClassBasedOnHeight(0, cliffHeight, 1, clLand);
849 paintTileClassBasedOnHeight(cliffHeight, 40, 1, clHill);
853 * Place resources and decoratives after the player territory was marked.
855 function createUnknownObjects()
857 log("Creating bumps...");
859 new ClumpPlacer(scaleByMapSize(20, 50), 0.3, 0.06, 1),
860 new SmoothElevationPainter(ELEVATION_MODIFY, 2, 2),
861 [avoidClasses(clWater, 2, clPlayer, 10), stayClasses(clLand, 3)],
862 randIntInclusive(0, scaleByMapSize(1, 2) * 200));
864 log("Creating hills...");
866 new ClumpPlacer(scaleByMapSize(20, 150), 0.2, 0.1, 1),
868 new LayeredPainter([tCliff, tHill], [2]),
869 new SmoothElevationPainter(ELEVATION_SET, 18, 2),
872 [avoidClasses(clPlayer, 15, clHill, randIntInclusive(6, 18)), stayClasses(clLand, 0)],
873 randIntInclusive(0, scaleByMapSize(4, 8))*randIntInclusive(1, scaleByMapSize(4, 9))
877 log("Creating forests...");
878 let [numForest, numStragglers] = getTreeCounts(...rBiomeTreeCount(1));
881 [[tForestFloor2, tMainTerrain, pForest1], [tForestFloor2, pForest1]],
882 [[tForestFloor1, tMainTerrain, pForest2], [tForestFloor1, pForest2]]
885 let size = numForest / (scaleByMapSize(2, 8) * numPlayers);
886 let num = Math.floor(size / types.length);
887 for (let type of types)
889 new ClumpPlacer(numForest / num, 0.1, 0.1, 1),
891 new LayeredPainter(type, [2]),
894 [avoidClasses(clPlayer, 20, clForest, randIntInclusive(5, 15), clHill, 0), stayClasses(clLand, 4)],
898 log("Creating dirt patches...");
899 let patchCount = (currentBiome() == "savanna" ? 3 : 1) * scaleByMapSize(15, 45);
900 for (let size of [scaleByMapSize(3, 48), scaleByMapSize(5, 84), scaleByMapSize(8, 128)])
902 new ClumpPlacer(size, 0.3, 0.06, 0.5),
904 new LayeredPainter([[tMainTerrain, tTier1Terrain], [tTier1Terrain, tTier2Terrain], [tTier2Terrain, tTier3Terrain]], [1, 1]),
907 [avoidClasses(clForest, 0, clHill, 0, clDirt, 5, clPlayer, 7), stayClasses(clLand, 4)],
910 log("Creating grass patches...");
911 for (let size of [scaleByMapSize(2, 32), scaleByMapSize(3, 48), scaleByMapSize(5, 80)])
913 new ClumpPlacer(size, 0.3, 0.06, 0.5),
914 new TerrainPainter(tTier4Terrain),
915 [avoidClasses(clForest, 0, clHill, 0, clDirt, 5, clPlayer, 7), stayClasses(clLand, 4)],
920 log("Creating stone mines...");
921 createObjectGroupsDeprecated(
922 new SimpleGroup([new SimpleObject(oStoneSmall, 0, 2, 0, 4), new SimpleObject(oStoneLarge, 1, 1, 0, 4)], true, clRock),
924 [avoidClasses(clForest, 1, clPlayer, 10, clRock, 10, clHill, 1), stayClasses(clLand, 3)],
925 randIntInclusive(scaleByMapSize(2, 9), scaleByMapSize(9, 40)),
928 log("Creating small stone quarries...");
929 createObjectGroupsDeprecated(
930 new SimpleGroup([new SimpleObject(oStoneSmall, 2, 5, 1, 3)], true, clRock),
932 [avoidClasses(clForest, 1, clPlayer, 10, clRock, 10, clHill, 1), stayClasses(clLand, 3)],
933 randIntInclusive(scaleByMapSize(2, 9),scaleByMapSize(9, 40)),
936 log("Creating metal mines...");
937 createObjectGroupsDeprecated(
938 new SimpleGroup([new SimpleObject(oMetalLarge, 1, 1, 0, 4)], true, clMetal),
940 [avoidClasses(clForest, 1, clPlayer, 10, clMetal, 10, clRock, 5, clHill, 1), stayClasses(clLand, 3)],
941 randIntInclusive(scaleByMapSize(2, 9), scaleByMapSize(9, 40)),
945 log("Creating small decorative rocks...");
946 createObjectGroupsDeprecated(
947 new SimpleGroup([new SimpleObject(aRockMedium, 1, 3, 0, 1)], true),
949 [avoidClasses(clWater, 0, clForest, 0, clPlayer, 0, clHill, 0), stayClasses(clLand, 3)],
950 scaleByMapSize(16, 262),
953 log("Creating large decorative rocks...");
954 createObjectGroupsDeprecated(
955 new SimpleGroup([new SimpleObject(aRockLarge, 1, 2, 0, 1), new SimpleObject(aRockMedium, 1, 3, 0, 2)], true),
957 [avoidClasses(clWater, 0, clForest, 0, clPlayer, 0, clHill, 0), stayClasses(clLand, 3)],
958 scaleByMapSize(8, 131),
962 log("Creating deer...");
963 createObjectGroupsDeprecated(
964 new SimpleGroup([new SimpleObject(oMainHuntableAnimal, 5, 7, 0, 4)], true, clFood),
966 [avoidClasses(clWater, 0, clForest, 0, clPlayer, 8, clHill, 1, clFood, 20), stayClasses(clLand, 2)],
967 randIntInclusive(numPlayers + 3, 5 * numPlayers + 4),
970 log("Creating berry bush...");
971 createObjectGroupsDeprecated(
972 new SimpleGroup([new SimpleObject(oFruitBush, 5, 7, 0, 4)], true, clFood),
974 [avoidClasses(clWater, 0, clForest, 0, clPlayer, 8, clHill, 1, clFood, 20), stayClasses(clLand, 2)],
975 randIntInclusive(1, 4) * numPlayers + 2,
979 log("Creating sheep...");
980 createObjectGroupsDeprecated(
981 new SimpleGroup([new SimpleObject(oSecondaryHuntableAnimal, 2, 3, 0, 2)], true, clFood),
983 [avoidClasses(clWater, 0, clForest, 0, clPlayer, 8, clHill, 1, clFood, 20), stayClasses(clLand, 2)],
984 randIntInclusive(numPlayers + 3, 5 * numPlayers + 4),
987 log("Creating fish...");
988 createObjectGroupsDeprecated(
989 new SimpleGroup([new SimpleObject(oFish, 2, 3, 0, 2)], true, clFood),
991 avoidClasses(clLand, 4, clForest, 0, clPlayer, 0, clHill, 0, clFood, 20),
992 randIntInclusive(15, 40) * numPlayers,
996 log("Creating straggler trees...");
997 types = [g_Gaia.tree1, g_Gaia.tree2, g_Gaia.tree3, g_Gaia.tree4];
999 num = Math.floor(numStragglers / types.length);
1000 for (let type of types)
1001 createObjectGroupsDeprecated(
1002 new SimpleGroup([new SimpleObject(type, 1, 1, 0, 3)], true, clForest),
1004 [avoidClasses(clWater, 1, clForest, 1, clHill, 1, clPlayer, 0, clMetal, 6, clRock, 6, clBaseResource, 6), stayClasses(clLand, 4)],
1007 let planetm = currentBiome() == "tropic" ? 8 : 1;
1009 log("Creating small grass tufts...");
1010 createObjectGroupsDeprecated(
1011 new SimpleGroup([new SimpleObject(aGrassShort, 1, 2, 0, 1, -Math.PI / 8, Math.PI / 8)]),
1013 [avoidClasses(clWater, 2, clHill, 2, clPlayer, 2, clDirt, 0), stayClasses(clLand, 3)],
1014 planetm * scaleByMapSize(13, 200));
1015 RMS.SetProgress(90);
1017 log("Creating large grass tufts...");
1018 createObjectGroupsDeprecated(
1019 new SimpleGroup([new SimpleObject(aGrass, 2, 4, 0, 1.8, -Math.PI / 8, Math.PI / 8), new SimpleObject(aGrassShort, 3, 6, 1.2, 2.5, -Math.PI / 8, Math.PI / 8)]),
1021 [avoidClasses(clWater, 3, clHill, 2, clPlayer, 2, clDirt, 1, clForest, 0), stayClasses(clLand, 3)],
1022 planetm * scaleByMapSize(13, 200));
1023 RMS.SetProgress(95);
1025 log("Creating shallow flora...");
1026 createObjectGroupsDeprecated(
1027 new SimpleGroup([new SimpleObject(aLillies, 1, 2, 0, 2), new SimpleObject(aReeds, 2, 4, 0, 2)]),
1029 stayClasses(clShallow, 1),
1030 60 * scaleByMapSize(13, 200),
1033 log("Creating bushes...");
1034 createObjectGroupsDeprecated(
1035 new SimpleGroup([new SimpleObject(aBushMedium, 1, 2, 0, 2), new SimpleObject(aBushSmall, 2, 4, 0, 2)]),
1037 [avoidClasses(clWater, 1, clHill, 1, clPlayer, 1, clDirt, 1), stayClasses(clLand, 3)],
1038 planetm * scaleByMapSize(13, 200),
1041 setSkySet(pickRandom(["cirrus", "cumulus", "sunny", "sunny 1", "mountainous", "stratus"]));
1042 setSunRotation(randFloat(0, 2 * Math.PI));
1043 setSunElevation(Math.PI * randFloat(1/5, 1/3));
1046 function createUnknownPlayerBases()
1048 for (var i = 0; i < numPlayers; ++i)
1050 var id = playerIDs[i];
1051 log("Creating base for player " + id + "...");
1053 var radius = scaleByMapSize(17,29);
1054 var shoreRadius = 4;
1057 var hillSize = PI * radius * radius;
1058 // get the x and z in tiles
1059 var fx = fractionToTiles(playerX[i]);
1060 var fz = fractionToTiles(playerZ[i]);
1064 placeCivDefaultEntities(fx, fz, id, { "iberWall": g_IberianWalls });
1066 placeDefaultChicken(fx, fz, clBaseResource);
1068 // create berry bushes
1069 var bbAngle = randFloat(0, TWO_PI);
1071 var bbX = round(fx + bbDist * cos(bbAngle));
1072 var bbZ = round(fz + bbDist * sin(bbAngle));
1073 var group = new SimpleGroup(
1074 [new SimpleObject(oFruitBush, 5,5, 0,3)],
1075 true, clBaseResource, bbX, bbZ
1077 createObjectGroup(group, 0);
1079 if (g_StartingTreasures)
1082 var bbAngle = randFloat(0, TWO_PI);
1084 var bbX = round(fx + bbDist * cos(bbAngle));
1085 var bbZ = round(fz + bbDist * sin(bbAngle));
1086 group = new SimpleGroup(
1087 [new SimpleObject(oWoodTreasure, 14, 14, 0, 3)],
1088 true, clBaseResource, bbX, bbZ
1090 createObjectGroup(group, 0);
1093 // create metal mine
1094 var mAngle = bbAngle;
1095 while (abs(mAngle - bbAngle) < PI/3)
1097 mAngle = randFloat(0, TWO_PI);
1100 var mX = round(fx + mDist * cos(mAngle));
1101 var mZ = round(fz + mDist * sin(mAngle));
1102 group = new SimpleGroup(
1103 [new SimpleObject(oMetalLarge, 1,1, 0,0)],
1104 true, clBaseResource, mX, mZ
1106 createObjectGroup(group, 0);
1108 // create stone mines
1109 mAngle += randFloat(PI/8, PI/4);
1110 mX = round(fx + mDist * cos(mAngle));
1111 mZ = round(fz + mDist * sin(mAngle));
1112 group = new SimpleGroup(
1113 [new SimpleObject(oStoneLarge, 1,1, 0,2)],
1114 true, clBaseResource, mX, mZ
1116 createObjectGroup(group, 0);
1117 var hillSize = PI * radius * radius;
1118 // create starting trees
1119 var num = floor(hillSize / 100);
1120 var tAngle = randFloat(-PI/3, 4*PI/3);
1121 var tDist = randFloat(11, 13);
1122 var tX = round(fx + tDist * cos(tAngle));
1123 var tZ = round(fz + tDist * sin(tAngle));
1124 group = new SimpleGroup(
1125 [new SimpleObject(oTree1, num, num, 0,5)],
1126 false, clBaseResource, tX, tZ
1128 createObjectGroup(group, 0, avoidClasses(clBaseResource,2));
1130 placeDefaultDecoratives(fx, fz, aGrassShort, clBaseResource, radius);
1132 // create the city patch
1133 var cityRadius = radius/3;
1134 var placer = new ClumpPlacer(PI*cityRadius*cityRadius, 0.6, 0.3, 10, ix, iz);
1135 var painter = new LayeredPainter([tRoadWild, tRoad], [1]);
1136 createArea(placer, [painter, paintClass(clPlayer)], null);