diff --git a/builtin/item.lua b/builtin/item.lua index 3d545eece..6d75fbf70 100644 --- a/builtin/item.lua +++ b/builtin/item.lua @@ -250,10 +250,12 @@ function minetest.node_dig(pos, node, digger) wielded:add_wear(dp.wear) digger:set_wielded_item(wielded) - -- Add dropped items - local _, dropped_item - for _, dropped_item in ipairs(drops) do - digger:get_inventory():add_item("main", dropped_item) + -- Add dropped items to object's inventory + if digger:get_inventory() then + local _, dropped_item + for _, dropped_item in ipairs(drops) do + digger:get_inventory():add_item("main", dropped_item) + end end end diff --git a/doc/lua_api.txt b/doc/lua_api.txt index 8b2b81c75..5e0f2f118 100644 --- a/doc/lua_api.txt +++ b/doc/lua_api.txt @@ -842,13 +842,23 @@ EnvRef: basically ServerEnvironment and ServerMap combined. methods: - set_node(pos, node) - add_node(pos, node): alias set_node(pos, node) -- remove_node(pos): equivalent to set_node(pos, "air") + ^ Set node at position (node = {name="foo", param1=0, param2=0}) +- remove_node(pos) + ^ Equivalent to set_node(pos, "air") - get_node(pos) ^ Returns {name="ignore", ...} for unloaded area - get_node_or_nil(pos) ^ Returns nil for unloaded area - get_node_light(pos, timeofday) -> 0...15 or nil ^ timeofday: nil = current time, 0 = night, 0.5 = day + +- place_node(pos, node) + ^ Place node with the same effects that a player would cause +- dig_node(pos) + ^ Dig node with the same effects that a player would cause +- punch_node(pos) + ^ Punch node with the same effects that a player would cause + - add_entity(pos, name): Spawn Lua-defined entity at position ^ Returns ObjectRef, or nil if failed - add_item(pos, itemstring): Spawn item diff --git a/games/minimal/mods/experimental/init.lua b/games/minimal/mods/experimental/init.lua index 8f92c13ee..ea11e6d3b 100644 --- a/games/minimal/mods/experimental/init.lua +++ b/games/minimal/mods/experimental/init.lua @@ -6,6 +6,11 @@ experimental = {} +function experimental.print_to_everything(msg) + minetest.log("action", msg) + minetest.chat_send_all(msg) +end + --[[ experimental.player_visual_index = 0 function switch_player_visual() @@ -97,235 +102,10 @@ function on_step(dtime) end minetest.register_globalstep(on_step) --- An example furnace-thing implemented in Lua - ---[[ -minetest.register_node("experimental:luafurnace", { - tile_images = {"default_lava.png", "default_furnace_side.png", - "default_furnace_side.png", "default_furnace_side.png", - "default_furnace_side.png", "default_furnace_front.png"}, - --inventory_image = "furnace_front.png", - inventory_image = minetest.inventorycube("default_furnace_front.png"), - paramtype = "facedir_simple", - metadata_name = "generic", - material = minetest.digprop_stonelike(3.0), -}) - -minetest.register_on_placenode(function(pos, newnode, placer) - if newnode.name == "experimental:luafurnace" then - local meta = minetest.env:get_meta(pos) - meta:inventory_set_list("fuel", {""}) - meta:inventory_set_list("src", {""}) - meta:inventory_set_list("dst", {"","","",""}) - meta:set_inventory_draw_spec( - "invsize[8,9;]" - .."list[current_name;fuel;2,3;1,1;]" - .."list[current_name;src;2,1;1,1;]" - .."list[current_name;dst;5,1;2,2;]" - .."list[current_player;main;0,5;8,4;]" - ) - - local total_cooked = 0; - meta:set_string("total_cooked", total_cooked) - meta:set_infotext("Lua Furnace: total cooked: "..total_cooked) - end -end) - -minetest.register_abm({ - nodenames = {"experimental:luafurnace"}, - interval = 1.0, - chance = 1, - action = function(pos, node, active_object_count, active_object_count_wider) - local meta = minetest.env:get_meta(pos) - for i, name in ipairs({ - "fuel_totaltime", - "fuel_time", - "src_totaltime", - "src_time" - }) do - if not meta:get_string(name) then - meta:set_string(name, 0) - end - end - - local inv = meta:get_inventory() - - local fuelitem = inv:get_stack("fuel", 1):peek_item() - local srcitem = inv:get_stack("src", 1):peek_item() - --print("fuelitem="..dump(fuelitem)) - --print("srcitem="..dump(srcitem)) - - local was_active = false - - local src_cooktime = -1 - local result_stackstring = nil - - if srcitem then - local prop = get_item_definition(srcitem) - if prop and prop.cookresult_itemstring ~= "" then - result_stackstring = prop.cookresult_itemstring - src_cooktime = prop.furnace_cooktime or 3 - end - end - - print("src_cooktime="..dump(src_cooktime)) - print("result_stackstring="..dump(result_stackstring)) - - if tonumber(meta:get_string("fuel_time")) < tonumber(meta:get_string("fuel_totaltime")) then - was_active = true - meta:set_string("fuel_time", tonumber(meta:get_string("fuel_time")) + 1) - meta:set_string("src_time", tonumber(meta:get_string("src_time")) + 1) - --print("result_stackstring="..dump(result_stackstring)) - --print('tonumber(meta:get_string("src_time"))='..dump(tonumber(meta:get_string("src_time")))) - --print("src_cooktime="..dump(src_cooktime)) - if result_stackstring and tonumber(meta:get_string("src_time")) >= src_cooktime and src_cooktime >= 0 then - -- Put result in "dst" list - success = inv:autoinsert_stackstring("dst", result_stackstring) - if not success then - print("Could not autoinsert '"..result_stackstring.."'") - end - -- If succeeded, take stuff from "src" list - if success then - srcstack = inv:get_stack("src", 1) - srcstack:take_item() - inv:set_stack("src", 1, srcstack) - end - meta:set_string("src_time", 0) - end - end - - if tonumber(meta:get_string("fuel_time")) < tonumber(meta:get_string("fuel_totaltime")) then - meta:set_infotext("Furnace active: "..(tonumber(meta:get_string("fuel_time"))/tonumber(meta:get_string("fuel_totaltime"))*100).."%") - return - end - - local srcitem = inv:get_stack("src", 1):peek_item() - - local src_cooktime = 0 - local result_stackstring = nil - - if srcitem then - local prop = get_item_definition(srcitem) - if prop and prop.cookresult_itemstring ~= "" then - result_stackstring = prop.cookresult_itemstring - src_cooktime = prop.furnace_cooktime or 3 - end - end - - local fuelitem = inv:get_stack("fuel", 1):peek_item() - - if not result_stackstring or not fuelitem then - if was_active then - meta:set_infotext("Furnace is empty") - end - return - end - - local burntime = -1 - if fuelitem then - local prop = get_item_definition(fuelitem) - if prop then - burntime = prop.furnace_burntime or -1 - end - end - - if burntime <= 0 then - meta:set_infotext("Furnace out of fuel") - return - end - - meta:set_string("fuel_totaltime", burntime) - meta:set_string("fuel_time", 0) - - local stack = inv:get_stack("fuel", 1) - stack:take_item() - inv:set_stack("fuel", 1, stack) - end, -}) -minetest.register_abm({ - nodenames = {"experimental:luafurnace"}, - interval = 1.0, - chance = 1, - action = function(pos, node, active_object_count, active_object_count_wider) - local meta = minetest.env:get_meta(pos) - local fuellist = meta:inventory_get_list("fuel") - local srclist = meta:inventory_get_list("src") - local dstlist = meta:inventory_get_list("dst") - if fuellist == nil or srclist == nil or dstlist == nil then - return - end - _, srcitem = stackstring_take_item(srclist[1]) - _, fuelitem = stackstring_take_item(fuellist[1]) - if not srcitem or not fuelitem then return end - if fuelitem.type == "node" then - local prop = minetest.registered_nodes[fuelitem.name] - if prop == nil then return end - if prop.furnace_burntime < 0 then return end - else - return - end - local resultstack = nil - if srcitem.type == "node" then - local prop = minetest.registered_nodes[srcitem.name] - if prop == nil then return end - if prop.cookresult_item == "" then return end - resultstack = prop.cookresult_item - else - return - end - - if resultstack == nil then - return - end - - dstlist[1], success = stackstring_put_stackstring(dstlist[1], resultstack) - if not success then - return - end - - fuellist[1], _ = stackstring_take_item(fuellist[1]) - srclist[1], _ = stackstring_take_item(srclist[1]) - - meta:inventory_set_list("fuel", fuellist) - meta:inventory_set_list("src", srclist) - meta:inventory_set_list("dst", dstlist) - - local total_cooked = meta:get_string("total_cooked") - total_cooked = tonumber(total_cooked) + 1 - meta:set_string("total_cooked", total_cooked) - meta:set_infotext("Lua Furnace: total cooked: "..total_cooked) - end, -}) -minetest.register_craft({ - output = 'node "experimental:luafurnace" 1', - recipe = { - {'node "default:cobble"', 'node "default:cobble"', 'node "default:cobble"'}, - {'node "default:cobble"', 'node "default:steel_ingot"', 'node "default:cobble"'}, - {'node "default:cobble"', 'node "default:cobble"', 'node "default:cobble"'}, - } -}) ---]] - -- -- Random stuff -- ---[[ -minetest.register_tool("experimental:horribletool", { - image = "default_lava.png", - basetime = 2.0 - dt_weight = 0.2 - dt_crackiness = 0.2 - dt_crumbliness = 0.2 - dt_cuttability = 0.2 - basedurability = 50 - dd_weight = -5 - dd_crackiness = -5 - dd_crumbliness = -5 - dd_cuttability = -5 -}) ---]] - -- -- TNT (not functional) -- @@ -662,6 +442,56 @@ minetest.register_abm({ end, })--]] +minetest.register_node("experimental:tester_node_1", { + description = "Tester Node 1", + tile_images = {"wieldhand.png"}, + groups = {oddly_breakable_by_hand=2}, + sounds = default.node_sound_wood_defaults(), + + on_construct = function(pos) + experimental.print_to_everything("experimental:tester_node_1:on_construct("..minetest.pos_to_string(pos)..")") + local meta = minetest.env:get_meta(pos) + meta:set_string("mine", "test") + end, + + after_place_node = function(pos, placer) + experimental.print_to_everything("experimental:tester_node_1:after_place_node("..minetest.pos_to_string(pos)..")") + local meta = minetest.env:get_meta(pos) + if meta:get_string("mine") == "test" then + experimental.print_to_everything("correct metadata found") + else + experimental.print_to_everything("incorrect metadata found") + end + end, + + on_destruct = function(pos) + experimental.print_to_everything("experimental:tester_node_1:on_destruct("..minetest.pos_to_string(pos)..")") + end, + + after_dig_node = function(pos, oldnode, oldmetadata, digger) + experimental.print_to_everything("experimental:tester_node_1:after_dig_node("..minetest.pos_to_string(pos)..")") + end, +}) + +minetest.register_craftitem("experimental:tester_tool_1", { + description = "Tester Tool 1", + inventory_image = "experimental_tester_tool_1.png", + on_use = function(itemstack, user, pointed_thing) + --print(dump(pointed_thing)) + if pointed_thing.type == "node" then + if minetest.env:get_node(pointed_thing.under).name == "experimental:tester_node_1" then + local p = pointed_thing.under + minetest.log("action", "Tester tool used at "..minetest.pos_to_string(p)) + minetest.env:dig_node(p) + else + local p = pointed_thing.above + minetest.log("action", "Tester tool used at "..minetest.pos_to_string(p)) + minetest.env:place_node(p, {name="experimental:tester_node_1"}) + end + end + end, +}) + minetest.log("experimental modname="..dump(minetest.get_current_modname())) minetest.log("experimental modpath="..dump(minetest.get_modpath("experimental"))) minetest.log("experimental worldpath="..dump(minetest.get_worldpath())) diff --git a/games/minimal/mods/give_initial_stuff/init.lua b/games/minimal/mods/give_initial_stuff/init.lua index fef23c328..29b835c7d 100644 --- a/games/minimal/mods/give_initial_stuff/init.lua +++ b/games/minimal/mods/give_initial_stuff/init.lua @@ -11,5 +11,6 @@ minetest.register_on_newplayer(function(player) player:get_inventory():add_item('main', 'default:pick_mese') player:get_inventory():add_item('main', 'default:mese 99') player:get_inventory():add_item('main', 'default:water_source 99') + player:get_inventory():add_item('main', 'experimental:tester_tool_1') end) diff --git a/src/scriptapi.cpp b/src/scriptapi.cpp index 50e7236c8..5091216dc 100644 --- a/src/scriptapi.cpp +++ b/src/scriptapi.cpp @@ -2465,7 +2465,11 @@ private: { ObjectRef *ref = checkobject(L, 1); ServerActiveObject *co = getobject(ref); - if(co == NULL) return 0; + if(co == NULL){ + // Default hp is 1 + lua_pushnumber(L, 1); + return 1; + } int hp = co->getHP(); /*infostream<<"ObjectRef::l_get_hp(): id="<getId() <<" hp="<getInventory(loc) != NULL) InvRef::create(L, loc); else - lua_pushnil(L); + lua_pushnil(L); // An object may have no inventory (nil) return 1; } @@ -2516,7 +2520,11 @@ private: { ObjectRef *ref = checkobject(L, 1); ServerActiveObject *co = getobject(ref); - if(co == NULL) return 0; + if(co == NULL){ + // Empty ItemStack + LuaItemStack::create(L, ItemStack()); + return 1; + } // Do it LuaItemStack::create(L, co->getWieldedItem()); return 1; @@ -2856,11 +2864,11 @@ const luaL_reg ObjectRef::methods[] = { {0,0} }; -// Creates a new anonymous reference if id=0 +// Creates a new anonymous reference if cobj=NULL or id=0 static void objectref_get_or_create(lua_State *L, ServerActiveObject *cobj) { - if(cobj->getId() == 0){ + if(cobj == NULL || cobj->getId() == 0){ ObjectRef::create(L, cobj); } else { objectref_get(L, cobj->getId()); @@ -3013,7 +3021,6 @@ private: // pos = {x=num, y=num, z=num} static int l_set_node(lua_State *L) { - //infostream<<"EnvRef::l_set_node()"<m_env; if(env == NULL) return 0; @@ -3043,17 +3050,16 @@ private: // pos = {x=num, y=num, z=num} static int l_remove_node(lua_State *L) { - //infostream<<"EnvRef::l_remove_node()"<m_env; if(env == NULL) return 0; - // pos v3s16 pos = read_v3s16(L, 2); // Do it // Call destructor MapNode n = env->getMap().getNodeNoEx(pos); scriptapi_node_on_destruct(L, pos, n); // Replace with air + // This is slightly optimized compared to addNodeWithEvent(air) bool succeeded = env->getMap().removeNodeWithEvent(pos); lua_pushboolean(L, succeeded); // Air doesn't require constructor @@ -3064,7 +3070,6 @@ private: // pos = {x=num, y=num, z=num} static int l_get_node(lua_State *L) { - //infostream<<"EnvRef::l_get_node()"<m_env; if(env == NULL) return 0; @@ -3081,7 +3086,6 @@ private: // pos = {x=num, y=num, z=num} static int l_get_node_or_nil(lua_State *L) { - //infostream<<"EnvRef::l_get_node()"<m_env; if(env == NULL) return 0; @@ -3128,6 +3132,82 @@ private: } } + // EnvRef:place_node(pos, node) + // pos = {x=num, y=num, z=num} + static int l_place_node(lua_State *L) + { + EnvRef *o = checkobject(L, 1); + ServerEnvironment *env = o->m_env; + if(env == NULL) return 0; + v3s16 pos = read_v3s16(L, 2); + MapNode n = readnode(L, 3, env->getGameDef()->ndef()); + + // Don't attempt to load non-loaded area as of now + MapNode n_old = env->getMap().getNodeNoEx(pos); + if(n_old.getContent() == CONTENT_IGNORE){ + lua_pushboolean(L, false); + return 1; + } + // Create item to place + INodeDefManager *ndef = get_server(L)->ndef(); + IItemDefManager *idef = get_server(L)->idef(); + ItemStack item(ndef->get(n).name, 1, 0, "", idef); + // Make pointed position + PointedThing pointed; + pointed.type = POINTEDTHING_NODE; + pointed.node_abovesurface = pos; + pointed.node_undersurface = pos + v3s16(0,-1,0); + // Place it with a NULL placer (appears in Lua as a non-functional + // ObjectRef) + bool success = scriptapi_item_on_place(L, item, NULL, pointed); + lua_pushboolean(L, success); + return 1; + } + + // EnvRef:dig_node(pos) + // pos = {x=num, y=num, z=num} + static int l_dig_node(lua_State *L) + { + EnvRef *o = checkobject(L, 1); + ServerEnvironment *env = o->m_env; + if(env == NULL) return 0; + v3s16 pos = read_v3s16(L, 2); + + // Don't attempt to load non-loaded area as of now + MapNode n = env->getMap().getNodeNoEx(pos); + if(n.getContent() == CONTENT_IGNORE){ + lua_pushboolean(L, false); + return 1; + } + // Dig it out with a NULL digger (appears in Lua as a + // non-functional ObjectRef) + bool success = scriptapi_node_on_dig(L, pos, n, NULL); + lua_pushboolean(L, success); + return 1; + } + + // EnvRef:punch_node(pos) + // pos = {x=num, y=num, z=num} + static int l_punch_node(lua_State *L) + { + EnvRef *o = checkobject(L, 1); + ServerEnvironment *env = o->m_env; + if(env == NULL) return 0; + v3s16 pos = read_v3s16(L, 2); + + // Don't attempt to load non-loaded area as of now + MapNode n = env->getMap().getNodeNoEx(pos); + if(n.getContent() == CONTENT_IGNORE){ + lua_pushboolean(L, false); + return 1; + } + // Punch it with a NULL puncher (appears in Lua as a non-functional + // ObjectRef) + bool success = scriptapi_node_on_punch(L, pos, n, NULL); + lua_pushboolean(L, success); + return 1; + } + // EnvRef:add_entity(pos, entityname) -> ObjectRef or nil // pos = {x=num, y=num, z=num} static int l_add_entity(lua_State *L) @@ -3482,6 +3562,9 @@ const luaL_reg EnvRef::methods[] = { method(EnvRef, get_node), method(EnvRef, get_node_or_nil), method(EnvRef, get_node_light), + method(EnvRef, place_node), + method(EnvRef, dig_node), + method(EnvRef, punch_node), method(EnvRef, add_entity), method(EnvRef, add_item), method(EnvRef, add_rat), @@ -4351,7 +4434,6 @@ void scriptapi_export(lua_State *L, Server *server) lua_getglobal(L, "minetest"); // Add tables to minetest - lua_newtable(L); lua_setfield(L, -2, "object_refs"); lua_newtable(L);