]> git.lizzy.rs Git - dragonfireclient.git/blob - src/script/common/c_content.cpp
Decoration: Fix schematic probability mess with new MTS file version
[dragonfireclient.git] / src / script / common / c_content.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 #include "common/c_content.h"
20 #include "common/c_converter.h"
21 #include "common/c_types.h"
22 #include "nodedef.h"
23 #include "itemdef.h"
24 #include "object_properties.h"
25 #include "cpp_api/s_node.h"
26 #include "lua_api/l_object.h"
27 #include "lua_api/l_item.h"
28 #include "common/c_internal.h"
29 #include "server.h"
30 #include "log.h"
31 #include "tool.h"
32 #include "server.h"
33 #include "mapgen.h"
34
35 struct EnumString es_TileAnimationType[] =
36 {
37         {TAT_NONE, "none"},
38         {TAT_VERTICAL_FRAMES, "vertical_frames"},
39         {0, NULL},
40 };
41
42 /******************************************************************************/
43 ItemDefinition read_item_definition(lua_State* L,int index,
44                 ItemDefinition default_def)
45 {
46         if(index < 0)
47                 index = lua_gettop(L) + 1 + index;
48
49         // Read the item definition
50         ItemDefinition def = default_def;
51
52         def.type = (ItemType)getenumfield(L, index, "type",
53                         es_ItemType, ITEM_NONE);
54         getstringfield(L, index, "name", def.name);
55         getstringfield(L, index, "description", def.description);
56         getstringfield(L, index, "inventory_image", def.inventory_image);
57         getstringfield(L, index, "wield_image", def.wield_image);
58
59         lua_getfield(L, index, "wield_scale");
60         if(lua_istable(L, -1)){
61                 def.wield_scale = check_v3f(L, -1);
62         }
63         lua_pop(L, 1);
64
65         def.stack_max = getintfield_default(L, index, "stack_max", def.stack_max);
66         if(def.stack_max == 0)
67                 def.stack_max = 1;
68
69         lua_getfield(L, index, "on_use");
70         def.usable = lua_isfunction(L, -1);
71         lua_pop(L, 1);
72
73         getboolfield(L, index, "liquids_pointable", def.liquids_pointable);
74
75         warn_if_field_exists(L, index, "tool_digging_properties",
76                         "deprecated: use tool_capabilities");
77
78         lua_getfield(L, index, "tool_capabilities");
79         if(lua_istable(L, -1)){
80                 def.tool_capabilities = new ToolCapabilities(
81                                 read_tool_capabilities(L, -1));
82         }
83
84         // If name is "" (hand), ensure there are ToolCapabilities
85         // because it will be looked up there whenever any other item has
86         // no ToolCapabilities
87         if(def.name == "" && def.tool_capabilities == NULL){
88                 def.tool_capabilities = new ToolCapabilities();
89         }
90
91         lua_getfield(L, index, "groups");
92         read_groups(L, -1, def.groups);
93         lua_pop(L, 1);
94
95         lua_getfield(L, index, "sounds");
96         if(lua_istable(L, -1)){
97                 lua_getfield(L, -1, "place");
98                 read_soundspec(L, -1, def.sound_place);
99                 lua_pop(L, 1);
100         }
101         lua_pop(L, 1);
102
103         def.range = getfloatfield_default(L, index, "range", def.range);
104
105         // Client shall immediately place this node when player places the item.
106         // Server will update the precise end result a moment later.
107         // "" = no prediction
108         getstringfield(L, index, "node_placement_prediction",
109                         def.node_placement_prediction);
110
111         return def;
112 }
113
114 /******************************************************************************/
115 void read_object_properties(lua_State *L, int index,
116                 ObjectProperties *prop)
117 {
118         if(index < 0)
119                 index = lua_gettop(L) + 1 + index;
120         if(!lua_istable(L, index))
121                 return;
122
123         prop->hp_max = getintfield_default(L, -1, "hp_max", 10);
124
125         getboolfield(L, -1, "physical", prop->physical);
126         getboolfield(L, -1, "collide_with_objects", prop->collideWithObjects);
127
128         getfloatfield(L, -1, "weight", prop->weight);
129
130         lua_getfield(L, -1, "collisionbox");
131         if(lua_istable(L, -1))
132                 prop->collisionbox = read_aabb3f(L, -1, 1.0);
133         lua_pop(L, 1);
134
135         getstringfield(L, -1, "visual", prop->visual);
136
137         getstringfield(L, -1, "mesh", prop->mesh);
138
139         lua_getfield(L, -1, "visual_size");
140         if(lua_istable(L, -1))
141                 prop->visual_size = read_v2f(L, -1);
142         lua_pop(L, 1);
143
144         lua_getfield(L, -1, "textures");
145         if(lua_istable(L, -1)){
146                 prop->textures.clear();
147                 int table = lua_gettop(L);
148                 lua_pushnil(L);
149                 while(lua_next(L, table) != 0){
150                         // key at index -2 and value at index -1
151                         if(lua_isstring(L, -1))
152                                 prop->textures.push_back(lua_tostring(L, -1));
153                         else
154                                 prop->textures.push_back("");
155                         // removes value, keeps key for next iteration
156                         lua_pop(L, 1);
157                 }
158         }
159         lua_pop(L, 1);
160
161         lua_getfield(L, -1, "colors");
162         if(lua_istable(L, -1)){
163                 prop->colors.clear();
164                 int table = lua_gettop(L);
165                 lua_pushnil(L);
166                 while(lua_next(L, table) != 0){
167                         // key at index -2 and value at index -1
168                         if(lua_isstring(L, -1))
169                                 prop->colors.push_back(readARGB8(L, -1));
170                         else
171                                 prop->colors.push_back(video::SColor(255, 255, 255, 255));
172                         // removes value, keeps key for next iteration
173                         lua_pop(L, 1);
174                 }
175         }
176         lua_pop(L, 1);
177
178         lua_getfield(L, -1, "spritediv");
179         if(lua_istable(L, -1))
180                 prop->spritediv = read_v2s16(L, -1);
181         lua_pop(L, 1);
182
183         lua_getfield(L, -1, "initial_sprite_basepos");
184         if(lua_istable(L, -1))
185                 prop->initial_sprite_basepos = read_v2s16(L, -1);
186         lua_pop(L, 1);
187
188         getboolfield(L, -1, "is_visible", prop->is_visible);
189         getboolfield(L, -1, "makes_footstep_sound", prop->makes_footstep_sound);
190         getfloatfield(L, -1, "automatic_rotate", prop->automatic_rotate);
191         getfloatfield(L, -1, "stepheight", prop->stepheight);
192         prop->stepheight*=BS;
193 }
194
195 /******************************************************************************/
196 TileDef read_tiledef(lua_State *L, int index)
197 {
198         if(index < 0)
199                 index = lua_gettop(L) + 1 + index;
200
201         TileDef tiledef;
202
203         // key at index -2 and value at index
204         if(lua_isstring(L, index)){
205                 // "default_lava.png"
206                 tiledef.name = lua_tostring(L, index);
207         }
208         else if(lua_istable(L, index))
209         {
210                 // {name="default_lava.png", animation={}}
211                 tiledef.name = "";
212                 getstringfield(L, index, "name", tiledef.name);
213                 getstringfield(L, index, "image", tiledef.name); // MaterialSpec compat.
214                 tiledef.backface_culling = getboolfield_default(
215                                         L, index, "backface_culling", true);
216                 // animation = {}
217                 lua_getfield(L, index, "animation");
218                 if(lua_istable(L, -1)){
219                         // {type="vertical_frames", aspect_w=16, aspect_h=16, length=2.0}
220                         tiledef.animation.type = (TileAnimationType)
221                                         getenumfield(L, -1, "type", es_TileAnimationType,
222                                         TAT_NONE);
223                         tiledef.animation.aspect_w =
224                                         getintfield_default(L, -1, "aspect_w", 16);
225                         tiledef.animation.aspect_h =
226                                         getintfield_default(L, -1, "aspect_h", 16);
227                         tiledef.animation.length =
228                                         getfloatfield_default(L, -1, "length", 1.0);
229                 }
230                 lua_pop(L, 1);
231         }
232
233         return tiledef;
234 }
235
236 /******************************************************************************/
237 ContentFeatures read_content_features(lua_State *L, int index)
238 {
239         if(index < 0)
240                 index = lua_gettop(L) + 1 + index;
241
242         ContentFeatures f;
243
244         /* Cache existence of some callbacks */
245         lua_getfield(L, index, "on_construct");
246         if(!lua_isnil(L, -1)) f.has_on_construct = true;
247         lua_pop(L, 1);
248         lua_getfield(L, index, "on_destruct");
249         if(!lua_isnil(L, -1)) f.has_on_destruct = true;
250         lua_pop(L, 1);
251         lua_getfield(L, index, "after_destruct");
252         if(!lua_isnil(L, -1)) f.has_after_destruct = true;
253         lua_pop(L, 1);
254
255         lua_getfield(L, index, "on_rightclick");
256         f.rightclickable = lua_isfunction(L, -1);
257         lua_pop(L, 1);
258         
259         /* Name */
260         getstringfield(L, index, "name", f.name);
261
262         /* Groups */
263         lua_getfield(L, index, "groups");
264         read_groups(L, -1, f.groups);
265         lua_pop(L, 1);
266
267         /* Visual definition */
268
269         f.drawtype = (NodeDrawType)getenumfield(L, index, "drawtype",
270                         ScriptApiNode::es_DrawType,NDT_NORMAL);
271         getfloatfield(L, index, "visual_scale", f.visual_scale);
272
273         // tiles = {}
274         lua_getfield(L, index, "tiles");
275         // If nil, try the deprecated name "tile_images" instead
276         if(lua_isnil(L, -1)){
277                 lua_pop(L, 1);
278                 warn_if_field_exists(L, index, "tile_images",
279                                 "Deprecated; new name is \"tiles\".");
280                 lua_getfield(L, index, "tile_images");
281         }
282         if(lua_istable(L, -1)){
283                 int table = lua_gettop(L);
284                 lua_pushnil(L);
285                 int i = 0;
286                 while(lua_next(L, table) != 0){
287                         // Read tiledef from value
288                         f.tiledef[i] = read_tiledef(L, -1);
289                         // removes value, keeps key for next iteration
290                         lua_pop(L, 1);
291                         i++;
292                         if(i==6){
293                                 lua_pop(L, 1);
294                                 break;
295                         }
296                 }
297                 // Copy last value to all remaining textures
298                 if(i >= 1){
299                         TileDef lasttile = f.tiledef[i-1];
300                         while(i < 6){
301                                 f.tiledef[i] = lasttile;
302                                 i++;
303                         }
304                 }
305         }
306         lua_pop(L, 1);
307
308         // special_tiles = {}
309         lua_getfield(L, index, "special_tiles");
310         // If nil, try the deprecated name "special_materials" instead
311         if(lua_isnil(L, -1)){
312                 lua_pop(L, 1);
313                 warn_if_field_exists(L, index, "special_materials",
314                                 "Deprecated; new name is \"special_tiles\".");
315                 lua_getfield(L, index, "special_materials");
316         }
317         if(lua_istable(L, -1)){
318                 int table = lua_gettop(L);
319                 lua_pushnil(L);
320                 int i = 0;
321                 while(lua_next(L, table) != 0){
322                         // Read tiledef from value
323                         f.tiledef_special[i] = read_tiledef(L, -1);
324                         // removes value, keeps key for next iteration
325                         lua_pop(L, 1);
326                         i++;
327                         if(i==6){
328                                 lua_pop(L, 1);
329                                 break;
330                         }
331                 }
332         }
333         lua_pop(L, 1);
334
335         f.alpha = getintfield_default(L, index, "alpha", 255);
336
337         bool usealpha = getboolfield_default(L, index,
338                         "use_texture_alpha", false);
339         if (usealpha)
340                 f.alpha = 0;
341
342         /* Other stuff */
343
344         lua_getfield(L, index, "post_effect_color");
345         if(!lua_isnil(L, -1))
346                 f.post_effect_color = readARGB8(L, -1);
347         lua_pop(L, 1);
348
349         f.param_type = (ContentParamType)getenumfield(L, index, "paramtype",
350                         ScriptApiNode::es_ContentParamType, CPT_NONE);
351         f.param_type_2 = (ContentParamType2)getenumfield(L, index, "paramtype2",
352                         ScriptApiNode::es_ContentParamType2, CPT2_NONE);
353
354         // Warn about some deprecated fields
355         warn_if_field_exists(L, index, "wall_mounted",
356                         "deprecated: use paramtype2 = 'wallmounted'");
357         warn_if_field_exists(L, index, "light_propagates",
358                         "deprecated: determined from paramtype");
359         warn_if_field_exists(L, index, "dug_item",
360                         "deprecated: use 'drop' field");
361         warn_if_field_exists(L, index, "extra_dug_item",
362                         "deprecated: use 'drop' field");
363         warn_if_field_exists(L, index, "extra_dug_item_rarity",
364                         "deprecated: use 'drop' field");
365         warn_if_field_exists(L, index, "metadata_name",
366                         "deprecated: use on_add and metadata callbacks");
367
368         // True for all ground-like things like stone and mud, false for eg. trees
369         getboolfield(L, index, "is_ground_content", f.is_ground_content);
370         f.light_propagates = (f.param_type == CPT_LIGHT);
371         getboolfield(L, index, "sunlight_propagates", f.sunlight_propagates);
372         // This is used for collision detection.
373         // Also for general solidness queries.
374         getboolfield(L, index, "walkable", f.walkable);
375         // Player can point to these
376         getboolfield(L, index, "pointable", f.pointable);
377         // Player can dig these
378         getboolfield(L, index, "diggable", f.diggable);
379         // Player can climb these
380         getboolfield(L, index, "climbable", f.climbable);
381         // Player can build on these
382         getboolfield(L, index, "buildable_to", f.buildable_to);
383         // Whether the node is non-liquid, source liquid or flowing liquid
384         f.liquid_type = (LiquidType)getenumfield(L, index, "liquidtype",
385                         ScriptApiNode::es_LiquidType, LIQUID_NONE);
386         // If the content is liquid, this is the flowing version of the liquid.
387         getstringfield(L, index, "liquid_alternative_flowing",
388                         f.liquid_alternative_flowing);
389         // If the content is liquid, this is the source version of the liquid.
390         getstringfield(L, index, "liquid_alternative_source",
391                         f.liquid_alternative_source);
392         // Viscosity for fluid flow, ranging from 1 to 7, with
393         // 1 giving almost instantaneous propagation and 7 being
394         // the slowest possible
395         f.liquid_viscosity = getintfield_default(L, index,
396                         "liquid_viscosity", f.liquid_viscosity);
397         f.liquid_range = getintfield_default(L, index,
398                         "liquid_range", f.liquid_range);
399         f.leveled = getintfield_default(L, index, "leveled", f.leveled);
400
401         getboolfield(L, index, "liquid_renewable", f.liquid_renewable);
402         getstringfield(L, index, "freezemelt", f.freezemelt);
403         f.drowning = getintfield_default(L, index,
404                         "drowning", f.drowning);
405         // Amount of light the node emits
406         f.light_source = getintfield_default(L, index,
407                         "light_source", f.light_source);
408         f.damage_per_second = getintfield_default(L, index,
409                         "damage_per_second", f.damage_per_second);
410
411         lua_getfield(L, index, "node_box");
412         if(lua_istable(L, -1))
413                 f.node_box = read_nodebox(L, -1);
414         lua_pop(L, 1);
415
416         lua_getfield(L, index, "selection_box");
417         if(lua_istable(L, -1))
418                 f.selection_box = read_nodebox(L, -1);
419         lua_pop(L, 1);
420
421         // Set to true if paramtype used to be 'facedir_simple'
422         getboolfield(L, index, "legacy_facedir_simple", f.legacy_facedir_simple);
423         // Set to true if wall_mounted used to be set to true
424         getboolfield(L, index, "legacy_wallmounted", f.legacy_wallmounted);
425
426         // Sound table
427         lua_getfield(L, index, "sounds");
428         if(lua_istable(L, -1)){
429                 lua_getfield(L, -1, "footstep");
430                 read_soundspec(L, -1, f.sound_footstep);
431                 lua_pop(L, 1);
432                 lua_getfield(L, -1, "dig");
433                 read_soundspec(L, -1, f.sound_dig);
434                 lua_pop(L, 1);
435                 lua_getfield(L, -1, "dug");
436                 read_soundspec(L, -1, f.sound_dug);
437                 lua_pop(L, 1);
438         }
439         lua_pop(L, 1);
440
441         return f;
442 }
443
444 /******************************************************************************/
445 void read_server_sound_params(lua_State *L, int index,
446                 ServerSoundParams &params)
447 {
448         if(index < 0)
449                 index = lua_gettop(L) + 1 + index;
450         // Clear
451         params = ServerSoundParams();
452         if(lua_istable(L, index)){
453                 getfloatfield(L, index, "gain", params.gain);
454                 getstringfield(L, index, "to_player", params.to_player);
455                 lua_getfield(L, index, "pos");
456                 if(!lua_isnil(L, -1)){
457                         v3f p = read_v3f(L, -1)*BS;
458                         params.pos = p;
459                         params.type = ServerSoundParams::SSP_POSITIONAL;
460                 }
461                 lua_pop(L, 1);
462                 lua_getfield(L, index, "object");
463                 if(!lua_isnil(L, -1)){
464                         ObjectRef *ref = ObjectRef::checkobject(L, -1);
465                         ServerActiveObject *sao = ObjectRef::getobject(ref);
466                         if(sao){
467                                 params.object = sao->getId();
468                                 params.type = ServerSoundParams::SSP_OBJECT;
469                         }
470                 }
471                 lua_pop(L, 1);
472                 params.max_hear_distance = BS*getfloatfield_default(L, index,
473                                 "max_hear_distance", params.max_hear_distance/BS);
474                 getboolfield(L, index, "loop", params.loop);
475         }
476 }
477
478 /******************************************************************************/
479 void read_soundspec(lua_State *L, int index, SimpleSoundSpec &spec)
480 {
481         if(index < 0)
482                 index = lua_gettop(L) + 1 + index;
483         if(lua_isnil(L, index)){
484         } else if(lua_istable(L, index)){
485                 getstringfield(L, index, "name", spec.name);
486                 getfloatfield(L, index, "gain", spec.gain);
487         } else if(lua_isstring(L, index)){
488                 spec.name = lua_tostring(L, index);
489         }
490 }
491
492 /******************************************************************************/
493 NodeBox read_nodebox(lua_State *L, int index)
494 {
495         NodeBox nodebox;
496         if(lua_istable(L, -1)){
497                 nodebox.type = (NodeBoxType)getenumfield(L, index, "type",
498                                 ScriptApiNode::es_NodeBoxType, NODEBOX_REGULAR);
499
500                 lua_getfield(L, index, "fixed");
501                 if(lua_istable(L, -1))
502                         nodebox.fixed = read_aabb3f_vector(L, -1, BS);
503                 lua_pop(L, 1);
504
505                 lua_getfield(L, index, "wall_top");
506                 if(lua_istable(L, -1))
507                         nodebox.wall_top = read_aabb3f(L, -1, BS);
508                 lua_pop(L, 1);
509
510                 lua_getfield(L, index, "wall_bottom");
511                 if(lua_istable(L, -1))
512                         nodebox.wall_bottom = read_aabb3f(L, -1, BS);
513                 lua_pop(L, 1);
514
515                 lua_getfield(L, index, "wall_side");
516                 if(lua_istable(L, -1))
517                         nodebox.wall_side = read_aabb3f(L, -1, BS);
518                 lua_pop(L, 1);
519         }
520         return nodebox;
521 }
522
523 /******************************************************************************/
524 MapNode readnode(lua_State *L, int index, INodeDefManager *ndef)
525 {
526         lua_getfield(L, index, "name");
527         const char *name = luaL_checkstring(L, -1);
528         lua_pop(L, 1);
529         u8 param1;
530         lua_getfield(L, index, "param1");
531         if(lua_isnil(L, -1))
532                 param1 = 0;
533         else
534                 param1 = lua_tonumber(L, -1);
535         lua_pop(L, 1);
536         u8 param2;
537         lua_getfield(L, index, "param2");
538         if(lua_isnil(L, -1))
539                 param2 = 0;
540         else
541                 param2 = lua_tonumber(L, -1);
542         lua_pop(L, 1);
543         return MapNode(ndef, name, param1, param2);
544 }
545
546 /******************************************************************************/
547 void pushnode(lua_State *L, const MapNode &n, INodeDefManager *ndef)
548 {
549         lua_newtable(L);
550         lua_pushstring(L, ndef->get(n).name.c_str());
551         lua_setfield(L, -2, "name");
552         lua_pushnumber(L, n.getParam1());
553         lua_setfield(L, -2, "param1");
554         lua_pushnumber(L, n.getParam2());
555         lua_setfield(L, -2, "param2");
556 }
557
558 /******************************************************************************/
559 void warn_if_field_exists(lua_State *L, int table,
560                 const char *fieldname, const std::string &message)
561 {
562         lua_getfield(L, table, fieldname);
563         if(!lua_isnil(L, -1)){
564 //TODO find way to access backtrace fct from here
565                 //              infostream<<script_get_backtrace(L)<<std::endl;
566                 infostream<<"WARNING: field \""<<fieldname<<"\": "
567                                 <<message<<std::endl;
568         }
569         lua_pop(L, 1);
570 }
571
572 /******************************************************************************/
573 int getenumfield(lua_State *L, int table,
574                 const char *fieldname, const EnumString *spec, int default_)
575 {
576         int result = default_;
577         string_to_enum(spec, result,
578                         getstringfield_default(L, table, fieldname, ""));
579         return result;
580 }
581
582 /******************************************************************************/
583 bool string_to_enum(const EnumString *spec, int &result,
584                 const std::string &str)
585 {
586         const EnumString *esp = spec;
587         while(esp->str){
588                 if(str == std::string(esp->str)){
589                         result = esp->num;
590                         return true;
591                 }
592                 esp++;
593         }
594         return false;
595 }
596
597 /******************************************************************************/
598 ItemStack read_item(lua_State* L, int index,Server* srv)
599 {
600         if(index < 0)
601                 index = lua_gettop(L) + 1 + index;
602
603         if(lua_isnil(L, index))
604         {
605                 return ItemStack();
606         }
607         else if(lua_isuserdata(L, index))
608         {
609                 // Convert from LuaItemStack
610                 LuaItemStack *o = LuaItemStack::checkobject(L, index);
611                 return o->getItem();
612         }
613         else if(lua_isstring(L, index))
614         {
615                 // Convert from itemstring
616                 std::string itemstring = lua_tostring(L, index);
617                 IItemDefManager *idef = srv->idef();
618                 try
619                 {
620                         ItemStack item;
621                         item.deSerialize(itemstring, idef);
622                         return item;
623                 }
624                 catch(SerializationError &e)
625                 {
626                         infostream<<"WARNING: unable to create item from itemstring"
627                                         <<": "<<itemstring<<std::endl;
628                         return ItemStack();
629                 }
630         }
631         else if(lua_istable(L, index))
632         {
633                 // Convert from table
634                 IItemDefManager *idef = srv->idef();
635                 std::string name = getstringfield_default(L, index, "name", "");
636                 int count = getintfield_default(L, index, "count", 1);
637                 int wear = getintfield_default(L, index, "wear", 0);
638                 std::string metadata = getstringfield_default(L, index, "metadata", "");
639                 return ItemStack(name, count, wear, metadata, idef);
640         }
641         else
642         {
643                 throw LuaError(L, "Expecting itemstack, itemstring, table or nil");
644         }
645 }
646
647 /******************************************************************************/
648 void push_tool_capabilities(lua_State *L,
649                 const ToolCapabilities &toolcap)
650 {
651         lua_newtable(L);
652         setfloatfield(L, -1, "full_punch_interval", toolcap.full_punch_interval);
653                 setintfield(L, -1, "max_drop_level", toolcap.max_drop_level);
654                 // Create groupcaps table
655                 lua_newtable(L);
656                 // For each groupcap
657                 for(std::map<std::string, ToolGroupCap>::const_iterator
658                                 i = toolcap.groupcaps.begin(); i != toolcap.groupcaps.end(); i++){
659                         // Create groupcap table
660                         lua_newtable(L);
661                         const std::string &name = i->first;
662                         const ToolGroupCap &groupcap = i->second;
663                         // Create subtable "times"
664                         lua_newtable(L);
665                         for(std::map<int, float>::const_iterator
666                                         i = groupcap.times.begin(); i != groupcap.times.end(); i++){
667                                 int rating = i->first;
668                                 float time = i->second;
669                                 lua_pushinteger(L, rating);
670                                 lua_pushnumber(L, time);
671                                 lua_settable(L, -3);
672                         }
673                         // Set subtable "times"
674                         lua_setfield(L, -2, "times");
675                         // Set simple parameters
676                         setintfield(L, -1, "maxlevel", groupcap.maxlevel);
677                         setintfield(L, -1, "uses", groupcap.uses);
678                         // Insert groupcap table into groupcaps table
679                         lua_setfield(L, -2, name.c_str());
680                 }
681                 // Set groupcaps table
682                 lua_setfield(L, -2, "groupcaps");
683                 //Create damage_groups table
684                 lua_newtable(L);
685                 // For each damage group
686                 for(std::map<std::string, s16>::const_iterator
687                                 i = toolcap.damageGroups.begin(); i != toolcap.damageGroups.end(); i++){
688                         // Create damage group table
689                         lua_pushinteger(L, i->second);
690                         lua_setfield(L, -2, i->first.c_str());
691                 }
692                 lua_setfield(L, -2, "damage_groups");
693 }
694
695 /******************************************************************************/
696 void push_inventory_list(Inventory *inv, const char *name,
697                 lua_State *L)
698 {
699         InventoryList *invlist = inv->getList(name);
700         if(invlist == NULL){
701                 lua_pushnil(L);
702                 return;
703         }
704         std::vector<ItemStack> items;
705         for(u32 i=0; i<invlist->getSize(); i++)
706                 items.push_back(invlist->getItem(i));
707         push_items(L, items);
708 }
709
710 /******************************************************************************/
711 void read_inventory_list(Inventory *inv, const char *name,
712                 lua_State *L, int tableindex, Server* srv,int forcesize)
713 {
714         if(tableindex < 0)
715                 tableindex = lua_gettop(L) + 1 + tableindex;
716         // If nil, delete list
717         if(lua_isnil(L, tableindex)){
718                 inv->deleteList(name);
719                 return;
720         }
721         // Otherwise set list
722         std::vector<ItemStack> items = read_items(L, tableindex,srv);
723         int listsize = (forcesize != -1) ? forcesize : items.size();
724         InventoryList *invlist = inv->addList(name, listsize);
725         int index = 0;
726         for(std::vector<ItemStack>::const_iterator
727                         i = items.begin(); i != items.end(); i++){
728                 if(forcesize != -1 && index == forcesize)
729                         break;
730                 invlist->changeItem(index, *i);
731                 index++;
732         }
733         while(forcesize != -1 && index < forcesize){
734                 invlist->deleteItem(index);
735                 index++;
736         }
737 }
738
739 /******************************************************************************/
740 ToolCapabilities read_tool_capabilities(
741                 lua_State *L, int table)
742 {
743         ToolCapabilities toolcap;
744         getfloatfield(L, table, "full_punch_interval", toolcap.full_punch_interval);
745         getintfield(L, table, "max_drop_level", toolcap.max_drop_level);
746         lua_getfield(L, table, "groupcaps");
747         if(lua_istable(L, -1)){
748                 int table_groupcaps = lua_gettop(L);
749                 lua_pushnil(L);
750                 while(lua_next(L, table_groupcaps) != 0){
751                         // key at index -2 and value at index -1
752                         std::string groupname = luaL_checkstring(L, -2);
753                         if(lua_istable(L, -1)){
754                                 int table_groupcap = lua_gettop(L);
755                                 // This will be created
756                                 ToolGroupCap groupcap;
757                                 // Read simple parameters
758                                 getintfield(L, table_groupcap, "maxlevel", groupcap.maxlevel);
759                                 getintfield(L, table_groupcap, "uses", groupcap.uses);
760                                 // DEPRECATED: maxwear
761                                 float maxwear = 0;
762                                 if(getfloatfield(L, table_groupcap, "maxwear", maxwear)){
763                                         if(maxwear != 0)
764                                                 groupcap.uses = 1.0/maxwear;
765                                         else
766                                                 groupcap.uses = 0;
767                                         infostream<<script_get_backtrace(L)<<std::endl;
768                                         infostream<<"WARNING: field \"maxwear\" is deprecated; "
769                                                         <<"should replace with uses=1/maxwear"<<std::endl;
770                                 }
771                                 // Read "times" table
772                                 lua_getfield(L, table_groupcap, "times");
773                                 if(lua_istable(L, -1)){
774                                         int table_times = lua_gettop(L);
775                                         lua_pushnil(L);
776                                         while(lua_next(L, table_times) != 0){
777                                                 // key at index -2 and value at index -1
778                                                 int rating = luaL_checkinteger(L, -2);
779                                                 float time = luaL_checknumber(L, -1);
780                                                 groupcap.times[rating] = time;
781                                                 // removes value, keeps key for next iteration
782                                                 lua_pop(L, 1);
783                                         }
784                                 }
785                                 lua_pop(L, 1);
786                                 // Insert groupcap into toolcap
787                                 toolcap.groupcaps[groupname] = groupcap;
788                         }
789                         // removes value, keeps key for next iteration
790                         lua_pop(L, 1);
791                 }
792         }
793         lua_pop(L, 1);
794
795         lua_getfield(L, table, "damage_groups");
796         if(lua_istable(L, -1)){
797                 int table_damage_groups = lua_gettop(L);
798                 lua_pushnil(L);
799                 while(lua_next(L, table_damage_groups) != 0){
800                         // key at index -2 and value at index -1
801                         std::string groupname = luaL_checkstring(L, -2);
802                         u16 value = luaL_checkinteger(L, -1);
803                         toolcap.damageGroups[groupname] = value;
804                         // removes value, keeps key for next iteration
805                         lua_pop(L, 1);
806                 }
807         }
808         lua_pop(L, 1);
809         return toolcap;
810 }
811
812 /******************************************************************************/
813 void push_dig_params(lua_State *L,const DigParams &params)
814 {
815         lua_newtable(L);
816         setboolfield(L, -1, "diggable", params.diggable);
817         setfloatfield(L, -1, "time", params.time);
818         setintfield(L, -1, "wear", params.wear);
819 }
820
821 /******************************************************************************/
822 void push_hit_params(lua_State *L,const HitParams &params)
823 {
824         lua_newtable(L);
825         setintfield(L, -1, "hp", params.hp);
826         setintfield(L, -1, "wear", params.wear);
827 }
828
829 /******************************************************************************/
830 u32 getflagsfield(lua_State *L, int table,
831         const char *fieldname, FlagDesc *flagdesc) {
832         std::string flagstring;
833
834         flagstring = getstringfield_default(L, table, fieldname, "");
835         return readFlagString(flagstring, flagdesc);
836 }
837
838 /******************************************************************************/
839 /* Lua Stored data!                                                           */
840 /******************************************************************************/
841
842 /******************************************************************************/
843 void read_groups(lua_State *L, int index,
844                 std::map<std::string, int> &result)
845 {
846         if (!lua_istable(L,index))
847                 return;
848         result.clear();
849         lua_pushnil(L);
850         if(index < 0)
851                 index -= 1;
852         while(lua_next(L, index) != 0){
853                 // key at index -2 and value at index -1
854                 std::string name = luaL_checkstring(L, -2);
855                 int rating = luaL_checkinteger(L, -1);
856                 result[name] = rating;
857                 // removes value, keeps key for next iteration
858                 lua_pop(L, 1);
859         }
860 }
861
862 /******************************************************************************/
863 void push_items(lua_State *L, const std::vector<ItemStack> &items)
864 {
865         // Get the table insert function
866         lua_getglobal(L, "table");
867         lua_getfield(L, -1, "insert");
868         int table_insert = lua_gettop(L);
869         // Create and fill table
870         lua_newtable(L);
871         int table = lua_gettop(L);
872         for(u32 i=0; i<items.size(); i++){
873                 ItemStack item = items[i];
874                 lua_pushvalue(L, table_insert);
875                 lua_pushvalue(L, table);
876                 LuaItemStack::create(L, item);
877                 if(lua_pcall(L, 2, 0, 0))
878                         script_error(L, "error: %s", lua_tostring(L, -1));
879         }
880         lua_remove(L, -2); // Remove table
881         lua_remove(L, -2); // Remove insert
882 }
883
884 /******************************************************************************/
885 std::vector<ItemStack> read_items(lua_State *L, int index,Server* srv)
886 {
887         if(index < 0)
888                 index = lua_gettop(L) + 1 + index;
889
890         std::vector<ItemStack> items;
891         luaL_checktype(L, index, LUA_TTABLE);
892         lua_pushnil(L);
893         while(lua_next(L, index) != 0){
894                 // key at index -2 and value at index -1
895                 items.push_back(read_item(L, -1, srv));
896                 // removes value, keeps key for next iteration
897                 lua_pop(L, 1);
898         }
899         return items;
900 }
901
902 /******************************************************************************/
903 void luaentity_get(lua_State *L, u16 id)
904 {
905         // Get minetest.luaentities[i]
906         lua_getglobal(L, "minetest");
907         lua_getfield(L, -1, "luaentities");
908         luaL_checktype(L, -1, LUA_TTABLE);
909         lua_pushnumber(L, id);
910         lua_gettable(L, -2);
911         lua_remove(L, -2); // luaentities
912         lua_remove(L, -2); // minetest
913 }
914
915 /******************************************************************************/
916 NoiseParams *read_noiseparams(lua_State *L, int index)
917 {
918         if (index < 0)
919                 index = lua_gettop(L) + 1 + index;
920
921         if (!lua_istable(L, index))
922                 return NULL;
923
924         NoiseParams *np = new NoiseParams;
925
926         np->offset  = getfloatfield_default(L, index, "offset", 0.0);
927         np->scale   = getfloatfield_default(L, index, "scale", 0.0);
928         lua_getfield(L, index, "spread");
929         np->spread  = read_v3f(L, -1);
930         lua_pop(L, 1);
931         np->seed    = getintfield_default(L, index, "seed", 0);
932         np->octaves = getintfield_default(L, index, "octaves", 0);
933         np->persist = getfloatfield_default(L, index, "persist", 0.0);
934
935         return np;
936 }
937
938 /******************************************************************************/
939 bool read_schematic(lua_State *L, int index, DecoSchematic *dschem, Server *server) {
940         if (index < 0)
941                 index = lua_gettop(L) + 1 + index;
942
943         INodeDefManager *ndef = server->getNodeDefManager();
944
945         if (lua_istable(L, index)) {
946                 lua_getfield(L, index, "size");
947                 v3s16 size = read_v3s16(L, -1);
948                 lua_pop(L, 1);
949                 
950                 int numnodes = size.X * size.Y * size.Z;
951                 MapNode *schemdata = new MapNode[numnodes];
952                 int i = 0;
953                 
954                 lua_getfield(L, index, "data");
955                 luaL_checktype(L, -1, LUA_TTABLE);
956                 
957                 lua_pushnil(L);
958                 while (lua_next(L, -2)) {
959                         if (i < numnodes) {
960                                 // same as readnode, except param1 default is MTSCHEM_PROB_CONST
961                                 lua_getfield(L, -1, "name");
962                                 const char *name = luaL_checkstring(L, -1);
963                                 lua_pop(L, 1);
964                                 
965                                 u8 param1;
966                                 lua_getfield(L, -1, "param1");
967                                 param1 = !lua_isnil(L, -1) ? lua_tonumber(L, -1) : MTSCHEM_PROB_ALWAYS;
968                                 lua_pop(L, 1);
969         
970                                 u8 param2;
971                                 lua_getfield(L, -1, "param2");
972                                 param2 = !lua_isnil(L, -1) ? lua_tonumber(L, -1) : 0;
973                                 lua_pop(L, 1);
974                                 
975                                 schemdata[i] = MapNode(ndef, name, param1, param2);
976                         }
977                         
978                         i++;
979                         lua_pop(L, 1);
980                 }
981                 
982                 dschem->size      = size;
983                 dschem->schematic = schemdata;
984                 
985                 if (i != numnodes) {
986                         errorstream << "read_schematic: incorrect number of "
987                                 "nodes provided in raw schematic data (got " << i <<
988                                 ", expected " << numnodes << ")." << std::endl;
989                         return false;
990                 }
991         } else if (lua_isstring(L, index)) {
992                 dschem->filename = std::string(lua_tostring(L, index));
993         } else {
994                 errorstream << "read_schematic: missing schematic "
995                         "filename or raw schematic data" << std::endl;
996                 return false;
997         }
998         
999         return true;
1000 }