nudger/init.lua

416 lines
9.6 KiB
Lua

-- ======== FYI ========
minetest.register_craft({
output = "nudger:nudger",
recipe = {
{"default:copper_ingot"},
{"group:stick"}
}
})
nudger = {}
local transforms = {}
nudger.register_transforms = function(prefix, suffixes, cost, callback)
--[[
prefix = string. First common part of node names. Longer is better. Can be ''.
suffixes = table of strings. Remainders of node names with prefix removed. Can include ''.
cost = integer. How many rotations worth of tool wear should one transform cost for this group.
callback = function, called with (pos). In case other adjustments are needed after transforming. Can be nil.
--]]
local l, n = string.len(prefix), 0
for i,j in ipairs(transforms) do
if string.len(j[1]) <= l then break end
n=i
end
table.insert(transforms,n+1,{prefix, suffixes, cost, callback})
end
-- ======== Chat ========
local menu0 = {
"Nudge clockwise.",
"Nudge leftwards.",
"Nudge downwards.",
"Nudge anticlockwise.",
"Nudge rightwards.",
"Nudge upwards.",
}
local menu1 = {
"Reverse directions.",
"Store orientation.",
"Equip orientation.",
"Transform.",
"Toggle chat level.",
"Get sixel node for 20% tool wear.",
"",
-- submenu
"Nudge to orientation.",
"Store ...",
}
-- ======== Helpers ========
local function say(msg, plr, sh)
if sh ~= 1 then minetest.chat_send_player(plr and plr:get_player_name() or "singleplayer", msg) end
end
local function edit_ok(pos, plr)
if minetest.is_protected(pos, plr:get_player_name()) then
minetest.record_protection_violation(pos, plr:get_player_name())
return
end
return true
end
local function node_ok(pos, plr)
local node = minetest.get_node(pos)
local ndef = minetest.registered_nodes[node.name]
if not ndef or not (ndef.paramtype2 == "facedir") or node.param2 == nil
or (ndef.drawtype == "nodebox" and not (ndef.node_box.type == "fixed")) then
if plr then say("Target can't be nudged.", plr) end
return
end
return node
end
local function is_sixel(pos)
return minetest.get_node(pos).name:sub(1,12) == "nudger:sixel"
end
local function tool_use(istk, cost, pos)
if not pos or not is_sixel(pos) then
local wear = tonumber(istk:get_wear()) + 257*cost
if wear > 65534 then istk:clear()
else istk:set_wear(wear)
end
end
end
-- ======== Actions ========
-- Choose axis of rotation
local function face(ptd)
local a, u = ptd.above.x, ptd.under.x
if a > u then return 0,1
elseif u > a then return 0,-1
else
a, u = ptd.above.y, ptd.under.y
if a > u then return 1,1
elseif u > a then return 1,-1
else
a, u = ptd.above.z, ptd.under.z
if a > u then return 2,1
elseif u > a then return 2,-1
end
end
end
end
local function axsgn(d)
if d%2 == 0 then return 2, 1-d
else return 0, 2-d
end
end
local function choose_axis(plr, ptd, mode)
local axis, sign = face(ptd)
if mode == 0 then return axis, sign
elseif axis ~= 1 then
if mode == 1 then return 1, 1
else return 2-axis, (axis-1)*sign
end
else
local hdir = (5 - math.floor(plr:get_look_yaw()/1.571+.5))%4
if mode == 2 then return axsgn((hdir+3)%4)
elseif sign == 1 then return axsgn(hdir)
else return axsgn((hdir+2)%4)
end
end
end
-- == Rotate ==
local map = {
{ -- x
{0, 1, 3, -1, -2, 2},
{0, 4, 20, 8},
{0, 0, 2, 0}, 12, 20,
},
{ --y
{-1, 0, 2, 1, 3, -2},
{4, 12, 8, 16},
{0, 3, 2, 1}, 0, 24,
},
{ --z
{0, -1, -2, 3, 1, 2},
{0, 16, 20, 12},
{0, 0, 0, 0}, 4, 12,
},
}
local function rotate(istk, plr, ptd, mode, sgn)
local pos = ptd.under
local node = node_ok(pos, plr)
if not node then return end
local p = (node.param2)%24
local q, r = math.floor(p/4), p%4
local a, s = choose_axis(plr,ptd,mode)
local t = map[a+1]
local k = t[1][q+1]
s = s*sgn
if k == -1 then p = t[4] + (p + 4 + s)%4
elseif k == -2 then p = t[5] - (t[5] - p + 3 + s)%4 - 1
else
local o, i = t[3], (k + 4 + s)%4 + 1
p = t[2][i] + (r + o[k+1] + 4 - o[i])%4
end
node.param2 = p
minetest.swap_node(pos, node)
tool_use(istk, 1, pos)
return p
end
-- == Store / Apply Orientation ==
local function store(istk, pos)
local node = node_ok(pos)
if not node then return 0 end
tool_use(istk, 8, pos)
return node.param2
end
local function apply(istk, pos, plr, p2)
local node = node_ok(pos, plr)
if not node then return end
node.param2 = p2
minetest.swap_node(pos, node)
tool_use(istk, 1, pos)
return p2
end
-- == Transform ==
local function transform(istk,pos,plr)
local node = minetest.get_node(pos)
local name = node.name
for i,j in ipairs(transforms) do
if string.match(name,'^'..j[1]) then
s = string.sub(name, string.len(j[1])+1)
jj = j[2]
for k,t in ipairs(jj) do
if t == s then
node.name=j[1]..jj[k%#jj+1]
minetest.swap_node(pos,node)
if j[4] then j[4](pos) end
tool_use(istk,j[3])
return
end
end
end
end
say("Target can't transform.",plr)
end
-- ======== Sixel ========
local function sixel(istk,plr)
if tonumber(istk:get_wear()) > 52428 then
say("Sorry, this nudger is too damaged.",plr)
else
tool_use(istk,51,nil)
local inv = plr:get_inventory()
local stk = inv:add_item("main",ItemStack("nudger:sixel"))
if not stk:is_empty() then
minetest.item_drop(stk,plr,plr:get_pos())
end
say("Sixel can be nudged without tool damage,",plr)
say(" and reports its param2 with 'More chat.'",plr)
end
end
-- ======== Interface ========
local function do_on_use(istk, plr, ptd, rt)
local m = tonumber(istk:get_metadata())
if m then
-- unpack metadata
local p2 = math.floor(m/120)
local sh = math.floor((m%120)/60)
local mm = math.floor((m%60)/6)
local rm = m%6
local sr, dr = math.floor(rm/3), rm%3
-- Switch menus
if rt then
mm = (mm == 0 and 1) or 0
if mm == 1 then
say(menu1[1], plr, sh)
istk:set_name("nudger:nudger")
else
istk:set_name("nudger:nudger"..rm)
end
-- Cycle menu options
elseif plr:get_player_control().sneak then
if mm == 0 then
rm = 3*sr + (dr + 1)%3
elseif mm < 7 then
mm = mm%6 + 1
elseif mm < 10 then
mm = 17 - mm
end
-- show correct tool
if mm == 0 then
say(menu0[rm + 1], plr, sh)
istk:set_name("nudger:nudger"..rm)
else
say(menu1[mm], plr)
if mm == 3 or mm == 5 then istk:set_name("nudger:nudger")
elseif mm == 2 or mm == 9 then istk:set_name("nudger:nudger6")
elseif mm == 4 then istk:set_name("nudger:nudger8")
elseif mm == 8 then istk:set_name("nudger:nudger7")
end
end
-- Apply menu actions
else
local once = true
if mm == 1 then
rm = 3*(1 - sr) + dr
say("Reversed.", plr, sh)
elseif mm == 5 then
sh = 1 - sh
say(((sh==0 and "More") or "Less").." chat.", plr)
elseif mm == 6 then
sixel(istk,plr)
else
local pos = ptd.type == "node" and ptd.under
if pos then
if mm == 2 or mm == 3 or mm == 9 then
if mm ~= 3 then
p2 = store(istk, pos)
say(p2.." Stored.", plr, sh)
end
if mm ~= 9 then say(" * storage submenu *", plr, sh) end
mm = 8
istk:set_name("nudger:nudger7")
say(menu1[8], plr)
elseif edit_ok(pos, plr) then
local qp2
if mm == 0 then
qp2 = rotate(istk, plr, ptd, dr, 1-2*sr)
elseif mm == 4 then
transform(istk,pos,plr)
elseif mm == 8 then
qp2 = apply(istk, pos, plr, p2)
end
if qp2 and is_sixel(pos) then
say("sixel: "..qp2, plr, sh)
end
end
end
once = false
end
if once then
mm = 0
istk:set_name("nudger:nudger"..rm)
end
end
m = 120*p2 + 60*sh + 6*mm + rm
else m = 0
say("Shift click to cycle menu options.", plr)
say("Right click to switch menus.", plr)
istk:set_name("nudger:nudger0")
end
istk:set_metadata(m)
return istk
end
-- ======== Registration ========
-- * Tools *
minetest.register_tool("nudger:nudger", {
description = "Nudger",
inventory_image = "nudger.png",
on_use = function(istk, plr, ptd)
return do_on_use(istk, plr, ptd)
end,
on_place = function(istk, plr, ptd)
return do_on_use(istk, plr, ptd, 1)
end,
})
local adj={"+cw","lf","dn","-cw","rt","up","store","apply"}
for i = 0, 7 do
minetest.register_tool("nudger:nudger"..i, {
description = "Nudger ("..adj[i+1]..")",
inventory_image = "nudger.png^nudge"..i..".png",
wield_image = "nudger.png",
groups = {not_in_creative_inventory=1},
on_use = function(istk, plr, ptd)
return do_on_use(istk, plr, ptd)
end,
on_place = function(istk, plr, ptd)
return do_on_use(istk, plr, ptd, 1)
end,
})
end
minetest.register_tool("nudger:nudger8", {
description = "Gerund",
inventory_image = "nudger.png^[transform1",
on_use = function(istk, plr, ptd)
return do_on_use(istk, plr, ptd)
end,
on_place = function(istk, plr, ptd)
return do_on_use(istk, plr, ptd, 1)
end,
})
-- * Nodes *
minetest.register_node("nudger:sixel", {
description = "Sixel",
drop = "nudger:sixel",
tiles = {"sixel_tp.png","sixel_bt.png","sixel_rt.png","sixel_lf.png","sixel_ft.png","sixel_bk.png"},
paramtype = "light",
paramtype2 = "facedir",
is_ground_content = false,
sunlight_propagates = true,
groups = {dig_immediate=3},
})
minetest.register_node("nudger:sixel_t", {
description = "Sixel t",
drop = "nudger:sixel",
tiles = {"sixel_t2.png","sixel_t2.png","sixel_t1.png","sixel_t3.png","sixel_t1.png","sixel_t3.png",},
paramtype = "light",
paramtype2 = "facedir",
is_ground_content = false,
sunlight_propagates = true,
groups = {dig_immediate=3,not_in_creative_inventory=1},
drawtype = "nodebox",
node_box = {
type = "fixed",
fixed = {
{-0.5, -0.5, -0.5, 0.5, -0.3, -0.3},
{-0.3, -0.3, -0.5, -0.1, 0.5, -0.3},
{-0.5, -0.3, -0.5, -0.3, -0.1, 0.5},
},
},
})
-- * Transforms *
local function example(pos)
say('Sixel transformed at '..pos.x..','..pos.y..','..pos.z)
end
nudger.register_transforms('nudger:sixel', {'','_t'}, 0, example)