Add screwdriver callbacks, and code them for doors and beds

This commit is contained in:
Novatux 2015-05-13 11:49:11 +02:00
parent 852b337916
commit 2824562dc9
4 changed files with 142 additions and 25 deletions

View File

@ -144,6 +144,21 @@ farming.register_plant(name, Plant definition)
maxlight = default.LIGHT_MAX -- Maximum light to grow 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 Stairs API
---------- ----------
The stairs API lets you register stairs and slabs and ensures that they are registered the same way as those The stairs API lets you register stairs and slabs and ensures that they are registered the same way as those

View File

@ -26,10 +26,10 @@ function beds.register_bed(name, def)
return true return true
end end
local dir = minetest.facedir_to_dir(n.param2) 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 n2 = minetest.get_node_or_nil(p)
local def = minetest.registered_items[n2.name] or nil local def = n2 and minetest.registered_items[n2.name]
if not n2 or not def or not def.buildable_to then if not def or not def.buildable_to then
minetest.remove_node(pos) minetest.remove_node(pos)
return true return true
end end
@ -40,7 +40,7 @@ function beds.register_bed(name, def)
local n = minetest.get_node_or_nil(pos) local n = minetest.get_node_or_nil(pos)
if not n then return end if not n then return end
local dir = minetest.facedir_to_dir(n.param2) 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) local n2 = minetest.get_node(p)
if minetest.get_item_group(n2.name, "bed") == 2 and n.param2 == n2.param2 then if minetest.get_item_group(n2.name, "bed") == 2 and n.param2 == n2.param2 then
minetest.remove_node(p) minetest.remove_node(p)
@ -49,6 +49,37 @@ function beds.register_bed(name, def)
on_rightclick = function(pos, node, clicker) on_rightclick = function(pos, node, clicker)
beds.on_rightclick(pos, clicker) beds.on_rightclick(pos, clicker)
end, 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", { minetest.register_node(name .. "_top", {

View File

@ -163,6 +163,33 @@ function doors.register_door(name, def)
return meta:get_string("doors_owner") == pn return meta:get_string("doors_owner") == pn
end 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", { minetest.register_node(name.."_b_1", {
tiles = {tb[2], tb[2], tb[2], tb[2], tb[1], tb[1].."^[transformfx"}, tiles = {tb[2], tb[2], tb[2], tb[2], tb[1], tb[1].."^[transformfx"},
paramtype = "light", paramtype = "light",
@ -190,6 +217,10 @@ function doors.register_door(name, def)
end end
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, can_dig = check_player_priv,
sounds = def.sounds, sounds = def.sounds,
sunlight_propagates = def.sunlight, sunlight_propagates = def.sunlight,
@ -223,6 +254,10 @@ function doors.register_door(name, def)
end end
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, can_dig = check_player_priv,
sounds = def.sounds, sounds = def.sounds,
sunlight_propagates = def.sunlight, sunlight_propagates = def.sunlight,
@ -256,6 +291,10 @@ function doors.register_door(name, def)
end end
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, can_dig = check_player_priv,
sounds = def.sounds, sounds = def.sounds,
sunlight_propagates = def.sunlight, sunlight_propagates = def.sunlight,
@ -289,6 +328,10 @@ function doors.register_door(name, def)
end end
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, can_dig = check_player_priv,
sounds = def.sounds, sounds = def.sounds,
sunlight_propagates = def.sunlight, 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}) minetest.set_node(pos, {name = newname, param1 = node.param1, param2 = node.param2})
end end
def.on_rotate = screwdriver.rotate_simple
-- Common trapdoor configuration -- Common trapdoor configuration
def.drawtype = "nodebox" def.drawtype = "nodebox"
def.paramtype = "light" def.paramtype = "light"

View File

@ -1,3 +1,5 @@
screwdriver = {}
local function nextrange(x, max) local function nextrange(x, max)
x = x + 1 x = x + 1
if x > max then if x > max then
@ -6,8 +8,16 @@ local function nextrange(x, max)
return x return x
end end
local ROTATE_FACE = 1 screwdriver.ROTATE_FACE = 1
local ROTATE_AXIS = 2 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 local USES = 200
-- Handles rotation -- Handles rotation
@ -25,6 +35,31 @@ local function screwdriver_handler(itemstack, user, pointed_thing, mode)
local node = minetest.get_node(pos) local node = minetest.get_node(pos)
local ndef = minetest.registered_nodes[node.name] local ndef = minetest.registered_nodes[node.name]
-- 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 == screwdriver.ROTATE_FACE then
rotationPart = axisdir * 4 + nextrange(rotation, 3)
elseif mode == screwdriver.ROTATE_AXIS then
rotationPart = nextrange(axisdir, 5) * 4
end
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 if not ndef or not ndef.paramtype2 == "facedir" or
(ndef.drawtype == "nodebox" and (ndef.drawtype == "nodebox" and
not ndef.node_box.type == "fixed") or not ndef.node_box.type == "fixed") or
@ -35,21 +70,12 @@ local function screwdriver_handler(itemstack, user, pointed_thing, mode)
if ndef.can_dig and not ndef.can_dig(pos, user) then if ndef.can_dig and not ndef.can_dig(pos, user) then
return return
end end
-- Set 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
rotationPart = axisdir * 4 + nextrange(rotation, 3)
elseif mode == ROTATE_AXIS then
rotationPart = nextrange(axisdir, 5) * 4
end end
node.param2 = preservePart + rotationPart if should_rotate then
node.param2 = new_param2
minetest.swap_node(pos, node) minetest.swap_node(pos, node)
end
if not minetest.setting_getbool("creative_mode") then if not minetest.setting_getbool("creative_mode") then
itemstack:add_wear(65535 / (USES - 1)) 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)", description = "Screwdriver (left-click rotates face, right-click rotates axis)",
inventory_image = "screwdriver.png", inventory_image = "screwdriver.png",
on_use = function(itemstack, user, pointed_thing) 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 return itemstack
end, end,
on_place = function(itemstack, user, pointed_thing) 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 return itemstack
end, end,
}) })