]> git.lizzy.rs Git - dragonblocks.git/blob - engine/mapgen.js
Reset file permissions to defaults
[dragonblocks.git] / engine / mapgen.js
1 /*
2  * mapgen.js
3  * 
4  * Copyright 2020 Elias Fleckenstein <eliasfleckenstein@web.de>
5  * 
6  * This program is free software; you can redistribute it and/or modify
7  * it under the terms of the GNU General Public License as published by
8  * the Free Software Foundation; either version 2 of the License, or
9  * (at your option) any later version.
10  * 
11  * This program is distributed in the hope that it will be useful,
12  * but WITHOUT ANY WARRANTY; without even the implied warranty of
13  * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the
14  * GNU General Public License for more details.
15  * 
16  * You should have received a copy of the GNU General Public License
17  * along with this program; if not, write to the Free Software
18  * Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston,
19  * MA 02110-1301, USA.
20  * 
21  * 
22  */
23 dragonblocks.mapgen = {};
24 dragonblocks.mapgen.addStructure = function(name, msg, pos){
25         let strs = dragonblocks.world.structures;
26         strs[name] = strs[name] || [];
27         strs[name].push({msg: msg, pos: pos});
28 }
29 dragonblocks.mapgen.biomes = [];
30 dragonblocks.registerBiome = function(obj){
31         dragonblocks.mapgen.biomes.push(obj);
32 }
33 dragonblocks.mapgen.materials = [];
34 dragonblocks.registerMaterial = function(obj){
35         dragonblocks.mapgen.materials.push(obj);
36 }
37 dragonblocks.mapgen.ores = [];
38 dragonblocks.registerOre = function(obj){
39         dragonblocks.mapgen.ores.push(obj);
40 }
41 dragonblocks.mapgen.selected = "empty";
42 dragonblocks.mapgen.list = {};
43 dragonblocks.generateMap = function(){
44         dragonblocks.mapgen.list[dragonblocks.mapgen.selected]();
45 }
46 dragonblocks.mapgen.list["v3"] = function(){
47         let int = parseInt;
48         let snode = dragonblocks.setNode;
49         let gnode = dragonblocks.getNode;
50         let pm = dragonblocks.getPixelManipulator;
51         let rand = dblib.random;
52         let height = dragonblocks.map.height;
53         let width = dragonblocks.map.width;
54         let biomeList = dragonblocks.mapgen.biomes;
55         let biomes = [];
56         let biomeBorders = [];
57         {
58                 for(let d = 0; d < width;){
59                         let max = 0;
60                         for(let biome of biomeList)
61                                 max += biome.probability;
62                         let r = rand(0, max);
63                         for(let i in biomeList){
64                                 r -= biomeList[i].probability;
65                                 if(r <= 0){
66                                         biomeBorders.push(d);
67                                         let border = Math.min(d + rand(biomeList[i].size[0], biomeList[i].size[1]), width);
68                                         dragonblocks.mapgen.addStructure(biomeList[i].name, "(" + d + " - " + border + ", *)", {x: int((d + border)/2), y: 5});
69                                         for(; d < border; d++)
70                                                 biomes.push(i);
71                                         break;
72                                 }
73                         }
74                 }
75         }
76         let ground = [];
77         {
78                 let levels = [
79                         {
80                                 name: "mountain_up",
81                                 probability: 3,
82                                 rise: [-3, -2, -2, -2, -1, -1, -1],
83                                 size: 15,
84                                 minsize: 15,
85                                 high: 10,
86                                 next: "mountain_down",
87                         },
88                         {
89                                 name: "mountain_down",
90                                 probability: 0,
91                                 rise: [3, 2, 2, 2, 1, 1, 1],
92                                 size: 15,
93                                 minsize: 15,
94                                 low: 50,
95                         },
96                         {
97                                 name: "hill_up",
98                                 probability: 4,
99                                 rise: [0, 0, 0, 0, 0, -1],
100                                 size: 20,
101                                 minsize: 0,
102                                 high: 20,
103                         },
104                         {
105                                 name: "hill_down",
106                                 probability: 4,
107                                 rise: [0, 0, 0, 0, 0, 1],
108                                 size: 20,
109                                 minsize: 0,
110                                 low: 50,
111                         },
112                         {
113                                 name: "ocean_border_start",
114                                 probability: 3,
115                                 rise: [1, 1, 1, 0],
116                                 size: 0,
117                                 minsize: 100,
118                                 low: 60,
119                                 next: "ocean",
120                         },
121                         {
122                                 name: "ocean",
123                                 probability: 0,
124                                 rise: [0, 0, 0, 0, 0, 0, 0, 1, -1],
125                                 size: 5,
126                                 minsize: 20,
127                                 high: 50,
128                                 next: "ocean_border_end",
129                         },
130                         {
131                                 name: "ocean_border_end",
132                                 probability: 0,
133                                 rise: [-1, -1, -1, 0],
134                                 size: 10,
135                                 minsize: 10,
136                         },
137                         {
138                                 name: "flat",
139                                 probability: 8,
140                                 rise: [0],
141                                 size: 10,
142                                 minsize: 0,
143                                 low: 50, 
144                                 high: 30,
145                         }
146                 ];
147                 let maxprob = 0;
148                 for(let lvl of levels){
149                         levels[lvl.name] = lvl;
150                         maxprob += lvl.probability;
151                 }
152                 let level = levels.flat;
153                 let leftsize = level.minsize;
154                 let lastground = 40 * height / 100;
155                 let addedstruct = false;
156                 for(let x = 0; x < width; x++){
157                         if(level.high && level.high * height / 100 > lastground || level.low && level.low * height / 100 < lastground || leftsize <= 0 && rand(0, level.size) == 0){
158                                 if(! addedstruct){
159                                         let start = x - level.minsize + leftsize;
160                                         let end = x;
161                                         let gx = int((start + end) / 2);
162                                         let gy = ground[gx] - 3;
163                                         dragonblocks.mapgen.addStructure(level.name, "(" + start + " - " + end + ", *)", {x: gx, y: gy});
164                                         addedstruct = true;
165                                 }
166                                 if(level.next)
167                                         level = levels[level.next];
168                                 else{
169                                         let r = rand(0, maxprob);
170                                         for(let lvl of levels){
171                                                 r -= lvl.probability;
172                                                 if(r <= 0){
173                                                         level = lvl;
174                                                         break;
175                                                 }
176                                         }
177                                 }
178                                 
179                                 leftsize = level.minsize;
180                                 x--;
181                                 continue;
182                         }
183                         addedstruct = false;
184                         leftsize--;
185                         lastground += level.rise[rand(0, level.rise.length - 1)];
186                         ground[x] = lastground;
187                 }
188         }
189         {
190                 function setore(x, y, ore){
191                         if(! ground[x] || y < ground[x] || (y / height  * 100 - 50) < ore.deep)
192                                 return false;
193                         snode(x, y, ore.name);
194                         return true;
195                 }
196                 for(let x = 0; x < width; x++){
197                         let y, g;
198                         y = g = ground[x];
199                         let biome = biomeList[biomes[x]];
200                         for(; y < g + 1; y++)
201                                 snode(x, y, biome.surface);
202                         for(; y < g + 5; y++)
203                                 snode(x, y, biome.ground);
204                         for(; y < height; y++){
205                                 snode(x, y, biome.underground);
206                                 for(let ore of dragonblocks.mapgen.ores){
207                                         if(dblib.random(0, ore.factor) == 0){
208                                                 if(setore(x, y, ore))
209                                                         dragonblocks.mapgen.addStructure(ore.name, "(" + x + ", " + y + ")", {x: x, y: y});
210                                                 for(let i = 0; i < ore.clustersize; i++)
211                                                         setore(x + dblib.random(-2, 2), y + dblib.random(-2, 2), ore);
212                                         }               
213                                 }
214                         }
215                 }
216         }
217         let water = [];
218         {
219                 let top, bottom, start;
220                 top = int(height / 2);
221                 for(let x = 0; x < width; x++){
222                         let biome = biomeList[biomes[x]];
223                         if(ground[x] > top){
224                                 start = start || x; 
225                                 water[x] = true;
226                                 snode(x, top, biome.watertop);
227                                 let y = top + 1;
228                                 for(; y < ground[x]; y++)
229                                         snode(x, y, biome.water);
230                                 for(; y < ground[x] + 5; y++)
231                                         snode(x, y, biome.floor);
232                         }
233                         else if(start){
234                                 let end = x - 1;
235                                 dragonblocks.mapgen.addStructure("water", "(" + start + " - " + end + ", " + top + ")", {x: int((start + end) / 2), y: top});
236                                 start = 0;
237                         }
238                 }
239                 if(start){
240                         let end = width;
241                         dragonblocks.mapgen.addStructure("water", "(" + start + " - " + end + ", " + top + ")", {x: int((start + end) / 2), y: top});
242                 }
243         }
244         {
245                 let nexttree = 0;
246                 for(let x = 0; x < width; x++){
247                         if(x >= nexttree && ! water[x]){
248                                 let g = ground[x];
249                                 let biome = biomeList[biomes[x]];
250                                 for(let tree of biome.trees){
251                                         if(Math.random() <= tree.chance){
252                                                 snode(x, g - 1, tree.sapling);
253                                                 gnode(x, g - 1) && dragonblocks.finishTimer("growTimer", gnode(x, g - 1).meta);
254                                                 nexttree = x + tree.width;
255                                                 break;
256                                         }
257                                 }
258                         }
259                 }
260         }
261         {
262                 function structure(x, y, mat){
263                         let core = pm([["§" + mat, mat], [mat, mat]]);
264                         core.addFunction((node, x, y) => {return y > ground[x]});
265                         core.apply(x, y);
266                         let sides = [
267                                 pm([[mat, mat], ["§", ""]]),
268                                 pm([["§", "", mat], ["", "", mat]]),
269                                 pm([["§", ""], ["", ""], [mat, mat]]), 
270                                 pm([[mat, "§"], [mat, ""]]),                                   
271                         ];
272                         for(let side of sides)
273                                 side.addFunction((node, x, y) => {return y > ground[x]});
274                         let moresides = [
275                                 pm([[mat, mat], ["", ""], ["§", ""]]),
276                                 pm([["§", "", "", mat], ["", "", "", mat]]),
277                                 pm([["§", ""], ["", ""], ["", ""], [mat, mat]]), 
278                                 pm([[mat, "", "§"], [mat, "", ""]]),                                   
279                         ];
280                         for(let moreside of moresides)
281                                 moreside.addFunction((node, x, y) => {return y > ground[x]});
282                         let corners = [
283                                 pm([[mat, ""], ["", "§"]]),
284                                 pm([["", "", mat], ["§", "", ""]]),
285                                 pm([["§", "", ""], ["", "", ""], ["", "", mat]]),
286                                 pm([["§", "", ""], ["", "", ""], ["", "", mat]]),
287                         ];
288                         for(let corner of corners)
289                                 corner.addFunction((node, x, y) => {return y > ground[x]});
290                         for(let i in sides){
291                                 if(Math.random() * 1.2 < 1){
292                                         sides[i].apply(x, y);
293                                         for(let j = i; j <= int(i) + 1; j++){
294                                                 let corner = corners[j] || corners[0];
295                                                 if(Math.random() * 1.5 < 1)
296                                                         corner.apply(x, y);
297                                         }
298                                         if(Math.random() * 2 < 1)
299                                                 moresides[i].apply(x, y);
300                                 }
301                         }
302                 }
303                 for(let material of dragonblocks.mapgen.materials)
304                         for(let i = 0; i < width / material.factor; i++)
305                                 structure(rand(0, width), rand(0, height), material.name);
306         }
307         {
308                  function newcave(x, y){
309                         let r = dblib.random(0, 10) + 1;
310                         if(y < ground[x] + 10)
311                                 return false;
312                         cave(x, y, r);
313                         dragonblocks.mapgen.addStructure("cave", "(" + x + ", " + y + ")", {x: x, y: y});
314                 }
315                 function cave(x, y, r){
316                         r *= 2;
317                         let cavepm = pm([
318                                 ["", "air", "air", "air", ""],
319                                 ["air", "air", "air", "air", "air"],
320                                 ["air", "air", "§air", "air", "air"],
321                                 ["air", "air", "air", "air", "air"],
322                                 ["", "air", "air", "air", ""],
323                         ]);
324                         cavepm.addFunction((node, x, y) =>{
325                                 if(y < ground[x])
326                                         return false;
327                                 if(dblib.random(0, r) == 0)
328                                         cave(x, y, r);
329                         });
330                         cavepm.apply(x, y);
331                 }
332                 let r = dblib.random(width / 5, width / 15);
333                 for(let i = 0; i < r; i++)
334                         newcave(rand(0, width), rand(0, height));
335         }
336 }
337 dragonblocks.mapgen.list["flat"] = function(){
338         for(let x = 0; x < dragonblocks.map.width; x++){
339                 let y = 0;
340                 for(; y < dragonblocks.map.height - 5; y++)
341                         dragonblocks.setNode(x, y, "air");
342                 for(; y < dragonblocks.map.height - 4; y++)
343                         dragonblocks.setNode(x, y, "dirt:grass");
344                 for(; y < dragonblocks.map.height - 3; y++)
345                         dragonblocks.setNode(x, y, "dirt:dirt");
346                 for(; y < dragonblocks.map.height; y++)
347                         dragonblocks.setNode(x, y, "core:stone");
348         }
349 }
350 dragonblocks.mapgen.list["empty"] = function(){}
351