Merge 'remotes/trunk'
[0ad.git] / binaries / data / mods / public / maps / random / islands.js
blob67c3445d25d67ae3b97ddd5f85d4bee68ad6a757
1 Engine.LoadLibrary("rmgen");
2 Engine.LoadLibrary("rmgen-common");
3 Engine.LoadLibrary("rmbiome");
5 function* GenerateMap()
7         TILE_CENTERED_HEIGHT_MAP = true;
9         setSelectedBiome();
11         const tMainTerrain = g_Terrains.mainTerrain;
12         const tForestFloor1 = g_Terrains.forestFloor1;
13         const tForestFloor2 = g_Terrains.forestFloor2;
14         const tCliff = g_Terrains.cliff;
15         const tTier1Terrain = g_Terrains.tier1Terrain;
16         const tTier2Terrain = g_Terrains.tier2Terrain;
17         const tTier3Terrain = g_Terrains.tier3Terrain;
18         const tHill = g_Terrains.hill;
19         const tRoad = g_Terrains.road;
20         const tRoadWild = g_Terrains.roadWild;
21         const tTier4Terrain = g_Terrains.tier4Terrain;
22         const tShore = g_Terrains.shore;
23         const tWater = g_Terrains.water;
25         const oTree1 = g_Gaia.tree1;
26         const oTree2 = g_Gaia.tree2;
27         const oTree3 = g_Gaia.tree3;
28         const oTree4 = g_Gaia.tree4;
29         const oTree5 = g_Gaia.tree5;
30         const oFruitBush = g_Gaia.fruitBush;
31         const oMainHuntableAnimal = g_Gaia.mainHuntableAnimal;
32         const oFish = g_Gaia.fish;
33         const oSecondaryHuntableAnimal = g_Gaia.secondaryHuntableAnimal;
34         const oStoneLarge = g_Gaia.stoneLarge;
35         const oStoneSmall = g_Gaia.stoneSmall;
36         const oMetalLarge = g_Gaia.metalLarge;
37         const oWoodTreasure = "gaia/treasure/wood";
38         const oDock = "skirmish/structures/default_dock";
40         const aGrass = g_Decoratives.grass;
41         const aGrassShort = g_Decoratives.grassShort;
42         const aRockLarge = g_Decoratives.rockLarge;
43         const aRockMedium = g_Decoratives.rockMedium;
44         const aBushMedium = g_Decoratives.bushMedium;
45         const aBushSmall = g_Decoratives.bushSmall;
47         const pForest1 = [
48                 tForestFloor2 + TERRAIN_SEPARATOR + oTree1,
49                 tForestFloor2 + TERRAIN_SEPARATOR + oTree2,
50                 tForestFloor2
51         ];
52         const pForest2 = [
53                 tForestFloor1 + TERRAIN_SEPARATOR + oTree4,
54                 tForestFloor1 + TERRAIN_SEPARATOR + oTree5,
55                 tForestFloor1
56         ];
58         const heightSeaGround = -5;
59         const heightLand = 3;
60         const heightOffsetBump = 2;
61         const heightHill = 18;
63         globalThis.g_Map = new RandomMap(heightSeaGround, tWater);
65         const numPlayers = getNumPlayers();
66         const mapSize = g_Map.getSize();
67         const mapCenter = g_Map.getCenter();
69         const clPlayer = g_Map.createTileClass();
70         const clHill = g_Map.createTileClass();
71         const clForest = g_Map.createTileClass();
72         const clDirt = g_Map.createTileClass();
73         const clRock = g_Map.createTileClass();
74         const clMetal = g_Map.createTileClass();
75         const clFood = g_Map.createTileClass();
76         const clBaseResource = g_Map.createTileClass();
77         const clLand = g_Map.createTileClass();
79         const playerIslandRadius = scaleByMapSize(20, 29);
81         const [playerIDs, playerPosition, playerAngle] = playerPlacementCircle(fractionToTiles(0.35));
83         if (!isNomad())
84         {
85                 g_Map.log("Creating player islands and docks");
86                 for (let i = 0; i < numPlayers; i++)
87                 {
88                         createArea(
89                                 new ClumpPlacer(diskArea(playerIslandRadius), 0.8, 0.1, Infinity,
90                                         playerPosition[i]),
91                                 [
92                                         new LayeredPainter([tMainTerrain, tMainTerrain, tMainTerrain], [1, 6]),
93                                         new SmoothElevationPainter(ELEVATION_SET, heightLand, 6),
94                                         new TileClassPainter(clLand),
95                                         new TileClassPainter(clPlayer)
96                                 ]);
98                         const dockLocation = findLocationInDirectionBasedOnHeight(playerPosition[i],
99                                 mapCenter, -3, heightLand - 0.5, heightLand);
100                         g_Map.placeEntityPassable(oDock, playerIDs[i], dockLocation, playerAngle[i] + Math.PI);
101                 }
102         }
104         g_Map.log("Creating big islands");
105         createAreas(
106                 new ChainPlacer(
107                         Math.floor(scaleByMapSize(4, 8)),
108                         Math.floor(scaleByMapSize(8, 14)),
109                         Math.floor(scaleByMapSize(25, 60)),
110                         0.07),
111                 [
112                         new TerrainPainter(tMainTerrain),
113                         new SmoothElevationPainter(ELEVATION_SET, heightLand, 6),
114                         new TileClassPainter(clLand)
115                 ],
116                 avoidClasses(clLand, scaleByMapSize(8, 12)),
117                 scaleByMapSize(4, 14));
119         g_Map.log("Creating small islands");
120         createAreas(
121                 new ChainPlacer(
122                         Math.floor(scaleByMapSize(4, 7)),
123                         Math.floor(scaleByMapSize(7, 10)),
124                         Math.floor(scaleByMapSize(16, 40)),
125                         0.07),
126                 [
127                         new TerrainPainter(tMainTerrain),
128                         new SmoothElevationPainter(ELEVATION_SET, heightLand, 6),
129                         new TileClassPainter(clLand)
130                 ],
131                 avoidClasses(clLand, scaleByMapSize(8, 12)),
132                 scaleByMapSize(6, 54));
134         paintTerrainBasedOnHeight(1, 3, 0, tShore);
135         paintTerrainBasedOnHeight(-8, 1, 2, tWater);
137         placePlayerBases({
138                 "PlayerPlacement": [playerIDs, playerPosition],
139                 // PlayerTileClass marked above
140                 "BaseResourceClass": clBaseResource,
141                 "Walls": "towers",
142                 "CityPatch": {
143                         "radius": playerIslandRadius / 3,
144                         "outerTerrain": tRoadWild,
145                         "innerTerrain": tRoad
146                 },
147                 "StartingAnimal": {
148                 },
149                 "Berries": {
150                         "template": oFruitBush
151                 },
152                 "Mines": {
153                         "types": [
154                                 { "template": oMetalLarge },
155                                 { "template": oStoneLarge }
156                         ]
157                 },
158                 "Treasures": {
159                         "types": [
160                                 {
161                                         "template": oWoodTreasure,
162                                         "count": 14
163                                 }
164                         ]
165                 },
166                 "Trees": {
167                         "template": oTree1,
168                         "count": 5
169                 },
170                 "Decoratives": {
171                         "template": aGrassShort
172                 }
173         });
175         g_Map.log("Creating bumps");
176         createAreas(
177                 new ClumpPlacer(scaleByMapSize(20, 50), 0.3, 0.06, Infinity),
178                 new SmoothElevationPainter(ELEVATION_MODIFY, heightOffsetBump, 2),
179                 [avoidClasses(clPlayer, 0), stayClasses(clLand, 3)],
180                 scaleByMapSize(20, 100));
182         g_Map.log("Creating hills");
183         createAreas(
184                 new ChainPlacer(1, Math.floor(scaleByMapSize(4, 6)), Math.floor(scaleByMapSize(16, 40)), 0.5),
185                 [
186                         new LayeredPainter([tCliff, tHill], [2]),
187                         new SmoothElevationPainter(ELEVATION_SET, heightHill, 2),
188                         new TileClassPainter(clHill)
189                 ],
190                 [avoidClasses(clPlayer, 2, clHill, 15), stayClasses(clLand, 0)],
191                 scaleByMapSize(4, 13));
193         g_Map.log("Creating forests");
194         const [forestTrees, stragglerTrees] = getTreeCounts(...rBiomeTreeCount(1));
195         const types = [
196                 [[tForestFloor2, tMainTerrain, pForest1], [tForestFloor2, pForest1]],
197                 [[tForestFloor1, tMainTerrain, pForest2], [tForestFloor1, pForest2]]
198         ];
200         if (currentBiome() != "generic/savanna")
201         {
202                 const size = forestTrees / (scaleByMapSize(3, 6) * numPlayers);
203                 const num = Math.floor(size / types.length);
204                 for (const type of types)
205                         createAreas(
206                                 new ChainPlacer(1, Math.floor(scaleByMapSize(3, 5)),
207                                         forestTrees / (num * Math.floor(scaleByMapSize(2, 5))), 0.5),
208                                 [
209                                         new LayeredPainter(type, [2]),
210                                         new TileClassPainter(clForest)
211                                 ],
212                                 [avoidClasses(clPlayer, 0, clForest, 10, clHill, 0), stayClasses(clLand, 6)],
213                                 num);
214         }
216         yield 50;
217         g_Map.log("Creating dirt patches");
218         const numberOfPatches = scaleByMapSize(15, 45) * (currentBiome() == "generic/savanna" ? 3 : 1);
219         for (const size of [scaleByMapSize(3, 6), scaleByMapSize(5, 10), scaleByMapSize(8, 21)])
220                 createAreas(
221                         new ChainPlacer(1, Math.floor(scaleByMapSize(3, 5)), size, 0.5),
222                         [
223                                 new LayeredPainter(
224                                         [
225                                                 [tMainTerrain, tTier1Terrain],
226                                                 [tTier1Terrain, tTier2Terrain],
227                                                 [tTier2Terrain, tTier3Terrain]
228                                         ], [1, 1]),
229                                 new TileClassPainter(clDirt)
230                         ],
231                         [avoidClasses(clForest, 0, clHill, 0, clDirt, 5, clPlayer, 0), stayClasses(clLand, 6)],
232                         numberOfPatches);
234         g_Map.log("Creating grass patches");
235         for (const size of [scaleByMapSize(2, 4), scaleByMapSize(3, 7), scaleByMapSize(5, 15)])
236                 createAreas(
237                         new ChainPlacer(1, Math.floor(scaleByMapSize(3, 5)), size, 0.5),
238                         new TerrainPainter(tTier4Terrain),
239                         [avoidClasses(clForest, 0, clHill, 0, clDirt, 5, clPlayer, 0), stayClasses(clLand, 6)],
240                         numberOfPatches);
242         yield 55;
244         g_Map.log("Creating stone mines");
245         let group = new SimpleGroup(
246                 [
247                         new SimpleObject(oStoneSmall, 0, 2, 0, 4, 0, 2 * Math.PI, 1),
248                         new SimpleObject(oStoneLarge, 1, 1, 0, 4, 0, 2 * Math.PI, 4)
249                 ], true, clRock);
250         createObjectGroupsDeprecated(group, 0,
251                 [avoidClasses(clForest, 1, clPlayer, 0, clRock, 10, clHill, 1), stayClasses(clLand, 5)],
252                 scaleByMapSize(4, 16), 100
253         );
255         g_Map.log("Creating small stone quarries");
256         group = new SimpleGroup([new SimpleObject(oStoneSmall, 2, 5, 1, 3)], true, clRock);
257         createObjectGroupsDeprecated(group, 0,
258                 [avoidClasses(clForest, 1, clPlayer, 0, clRock, 10, clHill, 1), stayClasses(clLand, 5)],
259                 scaleByMapSize(4, 16), 100
260         );
262         g_Map.log("Creating metal mines");
263         group = new SimpleGroup([new SimpleObject(oMetalLarge, 1, 1, 0, 4)], true, clMetal);
264         createObjectGroupsDeprecated(group, 0,
265                 [
266                         avoidClasses(clForest, 1, clPlayer, 0, clMetal, 10, clRock, 5, clHill, 1),
267                         stayClasses(clLand, 5)
268                 ],
269                 scaleByMapSize(4, 16), 100
270         );
272         yield 65;
274         g_Map.log("Creating small decorative rocks");
275         group = new SimpleGroup(
276                 [new SimpleObject(aRockMedium, 1, 3, 0, 1)],
277                 true
278         );
279         createObjectGroupsDeprecated(
280                 group, 0,
281                 [avoidClasses(clForest, 0, clPlayer, 0, clHill, 0), stayClasses(clLand, 5)],
282                 scaleByMapSize(16, 262), 50
283         );
285         g_Map.log("Creating large decorative rocks");
286         group = new SimpleGroup(
287                 [new SimpleObject(aRockLarge, 1, 2, 0, 1), new SimpleObject(aRockMedium, 1, 3, 0, 2)],
288                 true
289         );
290         createObjectGroupsDeprecated(
291                 group, 0,
292                 [avoidClasses(clForest, 0, clPlayer, 0, clHill, 0), stayClasses(clLand, 5)],
293                 scaleByMapSize(8, 131), 50
294         );
296         yield 70;
298         g_Map.log("Creating deer");
299         group = new SimpleGroup(
300                 [new SimpleObject(oMainHuntableAnimal, 5, 7, 0, 4)],
301                 true, clFood
302         );
303         createObjectGroupsDeprecated(group, 0,
304                 [avoidClasses(clForest, 0, clPlayer, 0, clHill, 1, clFood, 20), stayClasses(clLand, 5)],
305                 3 * numPlayers, 50
306         );
308         yield 75;
310         g_Map.log("Creating sheep");
311         group = new SimpleGroup(
312                 [new SimpleObject(oSecondaryHuntableAnimal, 2, 3, 0, 2)],
313                 true, clFood
314         );
315         createObjectGroupsDeprecated(group, 0,
316                 [avoidClasses(clForest, 0, clPlayer, 0, clHill, 1, clFood, 20), stayClasses(clLand, 5)],
317                 3 * numPlayers, 50
318         );
320         g_Map.log("Creating fruit bush");
321         group = new SimpleGroup(
322                 [new SimpleObject(oFruitBush, 5, 7, 0, 4)],
323                 true, clFood
324         );
325         createObjectGroupsDeprecated(group, 0,
326                 [avoidClasses(clForest, 0, clPlayer, 8, clHill, 1, clFood, 20), stayClasses(clLand, 5)],
327                 randIntInclusive(1, 4) * numPlayers + 2, 50
328         );
330         g_Map.log("Creating fish");
331         group = new SimpleGroup(
332                 [new SimpleObject(oFish, 2, 3, 0, 2)],
333                 true, clFood
334         );
335         createObjectGroupsDeprecated(group, 0,
336                 avoidClasses(clLand, 4, clForest, 2, clPlayer, 2, clHill, 2, clFood, 20),
337                 25 * numPlayers, 60
338         );
340         yield 85;
342         createStragglerTrees(
343                 [oTree1, oTree2, oTree4, oTree3],
344                 [
345                         avoidClasses(clForest, 1, clHill, 1, clPlayer, 0, clMetal, 6, clRock, 6),
346                         stayClasses(clLand, 6)
347                 ],
348                 clForest,
349                 stragglerTrees);
351         let planetm = 1;
352         if (currentBiome() == "generic/india")
353                 planetm = 8;
355         g_Map.log("Creating small grass tufts");
356         group = new SimpleGroup(
357                 [new SimpleObject(aGrassShort, 1, 2, 0, 1, -Math.PI / 8, Math.PI / 8)]
358         );
359         createObjectGroupsDeprecated(group, 0,
360                 [avoidClasses(clHill, 2, clPlayer, 2, clDirt, 0), stayClasses(clLand, 6)],
361                 planetm * scaleByMapSize(13, 200)
362         );
364         yield 90;
366         g_Map.log("Creating large grass tufts");
367         group = new SimpleGroup(
368                 [
369                         new SimpleObject(aGrass, 2, 4, 0, 1.8, -Math.PI / 8, Math.PI / 8),
370                         new SimpleObject(aGrassShort, 3, 6, 1.2, 2.5, -Math.PI / 8, Math.PI / 8)
371                 ]
372         );
373         createObjectGroupsDeprecated(group, 0,
374                 [avoidClasses(clHill, 2, clPlayer, 2, clDirt, 1, clForest, 0), stayClasses(clLand, 5)],
375                 planetm * scaleByMapSize(13, 200)
376         );
378         yield 95;
380         g_Map.log("Creating bushes");
381         group = new SimpleGroup(
382                 [new SimpleObject(aBushMedium, 1, 2, 0, 2), new SimpleObject(aBushSmall, 2, 4, 0, 2)]
383         );
384         createObjectGroupsDeprecated(group, 0,
385                 [avoidClasses(clHill, 1, clPlayer, 1, clDirt, 1), stayClasses(clLand, 6)],
386                 planetm * scaleByMapSize(13, 200), 50
387         );
389         placePlayersNomad(clPlayer,
390                 [
391                         stayClasses(clLand, 4),
392                         avoidClasses(clHill, 2, clForest, 1, clMetal, 4, clRock, 4, clFood, 2)
393                 ]);
395         setSkySet(pickRandom(["cirrus", "cumulus", "sunny"]));
396         setSunRotation(randomAngle());
397         setSunElevation(randFloat(1/5, 1/3) * Math.PI);
398         setWaterWaviness(2);
400         return g_Map;