1 Engine.LoadLibrary("rmgen");
5 var clPlayer = createTileClass();
6 var clPath = createTileClass();
7 var clHill = createTileClass();
8 var clForest = createTileClass();
9 var clBaseResource = createTileClass();
11 var templateStone = "gaia/geology_stone_temperate";
12 var templateStoneMine = "gaia/geology_stonemine_temperate_quarry";
13 var templateMetalMine = "gaia/geology_metal_temperate_slabs";
15 var terrainWood = ['temp_grass_mossy|gaia/flora_tree_oak', 'temp_forestfloor_pine|gaia/flora_tree_pine', 'temp_mud_plants|gaia/flora_tree_dead',
16 'temp_plants_bog|gaia/flora_tree_oak_large', "temp_dirt_gravel_plants|gaia/flora_tree_aleppo_pine", 'temp_forestfloor_autumn|gaia/flora_tree_carob']; //'temp_forestfloor_autumn|gaia/flora_tree_fig'
17 var terrainWoodBorder = ['temp_grass_plants|gaia/flora_tree_euro_beech', 'temp_grass_mossy|gaia/flora_tree_poplar', 'temp_grass_mossy|gaia/flora_tree_poplar_lombardy',
18 'temp_grass_long|gaia/flora_bush_temperate', 'temp_mud_plants|gaia/flora_bush_temperate', 'temp_mud_plants|gaia/flora_bush_badlands',
19 'temp_grass_long|gaia/flora_tree_apple', 'temp_grass_clovers|gaia/flora_bush_berry', 'temp_grass_clovers_2|gaia/flora_bush_grapes',
20 'temp_grass_plants|gaia/fauna_deer', "temp_grass_long_b|gaia/fauna_rabbit", "temp_grass_plants"];
21 var terrainBase = ['temp_dirt_gravel', 'temp_grass_b', 'temp_dirt_gravel', 'temp_grass_b', 'temp_dirt_gravel', 'temp_grass_b', 'temp_dirt_gravel', 'temp_grass_b',
22 'temp_dirt_gravel', 'temp_grass_b', 'temp_dirt_gravel', 'temp_grass_b', 'temp_dirt_gravel', 'temp_grass_b', 'temp_dirt_gravel', 'temp_grass_b',
23 'temp_dirt_gravel', 'temp_grass_b', 'temp_dirt_gravel', 'temp_grass_b', 'temp_dirt_gravel', 'temp_grass_b', 'temp_dirt_gravel', 'temp_grass_b',
24 'temp_dirt_gravel', 'temp_grass_b', 'temp_dirt_gravel', 'temp_grass_b', 'temp_dirt_gravel', 'temp_grass_b', 'temp_dirt_gravel', 'temp_grass_b',
25 'temp_grass_b|gaia/fauna_pig', 'temp_dirt_gravel|gaia/fauna_chicken'];
26 var terrainBaseBorder = ["temp_grass_b", "temp_grass_b", "temp_grass", "temp_grass_c", "temp_grass_mossy"];
27 var terrainBaseCenter = ['temp_dirt_gravel', 'temp_dirt_gravel', 'temp_grass_b'];
28 var terrainPath = ['temp_road', "temp_road_overgrown", 'temp_grass_b'];
29 var terrainHill = ["temp_highlands", "temp_highlands", "temp_highlands", "temp_dirt_gravel_b", "temp_cliff_a"];
30 var terrainHillBorder = ["temp_highlands", "temp_highlands", "temp_highlands", "temp_dirt_gravel_b", "temp_dirt_gravel_plants",
31 "temp_highlands", "temp_highlands", "temp_highlands", "temp_dirt_gravel_b", "temp_dirt_gravel_plants",
32 "temp_highlands", "temp_highlands", "temp_highlands", "temp_cliff_b", "temp_dirt_gravel_plants",
33 "temp_highlands", "temp_highlands", "temp_highlands", "temp_cliff_b", "temp_dirt_gravel_plants",
34 "temp_highlands|gaia/fauna_goat"];
36 var mapSize = getMapSize();
37 var mapArea = getMapArea();
38 var mapRadius = mapSize/2;
39 var mapCenterX = mapRadius;
40 var mapCenterZ = mapRadius;
42 var numPlayers = getNumPlayers();
44 var minPlayerRadius = Math.min(mapRadius - 1.5 * baseRadius, 5/8 * mapRadius);
45 var maxPlayerRadius = Math.min(mapRadius - baseRadius, 3/4 * mapRadius);
46 var playerStartLocX = [];
47 var playerStartLocZ = [];
49 var playerAngleStart = randFloat(0, 2 * Math.PI);
50 var playerAngleAddAvrg = 2 * Math.PI / numPlayers;
51 var playerAngleMaxOff = playerAngleAddAvrg/4;
54 var templateEC = "other/unfinished_greek_temple";
55 var radiusEC = Math.max(mapRadius/8, baseRadius/2);
58 var pathSucsessRadius = baseRadius/2;
59 var pathAngleOff = Math.PI / 2;
60 var pathWidth = 5; // This is not really the path's sickness in tiles but the number of tiles in the clumbs of the path
62 // Setup additional resources
63 var resourceRadius = 2*mapRadius/3; // 3*mapRadius/8;
64 var resourcePerPlayer = [templateStone, templateMetalMine];
67 // For large maps there are memory errors with too many trees. A density of 256*192/mapArea works with 0 players.
68 // Around each player there is an area without trees so with more players the max density can increase a bit.
69 var maxTreeDensity = Math.min(256 * (192 + 8 * numPlayers) / mapArea, 1); // Has to be tweeked but works ok
70 var bushChance = 1/3; // 1 means 50% chance in deepest wood, 0.5 means 25% chance in deepest wood
73 for (var i=0; i < numPlayers; i++)
76 playerAngle[i] = (playerAngleStart + i * playerAngleAddAvrg + randFloat(0, playerAngleMaxOff)) % (2 * Math.PI);
77 playerStartLocX[i] = mapCenterX + Math.round(randFloat(minPlayerRadius, maxPlayerRadius) * Math.cos(playerAngle[i]));
78 playerStartLocZ[i] = mapCenterZ + Math.round(randFloat(minPlayerRadius, maxPlayerRadius) * Math.sin(playerAngle[i]));
80 Engine.SetProgress(10);
83 "PlayerPlacement": [playerIDs, playerStartLocX.map(tilesToFraction), playerStartLocZ.map(tilesToFraction)],
84 "BaseResourceClass": clBaseResource,
85 // player class painted below
87 "radius": 0.8 * baseRadius,
90 new LayeredPainter([terrainBaseBorder, terrainBase, terrainBaseCenter], [baseRadius/4, baseRadius/4]),
94 // Chicken already placed at the base terrain
96 "template": "gaia/flora_bush_grapes",
104 { "template": templateMetalMine },
105 { "template": templateStoneMine }
107 "minAngle": Math.PI / 2,
111 "template": "gaia/flora_tree_oak_large",
115 Engine.SetProgress(10);
118 var doublePaths = true;
121 if (doublePaths == true)
122 var maxI = numPlayers+1;
124 var maxI = numPlayers;
125 for (var i = 0; i < maxI; i++)
127 if (doublePaths == true)
131 for (var j = minJ; j < numPlayers+1; j++)
133 // Setup start and target coordinates
136 var x = playerStartLocX[i];
137 var z = playerStartLocZ[i];
147 var targetX = playerStartLocX[j];
148 var targetZ = playerStartLocZ[j];
152 var targetX = mapCenterX;
153 var targetZ = mapCenterZ;
156 // Prepare path placement
157 var angle = getAngle(x, z, targetX, targetZ);
158 x += Math.round(pathSucsessRadius * Math.cos(angle));
159 z += Math.round(pathSucsessRadius * Math.sin(angle));
160 var targetReached = false;
163 while (targetReached == false && tries < 2*mapSize)
166 new ClumpPlacer(pathWidth, 1, 1, 1, x, z),
168 new TerrainPainter(terrainPath),
169 new ElevationPainter(randFloat(-1, 0)),
172 avoidClasses(clHill, 0, clBaseResource, 4));
174 // Set vars for next loop
175 angle = getAngle(x, z, targetX, targetZ);
176 if (doublePaths == true) // Bended paths
178 x += Math.round(Math.cos(angle + randFloat(-pathAngleOff/2, 3*pathAngleOff/2)));
179 z += Math.round(Math.sin(angle + randFloat(-pathAngleOff/2, 3*pathAngleOff/2)));
181 else // Straight paths
183 x += Math.round(Math.cos(angle + randFloat(-pathAngleOff, pathAngleOff)));
184 z += Math.round(Math.sin(angle + randFloat(-pathAngleOff, pathAngleOff)));
186 if (Math.euclidDistance2D(x, z, targetX, targetZ) < pathSucsessRadius)
187 targetReached = true;
194 Engine.SetProgress(50);
196 // Place expansion resources
197 for (var i=0; i < numPlayers; i++)
199 for (var rIndex = 0; rIndex < resourcePerPlayer.length; rIndex++)
202 var angleDist = (playerAngle[(i+1)%numPlayers] - playerAngle[i] + 2 * Math.PI) % (2 * Math.PI);
204 var angleDist = 2 * Math.PI;
206 var placeX = Math.round(mapCenterX + resourceRadius * Math.cos(playerAngle[i] + (rIndex+1)*angleDist/(resourcePerPlayer.length+1)));
207 var placeZ = Math.round(mapCenterX + resourceRadius * Math.sin(playerAngle[i] + (rIndex+1)*angleDist/(resourcePerPlayer.length+1)));
209 placeObject(placeX, placeZ, resourcePerPlayer[rIndex], 0, randFloat(0, 2 * Math.PI));
212 new ClumpPlacer(40, 1/2, 1/8, 1, placeX, placeZ),
214 new LayeredPainter([terrainHillBorder, terrainHill], [1]),
215 new ElevationPainter(randFloat(1, 2)),
221 Engine.SetProgress(60);
224 placeObject(mapCenterX, mapCenterZ, templateEC, 0, randFloat(0, 2 * Math.PI));
225 addToClass(mapCenterX, mapCenterZ, clBaseResource);
227 new ClumpPlacer(Math.square(radiusEC), 1/2, 1/8, 1, mapCenterX, mapCenterZ),
229 new LayeredPainter([terrainHillBorder, terrainHill], [radiusEC/4]),
230 new ElevationPainter(randFloat(1, 2)),
234 // Woods and general hight map
235 for (var x = 0; x < mapSize; x++)
237 for (var z = 0;z < mapSize;z++)
239 // The 0.5 is a correction for the entities placed on the center of tiles
240 var radius = Math.euclidDistance2D(x + 0.5, z + 0.5, mapCenterX, mapCenterZ);
241 var minDistToSL = mapSize;
242 for (var i=0; i < numPlayers; i++)
243 minDistToSL = Math.min(minDistToSL, Math.euclidDistance2D(x, z, playerStartLocX[i], playerStartLocZ[i]));
246 var tDensFactSL = Math.max(Math.min((minDistToSL - baseRadius) / baseRadius, 1), 0);
247 var tDensFactRad = Math.abs((resourceRadius - radius) / resourceRadius);
248 var tDensFactEC = Math.max(Math.min((radius - radiusEC) / radiusEC, 1), 0);
249 var tDensActual = maxTreeDensity * tDensFactSL * tDensFactRad * tDensFactEC;
251 if (randBool(tDensActual) && g_Map.validT(x, z))
253 let border = tDensActual < randFloat(0, bushChance * maxTreeDensity);
255 new ClumpPlacer(1, 1, 1, 1, x, z),
257 new TerrainPainter(border ? terrainWoodBorder : terrainWood),
258 new ElevationPainter(randFloat(0, 1)),
261 avoidClasses(clPath, 1, clHill, border ? 0 : 1));
265 var hVarMiddleHill = mapSize / 64 * (1 + Math.cos(3/2 * Math.PI * radius / mapRadius));
266 var hVarHills = 5 * (1 + Math.sin(x / 10) * Math.sin(z / 10));
267 setHeight(x, z, getHeight(x, z) + hVarMiddleHill + hVarHills + 1);
270 Engine.SetProgress(95);
272 placePlayersNomad(clPlayer, avoidClasses(clForest, 1, clBaseResource, 4));