1 RMS.LoadLibrary("rmgen");
3 TILE_CENTERED_HEIGHT_MAP = true;
8 var tPrimary = ["alpine_dirt_grass_50"];
9 var tForestFloor = "alpine_forrestfloor";
10 var tCliff = ["alpine_cliff_a", "alpine_cliff_b", "alpine_cliff_c"];
11 var tSecondary = "alpine_grass_rocky";
12 var tHalfSnow = ["alpine_grass_snow_50", "alpine_dirt_snow"];
13 var tSnowLimited = ["alpine_snow_rocky"];
14 var tDirt = "alpine_dirt";
15 var tRoad = "new_alpine_citytile";
16 var tRoadWild = "new_alpine_citytile";
17 var tShore = "alpine_shore_rocks_grass_50";
18 var tWater = "alpine_shore_rocks";
21 var oPine = "gaia/flora_tree_pine";
22 var oBerryBush = "gaia/flora_bush_berry";
23 var oDeer = "gaia/fauna_deer";
24 var oRabbit = "gaia/fauna_rabbit";
25 var oStoneLarge = "gaia/geology_stonemine_alpine_quarry";
26 var oStoneSmall = "gaia/geology_stone_alpine_a";
27 var oMetalLarge = "gaia/geology_metal_alpine_slabs";
30 var aGrass = "actor|props/flora/grass_soft_small_tall.xml";
31 var aGrassShort = "actor|props/flora/grass_soft_large.xml";
32 var aRockLarge = "actor|geology/stone_granite_med.xml";
33 var aRockMedium = "actor|geology/stone_granite_med.xml";
34 var aBushMedium = "actor|props/flora/bush_medit_me.xml";
35 var aBushSmall = "actor|props/flora/bush_medit_sm.xml";
40 var tPrimary = ["alpine_snow_a", "alpine_snow_b"];
41 var tForestFloor = "alpine_forrestfloor_snow";
42 var tCliff = ["alpine_cliff_snow"];
43 var tSecondary = "alpine_grass_snow_50";
44 var tHalfSnow = ["alpine_grass_snow_50", "alpine_dirt_snow"];
45 var tSnowLimited = ["alpine_snow_a", "alpine_snow_b"];
46 var tDirt = "alpine_dirt";
47 var tRoad = "new_alpine_citytile";
48 var tRoadWild = "new_alpine_citytile";
49 var tShore = "alpine_shore_rocks_icy";
50 var tWater = "alpine_shore_rocks";
53 var oPine = "gaia/flora_tree_pine_w";
54 var oBerryBush = "gaia/flora_bush_berry";
55 var oDeer = "gaia/fauna_deer";
56 var oRabbit = "gaia/fauna_rabbit";
57 var oStoneLarge = "gaia/geology_stonemine_alpine_quarry";
58 var oStoneSmall = "gaia/geology_stone_alpine_a";
59 var oMetalLarge = "gaia/geology_metal_alpine_slabs";
62 var aGrass = "actor|props/flora/grass_soft_dry_small_tall.xml";
63 var aGrassShort = "actor|props/flora/grass_soft_dry_large.xml";
64 var aRockLarge = "actor|geology/stone_granite_med.xml";
65 var aRockMedium = "actor|geology/stone_granite_med.xml";
66 var aBushMedium = "actor|props/flora/bush_medit_me_dry.xml";
67 var aBushSmall = "actor|props/flora/bush_medit_sm_dry.xml";
70 const pForest = [tForestFloor + TERRAIN_SEPARATOR + oPine, tForestFloor];
74 const numPlayers = getNumPlayers();
75 const mapSize = getMapSize();
76 const mapArea = mapSize*mapSize;
78 var clPlayer = createTileClass();
79 var clHill = createTileClass();
80 var clForest = createTileClass();
81 var clDirt = createTileClass();
82 var clRock = createTileClass();
83 var clMetal = createTileClass();
84 var clFood = createTileClass();
85 var clBaseResource = createTileClass();
86 var clSettlement = createTileClass();
88 initTerrain(tPrimary);
90 var [playerIDs, playerX, playerZ, playerAngle, startAngle] = radialPlayerPlacement();
92 for (var i = 0; i < numPlayers; i++)
94 var id = playerIDs[i];
95 log("Creating base for player " + id + "...");
97 var radius = scaleByMapSize(15,25);
101 // get the x and z in tiles
102 var fx = fractionToTiles(playerX[i]);
103 var fz = fractionToTiles(playerZ[i]);
106 addCivicCenterAreaToClass(ix, iz, clPlayer);
108 // create the city patch
109 var cityRadius = radius/3;
110 placer = new ClumpPlacer(PI*cityRadius*cityRadius, 0.6, 0.3, 10, ix, iz);
111 var painter = new LayeredPainter([tRoadWild, tRoad], [1]);
112 createArea(placer, painter, null);
114 placeCivDefaultEntities(fx, fz, id);
116 placeDefaultChicken(fx, fz, clBaseResource);
118 // create berry bushes
119 var bbAngle = randFloat(0, TWO_PI);
121 var bbX = round(fx + bbDist * cos(bbAngle));
122 var bbZ = round(fz + bbDist * sin(bbAngle));
123 var group = new SimpleGroup(
124 [new SimpleObject(oBerryBush, 5,5, 0,3)],
125 true, clBaseResource, bbX, bbZ
127 createObjectGroup(group, 0);
130 var mAngle = bbAngle;
131 while(abs(mAngle - bbAngle) < PI/3)
132 mAngle = randFloat(0, TWO_PI);
135 var mX = round(fx + mDist * cos(mAngle));
136 var mZ = round(fz + mDist * sin(mAngle));
137 group = new SimpleGroup(
138 [new SimpleObject(oMetalLarge, 1,1, 0,0)],
139 true, clBaseResource, mX, mZ
141 createObjectGroup(group, 0);
143 // create stone mines
144 mAngle += randFloat(PI/8, PI/4);
145 mX = round(fx + mDist * cos(mAngle));
146 mZ = round(fz + mDist * sin(mAngle));
147 group = new SimpleGroup(
148 [new SimpleObject(oStoneLarge, 1,1, 0,2)],
149 true, clBaseResource, mX, mZ
151 createObjectGroup(group, 0);
152 var hillSize = PI * radius * radius;
153 // create starting trees
154 var num = floor(hillSize / 100);
155 var tAngle = randFloat(-PI/3, 4*PI/3);
156 var tDist = randFloat(11, 13);
157 var tX = round(fx + tDist * cos(tAngle));
158 var tZ = round(fz + tDist * sin(tAngle));
159 group = new SimpleGroup(
160 [new SimpleObject(oPine, num, num, 0,5)],
161 false, clBaseResource, tX, tZ
163 createObjectGroup(group, 0, avoidClasses(clBaseResource,2));
165 placeDefaultDecoratives(fx, fz, aGrassShort, clBaseResource, radius);
169 //place the mountains
172 var edgesConncetedToPoints = [];
174 //we want the points near the start locations be the first ones. hence we use two "for" blocks
175 for (var i = 0; i < numPlayers; ++i)
177 playerAngle[i] = startAngle + (i+0.5)*TWO_PI/numPlayers;
178 points.push([round(fractionToTiles(0.5 + 0.49 * cos(playerAngle[i]))), round(fractionToTiles(0.5 + 0.49 * sin(playerAngle[i])))]);
181 //the order of the other points doesn't matter
182 for (var i = 0; i < numPlayers; ++i)
184 playerAngle[i] = startAngle + (i+0.7)*TWO_PI/numPlayers;
185 points.push([round(fractionToTiles(0.5 + 0.34 * cos(playerAngle[i]))), round(fractionToTiles(0.5 + 0.34 * sin(playerAngle[i])))]);
186 playerAngle[i] = startAngle + (i+0.3)*TWO_PI/numPlayers;
187 points.push([round(fractionToTiles(0.5 + 0.34 * cos(playerAngle[i]))), round(fractionToTiles(0.5 + 0.34 * sin(playerAngle[i])))]);
188 playerAngle[i] = startAngle + (i+0.5)*TWO_PI/numPlayers;
189 points.push([round(fractionToTiles(0.5 + 0.18 * cos(playerAngle[i]))), round(fractionToTiles(0.5 + 0.18 * sin(playerAngle[i])))]);
192 //add the center of the map
193 points.push([round(fractionToTiles(0.5)), round(fractionToTiles(0.5))]);
195 var numPoints = numPlayers * 4 + 1;
197 for (var i = 0; i < numPoints; ++i)
198 edgesConncetedToPoints.push(0);
200 //we are making a planar graph where every edge is a straight line.
201 var possibleEdges = [];
203 //add all of the possible combinations
204 for (var i = 0; i < numPoints; ++i)
205 for (var j = numPlayers; j < numPoints; ++j)
207 possibleEdges.push([i,j]);
209 //we need a matrix so that we can prevent the mountain ranges from bocking a player
211 for (var i = 0; i < numPoints; ++i)
214 for (var j = 0; j < numPoints; ++j)
215 matrix[i].push(i < numPlayers && j < numPlayers && i != j && (i == j - 1 || i == j + 1))
218 //find and place the edges
219 while (possibleEdges.length)
221 var index = randIntExclusive(0, possibleEdges.length);
223 //ensure that a point is connected to a maximum of 3 others
224 if (edgesConncetedToPoints[possibleEdges[index][0]] > 2 || edgesConncetedToPoints[possibleEdges[index][1]] > 2)
226 possibleEdges.splice(index,1);
230 //we don't want ranges that are longer than half of the map's size
231 if ((((points[possibleEdges[index][0]][0] - points[possibleEdges[index][1]][0]) *
232 (points[possibleEdges[index][0]][0] - points[possibleEdges[index][1]][0])) +
233 ((points[possibleEdges[index][0]][1] - points[possibleEdges[index][1]][1]) *
234 (points[possibleEdges[index][0]][1] - points[possibleEdges[index][1]][1]))) >
237 possibleEdges.splice(index,1);
242 var q = [possibleEdges[index][0]];
244 matrix[possibleEdges[index][0]][possibleEdges[index][1]] = true;
245 matrix[possibleEdges[index][1]][possibleEdges[index][0]] = true;
246 var selected, accept = true, tree = [], backtree = [];
249 selected = q.shift();
250 if (tree.indexOf(selected) == -1)
256 for (var i = 0; i < numPoints; ++i)
257 if (matrix[selected][i])
259 if (i == backtree[tree.lastIndexOf(selected)])
262 if (tree.indexOf(i) == -1)
265 backtree.push(selected);
271 matrix[possibleEdges[index][0]][possibleEdges[index][1]] = false;
272 matrix[possibleEdges[index][1]][possibleEdges[index][0]] = false;
280 possibleEdges.splice(index,1);
284 var ix = points[possibleEdges[index][0]][0];
285 var iz = points[possibleEdges[index][0]][1];
286 var ix2 = points[possibleEdges[index][1]][0];
287 var iz2 = points[possibleEdges[index][1]][1];
288 var placer = new PathPlacer(ix, iz, ix2, iz2, scaleByMapSize(9,15), 0.4, 3*(scaleByMapSize(1,4)), 0.1, 0.1, 0.1);
289 var terrainPainter = new LayeredPainter(
290 [tCliff, tPrimary], // terrains
293 var elevationPainter = new SmoothElevationPainter(
294 ELEVATION_SET, // type
298 accept = createArea(placer, [terrainPainter, elevationPainter, paintClass(clHill)], avoidClasses(clPlayer, 20));
302 matrix[possibleEdges[index][0]][possibleEdges[index][1]] = false;
303 matrix[possibleEdges[index][1]][possibleEdges[index][0]] = false;
304 possibleEdges.splice(index,1);
309 placer = new ClumpPlacer(floor(PI*scaleByMapSize(9,15)*scaleByMapSize(9,15)/4), 0.95, 0.6, 10, ix, iz);
310 var terrainPainter = new LayeredPainter(
311 [tCliff, tPrimary], // terrains
314 var elevationPainter = new SmoothElevationPainter(
315 ELEVATION_SET, // type
319 createArea(placer, [terrainPainter, elevationPainter, paintClass(clHill)], avoidClasses(clPlayer, 5));
321 placer = new ClumpPlacer(floor(PI*scaleByMapSize(9,15)*scaleByMapSize(9,15)/4), 0.95, 0.6, 10, ix2, iz2);
322 var terrainPainter = new LayeredPainter(
323 [tCliff, tPrimary], // terrains
326 var elevationPainter = new SmoothElevationPainter(
327 ELEVATION_SET, // type
331 createArea(placer, [terrainPainter, elevationPainter, paintClass(clHill)], avoidClasses(clPlayer, 5));
334 for (var i = 0; i < possibleEdges.length; ++i)
336 if (possibleEdges[index][0] != possibleEdges[i][0] && possibleEdges[index][1] != possibleEdges[i][0] &&
337 possibleEdges[index][0] != possibleEdges[i][1] && possibleEdges[index][1] != possibleEdges[i][1])
340 if (checkIfIntersect (points[possibleEdges[index][0]][0], points[possibleEdges[index][0]][1],
341 points[possibleEdges[index][1]][0], points[possibleEdges[index][1]][1], points[possibleEdges[i][0]][0],
342 points[possibleEdges[i][0]][1], points[possibleEdges[i][1]][0], points[possibleEdges[i][1]][1], scaleByMapSize(9,15) + scaleByMapSize(10,15)))
344 possibleEdges.splice(i,1);
350 else if (((possibleEdges[index][0] == possibleEdges[i][0] && possibleEdges[index][1] != possibleEdges[i][1]) ||
351 (possibleEdges[index][1] == possibleEdges[i][0] && possibleEdges[index][0] != possibleEdges[i][1])) &&
352 distanceOfPointFromLine(points[possibleEdges[index][0]][0],points[possibleEdges[index][0]][1],
353 points[possibleEdges[index][1]][0], points[possibleEdges[index][1]][1],points[possibleEdges[i][1]][0], points[possibleEdges[i][1]][1])
354 < scaleByMapSize(9,15) + scaleByMapSize(10,15))
356 possibleEdges.splice(i,1);
361 else if (((possibleEdges[index][0] == possibleEdges[i][1] && possibleEdges[index][1] != possibleEdges[i][0]) ||
362 (possibleEdges[index][1] == possibleEdges[i][1] && possibleEdges[index][0] != possibleEdges[i][0])) &&
363 distanceOfPointFromLine(points[possibleEdges[index][0]][0],points[possibleEdges[index][0]][1],
364 points[possibleEdges[index][1]][0], points[possibleEdges[index][1]][1],points[possibleEdges[i][0]][0], points[possibleEdges[i][0]][1])
365 < scaleByMapSize(9,15) + scaleByMapSize(10,15))
367 possibleEdges.splice(i,1);
375 edgesConncetedToPoints[possibleEdges[index][0]] += 1;
376 edgesConncetedToPoints[possibleEdges[index][1]] += 1;
378 possibleEdges.splice(index,1);
381 paintTerrainBasedOnHeight(3.1, 29, 0, tCliff);
382 paintTerrainBasedOnHeight(29, 30, 3, tSnowLimited);
384 log("Creating bumps...");
385 placer = new ClumpPlacer(scaleByMapSize(20, 50), 0.3, 0.06, 1);
386 painter = new SmoothElevationPainter(ELEVATION_MODIFY, 2, 2);
390 avoidClasses(clPlayer, 10),
391 scaleByMapSize(100, 200)
395 log("Creating hills...");
396 placer = new ClumpPlacer(scaleByMapSize(40, 150), 0.2, 0.1, 1);
397 var terrainPainter = new LayeredPainter(
398 [tCliff, tSnowLimited], // terrains
401 var elevationPainter = new SmoothElevationPainter(ELEVATION_SET, 30, 2);
404 [terrainPainter, elevationPainter, paintClass(clHill)],
405 avoidClasses(clPlayer, 20, clHill, 14),
406 scaleByMapSize(10, 80) * numPlayers
410 // calculate desired number of trees for map (based on size)
412 var MAX_TREES = 3000;
415 var totalTrees = scaleByMapSize(MIN_TREES, MAX_TREES);
416 var numForest = totalTrees * P_FOREST;
417 var numStragglers = totalTrees * (1.0 - P_FOREST);
419 log("Creating forests...");
421 [[tForestFloor, tPrimary, pForest], [tForestFloor, pForest]]
424 var size = numForest / (scaleByMapSize(2,8) * numPlayers);
426 var num = floor(size / types.length);
427 for (var i = 0; i < types.length; ++i)
429 placer = new ClumpPlacer(numForest / num, 0.1, 0.1, 1);
430 painter = new LayeredPainter(
431 types[i], // terrains
436 [painter, paintClass(clForest)],
437 avoidClasses(clPlayer, 12, clForest, 10, clHill, 0),
443 log("Creating dirt patches...");
444 var sizes = [scaleByMapSize(3, 48), scaleByMapSize(5, 84), scaleByMapSize(8, 128)];
445 for (var i = 0; i < sizes.length; i++)
447 placer = new ClumpPlacer(sizes[i], 0.3, 0.06, 0.5);
448 painter = new LayeredPainter(
449 [[tDirt,tHalfSnow], [tHalfSnow,tSnowLimited]], // terrains
454 [painter, paintClass(clDirt)],
455 avoidClasses(clForest, 0, clHill, 0, clDirt, 5, clPlayer, 12),
456 scaleByMapSize(15, 45)
460 log("Creating grass patches...");
461 var sizes = [scaleByMapSize(2, 32), scaleByMapSize(3, 48), scaleByMapSize(5, 80)];
462 for (var i = 0; i < sizes.length; i++)
464 placer = new ClumpPlacer(sizes[i], 0.3, 0.06, 0.5);
465 painter = new TerrainPainter(tSecondary);
469 avoidClasses(clForest, 0, clHill, 0, clDirt, 5, clPlayer, 12),
470 scaleByMapSize(15, 45)
475 log("Creating stone mines...");
476 group = new SimpleGroup([new SimpleObject(oStoneSmall, 0,2, 0,4), new SimpleObject(oStoneLarge, 1,1, 0,4)], true, clRock);
477 createObjectGroupsDeprecated(group, 0,
478 avoidClasses(clForest, 1, clPlayer, 20, clRock, 10, clHill, 1),
479 scaleByMapSize(4,16), 100
482 log("Creating small stone mines...");
483 group = new SimpleGroup([new SimpleObject(oStoneSmall, 2,5, 1,3)], true, clRock);
484 createObjectGroupsDeprecated(group, 0,
485 avoidClasses(clForest, 1, clPlayer, 20, clRock, 10, clHill, 1),
486 scaleByMapSize(4,16), 100
489 log("Creating metal mines...");
490 group = new SimpleGroup([new SimpleObject(oMetalLarge, 1,1, 0,4)], true, clMetal);
491 createObjectGroupsDeprecated(group, 0,
492 avoidClasses(clForest, 1, clPlayer, 20, clMetal, 10, clRock, 5, clHill, 1),
493 scaleByMapSize(4,16), 100
497 log("Creating small decorative rocks...");
498 group = new SimpleGroup(
499 [new SimpleObject(aRockMedium, 1,3, 0,1)],
502 createObjectGroupsDeprecated(
504 avoidClasses(clForest, 0, clPlayer, 0, clHill, 0),
505 scaleByMapSize(16, 262), 50
508 log("Creating large decorative rocks...");
509 group = new SimpleGroup(
510 [new SimpleObject(aRockLarge, 1,2, 0,1), new SimpleObject(aRockMedium, 1,3, 0,2)],
513 createObjectGroupsDeprecated(
515 avoidClasses(clForest, 0, clPlayer, 0, clHill, 0),
516 scaleByMapSize(8, 131), 50
520 log("Creating deer...");
521 group = new SimpleGroup(
522 [new SimpleObject(oDeer, 5,7, 0,4)],
525 createObjectGroupsDeprecated(group, 0,
526 avoidClasses(clForest, 0, clPlayer, 10, clHill, 1, clFood, 20),
530 log("Creating berry bush...");
531 group = new SimpleGroup(
532 [new SimpleObject(oBerryBush, 5,7, 0,4)],
535 createObjectGroupsDeprecated(group, 0,
536 avoidClasses(clForest, 0, clPlayer, 20, clHill, 1, clFood, 10),
537 randIntInclusive(1, 4) * numPlayers + 2, 50
540 log("Creating rabbit...");
541 group = new SimpleGroup(
542 [new SimpleObject(oRabbit, 2,3, 0,2)],
545 createObjectGroupsDeprecated(group, 0,
546 avoidClasses(clForest, 0, clPlayer, 10, clHill, 1, clFood, 20),
551 log("Creating straggler trees...");
552 var types = [oPine, oPine]; // some variation
553 var num = floor(numStragglers / types.length);
554 for (var i = 0; i < types.length; ++i)
556 group = new SimpleGroup(
557 [new SimpleObject(types[i], 1,1, 0,3)],
560 createObjectGroupsDeprecated(group, 0,
561 avoidClasses(clForest, 1, clHill, 1, clPlayer, 12, clMetal, 6, clRock, 6),
566 log("Creating small grass tufts...");
569 group = new SimpleGroup(
570 [new SimpleObject(aGrassShort, 1,2, 0,1, -PI/8,PI/8)]
572 createObjectGroupsDeprecated(group, 0,
573 avoidClasses(clHill, 2, clPlayer, 2, clDirt, 0),
574 planetm * scaleByMapSize(13, 200)
578 log("Creating large grass tufts...");
579 group = new SimpleGroup(
580 [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)]
582 createObjectGroupsDeprecated(group, 0,
583 avoidClasses(clHill, 2, clPlayer, 2, clDirt, 1, clForest, 0),
584 planetm * scaleByMapSize(13, 200)
588 log("Creating bushes...");
589 group = new SimpleGroup(
590 [new SimpleObject(aBushMedium, 1,2, 0,2), new SimpleObject(aBushSmall, 2,4, 0,2)]
592 createObjectGroupsDeprecated(group, 0,
593 avoidClasses(clHill, 1, clPlayer, 1, clDirt, 1),
594 planetm * scaleByMapSize(13, 200), 50
597 setSkySet(pickRandom(["cirrus", "cumulus", "sunny"]));
598 setSunRotation(randFloat(0, TWO_PI));
599 setSunElevation(randFloat(PI/ 5, PI / 3));
600 setWaterColor(0.0, 0.047, 0.286); // dark majestic blue
601 setWaterTint(0.471, 0.776, 0.863); // light blue
602 setWaterMurkiness(0.72);
603 setWaterWaviness(2.0);
604 setWaterType("lake");