Move leafdecay doc to game_api.txt
[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 -- Legacy
88 --
89
90 function default.spawn_falling_node(p, nodename)
91         spawn_falling_node(p, nodename)
92 end
93
94 -- Horrible crap to support old code
95 -- Don't use this and never do what this does, it's completely wrong!
96 -- (More specifically, the client and the C++ code doesn't get the group)
97 function default.register_falling_node(nodename, texture)
98         minetest.log("error", debug.traceback())
99         minetest.log('error', "WARNING: default.register_falling_node is deprecated")
100         if minetest.registered_nodes[nodename] then
101                 minetest.registered_nodes[nodename].groups.falling_node = 1
102         end
103 end
104
105 --
106 -- Global callbacks
107 --
108
109 -- Global environment step function
110 function on_step(dtime)
111         -- print("on_step")
112 end
113 minetest.register_globalstep(on_step)
114
115 function on_placenode(p, node)
116         --print("on_placenode")
117 end
118 minetest.register_on_placenode(on_placenode)
119
120 function on_dignode(p, node)
121         --print("on_dignode")
122 end
123 minetest.register_on_dignode(on_dignode)
124
125 function on_punchnode(p, node)
126 end
127 minetest.register_on_punchnode(on_punchnode)
128
129
130 --
131 -- Lavacooling
132 --
133
134 default.cool_lava_source = function(pos)
135         minetest.set_node(pos, {name="default:obsidian"})
136         minetest.sound_play("default_cool_lava", {pos = pos,  gain = 0.25})
137 end
138
139 default.cool_lava_flowing = function(pos)
140         minetest.set_node(pos, {name="default:stone"})
141         minetest.sound_play("default_cool_lava", {pos = pos,  gain = 0.25})
142 end
143
144 minetest.register_abm({
145         nodenames = {"default:lava_flowing"},
146         neighbors = {"group:water"},
147         interval = 1,
148         chance = 1,
149         action = function(pos, node, active_object_count, active_object_count_wider)
150                 default.cool_lava_flowing(pos, node, active_object_count, active_object_count_wider)
151         end,
152 })
153
154 minetest.register_abm({
155         nodenames = {"default:lava_source"},
156         neighbors = {"group:water"},
157         interval = 1,
158         chance = 1,
159         action = function(pos, node, active_object_count, active_object_count_wider)
160                 default.cool_lava_source(pos, node, active_object_count, active_object_count_wider)
161         end,
162 })
163
164 --
165 -- Papyrus and cactus growing
166 --
167
168 minetest.register_abm({
169         nodenames = {"default:cactus"},
170         neighbors = {"group:sand"},
171         interval = 50,
172         chance = 20,
173         action = function(pos, node)
174                 pos.y = pos.y-1
175                 local name = minetest.get_node(pos).name
176                 if minetest.get_item_group(name, "sand") ~= 0 then
177                         pos.y = pos.y+1
178                         local height = 0
179                         while minetest.get_node(pos).name == "default:cactus" and height < 4 do
180                                 height = height+1
181                                 pos.y = pos.y+1
182                         end
183                         if height < 4 then
184                                 if minetest.get_node(pos).name == "air" then
185                                         minetest.set_node(pos, {name="default:cactus"})
186                                 end
187                         end
188                 end
189         end,
190 })
191
192 minetest.register_abm({
193         nodenames = {"default:papyrus"},
194         neighbors = {"default:dirt", "default:dirt_with_grass"},
195         interval = 50,
196         chance = 20,
197         action = function(pos, node)
198                 pos.y = pos.y-1
199                 local name = minetest.get_node(pos).name
200                 if name == "default:dirt" or name == "default:dirt_with_grass" then
201                         if minetest.find_node_near(pos, 3, {"group:water"}) == nil then
202                                 return
203                         end
204                         pos.y = pos.y+1
205                         local height = 0
206                         while minetest.get_node(pos).name == "default:papyrus" and height < 4 do
207                                 height = height+1
208                                 pos.y = pos.y+1
209                         end
210                         if height < 4 then
211                                 if minetest.get_node(pos).name == "air" then
212                                         minetest.set_node(pos, {name="default:papyrus"})
213                                 end
214                         end
215                 end
216         end,
217 })
218
219 --
220 -- dig upwards
221 --
222
223 function default.dig_up(pos, node, digger)
224         if digger == nil then return end
225         local np = {x = pos.x, y = pos.y + 1, z = pos.z}
226         local nn = minetest.get_node(np)
227         if nn.name == node.name then
228                 minetest.node_dig(np, nn, digger)
229         end
230 end
231
232 --
233 -- Leafdecay
234 --
235
236 default.leafdecay_trunk_cache = {}
237 default.leafdecay_enable_cache = true
238 -- Spread the load of finding trunks
239 default.leafdecay_trunk_find_allow_accumulator = 0
240
241 minetest.register_globalstep(function(dtime)
242         local finds_per_second = 5000
243         default.leafdecay_trunk_find_allow_accumulator =
244                         math.floor(dtime * finds_per_second)
245 end)
246
247 minetest.register_abm({
248         nodenames = {"group:leafdecay"},
249         neighbors = {"air", "group:liquid"},
250         -- A low interval and a high inverse chance spreads the load
251         interval = 2,
252         chance = 5,
253
254         action = function(p0, node, _, _)
255                 --print("leafdecay ABM at "..p0.x..", "..p0.y..", "..p0.z..")")
256                 local do_preserve = false
257                 local d = minetest.registered_nodes[node.name].groups.leafdecay
258                 if not d or d == 0 then
259                         --print("not groups.leafdecay")
260                         return
261                 end
262                 local n0 = minetest.get_node(p0)
263                 if n0.param2 ~= 0 then
264                         --print("param2 ~= 0")
265                         return
266                 end
267                 local p0_hash = nil
268                 if default.leafdecay_enable_cache then
269                         p0_hash = minetest.hash_node_position(p0)
270                         local trunkp = default.leafdecay_trunk_cache[p0_hash]
271                         if trunkp then
272                                 local n = minetest.get_node(trunkp)
273                                 local reg = minetest.registered_nodes[n.name]
274                                 -- Assume ignore is a trunk, to make the thing work at the border of the active area
275                                 if n.name == "ignore" or (reg and reg.groups.tree and reg.groups.tree ~= 0) then
276                                         --print("cached trunk still exists")
277                                         return
278                                 end
279                                 --print("cached trunk is invalid")
280                                 -- Cache is invalid
281                                 table.remove(default.leafdecay_trunk_cache, p0_hash)
282                         end
283                 end
284                 if default.leafdecay_trunk_find_allow_accumulator <= 0 then
285                         return
286                 end
287                 default.leafdecay_trunk_find_allow_accumulator =
288                                 default.leafdecay_trunk_find_allow_accumulator - 1
289                 -- Assume ignore is a trunk, to make the thing work at the border of the active area
290                 local p1 = minetest.find_node_near(p0, d, {"ignore", "group:tree"})
291                 if p1 then
292                         do_preserve = true
293                         if default.leafdecay_enable_cache then
294                                 --print("caching trunk")
295                                 -- Cache the trunk
296                                 default.leafdecay_trunk_cache[p0_hash] = p1
297                         end
298                 end
299                 if not do_preserve then
300                         -- Drop stuff other than the node itself
301                         local itemstacks = minetest.get_node_drops(n0.name)
302                         for _, itemname in ipairs(itemstacks) do
303                                 if minetest.get_item_group(n0.name, "leafdecay_drop") ~= 0 or
304                                                 itemname ~= n0.name then
305                                         local p_drop = {
306                                                 x = p0.x - 0.5 + math.random(),
307                                                 y = p0.y - 0.5 + math.random(),
308                                                 z = p0.z - 0.5 + math.random(),
309                                         }
310                                         minetest.add_item(p_drop, itemname)
311                                 end
312                         end
313                         -- Remove node
314                         minetest.remove_node(p0)
315                         nodeupdate(p0)
316                 end
317         end
318 })
319