diff --git a/mods/ITEMS/mcl_buckets/init.lua b/mods/ITEMS/mcl_buckets/init.lua index e3e1c3f85..c8b9d9759 100644 --- a/mods/ITEMS/mcl_buckets/init.lua +++ b/mods/ITEMS/mcl_buckets/init.lua @@ -212,12 +212,12 @@ minetest.register_craftitem("mcl_buckets:bucket_empty", { -- Check if pointing to a liquid source local liquiddef = mcl_buckets.liquids[nn] local new_bucket - local cauldron_stuff + local cauldron_substance if mcl_cauldrons.is_cauldron(node) then if mcl_cauldrons.get_level(node, "cauldron_water") > 0 then - cauldron_stuff = "cauldron_water" + cauldron_substance = "cauldron_water" elseif mcl_cauldrons.get_level(node, "cauldron_river_water") > 0 then - cauldron_stuff = "cauldron_river_water" + cauldron_substance = "cauldron_river_water" end end if liquiddef ~= nil and liquiddef.itemname ~= nil and (nn == liquiddef.source_take) then @@ -237,7 +237,7 @@ minetest.register_craftitem("mcl_buckets:bucket_empty", { doc.mark_entry_as_revealed(user:get_player_name(), "nodes", nn) end - elseif cauldron_stuff then + elseif cauldron_substance then -- Cauldron local newnode local CAULDRON_TO_BUCKET = { @@ -245,7 +245,7 @@ minetest.register_craftitem("mcl_buckets:bucket_empty", { ["cauldron_river_water"]={bucket="mcl_buckets:bucket_river_water", sound="mcl_core:water_source"}, } for cauldron_specifier, bucket_spec in pairs(CAULDRON_TO_BUCKET) do - newnode = mcl_cauldrons.drain_levels(node, mcl_cauldrons.BUCKETFUL, cauldron_specifier) + newnode = mcl_cauldrons.drain_levels(node, mcl_cauldrons.BUCKET_FILL_LEVELS, cauldron_specifier) if node ~= newnode then -- substance was taken out. minetest.set_node(pointed_thing.under, newnode) diff --git a/mods/ITEMS/mcl_buckets/register.lua b/mods/ITEMS/mcl_buckets/register.lua index c0f753ad1..d30fc7d05 100644 --- a/mods/ITEMS/mcl_buckets/register.lua +++ b/mods/ITEMS/mcl_buckets/register.lua @@ -17,6 +17,28 @@ end end end]] +function mcl_buckets.get_bucket_from_cauldron(bucket_name, sound_name, cauldron_substance, pos, placer) + local node = minetest.get_node(pos) + if not mcl_cauldrons.is_cauldron(node) then + return nil + end + local placer_name = "" + if placer ~= nil then + placer_name = placer:get_player_name() + end + if placer and minetest.is_protected(pos, placer_name) then + minetest.record_protection_violation(pos, placer_name) + return nil + end + local newnode = mcl_cauldrons.fill_levels(node, mcl_cauldrons.BUCKET_FILL_LEVELS, cauldron_substance) + if newnode ~= node then + minetest.set_node(pos, newnode) + sound_place(sound_name, pos) + return bucket_name + end + return nil +end + if mod_mcl_core then -- Lava bucket mcl_buckets.register_liquid({ @@ -73,25 +95,7 @@ if mod_mcl_core then groups = { water_bucket = 1 }, -- TODO: this is getting clunkier by the commit, re-do handling of bucket/cauldron interaction (as a node callback, this function contains too many side effects). _mcl_get_bucket_from_cauldron = function(pos, placer) - local node = minetest.get_node(pos) - if not mcl_cauldrons.is_cauldron(node) then - return nil - end - local placer_name = "" - if placer ~= nil then - placer_name = placer:get_player_name() - end - if placer and minetest.is_protected(pos, placer_name) then - minetest.record_protection_violation(pos, placer_name) - return nil - end - local newnode = mcl_cauldrons.fill_levels(node, mcl_cauldrons.BUCKETFUL, "cauldron_water") - if newnode ~= node then - minetest.set_node(pos, newnode) - sound_place("mcl_core:water_source", pos) - return "mcl_buckets:bucket_water" - end - return nil + return mcl_buckets.get_bucket_from_cauldron("mcl_buckets:bucket_water", "mcl_core:water_source", "cauldron_water", pos, placer) end, }) end @@ -127,25 +131,7 @@ if mod_mclx_core then end, groups = { water_bucket = 1 }, _mcl_get_bucket_from_cauldron = function(pos, placer) - local node = minetest.get_node(pos) - if not mcl_cauldrons.is_cauldron(node) then - return nil - end - local placer_name = "" - if placer ~= nil then - placer_name = placer:get_player_name() - end - if placer and minetest.is_protected(pos, placer_name) then - minetest.record_protection_violation(pos, placer_name) - return nil - end - local newnode = mcl_cauldrons.fill_levels(node, mcl_cauldrons.BUCKETFUL, "cauldron_river_water") - if newnode ~= node then - minetest.set_node(pos, newnode) - sound_place("mcl_core:water_source", pos) - return "mcl_buckets:bucket_river_water" - end - return nil + return mcl_buckets.get_bucket_from_cauldron("mcl_buckets:bucket_river_water", "mcl_core:water_source", "cauldron_river_water", pos, placer) end, }) end diff --git a/mods/ITEMS/mcl_cauldrons/API.md b/mods/ITEMS/mcl_cauldrons/API.md index 768815dcb..61eec040d 100644 --- a/mods/ITEMS/mcl_cauldrons/API.md +++ b/mods/ITEMS/mcl_cauldrons/API.md @@ -14,8 +14,8 @@ Extensions to the base node definition descriptor (as passed to `minetest.regist * `.groups.cauldron_water`: 1 - contains water * `.groups.cauldron_river_water`: 1 - contains river water -* `.mcl_on_fill(node, amount)`: returns node { name, param1, param2 } -* `.mcl_on_drain(node, amount)`: returns node { name, param1, param2 } +* `._mcl_on_fill(node, amount)`: returns node { name, param1, param2 } +* `._mcl_on_drain(node, amount)`: returns node { name, param1, param2 } ### `mcl_cauldrons.registered_cauldrons` diff --git a/mods/ITEMS/mcl_cauldrons/api.lua b/mods/ITEMS/mcl_cauldrons/api.lua index a42b1a2d5..e0b0833ef 100644 --- a/mods/ITEMS/mcl_cauldrons/api.lua +++ b/mods/ITEMS/mcl_cauldrons/api.lua @@ -4,8 +4,8 @@ mcl_cauldrons.registered_cauldrons = {} -- symbolic constants. -mcl_cauldrons.BUCKETFUL = 3 -mcl_cauldrons.BOTTLEFUL = 1 +mcl_cauldrons.BUCKET_FILL_LEVELS = 3 +mcl_cauldrons.BOTTLE_FILL_LEVELS = 1 -- Find cauldron from registered cauldrons -> string, table @@ -15,31 +15,32 @@ mcl_cauldrons.BOTTLEFUL = 1 -- Returns 2 values: node_name:string, node_definition:table; -- if nothing else matches, returns empty cauldron ("mcl_cauldrons:cauldron"). function mcl_cauldrons.find_cauldron(substance, fill_level) + local empty_nodename = "mcl_cauldrons:cauldron" + local empty_nodedef = mcl_cauldrons.registered_cauldrons[empty_nodename] if (substance == "") then - fill_level = 0 + return empty_nodename, empty_nodedef end for nodename, nodedef in pairs(mcl_cauldrons.registered_cauldrons) do -- matched on substance: 'any', or exact match from .groups. - local substantial = (substance == nil) or (nodedef.groups[substance] and (nodedef.groups[substance] > 0)) + local match_substance = (substance == nil) or (nodedef.groups[substance] and (nodedef.groups[substance] ~= 0)) -- matched on fill_level: 'any', or exact match from .groups. - local filling = (fill_level == nil) or (nodedef.groups.cauldron_filled == fill_level) - if substantial and filling then + local match_level = (fill_level == nil) or (nodedef.groups.cauldron_filled == fill_level) + if match_substance and match_level then return nodename, nodedef end end -- no match, use empty. - local nodename = "mcl_cauldrons:cauldron" - return nodename, mcl_cauldrons.registered_cauldrons[nodename] + return empty_nodename, empty_nodedef end -- Test: node describes a cauldron -> boolean function mcl_cauldrons.is_cauldron(node) - return (minetest.get_item_group(node.name, "cauldron") > 0) + return (minetest.get_item_group(node.name, "cauldron") ~= 0) end -- Test: cauldron node contains specified substance -> boolean function mcl_cauldrons.has_substance(node, substance) - return (minetest.get_item_group(node.name, substance) > 0) + return (minetest.get_item_group(node.name, substance) ~= 0) end -- Get maximum number of levels available for cauldron node -> number @@ -98,32 +99,18 @@ end -- returns a node table as accepted by minetest.set_node() function mcl_cauldrons.fill_levels(node, change_levels, substance) local nodedef = mcl_cauldrons.registered_cauldrons[node.name] - local callback = nodedef.mcl_on_fill - local newnode - if callback then - -- specific rules. - newnode = callback(node, change_levels, substance) - end - if newnode == nil then - -- revert changes. - newnode = node - end + local callback = nodedef._mcl_on_fill + -- use callback if available, else revert. + local newnode = callback and callback(node, change_levels, substance) or node return newnode end -- drain counterpart to fill_levels() function mcl_cauldrons.drain_levels(node, change_levels, substance) local nodedef = mcl_cauldrons.registered_cauldrons[node.name] - local callback = nodedef.mcl_on_drain - local newnode - if callback then - -- specific rules. - newnode = callback(node, change_levels, substance) - end - if newnode == nil then - -- revert changes. - newnode = node - end + local callback = nodedef._mcl_on_drain + -- use callback if available, else revert. + local newnode = callback and callback(node, change_levels, substance) or node return newnode end diff --git a/mods/ITEMS/mcl_cauldrons/register.lua b/mods/ITEMS/mcl_cauldrons/register.lua index 87787ae19..34f2db53b 100644 --- a/mods/ITEMS/mcl_cauldrons/register.lua +++ b/mods/ITEMS/mcl_cauldrons/register.lua @@ -3,16 +3,13 @@ local S = minetest.get_translator(minetest.get_current_modname()) -- Convenience function because the cauldron nodeboxes are very similar local create_cauldron_nodebox = function(water_level) - local floor_y - if water_level == 0 then -- empty - floor_y = -0.1875 - elseif water_level == 1 then -- 1/3 filled - floor_y = 1/16 - elseif water_level == 2 then -- 2/3 filled - floor_y = 4/16 - elseif water_level == 3 then -- full - floor_y = 7/16 - end + local floors_table = { + [0]=-0.1875, -- empty + [1]=1/16, -- 1/3 filled + [2]=4/16, -- 2/3 filled + [3]=7/16, -- full + } + local floor_y = floors_table[water_level] return { type = "fixed", fixed = { @@ -42,17 +39,82 @@ end -- The normal Lua means of inheritance uses setmetatable. -- For node definitions, minetest.register_node() breaks/overwrite the metatable for its own use. --- This function copies in the "old" keys/values, to lets them be overwritten by another (newer) table. --- Care should be exercised updating/modifying the return value, as nested tables are copied by reference (viz. followup code might end up modifying nested tables in the *parent* defintion). +-- This function copies in the "old" keys/values, to let them be overwritten by another (newer) table. +-- Nested tables are recursively merged/copied, so nested keys may be selectively overridden. +-- Modifying the returned table does not risk mangling the source/parent table. -- This workaround happens to work as declarative objects do not change after instantiation. local function merge_tables(a,b) local result = {} for k,v in pairs(a) do result[k]=v end - for k,v in pairs(b) do result[k]=v end + for k,v in pairs(b) do + if type(a[k]) == "table" then + -- recursive merge table (with copy). + result[k] = merge_tables(a[k], v) + else + result[k] = v + end + end return result end +function mcl_cauldrons.empty_cauldron_on_fill(node, change_levels, substance) + -- base rules for cauldrons. + if change_levels <= 0 then + -- no change. + return nil + end + local old_level = mcl_cauldrons.get_level(node) + local whole, fraction = math.modf(change_levels) + local new_level + if fraction > 0 then + if math.random() < fraction then + whole = whole + 1 + end + end + if (substance and mcl_cauldrons.has_substance(node, substance)) or (substance == nil) then + -- same substance, add more. + new_level = old_level + whole + else + -- different substance, delete old content. + new_level = whole + end + -- clamp 0 through 3 inclusive. + new_level = math.max(0, math.min(new_level, 3)) + local newnode = mcl_cauldrons.set_level(node, new_level, substance) + return newnode +end + +function mcl_cauldrons.empty_cauldron_on_drain(node, change_levels, substance) + -- base rules for cauldrons. + if change_levels <= 0 then + -- no change. + return nil + end + if (substance and not mcl_cauldrons.has_substance(node, substance)) then + -- different substance, cannot drain. + return nil + end + local old_level = mcl_cauldrons.get_level(node) + local whole, fraction = math.modf(change_levels) + local new_level + if fraction > 0 then + if math.random() < fraction then + whole = whole + 1 + end + end + if (whole > old_level) then + -- insufficient amount, no change. + return nil + end + -- same substance, drain. + new_level = old_level - whole + -- clamp 0 through 3 inclusive. + new_level = math.max(0, math.min(new_level, 3)) + local newnode = mcl_cauldrons.set_level(node, new_level, substance) + return newnode +end + -- Empty cauldron mcl_cauldrons.register_cauldron_node("mcl_cauldrons:cauldron", { description = S("Cauldron"), @@ -77,60 +139,11 @@ mcl_cauldrons.register_cauldron_node("mcl_cauldrons:cauldron", { _mcl_hardness = 2, _mcl_blast_resistance = 2, - mcl_on_fill = function(node, change_levels, substance) - -- base rules for cauldrons. - if change_levels <= 0 then - -- no change. - return nil - end - local old_level = mcl_cauldrons.get_level(node) - local whole, fraction = math.modf(change_levels) - local new_level - if fraction > 0 then - if math.random() < fraction then - whole = whole + 1 - end - end - if (substance and mcl_cauldrons.has_substance(node, substance)) or (substance == nil) then - -- same substance, add more. - new_level = old_level + whole - else - -- different substance, delete old content. - new_level = whole - end - -- clamp 0 through 3 inclusive. - new_level = math.max(0, math.min(new_level, 3)) - local newnode = mcl_cauldrons.set_level(node, new_level, substance) - return newnode + _mcl_on_fill = function(node, change_levels, substance) + return mcl_cauldrons.empty_cauldron_on_fill(node, change_levels, substance) end, - mcl_on_drain = function(node, change_levels, substance) - -- base rules for cauldrons. - if change_levels <= 0 then - -- no change. - return nil - end - if (substance and not mcl_cauldrons.has_substance(node, substance)) then - -- different substance, cannot drain. - return nil - end - local old_level = mcl_cauldrons.get_level(node) - local whole, fraction = math.modf(change_levels) - local new_level - if fraction > 0 then - if math.random() < fraction then - whole = whole + 1 - end - end - if (whole > old_level) then - -- insufficient amount, no change. - return nil - end - -- same substance, drain. - new_level = old_level - whole - -- clamp 0 through 3 inclusive. - new_level = math.max(0, math.min(new_level, 3)) - local newnode = mcl_cauldrons.set_level(node, new_level, substance) - return newnode + _mcl_on_drain = function(node, change_levels, substance) + return mcl_cauldrons.empty_cauldron_on_drain(node, change_levels, substance) end, }) @@ -161,11 +174,7 @@ mcl_cauldrons.register_cauldron_node("mcl_cauldrons:cauldron_water_2", merge_tables(mcl_cauldrons.registered_cauldrons["mcl_cauldrons:cauldron_water_1"], { description = S("Cauldron (2/3 Water)"), groups = { - pickaxey = 1, - cauldron = 1, cauldron_filled = 2, - cauldron_maximum = 3, - cauldron_water = 1, }, node_box = mcl_cauldrons.cauldron_nodeboxes[2], }), "mcl_cauldrons:cauldron") @@ -175,19 +184,12 @@ mcl_cauldrons.register_cauldron_node("mcl_cauldrons:cauldron_water_3", merge_tables(mcl_cauldrons.registered_cauldrons["mcl_cauldrons:cauldron_water_1"], { description = S("Cauldron (3/3 Water)"), groups = { - pickaxey = 1, - cauldron = 1, cauldron_filled = 3, - cauldron_maximum = 3, - cauldron_water = 1, }, node_box = mcl_cauldrons.cauldron_nodeboxes[3], }), "mcl_cauldrons:cauldron") if minetest.get_modpath("mclx_core") then - --register_filled_cauldron(1, S("Cauldron (1/3 River Water)"), true) - --register_filled_cauldron(2, S("Cauldron (2/3 River Water)"), true) - --register_filled_cauldron(3, S("Cauldron (3/3 River Water)"), true) -- river water cauldron as extension of empty cauldron. mcl_cauldrons.register_cauldron_node("mcl_cauldrons:cauldron_river_water_1", merge_tables(mcl_cauldrons.registered_cauldrons["mcl_cauldrons:cauldron"], { @@ -213,11 +215,7 @@ if minetest.get_modpath("mclx_core") then merge_tables(mcl_cauldrons.registered_cauldrons["mcl_cauldrons:cauldron_river_water_1"], { description = S("Cauldron (2/3 River Water)"), groups = { - pickaxey = 1, - cauldron = 1, cauldron_filled = 2, - cauldron_maximum = 3, - cauldron_river_water = 1, }, node_box = mcl_cauldrons.cauldron_nodeboxes[2], }), "mcl_cauldrons:cauldron") @@ -226,11 +224,7 @@ if minetest.get_modpath("mclx_core") then merge_tables(mcl_cauldrons.registered_cauldrons["mcl_cauldrons:cauldron_river_water_1"], { description = S("Cauldron (3/3 River Water)"), groups = { - pickaxey = 1, - cauldron = 1, cauldron_filled = 3, - cauldron_maximum = 3, - cauldron_river_water = 1, }, node_box = mcl_cauldrons.cauldron_nodeboxes[3], }), "mcl_cauldrons:cauldron") diff --git a/mods/ITEMS/mcl_potions/init.lua b/mods/ITEMS/mcl_potions/init.lua index 8d8d5f822..80d5f4ddc 100644 --- a/mods/ITEMS/mcl_potions/init.lua +++ b/mods/ITEMS/mcl_potions/init.lua @@ -115,7 +115,7 @@ local function take_from_cauldron(pos, node, itemstack, placer) for cauldron_substance, bottle_name in pairs(CAULDRON_TO_BOTTLE) do -- check cauldron limit. if mcl_cauldrons.get_level(node, cauldron_substance) > 0 then - local newnode = mcl_cauldrons.drain_levels(node, mcl_cauldrons.BOTTLEFUL, cauldron_substance) + local newnode = mcl_cauldrons.drain_levels(node, mcl_cauldrons.BOTTLE_FILL_LEVELS, cauldron_substance) if newnode ~= node then -- change happening (success). minetest.set_node(pos, newnode) @@ -145,7 +145,7 @@ local function give_to_cauldron(pos, node, itemstack, placer, substance) local fit = maximum - level if fit > 0 then -- sufficiently low level, add; old contents are lost. - local newnode = mcl_cauldrons.fill_levels(node, mcl_cauldrons.BOTTLEFUL, substance) + local newnode = mcl_cauldrons.fill_levels(node, mcl_cauldrons.BOTTLE_FILL_LEVELS, substance) if node ~= newnode then -- change happening (success). minetest.set_node(pos, newnode)