Nomad mode on all random map scripts (except Survival of the Fittest), fixes #3591.
[0ad.git] / binaries / data / mods / public / maps / random / deep_forest.js
blob2106dcda8969697cd16ac3298bada519c5a26c1a
1 Engine.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";
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();
43 var baseRadius = 20;
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 = [];
48 var playerAngle = [];
49 var playerAngleStart = randFloat(0, 2 * Math.PI);
50 var playerAngleAddAvrg = 2 * Math.PI / numPlayers;
51 var playerAngleMaxOff = playerAngleAddAvrg/4;
53 // Setup eyecandy
54 var templateEC = "other/unfinished_greek_temple";
55 var radiusEC = Math.max(mapRadius/8, baseRadius/2);
57 // Setup paths
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];
66 // Setup woods
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
72 var playerIDs = [];
73 for (var i=0; i < numPlayers; i++)
75         playerIDs[i] = i+1;
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);
82 placePlayerBases({
83         "PlayerPlacement": [playerIDs, playerStartLocX.map(tilesToFraction), playerStartLocZ.map(tilesToFraction)],
84         "BaseResourceClass": clBaseResource,
85         // player class painted below
86         "CityPatch": {
87                 "radius": 0.8 * baseRadius,
88                 "smoothness": 1/8,
89                 "painters": [
90                         new LayeredPainter([terrainBaseBorder, terrainBase, terrainBaseCenter], [baseRadius/4, baseRadius/4]),
91                         paintClass(clPlayer)
92                 ]
93         },
94         // Chicken already placed at the base terrain
95         "Berries": {
96                 "template": "gaia/flora_bush_grapes",
97                 "minCount": 2,
98                 "maxCount": 2,
99                 "minDist": 10,
100                 "maxDist": 10
101         },
102         "Mines": {
103                 "types": [
104                         { "template": templateMetalMine },
105                         { "template": templateStoneMine }
106                 ],
107                 "minAngle": Math.PI / 2,
108                 "maxAngle": Math.PI
109         },
110         "Trees": {
111                 "template": "gaia/flora_tree_oak_large",
112                 "count": 2
113         }
115 Engine.SetProgress(10);
117 // Place paths
118 var doublePaths = true;
119 if (numPlayers > 4)
120         doublePaths = false;
121 if (doublePaths == true)
122         var maxI = numPlayers+1;
123 else
124         var maxI = numPlayers;
125 for (var i = 0; i < maxI; i++)
127         if (doublePaths == true)
128                 var minJ = 0;
129         else
130                 var minJ = i+1;
131         for (var j = minJ; j < numPlayers+1; j++)
132         {
133                 // Setup start and target coordinates
134                 if (i < numPlayers)
135                 {
136                         var x = playerStartLocX[i];
137                         var z = playerStartLocZ[i];
138                 }
139                 else
140                 {
141                         var x = mapCenterX;
142                         var z = mapCenterZ;
143                 }
145                 if (j < numPlayers)
146                 {
147                         var targetX = playerStartLocX[j];
148                         var targetZ = playerStartLocZ[j];
149                 }
150                 else
151                 {
152                         var targetX = mapCenterX;
153                         var targetZ = mapCenterZ;
154                 }
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;
161                 var tries = 0;
162                 // Placing paths
163                 while (targetReached == false && tries < 2*mapSize)
164                 {
165                         createArea(
166                                 new ClumpPlacer(pathWidth, 1, 1, 1, x, z),
167                                 [
168                                         new TerrainPainter(terrainPath),
169                                         new ElevationPainter(randFloat(-1, 0)),
170                                         paintClass(clPath)
171                                 ],
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
177                         {
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)));
180                         }
181                         else // Straight paths
182                         {
183                                 x += Math.round(Math.cos(angle + randFloat(-pathAngleOff, pathAngleOff)));
184                                 z += Math.round(Math.sin(angle + randFloat(-pathAngleOff, pathAngleOff)));
185                         }
186                         if (Math.euclidDistance2D(x, z, targetX, targetZ) < pathSucsessRadius)
187                                 targetReached = true;
188                         tries++;
190                 }
191         }
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++)
200         {
201                 if (numPlayers > 1)
202                         var angleDist = (playerAngle[(i+1)%numPlayers] - playerAngle[i] + 2 * Math.PI) % (2 * Math.PI);
203                 else
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));
211                 createArea(
212                         new ClumpPlacer(40, 1/2, 1/8, 1, placeX, placeZ),
213                         [
214                                 new LayeredPainter([terrainHillBorder, terrainHill], [1]),
215                                 new ElevationPainter(randFloat(1, 2)),
216                                 paintClass(clHill)
217                         ]);
218         }
221 Engine.SetProgress(60);
223 // Place eyecandy
224 placeObject(mapCenterX, mapCenterZ, templateEC, 0, randFloat(0, 2 * Math.PI));
225 addToClass(mapCenterX, mapCenterZ, clBaseResource);
226 createArea(
227         new ClumpPlacer(Math.square(radiusEC), 1/2, 1/8, 1, mapCenterX, mapCenterZ),
228         [
229                 new LayeredPainter([terrainHillBorder, terrainHill], [radiusEC/4]),
230                 new ElevationPainter(randFloat(1, 2)),
231                 paintClass(clHill)
232         ]);
234 // Woods and general hight map
235 for (var x = 0; x < mapSize; x++)
237         for (var z = 0;z < mapSize;z++)
238         {
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]));
245                 // Woods tile based
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))
252                 {
253                         let border = tDensActual < randFloat(0, bushChance * maxTreeDensity);
254                         createArea(
255                                 new ClumpPlacer(1, 1, 1, 1, x, z),
256                                 [
257                                         new TerrainPainter(border ? terrainWoodBorder : terrainWood),
258                                         new ElevationPainter(randFloat(0, 1)),
259                                         paintClass(clForest)
260                                 ],
261                                 avoidClasses(clPath, 1, clHill, border ? 0 : 1));
262                 }
264                 // General hight map
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);
268         }
270 Engine.SetProgress(95);
272 placePlayersNomad(clPlayer, avoidClasses(clForest, 1, clBaseResource, 4));
274 ExportMap();