Fix more translation strings (#2487)
[oweals/minetest_game.git] / mods / farming / api.lua
1 -- farming/api.lua
2
3 -- support for MT game translation.
4 local S = farming.get_translator
5
6 -- Wear out hoes, place soil
7 -- TODO Ignore group:flower
8 farming.registered_plants = {}
9
10 farming.hoe_on_use = function(itemstack, user, pointed_thing, uses)
11         local pt = pointed_thing
12         -- check if pointing at a node
13         if not pt then
14                 return
15         end
16         if pt.type ~= "node" then
17                 return
18         end
19
20         local under = minetest.get_node(pt.under)
21         local p = {x=pt.under.x, y=pt.under.y+1, z=pt.under.z}
22         local above = minetest.get_node(p)
23
24         -- return if any of the nodes is not registered
25         if not minetest.registered_nodes[under.name] then
26                 return
27         end
28         if not minetest.registered_nodes[above.name] then
29                 return
30         end
31
32         -- check if the node above the pointed thing is air
33         if above.name ~= "air" then
34                 return
35         end
36
37         -- check if pointing at soil
38         if minetest.get_item_group(under.name, "soil") ~= 1 then
39                 return
40         end
41
42         -- check if (wet) soil defined
43         local regN = minetest.registered_nodes
44         if regN[under.name].soil == nil or regN[under.name].soil.wet == nil or regN[under.name].soil.dry == nil then
45                 return
46         end
47
48         if minetest.is_protected(pt.under, user:get_player_name()) then
49                 minetest.record_protection_violation(pt.under, user:get_player_name())
50                 return
51         end
52         if minetest.is_protected(pt.above, user:get_player_name()) then
53                 minetest.record_protection_violation(pt.above, user:get_player_name())
54                 return
55         end
56
57         -- turn the node into soil and play sound
58         minetest.set_node(pt.under, {name = regN[under.name].soil.dry})
59         minetest.sound_play("default_dig_crumbly", {
60                 pos = pt.under,
61                 gain = 0.5,
62         })
63
64         if not (creative and creative.is_enabled_for
65                         and creative.is_enabled_for(user:get_player_name())) then
66                 -- wear tool
67                 local wdef = itemstack:get_definition()
68                 itemstack:add_wear(65535/(uses-1))
69                 -- tool break sound
70                 if itemstack:get_count() == 0 and wdef.sound and wdef.sound.breaks then
71                         minetest.sound_play(wdef.sound.breaks, {pos = pt.above, gain = 0.5})
72                 end
73         end
74         return itemstack
75 end
76
77 -- Register new hoes
78 farming.register_hoe = function(name, def)
79         -- Check for : prefix (register new hoes in your mod's namespace)
80         if name:sub(1,1) ~= ":" then
81                 name = ":" .. name
82         end
83         -- Check def table
84         if def.description == nil then
85                 def.description = S("Hoe")
86         end
87         if def.inventory_image == nil then
88                 def.inventory_image = "unknown_item.png"
89         end
90         if def.max_uses == nil then
91                 def.max_uses = 30
92         end
93         -- Register the tool
94         minetest.register_tool(name, {
95                 description = def.description,
96                 inventory_image = def.inventory_image,
97                 on_use = function(itemstack, user, pointed_thing)
98                         return farming.hoe_on_use(itemstack, user, pointed_thing, def.max_uses)
99                 end,
100                 groups = def.groups,
101                 sound = {breaks = "default_tool_breaks"},
102         })
103         -- Register its recipe
104         if def.recipe then
105                 minetest.register_craft({
106                         output = name:sub(2),
107                         recipe = def.recipe
108                 })
109         elseif def.material then
110                 minetest.register_craft({
111                         output = name:sub(2),
112                         recipe = {
113                                 {def.material, def.material},
114                                 {"", "group:stick"},
115                                 {"", "group:stick"}
116                         }
117                 })
118         end
119 end
120
121 -- how often node timers for plants will tick, +/- some random value
122 local function tick(pos)
123         minetest.get_node_timer(pos):start(math.random(166, 286))
124 end
125 -- how often a growth failure tick is retried (e.g. too dark)
126 local function tick_again(pos)
127         minetest.get_node_timer(pos):start(math.random(40, 80))
128 end
129
130 -- Seed placement
131 farming.place_seed = function(itemstack, placer, pointed_thing, plantname)
132         local pt = pointed_thing
133         -- check if pointing at a node
134         if not pt then
135                 return itemstack
136         end
137         if pt.type ~= "node" then
138                 return itemstack
139         end
140
141         local under = minetest.get_node(pt.under)
142         local above = minetest.get_node(pt.above)
143
144         local player_name = placer and placer:get_player_name() or ""
145
146         if minetest.is_protected(pt.under, player_name) then
147                 minetest.record_protection_violation(pt.under, player_name)
148                 return
149         end
150         if minetest.is_protected(pt.above, player_name) then
151                 minetest.record_protection_violation(pt.above, player_name)
152                 return
153         end
154
155         -- return if any of the nodes is not registered
156         if not minetest.registered_nodes[under.name] then
157                 return itemstack
158         end
159         if not minetest.registered_nodes[above.name] then
160                 return itemstack
161         end
162
163         -- check if pointing at the top of the node
164         if pt.above.y ~= pt.under.y+1 then
165                 return itemstack
166         end
167
168         -- check if you can replace the node above the pointed node
169         if not minetest.registered_nodes[above.name].buildable_to then
170                 return itemstack
171         end
172
173         -- check if pointing at soil
174         if minetest.get_item_group(under.name, "soil") < 2 then
175                 return itemstack
176         end
177
178         -- add the node and remove 1 item from the itemstack
179         minetest.add_node(pt.above, {name = plantname, param2 = 1})
180         tick(pt.above)
181         if not (creative and creative.is_enabled_for
182                         and creative.is_enabled_for(player_name)) then
183                 itemstack:take_item()
184         end
185         return itemstack
186 end
187
188 farming.grow_plant = function(pos, elapsed)
189         local node = minetest.get_node(pos)
190         local name = node.name
191         local def = minetest.registered_nodes[name]
192
193         if not def.next_plant then
194                 -- disable timer for fully grown plant
195                 return
196         end
197
198         -- grow seed
199         if minetest.get_item_group(node.name, "seed") and def.fertility then
200                 local soil_node = minetest.get_node_or_nil({x = pos.x, y = pos.y - 1, z = pos.z})
201                 if not soil_node then
202                         tick_again(pos)
203                         return
204                 end
205                 -- omitted is a check for light, we assume seeds can germinate in the dark.
206                 for _, v in pairs(def.fertility) do
207                         if minetest.get_item_group(soil_node.name, v) ~= 0 then
208                                 local placenode = {name = def.next_plant}
209                                 if def.place_param2 then
210                                         placenode.param2 = def.place_param2
211                                 end
212                                 minetest.swap_node(pos, placenode)
213                                 if minetest.registered_nodes[def.next_plant].next_plant then
214                                         tick(pos)
215                                         return
216                                 end
217                         end
218                 end
219
220                 return
221         end
222
223         -- check if on wet soil
224         local below = minetest.get_node({x = pos.x, y = pos.y - 1, z = pos.z})
225         if minetest.get_item_group(below.name, "soil") < 3 then
226                 tick_again(pos)
227                 return
228         end
229
230         -- check light
231         local light = minetest.get_node_light(pos)
232         if not light or light < def.minlight or light > def.maxlight then
233                 tick_again(pos)
234                 return
235         end
236
237         -- grow
238         local placenode = {name = def.next_plant}
239         if def.place_param2 then
240                 placenode.param2 = def.place_param2
241         end
242         minetest.swap_node(pos, placenode)
243
244         -- new timer needed?
245         if minetest.registered_nodes[def.next_plant].next_plant then
246                 tick(pos)
247         end
248         return
249 end
250
251 -- Register plants
252 farming.register_plant = function(name, def)
253         local mname = name:split(":")[1]
254         local pname = name:split(":")[2]
255
256         -- Check def table
257         if not def.description then
258                 def.description = S("Seed")
259         end
260         if not def.harvest_description then
261                 def.harvest_description = pname:gsub("^%l", string.upper)
262         end
263         if not def.inventory_image then
264                 def.inventory_image = "unknown_item.png"
265         end
266         if not def.steps then
267                 return nil
268         end
269         if not def.minlight then
270                 def.minlight = 1
271         end
272         if not def.maxlight then
273                 def.maxlight = 14
274         end
275         if not def.fertility then
276                 def.fertility = {}
277         end
278
279         farming.registered_plants[pname] = def
280
281         -- Register seed
282         local lbm_nodes = {mname .. ":seed_" .. pname}
283         local g = {seed = 1, snappy = 3, attached_node = 1, flammable = 2}
284         for k, v in pairs(def.fertility) do
285                 g[v] = 1
286         end
287         minetest.register_node(":" .. mname .. ":seed_" .. pname, {
288                 description = def.description,
289                 tiles = {def.inventory_image},
290                 inventory_image = def.inventory_image,
291                 wield_image = def.inventory_image,
292                 drawtype = "signlike",
293                 groups = g,
294                 paramtype = "light",
295                 paramtype2 = "wallmounted",
296                 place_param2 = def.place_param2 or nil, -- this isn't actually used for placement
297                 walkable = false,
298                 sunlight_propagates = true,
299                 selection_box = {
300                         type = "fixed",
301                         fixed = {-0.5, -0.5, -0.5, 0.5, -5/16, 0.5},
302                 },
303                 fertility = def.fertility,
304                 sounds = default.node_sound_dirt_defaults({
305                         dig = {name = "", gain = 0},
306                         dug = {name = "default_grass_footstep", gain = 0.2},
307                         place = {name = "default_place_node", gain = 0.25},
308                 }),
309
310                 on_place = function(itemstack, placer, pointed_thing)
311                         local under = pointed_thing.under
312                         local node = minetest.get_node(under)
313                         local udef = minetest.registered_nodes[node.name]
314                         if udef and udef.on_rightclick and
315                                         not (placer and placer:is_player() and
316                                         placer:get_player_control().sneak) then
317                                 return udef.on_rightclick(under, node, placer, itemstack,
318                                         pointed_thing) or itemstack
319                         end
320
321                         return farming.place_seed(itemstack, placer, pointed_thing, mname .. ":seed_" .. pname)
322                 end,
323                 next_plant = mname .. ":" .. pname .. "_1",
324                 on_timer = farming.grow_plant,
325                 minlight = def.minlight,
326                 maxlight = def.maxlight,
327         })
328
329         -- Register harvest
330         minetest.register_craftitem(":" .. mname .. ":" .. pname, {
331                 description = def.harvest_description,
332                 inventory_image = mname .. "_" .. pname .. ".png",
333                 groups = def.groups or {flammable = 2},
334         })
335
336         -- Register growing steps
337         for i = 1, def.steps do
338                 local base_rarity = 1
339                 if def.steps ~= 1 then
340                         base_rarity =  8 - (i - 1) * 7 / (def.steps - 1)
341                 end
342                 local drop = {
343                         items = {
344                                 {items = {mname .. ":" .. pname}, rarity = base_rarity},
345                                 {items = {mname .. ":" .. pname}, rarity = base_rarity * 2},
346                                 {items = {mname .. ":seed_" .. pname}, rarity = base_rarity},
347                                 {items = {mname .. ":seed_" .. pname}, rarity = base_rarity * 2},
348                         }
349                 }
350                 local nodegroups = {snappy = 3, flammable = 2, plant = 1, not_in_creative_inventory = 1, attached_node = 1}
351                 nodegroups[pname] = i
352
353                 local next_plant = nil
354
355                 if i < def.steps then
356                         next_plant = mname .. ":" .. pname .. "_" .. (i + 1)
357                         lbm_nodes[#lbm_nodes + 1] = mname .. ":" .. pname .. "_" .. i
358                 end
359
360                 minetest.register_node(":" .. mname .. ":" .. pname .. "_" .. i, {
361                         drawtype = "plantlike",
362                         waving = 1,
363                         tiles = {mname .. "_" .. pname .. "_" .. i .. ".png"},
364                         paramtype = "light",
365                         paramtype2 = def.paramtype2 or nil,
366                         place_param2 = def.place_param2 or nil,
367                         walkable = false,
368                         buildable_to = true,
369                         drop = drop,
370                         selection_box = {
371                                 type = "fixed",
372                                 fixed = {-0.5, -0.5, -0.5, 0.5, -5/16, 0.5},
373                         },
374                         groups = nodegroups,
375                         sounds = default.node_sound_leaves_defaults(),
376                         next_plant = next_plant,
377                         on_timer = farming.grow_plant,
378                         minlight = def.minlight,
379                         maxlight = def.maxlight,
380                 })
381         end
382
383         -- replacement LBM for pre-nodetimer plants
384         minetest.register_lbm({
385                 name = ":" .. mname .. ":start_nodetimer_" .. pname,
386                 nodenames = lbm_nodes,
387                 action = function(pos, node)
388                         tick_again(pos)
389                 end,
390         })
391
392         -- Return
393         local r = {
394                 seed = mname .. ":seed_" .. pname,
395                 harvest = mname .. ":" .. pname
396         }
397         return r
398 end