1 Engine.LoadLibrary("rmgen");
2 Engine.LoadLibrary("rmgen-common");
4 function* GenerateMap()
6 const tGrass = ["medit_grass_field", "medit_grass_field_b", "temp_grass_c"];
7 const tLushGrass = ["medit_grass_field", "medit_grass_field_a"];
9 const tSteepCliffs = ["temp_cliff_b", "temp_cliff_a"];
10 const tCliffs = ["temp_cliff_b", "medit_cliff_italia", "medit_cliff_italia_grass"];
12 "medit_cliff_italia_grass",
13 "medit_cliff_italia_grass",
18 const tMountain = ["medit_cliff_italia_grass", "medit_cliff_italia"];
20 const tRoad = ["medit_city_tile", "medit_rocks_grass", "medit_grass_field_b"];
21 const tRoadWild = ["medit_rocks_grass", "medit_grass_field_b"];
23 const tShoreBlend = ["medit_sand_wet", "medit_rocks_wet"];
24 const tShore = ["medit_rocks", "medit_sand", "medit_sand"];
25 const tSandTransition = ["medit_sand", "medit_rocks_grass", "medit_rocks_grass", "medit_rocks_grass"];
26 const tVeryDeepWater = ["medit_sea_depths", "medit_sea_coral_deep"];
27 const tDeepWater = ["medit_sea_coral_deep", "tropic_ocean_coral"];
28 const tCreekWater = "medit_sea_coral_plants";
30 const ePine = "gaia/tree/aleppo_pine";
31 const ePalmTall = "gaia/tree/cretan_date_palm_tall";
32 const eFanPalm = "gaia/tree/medit_fan_palm";
33 const eApple = "gaia/fruit/apple";
34 const eBush = "gaia/fruit/berry_01";
35 const eFish = "gaia/fish/generic";
36 const ePig = "gaia/fauna_pig";
37 const eStoneMine = "gaia/rock/mediterranean_large";
38 const eMetalMine = "gaia/ore/mediterranean_large";
40 const aRock = "actor|geology/stone_granite_med.xml";
41 const aLargeRock = "actor|geology/stone_granite_large.xml";
42 const aBushA = "actor|props/flora/bush_medit_sm_lush.xml";
43 const aBushB = "actor|props/flora/bush_medit_me_lush.xml";
44 const aPlantA = "actor|props/flora/plant_medit_artichoke.xml";
45 const aPlantB = "actor|props/flora/grass_tufts_a.xml";
46 const aPlantC = "actor|props/flora/grass_soft_tuft_a.xml";
48 const aStandingStone = "actor|props/special/eyecandy/standing_stones.xml";
50 const heightSeaGround = -8;
51 const heightCreeks = -5;
52 const heightBeaches = -1;
55 const heightOffsetMainRelief = 30;
56 const heightOffsetLevel1 = 9;
57 const heightOffsetLevel2 = 8;
58 const heightOffsetBumps = 2;
59 const heightOffsetAntiBumps = -5;
61 globalThis.g_Map = new RandomMap(heightSeaGround, tVeryDeepWater);
63 const numPlayers = getNumPlayers();
64 const mapSize = g_Map.getSize();
65 const mapCenter = g_Map.getCenter();
67 const clIsland = g_Map.createTileClass();
68 const clCreek = g_Map.createTileClass();
69 const clWater = g_Map.createTileClass();
70 const clCliffs = g_Map.createTileClass();
71 const clForest = g_Map.createTileClass();
72 const clShore = g_Map.createTileClass();
73 const clPlayer = g_Map.createTileClass();
74 const clBaseResource = g_Map.createTileClass();
75 const clPassage = g_Map.createTileClass();
76 const clSettlement = g_Map.createTileClass();
78 const radiusBeach = fractionToTiles(0.57);
79 const radiusCreeks = fractionToTiles(0.52);
80 const radiusIsland = fractionToTiles(0.4);
81 const radiusLevel1 = fractionToTiles(0.35);
82 const radiusPlayer = fractionToTiles(0.25);
83 const radiusLevel2 = fractionToTiles(0.2);
85 const creeksArea = () => randBool() ? randFloat(10, 50) : scaleByMapSize(75, 100) + randFloat(0, 20);
87 const nbCreeks = scaleByMapSize(6, 15);
88 const nbSubIsland = 5;
89 const nbBeaches = scaleByMapSize(2, 5);
90 const nbPassagesLevel1 = scaleByMapSize(4, 8);
91 const nbPassagesLevel2 = scaleByMapSize(2, 4);
93 g_Map.log("Creating Corsica and Sardinia");
94 const swapAngle = randBool() ? Math.PI / 2 : 0;
95 const islandLocations = [new Vector2D(0.05, 0.05), new Vector2D(0.95, 0.95)]
96 .map(v => v.mult(mapSize).rotateAround(-swapAngle, mapCenter));
98 for (let island = 0; island < 2; ++island)
100 g_Map.log("Creating island area");
102 new ClumpPlacer(diskArea(radiusIsland), 1, 0.5, Infinity, islandLocations[island]),
104 new LayeredPainter([tCliffs, tGrass], [2]),
105 new SmoothElevationPainter(ELEVATION_SET, heightMain, 0),
106 new TileClassPainter(clIsland)
109 g_Map.log("Creating subislands");
110 for (let i = 0; i < nbSubIsland + 1; ++i)
112 const angle = Math.PI * (island + i / (nbSubIsland * 2)) + swapAngle;
114 Vector2D.add(islandLocations[island], new Vector2D(radiusIsland, 0).rotate(-angle));
116 new ClumpPlacer(diskArea(fractionToTiles(0.09)), 0.6, 0.03, Infinity, location),
118 new LayeredPainter([tCliffs, tGrass], [2]),
119 new SmoothElevationPainter(ELEVATION_SET, heightMain, 1),
120 new TileClassPainter(clIsland)
124 g_Map.log("Creating creeks");
125 for (let i = 0; i < nbCreeks + 1; ++i)
127 const angle = Math.PI * (island + i * (1 / (nbCreeks * 2))) + swapAngle;
129 Vector2D.add(islandLocations[island], new Vector2D(radiusCreeks, 0).rotate(-angle));
131 new ClumpPlacer(creeksArea(), 0.4, 0.01, Infinity, location),
133 new TerrainPainter(tSteepCliffs),
134 new SmoothElevationPainter(ELEVATION_SET, heightCreeks, 0),
135 new TileClassPainter(clCreek)
139 g_Map.log("Creating beaches");
140 for (let i = 0; i < nbBeaches + 1; ++i)
142 const angle = Math.PI * (island +
143 (i / (nbBeaches * 2.5)) + 1 / (nbBeaches * 6) +
144 randFloat(-1, 1) / (nbBeaches * 7)) +
147 Vector2D.add(islandLocations[island], new Vector2D(radiusIsland, 0).rotate(-angle));
149 Vector2D.add(islandLocations[island], new Vector2D(radiusBeach, 0).rotate(-angle));
152 new ClumpPlacer(130, 0.7, 0.8, Infinity,
153 Vector2D.add(start, Vector2D.mult(end, 3)).div(4)),
154 new SmoothElevationPainter(ELEVATION_SET, heightBeaches, 5));
166 g_Map.log("Creating main relief");
168 new ClumpPlacer(diskArea(radiusIsland), 1, 0.2, Infinity, islandLocations[island]),
169 new SmoothElevationPainter(ELEVATION_MODIFY, heightOffsetMainRelief,
170 fractionToTiles(0.45)));
172 g_Map.log("Creating first level plateau");
174 new ClumpPlacer(diskArea(radiusLevel1), 0.95, 0.02, Infinity, islandLocations[island]),
175 new SmoothElevationPainter(ELEVATION_MODIFY, heightOffsetLevel1, 1));
177 g_Map.log("Creating first level passages");
178 for (let i = 0; i <= nbPassagesLevel1; ++i)
180 const angle = Math.PI * (i / 7 + 1 / 9 + island) + swapAngle;
182 "start": Vector2D.add(islandLocations[island],
183 new Vector2D(radiusLevel1 + 10, 0).rotate(-angle)),
184 "end": Vector2D.add(islandLocations[island],
185 new Vector2D(radiusLevel1 - 4, 0).rotate(-angle)),
189 "tileClass": clPassage
195 g_Map.log("Creating second level plateau");
197 new ClumpPlacer(diskArea(radiusLevel2), 0.98, 0.04, Infinity,
198 islandLocations[island]),
200 new LayeredPainter([tCliffs, tGrass], [2]),
201 new SmoothElevationPainter(ELEVATION_MODIFY, heightOffsetLevel2, 1)
204 g_Map.log("Creating second level passages");
205 for (let i = 0; i < nbPassagesLevel2; ++i)
208 Math.PI * (i / (2 * nbPassagesLevel2) + 1 / (4 * nbPassagesLevel2) + island) +
211 "start": Vector2D.add(islandLocations[island],
212 new Vector2D(radiusLevel2 + 3, 0).rotate(-angle)),
213 "end": Vector2D.add(islandLocations[island],
214 new Vector2D(radiusLevel2 - 6, 0).rotate(-angle)),
218 "tileClass": clPassage
225 g_Map.log("Determining player locations");
226 const playerIDs = sortAllPlayers();
227 const playerPosition = [];
228 const playerAngle = [];
230 for (let island = 0; island < 2; ++island)
232 const playersPerIsland = island == 0 ? Math.ceil(numPlayers / 2) : Math.floor(numPlayers / 2);
234 for (let i = 0; i < playersPerIsland; ++i)
236 playerAngle[p] = Math.PI * ((i + 0.5) / (2 * playersPerIsland) + island) + swapAngle;
237 playerPosition[p] = Vector2D.add(islandLocations[island],
238 new Vector2D(radiusPlayer).rotate(-playerAngle[p]));
239 addCivicCenterAreaToClass(playerPosition[p], clPlayer);
245 "PlayerPlacement": [sortAllPlayers(), playerPosition],
246 "BaseResourceClass": clBaseResource,
247 "baseResourceConstraint": avoidClasses(clPlayer, 2),
250 "outerTerrain": tRoadWild,
251 "innerTerrain": tRoad,
255 new TileClassPainter(clSettlement)
265 { "template": eMetalMine },
266 { "template": eStoneMine }
269 // Sufficient starting trees around, no decoratives
273 g_Map.log("Creating bumps");
275 new ClumpPlacer(70, 0.6, 0.1, Infinity),
276 [new SmoothElevationPainter(ELEVATION_MODIFY, heightOffsetBumps, 3)],
278 stayClasses(clIsland, 2),
279 avoidClasses(clPlayer, 6, clPassage, 2)
281 scaleByMapSize(20, 100),
284 g_Map.log("Creating anti bumps");
286 new ClumpPlacer(120, 0.3, 0.1, Infinity),
287 new SmoothElevationPainter(ELEVATION_MODIFY, heightOffsetAntiBumps, 6),
288 avoidClasses(clPlayer, 6, clPassage, 2, clIsland, 2),
289 scaleByMapSize(20, 100),
292 g_Map.log("Painting water");
293 paintTileClassBasedOnHeight(-Infinity, 0, Elevation_ExcludeMin_ExcludeMax, clWater);
295 g_Map.log("Painting land");
296 for (let mapX = 0; mapX < mapSize; ++mapX)
297 for (let mapZ = 0; mapZ < mapSize; ++mapZ)
299 const position = new Vector2D(mapX, mapZ);
300 const terrain = getCosricaSardiniaTerrain(position);
304 createTerrain(terrain).place(position);
306 if (terrain == tCliffs || terrain == tSteepCliffs)
307 clCliffs.add(position);
310 function getCosricaSardiniaTerrain(position)
312 const isWater = clWater.countMembersInRadius(position, 3);
313 const isShore = clShore.countMembersInRadius(position, 2);
314 const isPassage = clPassage.countMembersInRadius(position, 2);
315 const isSettlement = clSettlement.countMembersInRadius(position, 2);
320 const height = g_Map.getHeight(position);
321 const slope = g_Map.getSlope(position);
323 if (height >= 0.5 && height < 1.5 && isShore)
324 return tSandTransition;
326 // Paint land cliffs and grass
327 if (height >= 1 && !isWater)
333 return height > 25 ? tSteepCliffs : tCliffs;
359 if (height > -10 && slope < 0.75)
367 g_Map.log("Creating mines");
368 for (const mine of [eMetalMine, eStoneMine])
369 createObjectGroupsDeprecated(
372 new SimpleObject(mine, 1, 1, 0, 0),
373 new SimpleObject(aBushB, 1, 1, 2, 2),
374 new SimpleObject(aBushA, 0, 2, 1, 3)
380 stayClasses(clIsland, 1),
388 scaleByMapSize(6, 25),
391 g_Map.log("Creating grass patches");
393 new ClumpPlacer(20, 0.3, 0.06, 0.5),
395 new TerrainPainter(tLushGrass),
396 new TileClassPainter(clForest)
403 scaleByMapSize(10, 40));
405 g_Map.log("Creating forests");
406 createObjectGroupsDeprecated(
409 new SimpleObject(ePine, 3, 6, 1, 3),
410 new SimpleObject(ePalmTall, 1, 3, 1, 3),
411 new SimpleObject(eFanPalm, 0, 2, 0, 2),
412 new SimpleObject(eApple, 0, 1, 1, 2)
418 stayClasses(clIsland, 3),
427 scaleByMapSize(350, 2500),
432 g_Map.log("Creating small decorative rocks");
433 createObjectGroupsDeprecated(
436 new SimpleObject(aRock, 1, 3, 0, 1),
437 new SimpleObject(aStandingStone, 0, 2, 0, 3)
447 scaleByMapSize(16, 262),
450 g_Map.log("Creating large decorative rocks");
451 const rocksGroup = new SimpleGroup(
453 new SimpleObject(aLargeRock, 1, 2, 0, 1),
454 new SimpleObject(aRock, 1, 3, 0, 2)
458 createObjectGroupsDeprecated(
467 scaleByMapSize(8, 131),
470 createObjectGroupsDeprecated(
473 borderClasses(clWater, 5, 10),
474 scaleByMapSize(100, 800),
477 g_Map.log("Creating decorative plants");
478 const plantGroups = [
481 new SimpleObject(aPlantA, 3, 7, 0, 3),
482 new SimpleObject(aPlantB, 3, 6, 0, 3),
483 new SimpleObject(aPlantC, 1, 4, 0, 4)
488 new SimpleObject(aPlantB, 5, 20, 0, 5),
489 new SimpleObject(aPlantC, 4, 10, 0, 4)
493 for (const group of plantGroups)
494 createObjectGroupsDeprecated(
501 scaleByMapSize(100, 600),
506 g_Map.log("Creating animals");
507 createObjectGroupsDeprecated(
508 new SimpleGroup([new SimpleObject(ePig, 2, 4, 0, 3)]),
514 scaleByMapSize(20, 100),
517 g_Map.log("Creating fish");
518 createObjectGroupsDeprecated(
519 new SimpleGroup([new SimpleObject(eFish, 1, 2, 0, 3)]),
522 stayClasses(clWater, 3),
523 avoidClasses(clCreek, 3, clShore, 3)
525 scaleByMapSize(50, 150),
530 placePlayersNomad(clPlayer, avoidClasses(clWater, 4, clForest, 1, clBaseResource, 4, clCliffs, 4));
532 setSkySet(pickRandom(["cumulus", "sunny"]));
534 setSunColor(0.8, 0.66, 0.48);
535 setSunElevation(0.828932);
536 setSunRotation((swapAngle ? 0.288 : 0.788) * Math.PI);
538 setAmbientColor(0.564706, 0.543726, 0.419608);
539 setWaterColor(0.2, 0.294, 0.49);
540 setWaterTint(0.208, 0.659, 0.925);
541 setWaterMurkiness(0.72);
542 setWaterWaviness(2.0);
543 setWaterType("ocean");