place_node, dig_node and punch_node; an in-game tester tool; remove old code
authorPerttu Ahola <celeron55@gmail.com>
Tue, 5 Jun 2012 20:09:18 +0000 (23:09 +0300)
committerPerttu Ahola <celeron55@gmail.com>
Tue, 5 Jun 2012 20:10:07 +0000 (23:10 +0300)
builtin/item.lua
doc/lua_api.txt
games/minimal/mods/experimental/init.lua
games/minimal/mods/give_initial_stuff/init.lua
src/scriptapi.cpp

index 3d545eece1efbc5b39c093ce7fe452739a3e5e52..6d75fbf706a9f47b4199d55ee98afb8c5e9b920f 100644 (file)
@@ -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
        
index 8b2b81c7512d5fa1124fb1705bb11c40b2a10b2e..5e0f2f1185ce8327ea9614d170d14bcdd131fe22 100644 (file)
@@ -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
index 8f92c13ee0dd620670aba8dd653a1fec08c9e3e7..ea11e6d3b8fcd80fcaff38b675f209780d6755f0 100644 (file)
@@ -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()))
index fef23c3288680c15028066effa46886c192a5683..29b835c7d42244c99a0b6cd4fb47a2ee016eaf8d 100644 (file)
@@ -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)
 
index 50e7236c8363b4799473c1741c290bc18745dbf3..5091216dc2f5c23d0799512e7e4b62c19d7f6918 100644 (file)
@@ -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="<<co->getId()
                                <<" hp="<<hp<<std::endl;*/
@@ -2485,7 +2489,7 @@ private:
                if(get_server(L)->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()"<<std::endl;
                EnvRef *o = checkobject(L, 1);
                ServerEnvironment *env = o->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()"<<std::endl;
                EnvRef *o = checkobject(L, 1);
                ServerEnvironment *env = o->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()"<<std::endl;
                EnvRef *o = checkobject(L, 1);
                ServerEnvironment *env = o->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()"<<std::endl;
                EnvRef *o = checkobject(L, 1);
                ServerEnvironment *env = o->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);