minetest/mods/screwdriver/init.lua
2014-04-24 20:34:01 +02:00

173 lines
5 KiB
Lua

local mode_text = {
{"Change rotation, Don't change axisdir."},
{"Keep choosen face in front then rotate it."},
{"Change axis dir, Reset rotation."},
{"Bring top in front then rotate it."},
}
-- Use Lua-friendly tables to avoid hash-lookups:
local opposite_faces = {
-- 0 1 2 3 4 5
5, 2, 1, 4, 3, 0
}
-- Rotational order for a given rotation axis as primary index:
-- Negative values indicate X rotation adjustments (rotate to opposite side),
-- 00 is just a visual indicator for invalid/unused axisdir indices.
-- Rotation order is always clockwise.
-- Layout: Row is selected by the face pointed at (the rotation axis),
-- current axisdir selects column, value is next axisdir:
local axis_rotations = {
-- 0 1 2 3 4 5
{00, 3, 4, 2, 1, 00}, -- Y+
{ 4, 00, 00, 0, 5, 3}, -- Z+
{ 3, 00, 00, 5, 0, 4}, -- Z-
{ 1, -5, 0, 00, 00, -2}, -- X+
{ 2, 0, -5, 00, 00, -1}, -- X-
{00, 4, 3, 1, 2, 00}, -- Y-
}
local function screwdriver_setmode(user,itemstack)
local player_name = user:get_player_name()
local item = itemstack:to_table()
local mode = tonumber(itemstack:get_metadata())
if not mode then
minetest.chat_send_player(player_name, "Hold shift and use to change screwdriwer modes.")
mode = 0
end
mode = mode + 1
if mode == 5 then
mode = 1
end
minetest.chat_send_player(player_name, "Screwdriver mode : "..mode.." - "..mode_text[mode][1] )
itemstack:set_name("screwdriver:screwdriver"..mode)
itemstack:set_metadata(mode)
return itemstack
end
local function get_node_face(pointed_thing)
local ax, ay, az = pointed_thing.above.x, pointed_thing.above.y, pointed_thing.above.z
local ux, uy, uz = pointed_thing.under.x, pointed_thing.under.y, pointed_thing.under.z
if ay > uy then return 0 -- Top
elseif az > uz then return 1 -- Z+ side
elseif az < uz then return 2 -- Z- side
elseif ax > ux then return 3 -- X+ side
elseif ax < ux then return 4 -- X- side
elseif ay < uy then return 5 -- Bottom
else
error("pointed_thing.above and under are the same!")
end
end
local function screwdriver_handler(itemstack, user, pointed_thing)
if pointed_thing.type ~= "node" then
return
end
local pos = pointed_thing.under
local keys = user:get_player_control()
local player_name = user:get_player_name()
local mode = tonumber(itemstack:get_metadata())
if not mode or keys["sneak"] == true then
return screwdriver_setmode(user, itemstack)
end
if minetest.is_protected(pos, user:get_player_name()) then
minetest.record_protection_violation(pos, user:get_player_name())
return
end
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
-- Split current param2 facedir value into axisdir and rotation:
local rotation = node.param2 % 4
local axisdir = math.floor(node.param2 / 4) % 6
if mode == 1 then
rotation = rotation + 1
elseif mode == 2 then
-- rotates the pointed face clockwise:
local face = get_node_face(pointed_thing)
-- when rotating the top/bottom faces, only change rotation:
if axisdir == face then
rotation = rotation + 1
elseif axisdir == opposite_faces[face+1] then
rotation = rotation - 1
else
-- rotate side faces: get next axisdir from table:
axisdir = axis_rotations[face+1][axisdir+1]
-- handle rotation adjustment (to keep face in front):
if face == 0 then -- Y+ (top) axis rotation fix
rotation = rotation + 1
elseif face == 5 then -- Y- (bottom)
rotation = rotation - 1
elseif axisdir < 0 then -- X axis rotation fix
axisdir = -axisdir
rotation = rotation + 2
end
end
elseif mode == 3 then
axisdir = axisdir + 1
rotation = 0
elseif mode == 4 then
local face = get_node_face(pointed_thing)
if axisdir == face then
rotation = rotation + 1
else
axisdir = face
rotation = 0
end
end
-- recombine axisdir and rotation to facedir value:
node.param2 = (axisdir%6) * 4 + (rotation%4)
minetest.swap_node(pos, node)
if not minetest.setting_getbool("creative_mode") then
local item_wear = tonumber(itemstack:get_wear())
item_wear = item_wear + 327
if item_wear > 65535 then
itemstack:clear()
return itemstack
end
itemstack:set_wear(item_wear)
end
return itemstack
end
minetest.register_craft({
output = "screwdriver:screwdriver",
recipe = {
{"default:steel_ingot"},
{"group:stick"}
}
})
minetest.register_tool("screwdriver:screwdriver", {
description = "Screwdriver",
inventory_image = "screwdriver.png",
on_use = function(itemstack, user, pointed_thing)
screwdriver_handler(itemstack, user, pointed_thing)
return itemstack
end,
})
for i = 1, 4 do
minetest.register_tool("screwdriver:screwdriver"..i, {
description = "Screwdriver in Mode "..i,
inventory_image = "screwdriver.png^tool_mode"..i..".png",
wield_image = "screwdriver.png",
groups = {not_in_creative_inventory=1},
on_use = function(itemstack, user, pointed_thing)
screwdriver_handler(itemstack, user, pointed_thing)
return itemstack
end,
})
end