Consolidate ABMs
[oweals/minetest_game.git] / mods / farming / api.lua
1 -- Wear out hoes, place soil
2 -- TODO Ignore group:flower
3 farming.hoe_on_use = function(itemstack, user, pointed_thing, uses)
4         local pt = pointed_thing
5         -- check if pointing at a node
6         if not pt then
7                 return
8         end
9         if pt.type ~= "node" then
10                 return
11         end
12         
13         local under = minetest.get_node(pt.under)
14         local p = {x=pt.under.x, y=pt.under.y+1, z=pt.under.z}
15         local above = minetest.get_node(p)
16         
17         -- return if any of the nodes is not registered
18         if not minetest.registered_nodes[under.name] then
19                 return
20         end
21         if not minetest.registered_nodes[above.name] then
22                 return
23         end
24         
25         -- check if the node above the pointed thing is air
26         if above.name ~= "air" then
27                 return
28         end
29         
30         -- check if pointing at soil
31         if minetest.get_item_group(under.name, "soil") ~= 1 then
32                 return
33         end
34         
35         -- check if (wet) soil defined
36         local regN = minetest.registered_nodes
37         if regN[under.name].soil == nil or regN[under.name].soil.wet == nil or regN[under.name].soil.dry == nil then
38                 return
39         end
40         
41         if minetest.is_protected(pt.under, user:get_player_name()) then
42                 minetest.record_protection_violation(pt.under, user:get_player_name())
43                 return
44         end
45         if minetest.is_protected(pt.above, user:get_player_name()) then
46                 minetest.record_protection_violation(pt.above, user:get_player_name())
47                 return
48         end
49
50         
51         -- turn the node into soil, wear out item and play sound
52         minetest.set_node(pt.under, {name = regN[under.name].soil.dry})
53         minetest.sound_play("default_dig_crumbly", {
54                 pos = pt.under,
55                 gain = 0.5,
56         })
57         
58         if not minetest.setting_getbool("creative_mode") then
59                 itemstack:add_wear(65535/(uses-1))
60         end
61         return itemstack
62 end
63
64 -- Register new hoes
65 farming.register_hoe = function(name, def)
66         -- Check for : prefix (register new hoes in your mod's namespace)
67         if name:sub(1,1) ~= ":" then
68                 name = ":" .. name
69         end
70         -- Check def table
71         if def.description == nil then
72                 def.description = "Hoe"
73         end
74         if def.inventory_image == nil then
75                 def.inventory_image = "unknown_item.png"
76         end
77         if def.recipe == nil then
78                 def.recipe = {
79                         {"air","air",""},
80                         {"","group:stick",""},
81                         {"","group:stick",""}
82                 }
83         end
84         if def.max_uses == nil then
85                 def.max_uses = 30
86         end
87         -- Register the tool
88         minetest.register_tool(name, {
89                 description = def.description,
90                 inventory_image = def.inventory_image,
91                 on_use = function(itemstack, user, pointed_thing)
92                         return farming.hoe_on_use(itemstack, user, pointed_thing, def.max_uses)
93                 end
94         })
95         -- Register its recipe
96         if def.material == nil then
97                 minetest.register_craft({
98                         output = name:sub(2),
99                         recipe = def.recipe
100                 })
101         else
102                 minetest.register_craft({
103                         output = name:sub(2),
104                         recipe = {
105                                 {def.material, def.material, ""},
106                                 {"", "group:stick", ""},
107                                 {"", "group:stick", ""}
108                         }
109                 })
110                 -- Reverse Recipe
111                 minetest.register_craft({
112                         output = name:sub(2),
113                         recipe = {
114                                 {"", def.material, def.material},
115                                 {"", "group:stick", ""},
116                                 {"", "group:stick", ""}
117                         }
118                 })
119         end
120 end
121
122 -- Seed placement
123 farming.place_seed = function(itemstack, placer, pointed_thing, plantname)
124         local pt = pointed_thing
125         -- check if pointing at a node
126         if not pt then
127                 return
128         end
129         if pt.type ~= "node" then
130                 return
131         end
132         
133         local under = minetest.get_node(pt.under)
134         local above = minetest.get_node(pt.above)
135         
136         if minetest.is_protected(pt.under, placer:get_player_name()) then
137                 minetest.record_protection_violation(pt.under, placer:get_player_name())
138                 return
139         end
140         if minetest.is_protected(pt.above, placer:get_player_name()) then
141                 minetest.record_protection_violation(pt.above, placer:get_player_name())
142                 return
143         end
144
145         
146         -- return if any of the nodes is not registered
147         if not minetest.registered_nodes[under.name] then
148                 return
149         end
150         if not minetest.registered_nodes[above.name] then
151                 return
152         end
153         
154         -- check if pointing at the top of the node
155         if pt.above.y ~= pt.under.y+1 then
156                 return
157         end
158         
159         -- check if you can replace the node above the pointed node
160         if not minetest.registered_nodes[above.name].buildable_to then
161                 return
162         end
163         
164         -- check if pointing at soil
165         if minetest.get_item_group(under.name, "soil") < 2 then
166                 return
167         end
168         
169         -- add the node and remove 1 item from the itemstack
170         minetest.add_node(pt.above, {name = plantname, param2 = 1})
171         if not minetest.setting_getbool("creative_mode") then
172                 itemstack:take_item()
173         end
174         return itemstack
175 end
176
177 -- Register plants
178 farming.register_plant = function(name, def)
179         local mname = name:split(":")[1]
180         local pname = name:split(":")[2]
181
182         -- Check def table
183         if not def.description then
184                 def.description = "Seed"
185         end
186         if not def.inventory_image then
187                 def.inventory_image = "unknown_item.png"
188         end
189         if not def.steps then
190                 return nil
191         end
192         if not def.minlight then
193                 def.minlight = 1
194         end
195         if not def.maxlight then
196                 def.maxlight = 14
197         end
198         if not def.fertility then
199                 def.fertility = {}
200         end
201
202         -- Register seed
203         local g = {seed = 1, snappy = 3, attached_node = 1}
204         for k, v in pairs(def.fertility) do
205                 g[v] = 1
206         end
207         minetest.register_node(":" .. mname .. ":seed_" .. pname, {
208                 description = def.description,
209                 tiles = {def.inventory_image},
210                 inventory_image = def.inventory_image,
211                 wield_image = def.inventory_image,
212                 drawtype = "signlike",
213                 groups = g,
214                 paramtype = "light",
215                 paramtype2 = "wallmounted",
216                 walkable = false,
217                 sunlight_propagates = true,
218                 selection_box = {
219                         type = "fixed",
220                         fixed = {-0.5, -0.5, -0.5, 0.5, -5/16, 0.5},
221                 },
222                 fertility = def.fertility,
223                 on_place = function(itemstack, placer, pointed_thing)
224                         return farming.place_seed(itemstack, placer, pointed_thing, mname .. ":seed_" .. pname)
225                 end
226         })
227
228         -- Register harvest
229         minetest.register_craftitem(":" .. mname .. ":" .. pname, {
230                 description = pname:gsub("^%l", string.upper),
231                 inventory_image = mname .. "_" .. pname .. ".png",
232         })
233
234         -- Register growing steps
235         for i=1,def.steps do
236                 local drop = {
237                         items = {
238                                 {items = {mname .. ":" .. pname}, rarity = 9 - i},
239                                 {items = {mname .. ":" .. pname}, rarity= 18 - i * 2},
240                                 {items = {mname .. ":seed_" .. pname}, rarity = 9 - i},
241                                 {items = {mname .. ":seed_" .. pname}, rarity = 18 - i * 2},
242                         }
243                 }
244                 local nodegroups = {snappy = 3, flammable = 2, plant = 1, not_in_creative_inventory = 1, attached_node = 1}
245                 nodegroups[pname] = i
246                 minetest.register_node(mname .. ":" .. pname .. "_" .. i, {
247                         drawtype = "plantlike",
248                         waving = 1,
249                         tiles = {mname .. "_" .. pname .. "_" .. i .. ".png"},
250                         paramtype = "light",
251                         walkable = false,
252                         buildable_to = true,
253                         drop = drop,
254                         selection_box = {
255                                 type = "fixed",
256                                 fixed = {-0.5, -0.5, -0.5, 0.5, -5/16, 0.5},
257                         },
258                         groups = nodegroups,
259                         sounds = default.node_sound_leaves_defaults(),
260                 })
261         end
262
263         -- Growing ABM
264         minetest.register_abm({
265                 nodenames = {"group:" .. pname, "group:seed"},
266                 neighbors = {"group:soil"},
267                 interval = 9,
268                 chance = 20,
269                 action = function(pos, node)
270                         local plant_height = minetest.get_item_group(node.name, pname)
271
272                         -- return if already full grown
273                         if plant_height == def.steps then
274                                 return
275                         end
276
277                         local node_def = minetest.registered_items[node.name] or nil
278
279                         -- grow seed
280                         if minetest.get_item_group(node.name, "seed") and node_def.fertility then
281                                 local can_grow = false
282                                 local soil_node = minetest.get_node_or_nil({x = pos.x, y = pos.y - 1, z = pos.z})
283                                 if not soil_node then
284                                         return
285                                 end
286                                 for _, v in pairs(node_def.fertility) do
287                                         if minetest.get_item_group(soil_node.name, v) ~= 0 then
288                                                 can_grow = true
289                                         end
290                                 end
291                                 if can_grow then
292                                         minetest.set_node(pos, {name = node.name:gsub("seed_", "") .. "_1"})
293                                 end
294                                 return
295                         end
296
297                         -- check if on wet soil
298                         pos.y = pos.y - 1
299                         local n = minetest.get_node(pos)
300                         if minetest.get_item_group(n.name, "soil") < 3 then
301                                 return
302                         end
303                         pos.y = pos.y + 1
304
305                         -- check light
306                         local ll = minetest.get_node_light(pos)
307
308                         if not ll or ll < def.minlight or ll > def.maxlight then
309                                 return
310                         end
311
312                         -- grow
313                         minetest.set_node(pos, {name = mname .. ":" .. pname .. "_" .. plant_height + 1})
314                 end
315         })
316
317         -- Return
318         local r = {
319                 seed = mname .. ":seed_" .. pname,
320                 harvest = mname .. ":" .. pname
321         }
322         return r
323 end