diff --git a/mods/bg_crafting/api.lua b/mods/bg_crafting/api.lua index cfffe20..f62ad45 100644 --- a/mods/bg_crafting/api.lua +++ b/mods/bg_crafting/api.lua @@ -43,3 +43,98 @@ api.handle_stack_recipe = function (recipe, pos, top_node) return true end + +-- pummeling is heavily based on nodecore by Warr1024 (both the mechanic itself and the code here implementing it). + +local pummel_recipes = {} + +api.register_pummel_recipe = function (def) + local def = def or {} + + def.label = def.label or "unnamed pummel recipe" + + -- TODO: throw errors when these defs are invalid instead of just returning. + if not def.used_node then return false end + if not def.target_node then return false end + if not type(def.on_success) == "function" then return false end + + local key = def.used_node + def.index_node = key + + pummel_recipes[key] = pummel_recipes[key] or {} + table.insert(pummel_recipes[key], def) +end + +-- TODO: add support for pummel recipes using groups instead of just specific node names. +api.pummel_check = function (pos, used_node, target_node) + local key = used_node.name + if not pummel_recipes[key] then return false end + + local potential_recipes = pummel_recipes[key] + for _, def in pairs(potential_recipes) do + if def.target_node == target_node.name then + if type(def.check) == "function" and not def.check(pos, used_node, target_node) then + return false + end + def.on_success(pos, used_node, target_node) + return true + end + end +end + + +local pummeling = {} + +-- NOTE: might wanna change this to somehow store pummels per-node instead of per-player? +minetest.register_on_dignode(function (_, _, digger) + if not (digger and digger:is_player()) then return end + pummeling[digger:get_player_name()] = nil +end) + +minetest.register_on_punchnode(function (pos, node, puncher, pointed) + if (not puncher:is_player()) or puncher:get_player_control().sneak then return end + local player_name = puncher:get_player_name() + -- if not minetest.interact(player_name) then return end + if not minetest.check_player_privs(player_name, "interact") then return end + + node = node or minetest.get_node(pos) + local node_def = minetest.registered_items[node.name] or {} + if not node_def.pointable then return end + + local wield = puncher:get_wielded_item() + local now = minetest.get_us_time() / 1000000 + + local pummel_data = { + action = "pummel", + crafter = puncher, + crafter_name = player_name, + pos = pos, + pointed = pointed, + node = node, + node_def = node_def, + start = now, + wield = wield:get_name() .. " " .. wield:get_count(), + count = 0, + } + + local old_data = pummeling[player_name] + local hash = minetest.hash_node_position + if old_data and hash(old_data.pos) == hash(pummel_data.pos) + and hash(old_data.pointed.above) == hash(pummel_data.pointed.above) + and hash(old_data.pointed.under) == hash(pummel_data.pointed.under) + and old_data.wield == pummel_data.wield + and old_data.last >= (now - 3) + then pummel_data = old_data + end + + pummel_data.count = pummel_data.count + 1 + pummel_data.last = now + pummel_data.duration = now - pummel_data.start - 1 + pummeling[player_name] = pummel_data + + if pummel_data.count < 2 then return end + + if api.pummel_check(pos, node, minetest.get_node(pointed.under)) then + pummeling[player_name] = nil + end +end)