diff --git a/CMakeLists.txt b/CMakeLists.txt index 68fffb012..ef9016526 100644 --- a/CMakeLists.txt +++ b/CMakeLists.txt @@ -10,7 +10,7 @@ project(minetest) # Also remember to set PROTOCOL_VERSION in clientserver.h when releasing set(VERSION_MAJOR 0) set(VERSION_MINOR 4) -set(VERSION_PATCH dev-20120106-1) +set(VERSION_PATCH dev-20120122-1) set(VERSION_STRING "${VERSION_MAJOR}.${VERSION_MINOR}.${VERSION_PATCH}") MESSAGE(STATUS "*** Will build version ${VERSION_STRING} ***") diff --git a/data/builtin.lua b/data/builtin.lua index 1046e934e..3a38b60ad 100644 --- a/data/builtin.lua +++ b/data/builtin.lua @@ -80,15 +80,305 @@ function dump(o, dumped) end -- --- Built-in node definitions. Also defined in C. +-- Item definition helpers -- -minetest.register_nodedef_defaults({ +function minetest.inventorycube(img1, img2, img3) + img2 = img2 or img1 + img3 = img3 or img1 + return "[inventorycube" + .. "{" .. img1:gsub("%^", "&") + .. "{" .. img2:gsub("%^", "&") + .. "{" .. img3:gsub("%^", "&") +end + +function minetest.pos_to_string(pos) + return "(" .. pos.x .. "," .. pos.y .. "," .. pos.z .. ")" +end + +function minetest.get_pointed_thing_position(pointed_thing, above) + if pointed_thing.type == "node" then + if above then + -- The position where a node would be placed + return pointed_thing.above + else + -- The position where a node would be dug + return pointed_thing.under + end + elseif pointed_thing.type == "object" then + obj = pointed.thing.ref + if obj ~= nil then + return obj:getpos() + else + return nil + end + else + return nil + end +end + +function minetest.dir_to_facedir(dir) + if math.abs(dir.x) > math.abs(dir.z) then + if dir.x < 0 then + return 3 + else + return 1 + end + else + if dir.z < 0 then + return 2 + else + return 0 + end + end +end + +function minetest.dir_to_wallmounted(dir) + if math.abs(dir.y) > math.max(math.abs(dir.x), math.abs(dir.z)) then + if dir.y < 0 then + return 1 + else + return 0 + end + elseif math.abs(dir.x) > math.abs(dir.z) then + if dir.x < 0 then + return 3 + else + return 2 + end + else + if dir.z < 0 then + return 5 + else + return 4 + end + end +end + +function minetest.get_node_drops(nodename, toolname) + local drop = ItemStack({name=nodename}):get_definition().drop + if drop == nil then + -- default drop + return {ItemStack({name=nodename})} + elseif type(drop) == "string" then + -- itemstring drop + return {ItemStack(drop)} + elseif drop.items == nil then + -- drop = {} to disable default drop + return {} + end + + -- Extended drop table + local got_items = {} + local got_count = 0 + local _, item, tool + for _, item in ipairs(drop.items) do + local good_rarity = true + local good_tool = true + if item.rarity ~= nil then + good_rarity = item.rarity < 1 or math.random(item.rarity) == 1 + end + if item.tools ~= nil then + good_tool = false + for _, tool in ipairs(item.tools) do + if tool:sub(1, 1) == '~' then + good_tool = toolname:find(tool:sub(2)) ~= nil + else + good_tool = toolname == tool + end + if good_tool then + break + end + end + end + if good_rarity and good_tool then + got_count = got_count + 1 + for _, add_item in ipairs(item.items) do + got_items[#got_items+1] = add_item + end + if drop.max_items ~= nil and got_count == drop.max_items then + break + end + end + end + return got_items +end + +function minetest.item_place_node(itemstack, placer, pointed_thing) + local item = itemstack:peek_item() + local def = itemstack:get_definition() + if def.type == "node" and pointed_thing.type == "node" then + local pos = pointed_thing.above + local oldnode = minetest.env:get_node(pos) + local olddef = ItemStack({name=oldnode.name}):get_definition() + + if not olddef.buildable_to then + minetest.log("info", placer:get_player_name() .. " tried to place" + .. " node in invalid position " .. minetest.pos_to_string(pos) + .. ", replacing " .. oldnode.name) + return + end + + minetest.log("action", placer:get_player_name() .. " places node " + .. def.name .. " at " .. minetest.pos_to_string(pos)) + + local newnode = {name = def.name, param1 = 0, param2 = 0} + + -- Calculate direction for wall mounted stuff like torches and signs + if def.paramtype2 == 'wallmounted' then + local under = pointed_thing.under + local above = pointed_thing.above + local dir = {x = under.x - above.x, y = under.y - above.y, z = under.z - above.z} + newnode.param2 = minetest.dir_to_wallmounted(dir) + -- Calculate the direction for furnaces and chests and stuff + elseif def.paramtype2 == 'facedir' then + local playerpos = placer:getpos() + local dir = {x = pos.x - playerpos.x, y = pos.y - playerpos.y, z = pos.z - playerpos.z} + newnode.param2 = minetest.dir_to_facedir(dir) + minetest.log("action", "facedir: " .. newnode.param2) + end + + -- Add node and update + minetest.env:add_node(pos, newnode) + + -- Set metadata owner + if def.metadata_name ~= "" then + minetest.env:get_meta(pos):set_owner(placer:get_player_name()) + end + + -- Run script hook + local _, callback + for _, callback in ipairs(minetest.registered_on_placenodes) do + callback(pos, newnode, placer) + end + + itemstack:take_item() + end + return itemstack +end + +function minetest.item_place_object(itemstack, placer, pointed_thing) + local pos = minetest.get_pointed_thing_position(pointed_thing, true) + if pos ~= nil then + local item = itemstack:take_item() + minetest.env:add_item(pos, item) + end + return itemstack +end + +function minetest.item_place(itemstack, placer, pointed_thing) + if itemstack:get_definition().type == "node" then + return minetest.item_place_node(itemstack, placer, pointed_thing) + else + return minetest.item_place_object(itemstack, placer, pointed_thing) + end +end + +function minetest.item_drop(itemstack, dropper, pos) + minetest.env:add_item(pos, itemstack) + return "" +end + +function minetest.item_eat(hp_change, replace_with_item) + return function(itemstack, user, pointed_thing) -- closure + if itemstack:take_item() ~= nil then + user:set_hp(user:get_hp() + hp_change) + itemstack:add_item(replace_with_item) -- note: replace_with_item is optional + end + return itemstack + end +end + +function minetest.node_punch(pos, node, puncher) + -- Run script hook + local _, callback + for _, callback in ipairs(minetest.registered_on_punchnodes) do + callback(pos, node, puncher) + end + +end + +function minetest.node_dig(pos, node, digger) + minetest.debug("node_dig") + + local def = ItemStack({name=node.name}):get_definition() + if not def.diggable then + minetest.debug("not diggable") + minetest.log("info", digger:get_player_name() .. " tried to dig " + .. node.name .. " which is not diggable " + .. minetest.pos_to_string(pos)) + return + end + + local meta = minetest.env:get_meta(pos) + if meta ~= nil and not meta:get_allow_removal() then + minetest.debug("dig prevented by metadata") + minetest.log("info", digger:get_player_name() .. " tried to dig " + .. node.name .. ", but removal is disabled by metadata " + .. minetest.pos_to_string(pos)) + return + end + + minetest.log('action', digger:get_player_name() .. " digs " + .. node.name .. " at " .. minetest.pos_to_string(pos)) + + if not minetest.setting_getbool("creative_mode") then + local wielded = digger:get_wielded_item() + local drops = minetest.get_node_drops(node.name, wielded:get_name()) + + -- Wear out tool + mp = def.material + tp = wielded:get_tool_digging_properties() + dp = minetest.get_digging_properties(mp, tp) + 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) + end + end + + -- Remove node and update + minetest.env:remove_node(pos) + + -- Run script hook + local _, callback + for _, callback in ipairs(minetest.registered_on_dignodes) do + callback(pos, node, digger) + end +end + +-- +-- Item definition defaults +-- + +minetest.nodedef_default = { + -- Item properties + type="node", -- name intentionally not defined here + description = "", + inventory_image = "", + wield_image = "", + wield_scale = {x=1,y=1,z=1}, + stack_max = 99, + usable = false, + liquids_pointable = false, + tool_digging_properties = nil, + + -- Interaction callbacks + on_place = minetest.item_place, + on_drop = minetest.item_drop, + on_use = nil, + + on_punch = minetest.node_punch, + on_dig = minetest.node_dig, + + -- Node properties drawtype = "normal", visual_scale = 1.0, - tile_images = {"unknown_block.png"}, - inventory_image = "unknown_block.png", + tile_images = {""}, special_materials = { {image="", backface_culling=true}, {image="", backface_culling=true}, @@ -96,6 +386,7 @@ minetest.register_nodedef_defaults({ alpha = 255, post_effect_color = {a=0, r=0, g=0, b=0}, paramtype = "none", + paramtype2 = "none", is_ground_content = false, sunlight_propagates = false, walkable = true, @@ -103,11 +394,6 @@ minetest.register_nodedef_defaults({ diggable = true, climbable = false, buildable_to = false, - wall_mounted = false, - often_contains_mineral = false, - dug_item = "", - extra_dug_item = "", - extra_dug_item_rarity = 2, metadata_name = "", liquidtype = "none", liquid_alternative_flowing = "", @@ -124,12 +410,330 @@ minetest.register_nodedef_defaults({ cuttability = 0, flammability = 0, }, - cookresult_item = "", -- Cannot be cooked - furnace_cooktime = 3.0, - furnace_burntime = -1, -- Cannot be used as fuel + legacy_facedir_simple = false, + legacy_wallmounted = false, +} + +minetest.craftitemdef_default = { + type="craft", + -- name intentionally not defined here + description = "", + inventory_image = "", + wield_image = "", + wield_scale = {x=1,y=1,z=1}, + stack_max = 99, + liquids_pointable = false, + tool_digging_properties = nil, + + -- Interaction callbacks + on_place = minetest.item_place, + on_drop = minetest.item_drop, + on_use = nil, +} + +minetest.tooldef_default = { + type="tool", + -- name intentionally not defined here + description = "", + inventory_image = "", + wield_image = "", + wield_scale = {x=1,y=1,z=1}, + stack_max = 1, + liquids_pointable = false, + tool_digging_properties = nil, + + -- Interaction callbacks + on_place = minetest.item_place, + on_drop = minetest.item_drop, + on_use = nil, +} + +minetest.noneitemdef_default = { -- This is used for the hand and unknown items + type="none", + -- name intentionally not defined here + description = "", + inventory_image = "", + wield_image = "", + wield_scale = {x=1,y=1,z=1}, + stack_max = 99, + liquids_pointable = false, + tool_digging_properties = nil, + + -- Interaction callbacks + on_place = nil, + on_drop = nil, + on_use = nil, +} + +-- +-- Make raw registration functions inaccessible to anyone except builtin.lua +-- + +local register_item_raw = minetest.register_item_raw +minetest.register_item_raw = nil + +local register_alias_raw = minetest.register_alias_raw +minetest.register_item_raw = nil + +-- +-- Item / entity / ABM registration functions +-- + +minetest.registered_abms = {} +minetest.registered_entities = {} +minetest.registered_items = {} +minetest.registered_nodes = {} +minetest.registered_craftitems = {} +minetest.registered_tools = {} +minetest.registered_aliases = {} + +-- For tables that are indexed by item name: +-- If table[X] does not exist, default to table[minetest.registered_aliases[X]] +local function set_alias_metatable(table) + setmetatable(table, { + __index = function(name) + return rawget(table, minetest.registered_aliases[name]) + end + }) +end +set_alias_metatable(minetest.registered_items) +set_alias_metatable(minetest.registered_nodes) +set_alias_metatable(minetest.registered_craftitems) +set_alias_metatable(minetest.registered_tools) + +-- These item names may not be used because they would interfere +-- with legacy itemstrings +local forbidden_item_names = { + MaterialItem = true, + MaterialItem2 = true, + MaterialItem3 = true, + NodeItem = true, + node = true, + CraftItem = true, + craft = true, + MBOItem = true, + ToolItem = true, + tool = true, +} + +local function check_modname_prefix(name) + if name:sub(1,1) == ":" then + -- Escape the modname prefix enforcement mechanism + return name:sub(2) + else + -- Modname prefix enforcement + local expected_prefix = minetest.get_current_modname() .. ":" + if name:sub(1, #expected_prefix) ~= expected_prefix then + error("Name " .. name .. " does not follow naming conventions: " .. + "\"modname:\" or \":\" prefix required") + end + local subname = name:sub(#expected_prefix+1) + if subname:find("[^abcdefghijklmnopqrstuvwxyzABCDEFGHIJKLMNOPQRSTUVWXYZ0123456789_]") then + error("Name " .. name .. " does not follow naming conventions: " .. + "contains unallowed characters") + end + return name + end +end + +function minetest.register_abm(spec) + -- Add to minetest.registered_abms + minetest.registered_abms[#minetest.registered_abms+1] = spec +end + +function minetest.register_entity(name, prototype) + -- Check name + if name == nil then + error("Unable to register entity: Name is nil") + end + name = check_modname_prefix(tostring(name)) + + prototype.name = name + prototype.__index = prototype -- so that it can be used as a metatable + + -- Add to minetest.registered_entities + minetest.registered_entities[name] = prototype +end + +function minetest.register_item(name, itemdef) + -- Check name + if name == nil then + error("Unable to register item: Name is nil") + end + name = check_modname_prefix(tostring(name)) + if forbidden_item_names[name] then + error("Unable to register item: Name is forbidden: " .. name) + end + itemdef.name = name + + -- Apply defaults and add to registered_* table + if itemdef.type == "node" then + setmetatable(itemdef, {__index = minetest.nodedef_default}) + minetest.registered_nodes[itemdef.name] = itemdef + elseif itemdef.type == "craft" then + setmetatable(itemdef, {__index = minetest.craftitemdef_default}) + minetest.registered_craftitems[itemdef.name] = itemdef + elseif itemdef.type == "tool" then + setmetatable(itemdef, {__index = minetest.tooldef_default}) + minetest.registered_tools[itemdef.name] = itemdef + elseif itemdef.type == "none" then + setmetatable(itemdef, {__index = minetest.noneitemdef_default}) + else + error("Unable to register item: Type is invalid: " .. dump(itemdef)) + end + + -- Flowing liquid uses param2 + if itemdef.type == "node" and itemdef.liquidtype == "flowing" then + itemdef.paramtype2 = "flowingliquid" + end + + -- BEGIN Legacy stuff + if itemdef.cookresult_itemstring ~= nil and itemdef.cookresult_itemstring ~= "" then + minetest.register_craft({ + type="cooking", + output=itemdef.cookresult_itemstring, + recipe=itemdef.name, + cooktime=itemdef.furnace_cooktime + }) + end + if itemdef.furnace_burntime ~= nil and itemdef.furnace_burntime >= 0 then + minetest.register_craft({ + type="fuel", + recipe=itemdef.name, + burntime=itemdef.furnace_burntime + }) + end + -- END Legacy stuff + + -- Disable all further modifications + getmetatable(itemdef).__newindex = {} + + --minetest.log("Registering item: " .. itemdef.name) + minetest.registered_items[itemdef.name] = itemdef + minetest.registered_aliases[itemdef.name] = nil + register_item_raw(itemdef) +end + +function minetest.register_node(name, nodedef) + nodedef.type = "node" + minetest.register_item(name, nodedef) +end + +function minetest.register_craftitem(name, craftitemdef) + craftitemdef.type = "craft" + + -- BEGIN Legacy stuff + if craftitemdef.inventory_image == nil and craftitemdef.image ~= nil then + craftitemdef.inventory_image = craftitemdef.image + end + -- END Legacy stuff + + minetest.register_item(name, craftitemdef) +end + +function minetest.register_tool(name, tooldef) + tooldef.type = "tool" + tooldef.stack_max = 1 + + -- BEGIN Legacy stuff + if tooldef.inventory_image == nil and tooldef.image ~= nil then + tooldef.inventory_image = tooldef.image + end + if tooldef.tool_digging_properties == nil and + (tooldef.full_punch_interval ~= nil or + tooldef.basetime ~= nil or + tooldef.dt_weight ~= nil or + tooldef.dt_crackiness ~= nil or + tooldef.dt_crumbliness ~= nil or + tooldef.dt_cuttability ~= nil or + tooldef.basedurability ~= nil or + tooldef.dd_weight ~= nil or + tooldef.dd_crackiness ~= nil or + tooldef.dd_crumbliness ~= nil or + tooldef.dd_cuttability ~= nil) then + tooldef.tool_digging_properties = { + full_punch_interval = tooldef.full_punch_interval, + basetime = tooldef.basetime, + dt_weight = tooldef.dt_weight, + dt_crackiness = tooldef.dt_crackiness, + dt_crumbliness = tooldef.dt_crumbliness, + dt_cuttability = tooldef.dt_cuttability, + basedurability = tooldef.basedurability, + dd_weight = tooldef.dd_weight, + dd_crackiness = tooldef.dd_crackiness, + dd_crumbliness = tooldef.dd_crumbliness, + dd_cuttability = tooldef.dd_cuttability, + } + end + -- END Legacy stuff + + minetest.register_item(name, tooldef) +end + +function minetest.register_alias(name, convert_to) + if forbidden_item_names[name] then + error("Unable to register alias: Name is forbidden: " .. name) + end + if minetest.registered_items[name] ~= nil then + minetest.log("WARNING: Not registering alias, item with same name" .. + " is already defined: " .. name .. " -> " .. convert_to) + else + --minetest.log("Registering alias: " .. name .. " -> " .. convert_to) + minetest.registered_aliases[name] = convert_to + register_alias_raw(name, convert_to) + end +end + +-- Alias the forbidden item names to "" so they can't be +-- created via itemstrings (e.g. /give) +local name +for name in pairs(forbidden_item_names) do + minetest.registered_aliases[name] = "" + register_alias_raw(name, "") +end + + +-- Deprecated: +-- Aliases for minetest.register_alias (how ironic...) +--minetest.alias_node = minetest.register_alias +--minetest.alias_tool = minetest.register_alias +--minetest.alias_craftitem = minetest.register_alias + +-- +-- Built-in node definitions. Also defined in C. +-- + +minetest.register_item(":", { + type = "none", + wield_image = "wieldhand.png", + wield_scale = {x=1,y=1,z=2.5}, + tool_digging_properties = { + full_punch_interval = 2.0, + basetime = 0.5, + dt_weight = 1, + dt_crackiness = 0, + dt_crumbliness = -1, + dt_cuttability = 0, + basedurability = 50, + dd_weight = 0, + dd_crackiness = 0, + dd_crumbliness = 0, + dd_cuttability = 0, + } }) -minetest.register_node("air", { +minetest.register_item(":unknown", { + type = "none", + description = "Unknown Item", + inventory_image = "unknown_item.png", + on_place = minetest.item_place, + on_drop = minetest.item_drop, +}) + +minetest.register_node(":air", { + description = "Air (you hacker you!)", + inventory_image = "unknown_block.png", + wield_image = "unknown_block.png", drawtype = "airlike", paramtype = "light", sunlight_propagates = true, @@ -140,7 +744,10 @@ minetest.register_node("air", { air_equivalent = true, }) -minetest.register_node("ignore", { +minetest.register_node(":ignore", { + description = "Ignore (you hacker you!)", + inventory_image = "unknown_block.png", + wield_image = "unknown_block.png", drawtype = "airlike", paramtype = "none", sunlight_propagates = false, @@ -151,192 +758,6 @@ minetest.register_node("ignore", { air_equivalent = true, }) --- --- stackstring manipulation functions --- example stackstring: 'craft "apple" 4' --- example item: {type="craft", name="apple"} --- example item: {type="tool", name="SteelPick", wear="23272"} --- - -function stackstring_take_item(stackstring) - if stackstring == nil then - return '', nil - end - local stacktype = nil - stacktype = string.match(stackstring, - '([%a%d]+)') - if stacktype == "node" or stacktype == "craft" then - local itemtype = nil - local itemname = nil - local itemcount = nil - itemtype, itemname, itemcount = string.match(stackstring, - '([%a%d]+) "([^"]*)" (%d+)') - itemcount = tonumber(itemcount) - if itemcount == 0 then - return '', nil - elseif itemcount == 1 then - return '', {type=itemtype, name=itemname} - else - return itemtype.." \""..itemname.."\" "..(itemcount-1), - {type=itemtype, name=itemname} - end - elseif stacktype == "tool" then - local itemtype = nil - local itemname = nil - local itemwear = nil - itemtype, itemname, itemwear = string.match(stackstring, - '([%a%d]+) "([^"]*)" (%d+)') - itemwear = tonumber(itemwear) - return '', {type=itemtype, name=itemname, wear=itemwear} - end -end - -function stackstring_put_item(stackstring, item) - if item == nil then - return stackstring, false - end - stackstring = stackstring or '' - local stacktype = nil - stacktype = string.match(stackstring, - '([%a%d]+)') - stacktype = stacktype or '' - if stacktype ~= '' and stacktype ~= item.type then - return stackstring, false - end - if item.type == "node" or item.type == "craft" then - local itemtype = nil - local itemname = nil - local itemcount = nil - itemtype, itemname, itemcount = string.match(stackstring, - '([%a%d]+) "([^"]*)" (%d+)') - itemtype = itemtype or item.type - itemname = itemname or item.name - if itemcount == nil then - itemcount = 0 - end - itemcount = itemcount + 1 - return itemtype.." \""..itemname.."\" "..itemcount, true - elseif item.type == "tool" then - if stacktype ~= nil then - return stackstring, false - end - local itemtype = nil - local itemname = nil - local itemwear = nil - itemtype, itemname, itemwear = string.match(stackstring, - '([%a%d]+) "([^"]*)" (%d+)') - itemwear = tonumber(itemwear) - return itemtype.." \""..itemname.."\" "..itemwear, true - end - return stackstring, false -end - -function stackstring_put_stackstring(stackstring, src) - while src ~= '' do - --print("src="..dump(src)) - src, item = stackstring_take_item(src) - --print("src="..dump(src).." item="..dump(item)) - local success - stackstring, success = stackstring_put_item(stackstring, item) - if not success then - return stackstring, false - end - end - return stackstring, true -end - -function test_stackstring() - local stack - local item - local success - - stack, item = stackstring_take_item('node "TNT" 3') - assert(stack == 'node "TNT" 2') - assert(item.type == 'node') - assert(item.name == 'TNT') - - stack, item = stackstring_take_item('craft "with spaces" 2') - assert(stack == 'craft "with spaces" 1') - assert(item.type == 'craft') - assert(item.name == 'with spaces') - - stack, item = stackstring_take_item('craft "with spaces" 1') - assert(stack == '') - assert(item.type == 'craft') - assert(item.name == 'with spaces') - - stack, item = stackstring_take_item('craft "s8df2kj3" 0') - assert(stack == '') - assert(item == nil) - - stack, item = stackstring_take_item('tool "With Spaces" 32487') - assert(stack == '') - assert(item.type == 'tool') - assert(item.name == 'With Spaces') - assert(item.wear == 32487) - - stack, success = stackstring_put_item('node "With Spaces" 40', - {type='node', name='With Spaces'}) - assert(stack == 'node "With Spaces" 41') - assert(success == true) - - stack, success = stackstring_put_item('craft "With Spaces" 40', - {type='craft', name='With Spaces'}) - assert(stack == 'craft "With Spaces" 41') - assert(success == true) - - stack, success = stackstring_put_item('tool "With Spaces" 32487', - {type='tool', name='With Spaces'}) - assert(stack == 'tool "With Spaces" 32487') - assert(success == false) - - stack, success = stackstring_put_item('node "With Spaces" 40', - {type='tool', name='With Spaces'}) - assert(stack == 'node "With Spaces" 40') - assert(success == false) - - assert(stackstring_put_stackstring('node "With Spaces" 2', - 'node "With Spaces" 1') == 'node "With Spaces" 3') -end -test_stackstring() - --- --- NodeItem helpers --- - -minetest.inventorycube = function(img1, img2, img3) - img2 = img2 or img1 - img3 = img3 or img1 - return "[inventorycube" - .. "{" .. img1:gsub("%^", "&") - .. "{" .. img2:gsub("%^", "&") - .. "{" .. img3:gsub("%^", "&") -end - --- --- CraftItem helpers --- - -minetest.craftitem_place_item = function(item, placer, pos) - --print("craftitem_place_item") - --print("item: " .. dump(item)) - --print("placer: " .. dump(placer)) - --print("pos: " .. dump(pos)) - minetest.env:add_item(pos, 'craft "' .. item .. '" 1') - return true -end - -minetest.craftitem_eat = function(hp_change) - return function(item, user, pointed_thing) -- closure - --print("craftitem_eat(" .. hp_change .. ")") - --print("item: " .. dump(item)) - --print("user: " .. dump(user)) - --print("pointed_thing: " .. dump(pointed_thing)) - user:set_hp(user:get_hp() + hp_change) - return true - end -end - -- -- Default material types -- @@ -422,7 +843,7 @@ end -- Callback registration -- -function make_registration() +local function make_registration() local t = {} local registerfunc = function(func) table.insert(t, func) end return t, registerfunc @@ -438,4 +859,10 @@ minetest.registered_on_newplayers, minetest.register_on_newplayer = make_registr minetest.registered_on_dieplayers, minetest.register_on_dieplayer = make_registration() minetest.registered_on_respawnplayers, minetest.register_on_respawnplayer = make_registration() +-- +-- Set random seed +-- + +math.randomseed(os.time()) + -- END diff --git a/data/clienttextures/unknown_item.png b/data/clienttextures/unknown_item.png new file mode 100644 index 000000000..35cabf0ad Binary files /dev/null and b/data/clienttextures/unknown_item.png differ diff --git a/data/mods/bucket/init.lua b/data/mods/bucket/init.lua index 639a614d4..8ed9da522 100644 --- a/data/mods/bucket/init.lua +++ b/data/mods/bucket/init.lua @@ -1,80 +1,95 @@ -- bucket (Minetest 0.4 mod) -- A bucket, which can pick up water and lava -minetest.alias_craftitem("bucket", "bucket:bucket_empty") -minetest.alias_craftitem("bucket_water", "bucket:bucket_water") -minetest.alias_craftitem("bucket_lava", "bucket:bucket_lava") +minetest.register_alias("bucket", "bucket:bucket_empty") +minetest.register_alias("bucket_water", "bucket:bucket_water") +minetest.register_alias("bucket_lava", "bucket:bucket_lava") minetest.register_craft({ - output = 'craft "bucket:bucket_empty" 1', + output = 'bucket:bucket_empty 1', recipe = { - {'craft "steel_ingot"', '', 'craft "steel_ingot"'}, - {'', 'craft "steel_ingot"', ''}, + {'default:steel_ingot', '', 'default:steel_ingot'}, + {'', 'default:steel_ingot', ''}, } }) +bucket = {} +bucket.liquids = {} + +-- Register a new liquid +-- source = name of the source node +-- flowing = name of the flowing node +-- itemname = name of the new bucket item (or nil if liquid is not takeable) +-- inventory_image = texture of the new bucket item (ignored if itemname == nil) +-- This function can be called from any mod (that depends on bucket). +function bucket.register_liquid(source, flowing, itemname, inventory_image) + bucket.liquids[source] = { + source = source, + flowing = flowing, + itemname = itemname, + } + bucket.liquids[flowing] = bucket.liquids[source] + + if itemname ~= nil then + minetest.register_craftitem(itemname, { + inventory_image = inventory_image, + stack_max = 1, + liquids_pointable = true, + on_use = function(itemstack, user, pointed_thing) + -- Must be pointing to node + if pointed_thing.type ~= "node" then + return + end + -- Check if pointing to a liquid + n = minetest.env:get_node(pointed_thing.under) + if bucket.liquids[n.name] == nil then + -- Not a liquid + minetest.env:add_node(pointed_thing.above, {name=source}) + elseif n.name ~= source then + -- It's a liquid + minetest.env:add_node(pointed_thing.under, {name=source}) + end + return {name="bucket:bucket_empty"} + end + }) + end +end + minetest.register_craftitem("bucket:bucket_empty", { - image = "bucket.png", + inventory_image = "bucket.png", stack_max = 1, liquids_pointable = true, - on_place_on_ground = minetest.craftitem_place_item, - on_use = function(item, player, pointed_thing) - if pointed_thing.type == "node" then - n = minetest.env:get_node(pointed_thing.under) - if n.name == "default:water_source" then - minetest.env:add_node(pointed_thing.under, {name="air"}) - player:add_to_inventory_later('craft "bucket:bucket_water" 1') - return true - elseif n.name == "default:lava_source" then - minetest.env:add_node(pointed_thing.under, {name="air"}) - player:add_to_inventory_later('craft "bucket:bucket_lava" 1') - return true - end + on_use = function(itemstack, user, pointed_thing) + -- Must be pointing to node + if pointed_thing.type ~= "node" then + return + end + -- Check if pointing to a liquid source + n = minetest.env:get_node(pointed_thing.under) + liquiddef = bucket.liquids[n.name] + if liquiddef ~= nil and liquiddef.source == n.name and liquiddef.itemname ~= nil then + minetest.env:add_node(pointed_thing.under, {name="air"}) + return {name=liquiddef.itemname} end - return false end, }) -minetest.register_craftitem("bucket:bucket_water", { - image = "bucket_water.png", - stack_max = 1, - liquids_pointable = true, - on_place_on_ground = minetest.craftitem_place_item, - on_use = function(item, player, pointed_thing) - if pointed_thing.type == "node" then - n = minetest.env:get_node(pointed_thing.under) - if n.name == "default:water_source" then - -- unchanged - elseif n.name == "default:water_flowing" or n.name == "default:lava_source" or n.name == "default:lava_flowing" then - minetest.env:add_node(pointed_thing.under, {name="default:water_source"}) - else - minetest.env:add_node(pointed_thing.above, {name="default:water_source"}) - end - player:add_to_inventory_later('craft "bucket:bucket_empty" 1') - return true - end - return false - end, -}) +bucket.register_liquid( + "default:water_source", + "default:water_flowing", + "bucket:bucket_water", + "bucket_water.png" +) -minetest.register_craftitem("bucket:bucket_lava", { - image = "bucket_lava.png", - stack_max = 1, - liquids_pointable = true, - on_place_on_ground = minetest.craftitem_place_item, - on_use = function(item, player, pointed_thing) - if pointed_thing.type == "node" then - n = minetest.env:get_node(pointed_thing.under) - if n.name == "default:lava_source" then - -- unchanged - elseif n.name == "default:water_source" or n.name == "default:water_flowing" or n.name == "default:lava_flowing" then - minetest.env:add_node(pointed_thing.under, {name="default:lava_source"}) - else - minetest.env:add_node(pointed_thing.above, {name="default:lava_source"}) - end - player:add_to_inventory_later('craft "bucket:bucket_empty" 1') - return true - end - return false - end, +bucket.register_liquid( + "default:lava_source", + "default:lava_flowing", + "bucket:bucket_lava", + "bucket_lava.png" +) + +minetest.register_craft({ + type = "fuel", + recipe = "default:bucket_lava", + burntime = 60, }) diff --git a/data/mods/default/init.lua b/data/mods/default/init.lua index aa03eabe8..f0e6b6dc2 100644 --- a/data/mods/default/init.lua +++ b/data/mods/default/init.lua @@ -77,24 +77,25 @@ -- eg. 'tool "default:pick_wood" 21323' -- eg. 'craft "default:apple" 2' -- --- item: A single item in Lua table format. --- eg. {type="node", name="default:dirt"} +-- item: A stack of items in Lua table format. +-- eg. {name="default:dirt", count=1, wear=0, metadata=""} -- ^ a single dirt node --- eg. {type="tool", name="default:pick_wood", wear=21323} +-- eg. {name="default:pick_wood", count=1, wear=21323, metadata=""} -- ^ a wooden pick about 1/3 weared out --- eg. {type="craft", name="default:apple"} +-- eg. {name="default:apple", count=1, wear=0, metadata=""} -- ^ an apple. -- +-- Any time an item must be passed to a function, it can be an +-- ItemStack (see below), an itemstring or a table in the above format. +-- -- Global functions: -- minetest.register_entity(name, prototype table) --- minetest.register_tool(name, tool definition) --- minetest.register_node(name, node definition) --- minetest.register_craftitem(name, craftitem definition) --- minetest.register_craft(recipe) -- minetest.register_abm(abm definition) --- minetest.alias_node(name, convert_to) --- minetest.alias_tool(name, convert_to) --- minetest.alias_craftitem(name, convert_to) +-- minetest.register_node(name, node definition) +-- minetest.register_tool(name, item definition) +-- minetest.register_craftitem(name, item definition) +-- minetest.register_alias(name, convert_to) +-- minetest.register_craft(recipe) -- minetest.register_globalstep(func(dtime)) -- minetest.register_on_placenode(func(pos, newnode, placer)) -- minetest.register_on_dignode(func(pos, oldnode, digger)) @@ -113,13 +114,16 @@ -- minetest.chat_send_player(name, text) -- minetest.get_player_privs(name) -> set of privs -- minetest.get_inventory(location) -> InvRef --- minetest.get_modpath(modname) -> eg. "/home/user/.minetest/usermods/modname" -- ^ location = eg. {type="player", name="celeron55"} -- {type="node", pos={x=, y=, z=}} +-- minetest.get_current_modname() -> string +-- minetest.get_modpath(modname) -> eg. "/home/user/.minetest/usermods/modname" -- --- stackstring_take_item(stackstring) -> stackstring, item --- stackstring_put_item(stackstring, item) -> stackstring, success --- stackstring_put_stackstring(stackstring, stackstring) -> stackstring, success +-- minetest.debug(line) +-- ^ Goes to dstream +-- minetest.log(line) +-- minetest.log(loglevel, line) +-- ^ loglevel one of "error", "action", "info", "verbose" -- -- minetest.digprop_constanttime(time) -- minetest.digprop_stonelike(toughness) @@ -133,10 +137,14 @@ -- minetest.env - environment reference -- -- Global tables: +-- minetest.registered_items +-- ^ List of registered items, indexed by name -- minetest.registered_nodes -- ^ List of registered node definitions, indexed by name -- minetest.registered_craftitems -- ^ List of registered craft item definitions, indexed by name +-- minetest.registered_tools +-- ^ List of registered tool definitions, indexed by name -- minetest.registered_entities -- ^ List of registered entity prototypes, indexed by name -- minetest.object_refs @@ -161,6 +169,8 @@ -- - get_meta(pos) -- Get a NodeMetaRef at that position -- - get_player_by_name(name) -- Get an ObjectRef to a player -- - get_objects_inside_radius(pos, radius) +-- - set_timeofday(val): val: 0...1; 0 = midnight, 0.5 = midday +-- - get_timeofday() -- -- NodeMetaRef (this stuff is subject to change in a future version) -- - get_type() @@ -168,11 +178,10 @@ -- - set_text(text) -- eg. set the text of a sign -- - get_text() -- - get_owner() +-- - set_owner(string) -- Generic node metadata specific: -- - set_infotext(infotext) -- - get_inventory() -> InvRef --- - inventory_set_list(name, {item1, item2, ...}) --- - inventory_get_list(name) -- - set_inventory_draw_spec(string) -- - set_allow_text_input(bool) -- - set_allow_removal(bool) @@ -194,12 +203,13 @@ -- ^ puncher = an another ObjectRef, -- ^ time_from_last_punch = time since last punch action of the puncher -- - right_click(clicker); clicker = an another ObjectRef --- - get_wield_digging_properties() -> digging property table --- - damage_wielded_item(num) (item damage/wear range is 0-65535) --- - add_to_inventory(itemstring): add an item to object inventory (actually only works for the player as of now) --- - add_to_inventory_later(itemstring): like above, but after callback returns (only allowed for craftitem callbacks) -- - get_hp(): returns number of hitpoints (2 * number of hearts) -- - set_hp(hp): set number of hitpoints (2 * number of hearts) +-- - get_inventory() -> InvRef +-- - get_wield_list(): returns the name of the inventory list the wielded item is in +-- - get_wield_index(): returns the index of the wielded item +-- - get_wielded_item() -> ItemStack +-- - set_wielded_item(item): replaces the wielded item, returns true if successful -- LuaEntitySAO-only: (no-op for other objects) -- - setvelocity({x=num, y=num, z=num}) -- - getvelocity() -> {x=num, y=num, z=num} @@ -216,9 +226,6 @@ -- - get_luaentity() -- Player-only: (no-op for other objects) -- - get_player_name(): will return nil if is not a player --- - get_inventory() -> InvRef --- - inventory_set_list(name, {item1, item2, ...}) --- - inventory_get_list(name) -> {item1, item2, ...} -- - get_look_dir(): get camera direction as a unit vector -- - get_look_pitch(): pitch in radians -- - get_look_yaw(): yaw in radians (wraps around pretty randomly as of now) @@ -230,14 +237,41 @@ -- - set_stack(listname, i, stack): copy stack to index i in list -- - get_list(listname): return full list -- - set_list(listname, list): set full list (size will not change) --- - autoinsert_stack(listname, stack): insert stack somewhere in list --- - autoinsert_stackstring(listname, stackstring) +-- - add_item(listname, stack): add item somewhere in list, returns leftover ItemStack +-- - room_for_item(listname, stack): returns true if the stack of items +-- can be fully added to the list +-- - contains_item(listname, stack): returns true if the stack of items +-- can be fully taken from the list +-- remove_item(listname, stack): take as many items as specified from the list, +-- returns the items that were actually removed (as an ItemStack) -- -- ItemStack methods: --- - peek_item(): return item from stack without removing it --- - take_item(): remove item from stack and return it --- - put_item(item): put item in stack; return false if not possible --- - put_stackstring(stackstring): return false if not possible +-- - is_empty(): return true if stack is empty +-- - get_name(): returns item name (e.g. "default:stone") +-- - get_count(): returns number of items on the stack +-- - get_wear(): returns tool wear (0-65535), 0 for non-tools +-- - get_metadata(): returns metadata (a string attached to an item stack) +-- - clear(): removes all items from the stack, making it empty +-- - replace(item): replace the contents of this stack (item can also +-- be an itemstring or table) +-- - to_string(): returns the stack in itemstring form +-- - to_table(): returns the stack in Lua table form +-- - get_stack_max(): returns the maximum size of the stack (depends on the item) +-- - get_free_space(): returns get_stack_max() - get_count() +-- - is_known(): returns true if the item name refers to a defined item type +-- - get_definition(): returns the item definition table +-- - get_tool_digging_properties(): returns the digging properties of the item, +-- ^ or those of the hand if none are defined for this item type +-- - add_wear(amount): increases wear by amount if the item is a tool +-- - add_item(item): put some item or stack onto this stack, +-- ^ returns leftover ItemStack +-- - item_fits(item): returns true if item or stack can be fully added to this one +-- - take_item(n): take (and remove) up to n items from this stack +-- ^ returns taken ItemStack +-- ^ if n is omitted, n=1 is used +-- - peek_item(n): copy (don't remove) up to n items from this stack +-- ^ returns copied ItemStack +-- ^ if n is omitted, n=1 is used -- -- Registered entities: -- - Functions receive a "luaentity" as self: @@ -271,29 +305,38 @@ -- myvariable = whatever, -- } -- --- Tool definition: +-- Item definition options (register_node, register_craftitem, register_tool) -- { --- image = "default_tool_steelaxe.png", --- full_punch_interval = 1.0, --- basetime = 1.0, --- dt_weight = 0.5, --- dt_crackiness = -0.2, --- dt_crumbliness = 1, --- dt_cuttability = -0.5, --- basedurability = 330, --- dd_weight = 0, --- dd_crackiness = 0, --- dd_crumbliness = 0, --- dd_cuttability = 0, +-- description = "Steel Axe", +-- inventory_image = "default_tool_steelaxe.png", +-- wield_image = "", +-- wield_scale = {x=1,y=1,z=1}, +-- stack_max = 99, +-- liquids_pointable = false, +-- tool_digging_properties = { +-- full_punch_interval = 1.0, +-- basetime = 1.0, +-- dt_weight = 0.5, +-- dt_crackiness = -0.2, +-- dt_crumbliness = 1, +-- dt_cuttability = -0.5, +-- basedurability = 330, +-- dd_weight = 0, +-- dd_crackiness = 0, +-- dd_crumbliness = 0, +-- dd_cuttability = 0, +-- } +-- on_drop = func(item, dropper, pos), +-- on_place = func(item, placer, pointed_thing), +-- on_use = func(item, user, pointed_thing), -- } -- --- Node definition options: +-- Node definition options (register_node): -- { --- name = "modname:somenode", +-- , -- drawtype = "normal", -- visual_scale = 1.0, -- tile_images = {"default_unknown_block.png"}, --- inventory_image = "default_unknown_block.png", -- special_materials = { -- {image="", backface_culling=true}, -- {image="", backface_culling=true}, @@ -301,6 +344,7 @@ -- alpha = 255, -- post_effect_color = {a=0, r=0, g=0, b=0}, -- paramtype = "none", +-- paramtype2 = "none", -- is_ground_content = false, -- sunlight_propagates = false, -- walkable = true, @@ -308,11 +352,8 @@ -- diggable = true, -- climbable = false, -- buildable_to = false, --- wall_mounted = false, --- often_contains_mineral = false, --- dug_item = "", --- extra_dug_item = "", --- extra_dug_item_rarity = 2, +-- drop = "", +-- -- alternatively drop = { max_items = ..., items = { ... } } -- metadata_name = "", -- liquidtype = "none", -- liquid_alternative_flowing = "", @@ -329,34 +370,54 @@ -- cuttability = 0, -- flammability = 0, -- }, --- cookresult_itemstring = "", -- Cannot be cooked --- furnace_cooktime = 3.0, --- furnace_burntime = -1, -- Cannot be used as fuel +-- legacy_facedir_simple = false, -- Support maps made in and before January 2012 +-- legacy_wallmounted = false, -- Support maps made in and before January 2012 -- } -- --- Craftitem definition options: --- minetest.register_craftitem("modname_name", { --- image = "default_image.png", --- stack_max = , --- cookresult_itemstring = itemstring (result of cooking), --- furnace_cooktime = , --- furnace_burntime =