68f7be752c32f7211774a731e4c2fbf7dee86832
[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                 sounds = default.node_sound_dirt_defaults({
224                         dug = {name = "default_grass_footstep", gain = 0.2},
225                         place = {name = "default_place_node", gain = 0.25},
226                 }),
227
228                 on_place = function(itemstack, placer, pointed_thing)
229                         return farming.place_seed(itemstack, placer, pointed_thing, mname .. ":seed_" .. pname)
230                 end,
231         })
232
233         -- Register harvest
234         minetest.register_craftitem(":" .. mname .. ":" .. pname, {
235                 description = pname:gsub("^%l", string.upper),
236                 inventory_image = mname .. "_" .. pname .. ".png",
237         })
238
239         -- Register growing steps
240         for i=1,def.steps do
241                 local drop = {
242                         items = {
243                                 {items = {mname .. ":" .. pname}, rarity = 9 - i},
244                                 {items = {mname .. ":" .. pname}, rarity= 18 - i * 2},
245                                 {items = {mname .. ":seed_" .. pname}, rarity = 9 - i},
246                                 {items = {mname .. ":seed_" .. pname}, rarity = 18 - i * 2},
247                         }
248                 }
249                 local nodegroups = {snappy = 3, flammable = 2, plant = 1, not_in_creative_inventory = 1, attached_node = 1}
250                 nodegroups[pname] = i
251                 minetest.register_node(mname .. ":" .. pname .. "_" .. i, {
252                         drawtype = "plantlike",
253                         waving = 1,
254                         tiles = {mname .. "_" .. pname .. "_" .. i .. ".png"},
255                         paramtype = "light",
256                         walkable = false,
257                         buildable_to = true,
258                         drop = drop,
259                         selection_box = {
260                                 type = "fixed",
261                                 fixed = {-0.5, -0.5, -0.5, 0.5, -5/16, 0.5},
262                         },
263                         groups = nodegroups,
264                         sounds = default.node_sound_leaves_defaults(),
265                 })
266         end
267
268         -- Growing ABM
269         minetest.register_abm({
270                 nodenames = {"group:" .. pname, "group:seed"},
271                 neighbors = {"group:soil"},
272                 interval = 9,
273                 chance = 20,
274                 action = function(pos, node)
275                         local plant_height = minetest.get_item_group(node.name, pname)
276
277                         -- return if already full grown
278                         if plant_height == def.steps then
279                                 return
280                         end
281
282                         local node_def = minetest.registered_items[node.name] or nil
283
284                         -- grow seed
285                         if minetest.get_item_group(node.name, "seed") and node_def.fertility then
286                                 local can_grow = false
287                                 local soil_node = minetest.get_node_or_nil({x = pos.x, y = pos.y - 1, z = pos.z})
288                                 if not soil_node then
289                                         return
290                                 end
291                                 for _, v in pairs(node_def.fertility) do
292                                         if minetest.get_item_group(soil_node.name, v) ~= 0 then
293                                                 can_grow = true
294                                         end
295                                 end
296                                 if can_grow then
297                                         minetest.set_node(pos, {name = node.name:gsub("seed_", "") .. "_1"})
298                                 end
299                                 return
300                         end
301
302                         -- check if on wet soil
303                         pos.y = pos.y - 1
304                         local n = minetest.get_node(pos)
305                         if minetest.get_item_group(n.name, "soil") < 3 then
306                                 return
307                         end
308                         pos.y = pos.y + 1
309
310                         -- check light
311                         local ll = minetest.get_node_light(pos)
312
313                         if not ll or ll < def.minlight or ll > def.maxlight then
314                                 return
315                         end
316
317                         -- grow
318                         minetest.set_node(pos, {name = mname .. ":" .. pname .. "_" .. plant_height + 1})
319                 end
320         })
321
322         -- Return
323         local r = {
324                 seed = mname .. ":seed_" .. pname,
325                 harvest = mname .. ":" .. pname
326         }
327         return r
328 end