549 lines
16 KiB
Lua

--
-- hand tools
--
minetest.register_item(":", {
type = "none",
wield_image = "wieldhand.png",
inventory_image = "wieldhand.png",
wield_scale = {x = 1, y = 1, z = 2},
range = 4,
tool_capabilities = {
full_punch_interval = 0.5,
max_drop_level = 0,
-- can't pick up any node by hand
groupcaps = {},
damage_groups = {},
},
groups = {not_in_creative_inventory = 1}
})
minetest.register_item("tools:edit", {
type = "none",
wield_image = "wieldhand_edit.png",
inventory_image = "wieldhand_edit.png",
wield_scale = {x = 1, y = 1, z = 2},
range = 4, -- to make sure we can reach as far as the player
tool_capabilities = {
full_punch_interval = 0.1,
max_drop_level = 0,
groupcaps = {
axe = {times={[1] = 0.2, [2] = 0.2, [3] = 0.2}, uses = 0, maxlevel = 1},
shovel = {times={[1] = 0.2, [2] = 0.2, [3] = 0.2}, uses = 0, maxlevel = 1},
pickaxe = {times={[1] = 0.2, [2] = 0.2, [3] = 0.2}, uses = 0, maxlevel = 1},
node = {times={[1] = 0.2, [2] = 0.2, [3] = 0.2}, uses = 0, maxlevel = 1},
unbreakable = {times={[1] = 0.2, [2] = 0.2, [3] = 0.2}, uses = 0, maxlevel = 1},
},
damage_groups = {},
},
groups = {not_in_creative_inventory = 1}
})
-- node tools
minetest.register_tool("tools:shovel", {
description = "Shovel",
inventory_image = "shovel.png",
tool_capabilities = {
groupcaps = {
shovel = {
times = {[1] = 1.5, [2] = 1.5, [3] = 1.5},
uses = 0,
},
},
},
})
frame.register("tools:shovel")
minetest.register_tool("tools:axe", {
description = "Axe",
inventory_image = "axe.png",
tool_capabilities = {
groupcaps = {
axe = {
times = {[1] = 1.5, [2] = 1.5, [3] = 1.5},
uses = 0,
},
},
},
})
frame.register("tools:axe")
minetest.register_tool("tools:pickaxe", {
description = "Pickaxe",
inventory_image = "pickaxe.png",
tool_capabilities = {
groupcaps = {
pickaxe = {
times = {[1] = 3, [2] = 3, [3] = 3},
uses = 0,
},
},
},
})
frame.register("tools:pickaxe")
minetest.register_tool("tools:sword", {
description = "Sword",
inventory_image = "sword.png",
})
frame.register("tools:sword")
minetest.register_tool("tools:flint_and_steel", {
description = "Flint and Steel",
inventory_image = "flint_and_steel.png",
})
frame.register("tools:flint_and_steel")
local function node_dig(pos, digger)
-- from builtin/item.lua core.node_dig():
local node = minetest.get_node(pos)
local def = minetest.registered_nodes[node.name]
local sounds = minetest.registered_nodes[node.name].sounds
if sounds and sounds.dig then
minetest.sound_play(sounds.dig, {pos = pos})
end
local oldmetadata = nil
if def and def.after_dig_node then
oldmetadata = core.get_meta(pos):to_table()
end
minetest.remove_node(pos, node)
if def and def.after_dig_node then
local pos_copy = {x=pos.x, y=pos.y, z=pos.z}
local node_copy = {name = node.name, param1 = node.param1, param2 = node.param2}
def.after_dig_node(pos_copy, node_copy, oldmetadata, digger)
end
for _, callback in ipairs(core.registered_on_dignodes) do
local origin = core.callback_origins[callback]
if origin then
core.set_last_run_mod(origin.mod)
end
-- Copy pos and node because callback can modify them
local pos_copy = {x=pos.x, y=pos.y, z=pos.z}
local node_copy = {name = node.name, param1 = node.param1, param2 = node.param2}
callback(pos_copy, node_copy, digger)
end
end
minetest.register_tool("tools:admin", {
description = "Admin tool",
inventory_image = "admin_tool.png",
liquids_pointable = true,
on_use = function(itemstack, digger, pointed_thing)
if not pointed_thing or not pointed_thing.under then
return
end
-- Prevent non-admins from using an admin tool if they ever get one
if not digger or not minetest.check_player_privs(digger, "server") then
return
end
node_dig(pointed_thing.under, digger)
return itemstack
end,
})
minetest.register_tool("tools:player", {
description = "Remove tool\nLeft click to remove a node",
inventory_image = "admin_tool.png",
on_use = function(itemstack, digger, pointed_thing)
if not pointed_thing or not pointed_thing.under then
return
end
if not digger then
return
end
local name = digger:get_player_name()
if not boxes.players_editing_boxes[name] then
return
end
local box = boxes.players_editing_boxes[name]
local pos = pointed_thing.under
if pos.x <= box.minp.x or pos.x >= box.maxp.x or
pos.y <= box.minp.y or pos.y >= box.maxp.y or
pos.z <= box.minp.z or pos.z >= box.maxp.z
then
return
end
node_dig(pointed_thing.under, digger)
return itemstack
end,
})
frame.register("tools:player")
minetest.register_tool("tools:bulk", {
description = "Bulk placement tool\nLeft-click air to toggle mode\nShift-left-click " ..
"to toggle mode\nLeft-click a node to pick it up\nRight-click to place nodes",
inventory_image = "node_place_tool.png",
on_use = function(itemstack, placer, pointed_thing)
if not pointed_thing or not pointed_thing.under or
placer:get_player_control().sneak then
-- toggle placement mode
local meta = itemstack:get_meta()
local mode = meta:get_int("mode") or 0
if mode == 0 then
minetest.chat_send_player(placer:get_player_name(),
"Buld tool will now place a \"sheet\"")
mode = 1 -- sheet
elseif mode == 1 then
minetest.chat_send_player(placer:get_player_name(),
"Buld tool will now place a \"large blob\"")
mode = 2 -- large blob
elseif mode == 2 then
minetest.chat_send_player(placer:get_player_name(),
"Buld tool will now place a \"large sheet\"")
mode = 3 -- large sheet
elseif mode == 3 then
minetest.chat_send_player(placer:get_player_name(),
"Buld tool will now place a \"blob\"")
mode = 0 -- blob (default)
end
meta:set_int("mode", mode)
return itemstack
end
local node = minetest.get_node(pointed_thing.under)
local def = minetest.registered_nodes[node.name]
if not def and not def.groups then
return itemstack
end
if def.groups.not_in_creative_inventory or
def.groups.trigger or def.groups.mech or
def.groups.door
then
return itemstack
end
itemstack:set_metadata(minetest.serialize(node))
minetest.chat_send_player(placer:get_player_name(),
"Bulk tool will place " .. node.name)
local meta = itemstack:get_meta()
meta:set_string("description", "Bulk placement tool\nNode: " .. node.name)
return itemstack
end,
on_place = function(itemstack, placer, pointed_thing)
if not pointed_thing or not pointed_thing.above or not placer then
return
end
local node = minetest.deserialize(itemstack:get_metadata())
if not node then
minetest.chat_send_player(placer:get_player_name(),
"Pick up a node first by left-clicking it with this tool")
return
end
local name = placer:get_player_name()
local box = boxes.players_editing_boxes[name]
if not box and not minetest.check_player_privs(name, "server") then
return
end
if not box then
box = {
minp = { x = -32768, y = -32768, z = -32768 },
maxp = { x = 32768, y = 32768, z = 32768 },
}
end
-- make sure we don't choke the player.
local head = vector.add(vector.round(placer:get_pos()), {x = 0, y = 1, z = 0})
local pos = pointed_thing.above
local meta = itemstack:get_meta()
local mode = meta:get_int("mode") or 0
-- toggle size
local size = { 3, 20, 28 }
if mode == 2 or mode == 3 then
size = {7, 50, 68 }
end
if mode == 0 or mode == 2 then
for x = pos.x - size[1], pos.x + size[1] do
for y = pos.y - size[1], pos.y + size[1] do
for z = pos.z - size[1], pos.z + size[1] do
local ppos = {x = x, y = y, z = z}
if minetest.get_node(ppos).name == "air" and
ppos.x > box.minp.x and ppos.x < box.maxp.x and
ppos.y > box.minp.y and ppos.y < box.maxp.y and
ppos.z > box.minp.z and ppos.z < box.maxp.z and
not vector.equals(ppos, head) and
vector.distance(pos, ppos) <=
(math.random(size[2], size[3]) / 10)
then
minetest.set_node(ppos, node)
end
end
end
end
elseif mode == 1 or mode == 3 then
for x = pos.x - size[1], pos.x + size[1] do
for z = pos.z - size[1], pos.z + size[1] do
local ppos = {x = x, y = pos.y, z = z}
if minetest.get_node(ppos).name == "air" and
ppos.x > box.minp.x and ppos.x < box.maxp.x and
ppos.y > box.minp.y and ppos.y < box.maxp.y and
ppos.z > box.minp.z and ppos.z < box.maxp.z and
not vector.equals(ppos, head) and
vector.distance(pos, ppos) <=
(math.random(size[2], size[3]) / 10)
then
minetest.set_node(ppos, node)
end
end
end
end
return itemstack
end,
})
frame.register("tools:bulk")
minetest.register_tool("tools:paint", {
description = "Paint tool\nPaint nodes over with a different node\nLeft-click to " ..
"fill the tool with a node\nRight-click to paint",
inventory_image = "node_paint_tool.png",
on_use = function(itemstack, placer, pointed_thing)
if not pointed_thing or not pointed_thing.under then
return itemstack
end
local node = minetest.get_node(pointed_thing.under)
local def = minetest.registered_nodes[node.name]
if not def and not def.groups then
return itemstack
end
if def.groups.not_in_creative_inventory or
def.groups.trigger or def.groups.mech or
def.groups.door
then
return itemstack
end
itemstack:set_metadata(minetest.serialize(node))
minetest.chat_send_player(placer:get_player_name(),
"Paint tool will paint " .. node.name)
local meta = itemstack:get_meta()
meta:set_string("description", "Paint tool\nNode: " .. node.name)
return itemstack
end,
on_place = function(itemstack, placer, pointed_thing)
if not pointed_thing or not pointed_thing.above or not placer then
return
end
local node = minetest.deserialize(itemstack:get_metadata())
if not node then
minetest.chat_send_player(placer:get_player_name(),
"Pick up a node first by left-clicking it with this tool")
return
end
local name = placer:get_player_name()
local box = boxes.players_editing_boxes[name]
if not box and not minetest.check_player_privs(name, "server") then
return
end
if not box then
box = {
minp = { x = -32768, y = -32768, z = -32768 },
maxp = { x = 32768, y = 32768, z = 32768 },
}
end
local pos = pointed_thing.under
if pos.x > box.minp.x and pos.x < box.maxp.x and
pos.y > box.minp.y and pos.y < box.maxp.y and
pos.z > box.minp.z and pos.z < box.maxp.z then
minetest.set_node(pos, node)
end
return itemstack
end,
})
frame.register("tools:paint")
minetest.register_tool("tools:grow", {
description = "Grow things",
inventory_image = "grow_tool.png",
on_place = function(itemstack, placer, pointed_thing)
if not pointed_thing or not pointed_thing.under or not placer then
return
end
local name = placer:get_player_name()
local box = boxes.players_editing_boxes[name]
if not box then
if not minetest.check_player_privs(placer, "server") then
return
end
box = {
minp = { x = -32768, y = -32768, z = -32768 },
maxp = { x = 32768, y = 32768, z = 32768 },
}
end
local pos = pointed_thing.under
local nname = minetest.get_node(pos).name
if nname == "nodes:dirt" then
for x = math.max(box.minp.x + 1, pos.x - 2), math.min(box.maxp.x - 1, pos.x + 2) do
for y = math.max(box.minp.y + 1, pos.y), math.min(box.maxp.y - 1, pos.y) do
for z = math.max(box.minp.z + 1, pos.z - 2), math.min(box.maxp.z - 1, pos.z + 2) do
local ppos = {x = x, y = y, z = z}
if vector.distance(pos, ppos) <= 2.3 then
local node = minetest.get_node(ppos)
local above_node = minetest.get_node({x = x, y = y + 1, z = z})
if node.name == "nodes:dirt" and
minetest.registered_nodes[above_node.name] and
minetest.registered_nodes[above_node.name].walkable == false then
node.name = "nodes:dirt_with_grass"
minetest.set_node(ppos, node)
end
end
end
end
end
elseif nname == "nodes:grass" or nname == "nodes:dirt_with_grass" then
-- Grow grass and other things
for x = math.max(box.minp.x + 1, pos.x - 2), math.min(box.maxp.x - 1, pos.x + 2) do
for y = math.max(box.minp.y + 1, pos.y), math.min(box.maxp.y - 1, pos.y) do
for z = math.max(box.minp.z + 1, pos.z - 2), math.min(box.maxp.z - 1, pos.z + 2) do
local ppos = {x = x, y = y, z = z}
if vector.distance(pos, ppos) <= 2.3 then
local node = minetest.get_node(ppos)
local pos_above = {x = x, y = y + 1, z = z}
local above_node = minetest.get_node(pos_above)
if (node.name == "nodes:grass" or node.name == "nodes:dirt_with_grass") and
above_node.name == "air" and math.random() < 0.2 then
local plants = {
{"grass_1", 56},
{"grass_2", 56},
{"grass_3", 56},
{"grass_4", 56},
{"grass_5", 56},
{"grass_1", 56},
{"grass_2", 56},
{"grass_3", 56},
{"grass_4", 56},
{"grass_5", 56},
{"grass_1", 56},
{"grass_2", 56},
{"grass_3", 56},
{"grass_4", 56},
{"grass_5", 56},
{"grass_1", 56},
{"grass_2", 56},
{"grass_3", 56},
{"grass_4", 56},
{"grass_5", 56},
{"rose", 9},
{"dandelion", 9},
{"white_tulip", 9},
{"allium", 9},
{"orchid", 9},
{"daisy", 9},
{"houstonia", 9},
{"paeonia", 9},
}
local p = plants[math.random(1, 28)]
local nnode = {name = "nodes:" .. p[1], param2 = p[2]}
minetest.set_node(pos_above, nnode)
end
end
end
end
end
end
return itemstack
end,
})
frame.register("tools:grow")
minetest.register_tool("tools:reveal", {
description = "Reveal breakable nodes and Placeholder nodes",
inventory_image = "reveal_tool.png",
on_use = function(itemstack, digger, pointed_thing)
if not digger then
return
end
local name = digger:get_player_name()
if not boxes.players_editing_boxes[name] then
return
end
local box = boxes.players_editing_boxes[name]
if not box then
if not minetest.check_player_privs(digger, "server") then
return
end
box = {
minp = { x = -32768, y = -32768, z = -32768 },
maxp = { x = 32768, y = 32768, z = 32768 },
}
end
local off = {
{ x = 0, y = 0, z = -9/16},
{ x = 0, y = 0, z = 9/16},
{ x = 0, y = -9/16, z = 0},
{ x = 0, y = 9/16, z = 0},
{ x = -9/16, y = 0, z = 0},
{ x = 9/16, y = 0, z = 0},
}
local ppos = vector.floor(digger:get_pos())
for x = math.max(ppos.x - 8, box.minp.x + 1),
math.min(ppos.x + 8, box.maxp.x - 1) do
for y = math.max(ppos.y - 8, box.minp.y + 1),
math.min(ppos.y + 8, box.maxp.y - 1) do
for z = math.max(ppos.z - 8, box.minp.z + 1),
math.min(ppos.z + 8, box.maxp.z - 1) do
local pos = vector.new(x, y, z)
local node = minetest.get_node(pos)
local groups = minetest.registered_nodes[node.name] and
minetest.registered_nodes[node.name].groups
local texture
if groups.axe then
texture = "axe.png"
elseif groups.shovel then
texture = "shovel.png"
elseif groups.pickaxe then
texture = "pickaxe.png"
elseif groups.hand then
texture = "wieldhand.png"
end
--FIXME leaves somehow don't work?
if texture and vector.distance(pos, digger:get_pos()) < 8 then
for _, v in ipairs(off) do
minetest.add_particle({
pos = vector.add(pos, v),
expirationtime = 8,
size = 3,
texture = texture,
playername = name,
glow = 13,
})
end
end
if node.name == "nodes:placeholder" then
local meta = minetest.get_meta(pos)
local placeable = meta:get_string("placeable")
if placeable ~= "" then
local nodelist = minetest.parse_json(placeable)
--FIXME just do the first placeholder, only
local n, _ = next(nodelist)
minetest.add_particle({
pos = pos,
expirationtime = 8,
size = 3,
texture = nodes.get_tiles(n),
glow = 14,
playername = name,
})
end
end
end
end
end
return itemstack
end,
})
frame.register("tools:reveal")