Fix reveal node for placeholders.
[insidethebox.git] / mods / tools / init.lua
blob4c00b2a746ed6f65c4332e3e8fc137b72d3c50ec
2 --[[
4 ITB (insidethebox) minetest game - Copyright (C) 2017-2018 sofar & nore
6 This library is free software; you can redistribute it and/or
7 modify it under the terms of the GNU Lesser General Public License
8 as published by the Free Software Foundation; either version 2.1
9 of the License, or (at your option) any later version.
11 This library is distributed in the hope that it will be useful,
12 but WITHOUT ANY WARRANTY; without even the implied warranty of
13 MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU
14 Lesser General Public License for more details.
16 You should have received a copy of the GNU Lesser General Public
17 License along with this library; if not, write to the Free
18 Software Foundation, Inc., 59 Temple Place, Suite 330, Boston,
19 MA 02111-1307 USA
21 ]]--
23 local S = minetest.get_translator("tools")
26 -- hand tools
28 minetest.register_item(":", {
29 type = "none",
30 wield_image = "wieldhand.png",
31 inventory_image = "wieldhand.png",
32 wield_scale = {x = 1, y = 1, z = 2},
33 range = 4,
34 tool_capabilities = {
35 full_punch_interval = 0.5,
36 max_drop_level = 0,
37 -- can't pick up any node by hand
38 groupcaps = {
39 hand = {times={[1] = 0.2}, uses = 0, maxlevel = 1},
41 damage_groups = {},
43 groups = {not_in_creative_inventory = 1}
46 minetest.register_item("tools:edit", {
47 type = "none",
48 wield_image = "wieldhand_edit.png",
49 inventory_image = "wieldhand_edit.png",
50 wield_scale = {x = 1, y = 1, z = 2},
51 range = 4, -- to make sure we can reach as far as the player
52 tool_capabilities = {
53 full_punch_interval = 0.1,
54 max_drop_level = 0,
55 groupcaps = {
56 hand = {times={[1] = 0.2}, uses = 0, maxlevel = 1},
57 axe = {times={[1] = 0.2}, uses = 0, maxlevel = 1},
58 shovel = {times={[1] = 0.2}, uses = 0, maxlevel = 1},
59 pickaxe = {times={[1] = 0.2}, uses = 0, maxlevel = 1},
60 node = {times={[1] = 0.2}, uses = 0, maxlevel = 1},
61 unbreakable = {times={[1] = 0.2}, uses = 0, maxlevel = 1},
63 damage_groups = {},
65 groups = {not_in_creative_inventory = 1}
69 -- node tools
70 minetest.register_tool("tools:shovel", {
71 description = S("Shovel"),
72 inventory_image = "shovel.png",
73 tool_capabilities = {
74 groupcaps = {
75 shovel = {
76 times = {[1] = 1.5, [2] = 1.5, [3] = 1.5},
77 uses = 0,
82 frame.register("tools:shovel")
84 minetest.register_tool("tools:axe", {
85 description = S("Axe"),
86 inventory_image = "axe.png",
87 tool_capabilities = {
88 groupcaps = {
89 axe = {
90 times = {[1] = 1.5, [2] = 1.5, [3] = 1.5},
91 uses = 0,
96 frame.register("tools:axe")
98 minetest.register_tool("tools:pickaxe", {
99 description = S("Pickaxe"),
100 inventory_image = "pickaxe.png",
101 tool_capabilities = {
102 groupcaps = {
103 pickaxe = {
104 times = {[1] = 3, [2] = 3, [3] = 3},
105 uses = 0,
110 frame.register("tools:pickaxe")
112 minetest.register_tool("tools:sword", {
113 description = S("Sword"),
114 inventory_image = "sword.png",
116 frame.register("tools:sword")
119 minetest.register_tool("tools:flint_and_steel", {
120 description = S("Flint and steel"),
121 inventory_image = "flint_and_steel.png",
123 frame.register("tools:flint_and_steel")
125 local function node_dig(pos, digger)
126 -- from builtin/item.lua core.node_dig():
127 local node = minetest.get_node(pos)
128 local def = minetest.registered_nodes[node.name]
130 local sounds = minetest.registered_nodes[node.name].sounds
131 if sounds and sounds.dig then
132 minetest.sound_play(sounds.dig, {pos = pos})
135 local oldmetadata = nil
136 if def and def.after_dig_node then
137 oldmetadata = core.get_meta(pos):to_table()
140 minetest.remove_node(pos, node)
142 if def and def.after_dig_node then
143 local pos_copy = {x=pos.x, y=pos.y, z=pos.z}
144 local node_copy = {name = node.name, param1 = node.param1, param2 = node.param2}
145 def.after_dig_node(pos_copy, node_copy, oldmetadata, digger)
148 for _, callback in ipairs(core.registered_on_dignodes) do
149 local origin = core.callback_origins[callback]
150 if origin then
151 core.set_last_run_mod(origin.mod)
154 -- Copy pos and node because callback can modify them
155 local pos_copy = {x=pos.x, y=pos.y, z=pos.z}
156 local node_copy = {name = node.name, param1 = node.param1, param2 = node.param2}
157 callback(pos_copy, node_copy, digger)
161 minetest.register_tool("tools:admin", {
162 description = S("Admin remove tool"),
163 inventory_image = "admin_tool.png",
164 liquids_pointable = true,
165 range = 10,
166 on_use = function(itemstack, digger, pointed_thing)
167 if not pointed_thing or not pointed_thing.under then
168 return
170 -- Prevent non-admins from using an admin tool if they ever get one
171 if not digger or not minetest.check_player_privs(digger, "server") then
172 return
174 node_dig(pointed_thing.under, digger)
175 return itemstack
176 end,
180 minetest.register_tool("tools:player", {
181 description = S("Remove tool").."\n"..
182 S("Left-click to remove a node").."\n"..
183 S("Right-click to remove a lot of nodes").."\n"..
184 S("Shift-left-click a placed node to restrict removal"),
185 inventory_image = "remove_tool.png",
186 liquids_pointable = true,
187 range = 6,
188 on_use = function(itemstack, digger, pointed_thing)
189 if not digger then
190 return
192 local name = digger:get_player_name()
193 if not boxes.players_editing_boxes[name] then
194 return
196 if not pointed_thing or not pointed_thing.under then
197 if not digger:get_player_control().sneak then
198 return itemstack
200 -- empty the contained node
201 local meta = itemstack:get_meta()
202 meta:set_string("nodes", "return {}")
203 minetest.chat_send_player(name, S("Remove tool unrestricted"))
204 meta:set_string("description", S("Remove tool").."\n"..
205 S("Left-click to remove a node").."\n"..
206 S("Right-click to remove a lot of nodes").."\n"..
207 S("Shift-left-click a placed node to restrict removal"))
208 return itemstack
210 if digger:get_player_control().sneak then
211 -- fill the itemstack
212 local meta = itemstack:get_meta()
213 local nodes = minetest.deserialize(meta:get_string("nodes") or {}) or {}
214 local node = minetest.get_node(pointed_thing.under)
215 nodes[#nodes + 1] = node.name
216 meta:set_string("nodes", minetest.serialize(nodes))
217 minetest.chat_send_player(name, S("Remove tool restricted to: @1", table.concat(nodes, ", ")))
218 meta:set_string("description", S("Remove tool").."\n"..S("Will remove: @1", table.concat(nodes, ", ")))
219 return itemstack
222 local box = boxes.players_editing_boxes[name]
223 local pos = pointed_thing.under
224 if pos.x <= box.minp.x or pos.x >= box.maxp.x or
225 pos.y <= box.minp.y or pos.y >= box.maxp.y or
226 pos.z <= box.minp.z or pos.z >= box.maxp.z
227 then
228 return
230 local meta = itemstack:get_meta()
231 local n = meta:get_string("nodes")
233 if n and n ~= "" and n ~= "return {}" then
234 local nodes = minetest.deserialize(n)
235 local t = minetest.get_node(pointed_thing.under)
236 for _, v in ipairs(nodes) do
237 if t.name == v then
238 node_dig(pointed_thing.under, digger)
241 return itemstack
244 node_dig(pointed_thing.under, digger)
246 return itemstack
247 end,
248 on_place = function(itemstack, placer, pointed_thing)
249 if not pointed_thing or not pointed_thing.under then
250 return
252 if not placer then
253 return
255 local name = placer:get_player_name()
256 if not boxes.players_editing_boxes[name] then
257 return
259 local box = boxes.players_editing_boxes[name]
260 local pos = pointed_thing.under
262 local meta = itemstack:get_meta()
263 local n = meta:get_string("nodes")
264 local nodes = {}
265 if n and n ~= "" and n ~= "return {}" then
266 nodes = minetest.deserialize(n)
269 for x = pos.x - 1, pos.x + 1 do
270 for y = pos.y + 1, pos.y - 1, -1 do
271 for z = pos.z - 1, pos.z + 1 do
272 if x > box.minp.x and x < box.maxp.x and
273 y > box.minp.y and y < box.maxp.y and
274 z > box.minp.z and z < box.maxp.z then
275 if #nodes == 0 then
276 node_dig({x = x, y = y, z = z}, placer)
277 else
278 for _, v in ipairs(nodes) do
279 local p = {x = x, y = y, z = z}
280 local t = minetest.get_node(p)
281 if t.name == v then
282 node_dig(p, placer)
290 return itemstack
291 end,
293 frame.register("tools:player")
295 local bulk_modes = {
296 [0] = "blob",
297 [1] = "sheet",
298 [2] = "large blob",
299 [3] = "large sheet",
300 [4] = "wall",
302 minetest.register_tool("tools:bulk", {
303 description = S("Bulk placement tool").."\n"..
304 S("Left-click air to toggle mode").."\n"..
305 S("Shift-left-click to toggle mode").."\n"..
306 S("Left-click a node to pick it up").."\n"..
307 S("Right-click to place nodes"),
308 inventory_image = "node_place_tool.png",
309 liquids_pointable = true,
310 range = 8,
311 on_use = function(itemstack, placer, pointed_thing)
312 if not pointed_thing or not pointed_thing.under or
313 placer:get_player_control().sneak then
314 -- toggle placement mode
315 local meta = itemstack:get_meta()
316 local mode = meta:get_int("mode") or 0
317 mode = mode + 1
318 if mode > #bulk_modes then
319 mode = 0
321 minetest.chat_send_player(placer:get_player_name(),
322 S("Bulk placement tool will place \"@1\".", bulk_modes[mode]))
324 meta:set_int("mode", mode)
325 return itemstack
327 local node = minetest.get_node(pointed_thing.under)
328 local def = minetest.registered_nodes[node.name]
329 if not def and not def.groups then
330 return itemstack
332 if def.groups.not_in_creative_inventory or
333 def.groups.trigger or def.groups.mech or
334 def.groups.door
335 then
336 if not minetest.check_player_privs(placer:get_player_name(), "server") then
337 return itemstack
340 itemstack:set_metadata(minetest.serialize(node))
341 minetest.chat_send_player(placer:get_player_name(),
342 "Bulk tool will place " .. node.name)
343 local meta = itemstack:get_meta()
344 meta:set_string("description", S("Bulk placement tool").."\n"..
345 S("Node: @1", node.name).."\n"..
346 S("Mode: @1", bulk_modes[meta:get_int("mode")]))
347 return itemstack
348 end,
349 on_place = function(itemstack, placer, pointed_thing)
350 if not pointed_thing or not pointed_thing.above or not placer then
351 return
353 local node = minetest.deserialize(itemstack:get_metadata())
354 if not node then
355 minetest.chat_send_player(placer:get_player_name(),
356 S("Pick up a node first by left-clicking it with this tool"))
357 return
359 local name = placer:get_player_name()
360 local box = boxes.players_editing_boxes[name]
361 if not box and not minetest.check_player_privs(name, "server") then
362 return
364 if not box then
365 box = {
366 minp = { x = -32768, y = -32768, z = -32768 },
367 maxp = { x = 32768, y = 32768, z = 32768 },
371 -- make sure we don't choke the player.
372 local head = vector.add(vector.round(placer:get_pos()), {x = 0, y = 1, z = 0})
374 local pos = pointed_thing.under
375 local pnode = minetest.get_node(pos)
376 if not minetest.registered_nodes[pnode.name].buildable_to then
377 pos = pointed_thing.above
379 local meta = itemstack:get_meta()
380 local mode = meta:get_int("mode") or 0
381 -- toggle size
382 local size = { 3, 20, 28 }
383 if mode == 2 or mode == 3 then
384 size = {7, 50, 68 }
387 local function can_place_at(p, b, h)
388 if p.x <= b.minp.x or p.x >= b.maxp.x or
389 p.y <= b.minp.y or p.y >= b.maxp.y or
390 p.z <= b.minp.z or p.z >= b.maxp.z then
391 return false
393 if vector.equals(p, h) then
394 return false
396 local n = minetest.get_node(p)
397 if n.name == "air" then
398 return true
400 local def = minetest.registered_nodes[n.name]
401 if def and def.liquidtype and def.liquidtype == "flowing" then
402 return true
404 return false
407 if mode == 0 or mode == 2 then
408 for x = pos.x - size[1], pos.x + size[1] do
409 for y = pos.y - size[1], pos.y + size[1] do
410 for z = pos.z - size[1], pos.z + size[1] do
411 local ppos = {x = x, y = y, z = z}
412 if can_place_at(ppos, box, head) and
413 vector.distance(pos, ppos) <=
414 (math.random(size[2], size[3]) / 10)
415 then
416 minetest.set_node(ppos, node)
421 elseif mode == 1 or mode == 3 then
422 for x = pos.x - size[1], pos.x + size[1] do
423 for z = pos.z - size[1], pos.z + size[1] do
424 local ppos = {x = x, y = pos.y, z = z}
425 if can_place_at(ppos, box, head) and
426 vector.distance(pos, ppos) <=
427 (math.random(size[2], size[3]) / 10)
428 then
429 minetest.set_node(ppos, node)
433 elseif mode == 4 then
434 local dir = minetest.yaw_to_dir(placer:get_look_yaw() - (math.pi / 2))
435 for i = 0, 4 do
436 for y = 0, 2 do
437 local ppos = vector.round(vector.add(pos, vector.multiply(dir, i)))
438 ppos.y = ppos.y + y
439 if can_place_at(ppos, box, head) then
440 minetest.set_node(ppos, node)
444 else
445 return itemstack
447 minetest.log("action", name .. " uses tools:bulk placing a " .. bulk_modes[mode] ..
448 " of " .. node.name .. " at " .. minetest.pos_to_string(pos))
449 return itemstack
450 end,
452 frame.register("tools:bulk")
454 minetest.register_tool("tools:paint", {
455 description = S("Paint tool").."\n"..
456 S("Paint nodes over with a different node").."\n"..
457 S("Left-click to fill the tool with a node").."\n"..
458 S("Right-click to paint"),
459 inventory_image = "node_paint_tool.png",
460 liquids_pointable = true,
461 range = 6,
462 on_use = function(itemstack, placer, pointed_thing)
463 if not pointed_thing or not pointed_thing.under then
464 return itemstack
466 local node = minetest.get_node(pointed_thing.under)
467 local def = minetest.registered_nodes[node.name]
468 if not def and not def.groups then
469 return itemstack
471 if def.groups.not_in_creative_inventory or
472 def.groups.door
473 then
474 if not minetest.check_player_privs(placer:get_player_name(), "server") then
475 return itemstack
478 local meta = itemstack:get_meta()
479 meta:set_string("node", minetest.serialize(node))
480 meta:set_string("meta", minetest.serialize(minetest.get_meta(pointed_thing.under):to_table()))
481 meta:set_string("description", "Paint tool\nNode: " .. node.name)
482 minetest.chat_send_player(placer:get_player_name(),
483 "Paint tool will paint " .. node.name)
484 return itemstack
485 end,
486 on_place = function(itemstack, placer, pointed_thing)
487 if not pointed_thing or not pointed_thing.above or not placer then
488 return
490 local meta = itemstack:get_meta()
491 local node = minetest.deserialize(meta:get_string("node"))
492 local nmeta = minetest.deserialize(meta:get_string("meta"))
493 if not node then
494 minetest.chat_send_player(placer:get_player_name(),
495 S("Pick up a node first by left-clicking it with this tool"))
496 return
498 local name = placer:get_player_name()
499 local box = boxes.players_editing_boxes[name]
500 if not box and not minetest.check_player_privs(name, "server") then
501 return
504 if not box then
505 box = {
506 minp = { x = -32768, y = -32768, z = -32768 },
507 maxp = { x = 32768, y = 32768, z = 32768 },
511 local pos = pointed_thing.under
512 if pos.x > box.minp.x and pos.x < box.maxp.x and
513 pos.y > box.minp.y and pos.y < box.maxp.y and
514 pos.z > box.minp.z and pos.z < box.maxp.z then
515 minetest.set_node(pos, node)
517 if nmeta then
518 local pmeta = minetest.get_meta(pos)
519 pmeta:from_table(nmeta)
522 return itemstack
523 end,
525 frame.register("tools:paint")
527 minetest.register_tool("tools:grow", {
528 description = S("Growth tool"),
529 inventory_image = "grow_tool.png",
530 range = 6,
531 on_place = function(itemstack, placer, pointed_thing)
532 if not pointed_thing or not pointed_thing.under or not placer then
533 return
535 local name = placer:get_player_name()
536 local box = boxes.players_editing_boxes[name]
537 if not box then
538 if not minetest.check_player_privs(placer, "server") then
539 return
541 box = {
542 minp = { x = -32768, y = -32768, z = -32768 },
543 maxp = { x = 32768, y = 32768, z = 32768 },
546 local pos = pointed_thing.under
547 local nname = minetest.get_node(pos).name
548 if nname == "nodes:dirt" then
549 for x = math.max(box.minp.x + 1, pos.x - 2), math.min(box.maxp.x - 1, pos.x + 2) do
550 for y = math.max(box.minp.y + 1, pos.y), math.min(box.maxp.y - 1, pos.y) do
551 for z = math.max(box.minp.z + 1, pos.z - 2), math.min(box.maxp.z - 1, pos.z + 2) do
552 local ppos = {x = x, y = y, z = z}
553 if vector.distance(pos, ppos) <= 2.3 then
554 local node = minetest.get_node(ppos)
555 local above_node = minetest.get_node({x = x, y = y + 1, z = z})
556 if node.name == "nodes:dirt" and
557 minetest.registered_nodes[above_node.name] and
558 minetest.registered_nodes[above_node.name].walkable == false then
559 node.name = "nodes:dirt_with_grass"
560 minetest.set_node(ppos, node)
566 elseif nname == "nodes:grass" or nname == "nodes:dirt_with_grass" then
567 -- Grow grass and other things
568 for x = math.max(box.minp.x + 1, pos.x - 2), math.min(box.maxp.x - 1, pos.x + 2) do
569 for y = math.max(box.minp.y + 1, pos.y), math.min(box.maxp.y - 1, pos.y) do
570 for z = math.max(box.minp.z + 1, pos.z - 2), math.min(box.maxp.z - 1, pos.z + 2) do
571 local ppos = {x = x, y = y, z = z}
572 if vector.distance(pos, ppos) <= 2.3 then
573 local node = minetest.get_node(ppos)
574 local pos_above = {x = x, y = y + 1, z = z}
575 local above_node = minetest.get_node(pos_above)
576 if (node.name == "nodes:grass" or node.name == "nodes:dirt_with_grass") and
577 above_node.name == "air" and math.random() < 0.2 then
578 local plants = {
579 {"grass_1", 56},
580 {"grass_2", 56},
581 {"grass_3", 56},
582 {"grass_4", 56},
583 {"grass_5", 56},
584 {"grass_1", 56},
585 {"grass_2", 56},
586 {"grass_3", 56},
587 {"grass_4", 56},
588 {"grass_5", 56},
589 {"grass_1", 56},
590 {"grass_2", 56},
591 {"grass_3", 56},
592 {"grass_4", 56},
593 {"grass_5", 56},
594 {"grass_1", 56},
595 {"grass_2", 56},
596 {"grass_3", 56},
597 {"grass_4", 56},
598 {"grass_5", 56},
599 {"rose", 9},
600 {"dandelion", 9},
601 {"white_tulip", 9},
602 {"allium", 9},
603 {"orchid", 9},
604 {"daisy", 9},
605 {"houstonia", 9},
606 {"paeonia", 9},
608 local p = plants[math.random(1, 28)]
609 local nnode = {name = "nodes:" .. p[1], param2 = p[2]}
610 minetest.set_node(pos_above, nnode)
617 return itemstack
618 end,
620 frame.register("tools:grow")
622 local function dehash_vector(s)
623 return {
624 x = 256 * string.byte(s, 1) + string.byte(s, 2) - 32768,
625 y = 256 * string.byte(s, 3) + string.byte(s, 4) - 32768,
626 z = 256 * string.byte(s, 5) + string.byte(s, 6) - 32768,
630 local function particlestream(p, o, name)
631 local d = vector.length(o)
632 local c = 0
633 while c < d - 0.5 do
634 minetest.add_particle({
635 texture = "glowblock.png",
636 pos = vector.add(p, vector.multiply(o, c / d)),
637 velocity = vector.divide(o, d * 3),
638 expirationtime = 3,
639 size = 2,
640 glow = 14,
641 playername = name,
643 c = c + 0.5
647 minetest.register_tool("tools:reveal", {
648 description = S("Reveal tool").."\n"..
649 S("Reveal breakable nodes and placeholder nodes").."\n"..
650 S("Punch a node to see its connections"),
651 inventory_image = "reveal_tool.png",
652 on_use = function(itemstack, digger, pointed_thing)
653 if not digger then
654 return
656 local name = digger:get_player_name()
657 if not boxes.players_editing_boxes[name] and not minetest.check_player_privs(digger, "server") then
658 return
660 local box = boxes.players_editing_boxes[name]
662 if not box then
663 if not minetest.check_player_privs(digger, "server") then
664 return
666 box = {
667 minp = { x = -32768, y = -32768, z = -32768 },
668 maxp = { x = 32768, y = 32768, z = 32768 },
672 local off = {
673 { x = 0, y = 0, z = -9/16},
674 { x = 0, y = 0, z = 9/16},
675 { x = 0, y = -9/16, z = 0},
676 { x = 0, y = 9/16, z = 0},
677 { x = -9/16, y = 0, z = 0},
678 { x = 9/16, y = 0, z = 0},
681 -- if clicking a node, reveal mech connections
682 if pointed_thing.under then
683 local p = pointed_thing.under
684 local meta = minetest.get_meta(p)
685 local offsets = minetest.deserialize(meta:get_string("offsets")) or {}
686 for v, _ in pairs(offsets) do
687 local o = dehash_vector(v)
688 particlestream(p, o, name)
690 local roffsets = minetest.deserialize(meta:get_string("roffsets")) or {}
691 for v, _ in pairs(roffsets) do
692 local o = dehash_vector(v)
693 particlestream(vector.add(p, o), {x=-o.x, y=-o.y, z=-o.z}, name)
696 local dn = digger:get_player_name()
698 -- reveal callbacks, mech linkage info
699 local n = minetest.get_node(p)
700 if n and n.name and minetest.registered_nodes[n.name] then
701 local def = minetest.registered_nodes[n.name]
702 minetest.chat_send_player(dn, minetest.colorize("#ff8888",
703 "Detailed info for \"" .. def.description:gsub("\n.*", "") ..
704 "\" at " .. minetest.pos_to_string(p) .. ":"))
706 for so, _ in pairs(offsets) do
707 local offs = dehash_vector(so)
708 local npos = vector.add(p, offs)
709 local nname = minetest.get_node(npos).name
710 minetest.chat_send_player(dn, minetest.colorize("#44ff88",
711 "> triggers " .. nname .. " at " ..
712 minetest.pos_to_string(npos) .. " (offset is " ..
713 minetest.pos_to_string(offs) .. ")"))
716 for so, _ in pairs(roffsets) do
717 local offs = dehash_vector(so)
718 local npos = vector.add(p, offs)
719 local nname = minetest.get_node(npos).name
720 minetest.chat_send_player(dn, minetest.colorize("#8888ff",
721 "> triggered by " .. nname .. " at " ..
722 minetest.pos_to_string(npos) .. " (offset is " ..
723 minetest.pos_to_string(offs) .. ")"))
726 local cb = def.on_reveal
727 if cb then
728 cb(dn, p)
734 local limit = 32
735 local ppos = vector.floor(digger:get_pos())
736 local nodeslist = {}
737 local needle = {"group:axe", "group:shovel", "group:pickaxe", "group:hand", "nodes:placeholder"}
738 for d = 3, 6 do
739 if limit > 0 then
740 local poslist, _ = minetest.find_nodes_in_area(vector.subtract(ppos, d),
741 vector.add(ppos, d),
742 needle)
744 for _, v in pairs(poslist) do
745 if limit > 0 then
746 if v.x < box.maxp.x and v.y < box.maxp.y and v.z < box.maxp.z and
747 v.x > box.minp.x and v.y > box.minp.y and v.z > box.minp.z then
748 nodeslist[minetest.pos_to_string(v)] = 1
749 limit = limit - 1
756 for k, _ in pairs(nodeslist) do
757 local pos = minetest.string_to_pos(k)
758 local node = minetest.get_node(pos)
759 local groups = minetest.registered_nodes[node.name] and
760 minetest.registered_nodes[node.name].groups
762 local texture
763 if groups.axe then
764 texture = "axe.png"
765 elseif groups.shovel then
766 texture = "shovel.png"
767 elseif groups.pickaxe then
768 texture = "pickaxe.png"
769 elseif groups.hand then
770 texture = "wieldhand.png"
772 --FIXME leaves somehow don't work?
773 if texture and vector.distance(pos, digger:get_pos()) < 8 and
774 node.name ~= "nodes:snow_ledge" then
775 for _, v in ipairs(off) do
776 minetest.add_particle({
777 pos = vector.add(pos, v),
778 expirationtime = 8,
779 size = 3,
780 texture = texture,
781 playername = name,
782 glow = 13,
787 if node.name == "nodes:placeholder" then
788 local meta = minetest.get_meta(pos)
789 local placeable = meta:get_string("placeable")
790 if placeable ~= "" then
791 local nodelist = minetest.parse_json(placeable)
792 --FIXME just do the first placeholder, only
793 local n, _ = next(nodelist)
794 minetest.add_particle({
795 pos = pos,
796 expirationtime = 8,
797 size = 3,
798 texture = nodes.get_tiles(n),
799 glow = 14,
800 playername = name,
806 return itemstack
807 end,
809 frame.register("tools:reveal")