Default/functions: Fix cacti not growing when rotation is 1-3
[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", {pos = pos,  gain = 0.25})
94 end
95
96 default.cool_lava_flowing = function(pos)
97         minetest.set_node(pos, {name="default:stone"})
98         minetest.sound_play("default_cool_lava", {pos = pos,  gain = 0.25})
99 end
100
101 minetest.register_abm({
102         nodenames = {"default:lava_flowing"},
103         neighbors = {"group:water"},
104         interval = 1,
105         chance = 1,
106         action = function(...)
107                 default.cool_lava_flowing(...)
108         end,
109 })
110
111 minetest.register_abm({
112         nodenames = {"default:lava_source"},
113         neighbors = {"group:water"},
114         interval = 1,
115         chance = 1,
116         action = function(...)
117                 default.cool_lava_source(...)
118         end,
119 })
120
121
122 --
123 -- Papyrus and cactus growing
124 --
125
126 function default.grow_cactus(pos, node)
127         if node.param2 >= 4 then
128                 return
129         end
130         pos.y = pos.y-1
131         if minetest.get_item_group(minetest.get_node(pos).name, "sand") == 0 then
132                 return
133         end
134         pos.y = pos.y+1
135         local height = 0
136         while node.name == "default:cactus" and height < 4 and node.param2 == 0 do
137                 height = height+1
138                 pos.y = pos.y+1
139                 node = minetest.get_node(pos)
140         end
141         if height == 4
142         or node.name ~= "air" then
143                 return
144         end
145         minetest.set_node(pos, {name="default:cactus"})
146         return true
147 end
148
149 function default.grow_papyrus(pos, node)
150         pos.y = pos.y-1
151         local name = minetest.get_node(pos).name
152         if name ~= "default:dirt_with_grass"
153         and name ~= "default:dirt" then
154                 return
155         end
156         if not minetest.find_node_near(pos, 3, {"group:water"}) then
157                 return
158         end
159         pos.y = pos.y+1
160         local height = 0
161         while node.name == "default:papyrus" and height < 4 do
162                 height = height+1
163                 pos.y = pos.y+1
164                 node = minetest.get_node(pos)
165         end
166         if height == 4
167         or node.name ~= "air" then
168                 return
169         end
170         minetest.set_node(pos, {name="default:papyrus"})
171         return true
172 end
173
174 -- wrapping the functions in abm action is necessary to make overriding them possible
175 minetest.register_abm({
176         nodenames = {"default:cactus"},
177         neighbors = {"group:sand"},
178         interval = 50,
179         chance = 20,
180         action = function(...)
181                 default.grow_cactus(...)
182         end
183 })
184
185 minetest.register_abm({
186         nodenames = {"default:papyrus"},
187         neighbors = {"default:dirt", "default:dirt_with_grass"},
188         interval = 50,
189         chance = 20,
190         action = function(...)
191                 default.grow_papyrus(...)
192         end
193 })
194
195
196 --
197 -- dig upwards
198 --
199
200 function default.dig_up(pos, node, digger)
201         if digger == nil then return end
202         local np = {x = pos.x, y = pos.y + 1, z = pos.z}
203         local nn = minetest.get_node(np)
204         if nn.name == node.name then
205                 minetest.node_dig(np, nn, digger)
206         end
207 end
208
209
210 --
211 -- Leafdecay
212 --
213
214 default.leafdecay_trunk_cache = {}
215 default.leafdecay_enable_cache = true
216 -- Spread the load of finding trunks
217 default.leafdecay_trunk_find_allow_accumulator = 0
218
219 minetest.register_globalstep(function(dtime)
220         local finds_per_second = 5000
221         default.leafdecay_trunk_find_allow_accumulator =
222                         math.floor(dtime * finds_per_second)
223 end)
224
225 default.after_place_leaves = function(pos, placer, itemstack, pointed_thing)
226         local node = minetest.get_node(pos)
227         node.param2 = 1
228         minetest.set_node(pos, node)
229 end
230
231 minetest.register_abm({
232         nodenames = {"group:leafdecay"},
233         neighbors = {"air", "group:liquid"},
234         -- A low interval and a high inverse chance spreads the load
235         interval = 2,
236         chance = 5,
237
238         action = function(p0, node, _, _)
239                 --print("leafdecay ABM at "..p0.x..", "..p0.y..", "..p0.z..")")
240                 local do_preserve = false
241                 local d = minetest.registered_nodes[node.name].groups.leafdecay
242                 if not d or d == 0 then
243                         --print("not groups.leafdecay")
244                         return
245                 end
246                 local n0 = minetest.get_node(p0)
247                 if n0.param2 ~= 0 then
248                         --print("param2 ~= 0")
249                         return
250                 end
251                 local p0_hash = nil
252                 if default.leafdecay_enable_cache then
253                         p0_hash = minetest.hash_node_position(p0)
254                         local trunkp = default.leafdecay_trunk_cache[p0_hash]
255                         if trunkp then
256                                 local n = minetest.get_node(trunkp)
257                                 local reg = minetest.registered_nodes[n.name]
258                                 -- Assume ignore is a trunk, to make the thing work at the border of the active area
259                                 if n.name == "ignore" or (reg and reg.groups.tree and reg.groups.tree ~= 0) then
260                                         --print("cached trunk still exists")
261                                         return
262                                 end
263                                 --print("cached trunk is invalid")
264                                 -- Cache is invalid
265                                 table.remove(default.leafdecay_trunk_cache, p0_hash)
266                         end
267                 end
268                 if default.leafdecay_trunk_find_allow_accumulator <= 0 then
269                         return
270                 end
271                 default.leafdecay_trunk_find_allow_accumulator =
272                                 default.leafdecay_trunk_find_allow_accumulator - 1
273                 -- Assume ignore is a trunk, to make the thing work at the border of the active area
274                 local p1 = minetest.find_node_near(p0, d, {"ignore", "group:tree"})
275                 if p1 then
276                         do_preserve = true
277                         if default.leafdecay_enable_cache then
278                                 --print("caching trunk")
279                                 -- Cache the trunk
280                                 default.leafdecay_trunk_cache[p0_hash] = p1
281                         end
282                 end
283                 if not do_preserve then
284                         -- Drop stuff other than the node itself
285                         local itemstacks = minetest.get_node_drops(n0.name)
286                         for _, itemname in ipairs(itemstacks) do
287                                 if minetest.get_item_group(n0.name, "leafdecay_drop") ~= 0 or
288                                                 itemname ~= n0.name then
289                                         local p_drop = {
290                                                 x = p0.x - 0.5 + math.random(),
291                                                 y = p0.y - 0.5 + math.random(),
292                                                 z = p0.z - 0.5 + math.random(),
293                                         }
294                                         minetest.add_item(p_drop, itemname)
295                                 end
296                         end
297                         -- Remove node
298                         minetest.remove_node(p0)
299                         nodeupdate(p0)
300                 end
301         end
302 })
303
304 --
305 -- Grass growing
306 --
307
308 minetest.register_abm({
309         nodenames = {"default:dirt"},
310         interval = 2,
311         chance = 200,
312         action = function(pos, node)
313                 local above = {x=pos.x, y=pos.y+1, z=pos.z}
314                 local name = minetest.get_node(above).name
315                 local nodedef = minetest.registered_nodes[name]
316                 if nodedef and (nodedef.sunlight_propagates or nodedef.paramtype == "light")
317                                 and nodedef.liquidtype == "none"
318                                 and (minetest.get_node_light(above) or 0) >= 13 then
319                         if name == "default:snow" or name == "default:snowblock" then
320                                 minetest.set_node(pos, {name = "default:dirt_with_snow"})
321                         else
322                                 minetest.set_node(pos, {name = "default:dirt_with_grass"})
323                         end
324                 end
325         end
326 })
327
328 minetest.register_abm({
329         nodenames = {"default:dirt_with_grass"},
330         interval = 2,
331         chance = 20,
332         action = function(pos, node)
333                 local above = {x=pos.x, y=pos.y+1, z=pos.z}
334                 local name = minetest.get_node(above).name
335                 local nodedef = minetest.registered_nodes[name]
336                 if name ~= "ignore" and nodedef
337                                 and not ((nodedef.sunlight_propagates or nodedef.paramtype == "light")
338                                 and nodedef.liquidtype == "none") then
339                         minetest.set_node(pos, {name = "default:dirt"})
340                 end
341         end
342 })