diff options
Diffstat (limited to 'src/script/common/c_content.cpp')
-rw-r--r-- | src/script/common/c_content.cpp | 923 |
1 files changed, 923 insertions, 0 deletions
diff --git a/src/script/common/c_content.cpp b/src/script/common/c_content.cpp new file mode 100644 index 000000000..c7966a0be --- /dev/null +++ b/src/script/common/c_content.cpp @@ -0,0 +1,923 @@ +/* +Minetest +Copyright (C) 2013 celeron55, Perttu Ahola <celeron55@gmail.com> + +This program is free software; you can redistribute it and/or modify +it under the terms of the GNU Lesser General Public License as published by +the Free Software Foundation; either version 2.1 of the License, or +(at your option) any later version. + +This program is distributed in the hope that it will be useful, +but WITHOUT ANY WARRANTY; without even the implied warranty of +MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the +GNU Lesser General Public License for more details. + +You should have received a copy of the GNU Lesser General Public License along +with this program; if not, write to the Free Software Foundation, Inc., +51 Franklin Street, Fifth Floor, Boston, MA 02110-1301 USA. +*/ +#include "common/c_content.h" +#include "common/c_converter.h" +#include "common/c_types.h" +#include "nodedef.h" +#include "itemdef.h" +#include "object_properties.h" +#include "cpp_api/s_node.h" +#include "lua_api/l_object.h" +#include "lua_api/l_item.h" +#include "common/c_internal.h" +#include "server.h" +#include "log.h" +#include "tool.h" +#include "server.h" + +struct EnumString es_TileAnimationType[] = +{ + {TAT_NONE, "none"}, + {TAT_VERTICAL_FRAMES, "vertical_frames"}, + {0, NULL}, +}; + +/******************************************************************************/ +ItemDefinition read_item_definition(lua_State* L,int index, + ItemDefinition default_def) +{ + if(index < 0) + index = lua_gettop(L) + 1 + index; + + // Read the item definition + ItemDefinition def = default_def; + + def.type = (ItemType)getenumfield(L, index, "type", + es_ItemType, ITEM_NONE); + getstringfield(L, index, "name", def.name); + getstringfield(L, index, "description", def.description); + getstringfield(L, index, "inventory_image", def.inventory_image); + getstringfield(L, index, "wield_image", def.wield_image); + + lua_getfield(L, index, "wield_scale"); + if(lua_istable(L, -1)){ + def.wield_scale = check_v3f(L, -1); + } + lua_pop(L, 1); + + def.stack_max = getintfield_default(L, index, "stack_max", def.stack_max); + if(def.stack_max == 0) + def.stack_max = 1; + + lua_getfield(L, index, "on_use"); + def.usable = lua_isfunction(L, -1); + lua_pop(L, 1); + + getboolfield(L, index, "liquids_pointable", def.liquids_pointable); + + warn_if_field_exists(L, index, "tool_digging_properties", + "deprecated: use tool_capabilities"); + + lua_getfield(L, index, "tool_capabilities"); + if(lua_istable(L, -1)){ + def.tool_capabilities = new ToolCapabilities( + read_tool_capabilities(L, -1)); + } + + // If name is "" (hand), ensure there are ToolCapabilities + // because it will be looked up there whenever any other item has + // no ToolCapabilities + if(def.name == "" && def.tool_capabilities == NULL){ + def.tool_capabilities = new ToolCapabilities(); + } + + lua_getfield(L, index, "groups"); + read_groups(L, -1, def.groups); + lua_pop(L, 1); + + lua_getfield(L, index, "sounds"); + if(lua_istable(L, -1)){ + lua_getfield(L, -1, "place"); + read_soundspec(L, -1, def.sound_place); + lua_pop(L, 1); + } + lua_pop(L, 1); + + // Client shall immediately place this node when player places the item. + // Server will update the precise end result a moment later. + // "" = no prediction + getstringfield(L, index, "node_placement_prediction", + def.node_placement_prediction); + + return def; +} + +/******************************************************************************/ +void read_object_properties(lua_State *L, int index, + ObjectProperties *prop) +{ + if(index < 0) + index = lua_gettop(L) + 1 + index; + if(!lua_istable(L, index)) + return; + + prop->hp_max = getintfield_default(L, -1, "hp_max", 10); + + getboolfield(L, -1, "physical", prop->physical); + + getfloatfield(L, -1, "weight", prop->weight); + + lua_getfield(L, -1, "collisionbox"); + if(lua_istable(L, -1)) + prop->collisionbox = read_aabb3f(L, -1, 1.0); + lua_pop(L, 1); + + getstringfield(L, -1, "visual", prop->visual); + + getstringfield(L, -1, "mesh", prop->mesh); + + lua_getfield(L, -1, "visual_size"); + if(lua_istable(L, -1)) + prop->visual_size = read_v2f(L, -1); + lua_pop(L, 1); + + lua_getfield(L, -1, "textures"); + if(lua_istable(L, -1)){ + prop->textures.clear(); + int table = lua_gettop(L); + lua_pushnil(L); + while(lua_next(L, table) != 0){ + // key at index -2 and value at index -1 + if(lua_isstring(L, -1)) + prop->textures.push_back(lua_tostring(L, -1)); + else + prop->textures.push_back(""); + // removes value, keeps key for next iteration + lua_pop(L, 1); + } + } + lua_pop(L, 1); + + lua_getfield(L, -1, "colors"); + if(lua_istable(L, -1)){ + prop->colors.clear(); + int table = lua_gettop(L); + lua_pushnil(L); + while(lua_next(L, table) != 0){ + // key at index -2 and value at index -1 + if(lua_isstring(L, -1)) + prop->colors.push_back(readARGB8(L, -1)); + else + prop->colors.push_back(video::SColor(255, 255, 255, 255)); + // removes value, keeps key for next iteration + lua_pop(L, 1); + } + } + lua_pop(L, 1); + + lua_getfield(L, -1, "spritediv"); + if(lua_istable(L, -1)) + prop->spritediv = read_v2s16(L, -1); + lua_pop(L, 1); + + lua_getfield(L, -1, "initial_sprite_basepos"); + if(lua_istable(L, -1)) + prop->initial_sprite_basepos = read_v2s16(L, -1); + lua_pop(L, 1); + + getboolfield(L, -1, "is_visible", prop->is_visible); + getboolfield(L, -1, "makes_footstep_sound", prop->makes_footstep_sound); + getfloatfield(L, -1, "automatic_rotate", prop->automatic_rotate); +} + +/******************************************************************************/ +TileDef read_tiledef(lua_State *L, int index) +{ + if(index < 0) + index = lua_gettop(L) + 1 + index; + + TileDef tiledef; + + // key at index -2 and value at index + if(lua_isstring(L, index)){ + // "default_lava.png" + tiledef.name = lua_tostring(L, index); + } + else if(lua_istable(L, index)) + { + // {name="default_lava.png", animation={}} + tiledef.name = ""; + getstringfield(L, index, "name", tiledef.name); + getstringfield(L, index, "image", tiledef.name); // MaterialSpec compat. + tiledef.backface_culling = getboolfield_default( + L, index, "backface_culling", true); + // animation = {} + lua_getfield(L, index, "animation"); + if(lua_istable(L, -1)){ + // {type="vertical_frames", aspect_w=16, aspect_h=16, length=2.0} + tiledef.animation.type = (TileAnimationType) + getenumfield(L, -1, "type", es_TileAnimationType, + TAT_NONE); + tiledef.animation.aspect_w = + getintfield_default(L, -1, "aspect_w", 16); + tiledef.animation.aspect_h = + getintfield_default(L, -1, "aspect_h", 16); + tiledef.animation.length = + getfloatfield_default(L, -1, "length", 1.0); + } + lua_pop(L, 1); + } + + return tiledef; +} + +/******************************************************************************/ +ContentFeatures read_content_features(lua_State *L, int index) +{ + if(index < 0) + index = lua_gettop(L) + 1 + index; + + ContentFeatures f; + + /* Cache existence of some callbacks */ + lua_getfield(L, index, "on_construct"); + if(!lua_isnil(L, -1)) f.has_on_construct = true; + lua_pop(L, 1); + lua_getfield(L, index, "on_destruct"); + if(!lua_isnil(L, -1)) f.has_on_destruct = true; + lua_pop(L, 1); + lua_getfield(L, index, "after_destruct"); + if(!lua_isnil(L, -1)) f.has_after_destruct = true; + lua_pop(L, 1); + + lua_getfield(L, index, "on_rightclick"); + f.rightclickable = lua_isfunction(L, -1); + lua_pop(L, 1); + + /* Name */ + getstringfield(L, index, "name", f.name); + + /* Groups */ + lua_getfield(L, index, "groups"); + read_groups(L, -1, f.groups); + lua_pop(L, 1); + + /* Visual definition */ + + f.drawtype = (NodeDrawType)getenumfield(L, index, "drawtype", + ScriptApiNode::es_DrawType,NDT_NORMAL); + getfloatfield(L, index, "visual_scale", f.visual_scale); + + // tiles = {} + lua_getfield(L, index, "tiles"); + // If nil, try the deprecated name "tile_images" instead + if(lua_isnil(L, -1)){ + lua_pop(L, 1); + warn_if_field_exists(L, index, "tile_images", + "Deprecated; new name is \"tiles\"."); + lua_getfield(L, index, "tile_images"); + } + if(lua_istable(L, -1)){ + int table = lua_gettop(L); + lua_pushnil(L); + int i = 0; + while(lua_next(L, table) != 0){ + // Read tiledef from value + f.tiledef[i] = read_tiledef(L, -1); + // removes value, keeps key for next iteration + lua_pop(L, 1); + i++; + if(i==6){ + lua_pop(L, 1); + break; + } + } + // Copy last value to all remaining textures + if(i >= 1){ + TileDef lasttile = f.tiledef[i-1]; + while(i < 6){ + f.tiledef[i] = lasttile; + i++; + } + } + } + lua_pop(L, 1); + + // special_tiles = {} + lua_getfield(L, index, "special_tiles"); + // If nil, try the deprecated name "special_materials" instead + if(lua_isnil(L, -1)){ + lua_pop(L, 1); + warn_if_field_exists(L, index, "special_materials", + "Deprecated; new name is \"special_tiles\"."); + lua_getfield(L, index, "special_materials"); + } + if(lua_istable(L, -1)){ + int table = lua_gettop(L); + lua_pushnil(L); + int i = 0; + while(lua_next(L, table) != 0){ + // Read tiledef from value + f.tiledef_special[i] = read_tiledef(L, -1); + // removes value, keeps key for next iteration + lua_pop(L, 1); + i++; + if(i==6){ + lua_pop(L, 1); + break; + } + } + } + lua_pop(L, 1); + + f.alpha = getintfield_default(L, index, "alpha", 255); + + bool usealpha = getboolfield_default(L, index, + "use_texture_alpha", false); + if (usealpha) + f.alpha = 0; + + /* Other stuff */ + + lua_getfield(L, index, "post_effect_color"); + if(!lua_isnil(L, -1)) + f.post_effect_color = readARGB8(L, -1); + lua_pop(L, 1); + + f.param_type = (ContentParamType)getenumfield(L, index, "paramtype", + ScriptApiNode::es_ContentParamType, CPT_NONE); + f.param_type_2 = (ContentParamType2)getenumfield(L, index, "paramtype2", + ScriptApiNode::es_ContentParamType2, CPT2_NONE); + + // Warn about some deprecated fields + warn_if_field_exists(L, index, "wall_mounted", + "deprecated: use paramtype2 = 'wallmounted'"); + warn_if_field_exists(L, index, "light_propagates", + "deprecated: determined from paramtype"); + warn_if_field_exists(L, index, "dug_item", + "deprecated: use 'drop' field"); + warn_if_field_exists(L, index, "extra_dug_item", + "deprecated: use 'drop' field"); + warn_if_field_exists(L, index, "extra_dug_item_rarity", + "deprecated: use 'drop' field"); + warn_if_field_exists(L, index, "metadata_name", + "deprecated: use on_add and metadata callbacks"); + + // True for all ground-like things like stone and mud, false for eg. trees + getboolfield(L, index, "is_ground_content", f.is_ground_content); + f.light_propagates = (f.param_type == CPT_LIGHT); + getboolfield(L, index, "sunlight_propagates", f.sunlight_propagates); + // This is used for collision detection. + // Also for general solidness queries. + getboolfield(L, index, "walkable", f.walkable); + // Player can point to these + getboolfield(L, index, "pointable", f.pointable); + // Player can dig these + getboolfield(L, index, "diggable", f.diggable); + // Player can climb these + getboolfield(L, index, "climbable", f.climbable); + // Player can build on these + getboolfield(L, index, "buildable_to", f.buildable_to); + // Whether the node is non-liquid, source liquid or flowing liquid + f.liquid_type = (LiquidType)getenumfield(L, index, "liquidtype", + ScriptApiNode::es_LiquidType, LIQUID_NONE); + // If the content is liquid, this is the flowing version of the liquid. + getstringfield(L, index, "liquid_alternative_flowing", + f.liquid_alternative_flowing); + // If the content is liquid, this is the source version of the liquid. + getstringfield(L, index, "liquid_alternative_source", + f.liquid_alternative_source); + // Viscosity for fluid flow, ranging from 1 to 7, with + // 1 giving almost instantaneous propagation and 7 being + // the slowest possible + f.liquid_viscosity = getintfield_default(L, index, + "liquid_viscosity", f.liquid_viscosity); + getboolfield(L, index, "liquid_renewable", f.liquid_renewable); + // Amount of light the node emits + f.light_source = getintfield_default(L, index, + "light_source", f.light_source); + f.damage_per_second = getintfield_default(L, index, + "damage_per_second", f.damage_per_second); + + lua_getfield(L, index, "node_box"); + if(lua_istable(L, -1)) + f.node_box = read_nodebox(L, -1); + lua_pop(L, 1); + + lua_getfield(L, index, "selection_box"); + if(lua_istable(L, -1)) + f.selection_box = read_nodebox(L, -1); + lua_pop(L, 1); + + // Set to true if paramtype used to be 'facedir_simple' + getboolfield(L, index, "legacy_facedir_simple", f.legacy_facedir_simple); + // Set to true if wall_mounted used to be set to true + getboolfield(L, index, "legacy_wallmounted", f.legacy_wallmounted); + + // Sound table + lua_getfield(L, index, "sounds"); + if(lua_istable(L, -1)){ + lua_getfield(L, -1, "footstep"); + read_soundspec(L, -1, f.sound_footstep); + lua_pop(L, 1); + lua_getfield(L, -1, "dig"); + read_soundspec(L, -1, f.sound_dig); + lua_pop(L, 1); + lua_getfield(L, -1, "dug"); + read_soundspec(L, -1, f.sound_dug); + lua_pop(L, 1); + } + lua_pop(L, 1); + + return f; +} + +/******************************************************************************/ +void read_server_sound_params(lua_State *L, int index, + ServerSoundParams ¶ms) +{ + if(index < 0) + index = lua_gettop(L) + 1 + index; + // Clear + params = ServerSoundParams(); + if(lua_istable(L, index)){ + getfloatfield(L, index, "gain", params.gain); + getstringfield(L, index, "to_player", params.to_player); + lua_getfield(L, index, "pos"); + if(!lua_isnil(L, -1)){ + v3f p = read_v3f(L, -1)*BS; + params.pos = p; + params.type = ServerSoundParams::SSP_POSITIONAL; + } + lua_pop(L, 1); + lua_getfield(L, index, "object"); + if(!lua_isnil(L, -1)){ + ObjectRef *ref = ObjectRef::checkobject(L, -1); + ServerActiveObject *sao = ObjectRef::getobject(ref); + if(sao){ + params.object = sao->getId(); + params.type = ServerSoundParams::SSP_OBJECT; + } + } + lua_pop(L, 1); + params.max_hear_distance = BS*getfloatfield_default(L, index, + "max_hear_distance", params.max_hear_distance/BS); + getboolfield(L, index, "loop", params.loop); + } +} + +/******************************************************************************/ +void read_soundspec(lua_State *L, int index, SimpleSoundSpec &spec) +{ + if(index < 0) + index = lua_gettop(L) + 1 + index; + if(lua_isnil(L, index)){ + } else if(lua_istable(L, index)){ + getstringfield(L, index, "name", spec.name); + getfloatfield(L, index, "gain", spec.gain); + } else if(lua_isstring(L, index)){ + spec.name = lua_tostring(L, index); + } +} + +/******************************************************************************/ +NodeBox read_nodebox(lua_State *L, int index) +{ + NodeBox nodebox; + if(lua_istable(L, -1)){ + nodebox.type = (NodeBoxType)getenumfield(L, index, "type", + ScriptApiNode::es_NodeBoxType, NODEBOX_REGULAR); + + lua_getfield(L, index, "fixed"); + if(lua_istable(L, -1)) + nodebox.fixed = read_aabb3f_vector(L, -1, BS); + lua_pop(L, 1); + + lua_getfield(L, index, "wall_top"); + if(lua_istable(L, -1)) + nodebox.wall_top = read_aabb3f(L, -1, BS); + lua_pop(L, 1); + + lua_getfield(L, index, "wall_bottom"); + if(lua_istable(L, -1)) + nodebox.wall_bottom = read_aabb3f(L, -1, BS); + lua_pop(L, 1); + + lua_getfield(L, index, "wall_side"); + if(lua_istable(L, -1)) + nodebox.wall_side = read_aabb3f(L, -1, BS); + lua_pop(L, 1); + } + return nodebox; +} + +/******************************************************************************/ +MapNode readnode(lua_State *L, int index, INodeDefManager *ndef) +{ + lua_getfield(L, index, "name"); + const char *name = luaL_checkstring(L, -1); + lua_pop(L, 1); + u8 param1; + lua_getfield(L, index, "param1"); + if(lua_isnil(L, -1)) + param1 = 0; + else + param1 = lua_tonumber(L, -1); + lua_pop(L, 1); + u8 param2; + lua_getfield(L, index, "param2"); + if(lua_isnil(L, -1)) + param2 = 0; + else + param2 = lua_tonumber(L, -1); + lua_pop(L, 1); + return MapNode(ndef, name, param1, param2); +} + +/******************************************************************************/ +void pushnode(lua_State *L, const MapNode &n, INodeDefManager *ndef) +{ + lua_newtable(L); + lua_pushstring(L, ndef->get(n).name.c_str()); + lua_setfield(L, -2, "name"); + lua_pushnumber(L, n.getParam1()); + lua_setfield(L, -2, "param1"); + lua_pushnumber(L, n.getParam2()); + lua_setfield(L, -2, "param2"); +} + +/******************************************************************************/ +void warn_if_field_exists(lua_State *L, int table, + const char *fieldname, const std::string &message) +{ + lua_getfield(L, table, fieldname); + if(!lua_isnil(L, -1)){ +//TODO find way to access backtrace fct from here + // infostream<<script_get_backtrace(L)<<std::endl; + infostream<<"WARNING: field \""<<fieldname<<"\": " + <<message<<std::endl; + } + lua_pop(L, 1); +} + +/******************************************************************************/ +int getenumfield(lua_State *L, int table, + const char *fieldname, const EnumString *spec, int default_) +{ + int result = default_; + string_to_enum(spec, result, + getstringfield_default(L, table, fieldname, "")); + return result; +} + +/******************************************************************************/ +bool string_to_enum(const EnumString *spec, int &result, + const std::string &str) +{ + const EnumString *esp = spec; + while(esp->str){ + if(str == std::string(esp->str)){ + result = esp->num; + return true; + } + esp++; + } + return false; +} + +/******************************************************************************/ +ItemStack read_item(lua_State* L, int index,Server* srv) +{ + if(index < 0) + index = lua_gettop(L) + 1 + index; + + if(lua_isnil(L, index)) + { + return ItemStack(); + } + else if(lua_isuserdata(L, index)) + { + // Convert from LuaItemStack + LuaItemStack *o = LuaItemStack::checkobject(L, index); + return o->getItem(); + } + else if(lua_isstring(L, index)) + { + // Convert from itemstring + std::string itemstring = lua_tostring(L, index); + IItemDefManager *idef = srv->idef(); + try + { + ItemStack item; + item.deSerialize(itemstring, idef); + return item; + } + catch(SerializationError &e) + { + infostream<<"WARNING: unable to create item from itemstring" + <<": "<<itemstring<<std::endl; + return ItemStack(); + } + } + else if(lua_istable(L, index)) + { + // Convert from table + IItemDefManager *idef = srv->idef(); + std::string name = getstringfield_default(L, index, "name", ""); + int count = getintfield_default(L, index, "count", 1); + int wear = getintfield_default(L, index, "wear", 0); + std::string metadata = getstringfield_default(L, index, "metadata", ""); + return ItemStack(name, count, wear, metadata, idef); + } + else + { + throw LuaError(L, "Expecting itemstack, itemstring, table or nil"); + } +} + +/******************************************************************************/ +void push_tool_capabilities(lua_State *L, + const ToolCapabilities &toolcap) +{ + lua_newtable(L); + setfloatfield(L, -1, "full_punch_interval", toolcap.full_punch_interval); + setintfield(L, -1, "max_drop_level", toolcap.max_drop_level); + // Create groupcaps table + lua_newtable(L); + // For each groupcap + for(std::map<std::string, ToolGroupCap>::const_iterator + i = toolcap.groupcaps.begin(); i != toolcap.groupcaps.end(); i++){ + // Create groupcap table + lua_newtable(L); + const std::string &name = i->first; + const ToolGroupCap &groupcap = i->second; + // Create subtable "times" + lua_newtable(L); + for(std::map<int, float>::const_iterator + i = groupcap.times.begin(); i != groupcap.times.end(); i++){ + int rating = i->first; + float time = i->second; + lua_pushinteger(L, rating); + lua_pushnumber(L, time); + lua_settable(L, -3); + } + // Set subtable "times" + lua_setfield(L, -2, "times"); + // Set simple parameters + setintfield(L, -1, "maxlevel", groupcap.maxlevel); + setintfield(L, -1, "uses", groupcap.uses); + // Insert groupcap table into groupcaps table + lua_setfield(L, -2, name.c_str()); + } + // Set groupcaps table + lua_setfield(L, -2, "groupcaps"); + //Create damage_groups table + lua_newtable(L); + // For each damage group + for(std::map<std::string, s16>::const_iterator + i = toolcap.damageGroups.begin(); i != toolcap.damageGroups.end(); i++){ + // Create damage group table + lua_pushinteger(L, i->second); + lua_setfield(L, -2, i->first.c_str()); + } + lua_setfield(L, -2, "damage_groups"); +} + +/******************************************************************************/ +void push_inventory_list(Inventory *inv, const char *name, + lua_State *L) +{ + InventoryList *invlist = inv->getList(name); + if(invlist == NULL){ + lua_pushnil(L); + return; + } + std::vector<ItemStack> items; + for(u32 i=0; i<invlist->getSize(); i++) + items.push_back(invlist->getItem(i)); + push_items(L, items); +} + +/******************************************************************************/ +void read_inventory_list(Inventory *inv, const char *name, + lua_State *L, int tableindex, Server* srv,int forcesize) +{ + if(tableindex < 0) + tableindex = lua_gettop(L) + 1 + tableindex; + // If nil, delete list + if(lua_isnil(L, tableindex)){ + inv->deleteList(name); + return; + } + // Otherwise set list + std::vector<ItemStack> items = read_items(L, tableindex,srv); + int listsize = (forcesize != -1) ? forcesize : items.size(); + InventoryList *invlist = inv->addList(name, listsize); + int index = 0; + for(std::vector<ItemStack>::const_iterator + i = items.begin(); i != items.end(); i++){ + if(forcesize != -1 && index == forcesize) + break; + invlist->changeItem(index, *i); + index++; + } + while(forcesize != -1 && index < forcesize){ + invlist->deleteItem(index); + index++; + } +} + +/******************************************************************************/ +ToolCapabilities read_tool_capabilities( + lua_State *L, int table) +{ + ToolCapabilities toolcap; + getfloatfield(L, table, "full_punch_interval", toolcap.full_punch_interval); + getintfield(L, table, "max_drop_level", toolcap.max_drop_level); + lua_getfield(L, table, "groupcaps"); + if(lua_istable(L, -1)){ + int table_groupcaps = lua_gettop(L); + lua_pushnil(L); + while(lua_next(L, table_groupcaps) != 0){ + // key at index -2 and value at index -1 + std::string groupname = luaL_checkstring(L, -2); + if(lua_istable(L, -1)){ + int table_groupcap = lua_gettop(L); + // This will be created + ToolGroupCap groupcap; + // Read simple parameters + getintfield(L, table_groupcap, "maxlevel", groupcap.maxlevel); + getintfield(L, table_groupcap, "uses", groupcap.uses); + // DEPRECATED: maxwear + float maxwear = 0; + if(getfloatfield(L, table_groupcap, "maxwear", maxwear)){ + if(maxwear != 0) + groupcap.uses = 1.0/maxwear; + else + groupcap.uses = 0; + infostream<<script_get_backtrace(L)<<std::endl; + infostream<<"WARNING: field \"maxwear\" is deprecated; " + <<"should replace with uses=1/maxwear"<<std::endl; + } + // Read "times" table + lua_getfield(L, table_groupcap, "times"); + if(lua_istable(L, -1)){ + int table_times = lua_gettop(L); + lua_pushnil(L); + while(lua_next(L, table_times) != 0){ + // key at index -2 and value at index -1 + int rating = luaL_checkinteger(L, -2); + float time = luaL_checknumber(L, -1); + groupcap.times[rating] = time; + // removes value, keeps key for next iteration + lua_pop(L, 1); + } + } + lua_pop(L, 1); + // Insert groupcap into toolcap + toolcap.groupcaps[groupname] = groupcap; + } + // removes value, keeps key for next iteration + lua_pop(L, 1); + } + } + lua_pop(L, 1); + + lua_getfield(L, table, "damage_groups"); + if(lua_istable(L, -1)){ + int table_damage_groups = lua_gettop(L); + lua_pushnil(L); + while(lua_next(L, table_damage_groups) != 0){ + // key at index -2 and value at index -1 + std::string groupname = luaL_checkstring(L, -2); + u16 value = luaL_checkinteger(L, -1); + toolcap.damageGroups[groupname] = value; + // removes value, keeps key for next iteration + lua_pop(L, 1); + } + } + lua_pop(L, 1); + return toolcap; +} + +/******************************************************************************/ +void push_dig_params(lua_State *L,const DigParams ¶ms) +{ + lua_newtable(L); + setboolfield(L, -1, "diggable", params.diggable); + setfloatfield(L, -1, "time", params.time); + setintfield(L, -1, "wear", params.wear); +} + +/******************************************************************************/ +void push_hit_params(lua_State *L,const HitParams ¶ms) +{ + lua_newtable(L); + setintfield(L, -1, "hp", params.hp); + setintfield(L, -1, "wear", params.wear); +} + +/******************************************************************************/ +u32 getflagsfield(lua_State *L, int table, + const char *fieldname, FlagDesc *flagdesc) { + std::string flagstring; + + flagstring = getstringfield_default(L, table, fieldname, ""); + return readFlagString(flagstring, flagdesc); +} + +/******************************************************************************/ +/* Lua Stored data! */ +/******************************************************************************/ + +/******************************************************************************/ +void read_groups(lua_State *L, int index, + std::map<std::string, int> &result) +{ + if (!lua_istable(L,index)) + return; + result.clear(); + lua_pushnil(L); + if(index < 0) + index -= 1; + while(lua_next(L, index) != 0){ + // key at index -2 and value at index -1 + std::string name = luaL_checkstring(L, -2); + int rating = luaL_checkinteger(L, -1); + result[name] = rating; + // removes value, keeps key for next iteration + lua_pop(L, 1); + } +} + +/******************************************************************************/ +void push_items(lua_State *L, const std::vector<ItemStack> &items) +{ + // Get the table insert function + lua_getglobal(L, "table"); + lua_getfield(L, -1, "insert"); + int table_insert = lua_gettop(L); + // Create and fill table + lua_newtable(L); + int table = lua_gettop(L); + for(u32 i=0; i<items.size(); i++){ + ItemStack item = items[i]; + lua_pushvalue(L, table_insert); + lua_pushvalue(L, table); + LuaItemStack::create(L, item); + if(lua_pcall(L, 2, 0, 0)) + script_error(L, "error: %s", lua_tostring(L, -1)); + } + lua_remove(L, -2); // Remove table + lua_remove(L, -2); // Remove insert +} + +/******************************************************************************/ +std::vector<ItemStack> read_items(lua_State *L, int index,Server* srv) +{ + if(index < 0) + index = lua_gettop(L) + 1 + index; + + std::vector<ItemStack> items; + luaL_checktype(L, index, LUA_TTABLE); + lua_pushnil(L); + while(lua_next(L, index) != 0){ + // key at index -2 and value at index -1 + items.push_back(read_item(L, -1, srv)); + // removes value, keeps key for next iteration + lua_pop(L, 1); + } + return items; +} + +/******************************************************************************/ +void luaentity_get(lua_State *L, u16 id) +{ + // Get minetest.luaentities[i] + lua_getglobal(L, "minetest"); + lua_getfield(L, -1, "luaentities"); + luaL_checktype(L, -1, LUA_TTABLE); + lua_pushnumber(L, id); + lua_gettable(L, -2); + lua_remove(L, -2); // luaentities + lua_remove(L, -2); // minetest +} + +/******************************************************************************/ +NoiseParams *read_noiseparams(lua_State *L, int index) +{ + if (index < 0) + index = lua_gettop(L) + 1 + index; + + if (!lua_istable(L, index)) + return NULL; + + NoiseParams *np = new NoiseParams; + + np->offset = getfloatfield_default(L, index, "offset", 0.0); + np->scale = getfloatfield_default(L, index, "scale", 0.0); + lua_getfield(L, index, "spread"); + np->spread = read_v3f(L, -1); + lua_pop(L, 1); + np->seed = getintfield_default(L, index, "seed", 0); + np->octaves = getintfield_default(L, index, "octaves", 0); + np->persist = getfloatfield_default(L, index, "persist", 0.0); + + return np; +} |