convertHeightmap1Dto2D helper function which allows extracting a subset of a heightma...
[0ad.git] / binaries / data / mods / public / maps / random / rmgen / library.js
blobbbb3ea147fcde8624101b1d9dcf9e38591caa0e2
1 const TERRAIN_SEPARATOR = "|";
2 const SEA_LEVEL = 20.0;
3 const HEIGHT_UNITS_PER_METRE = 92;
5 /**
6  * Number of impassable, unexplorable tiles at the map border.
7  */
8 const MAP_BORDER_WIDTH = 3;
10 const g_DamageTypes = new DamageTypes();
12 /**
13  * Constants needed for heightmap_manipulation.js
14  */
15 const MAX_HEIGHT_RANGE = 0xFFFF / HEIGHT_UNITS_PER_METRE; // Engine limit, Roughly 700 meters
16 const MIN_HEIGHT = - SEA_LEVEL;
18 /**
19  * Length of one tile of the terrain grid in metres.
20  * Useful to transform footprint sizes of templates to the coordinate system used by getMapSize.
21  */
22 const TERRAIN_TILE_SIZE = Engine.GetTerrainTileSize();
24 const MAX_HEIGHT = MAX_HEIGHT_RANGE - SEA_LEVEL;
26 /**
27  * Default angle for buildings.
28  */
29 const BUILDING_ORIENTATION = -1/4 * Math.PI;
31 const g_CivData = deepfreeze(loadCivFiles(false));
33 /**
34  * Sets whether setHeight operates on the center of a tile or on the vertices.
35  */
36 var TILE_CENTERED_HEIGHT_MAP = false;
38 function fractionToTiles(f)
40         return g_MapSettings.Size * f;
43 function tilesToFraction(t)
45         return t / g_MapSettings.Size;
48 function scaleByMapSize(min, max, minMapSize = 128, maxMapSize = 512)
50         return min + (max - min) * (g_MapSettings.Size - minMapSize) / (maxMapSize - minMapSize);
53 function randomPositionOnTile(tilePosition)
55         return Vector2D.add(tilePosition, new Vector2D(randFloat(0, 1), randFloat(0, 1)));
58 /**
59  * Retries the given function with those arguments as often as specified.
60  */
61 function retryPlacing(placeFunc, retryFactor, amount, getResult, behaveDeprecated = false)
63         let maxFail = amount * retryFactor;
65         let results = [];
66         let good = 0;
67         let bad = 0;
69         while (good < amount && bad <= maxFail)
70         {
71                 let result = placeFunc();
73                 if (result !== undefined || behaveDeprecated)
74                 {
75                         ++good;
76                         if (getResult)
77                                 results.push(result);
78                 }
79                 else
80                         ++bad;
81         }
82         return getResult ? results : good;
85 // TODO this is a hack to simulate the old behaviour of those functions
86 // until all old maps are changed to use the correct version of these functions
87 function createObjectGroupsDeprecated(group, player, constraint, amount, retryFactor = 10)
89         return createObjectGroups(group, player, constraint, amount, retryFactor, true);
92 function createObjectGroupsByAreasDeprecated(group, player, constraint, amount, retryFactor, areas)
94         return createObjectGroupsByAreas(group, player, constraint, amount, retryFactor, areas, true);
97 /**
98  * Attempts to place the given number of areas in random places of the map.
99  * Returns actually placed areas.
100  */
101 function createAreas(centeredPlacer, painter, constraint, amount, retryFactor = 10)
103         let placeFunc = function() {
104                 centeredPlacer.setCenterPosition(g_Map.randomCoordinate(false));
105                 return createArea(centeredPlacer, painter, constraint);
106         };
108         return retryPlacing(placeFunc, retryFactor, amount, true, false);
112  * Attempts to place the given number of areas in random places of the given areas.
113  * Returns actually placed areas.
114  */
115 function createAreasInAreas(centeredPlacer, painter, constraint, amount, retryFactor, areas)
117         let placeFunc = function() {
118                 centeredPlacer.setCenterPosition(pickRandom(pickRandom(areas).points));
119                 return createArea(centeredPlacer, painter, constraint);
120         };
122         return retryPlacing(placeFunc, retryFactor, amount, true, false);
126  * Attempts to place the given number of groups in random places of the map.
127  * Returns the number of actually placed groups.
128  */
129 function createObjectGroups(group, player, constraint, amount, retryFactor = 10, behaveDeprecated = false)
131         let placeFunc = function() {
132                 group.setCenterPosition(g_Map.randomCoordinate(true));
133                 return createObjectGroup(group, player, constraint);
134         };
136         return retryPlacing(placeFunc, retryFactor, amount, false, behaveDeprecated);
140  * Attempts to place the given number of groups in random places of the given areas.
141  * Returns the number of actually placed groups.
142  */
143 function createObjectGroupsByAreas(group, player, constraint, amount, retryFactor, areas, behaveDeprecated = false)
145         let placeFunc = function() {
146                 group.setCenterPosition(pickRandom(pickRandom(areas).points));
147                 return createObjectGroup(group, player, constraint);
148         };
150         return retryPlacing(placeFunc, retryFactor, amount, false, behaveDeprecated);
153 function createTerrain(terrain)
155         return typeof terrain == "string" ?
156                 new SimpleTerrain(...terrain.split(TERRAIN_SEPARATOR)) :
157                 new RandomTerrain(terrain.map(t => createTerrain(t)));
161  * Constructs a new Area shaped by the Placer meeting the Constraints and calls the Painters there.
162  * Supports both Centered and Non-Centered Placers.
163  */
164 function createArea(placer, painters, constraints)
166         let points = placer.place(new AndConstraint(constraints));
167         if (!points)
168                 return undefined;
170         let area = g_Map.createArea(points);
172         new MultiPainter(painters).paint(area);
174         return area;
178  * @param mode is one of the HeightPlacer constants determining whether to exclude the min/max elevation.
179  */
180 function paintTerrainBasedOnHeight(minHeight, maxHeight, mode, terrain)
182         createArea(
183                 new HeightPlacer(mode, minHeight, maxHeight),
184                 new TerrainPainter(terrain));
187 function paintTileClassBasedOnHeight(minHeight, maxHeight, mode, tileClass)
189         createArea(
190                 new HeightPlacer(mode, minHeight, maxHeight),
191                 new TileClassPainter(tileClass));
194 function unPaintTileClassBasedOnHeight(minHeight, maxHeight, mode, tileClass)
196         createArea(
197                 new HeightPlacer(mode, minHeight, maxHeight),
198                 new TileClassUnPainter(tileClass));
202  * Places the Entities of the given Group if they meet the Constraints
203  * and sets the given player as the owner.
204  */
205 function createObjectGroup(group, player, constraints)
207         return group.place(player, new AndConstraint(constraints));
211  * Create an avoid constraint for the given classes by the given distances
212  */
213 function avoidClasses(/*class1, dist1, class2, dist2, etc*/)
215         let ar = [];
216         for (let i = 0; i < arguments.length/2; ++i)
217                 ar.push(new AvoidTileClassConstraint(arguments[2*i], arguments[2*i+1]));
219         // Return single constraint
220         if (ar.length == 1)
221                 return ar[0];
223         return new AndConstraint(ar);
227  * Create a stay constraint for the given classes by the given distances
228  */
229 function stayClasses(/*class1, dist1, class2, dist2, etc*/)
231         let ar = [];
232         for (let i = 0; i < arguments.length/2; ++i)
233                 ar.push(new StayInTileClassConstraint(arguments[2*i], arguments[2*i+1]));
235         // Return single constraint
236         if (ar.length == 1)
237                 return ar[0];
239         return new AndConstraint(ar);
243  * Create a border constraint for the given classes by the given distances
244  */
245 function borderClasses(/*class1, idist1, odist1, class2, idist2, odist2, etc*/)
247         let ar = [];
248         for (let i = 0; i < arguments.length/3; ++i)
249                 ar.push(new BorderTileClassConstraint(arguments[3*i], arguments[3*i+1], arguments[3*i+2]));
251         // Return single constraint
252         if (ar.length == 1)
253                 return ar[0];
255         return new AndConstraint(ar);
258 function convertHeightmap1Dto2D(heightmap)
260         let result = [];
261         let hmSize = Math.sqrt(heightmap.length);
262         for (let x = 0; x < hmSize; ++x)
263         {
264                 result[x] = new Float32Array(hmSize);
265                 for (let y = 0; y < hmSize; ++y)
266                         result[x][y] = heightmap[y * hmSize + x];
267         }
268         return result;