Auke Kok ca7c77c895 Undo translation of technical items.
This really breaks badly. Too many untranslatable characters that
completely break things. These are meant to be technical and postion
strings are not translatable either. Revert.
2019-09-12 22:27:45 -07:00

810 lines
23 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_tool("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_tool("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_tool("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_tool("tools:sword", {
description = S("Sword"),
inventory_image = "sword.png",
})
frame.register("tools:sword")
minetest.register_tool("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")
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 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")
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, "server") 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.registered_nodes[minetest.get_node(npos).name].description
minetest.chat_send_player(dn, minetest.colorize("#44ff88",
"> triggers " .. nname:gsub("[\n(].*", "") .. " 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.registered_nodes[minetest.get_node(npos).name].description
minetest.chat_send_player(dn, minetest.colorize("#8888ff",
"> triggered by " .. nname:gsub("[\n(].*", "") .. " 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 nodes = {}
local needle = {"group:axe", "group:shovel", "group:pickaxe", "group:hand"}
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
nodes[minetest.pos_to_string(v)] = 1
limit = limit - 1
end
end
end
end
end
for k, _ in pairs(nodes) 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" 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")