Remove rmgen euclidian distance helper function, refs rP20328 / D969.
[0ad.git] / binaries / data / mods / public / maps / random / deep_forest.js
blob4dcbc141562fc9e3f960fd3cce740b31001c9db5
1 RMS.LoadLibrary("rmgen");
3 InitMap();
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";
14 var startingResourcees = ["gaia/flora_tree_oak_large", "gaia/flora_bush_temperate", templateStoneMine,
15         "gaia/flora_bush_grapes", "gaia/flora_tree_apple", "gaia/flora_bush_berry", templateMetalMine, "gaia/flora_bush_badlands"];
17 var terrainWood = ['temp_grass_mossy|gaia/flora_tree_oak', 'temp_forestfloor_pine|gaia/flora_tree_pine', 'temp_mud_plants|gaia/flora_tree_dead',
18         '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'
19 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',
20         'temp_grass_long|gaia/flora_bush_temperate', 'temp_mud_plants|gaia/flora_bush_temperate', 'temp_mud_plants|gaia/flora_bush_badlands',
21         'temp_grass_long|gaia/flora_tree_apple', 'temp_grass_clovers|gaia/flora_bush_berry', 'temp_grass_clovers_2|gaia/flora_bush_grapes',
22         'temp_grass_plants|gaia/fauna_deer', "temp_grass_long_b|gaia/fauna_rabbit", "temp_grass_plants"];
23 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',
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_dirt_gravel', 'temp_grass_b', 'temp_dirt_gravel', 'temp_grass_b', 'temp_dirt_gravel', 'temp_grass_b', 'temp_dirt_gravel', 'temp_grass_b',
26         'temp_dirt_gravel', 'temp_grass_b', 'temp_dirt_gravel', 'temp_grass_b', 'temp_dirt_gravel', 'temp_grass_b', 'temp_dirt_gravel', 'temp_grass_b',
27         'temp_grass_b|gaia/fauna_pig', 'temp_dirt_gravel|gaia/fauna_chicken'];
28 var terrainBaseBorder = ["temp_grass_b", "temp_grass_b", "temp_grass", "temp_grass_c", "temp_grass_mossy"];
29 var terrainBaseCenter = ['temp_dirt_gravel', 'temp_dirt_gravel', 'temp_grass_b'];
30 var terrainPath = ['temp_road', "temp_road_overgrown", 'temp_grass_b'];
31 var terrainHill = ["temp_highlands", "temp_highlands", "temp_highlands", "temp_dirt_gravel_b", "temp_cliff_a"];
32 var terrainHillBorder = ["temp_highlands", "temp_highlands", "temp_highlands", "temp_dirt_gravel_b", "temp_dirt_gravel_plants",
33         "temp_highlands", "temp_highlands", "temp_highlands", "temp_dirt_gravel_b", "temp_dirt_gravel_plants",
34         "temp_highlands", "temp_highlands", "temp_highlands", "temp_cliff_b", "temp_dirt_gravel_plants",
35         "temp_highlands", "temp_highlands", "temp_highlands", "temp_cliff_b", "temp_dirt_gravel_plants",
36         "temp_highlands|gaia/fauna_goat"];
38 var mapSize = getMapSize();
39 var mapRadius = mapSize/2;
40 var playableMapRadius = mapRadius - 5;
41 var mapCenterX = mapRadius;
42 var mapCenterZ = mapRadius;
44 var numPlayers = getNumPlayers();
45 var baseRadius = 20;
46 var minPlayerRadius = min(mapRadius-1.5*baseRadius, 5*mapRadius/8);
47 var maxPlayerRadius = min(mapRadius-baseRadius, 3*mapRadius/4);
48 var playerStartLocX = [];
49 var playerStartLocZ = [];
50 var playerAngle = [];
51 var playerAngleStart = randFloat(0, 2*PI);
52 var playerAngleAddAvrg = 2*PI / numPlayers;
53 var playerAngleMaxOff = playerAngleAddAvrg/4;
55 // Setup eyecandy
56 var templateEC = "other/unfinished_greek_temple";
57 var radiusEC = max(mapRadius/8, baseRadius/2);
59 // Setup paths
60 var pathSucsessRadius = baseRadius/2;
61 var pathAngleOff = PI/2;
62 var pathWidth = 5; // This is not really the path's sickness in tiles but the number of tiles in the clumbs of the path
64 // Setup additional resources
65 var resourceRadius = 2*mapRadius/3; // 3*mapRadius/8;
66 var resourcePerPlayer = [templateStone, templateMetalMine];
68 // Setup woods
69 // For large maps there are memory errors with too many trees.  A density of 256*192/mapArea works with 0 players.
70 // Around each player there is an area without trees so with more players the max density can increase a bit.
71 var maxTreeDensity = min(256 * (192 + 8 * numPlayers) / (mapSize * mapSize), 1); // Has to be tweeked but works ok
72 var bushChance = 1/3; // 1 means 50% chance in deepest wood, 0.5 means 25% chance in deepest wood
74 RMS.SetProgress(2);
76 // Place bases
77 for (var i=0; i < numPlayers; i++)
79         playerAngle[i] = (playerAngleStart + i*playerAngleAddAvrg + randFloat(0, playerAngleMaxOff))%(2*PI);
80         var x = round(mapCenterX + randFloat(minPlayerRadius, maxPlayerRadius)*cos(playerAngle[i]));
81         var z = round(mapCenterZ + randFloat(minPlayerRadius, maxPlayerRadius)*sin(playerAngle[i]));
82         playerStartLocX[i] = x;
83         playerStartLocZ[i] = z;
85         placeCivDefaultEntities(x, z, i+1);
87         // Place base texture
88         var placer = new ClumpPlacer(2*baseRadius*baseRadius, 2/3, 1/8, 10, x, z);
89         var painter = [new LayeredPainter([terrainBaseBorder, terrainBase, terrainBaseCenter], [baseRadius/4, baseRadius/4]), paintClass(clPlayer)];
90         createArea(placer, painter);
92         // Place starting resources
93         var distToSL = 10;
94         var resStartAngle = playerAngle[i] + PI;
95         var resAddAngle = 2*PI / startingResourcees.length;
96         for (var rIndex = 0; rIndex < startingResourcees.length; rIndex++)
97         {
98                 var angleOff = randFloat(-resAddAngle/2, resAddAngle/2);
99                 var placeX = x + distToSL*cos(resStartAngle + rIndex*resAddAngle + angleOff);
100                 var placeZ = z + distToSL*sin(resStartAngle + rIndex*resAddAngle + angleOff);
101                 placeObject(placeX, placeZ, startingResourcees[rIndex], 0, randFloat(0, 2*PI));
102                 addToClass(round(placeX), round(placeZ), clBaseResource);
103         }
106 RMS.SetProgress(10);
108 // Place paths
109 var doublePaths = true;
110 if (numPlayers > 4)
111         doublePaths = false;
112 if (doublePaths == true)
113         var maxI = numPlayers+1;
114 else
115         var maxI = numPlayers;
116 for (var i = 0; i < maxI; i++)
118         if (doublePaths == true)
119                 var minJ = 0;
120         else
121                 var minJ = i+1;
122         for (var j = minJ; j < numPlayers+1; j++)
123         {
124                 // Setup start and target coordinates
125                 if (i < numPlayers)
126                 {
127                         var x = playerStartLocX[i];
128                         var z = playerStartLocZ[i];
129                 }
130                 else
131                 {
132                         var x = mapCenterX;
133                         var z = mapCenterZ;
134                 }
136                 if (j < numPlayers)
137                 {
138                         var targetX = playerStartLocX[j];
139                         var targetZ = playerStartLocZ[j];
140                 }
141                 else
142                 {
143                         var targetX = mapCenterX;
144                         var targetZ = mapCenterZ;
145                 }
147                 // Prepare path placement
148                 var angle = getAngle(x, z, targetX, targetZ);
149                 x += round(pathSucsessRadius*cos(angle));
150                 z += round(pathSucsessRadius*sin(angle));
151                 var targetReached = false;
152                 var tries = 0;
153                 // Placing paths
154                 while (targetReached == false && tries < 2*mapSize)
155                 {
156                         var placer = new ClumpPlacer(pathWidth, 1, 1, 1, x, z);
157                         var painter = [new TerrainPainter(terrainPath), new ElevationPainter(randFloat(-1, 0)), paintClass(clPath)];
158                         createArea(placer, painter, avoidClasses(clHill, 0, clBaseResource, 4));
159                         // addToClass(x, z, clPath); // Not needed...
160                         // Set vars for next loop
161                         angle = getAngle(x, z, targetX, targetZ);
162                         if (doublePaths == true) // Bended paths
163                         {
164                                 x += round(cos(angle + randFloat(-pathAngleOff/2, 3*pathAngleOff/2)));
165                                 z += round(sin(angle + randFloat(-pathAngleOff/2, 3*pathAngleOff/2)));
166                         }
167                         else // Straight paths
168                         {
169                                 x += round(cos(angle + randFloat(-pathAngleOff, pathAngleOff)));
170                                 z += round(sin(angle + randFloat(-pathAngleOff, pathAngleOff)));
171                         }
172                         if (Math.euclidDistance2D(x, z, targetX, targetZ) < pathSucsessRadius)
173                                 targetReached = true;
174                         tries++;
176                 }
177         }
180 RMS.SetProgress(50);
182 // Place expansion resources
183 for (var i=0; i < numPlayers; i++)
185         for (var rIndex = 0; rIndex < resourcePerPlayer.length; rIndex++)
186         {
187                 if (numPlayers > 1)
188                         var angleDist = (playerAngle[(i+1)%numPlayers] - playerAngle[i] + 2*PI)%(2*PI);
189                 else
190                         var angleDist = 2*PI;
191                 var placeX = round(mapCenterX + resourceRadius*cos(playerAngle[i] + (rIndex+1)*angleDist/(resourcePerPlayer.length+1)));
192                 var placeZ = round(mapCenterX + resourceRadius*sin(playerAngle[i] + (rIndex+1)*angleDist/(resourcePerPlayer.length+1)));
193                 placeObject(placeX, placeZ, resourcePerPlayer[rIndex], 0, randFloat(0, 2*PI));
194                 var placer = new ClumpPlacer(40, 1/2, 1/8, 1, placeX, placeZ);
195                 var painter = [new LayeredPainter([terrainHillBorder, terrainHill], [1]), new ElevationPainter(randFloat(1, 2)), paintClass(clHill)];
196                 createArea(placer, painter);
197         }
200 RMS.SetProgress(60);
202 // Place eyecandy
203 placeObject(mapCenterX, mapCenterZ, templateEC, 0, randFloat(0, 2*PI));
204 var placer = new ClumpPlacer(radiusEC*radiusEC, 1/2, 1/8, 1, mapCenterX, mapCenterZ);
205 var painter = [new LayeredPainter([terrainHillBorder, terrainHill], [radiusEC/4]), new ElevationPainter(randFloat(1, 2)), paintClass(clHill)];
206 createArea(placer, painter);
208 // Woods and general hight map
209 for (var x = 0; x < mapSize; x++)
211         for (var z = 0;z < mapSize;z++)
212         {
213                 // The 0.5 is a correction for the entities placed on the center of tiles
214                 var radius = Math.euclidDistance2D(x + 0.5, z + 0.5, mapCenterX, mapCenterZ);
215                 var minDistToSL = mapSize;
216                 for (var i=0; i < numPlayers; i++)
217                         minDistToSL = Math.min(minDistToSL, Math.euclidDistance2D(x, z, playerStartLocX[i], playerStartLocZ[i]));
219                 // Woods tile based
220                 var tDensFactSL = max(min((minDistToSL - baseRadius) / baseRadius, 1), 0);
221                 var tDensFactRad = abs((resourceRadius - radius) / resourceRadius);
222                 var tDensFactEC = max(min((radius - radiusEC) / radiusEC, 1), 0);
223                 var tDensActual = maxTreeDensity * tDensFactSL * tDensFactRad * tDensFactEC;
225                 if (randBool(tDensActual) && radius < playableMapRadius)
226                 {
227                         if (tDensActual < randFloat(0, bushChance * maxTreeDensity))
228                         {
229                                 var placer = new ClumpPlacer(1, 1.0, 1.0, 1, x, z);
230                                 var painter = [new TerrainPainter(terrainWoodBorder), new ElevationPainter(randFloat(0, 1)), paintClass(clForest)];
231                                 createArea(placer, painter, avoidClasses(clPath, 1, clHill, 0));
232                         }
233                         else
234                         {
235                                 var placer = new ClumpPlacer(1, 1.0, 1.0, 1, x, z);
236                                 var painter = [new TerrainPainter(terrainWood), new ElevationPainter(randFloat(0, 1)), paintClass(clForest)];
237                                 createArea(placer, painter, avoidClasses(clPath, 2, clHill, 1));
238                         }
239                 }
241                 // General hight map
242                 var hVarMiddleHill = mapSize/64 * (1+cos(3*PI/2 * radius/mapRadius));
243                 var hVarHills = 5*(1+sin(x/10)*sin(z/10));
244                 setHeight(x, z, getHeight(x, z) + hVarMiddleHill + hVarHills + 1);
245         }
247 RMS.SetProgress(95);
249 ExportMap();