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