]> git.lizzy.rs Git - dragonfireclient.git/blob - builtin/game/item.lua
Builtin: Allow to revoke unknown privileges
[dragonfireclient.git] / builtin / game / item.lua
1 -- Minetest: builtin/item.lua
2
3 local builtin_shared = ...
4
5 local function copy_pointed_thing(pointed_thing)
6         return {
7                 type  = pointed_thing.type,
8                 above = vector.new(pointed_thing.above),
9                 under = vector.new(pointed_thing.under),
10                 ref   = pointed_thing.ref,
11         }
12 end
13
14 --
15 -- Item definition helpers
16 --
17
18 function core.inventorycube(img1, img2, img3)
19         img2 = img2 or img1
20         img3 = img3 or img1
21         return "[inventorycube"
22                         .. "{" .. img1:gsub("%^", "&")
23                         .. "{" .. img2:gsub("%^", "&")
24                         .. "{" .. img3:gsub("%^", "&")
25 end
26
27 function core.get_pointed_thing_position(pointed_thing, above)
28         if pointed_thing.type == "node" then
29                 if above then
30                         -- The position where a node would be placed
31                         return pointed_thing.above
32                 end
33                 -- The position where a node would be dug
34                 return pointed_thing.under
35         elseif pointed_thing.type == "object" then
36                 return pointed_thing.ref and pointed_thing.ref:get_pos()
37         end
38 end
39
40 function core.dir_to_facedir(dir, is6d)
41         --account for y if requested
42         if is6d and math.abs(dir.y) > math.abs(dir.x) and math.abs(dir.y) > math.abs(dir.z) then
43
44                 --from above
45                 if dir.y < 0 then
46                         if math.abs(dir.x) > math.abs(dir.z) then
47                                 if dir.x < 0 then
48                                         return 19
49                                 else
50                                         return 13
51                                 end
52                         else
53                                 if dir.z < 0 then
54                                         return 10
55                                 else
56                                         return 4
57                                 end
58                         end
59
60                 --from below
61                 else
62                         if math.abs(dir.x) > math.abs(dir.z) then
63                                 if dir.x < 0 then
64                                         return 15
65                                 else
66                                         return 17
67                                 end
68                         else
69                                 if dir.z < 0 then
70                                         return 6
71                                 else
72                                         return 8
73                                 end
74                         end
75                 end
76
77         --otherwise, place horizontally
78         elseif math.abs(dir.x) > math.abs(dir.z) then
79                 if dir.x < 0 then
80                         return 3
81                 else
82                         return 1
83                 end
84         else
85                 if dir.z < 0 then
86                         return 2
87                 else
88                         return 0
89                 end
90         end
91 end
92
93 -- Table of possible dirs
94 local facedir_to_dir = {
95         vector.new( 0,  0,  1),
96         vector.new( 1,  0,  0),
97         vector.new( 0,  0, -1),
98         vector.new(-1,  0,  0),
99         vector.new( 0, -1,  0),
100         vector.new( 0,  1,  0),
101 }
102 -- Mapping from facedir value to index in facedir_to_dir.
103 local facedir_to_dir_map = {
104         [0]=1, 2, 3, 4,
105         5, 2, 6, 4,
106         6, 2, 5, 4,
107         1, 5, 3, 6,
108         1, 6, 3, 5,
109         1, 4, 3, 2,
110 }
111 function core.facedir_to_dir(facedir)
112         return facedir_to_dir[facedir_to_dir_map[facedir % 32]]
113 end
114
115 function core.dir_to_wallmounted(dir)
116         if math.abs(dir.y) > math.max(math.abs(dir.x), math.abs(dir.z)) then
117                 if dir.y < 0 then
118                         return 1
119                 else
120                         return 0
121                 end
122         elseif math.abs(dir.x) > math.abs(dir.z) then
123                 if dir.x < 0 then
124                         return 3
125                 else
126                         return 2
127                 end
128         else
129                 if dir.z < 0 then
130                         return 5
131                 else
132                         return 4
133                 end
134         end
135 end
136
137 -- table of dirs in wallmounted order
138 local wallmounted_to_dir = {
139         [0] = vector.new( 0,  1,  0),
140         vector.new( 0, -1,  0),
141         vector.new( 1,  0,  0),
142         vector.new(-1,  0,  0),
143         vector.new( 0,  0,  1),
144         vector.new( 0,  0, -1),
145 }
146 function core.wallmounted_to_dir(wallmounted)
147         return wallmounted_to_dir[wallmounted % 8]
148 end
149
150 function core.dir_to_yaw(dir)
151         return -math.atan2(dir.x, dir.z)
152 end
153
154 function core.yaw_to_dir(yaw)
155         return vector.new(-math.sin(yaw), 0, math.cos(yaw))
156 end
157
158 function core.is_colored_paramtype(ptype)
159         return (ptype == "color") or (ptype == "colorfacedir") or
160                 (ptype == "colorwallmounted") or (ptype == "colordegrotate")
161 end
162
163 function core.strip_param2_color(param2, paramtype2)
164         if not core.is_colored_paramtype(paramtype2) then
165                 return nil
166         end
167         if paramtype2 == "colorfacedir" then
168                 param2 = math.floor(param2 / 32) * 32
169         elseif paramtype2 == "colorwallmounted" then
170                 param2 = math.floor(param2 / 8) * 8
171         elseif paramtype2 == "colordegrotate" then
172                 param2 = math.floor(param2 / 32) * 32
173         end
174         -- paramtype2 == "color" requires no modification.
175         return param2
176 end
177
178 local function has_all_groups(tbl, required_groups)
179         if type(required_groups) == "string" then
180                 return (tbl[required_groups] or 0) ~= 0
181         end
182         for _, group in ipairs(required_groups) do
183                 if (tbl[group] or 0) == 0 then
184                         return false
185                 end
186         end
187         return true
188 end
189
190 function core.get_node_drops(node, toolname)
191         -- Compatibility, if node is string
192         local nodename = node
193         local param2 = 0
194         -- New format, if node is table
195         if (type(node) == "table") then
196                 nodename = node.name
197                 param2 = node.param2
198         end
199         local def = core.registered_nodes[nodename]
200         local drop = def and def.drop
201         local ptype = def and def.paramtype2
202         -- get color, if there is color (otherwise nil)
203         local palette_index = core.strip_param2_color(param2, ptype)
204         if drop == nil then
205                 -- default drop
206                 if palette_index then
207                         local stack = ItemStack(nodename)
208                         stack:get_meta():set_int("palette_index", palette_index)
209                         return {stack:to_string()}
210                 end
211                 return {nodename}
212         elseif type(drop) == "string" then
213                 -- itemstring drop
214                 return drop ~= "" and {drop} or {}
215         elseif drop.items == nil then
216                 -- drop = {} to disable default drop
217                 return {}
218         end
219
220         -- Extended drop table
221         local got_items = {}
222         local got_count = 0
223         for _, item in ipairs(drop.items) do
224                 local good_rarity = true
225                 local good_tool = true
226                 if item.rarity ~= nil then
227                         good_rarity = item.rarity < 1 or math.random(item.rarity) == 1
228                 end
229                 if item.tools ~= nil or item.tool_groups ~= nil then
230                         good_tool = false
231                 end
232                 if item.tools ~= nil and toolname then
233                         for _, tool in ipairs(item.tools) do
234                                 if tool:sub(1, 1) == '~' then
235                                         good_tool = toolname:find(tool:sub(2)) ~= nil
236                                 else
237                                         good_tool = toolname == tool
238                                 end
239                                 if good_tool then
240                                         break
241                                 end
242                         end
243                 end
244                 if item.tool_groups ~= nil and toolname then
245                         local tooldef = core.registered_items[toolname]
246                         if tooldef ~= nil and type(tooldef.groups) == "table" then
247                                 if type(item.tool_groups) == "string" then
248                                         -- tool_groups can be a string which specifies the required group
249                                         good_tool = core.get_item_group(toolname, item.tool_groups) ~= 0
250                                 else
251                                         -- tool_groups can be a list of sufficient requirements.
252                                         -- i.e. if any item in the list can be satisfied then the tool is good
253                                         assert(type(item.tool_groups) == "table")
254                                         for _, required_groups in ipairs(item.tool_groups) do
255                                                 -- required_groups can be either a string (a single group),
256                                                 -- or an array of strings where all must be in tooldef.groups
257                                                 good_tool = has_all_groups(tooldef.groups, required_groups)
258                                                 if good_tool then
259                                                         break
260                                                 end
261                                         end
262                                 end
263                         end
264                 end
265                 if good_rarity and good_tool then
266                         got_count = got_count + 1
267                         for _, add_item in ipairs(item.items) do
268                                 -- add color, if necessary
269                                 if item.inherit_color and palette_index then
270                                         local stack = ItemStack(add_item)
271                                         stack:get_meta():set_int("palette_index", palette_index)
272                                         add_item = stack:to_string()
273                                 end
274                                 got_items[#got_items+1] = add_item
275                         end
276                         if drop.max_items ~= nil and got_count == drop.max_items then
277                                 break
278                         end
279                 end
280         end
281         return got_items
282 end
283
284 local function user_name(user)
285         return user and user:get_player_name() or ""
286 end
287
288 -- Returns a logging function. For empty names, does not log.
289 local function make_log(name)
290         return name ~= "" and core.log or function() end
291 end
292
293 function core.item_place_node(itemstack, placer, pointed_thing, param2,
294                 prevent_after_place)
295         local def = itemstack:get_definition()
296         if def.type ~= "node" or pointed_thing.type ~= "node" then
297                 return itemstack, nil
298         end
299
300         local under = pointed_thing.under
301         local oldnode_under = core.get_node_or_nil(under)
302         local above = pointed_thing.above
303         local oldnode_above = core.get_node_or_nil(above)
304         local playername = user_name(placer)
305         local log = make_log(playername)
306
307         if not oldnode_under or not oldnode_above then
308                 log("info", playername .. " tried to place"
309                         .. " node in unloaded position " .. core.pos_to_string(above))
310                 return itemstack, nil
311         end
312
313         local olddef_under = core.registered_nodes[oldnode_under.name]
314         olddef_under = olddef_under or core.nodedef_default
315         local olddef_above = core.registered_nodes[oldnode_above.name]
316         olddef_above = olddef_above or core.nodedef_default
317
318         if not olddef_above.buildable_to and not olddef_under.buildable_to then
319                 log("info", playername .. " tried to place"
320                         .. " node in invalid position " .. core.pos_to_string(above)
321                         .. ", replacing " .. oldnode_above.name)
322                 return itemstack, nil
323         end
324
325         -- Place above pointed node
326         local place_to = vector.new(above)
327
328         -- If node under is buildable_to, place into it instead (eg. snow)
329         if olddef_under.buildable_to then
330                 log("info", "node under is buildable to")
331                 place_to = vector.new(under)
332         end
333
334         if core.is_protected(place_to, playername) then
335                 log("action", playername
336                                 .. " tried to place " .. def.name
337                                 .. " at protected position "
338                                 .. core.pos_to_string(place_to))
339                 core.record_protection_violation(place_to, playername)
340                 return itemstack, nil
341         end
342
343         local oldnode = core.get_node(place_to)
344         local newnode = {name = def.name, param1 = 0, param2 = param2 or 0}
345
346         -- Calculate direction for wall mounted stuff like torches and signs
347         if def.place_param2 ~= nil then
348                 newnode.param2 = def.place_param2
349         elseif (def.paramtype2 == "wallmounted" or
350                         def.paramtype2 == "colorwallmounted") and not param2 then
351                 local dir = vector.subtract(under, above)
352                 newnode.param2 = core.dir_to_wallmounted(dir)
353         -- Calculate the direction for furnaces and chests and stuff
354         elseif (def.paramtype2 == "facedir" or
355                         def.paramtype2 == "colorfacedir") and not param2 then
356                 local placer_pos = placer and placer:get_pos()
357                 if placer_pos then
358                         local dir = vector.subtract(above, placer_pos)
359                         newnode.param2 = core.dir_to_facedir(dir)
360                         log("info", "facedir: " .. newnode.param2)
361                 end
362         end
363
364         local metatable = itemstack:get_meta():to_table().fields
365
366         -- Transfer color information
367         if metatable.palette_index and not def.place_param2 then
368                 local color_divisor = nil
369                 if def.paramtype2 == "color" then
370                         color_divisor = 1
371                 elseif def.paramtype2 == "colorwallmounted" then
372                         color_divisor = 8
373                 elseif def.paramtype2 == "colorfacedir" then
374                         color_divisor = 32
375                 elseif def.paramtype2 == "colordegrotate" then
376                         color_divisor = 32
377                 end
378                 if color_divisor then
379                         local color = math.floor(metatable.palette_index / color_divisor)
380                         local other = newnode.param2 % color_divisor
381                         newnode.param2 = color * color_divisor + other
382                 end
383         end
384
385         -- Check if the node is attached and if it can be placed there
386         if core.get_item_group(def.name, "attached_node") ~= 0 and
387                 not builtin_shared.check_attached_node(place_to, newnode) then
388                 log("action", "attached node " .. def.name ..
389                         " can not be placed at " .. core.pos_to_string(place_to))
390                 return itemstack, nil
391         end
392
393         log("action", playername .. " places node "
394                 .. def.name .. " at " .. core.pos_to_string(place_to))
395
396         -- Add node and update
397         core.add_node(place_to, newnode)
398
399         -- Play sound if it was done by a player
400         if playername ~= "" and def.sounds and def.sounds.place then
401                 core.sound_play(def.sounds.place, {
402                         pos = place_to,
403                         exclude_player = playername,
404                 }, true)
405         end
406
407         local take_item = true
408
409         -- Run callback
410         if def.after_place_node and not prevent_after_place then
411                 -- Deepcopy place_to and pointed_thing because callback can modify it
412                 local place_to_copy = vector.new(place_to)
413                 local pointed_thing_copy = copy_pointed_thing(pointed_thing)
414                 if def.after_place_node(place_to_copy, placer, itemstack,
415                                 pointed_thing_copy) then
416                         take_item = false
417                 end
418         end
419
420         -- Run script hook
421         for _, callback in ipairs(core.registered_on_placenodes) do
422                 -- Deepcopy pos, node and pointed_thing because callback can modify them
423                 local place_to_copy = vector.new(place_to)
424                 local newnode_copy = {name=newnode.name, param1=newnode.param1, param2=newnode.param2}
425                 local oldnode_copy = {name=oldnode.name, param1=oldnode.param1, param2=oldnode.param2}
426                 local pointed_thing_copy = copy_pointed_thing(pointed_thing)
427                 if callback(place_to_copy, newnode_copy, placer, oldnode_copy, itemstack, pointed_thing_copy) then
428                         take_item = false
429                 end
430         end
431
432         if take_item then
433                 itemstack:take_item()
434         end
435         return itemstack, place_to
436 end
437
438 -- deprecated, item_place does not call this
439 function core.item_place_object(itemstack, placer, pointed_thing)
440         local pos = core.get_pointed_thing_position(pointed_thing, true)
441         if pos ~= nil then
442                 local item = itemstack:take_item()
443                 core.add_item(pos, item)
444         end
445         return itemstack
446 end
447
448 function core.item_place(itemstack, placer, pointed_thing, param2)
449         -- Call on_rightclick if the pointed node defines it
450         if pointed_thing.type == "node" and placer and
451                         not placer:get_player_control().sneak then
452                 local n = core.get_node(pointed_thing.under)
453                 local nn = n.name
454                 if core.registered_nodes[nn] and core.registered_nodes[nn].on_rightclick then
455                         return core.registered_nodes[nn].on_rightclick(pointed_thing.under, n,
456                                         placer, itemstack, pointed_thing) or itemstack, nil
457                 end
458         end
459
460         -- Place if node, otherwise do nothing
461         if itemstack:get_definition().type == "node" then
462                 return core.item_place_node(itemstack, placer, pointed_thing, param2)
463         end
464         return itemstack, nil
465 end
466
467 function core.item_secondary_use(itemstack, placer)
468         return itemstack
469 end
470
471 function core.item_drop(itemstack, dropper, pos)
472         local dropper_is_player = dropper and dropper:is_player()
473         local p = table.copy(pos)
474         local cnt = itemstack:get_count()
475         if dropper_is_player then
476                 p.y = p.y + 1.2
477         end
478         local item = itemstack:take_item(cnt)
479         local obj = core.add_item(p, item)
480         if obj then
481                 if dropper_is_player then
482                         local dir = dropper:get_look_dir()
483                         dir.x = dir.x * 2.9
484                         dir.y = dir.y * 2.9 + 2
485                         dir.z = dir.z * 2.9
486                         obj:set_velocity(dir)
487                         obj:get_luaentity().dropped_by = dropper:get_player_name()
488                 end
489                 return itemstack
490         end
491         -- If we reach this, adding the object to the
492         -- environment failed
493 end
494
495 function core.do_item_eat(hp_change, replace_with_item, itemstack, user, pointed_thing)
496         for _, callback in pairs(core.registered_on_item_eats) do
497                 local result = callback(hp_change, replace_with_item, itemstack, user, pointed_thing)
498                 if result then
499                         return result
500                 end
501         end
502         -- read definition before potentially emptying the stack
503         local def = itemstack:get_definition()
504         if itemstack:take_item():is_empty() then
505                 return itemstack
506         end
507
508         if def and def.sound and def.sound.eat then
509                 core.sound_play(def.sound.eat, {
510                         pos = user:get_pos(),
511                         max_hear_distance = 16
512                 }, true)
513         end
514
515         -- Changing hp might kill the player causing mods to do who-knows-what to the
516         -- inventory, so do this before set_hp().
517         if replace_with_item then
518                 if itemstack:is_empty() then
519                         itemstack:add_item(replace_with_item)
520                 else
521                         local inv = user:get_inventory()
522                         -- Check if inv is null, since non-players don't have one
523                         if inv and inv:room_for_item("main", {name=replace_with_item}) then
524                                 inv:add_item("main", replace_with_item)
525                         else
526                                 local pos = user:get_pos()
527                                 pos.y = math.floor(pos.y + 0.5)
528                                 core.add_item(pos, replace_with_item)
529                         end
530                 end
531         end
532         user:set_wielded_item(itemstack)
533
534         user:set_hp(user:get_hp() + hp_change)
535
536         return nil -- don't overwrite wield item a second time
537 end
538
539 function core.item_eat(hp_change, replace_with_item)
540         return function(itemstack, user, pointed_thing)  -- closure
541                 if user then
542                         return core.do_item_eat(hp_change, replace_with_item, itemstack, user, pointed_thing)
543                 end
544         end
545 end
546
547 function core.node_punch(pos, node, puncher, pointed_thing)
548         -- Run script hook
549         for _, callback in ipairs(core.registered_on_punchnodes) do
550                 -- Copy pos and node because callback can modify them
551                 local pos_copy = vector.new(pos)
552                 local node_copy = {name=node.name, param1=node.param1, param2=node.param2}
553                 local pointed_thing_copy = pointed_thing and copy_pointed_thing(pointed_thing) or nil
554                 callback(pos_copy, node_copy, puncher, pointed_thing_copy)
555         end
556 end
557
558 function core.handle_node_drops(pos, drops, digger)
559         -- Add dropped items to object's inventory
560         local inv = digger and digger:get_inventory()
561         local give_item
562         if inv then
563                 give_item = function(item)
564                         return inv:add_item("main", item)
565                 end
566         else
567                 give_item = function(item)
568                         -- itemstring to ItemStack for left:is_empty()
569                         return ItemStack(item)
570                 end
571         end
572
573         for _, dropped_item in pairs(drops) do
574                 local left = give_item(dropped_item)
575                 if not left:is_empty() then
576                         local p = vector.offset(pos,
577                                 math.random()/2-0.25,
578                                 math.random()/2-0.25,
579                                 math.random()/2-0.25
580                         )
581                         core.add_item(p, left)
582                 end
583         end
584 end
585
586 function core.node_dig(pos, node, digger)
587         local diggername = user_name(digger)
588         local log = make_log(diggername)
589         local def = core.registered_nodes[node.name]
590         -- Copy pos because the callback could modify it
591         if def and (not def.diggable or
592                         (def.can_dig and not def.can_dig(vector.new(pos), digger))) then
593                 log("info", diggername .. " tried to dig "
594                         .. node.name .. " which is not diggable "
595                         .. core.pos_to_string(pos))
596                 return false
597         end
598
599         if core.is_protected(pos, diggername) then
600                 log("action", diggername
601                                 .. " tried to dig " .. node.name
602                                 .. " at protected position "
603                                 .. core.pos_to_string(pos))
604                 core.record_protection_violation(pos, diggername)
605                 return false
606         end
607
608         log('action', diggername .. " digs "
609                 .. node.name .. " at " .. core.pos_to_string(pos))
610
611         local wielded = digger and digger:get_wielded_item()
612         local drops = core.get_node_drops(node, wielded and wielded:get_name())
613
614         if wielded then
615                 local wdef = wielded:get_definition()
616                 local tp = wielded:get_tool_capabilities()
617                 local dp = core.get_dig_params(def and def.groups, tp, wielded:get_wear())
618                 if wdef and wdef.after_use then
619                         wielded = wdef.after_use(wielded, digger, node, dp) or wielded
620                 else
621                         -- Wear out tool
622                         if not core.is_creative_enabled(diggername) then
623                                 wielded:add_wear(dp.wear)
624                                 if wielded:get_count() == 0 and wdef.sound and wdef.sound.breaks then
625                                         core.sound_play(wdef.sound.breaks, {
626                                                 pos = pos,
627                                                 gain = 0.5
628                                         }, true)
629                                 end
630                         end
631                 end
632                 digger:set_wielded_item(wielded)
633         end
634
635         -- Check to see if metadata should be preserved.
636         if def and def.preserve_metadata then
637                 local oldmeta = core.get_meta(pos):to_table().fields
638                 -- Copy pos and node because the callback can modify them.
639                 local pos_copy = vector.new(pos)
640                 local node_copy = {name=node.name, param1=node.param1, param2=node.param2}
641                 local drop_stacks = {}
642                 for k, v in pairs(drops) do
643                         drop_stacks[k] = ItemStack(v)
644                 end
645                 drops = drop_stacks
646                 def.preserve_metadata(pos_copy, node_copy, oldmeta, drops)
647         end
648
649         -- Handle drops
650         core.handle_node_drops(pos, drops, digger)
651
652         local oldmetadata = nil
653         if def and def.after_dig_node then
654                 oldmetadata = core.get_meta(pos):to_table()
655         end
656
657         -- Remove node and update
658         core.remove_node(pos)
659
660         -- Play sound if it was done by a player
661         if diggername ~= "" and def and def.sounds and def.sounds.dug then
662                 core.sound_play(def.sounds.dug, {
663                         pos = pos,
664                         exclude_player = diggername,
665                 }, true)
666         end
667
668         -- Run callback
669         if def and def.after_dig_node then
670                 -- Copy pos and node because callback can modify them
671                 local pos_copy = vector.new(pos)
672                 local node_copy = {name=node.name, param1=node.param1, param2=node.param2}
673                 def.after_dig_node(pos_copy, node_copy, oldmetadata, digger)
674         end
675
676         -- Run script hook
677         for _, callback in ipairs(core.registered_on_dignodes) do
678                 local origin = core.callback_origins[callback]
679                 if origin then
680                         core.set_last_run_mod(origin.mod)
681                 end
682
683                 -- Copy pos and node because callback can modify them
684                 local pos_copy = vector.new(pos)
685                 local node_copy = {name=node.name, param1=node.param1, param2=node.param2}
686                 callback(pos_copy, node_copy, digger)
687         end
688
689         return true
690 end
691
692 function core.itemstring_with_palette(item, palette_index)
693         local stack = ItemStack(item) -- convert to ItemStack
694         stack:get_meta():set_int("palette_index", palette_index)
695         return stack:to_string()
696 end
697
698 function core.itemstring_with_color(item, colorstring)
699         local stack = ItemStack(item) -- convert to ItemStack
700         stack:get_meta():set_string("color", colorstring)
701         return stack:to_string()
702 end
703
704 -- This is used to allow mods to redefine core.item_place and so on
705 -- NOTE: This is not the preferred way. Preferred way is to provide enough
706 --       callbacks to not require redefining global functions. -celeron55
707 local function redef_wrapper(table, name)
708         return function(...)
709                 return table[name](...)
710         end
711 end
712
713 --
714 -- Item definition defaults
715 --
716
717 local default_stack_max = tonumber(core.settings:get("default_stack_max")) or 99
718
719 core.nodedef_default = {
720         -- Item properties
721         type="node",
722         -- name intentionally not defined here
723         description = "",
724         groups = {},
725         inventory_image = "",
726         wield_image = "",
727         wield_scale = vector.new(1, 1, 1),
728         stack_max = default_stack_max,
729         usable = false,
730         liquids_pointable = false,
731         tool_capabilities = nil,
732         node_placement_prediction = nil,
733
734         -- Interaction callbacks
735         on_place = redef_wrapper(core, 'item_place'), -- core.item_place
736         on_drop = redef_wrapper(core, 'item_drop'), -- core.item_drop
737         on_use = nil,
738         can_dig = nil,
739
740         on_punch = redef_wrapper(core, 'node_punch'), -- core.node_punch
741         on_rightclick = nil,
742         on_dig = redef_wrapper(core, 'node_dig'), -- core.node_dig
743
744         on_receive_fields = nil,
745
746         -- Node properties
747         drawtype = "normal",
748         visual_scale = 1.0,
749         -- Don't define these because otherwise the old tile_images and
750         -- special_materials wouldn't be read
751         --tiles ={""},
752         --special_tiles = {
753         --      {name="", backface_culling=true},
754         --      {name="", backface_culling=true},
755         --},
756         post_effect_color = {a=0, r=0, g=0, b=0},
757         paramtype = "none",
758         paramtype2 = "none",
759         is_ground_content = true,
760         sunlight_propagates = false,
761         walkable = true,
762         pointable = true,
763         diggable = true,
764         climbable = false,
765         buildable_to = false,
766         floodable = false,
767         liquidtype = "none",
768         liquid_alternative_flowing = "",
769         liquid_alternative_source = "",
770         liquid_viscosity = 0,
771         drowning = 0,
772         light_source = 0,
773         damage_per_second = 0,
774         selection_box = {type="regular"},
775         legacy_facedir_simple = false,
776         legacy_wallmounted = false,
777 }
778
779 core.craftitemdef_default = {
780         type="craft",
781         -- name intentionally not defined here
782         description = "",
783         groups = {},
784         inventory_image = "",
785         wield_image = "",
786         wield_scale = vector.new(1, 1, 1),
787         stack_max = default_stack_max,
788         liquids_pointable = false,
789         tool_capabilities = nil,
790
791         -- Interaction callbacks
792         on_place = redef_wrapper(core, 'item_place'), -- core.item_place
793         on_drop = redef_wrapper(core, 'item_drop'), -- core.item_drop
794         on_secondary_use = redef_wrapper(core, 'item_secondary_use'),
795         on_use = nil,
796 }
797
798 core.tooldef_default = {
799         type="tool",
800         -- name intentionally not defined here
801         description = "",
802         groups = {},
803         inventory_image = "",
804         wield_image = "",
805         wield_scale = vector.new(1, 1, 1),
806         stack_max = 1,
807         liquids_pointable = false,
808         tool_capabilities = nil,
809
810         -- Interaction callbacks
811         on_place = redef_wrapper(core, 'item_place'), -- core.item_place
812         on_secondary_use = redef_wrapper(core, 'item_secondary_use'),
813         on_drop = redef_wrapper(core, 'item_drop'), -- core.item_drop
814         on_use = nil,
815 }
816
817 core.noneitemdef_default = {  -- This is used for the hand and unknown items
818         type="none",
819         -- name intentionally not defined here
820         description = "",
821         groups = {},
822         inventory_image = "",
823         wield_image = "",
824         wield_scale = vector.new(1, 1, 1),
825         stack_max = default_stack_max,
826         liquids_pointable = false,
827         tool_capabilities = nil,
828
829         -- Interaction callbacks
830         on_place = redef_wrapper(core, 'item_place'),
831         on_secondary_use = redef_wrapper(core, 'item_secondary_use'),
832         on_drop = nil,
833         on_use = nil,
834 }