1045 lines
30 KiB
Lua
1045 lines
30 KiB
Lua
|
|
--[[
|
|
|
|
ITB (insidethebox) minetest game - Copyright (C) 2017-2018 sofar & nore
|
|
|
|
This library is free software; you can redistribute it and/or
|
|
modify it under the terms of the GNU Lesser General Public License
|
|
as published by the Free Software Foundation; either version 2.1
|
|
of the License, or (at your option) any later version.
|
|
|
|
This library is distributed in the hope that it will be useful,
|
|
but WITHOUT ANY WARRANTY; without even the implied warranty of
|
|
MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU
|
|
Lesser General Public License for more details.
|
|
|
|
You should have received a copy of the GNU Lesser General Public
|
|
License along with this library; if not, write to the Free
|
|
Software Foundation, Inc., 59 Temple Place, Suite 330, Boston,
|
|
MA 02111-1307 USA
|
|
|
|
]]--
|
|
|
|
local S = minetest.get_translator("tools")
|
|
|
|
--
|
|
-- 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 = {
|
|
hand = {times={[1] = 0.2}, uses = 0, maxlevel = 1},
|
|
},
|
|
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 = {
|
|
hand = {times={[1] = 0.2}, uses = 0, maxlevel = 1},
|
|
axe = {times={[1] = 0.2}, uses = 0, maxlevel = 1},
|
|
shovel = {times={[1] = 0.2}, uses = 0, maxlevel = 1},
|
|
pickaxe = {times={[1] = 0.2}, uses = 0, maxlevel = 1},
|
|
node = {times={[1] = 0.2}, uses = 0, maxlevel = 1},
|
|
unbreakable = {times={[1] = 0.2}, uses = 0, maxlevel = 1},
|
|
},
|
|
damage_groups = {},
|
|
},
|
|
groups = {not_in_creative_inventory = 1}
|
|
})
|
|
|
|
|
|
-- node tools
|
|
minetest.register_craftitem("tools:shovel", {
|
|
description = S("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_craftitem("tools:axe", {
|
|
description = S("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_craftitem("tools:pickaxe", {
|
|
description = S("Pickaxe"),
|
|
inventory_image = "pickaxe.png",
|
|
tool_capabilities = {
|
|
groupcaps = {
|
|
pickaxe = {
|
|
times = {[1] = 3, [2] = 3, [3] = 3},
|
|
uses = 0,
|
|
},
|
|
},
|
|
},
|
|
})
|
|
frame.register("tools:pickaxe")
|
|
|
|
minetest.register_craftitem("tools:sword", {
|
|
description = S("Sword"),
|
|
inventory_image = "sword.png",
|
|
})
|
|
frame.register("tools:sword")
|
|
|
|
|
|
minetest.register_craftitem("tools:flint_and_steel", {
|
|
description = S("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 = S("Admin remove tool"),
|
|
inventory_image = "admin_tool.png",
|
|
liquids_pointable = true,
|
|
range = 10,
|
|
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 = S("Remove tool").."\n"..
|
|
S("Left-click to remove a node").."\n"..
|
|
S("Right-click to remove a lot of nodes").."\n"..
|
|
S("Shift-left-click a placed node to restrict removal"),
|
|
inventory_image = "remove_tool.png",
|
|
liquids_pointable = true,
|
|
range = 6,
|
|
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
|
|
if not pointed_thing or not pointed_thing.under then
|
|
if not digger:get_player_control().sneak then
|
|
return itemstack
|
|
end
|
|
-- empty the contained node
|
|
local meta = itemstack:get_meta()
|
|
meta:set_string("nodes", "return {}")
|
|
minetest.chat_send_player(name, S("Remove tool unrestricted"))
|
|
meta:set_string("description", S("Remove tool").."\n"..
|
|
S("Left-click to remove a node").."\n"..
|
|
S("Right-click to remove a lot of nodes").."\n"..
|
|
S("Shift-left-click a placed node to restrict removal"))
|
|
return itemstack
|
|
end
|
|
if digger:get_player_control().sneak then
|
|
-- fill the itemstack
|
|
local meta = itemstack:get_meta()
|
|
local nodes = minetest.deserialize(meta:get_string("nodes") or {}) or {}
|
|
local node = minetest.get_node(pointed_thing.under)
|
|
nodes[#nodes + 1] = node.name
|
|
meta:set_string("nodes", minetest.serialize(nodes))
|
|
minetest.chat_send_player(name, S("Remove tool restricted to: @1", table.concat(nodes, ", ")))
|
|
meta:set_string("description", S("Remove tool").."\n"..S("Will remove: @1", table.concat(nodes, ", ")))
|
|
return itemstack
|
|
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
|
|
local meta = itemstack:get_meta()
|
|
local n = meta:get_string("nodes")
|
|
|
|
if n and n ~= "" and n ~= "return {}" then
|
|
local nodes = minetest.deserialize(n)
|
|
local t = minetest.get_node(pointed_thing.under)
|
|
for _, v in ipairs(nodes) do
|
|
if t.name == v then
|
|
node_dig(pointed_thing.under, digger)
|
|
end
|
|
end
|
|
return itemstack
|
|
end
|
|
|
|
node_dig(pointed_thing.under, digger)
|
|
|
|
return itemstack
|
|
end,
|
|
on_place = function(itemstack, placer, pointed_thing)
|
|
if not pointed_thing or not pointed_thing.under then
|
|
return
|
|
end
|
|
if not placer then
|
|
return
|
|
end
|
|
local name = placer: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
|
|
|
|
local meta = itemstack:get_meta()
|
|
local n = meta:get_string("nodes")
|
|
local nodes = {}
|
|
if n and n ~= "" and n ~= "return {}" then
|
|
nodes = minetest.deserialize(n)
|
|
end
|
|
|
|
for x = pos.x - 1, pos.x + 1 do
|
|
for y = pos.y + 1, pos.y - 1, -1 do
|
|
for z = pos.z - 1, pos.z + 1 do
|
|
if x > box.minp.x and x < box.maxp.x and
|
|
y > box.minp.y and y < box.maxp.y and
|
|
z > box.minp.z and z < box.maxp.z then
|
|
if #nodes == 0 then
|
|
node_dig({x = x, y = y, z = z}, placer)
|
|
else
|
|
for _, v in ipairs(nodes) do
|
|
local p = {x = x, y = y, z = z}
|
|
local t = minetest.get_node(p)
|
|
if t.name == v then
|
|
node_dig(p, placer)
|
|
end
|
|
end
|
|
end
|
|
end
|
|
end
|
|
end
|
|
end
|
|
return itemstack
|
|
end,
|
|
})
|
|
frame.register("tools:player")
|
|
|
|
local bulk_modes = {
|
|
[0] = "blob",
|
|
[1] = "sheet",
|
|
[2] = "large blob",
|
|
[3] = "large sheet",
|
|
[4] = "wall",
|
|
}
|
|
minetest.register_tool("tools:bulk", {
|
|
description = S("Bulk placement tool").."\n"..
|
|
S("Left-click air to toggle mode").."\n"..
|
|
S("Shift-left-click to toggle mode").."\n"..
|
|
S("Left-click a node to pick it up").."\n"..
|
|
S("Right-click to place nodes"),
|
|
inventory_image = "node_place_tool.png",
|
|
liquids_pointable = true,
|
|
range = 8,
|
|
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
|
|
mode = mode + 1
|
|
if mode > #bulk_modes then
|
|
mode = 0
|
|
end
|
|
minetest.chat_send_player(placer:get_player_name(),
|
|
S("Bulk placement tool will place \"@1\".", bulk_modes[mode]))
|
|
|
|
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
|
|
if not minetest.check_player_privs(placer:get_player_name(), "server") then
|
|
return itemstack
|
|
end
|
|
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", S("Bulk placement tool").."\n"..
|
|
S("Node: @1", node.name).."\n"..
|
|
S("Mode: @1", bulk_modes[meta:get_int("mode")]))
|
|
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(),
|
|
S("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.under
|
|
local pnode = minetest.get_node(pos)
|
|
if not minetest.registered_nodes[pnode.name].buildable_to then
|
|
pos = pointed_thing.above
|
|
end
|
|
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
|
|
|
|
local function can_place_at(p, b, h)
|
|
if p.x <= b.minp.x or p.x >= b.maxp.x or
|
|
p.y <= b.minp.y or p.y >= b.maxp.y or
|
|
p.z <= b.minp.z or p.z >= b.maxp.z then
|
|
return false
|
|
end
|
|
if vector.equals(p, h) then
|
|
return false
|
|
end
|
|
local n = minetest.get_node(p)
|
|
if n.name == "air" then
|
|
return true
|
|
end
|
|
local def = minetest.registered_nodes[n.name]
|
|
if def and def.liquidtype and def.liquidtype == "flowing" then
|
|
return true
|
|
end
|
|
return false
|
|
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 can_place_at(ppos, box, 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 can_place_at(ppos, box, head) and
|
|
vector.distance(pos, ppos) <=
|
|
(math.random(size[2], size[3]) / 10)
|
|
then
|
|
minetest.set_node(ppos, node)
|
|
end
|
|
end
|
|
end
|
|
elseif mode == 4 then
|
|
local dir = minetest.yaw_to_dir(placer:get_look_yaw() - (math.pi / 2))
|
|
for i = 0, 4 do
|
|
for y = 0, 2 do
|
|
local ppos = vector.round(vector.add(pos, vector.multiply(dir, i)))
|
|
ppos.y = ppos.y + y
|
|
if can_place_at(ppos, box, head) then
|
|
minetest.set_node(ppos, node)
|
|
end
|
|
end
|
|
end
|
|
else
|
|
return itemstack
|
|
end
|
|
minetest.log("action", name .. " uses tools:bulk placing a " .. bulk_modes[mode] ..
|
|
" of " .. node.name .. " at " .. minetest.pos_to_string(pos))
|
|
return itemstack
|
|
end,
|
|
})
|
|
frame.register("tools:bulk")
|
|
|
|
minetest.register_tool("tools:paint", {
|
|
description = S("Paint tool").."\n"..
|
|
S("Paint nodes over with a different node").."\n"..
|
|
S("Left-click to fill the tool with a node").."\n"..
|
|
S("Right-click to paint"),
|
|
inventory_image = "node_paint_tool.png",
|
|
liquids_pointable = true,
|
|
range = 6,
|
|
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.door
|
|
then
|
|
if not minetest.check_player_privs(placer:get_player_name(), "server") then
|
|
return itemstack
|
|
end
|
|
end
|
|
local meta = itemstack:get_meta()
|
|
meta:set_string("node", minetest.serialize(node))
|
|
meta:set_string("meta", minetest.serialize(minetest.get_meta(pointed_thing.under):to_table()))
|
|
meta:set_string("description", "Paint tool\nNode: " .. node.name)
|
|
minetest.chat_send_player(placer:get_player_name(),
|
|
"Paint tool will paint " .. 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 meta = itemstack:get_meta()
|
|
local node = minetest.deserialize(meta:get_string("node"))
|
|
local nmeta = minetest.deserialize(meta:get_string("meta"))
|
|
if not node then
|
|
minetest.chat_send_player(placer:get_player_name(),
|
|
S("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
|
|
if nmeta then
|
|
local pmeta = minetest.get_meta(pos)
|
|
pmeta:from_table(nmeta)
|
|
end
|
|
|
|
return itemstack
|
|
end,
|
|
})
|
|
frame.register("tools:paint")
|
|
|
|
-- Register tables for all plant variants
|
|
local plants_rotate = {}
|
|
do
|
|
-- Growth stages
|
|
|
|
local t = { 8 }
|
|
for i=0,3 do
|
|
table.insert(t, "carrots_stage_"..i)
|
|
end
|
|
table.insert(plants_rotate, t)
|
|
|
|
local t = { 10 }
|
|
for i=0,3 do
|
|
table.insert(t, "potatoes_stage_"..i)
|
|
end
|
|
table.insert(plants_rotate, t)
|
|
|
|
t = { 11 }
|
|
for i=0,7 do
|
|
table.insert(t, "wheat_stage_"..i)
|
|
end
|
|
table.insert(plants_rotate, t)
|
|
|
|
t = { 56 }
|
|
for i=1,5 do
|
|
table.insert(t, "grass_"..i)
|
|
end
|
|
table.insert(plants_rotate, t)
|
|
|
|
|
|
-- Plant style variants
|
|
|
|
t = { 8 }
|
|
for i=1,6 do
|
|
table.insert(t, "sapling_"..i)
|
|
end
|
|
table.insert(plants_rotate, t)
|
|
table.insert(plants_rotate, { 9, "rose", "dandelion", "white_tulip", "allium", "orchid", "daisy", "houstonia", "paeonia", })
|
|
table.insert(plants_rotate, { 10, "mushroom_red", "mushroom_brown" })
|
|
end
|
|
|
|
local plant_mappings = {}
|
|
for p=1, #plants_rotate do
|
|
local rotate = plants_rotate[p]
|
|
local param2 = rotate[1]
|
|
for r=2, #rotate do
|
|
local nextr
|
|
if r < #rotate then
|
|
nextr = r+1
|
|
else
|
|
nextr = 2
|
|
end
|
|
plant_mappings["nodes:"..rotate[r]] = { "nodes:"..rotate[nextr], param2 }
|
|
plant_mappings["nodes:flowerpot_"..rotate[r]] = { "nodes:flowerpot_"..rotate[nextr] }
|
|
end
|
|
end
|
|
|
|
minetest.register_tool("tools:grow", {
|
|
description = S("Growth tool"),
|
|
inventory_image = "grow_tool.png",
|
|
range = 6,
|
|
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 plant_mappings[nname] then
|
|
-- Cycle through plant growth stages and plant variants
|
|
minetest.set_node(pos, {name=plant_mappings[nname][1], param2=plant_mappings[nname][2]})
|
|
elseif nname == "nodes:melon_seeds" then
|
|
-- Grow melon
|
|
minetest.set_node(pos, {name="nodes:melon", param2=math.random(0,3)})
|
|
elseif nname == "nodes:pumpkin_seeds" then
|
|
-- Grow pumpkin
|
|
minetest.set_node(pos, {name="nodes:pumpkin", param2=math.random(0,3)})
|
|
elseif nname == "nodes:wheat_seeds" then
|
|
-- Grow wheat
|
|
minetest.set_node(pos, {name="nodes:wheat_stage_0", param2=11})
|
|
elseif nname == "nodes:flowerpot_empty" then
|
|
-- Grow random flower in empty flowerpot
|
|
local param2 = minetest.get_node(pos).param2
|
|
local flowers = {
|
|
"rose", "dandelion", "white_tulip", "allium", "orchid", "daisy", "houstonia", "paeonia",
|
|
}
|
|
local flower = flowers[math.random(1, #flowers)]
|
|
minetest.set_node(pos, {name="nodes:flowerpot_"..flower, param2=param2})
|
|
elseif nname == "nodes:fire" or minetest.get_item_group(nname, "leaves") == 1 then
|
|
-- Grow leaves and spread fire
|
|
local posses = {
|
|
{ x=0, y=0, z=1 },
|
|
{ x=0, y=0, z=-1 },
|
|
{ x=0, y=1, z=0 },
|
|
{ x=0, y=-1, z=0 },
|
|
{ x=1, y=0, z=0 },
|
|
{ x=-1, y=0, z=0 },
|
|
}
|
|
for p=1, #posses do
|
|
local ppos = vector.add(pos, posses[p])
|
|
if minetest.get_node(ppos).name == "air" then
|
|
minetest.set_node(ppos, {name=nname})
|
|
end
|
|
end
|
|
elseif nname == "nodes:reeds" or minetest.get_item_group(nname, "tree") == 1 then
|
|
-- Grow reeds and tree trunks upwards
|
|
local above
|
|
for i=1,15 do
|
|
above = {x=pos.x,y=pos.y+i,z=pos.z}
|
|
local node = minetest.get_node(above)
|
|
if node.name == "air" then
|
|
minetest.set_node(above, {name=nname})
|
|
break
|
|
elseif node.name ~= nname then
|
|
break
|
|
end
|
|
end
|
|
elseif nname == "nodes:vine" or nname == "nodes:ladder" or nname == "nodes:rope" then
|
|
-- Grow vines. Also "grow" other climbable nodes for convenience
|
|
local param2 = minetest.get_node(pos).param2
|
|
if param2 >= 2 or nname == "nodes:rope" then
|
|
-- Grow downwards if sideways or rope
|
|
local below
|
|
for i=1,15 do
|
|
below = {x=pos.x,y=pos.y-i,z=pos.z}
|
|
local node = minetest.get_node(below)
|
|
if node.name == "air" then
|
|
minetest.set_node(below, {name=nname, param2=param2})
|
|
break
|
|
elseif node.name ~= nname then
|
|
break
|
|
end
|
|
end
|
|
else
|
|
-- At floor or ceiling: grow around
|
|
local posses = {
|
|
{ x=1, y=0, z=0 },
|
|
{ x=-1, y=0, z=0 },
|
|
{ x=0, y=0, z=1 },
|
|
{ x=0, y=0, z=-1 },
|
|
}
|
|
for p=1, #posses do
|
|
local ppos = vector.add(pos, posses[p])
|
|
if minetest.get_node(ppos).name == "air" then
|
|
minetest.set_node(ppos, {name=nname, param2=param2})
|
|
break
|
|
end
|
|
end
|
|
end
|
|
elseif nname == "nodes:dirt" then
|
|
-- Grow grass cover on dirt
|
|
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" or nname == "nodes:mycelium" or nname == "nodes:dirt_with_snow" or nname == "nodes:sand" or nname == "nodes:gravel" or nname == "nodes:dirt_with_podzol" or nname == "nodes:soil" or nname == "nodes:soil_wet" then
|
|
-- Grow grass, flowers and other random plants
|
|
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 above_node.name == "air" and math.random() < 0.2 and node.name == nname then
|
|
local plants
|
|
if (node.name == "nodes:grass" or node.name == "nodes:dirt_with_grass") then
|
|
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},
|
|
}
|
|
elseif (node.name == "nodes:mycelium") then
|
|
plants = {
|
|
{"mushroom_red",10},
|
|
{"mushroom_brown",10},
|
|
}
|
|
elseif (node.name == "nodes:dirt_with_snow") then
|
|
plants = {
|
|
{ "dead_bush", 56 },
|
|
}
|
|
elseif (node.name == "nodes:sand") then
|
|
plants = {
|
|
{ "dead_bush", 56 },
|
|
{ "dead_bush", 56 },
|
|
{ "dead_bush", 56 },
|
|
{ "dead_bush", 56 },
|
|
{ "dead_bush", 56 },
|
|
{ "grass_1", 56 },
|
|
{ "grass_2", 56 },
|
|
}
|
|
elseif (node.name == "nodes:gravel") then
|
|
plants = {
|
|
{ "grass_1", 56 },
|
|
{ "grass_1", 56 },
|
|
{ "grass_2", 56 },
|
|
}
|
|
elseif (node.name == "nodes:dirt_with_podzol") then
|
|
plants = {
|
|
{"mushroom_red", 10},
|
|
{"mushroom_brown", 10},
|
|
{"fern", 9},
|
|
{"fern", 9},
|
|
{"fern", 9},
|
|
{"fern", 9},
|
|
{"fern", 9},
|
|
{"dead_bush", 9},
|
|
{"dead_bush", 9},
|
|
{"dead_bush", 9},
|
|
{"dead_bush", 9},
|
|
{"grass_1", 56},
|
|
{"grass_2", 56},
|
|
{"rose", 9},
|
|
{"dandelion", 9},
|
|
}
|
|
elseif (node.name == "nodes:soil" or node.name == "nodes:soil_wet") then
|
|
plants = {
|
|
{"carrots_stage_0", 8},
|
|
{"carrots_stage_0", 8},
|
|
{"carrots_stage_1", 8},
|
|
{"carrots_stage_1", 8},
|
|
{"carrots_stage_2", 8},
|
|
{"carrots_stage_2", 8},
|
|
{"carrots_stage_3", 8},
|
|
{"carrots_stage_3", 8},
|
|
{"potatoes_stage_0", 10},
|
|
{"potatoes_stage_0", 10},
|
|
{"potatoes_stage_1", 10},
|
|
{"potatoes_stage_1", 10},
|
|
{"potatoes_stage_2", 10},
|
|
{"potatoes_stage_2", 10},
|
|
{"potatoes_stage_3", 10},
|
|
{"potatoes_stage_3", 10},
|
|
{"wheat_stage_0", 11},
|
|
{"wheat_stage_1", 11},
|
|
{"wheat_stage_2", 11},
|
|
{"wheat_stage_3", 11},
|
|
{"wheat_stage_4", 11},
|
|
{"wheat_stage_5", 11},
|
|
{"wheat_stage_6", 11},
|
|
{"wheat_stage_7", 11},
|
|
}
|
|
end
|
|
if plants then
|
|
local p = plants[math.random(1, #plants)]
|
|
local nnode = {name = "nodes:" .. p[1], param2 = p[2]}
|
|
minetest.set_node(pos_above, nnode)
|
|
end
|
|
end
|
|
end
|
|
end
|
|
end
|
|
end
|
|
elseif nname == "nodes:waterlily" then
|
|
-- Spread waterlilies on water
|
|
for x = math.max(box.minp.x + 1, pos.x - 3), math.min(box.maxp.x - 1, pos.x + 3) 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 - 3), math.min(box.maxp.z - 1, pos.z + 3) do
|
|
local ppos = {x = x, y = y, z = z}
|
|
if vector.distance(pos, ppos) <= 3.0 then
|
|
local node = minetest.get_node(ppos)
|
|
local below_node = minetest.get_node({x = x, y = y - 1, z = z})
|
|
if node.name == "air" and
|
|
math.random() < 0.1 and
|
|
minetest.get_item_group(below_node.name, "water") >= 1 and
|
|
minetest.registered_nodes[below_node.name].liquidtype == "source" then
|
|
node.name = "nodes:waterlily"
|
|
node.param2 = math.random(0,3)
|
|
minetest.set_node(ppos, node)
|
|
end
|
|
end
|
|
end
|
|
end
|
|
end
|
|
|
|
end
|
|
return itemstack
|
|
end,
|
|
})
|
|
frame.register("tools:grow")
|
|
|
|
local function dehash_vector(s)
|
|
return {
|
|
x = 256 * string.byte(s, 1) + string.byte(s, 2) - 32768,
|
|
y = 256 * string.byte(s, 3) + string.byte(s, 4) - 32768,
|
|
z = 256 * string.byte(s, 5) + string.byte(s, 6) - 32768,
|
|
}
|
|
end
|
|
|
|
local function particlestream(p, o, name)
|
|
local d = vector.length(o)
|
|
local c = 0
|
|
while c < d - 0.5 do
|
|
minetest.add_particle({
|
|
texture = "glowblock.png",
|
|
pos = vector.add(p, vector.multiply(o, c / d)),
|
|
velocity = vector.divide(o, d * 3),
|
|
expirationtime = 3,
|
|
size = 2,
|
|
glow = 14,
|
|
playername = name,
|
|
})
|
|
c = c + 0.5
|
|
end
|
|
end
|
|
|
|
minetest.register_tool("tools:reveal", {
|
|
description = S("Reveal tool").."\n"..
|
|
S("Reveal breakable nodes and placeholder nodes").."\n"..
|
|
S("Punch a node to see its connections"),
|
|
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] and not minetest.check_player_privs(digger, "review") 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},
|
|
}
|
|
|
|
-- if clicking a node, reveal mech connections
|
|
if pointed_thing.under then
|
|
local p = pointed_thing.under
|
|
local meta = minetest.get_meta(p)
|
|
local offsets = minetest.deserialize(meta:get_string("offsets")) or {}
|
|
for v, _ in pairs(offsets) do
|
|
local o = dehash_vector(v)
|
|
particlestream(p, o, name)
|
|
end
|
|
local roffsets = minetest.deserialize(meta:get_string("roffsets")) or {}
|
|
for v, _ in pairs(roffsets) do
|
|
local o = dehash_vector(v)
|
|
particlestream(vector.add(p, o), {x=-o.x, y=-o.y, z=-o.z}, name)
|
|
end
|
|
|
|
local dn = digger:get_player_name()
|
|
|
|
-- reveal callbacks, mech linkage info
|
|
local n = minetest.get_node(p)
|
|
if n and n.name and minetest.registered_nodes[n.name] then
|
|
local def = minetest.registered_nodes[n.name]
|
|
minetest.chat_send_player(dn, minetest.colorize("#ff8888",
|
|
"Detailed info for \"" .. def.description:gsub("\n.*", "") ..
|
|
"\" at " .. minetest.pos_to_string(p) .. ":"))
|
|
|
|
for so, _ in pairs(offsets) do
|
|
local offs = dehash_vector(so)
|
|
local npos = vector.add(p, offs)
|
|
local nname = minetest.get_node(npos).name
|
|
minetest.chat_send_player(dn, minetest.colorize("#44ff88",
|
|
"> triggers " .. nname .. " at " ..
|
|
minetest.pos_to_string(npos) .. " (offset is " ..
|
|
minetest.pos_to_string(offs) .. ")"))
|
|
end
|
|
|
|
for so, _ in pairs(roffsets) do
|
|
local offs = dehash_vector(so)
|
|
local npos = vector.add(p, offs)
|
|
local nname = minetest.get_node(npos).name
|
|
minetest.chat_send_player(dn, minetest.colorize("#8888ff",
|
|
"> triggered by " .. nname .. " at " ..
|
|
minetest.pos_to_string(npos) .. " (offset is " ..
|
|
minetest.pos_to_string(offs) .. ")"))
|
|
end
|
|
|
|
local cb = def.on_reveal
|
|
if cb then
|
|
cb(dn, p)
|
|
end
|
|
|
|
end
|
|
end
|
|
|
|
local limit = 32
|
|
local ppos = vector.floor(digger:get_pos())
|
|
local nodeslist = {}
|
|
local needle = {"group:axe", "group:shovel", "group:pickaxe", "group:hand", "nodes:placeholder", "group:torch"}
|
|
for d = 3, 6 do
|
|
if limit > 0 then
|
|
local poslist, _ = minetest.find_nodes_in_area(vector.subtract(ppos, d),
|
|
vector.add(ppos, d),
|
|
needle)
|
|
|
|
for _, v in pairs(poslist) do
|
|
if limit > 0 then
|
|
if v.x < box.maxp.x and v.y < box.maxp.y and v.z < box.maxp.z and
|
|
v.x > box.minp.x and v.y > box.minp.y and v.z > box.minp.z then
|
|
nodeslist[minetest.pos_to_string(v)] = 1
|
|
limit = limit - 1
|
|
end
|
|
end
|
|
end
|
|
end
|
|
end
|
|
|
|
for k, _ in pairs(nodeslist) do
|
|
local pos = minetest.string_to_pos(k)
|
|
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 and
|
|
node.name ~= "nodes:snow_ledge" 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" or node.name == "torches:torch" or node.name == "torches:torch_wall" 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
|
|
|
|
return itemstack
|
|
end,
|
|
})
|
|
frame.register("tools:reveal")
|