diff --git a/mods/bg_crafting/api.lua b/mods/bg_crafting/api.lua index f7aa5de..d28d67f 100644 --- a/mods/bg_crafting/api.lua +++ b/mods/bg_crafting/api.lua @@ -1,153 +1,9 @@ blockgame.crafting = blockgame.crafting or {} local api = blockgame.crafting -local recipes = {} -api.registered_recipes = recipes - -local stack_recipes = {} - -function api.register_stack_recipe (top_node, bottom_node, result, consumes_top) - local consumes_top = consumes_top - if consumes_top == nil then consumes_top = true end - - stack_recipes[top_node] = stack_recipes[top_node] or {} - - local def = { - ["type"] = "stack_two_nodes", - index_key = top_node, - top_node = top_node, - bottom_node = bottom_node, - result = result, - consumes_top = consumes_top, - } - - table.insert(stack_recipes[top_node], def) - table.insert(api.registered_recipes, def) -end - -function api.handle_placement (pos, new_node, placer, old_node, itemstack, pointed_thing) - if stack_recipes[new_node.name] == nil then return false end - - for _, recipe in pairs(stack_recipes[new_node.name]) do - local result = api.handle_stack_recipe(recipe, pos, new_node) - if result then return not recipe.consumes_top end - end - - return false -end - -blockgame.register_on_placenode(function (...) - return blockgame.crafting.handle_placement(...) -end) - -function api.handle_stack_recipe (recipe, pos, top_node) - if top_node.name ~= recipe.top_node then return false end - - local down = vector.add(pos, vector.new(0, -1, 0)) - local below = minetest.get_node(down) - if below.name ~= recipe.bottom_node then return false end - - minetest.remove_node(pos) - minetest.set_node(down, recipe.result) - - return true -end - --- pummeling is heavily based on nodecore by Warr1024 (both the mechanic itself and the code here implementing it). - -local pummel_recipes = {} - -function api.register_pummel_recipe (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_item 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_item - def.index_key = key - - def["type"] = "pummel" - - pummel_recipes[key] = pummel_recipes[key] or {} - - table.insert(pummel_recipes[key], def) - table.insert(api.registered_recipes, def) -end - --- TODO: add support for pummel recipes using groups instead of just specific node names. -function api.pummel_check (pos, used_item, target_node) - local key = used_item - 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_item, target_node) then - return false - end - def.on_success(pos, used_item, target_node) - return true - end - end -end +api.registered_recipes = {} -local pummeling = {} --- NOTE: might wanna change this to somehow store pummels per-node instead of per-player? -blockgame.register_on_dignode(function (_, _, digger) - if not (digger and digger:is_player()) then return end - pummeling[digger:get_player_name()] = nil -end) - -blockgame.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, wield:get_name(), minetest.get_node(pointed.under)) then - pummeling[player_name] = nil - end -end) +load_file("stack") +load_file("pummel") diff --git a/mods/bg_crafting/pummel.lua b/mods/bg_crafting/pummel.lua new file mode 100644 index 0000000..a12b39e --- /dev/null +++ b/mods/bg_crafting/pummel.lua @@ -0,0 +1,100 @@ +local api = blockgame.crafting + +-- pummeling is heavily based on nodecore by Warr1024 (both the mechanic itself and the code here implementing it). + +local pummel_recipes = {} + +function api.register_pummel_recipe (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_item 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_item + def.index_key = key + + def["type"] = "pummel" + + pummel_recipes[key] = pummel_recipes[key] or {} + + table.insert(pummel_recipes[key], def) + table.insert(api.registered_recipes, def) +end + +-- TODO: add support for pummel recipes using groups instead of just specific node names. +function api.pummel_check (pos, used_item, target_node) + local key = used_item + 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_item, target_node) then + return false + end + def.on_success(pos, used_item, target_node) + return true + end + end +end + + +local pummeling = {} + +-- NOTE: might wanna change this to somehow store pummels per-node instead of per-player? +blockgame.register_on_dignode(function (_, _, digger) + if not (digger and digger:is_player()) then return end + pummeling[digger:get_player_name()] = nil +end) + +blockgame.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, wield:get_name(), minetest.get_node(pointed.under)) then + pummeling[player_name] = nil + end +end) diff --git a/mods/bg_crafting/stack.lua b/mods/bg_crafting/stack.lua new file mode 100644 index 0000000..805219a --- /dev/null +++ b/mods/bg_crafting/stack.lua @@ -0,0 +1,50 @@ +local api = blockgame.crafting + +local stack_recipes = {} + +function api.register_stack_recipe (top_node, bottom_node, result, consumes_top) + local consumes_top = consumes_top + if consumes_top == nil then consumes_top = true end + + stack_recipes[top_node] = stack_recipes[top_node] or {} + + local def = { + ["type"] = "stack_two_nodes", + index_key = top_node, + top_node = top_node, + bottom_node = bottom_node, + result = result, + consumes_top = consumes_top, + } + + table.insert(stack_recipes[top_node], def) + table.insert(api.registered_recipes, def) +end + +function api.handle_stack_recipe (recipe, pos, top_node) + if top_node.name ~= recipe.top_node then return false end + + local down = vector.add(pos, vector.new(0, -1, 0)) + local below = minetest.get_node(down) + if below.name ~= recipe.bottom_node then return false end + + minetest.remove_node(pos) + minetest.set_node(down, recipe.result) + + return true +end + +function api.handle_placement (pos, new_node, placer, old_node, itemstack, pointed_thing) + if stack_recipes[new_node.name] == nil then return false end + + for _, recipe in pairs(stack_recipes[new_node.name]) do + local result = api.handle_stack_recipe(recipe, pos, new_node) + if result then return not recipe.consumes_top end + end + + return false +end + +blockgame.register_on_placenode(function (...) + return blockgame.crafting.handle_placement(...) +end)