]> git.lizzy.rs Git - dragonfireclient.git/blob - src/script/lua_api/l_mapgen.cpp
Omnicleanup: header cleanup, add ModApiUtil shared between game and mainmenu
[dragonfireclient.git] / src / script / lua_api / l_mapgen.cpp
1 /*
2 Minetest
3 Copyright (C) 2013 celeron55, Perttu Ahola <celeron55@gmail.com>
4
5 This program is free software; you can redistribute it and/or modify
6 it under the terms of the GNU Lesser General Public License as published by
7 the Free Software Foundation; either version 2.1 of the License, or
8 (at your option) any later version.
9
10 This program is distributed in the hope that it will be useful,
11 but WITHOUT ANY WARRANTY; without even the implied warranty of
12 MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the
13 GNU Lesser General Public License for more details.
14
15 You should have received a copy of the GNU Lesser General Public License along
16 with this program; if not, write to the Free Software Foundation, Inc.,
17 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301 USA.
18 */
19
20 #include "lua_api/l_mapgen.h"
21 #include "lua_api/l_internal.h"
22 #include "lua_api/l_vmanip.h"
23 #include "common/c_converter.h"
24 #include "common/c_content.h"
25 #include "server.h"
26 #include "environment.h"
27 #include "biome.h"
28 #include "emerge.h"
29 #include "mapgen_v7.h"
30
31
32 struct EnumString ModApiMapgen::es_BiomeTerrainType[] =
33 {
34         {BIOME_TERRAIN_NORMAL, "normal"},
35         {BIOME_TERRAIN_LIQUID, "liquid"},
36         {BIOME_TERRAIN_NETHER, "nether"},
37         {BIOME_TERRAIN_AETHER, "aether"},
38         {BIOME_TERRAIN_FLAT,   "flat"},
39         {0, NULL},
40 };
41
42 struct EnumString ModApiMapgen::es_DecorationType[] =
43 {
44         {DECO_SIMPLE,    "simple"},
45         {DECO_SCHEMATIC, "schematic"},
46         {DECO_LSYSTEM,   "lsystem"},
47         {0, NULL},
48 };
49
50 struct EnumString ModApiMapgen::es_MapgenObject[] =
51 {
52         {MGOBJ_VMANIP,    "voxelmanip"},
53         {MGOBJ_HEIGHTMAP, "heightmap"},
54         {MGOBJ_BIOMEMAP,  "biomemap"},
55         {MGOBJ_HEATMAP,   "heatmap"},
56         {MGOBJ_HUMIDMAP,  "humiditymap"},
57         {0, NULL},
58 };
59
60 struct EnumString ModApiMapgen::es_OreType[] =
61 {
62         {ORE_SCATTER,  "scatter"},
63         {ORE_SHEET,    "sheet"},
64         {ORE_CLAYLIKE, "claylike"},
65         {0, NULL},
66 };
67
68 struct EnumString ModApiMapgen::es_Rotation[] =
69 {
70         {ROTATE_0,    "0"},
71         {ROTATE_90,   "90"},
72         {ROTATE_180,  "180"},
73         {ROTATE_270,  "270"},
74         {ROTATE_RAND, "random"},
75         {0, NULL},
76 };
77
78
79 // minetest.get_mapgen_object(objectname)
80 // returns the requested object used during map generation
81 int ModApiMapgen::l_get_mapgen_object(lua_State *L)
82 {
83         const char *mgobjstr = lua_tostring(L, 1);
84         
85         int mgobjint;
86         if (!string_to_enum(es_MapgenObject, mgobjint, mgobjstr ? mgobjstr : ""))
87                 return 0;
88                 
89         enum MapgenObject mgobj = (MapgenObject)mgobjint;
90
91         EmergeManager *emerge = getServer(L)->getEmergeManager();
92         Mapgen *mg = emerge->getCurrentMapgen();
93         if (!mg)
94                 return 0;
95         
96         size_t maplen = mg->csize.X * mg->csize.Z;
97         
98         int nargs = 1;
99         
100         switch (mgobj) {
101                 case MGOBJ_VMANIP: {
102                         ManualMapVoxelManipulator *vm = mg->vm;
103                         
104                         // VoxelManip object
105                         LuaVoxelManip *o = new LuaVoxelManip(vm, true);
106                         *(void **)(lua_newuserdata(L, sizeof(void *))) = o;
107                         luaL_getmetatable(L, "VoxelManip");
108                         lua_setmetatable(L, -2);
109                         
110                         // emerged min pos
111                         push_v3s16(L, vm->m_area.MinEdge);
112
113                         // emerged max pos
114                         push_v3s16(L, vm->m_area.MaxEdge);
115                         
116                         nargs = 3;
117                         
118                         break; }
119                 case MGOBJ_HEIGHTMAP: {
120                         if (!mg->heightmap)
121                                 return 0;
122                         
123                         lua_newtable(L);
124                         for (size_t i = 0; i != maplen; i++) {
125                                 lua_pushinteger(L, mg->heightmap[i]);
126                                 lua_rawseti(L, -2, i + 1);
127                         }
128                         break; }
129                 case MGOBJ_BIOMEMAP: {
130                         if (!mg->biomemap)
131                                 return 0;
132                         
133                         lua_newtable(L);
134                         for (size_t i = 0; i != maplen; i++) {
135                                 lua_pushinteger(L, mg->biomemap[i]);
136                                 lua_rawseti(L, -2, i + 1);
137                         }
138                         break; }
139                 case MGOBJ_HEATMAP: { // Mapgen V7 specific objects
140                 case MGOBJ_HUMIDMAP:
141                         if (strcmp(emerge->params->mg_name.c_str(), "v7"))
142                                 return 0;
143                         
144                         MapgenV7 *mgv7 = (MapgenV7 *)mg;
145
146                         float *arr = (mgobj == MGOBJ_HEATMAP) ? 
147                                 mgv7->noise_heat->result : mgv7->noise_humidity->result;
148                         if (!arr)
149                                 return 0;
150                         
151                         lua_newtable(L);
152                         for (size_t i = 0; i != maplen; i++) {
153                                 lua_pushnumber(L, arr[i]);
154                                 lua_rawseti(L, -2, i + 1);
155                         }
156                         break; }
157         }
158         
159         return nargs;
160 }
161
162 // minetest.set_mapgen_params(params)
163 // set mapgen parameters
164 int ModApiMapgen::l_set_mapgen_params(lua_State *L)
165 {
166         if (!lua_istable(L, 1))
167                 return 0;
168
169         EmergeManager *emerge = getServer(L)->getEmergeManager();
170         if (emerge->mapgen.size())
171                 return 0;
172         
173         MapgenParams *oparams = new MapgenParams;
174         u32 paramsmodified = 0;
175         u32 flagmask = 0;
176         
177         lua_getfield(L, 1, "mgname");
178         if (lua_isstring(L, -1)) {
179                 oparams->mg_name = std::string(lua_tostring(L, -1));
180                 paramsmodified |= MGPARAMS_SET_MGNAME;
181         }
182         
183         lua_getfield(L, 1, "seed");
184         if (lua_isnumber(L, -1)) {
185                 oparams->seed = lua_tointeger(L, -1);
186                 paramsmodified |= MGPARAMS_SET_SEED;
187         }
188         
189         lua_getfield(L, 1, "water_level");
190         if (lua_isnumber(L, -1)) {
191                 oparams->water_level = lua_tointeger(L, -1);
192                 paramsmodified |= MGPARAMS_SET_WATER_LEVEL;
193         }
194
195         lua_getfield(L, 1, "flags");
196         if (lua_isstring(L, -1)) {
197                 std::string flagstr = std::string(lua_tostring(L, -1));
198                 oparams->flags = readFlagString(flagstr, flagdesc_mapgen);
199                 paramsmodified |= MGPARAMS_SET_FLAGS;
200         
201                 lua_getfield(L, 1, "flagmask");
202                 if (lua_isstring(L, -1)) {
203                         flagstr = std::string(lua_tostring(L, -1));
204                         flagmask = readFlagString(flagstr, flagdesc_mapgen);
205                 }
206         }
207         
208         emerge->luaoverride_params          = oparams;
209         emerge->luaoverride_params_modified = paramsmodified;
210         emerge->luaoverride_flagmask        = flagmask;
211         
212         return 0;
213 }
214
215 // register_biome({lots of stuff})
216 int ModApiMapgen::l_register_biome(lua_State *L)
217 {
218         int index = 1;
219         luaL_checktype(L, index, LUA_TTABLE);
220
221         BiomeDefManager *bmgr = getServer(L)->getEmergeManager()->biomedef;
222         if (!bmgr) {
223                 verbosestream << "register_biome: BiomeDefManager not active" << std::endl;
224                 return 0;
225         }
226
227         enum BiomeTerrainType terrain = (BiomeTerrainType)getenumfield(L, index,
228                                 "terrain_type", es_BiomeTerrainType, BIOME_TERRAIN_NORMAL);
229         Biome *b = bmgr->createBiome(terrain);
230
231         b->name         = getstringfield_default(L, index, "name",
232                                                                                                 "<no name>");
233         b->nname_top    = getstringfield_default(L, index, "node_top",
234                                                                                                 "mapgen_dirt_with_grass");
235         b->nname_filler = getstringfield_default(L, index, "node_filler",
236                                                                                                 "mapgen_dirt");
237         b->nname_water  = getstringfield_default(L, index, "node_water",
238                                                                                                 "mapgen_water_source");
239         b->nname_dust   = getstringfield_default(L, index, "node_dust",
240                                                                                                 "air");
241         b->nname_dust_water = getstringfield_default(L, index, "node_dust_water",
242                                                                                                 "mapgen_water_source");
243         
244         b->depth_top      = getintfield_default(L, index, "depth_top",    1);
245         b->depth_filler   = getintfield_default(L, index, "depth_filler", 3);
246         b->height_min     = getintfield_default(L, index, "height_min",   0);
247         b->height_max     = getintfield_default(L, index, "height_max",   0);
248         b->heat_point     = getfloatfield_default(L, index, "heat_point",     0.);
249         b->humidity_point = getfloatfield_default(L, index, "humidity_point", 0.);
250
251         b->flags        = 0; //reserved
252         b->c_top        = CONTENT_IGNORE;
253         b->c_filler     = CONTENT_IGNORE;
254         b->c_water      = CONTENT_IGNORE;
255         b->c_dust       = CONTENT_IGNORE;
256         b->c_dust_water = CONTENT_IGNORE;
257         
258         verbosestream << "register_biome: " << b->name << std::endl;
259         bmgr->addBiome(b);
260
261         return 0;
262 }
263
264 // register_decoration({lots of stuff})
265 int ModApiMapgen::l_register_decoration(lua_State *L)
266 {
267         int index = 1;
268         luaL_checktype(L, index, LUA_TTABLE);
269
270         EmergeManager *emerge = getServer(L)->getEmergeManager();
271         BiomeDefManager *bdef = emerge->biomedef;
272
273         enum DecorationType decotype = (DecorationType)getenumfield(L, index,
274                                 "deco_type", es_DecorationType, -1);
275         if (decotype == -1) {
276                 errorstream << "register_decoration: unrecognized "
277                         "decoration placement type";
278                 return 0;
279         }
280         
281         Decoration *deco = createDecoration(decotype);
282         if (!deco) {
283                 errorstream << "register_decoration: decoration placement type "
284                         << decotype << " not implemented";
285                 return 0;
286         }
287
288         deco->c_place_on    = CONTENT_IGNORE;
289         deco->place_on_name = getstringfield_default(L, index, "place_on", "ignore");
290         deco->fill_ratio    = getfloatfield_default(L, index, "fill_ratio", 0.02);
291         deco->sidelen       = getintfield_default(L, index, "sidelen", 8);
292         if (deco->sidelen <= 0) {
293                 errorstream << "register_decoration: sidelen must be "
294                         "greater than 0" << std::endl;
295                 delete deco;
296                 return 0;
297         }
298         
299         lua_getfield(L, index, "noise_params");
300         deco->np = read_noiseparams(L, -1);
301         lua_pop(L, 1);
302         
303         lua_getfield(L, index, "biomes");
304         if (lua_istable(L, -1)) {
305                 lua_pushnil(L);
306                 while (lua_next(L, -2)) {
307                         const char *s = lua_tostring(L, -1);
308                         u8 biomeid = bdef->getBiomeIdByName(s);
309                         if (biomeid)
310                                 deco->biomes.insert(biomeid);
311
312                         lua_pop(L, 1);
313                 }
314                 lua_pop(L, 1);
315         }
316         
317         switch (decotype) {
318                 case DECO_SIMPLE: {
319                         DecoSimple *dsimple = (DecoSimple *)deco;
320                         dsimple->c_deco     = CONTENT_IGNORE;
321                         dsimple->c_spawnby  = CONTENT_IGNORE;
322                         dsimple->spawnby_name    = getstringfield_default(L, index, "spawn_by", "air");
323                         dsimple->deco_height     = getintfield_default(L, index, "height", 1);
324                         dsimple->deco_height_max = getintfield_default(L, index, "height_max", 0);
325                         dsimple->nspawnby        = getintfield_default(L, index, "num_spawn_by", -1);
326                         
327                         lua_getfield(L, index, "decoration");
328                         if (lua_istable(L, -1)) {
329                                 lua_pushnil(L);
330                                 while (lua_next(L, -2)) {
331                                         const char *s = lua_tostring(L, -1);
332                                         std::string str(s);
333                                         dsimple->decolist_names.push_back(str);
334
335                                         lua_pop(L, 1);
336                                 }
337                         } else if (lua_isstring(L, -1)) {
338                                 dsimple->deco_name = std::string(lua_tostring(L, -1));
339                         } else {
340                                 dsimple->deco_name = std::string("air");
341                         }
342                         lua_pop(L, 1);
343                         
344                         if (dsimple->deco_height <= 0) {
345                                 errorstream << "register_decoration: simple decoration height"
346                                         " must be greater than 0" << std::endl;
347                                 delete dsimple;
348                                 return 0;
349                         }
350
351                         break; }
352                 case DECO_SCHEMATIC: {
353                         DecoSchematic *dschem = (DecoSchematic *)deco;
354                         dschem->flags    = getflagsfield(L, index, "flags", flagdesc_deco_schematic);
355                         dschem->rotation = (Rotation)getenumfield(L, index,
356                                                                 "rotation", es_Rotation, ROTATE_0);
357
358                         lua_getfield(L, index, "replacements");
359                         if (lua_istable(L, -1)) {
360                                 int i = lua_gettop(L);
361                                 lua_pushnil(L);
362                                 while (lua_next(L, i) != 0) {
363                                         // key at index -2 and value at index -1
364                                         lua_rawgeti(L, -1, 1);
365                                         std::string replace_from = lua_tostring(L, -1);
366                                         lua_pop(L, 1);
367                                         lua_rawgeti(L, -1, 2);
368                                         std::string replace_to = lua_tostring(L, -1);
369                                         lua_pop(L, 1);
370                                         dschem->replacements[replace_from] = replace_to;
371                                         // removes value, keeps key for next iteration
372                                         lua_pop(L, 1);
373                                 }
374                         }
375                         lua_pop(L, 1);
376
377                         lua_getfield(L, index, "schematic");
378                         if (!read_schematic(L, -1, dschem, getServer(L))) {
379                                 delete dschem;
380                                 return 0;
381                         }
382                         lua_pop(L, -1);
383                         
384                         if (!dschem->filename.empty() && !dschem->loadSchematicFile()) {
385                                 errorstream << "register_decoration: failed to load schematic file '"
386                                         << dschem->filename << "'" << std::endl;
387                                 delete dschem;
388                                 return 0;
389                         }
390                         break; }
391                 case DECO_LSYSTEM: {
392                         //DecoLSystem *decolsystem = (DecoLSystem *)deco;
393                 
394                         break; }
395         }
396
397         emerge->decorations.push_back(deco);
398
399         verbosestream << "register_decoration: decoration '" << deco->getName()
400                 << "' registered" << std::endl;
401         return 0;
402 }
403
404 // register_ore({lots of stuff})
405 int ModApiMapgen::l_register_ore(lua_State *L)
406 {
407         int index = 1;
408         luaL_checktype(L, index, LUA_TTABLE);
409
410         EmergeManager *emerge = getServer(L)->getEmergeManager();
411
412         enum OreType oretype = (OreType)getenumfield(L, index,
413                                 "ore_type", es_OreType, ORE_SCATTER);
414         Ore *ore = createOre(oretype);
415         if (!ore) {
416                 errorstream << "register_ore: ore_type "
417                         << oretype << " not implemented";
418                 return 0;
419         }
420
421         ore->ore_name       = getstringfield_default(L, index, "ore", "");
422         ore->ore_param2     = (u8)getintfield_default(L, index, "ore_param2", 0);
423         ore->clust_scarcity = getintfield_default(L, index, "clust_scarcity", 1);
424         ore->clust_num_ores = getintfield_default(L, index, "clust_num_ores", 1);
425         ore->clust_size     = getintfield_default(L, index, "clust_size", 0);
426         ore->height_min     = getintfield_default(L, index, "height_min", 0);
427         ore->height_max     = getintfield_default(L, index, "height_max", 0);
428         ore->flags          = getflagsfield(L, index, "flags", flagdesc_ore);
429         ore->nthresh        = getfloatfield_default(L, index, "noise_threshhold", 0.);
430
431         lua_getfield(L, index, "wherein");
432         if (lua_istable(L, -1)) {
433                 int  i = lua_gettop(L);
434                 lua_pushnil(L);
435                 while(lua_next(L, i) != 0) {
436                         ore->wherein_names.push_back(lua_tostring(L, -1));
437                         lua_pop(L, 1);
438                 }
439         } else if (lua_isstring(L, -1)) {
440                 ore->wherein_names.push_back(lua_tostring(L, -1));
441         } else {
442                 ore->wherein_names.push_back("");
443         }
444         lua_pop(L, 1);
445
446         lua_getfield(L, index, "noise_params");
447         ore->np = read_noiseparams(L, -1);
448         lua_pop(L, 1);
449
450         ore->noise = NULL;
451
452         if (ore->clust_scarcity <= 0 || ore->clust_num_ores <= 0) {
453                 errorstream << "register_ore: clust_scarcity and clust_num_ores"
454                         "must be greater than 0" << std::endl;
455                 delete ore;
456                 return 0;
457         }
458
459         emerge->ores.push_back(ore);
460
461         verbosestream << "register_ore: ore '" << ore->ore_name
462                 << "' registered" << std::endl;
463         return 0;
464 }
465
466 // create_schematic(p1, p2, probability_list, filename)
467 int ModApiMapgen::l_create_schematic(lua_State *L)
468 {
469         DecoSchematic dschem;
470
471         Map *map = &(getEnv(L)->getMap());
472         INodeDefManager *ndef = getServer(L)->getNodeDefManager();
473
474         v3s16 p1 = read_v3s16(L, 1);
475         v3s16 p2 = read_v3s16(L, 2);
476         sortBoxVerticies(p1, p2);
477         
478         std::vector<std::pair<v3s16, u8> > probability_list;
479         if (lua_istable(L, 3)) {
480                 lua_pushnil(L);
481                 while (lua_next(L, 3)) {
482                         if (lua_istable(L, -1)) {
483                                 lua_getfield(L, -1, "pos");
484                                 v3s16 pos = read_v3s16(L, -1);
485                                 lua_pop(L, 1);
486                                 
487                                 u8 prob = getintfield_default(L, -1, "prob", 0xFF);
488                                 probability_list.push_back(std::make_pair(pos, prob));
489                         }
490
491                         lua_pop(L, 1);
492                 }
493         }
494         
495         dschem.filename = std::string(lua_tostring(L, 4));
496
497         if (!dschem.getSchematicFromMap(map, p1, p2)) {
498                 errorstream << "create_schematic: failed to get schematic "
499                         "from map" << std::endl;
500                 return 0;
501         }
502         
503         dschem.applyProbabilities(&probability_list, p1);
504         
505         dschem.saveSchematicFile(ndef);
506         actionstream << "create_schematic: saved schematic file '"
507                 << dschem.filename << "'." << std::endl;
508
509         return 1;
510 }
511
512
513 // place_schematic(p, schematic, rotation, replacement)
514 int ModApiMapgen::l_place_schematic(lua_State *L)
515 {
516         DecoSchematic dschem;
517
518         Map *map = &(getEnv(L)->getMap());
519         INodeDefManager *ndef = getServer(L)->getNodeDefManager();
520
521         v3s16 p = read_v3s16(L, 1);
522         if (!read_schematic(L, 2, &dschem, getServer(L)))
523                 return 0;
524                 
525         Rotation rot = ROTATE_0;
526         if (lua_isstring(L, 3))
527                 string_to_enum(es_Rotation, (int &)rot, std::string(lua_tostring(L, 3)));
528                 
529         dschem.rotation = rot;
530
531         if (lua_istable(L, 4)) {
532                 int index = 4;
533                 lua_pushnil(L);
534                 while (lua_next(L, index) != 0) {
535                         // key at index -2 and value at index -1
536                         lua_rawgeti(L, -1, 1);
537                         std::string replace_from = lua_tostring(L, -1);
538                         lua_pop(L, 1);
539                         lua_rawgeti(L, -1, 2);
540                         std::string replace_to = lua_tostring(L, -1);
541                         lua_pop(L, 1);
542                         dschem.replacements[replace_from] = replace_to;
543                         // removes value, keeps key for next iteration
544                         lua_pop(L, 1);
545                 }
546         }
547
548         if (!dschem.filename.empty()) {
549                 if (!dschem.loadSchematicFile()) {
550                         errorstream << "place_schematic: failed to load schematic file '"
551                                 << dschem.filename << "'" << std::endl;
552                         return 0;
553                 }
554                 dschem.resolveNodeNames(ndef);
555         }
556         
557         dschem.placeStructure(map, p);
558
559         return 1;
560 }
561
562 void ModApiMapgen::Initialize(lua_State *L, int top)
563 {
564         API_FCT(get_mapgen_object);
565
566         API_FCT(set_mapgen_params);
567
568         API_FCT(register_biome);
569         API_FCT(register_decoration);
570         API_FCT(register_ore);
571
572         API_FCT(create_schematic);
573         API_FCT(place_schematic);
574 }