From 2824562dc94da588fd2bc21415bbc193972d93a0 Mon Sep 17 00:00:00 2001 From: Novatux Date: Wed, 13 May 2015 11:49:11 +0200 Subject: [PATCH] Add screwdriver callbacks, and code them for doors and beds --- game_api.txt | 15 +++++++++ mods/beds/api.lua | 39 +++++++++++++++++++--- mods/doors/init.lua | 45 ++++++++++++++++++++++++++ mods/screwdriver/init.lua | 68 +++++++++++++++++++++++++++------------ 4 files changed, 142 insertions(+), 25 deletions(-) diff --git a/game_api.txt b/game_api.txt index fa9d6fc5..a3edcfe8 100644 --- a/game_api.txt +++ b/game_api.txt @@ -144,6 +144,21 @@ farming.register_plant(name, Plant definition) maxlight = default.LIGHT_MAX -- Maximum light to grow } +Screwdriver API +--------------- +The screwdriver API allows you to control a node's behaviour when a screwdriver is used on it. +To use it, add the on_screwdriver function to the node definition. +on_rotate(pos, node, user, mode, new_param2) +^ pos: position of the node that the screwdriver is being used on +^ node: that node +^ user: the player who used the screwdriver +^ mode: screwdriver.ROTATE_FACE or screwdriver.ROTATE_AXIS +^ new_param2: the new value of param2 that would have been set if on_rotate wasn't there +^ return value: false to disallow rotation, nil to keep default behaviour, true to allow + it but to indicate that changed have already been made (so the screwdriver will wear out) +^ use on_rotate = screwdriver.disallow to always disallow rotation +^ use on_rotate = screwdriver.rotate_simple to allow only face rotation + Stairs API ---------- The stairs API lets you register stairs and slabs and ensures that they are registered the same way as those diff --git a/mods/beds/api.lua b/mods/beds/api.lua index 320fcfb3..8f924730 100644 --- a/mods/beds/api.lua +++ b/mods/beds/api.lua @@ -26,10 +26,10 @@ function beds.register_bed(name, def) return true end local dir = minetest.facedir_to_dir(n.param2) - local p = {x=pos.x+dir.x,y=pos.y,z=pos.z+dir.z} + local p = vector.add(pos, dir) local n2 = minetest.get_node_or_nil(p) - local def = minetest.registered_items[n2.name] or nil - if not n2 or not def or not def.buildable_to then + local def = n2 and minetest.registered_items[n2.name] + if not def or not def.buildable_to then minetest.remove_node(pos) return true end @@ -40,7 +40,7 @@ function beds.register_bed(name, def) local n = minetest.get_node_or_nil(pos) if not n then return end local dir = minetest.facedir_to_dir(n.param2) - local p = {x=pos.x+dir.x,y=pos.y,z=pos.z+dir.z} + local p = vector.add(pos, dir) local n2 = minetest.get_node(p) if minetest.get_item_group(n2.name, "bed") == 2 and n.param2 == n2.param2 then minetest.remove_node(p) @@ -49,6 +49,37 @@ function beds.register_bed(name, def) on_rightclick = function(pos, node, clicker) beds.on_rightclick(pos, clicker) end, + on_rotate = function(pos, node, user, mode, new_param2) + local dir = minetest.facedir_to_dir(node.param2) + local p = vector.add(pos, dir) + local node2 = minetest.get_node_or_nil(p) + if not node2 or not minetest.get_item_group(node2.name, "bed") == 2 or + not node.param2 == node2.param2 then + return false + end + if minetest.is_protected(p, user:get_player_name()) then + minetest.record_protection_violation(p, user:get_player_name()) + return false + end + if mode ~= screwdriver.ROTATE_FACE then + return false + end + local newp = vector.add(pos, minetest.facedir_to_dir(new_param2)) + local node3 = minetest.get_node_or_nil(newp) + local def = node3 and minetest.registered_nodes[node3.name] + if not def or not def.buildable_to then + return false + end + if minetest.is_protected(newp, user:get_player_name()) then + minetest.record_protection_violation(newp, user:get_player_name()) + return false + end + node.param2 = new_param2 + minetest.swap_node(pos, node) + minetest.remove_node(p) + minetest.set_node(newp, {name = node.name:gsub("%_bottom", "_top"), param2 = new_param2}) + return true + end, }) minetest.register_node(name .. "_top", { diff --git a/mods/doors/init.lua b/mods/doors/init.lua index f3dd1695..b762751a 100644 --- a/mods/doors/init.lua +++ b/mods/doors/init.lua @@ -163,6 +163,33 @@ function doors.register_door(name, def) return meta:get_string("doors_owner") == pn end + local function on_rotate(pos, node, dir, user, check_name, mode, new_param2) + if not check_player_priv(pos, user) then + return false + end + if mode ~= screwdriver.ROTATE_FACE then + return false + end + + pos.y = pos.y + dir + if not minetest.get_node(pos).name == check_name then + return false + end + if minetest.is_protected(pos, user:get_player_name()) then + minetest.record_protection_violation(pos, user:get_player_name()) + return false + end + + local node2 = minetest.get_node(pos) + node2.param2 = (node2.param2 + 1) % 4 + minetest.swap_node(pos, node2) + + pos.y = pos.y - dir + node.param2 = (node.param2 + 1) % 4 + minetest.swap_node(pos, node) + return true + end + minetest.register_node(name.."_b_1", { tiles = {tb[2], tb[2], tb[2], tb[2], tb[1], tb[1].."^[transformfx"}, paramtype = "light", @@ -190,6 +217,10 @@ function doors.register_door(name, def) end end, + on_rotate = function(pos, node, user, mode, new_param2) + return on_rotate(pos, node, 1, user, name.."_t_1", mode) + end, + can_dig = check_player_priv, sounds = def.sounds, sunlight_propagates = def.sunlight, @@ -223,6 +254,10 @@ function doors.register_door(name, def) end end, + on_rotate = function(pos, node, user, mode, new_param2) + return on_rotate(pos, node, -1, user, name.."_b_1", mode) + end, + can_dig = check_player_priv, sounds = def.sounds, sunlight_propagates = def.sunlight, @@ -256,6 +291,10 @@ function doors.register_door(name, def) end end, + on_rotate = function(pos, node, user, mode, new_param2) + return on_rotate(pos, node, 1, user, name.."_t_2", mode) + end, + can_dig = check_player_priv, sounds = def.sounds, sunlight_propagates = def.sunlight, @@ -289,6 +328,10 @@ function doors.register_door(name, def) end end, + on_rotate = function(pos, node, user, mode, new_param2) + return on_rotate(pos, node, -1, user, name.."_b_2", mode) + end, + can_dig = check_player_priv, sounds = def.sounds, sunlight_propagates = def.sunlight, @@ -392,6 +435,8 @@ function doors.register_trapdoor(name, def) minetest.set_node(pos, {name = newname, param1 = node.param1, param2 = node.param2}) end + def.on_rotate = screwdriver.rotate_simple + -- Common trapdoor configuration def.drawtype = "nodebox" def.paramtype = "light" diff --git a/mods/screwdriver/init.lua b/mods/screwdriver/init.lua index 65e7f004..bccc9fbc 100644 --- a/mods/screwdriver/init.lua +++ b/mods/screwdriver/init.lua @@ -1,3 +1,5 @@ +screwdriver = {} + local function nextrange(x, max) x = x + 1 if x > max then @@ -6,8 +8,16 @@ local function nextrange(x, max) return x end -local ROTATE_FACE = 1 -local ROTATE_AXIS = 2 +screwdriver.ROTATE_FACE = 1 +screwdriver.ROTATE_AXIS = 2 +screwdriver.disallow = function(pos, node, user, mode, new_param2) + return false +end +screwdriver.rotate_simple = function(pos, node, user, mode, new_param2) + if mode ~= screwdriver.ROTATE_FACE then + return false + end +end local USES = 200 -- Handles rotation @@ -25,31 +35,47 @@ local function screwdriver_handler(itemstack, user, pointed_thing, mode) local node = minetest.get_node(pos) local ndef = minetest.registered_nodes[node.name] - if not ndef or not ndef.paramtype2 == "facedir" or - (ndef.drawtype == "nodebox" and - not ndef.node_box.type == "fixed") or - node.param2 == nil then - return - end - - if ndef.can_dig and not ndef.can_dig(pos, user) then - return - end - - -- Set param2 + -- Compute param2 local rotationPart = node.param2 % 32 -- get first 4 bits local preservePart = node.param2 - rotationPart - local axisdir = math.floor(rotationPart / 4) local rotation = rotationPart - axisdir * 4 - if mode == ROTATE_FACE then + if mode == screwdriver.ROTATE_FACE then rotationPart = axisdir * 4 + nextrange(rotation, 3) - elseif mode == ROTATE_AXIS then + elseif mode == screwdriver.ROTATE_AXIS then rotationPart = nextrange(axisdir, 5) * 4 end - node.param2 = preservePart + rotationPart - minetest.swap_node(pos, node) + local new_param2 = preservePart + rotationPart + local should_rotate = true + + if ndef and ndef.on_rotate then -- Node provides a handler, so let the handler decide instead if the node can be rotated + -- Copy pos and node because callback can modify it + local result = ndef.on_rotate(vector.new(pos), + {name = node.name, param1 = node.param1, param2 = node.param2}, + user, mode) + if result == false then -- Disallow rotation + return + elseif result == true then + should_rotate = false + end + else + if not ndef or not ndef.paramtype2 == "facedir" or + (ndef.drawtype == "nodebox" and + not ndef.node_box.type == "fixed") or + node.param2 == nil then + return + end + + if ndef.can_dig and not ndef.can_dig(pos, user) then + return + end + end + + if should_rotate then + node.param2 = new_param2 + minetest.swap_node(pos, node) + end if not minetest.setting_getbool("creative_mode") then itemstack:add_wear(65535 / (USES - 1)) @@ -63,11 +89,11 @@ minetest.register_tool("screwdriver:screwdriver", { description = "Screwdriver (left-click rotates face, right-click rotates axis)", inventory_image = "screwdriver.png", on_use = function(itemstack, user, pointed_thing) - screwdriver_handler(itemstack, user, pointed_thing, ROTATE_FACE) + screwdriver_handler(itemstack, user, pointed_thing, screwdriver.ROTATE_FACE) return itemstack end, on_place = function(itemstack, user, pointed_thing) - screwdriver_handler(itemstack, user, pointed_thing, ROTATE_AXIS) + screwdriver_handler(itemstack, user, pointed_thing, screwdriver.ROTATE_AXIS) return itemstack end, })