2 -- Wear out hoes, place soil
3 -- TODO Ignore group:flower
4 farming.registered_plants = {}
6 farming.hoe_on_use = function(itemstack, user, pointed_thing, uses)
7 local pt = pointed_thing
8 -- check if pointing at a node
12 if pt.type ~= "node" then
16 local under = minetest.get_node(pt.under)
17 local p = {x=pt.under.x, y=pt.under.y+1, z=pt.under.z}
18 local above = minetest.get_node(p)
20 -- return if any of the nodes is not registered
21 if not minetest.registered_nodes[under.name] then
24 if not minetest.registered_nodes[above.name] then
28 -- check if the node above the pointed thing is air
29 if above.name ~= "air" then
33 -- check if pointing at soil
34 if minetest.get_item_group(under.name, "soil") ~= 1 then
38 -- check if (wet) soil defined
39 local regN = minetest.registered_nodes
40 if regN[under.name].soil == nil or regN[under.name].soil.wet == nil or regN[under.name].soil.dry == nil then
44 if minetest.is_protected(pt.under, user:get_player_name()) then
45 minetest.record_protection_violation(pt.under, user:get_player_name())
48 if minetest.is_protected(pt.above, user:get_player_name()) then
49 minetest.record_protection_violation(pt.above, user:get_player_name())
53 -- turn the node into soil and play sound
54 minetest.set_node(pt.under, {name = regN[under.name].soil.dry})
55 minetest.sound_play("default_dig_crumbly", {
60 if not (creative and creative.is_enabled_for
61 and creative.is_enabled_for(user:get_player_name())) then
63 local wdef = itemstack:get_definition()
64 itemstack:add_wear(65535/(uses-1))
66 if itemstack:get_count() == 0 and wdef.sound and wdef.sound.breaks then
67 minetest.sound_play(wdef.sound.breaks, {pos = pt.above, gain = 0.5})
74 farming.register_hoe = function(name, def)
75 -- Check for : prefix (register new hoes in your mod's namespace)
76 if name:sub(1,1) ~= ":" then
80 if def.description == nil then
81 def.description = "Hoe"
83 if def.inventory_image == nil then
84 def.inventory_image = "unknown_item.png"
86 if def.recipe == nil then
89 {"","group:stick",""},
93 if def.max_uses == nil then
97 minetest.register_tool(name, {
98 description = def.description,
99 inventory_image = def.inventory_image,
100 on_use = function(itemstack, user, pointed_thing)
101 return farming.hoe_on_use(itemstack, user, pointed_thing, def.max_uses)
104 sound = {breaks = "default_tool_breaks"},
106 -- Register its recipe
107 if def.material == nil then
108 minetest.register_craft({
109 output = name:sub(2),
113 minetest.register_craft({
114 output = name:sub(2),
116 {def.material, def.material, ""},
117 {"", "group:stick", ""},
118 {"", "group:stick", ""}
124 -- how often node timers for plants will tick, +/- some random value
125 local function tick(pos)
126 minetest.get_node_timer(pos):start(math.random(166, 286))
128 -- how often a growth failure tick is retried (e.g. too dark)
129 local function tick_again(pos)
130 minetest.get_node_timer(pos):start(math.random(40, 80))
134 farming.place_seed = function(itemstack, placer, pointed_thing, plantname)
135 local pt = pointed_thing
136 -- check if pointing at a node
140 if pt.type ~= "node" then
144 local under = minetest.get_node(pt.under)
145 local above = minetest.get_node(pt.above)
147 if minetest.is_protected(pt.under, placer:get_player_name()) then
148 minetest.record_protection_violation(pt.under, placer:get_player_name())
151 if minetest.is_protected(pt.above, placer:get_player_name()) then
152 minetest.record_protection_violation(pt.above, placer:get_player_name())
156 -- return if any of the nodes is not registered
157 if not minetest.registered_nodes[under.name] then
160 if not minetest.registered_nodes[above.name] then
164 -- check if pointing at the top of the node
165 if pt.above.y ~= pt.under.y+1 then
169 -- check if you can replace the node above the pointed node
170 if not minetest.registered_nodes[above.name].buildable_to then
174 -- check if pointing at soil
175 if minetest.get_item_group(under.name, "soil") < 2 then
179 -- add the node and remove 1 item from the itemstack
180 minetest.add_node(pt.above, {name = plantname, param2 = 1})
182 if not (creative and creative.is_enabled_for
183 and creative.is_enabled_for(placer:get_player_name())) then
184 itemstack:take_item()
189 farming.grow_plant = function(pos, elapsed)
190 local node = minetest.get_node(pos)
191 local name = node.name
192 local def = minetest.registered_nodes[name]
194 if not def.next_plant then
195 -- disable timer for fully grown plant
200 if minetest.get_item_group(node.name, "seed") and def.fertility then
201 local soil_node = minetest.get_node_or_nil({x = pos.x, y = pos.y - 1, z = pos.z})
202 if not soil_node then
206 -- omitted is a check for light, we assume seeds can germinate in the dark.
207 for _, v in pairs(def.fertility) do
208 if minetest.get_item_group(soil_node.name, v) ~= 0 then
209 local placenode = {name = def.next_plant}
210 if def.place_param2 then
211 placenode.param2 = def.place_param2
213 minetest.swap_node(pos, placenode)
214 if minetest.registered_nodes[def.next_plant].next_plant then
224 -- check if on wet soil
225 local below = minetest.get_node({x = pos.x, y = pos.y - 1, z = pos.z})
226 if minetest.get_item_group(below.name, "soil") < 3 then
232 local light = minetest.get_node_light(pos)
233 if not light or light < def.minlight or light > def.maxlight then
239 local placenode = {name = def.next_plant}
240 if def.place_param2 then
241 placenode.param2 = def.place_param2
243 minetest.swap_node(pos, placenode)
246 if minetest.registered_nodes[def.next_plant].next_plant then
253 farming.register_plant = function(name, def)
254 local mname = name:split(":")[1]
255 local pname = name:split(":")[2]
258 if not def.description then
259 def.description = "Seed"
261 if not def.inventory_image then
262 def.inventory_image = "unknown_item.png"
264 if not def.steps then
267 if not def.minlight then
270 if not def.maxlight then
273 if not def.fertility then
277 farming.registered_plants[pname] = def
280 local lbm_nodes = {mname .. ":seed_" .. pname}
281 local g = {seed = 1, snappy = 3, attached_node = 1, flammable = 2}
282 for k, v in pairs(def.fertility) do
285 minetest.register_node(":" .. mname .. ":seed_" .. pname, {
286 description = def.description,
287 tiles = {def.inventory_image},
288 inventory_image = def.inventory_image,
289 wield_image = def.inventory_image,
290 drawtype = "signlike",
293 paramtype2 = "wallmounted",
294 place_param2 = def.place_param2 or nil, -- this isn't actually used for placement
296 sunlight_propagates = true,
299 fixed = {-0.5, -0.5, -0.5, 0.5, -5/16, 0.5},
301 fertility = def.fertility,
302 sounds = default.node_sound_dirt_defaults({
303 dig = {name = "", gain = 0},
304 dug = {name = "default_grass_footstep", gain = 0.2},
305 place = {name = "default_place_node", gain = 0.25},
308 on_place = function(itemstack, placer, pointed_thing)
309 local under = pointed_thing.under
310 local node = minetest.get_node(under)
311 local udef = minetest.registered_nodes[node.name]
312 if udef and udef.on_rightclick and
313 not (placer and placer:get_player_control().sneak) then
314 return udef.on_rightclick(under, node, placer, itemstack,
315 pointed_thing) or itemstack
318 return farming.place_seed(itemstack, placer, pointed_thing, mname .. ":seed_" .. pname)
320 next_plant = mname .. ":" .. pname .. "_1",
321 on_timer = farming.grow_plant,
322 minlight = def.minlight,
323 maxlight = def.maxlight,
327 minetest.register_craftitem(":" .. mname .. ":" .. pname, {
328 description = pname:gsub("^%l", string.upper),
329 inventory_image = mname .. "_" .. pname .. ".png",
330 groups = {flammable = 2},
333 -- Register growing steps
334 for i = 1, def.steps do
335 local base_rarity = 1
336 if def.steps ~= 1 then
337 base_rarity = 8 - (i - 1) * 7 / (def.steps - 1)
341 {items = {mname .. ":" .. pname}, rarity = base_rarity},
342 {items = {mname .. ":" .. pname}, rarity = base_rarity * 2},
343 {items = {mname .. ":seed_" .. pname}, rarity = base_rarity},
344 {items = {mname .. ":seed_" .. pname}, rarity = base_rarity * 2},
347 local nodegroups = {snappy = 3, flammable = 2, plant = 1, not_in_creative_inventory = 1, attached_node = 1}
348 nodegroups[pname] = i
350 local next_plant = nil
352 if i < def.steps then
353 next_plant = mname .. ":" .. pname .. "_" .. (i + 1)
354 lbm_nodes[#lbm_nodes + 1] = mname .. ":" .. pname .. "_" .. i
357 minetest.register_node(":" .. mname .. ":" .. pname .. "_" .. i, {
358 drawtype = "plantlike",
360 tiles = {mname .. "_" .. pname .. "_" .. i .. ".png"},
362 paramtype2 = def.paramtype2 or nil,
363 place_param2 = def.place_param2 or nil,
369 fixed = {-0.5, -0.5, -0.5, 0.5, -5/16, 0.5},
372 sounds = default.node_sound_leaves_defaults(),
373 next_plant = next_plant,
374 on_timer = farming.grow_plant,
375 minlight = def.minlight,
376 maxlight = def.maxlight,
380 -- replacement LBM for pre-nodetimer plants
381 minetest.register_lbm({
382 name = ":" .. mname .. ":start_nodetimer_" .. pname,
383 nodenames = lbm_nodes,
384 action = function(pos, node)
391 seed = mname .. ":seed_" .. pname,
392 harvest = mname .. ":" .. pname