1 -- mods/default/functions.lua
7 function default.node_sound_defaults(table)
9 table.footstep = table.footstep or
10 {name = "", gain = 1.0}
11 table.dug = table.dug or
12 {name = "default_dug_node", gain = 0.25}
13 table.place = table.place or
14 {name = "default_place_node_hard", gain = 1.0}
18 function default.node_sound_stone_defaults(table)
20 table.footstep = table.footstep or
21 {name = "default_hard_footstep", gain = 0.5}
22 table.dug = table.dug or
23 {name = "default_hard_footstep", gain = 1.0}
24 default.node_sound_defaults(table)
28 function default.node_sound_dirt_defaults(table)
30 table.footstep = table.footstep or
31 {name = "default_dirt_footstep", gain = 1.0}
32 table.dug = table.dug or
33 {name = "default_dirt_footstep", gain = 1.5}
34 table.place = table.place or
35 {name = "default_place_node", gain = 1.0}
36 default.node_sound_defaults(table)
40 function default.node_sound_sand_defaults(table)
42 table.footstep = table.footstep or
43 {name = "default_sand_footstep", gain = 0.12}
44 table.dug = table.dug or
45 {name = "default_sand_footstep", gain = 0.24}
46 table.place = table.place or
47 {name = "default_place_node", gain = 1.0}
48 default.node_sound_defaults(table)
52 function default.node_sound_gravel_defaults(table)
54 table.footstep = table.footstep or
55 {name = "default_gravel_footstep", gain = 0.5}
56 table.dug = table.dug or
57 {name = "default_gravel_footstep", gain = 1.0}
58 table.place = table.place or
59 {name = "default_place_node", gain = 1.0}
60 default.node_sound_defaults(table)
64 function default.node_sound_wood_defaults(table)
66 table.footstep = table.footstep or
67 {name = "default_wood_footstep", gain = 0.5}
68 table.dug = table.dug or
69 {name = "default_wood_footstep", gain = 1.0}
70 default.node_sound_defaults(table)
74 function default.node_sound_leaves_defaults(table)
76 table.footstep = table.footstep or
77 {name = "default_grass_footstep", gain = 0.35}
78 table.dug = table.dug or
79 {name = "default_grass_footstep", gain = 0.7}
80 table.dig = table.dig or
81 {name = "default_dig_crumbly", gain = 0.4}
82 table.place = table.place or
83 {name = "default_place_node", gain = 1.0}
84 default.node_sound_defaults(table)
88 function default.node_sound_glass_defaults(table)
90 table.footstep = table.footstep or
91 {name = "default_glass_footstep", gain = 0.5}
92 table.dug = table.dug or
93 {name = "default_break_glass", gain = 1.0}
94 default.node_sound_defaults(table)
103 default.cool_lava = function(pos, node)
104 if node.name == "default:lava_source" then
105 minetest.set_node(pos, {name = "default:obsidian"})
107 minetest.set_node(pos, {name = "default:stone"})
109 minetest.sound_play("default_cool_lava",
110 {pos = pos, max_hear_distance = 16, gain = 0.25})
113 minetest.register_abm({
114 nodenames = {"default:lava_source", "default:lava_flowing"},
115 neighbors = {"group:water"},
119 action = function(...)
120 default.cool_lava(...)
126 -- optimized helper to put all items in an inventory into a drops list
128 function default.get_inventory_drops(pos, inventory, drops)
129 local inv = minetest.get_meta(pos):get_inventory()
131 for i = 1, inv:get_size(inventory) do
132 local stack = inv:get_stack(inventory, i)
133 if stack:get_count() > 0 then
134 drops[n+1] = stack:to_table()
141 -- Papyrus and cactus growing
144 -- wrapping the functions in abm action is necessary to make overriding them possible
146 function default.grow_cactus(pos, node)
147 if node.param2 >= 4 then
151 if minetest.get_item_group(minetest.get_node(pos).name, "sand") == 0 then
156 while node.name == "default:cactus" and height < 4 do
159 node = minetest.get_node(pos)
161 if height == 4 or node.name ~= "air" then
164 minetest.set_node(pos, {name = "default:cactus"})
168 function default.grow_papyrus(pos, node)
170 local name = minetest.get_node(pos).name
171 if name ~= "default:dirt_with_grass" and name ~= "default:dirt" then
174 if not minetest.find_node_near(pos, 3, {"group:water"}) then
179 while node.name == "default:papyrus" and height < 4 do
182 node = minetest.get_node(pos)
184 if height == 4 or node.name ~= "air" then
187 minetest.set_node(pos, {name = "default:papyrus"})
191 minetest.register_abm({
192 nodenames = {"default:cactus"},
193 neighbors = {"group:sand"},
196 action = function(...)
197 default.grow_cactus(...)
201 minetest.register_abm({
202 nodenames = {"default:papyrus"},
203 neighbors = {"default:dirt", "default:dirt_with_grass"},
206 action = function(...)
207 default.grow_papyrus(...)
216 function default.dig_up(pos, node, digger)
217 if digger == nil then return end
218 local np = {x = pos.x, y = pos.y + 1, z = pos.z}
219 local nn = minetest.get_node(np)
220 if nn.name == node.name then
221 minetest.node_dig(np, nn, digger)
227 -- Fence registration helper
229 function default.register_fence(name, def)
230 minetest.register_craft({
231 output = name .. " 4",
233 { def.material, 'group:stick', def.material },
234 { def.material, 'group:stick', def.material },
238 local fence_texture = "default_fence_overlay.png^" .. def.texture ..
239 "^default_fence_overlay.png^[makealpha:255,126,126"
240 -- Allow almost everything to be overridden
241 local default_fields = {
243 drawtype = "nodebox",
246 fixed = {{-1/8, -1/2, -1/8, 1/8, 1/2, 1/8}},
249 connect_front = {{-1/16,3/16,-1/2,1/16,5/16,-1/8},
250 {-1/16,-5/16,-1/2,1/16,-3/16,-1/8}},
251 connect_left = {{-1/2,3/16,-1/16,-1/8,5/16,1/16},
252 {-1/2,-5/16,-1/16,-1/8,-3/16,1/16}},
253 connect_back = {{-1/16,3/16,1/8,1/16,5/16,1/2},
254 {-1/16,-5/16,1/8,1/16,-3/16,1/2}},
255 connect_right = {{1/8,3/16,-1/16,1/2,5/16,1/16},
256 {1/8,-5/16,-1/16,1/2,-3/16,1/16}},
258 connects_to = {"group:fence", "group:wood", "group:tree"},
259 inventory_image = fence_texture,
260 wield_image = fence_texture,
261 tiles = {def.texture},
262 sunlight_propagates = true,
263 is_ground_content = false,
266 for k, v in pairs(default_fields) do
272 -- Always add to the fence group, even if no group provided
278 minetest.register_node(name, def)
286 default.leafdecay_trunk_cache = {}
287 default.leafdecay_enable_cache = true
288 -- Spread the load of finding trunks
289 default.leafdecay_trunk_find_allow_accumulator = 0
291 minetest.register_globalstep(function(dtime)
292 local finds_per_second = 5000
293 default.leafdecay_trunk_find_allow_accumulator =
294 math.floor(dtime * finds_per_second)
297 default.after_place_leaves = function(pos, placer, itemstack, pointed_thing)
298 if placer and not placer:get_player_control().sneak then
299 local node = minetest.get_node(pos)
301 minetest.set_node(pos, node)
305 minetest.register_abm({
306 nodenames = {"group:leafdecay"},
307 neighbors = {"air", "group:liquid"},
308 -- A low interval and a high inverse chance spreads the load
312 action = function(p0, node, _, _)
313 --print("leafdecay ABM at "..p0.x..", "..p0.y..", "..p0.z..")")
314 local do_preserve = false
315 local d = minetest.registered_nodes[node.name].groups.leafdecay
316 if not d or d == 0 then
317 --print("not groups.leafdecay")
320 local n0 = minetest.get_node(p0)
321 if n0.param2 ~= 0 then
322 --print("param2 ~= 0")
326 if default.leafdecay_enable_cache then
327 p0_hash = minetest.hash_node_position(p0)
328 local trunkp = default.leafdecay_trunk_cache[p0_hash]
330 local n = minetest.get_node(trunkp)
331 local reg = minetest.registered_nodes[n.name]
332 -- Assume ignore is a trunk, to make the thing
333 -- work at the border of the active area
334 if n.name == "ignore" or (reg and reg.groups.tree and
335 reg.groups.tree ~= 0) then
336 --print("cached trunk still exists")
339 --print("cached trunk is invalid")
341 table.remove(default.leafdecay_trunk_cache, p0_hash)
344 if default.leafdecay_trunk_find_allow_accumulator <= 0 then
347 default.leafdecay_trunk_find_allow_accumulator =
348 default.leafdecay_trunk_find_allow_accumulator - 1
349 -- Assume ignore is a trunk, to make the thing
350 -- work at the border of the active area
351 local p1 = minetest.find_node_near(p0, d, {"ignore", "group:tree"})
354 if default.leafdecay_enable_cache then
355 --print("caching trunk")
357 default.leafdecay_trunk_cache[p0_hash] = p1
360 if not do_preserve then
361 -- Drop stuff other than the node itself
362 local itemstacks = minetest.get_node_drops(n0.name)
363 for _, itemname in ipairs(itemstacks) do
364 if minetest.get_item_group(n0.name, "leafdecay_drop") ~= 0 or
365 itemname ~= n0.name then
367 x = p0.x - 0.5 + math.random(),
368 y = p0.y - 0.5 + math.random(),
369 z = p0.z - 0.5 + math.random(),
371 minetest.add_item(p_drop, itemname)
375 minetest.remove_node(p0)
383 -- Convert dirt to something that fits the environment
386 minetest.register_abm({
387 nodenames = {"default:dirt"},
389 "default:dirt_with_grass",
390 "default:dirt_with_dry_grass",
391 "default:dirt_with_snow",
399 action = function(pos, node)
400 -- Most likely case, half the time it's too dark for this.
401 local above = {x = pos.x, y = pos.y + 1, z = pos.z}
402 if (minetest.get_node_light(above) or 0) < 13 then
406 -- Look for likely neighbors.
407 local p2 = minetest.find_node_near(pos, 1, {"default:dirt_with_grass",
408 "default:dirt_with_dry_grass", "default:dirt_with_snow"})
410 -- But the node needs to be under air in this case.
411 local n2 = minetest.get_node(above)
412 if n2 and n2.name == "air" then
413 local n3 = minetest.get_node(p2)
414 minetest.set_node(pos, {name = n3.name})
420 local n2 = minetest.get_node(above)
426 -- Snow check is cheapest, so comes first.
427 if name == "default:snow" then
428 minetest.set_node(pos, {name = "default:dirt_with_snow"})
429 -- Most likely case first.
430 elseif minetest.get_item_group(name, "grass") ~= 0 then
431 minetest.set_node(pos, {name = "default:dirt_with_grass"})
432 elseif minetest.get_item_group(name, "dry_grass") ~= 0 then
433 minetest.set_node(pos, {name = "default:dirt_with_dry_grass"})
439 -- Grass and dry grass removed in darkness
442 minetest.register_abm({
444 "default:dirt_with_grass",
445 "default:dirt_with_dry_grass",
446 "default:dirt_with_snow",
451 action = function(pos, node)
452 local above = {x = pos.x, y = pos.y + 1, z = pos.z}
453 local name = minetest.get_node(above).name
454 local nodedef = minetest.registered_nodes[name]
455 if name ~= "ignore" and nodedef and not ((nodedef.sunlight_propagates or
456 nodedef.paramtype == "light") and
457 nodedef.liquidtype == "none") then
458 minetest.set_node(pos, {name = "default:dirt"})
465 -- Moss growth on cobble near water
468 minetest.register_abm({
469 nodenames = {"default:cobble"},
470 neighbors = {"group:water"},
474 action = function(pos, node)
475 minetest.set_node(pos, {name = "default:mossycobble"})