0137d9126737b08cf6306bc12449aa7e3d22d7fd
[oweals/minetest_game.git] / mods / default / functions.lua
1 -- mods/default/functions.lua
2
3 --
4 -- Sounds
5 --
6
7 function default.node_sound_defaults(table)
8         table = table or {}
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}
15         return table
16 end
17
18 function default.node_sound_stone_defaults(table)
19         table = table or {}
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)
25         return table
26 end
27
28 function default.node_sound_dirt_defaults(table)
29         table = table or {}
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)
37         return table
38 end
39
40 function default.node_sound_sand_defaults(table)
41         table = table or {}
42         table.footstep = table.footstep or
43                         {name = "default_sand_footstep", gain = 0.2}
44         table.dug = table.dug or
45                         {name = "default_sand_footstep", gain = 0.4}
46         table.place = table.place or
47                         {name = "default_place_node", gain = 1.0}
48         default.node_sound_defaults(table)
49         return table
50 end
51
52 function default.node_sound_wood_defaults(table)
53         table = table or {}
54         table.footstep = table.footstep or
55                         {name = "default_wood_footstep", gain = 0.5}
56         table.dug = table.dug or
57                         {name = "default_wood_footstep", gain = 1.0}
58         default.node_sound_defaults(table)
59         return table
60 end
61
62 function default.node_sound_leaves_defaults(table)
63         table = table or {}
64         table.footstep = table.footstep or
65                         {name = "default_grass_footstep", gain = 0.35}
66         table.dug = table.dug or
67                         {name = "default_grass_footstep", gain = 0.7}
68         table.dig = table.dig or
69                         {name = "default_dig_crumbly", gain = 0.4}
70         table.place = table.place or
71                         {name = "default_place_node", gain = 1.0}
72         default.node_sound_defaults(table)
73         return table
74 end
75
76 function default.node_sound_glass_defaults(table)
77         table = table or {}
78         table.footstep = table.footstep or
79                         {name = "default_glass_footstep", gain = 0.5}
80         table.dug = table.dug or
81                         {name = "default_break_glass", gain = 1.0}
82         default.node_sound_defaults(table)
83         return table
84 end
85
86
87 --
88 -- Lavacooling
89 --
90
91 default.cool_lava_source = function(pos)
92         minetest.set_node(pos, {name = "default:obsidian"})
93         minetest.sound_play("default_cool_lava",
94                 {pos = pos, max_hear_distance = 16, gain = 0.25})
95 end
96
97 default.cool_lava_flowing = function(pos)
98         minetest.set_node(pos, {name = "default:stone"})
99         minetest.sound_play("default_cool_lava",
100                 {pos = pos, max_hear_distance = 16, gain = 0.25})
101 end
102
103 minetest.register_abm({
104         nodenames = {"default:lava_flowing"},
105         neighbors = {"group:water"},
106         interval = 1,
107         chance = 2,
108         catch_up = false,
109         action = function(...)
110                 default.cool_lava_flowing(...)
111         end,
112 })
113
114 minetest.register_abm({
115         nodenames = {"default:lava_source"},
116         neighbors = {"group:water"},
117         interval = 1,
118         chance = 2,
119         catch_up = false,
120         action = function(...)
121                 default.cool_lava_source(...)
122         end,
123 })
124
125
126 --
127 -- Papyrus and cactus growing
128 --
129
130 -- wrapping the functions in abm action is necessary to make overriding them possible
131
132 function default.grow_cactus(pos, node)
133         if node.param2 >= 4 then
134                 return
135         end
136         pos.y = pos.y - 1
137         if minetest.get_item_group(minetest.get_node(pos).name, "sand") == 0 then
138                 return
139         end
140         pos.y = pos.y + 1
141         local height = 0
142         while node.name == "default:cactus" and height < 4 do
143                 height = height + 1
144                 pos.y = pos.y + 1
145                 node = minetest.get_node(pos)
146         end
147         if height == 4 or node.name ~= "air" then
148                 return
149         end
150         minetest.set_node(pos, {name = "default:cactus"})
151         return true
152 end
153
154 function default.grow_papyrus(pos, node)
155         pos.y = pos.y - 1
156         local name = minetest.get_node(pos).name
157         if name ~= "default:dirt_with_grass" and name ~= "default:dirt" then
158                 return
159         end
160         if not minetest.find_node_near(pos, 3, {"group:water"}) then
161                 return
162         end
163         pos.y = pos.y + 1
164         local height = 0
165         while node.name == "default:papyrus" and height < 4 do
166                 height = height + 1
167                 pos.y = pos.y + 1
168                 node = minetest.get_node(pos)
169         end
170         if height == 4 or node.name ~= "air" then
171                 return
172         end
173         minetest.set_node(pos, {name = "default:papyrus"})
174         return true
175 end
176
177 minetest.register_abm({
178         nodenames = {"default:cactus"},
179         neighbors = {"group:sand"},
180         interval = 50,
181         chance = 20,
182         action = function(...)
183                 default.grow_cactus(...)
184         end
185 })
186
187 minetest.register_abm({
188         nodenames = {"default:papyrus"},
189         neighbors = {"default:dirt", "default:dirt_with_grass", "default:sand"},
190         interval = 50,
191         chance = 20,
192         action = function(...)
193                 default.grow_papyrus(...)
194         end
195 })
196
197
198 --
199 -- dig upwards
200 --
201
202 function default.dig_up(pos, node, digger)
203         if digger == nil then return end
204         local np = {x = pos.x, y = pos.y + 1, z = pos.z}
205         local nn = minetest.get_node(np)
206         if nn.name == node.name then
207                 minetest.node_dig(np, nn, digger)
208         end
209 end
210
211
212 --
213 -- Fence registration helper
214 --
215 function default.register_fence(name, def)
216         minetest.register_craft({
217                 output = name .. " 4",
218                 recipe = {
219                         { def.material, 'group:stick', def.material },
220                         { def.material, 'group:stick', def.material },
221                 }
222         })
223
224         local fence_texture = "default_fence_overlay.png^" .. def.texture ..
225                         "^default_fence_overlay.png^[makealpha:255,126,126"
226         -- Allow almost everything to be overridden
227         local default_fields = {
228                 paramtype = "light",
229                 drawtype = "fencelike",
230                 inventory_image = fence_texture,
231                 wield_image = fence_texture,
232                 tiles = { def.texture },
233                 sunlight_propagates = true,
234                 is_ground_content = false,
235                 selection_box = {
236                         type = "fixed",
237                         fixed = {-1/7, -1/2, -1/7, 1/7, 1/2, 1/7},
238                 },
239                 groups = {},
240         }
241         for k, v in pairs(default_fields) do
242                 if not def[k] then
243                         def[k] = v
244                 end
245         end
246
247         -- Always add to the fence group, even if no group provided
248         def.groups.fence = 1
249
250         def.texture = nil
251         def.material = nil
252
253         minetest.register_node(name, def)
254 end
255
256
257 --
258 -- Leafdecay
259 --
260
261 default.leafdecay_trunk_cache = {}
262 default.leafdecay_enable_cache = true
263 -- Spread the load of finding trunks
264 default.leafdecay_trunk_find_allow_accumulator = 0
265
266 minetest.register_globalstep(function(dtime)
267         local finds_per_second = 5000
268         default.leafdecay_trunk_find_allow_accumulator =
269                         math.floor(dtime * finds_per_second)
270 end)
271
272 default.after_place_leaves = function(pos, placer, itemstack, pointed_thing)
273         local node = minetest.get_node(pos)
274         node.param2 = 1
275         minetest.set_node(pos, node)
276 end
277
278 minetest.register_abm({
279         nodenames = {"group:leafdecay"},
280         neighbors = {"air", "group:liquid"},
281         -- A low interval and a high inverse chance spreads the load
282         interval = 2,
283         chance = 5,
284
285         action = function(p0, node, _, _)
286                 --print("leafdecay ABM at "..p0.x..", "..p0.y..", "..p0.z..")")
287                 local do_preserve = false
288                 local d = minetest.registered_nodes[node.name].groups.leafdecay
289                 if not d or d == 0 then
290                         --print("not groups.leafdecay")
291                         return
292                 end
293                 local n0 = minetest.get_node(p0)
294                 if n0.param2 ~= 0 then
295                         --print("param2 ~= 0")
296                         return
297                 end
298                 local p0_hash = nil
299                 if default.leafdecay_enable_cache then
300                         p0_hash = minetest.hash_node_position(p0)
301                         local trunkp = default.leafdecay_trunk_cache[p0_hash]
302                         if trunkp then
303                                 local n = minetest.get_node(trunkp)
304                                 local reg = minetest.registered_nodes[n.name]
305                                 -- Assume ignore is a trunk, to make the thing
306                                 -- work at the border of the active area
307                                 if n.name == "ignore" or (reg and reg.groups.tree and
308                                                 reg.groups.tree ~= 0) then
309                                         --print("cached trunk still exists")
310                                         return
311                                 end
312                                 --print("cached trunk is invalid")
313                                 -- Cache is invalid
314                                 table.remove(default.leafdecay_trunk_cache, p0_hash)
315                         end
316                 end
317                 if default.leafdecay_trunk_find_allow_accumulator <= 0 then
318                         return
319                 end
320                 default.leafdecay_trunk_find_allow_accumulator =
321                                 default.leafdecay_trunk_find_allow_accumulator - 1
322                 -- Assume ignore is a trunk, to make the thing
323                 -- work at the border of the active area
324                 local p1 = minetest.find_node_near(p0, d, {"ignore", "group:tree"})
325                 if p1 then
326                         do_preserve = true
327                         if default.leafdecay_enable_cache then
328                                 --print("caching trunk")
329                                 -- Cache the trunk
330                                 default.leafdecay_trunk_cache[p0_hash] = p1
331                         end
332                 end
333                 if not do_preserve then
334                         -- Drop stuff other than the node itself
335                         local itemstacks = minetest.get_node_drops(n0.name)
336                         for _, itemname in ipairs(itemstacks) do
337                                 if minetest.get_item_group(n0.name, "leafdecay_drop") ~= 0 or
338                                                 itemname ~= n0.name then
339                                         local p_drop = {
340                                                 x = p0.x - 0.5 + math.random(),
341                                                 y = p0.y - 0.5 + math.random(),
342                                                 z = p0.z - 0.5 + math.random(),
343                                         }
344                                         minetest.add_item(p_drop, itemname)
345                                 end
346                         end
347                         -- Remove node
348                         minetest.remove_node(p0)
349                         nodeupdate(p0)
350                 end
351         end
352 })
353
354
355 --
356 -- Grass growing on well-lit dirt
357 --
358
359 minetest.register_abm({
360         nodenames = {"default:dirt"},
361         interval = 2,
362         chance = 200,
363         catch_up = false,
364         action = function(pos, node)
365                 local above = {x = pos.x, y = pos.y + 1, z = pos.z}
366                 local name = minetest.get_node(above).name
367                 local nodedef = minetest.registered_nodes[name]
368                 if nodedef and (nodedef.sunlight_propagates or nodedef.paramtype == "light") and
369                                 nodedef.liquidtype == "none" and
370                                 (minetest.get_node_light(above) or 0) >= 13 then
371                         if name == "default:snow" or name == "default:snowblock" then
372                                 minetest.set_node(pos, {name = "default:dirt_with_snow"})
373                         else
374                                 minetest.set_node(pos, {name = "default:dirt_with_grass"})
375                         end
376                 end
377         end
378 })
379
380
381 --
382 -- Grass and dry grass removed in darkness
383 --
384
385 minetest.register_abm({
386         nodenames = {"default:dirt_with_grass", "default:dirt_with_dry_grass"},
387         interval = 2,
388         chance = 20,
389         catch_up = false,
390         action = function(pos, node)
391                 local above = {x = pos.x, y = pos.y + 1, z = pos.z}
392                 local name = minetest.get_node(above).name
393                 local nodedef = minetest.registered_nodes[name]
394                 if name ~= "ignore" and nodedef and not ((nodedef.sunlight_propagates or
395                                 nodedef.paramtype == "light") and
396                                 nodedef.liquidtype == "none") then
397                         minetest.set_node(pos, {name = "default:dirt"})
398                 end
399         end
400 })
401
402
403 --
404 -- Moss growth on cobble near water
405 --
406
407 minetest.register_abm({
408         nodenames = {"default:cobble"},
409         neighbors = {"group:water"},
410         interval = 17,
411         chance = 200,
412         catch_up = false,
413         action = function(pos, node)
414                 minetest.set_node(pos, {name = "default:mossycobble"})
415         end
416 })