123456789101112131415161718192021222324252627282930313233343536373839404142434445464748495051525354555657585960616263646566676869707172737475767778798081828384858687888990919293949596979899100101102103104105106107108109110111112113114115116117118119120121122123124125126127128129130131132133134135136137138139140141142143144145146147148149150151152153154155156157158159160161162163164165166167168169170171172173174175176177178179180181182183184185186187188189190191192193194195196197198199200201202203204205206207208209210211212213214215216217218219220221222223224225226227228229230231232233234235236237238239240241242243244245246247248249250251252253254255256257258259260261262263264265266267268269270271272273274275276277278279280281282283284285286287288289290291292293294295296297298299300301302303304305306307308309310311312313314315316317318319320321322323324325326327328329330331332333334335336337338339340341342343344345346347348349350351352353354355356357358359360361362363364365366367368369370371372373374375376377378379380381382383384385386387388389390391392393394395396397398399400401 |
- -- farming/api.lua
- -- support for MT game translation.
- local S = farming.get_translator
- -- Wear out hoes, place soil
- -- TODO Ignore group:flower
- farming.registered_plants = {}
- farming.hoe_on_use = function(itemstack, user, pointed_thing, uses)
- local pt = pointed_thing
- -- check if pointing at a node
- if not pt then
- return
- end
- if pt.type ~= "node" then
- return
- end
- local under = minetest.get_node(pt.under)
- local p = {x=pt.under.x, y=pt.under.y+1, z=pt.under.z}
- local above = minetest.get_node(p)
- -- return if any of the nodes is not registered
- if not minetest.registered_nodes[under.name] then
- return
- end
- if not minetest.registered_nodes[above.name] then
- return
- end
- -- check if the node above the pointed thing is air
- if above.name ~= "air" then
- return
- end
- -- check if pointing at soil
- if minetest.get_item_group(under.name, "soil") ~= 1 then
- return
- end
- -- check if (wet) soil defined
- local regN = minetest.registered_nodes
- if regN[under.name].soil == nil or regN[under.name].soil.wet == nil or regN[under.name].soil.dry == nil then
- return
- end
- if minetest.is_protected(pt.under, user:get_player_name()) then
- minetest.record_protection_violation(pt.under, user:get_player_name())
- return
- end
- if minetest.is_protected(pt.above, user:get_player_name()) then
- minetest.record_protection_violation(pt.above, user:get_player_name())
- return
- end
- -- turn the node into soil and play sound
- minetest.set_node(pt.under, {name = regN[under.name].soil.dry})
- minetest.sound_play("default_dig_crumbly", {
- pos = pt.under,
- gain = 0.5,
- }, true)
- if not (creative and creative.is_enabled_for
- and creative.is_enabled_for(user:get_player_name())) then
- -- wear tool
- local wdef = itemstack:get_definition()
- itemstack:add_wear(65535/(uses-1))
- -- tool break sound
- if itemstack:get_count() == 0 and wdef.sound and wdef.sound.breaks then
- minetest.sound_play(wdef.sound.breaks, {pos = pt.above,
- gain = 0.5}, true)
- end
- end
- return itemstack
- end
- -- Register new hoes
- farming.register_hoe = function(name, def)
- -- Check for : prefix (register new hoes in your mod's namespace)
- if name:sub(1,1) ~= ":" then
- name = ":" .. name
- end
- -- Check def table
- if def.description == nil then
- def.description = S("Hoe")
- end
- if def.inventory_image == nil then
- def.inventory_image = "unknown_item.png"
- end
- if def.max_uses == nil then
- def.max_uses = 30
- end
- -- Register the tool
- minetest.register_tool(name, {
- description = def.description,
- inventory_image = def.inventory_image,
- on_use = function(itemstack, user, pointed_thing)
- return farming.hoe_on_use(itemstack, user, pointed_thing, def.max_uses)
- end,
- groups = def.groups,
- sound = {breaks = "default_tool_breaks"},
- })
- -- Register its recipe
- if def.recipe then
- minetest.register_craft({
- output = name:sub(2),
- recipe = def.recipe
- })
- elseif def.material then
- minetest.register_craft({
- output = name:sub(2),
- recipe = {
- {def.material, def.material},
- {"", "group:stick"},
- {"", "group:stick"}
- }
- })
- end
- end
- -- how often node timers for plants will tick, +/- some random value
- local function tick(pos)
- minetest.get_node_timer(pos):start(math.random(166, 286))
- end
- -- how often a growth failure tick is retried (e.g. too dark)
- local function tick_again(pos)
- minetest.get_node_timer(pos):start(math.random(40, 80))
- end
- -- Seed placement
- farming.place_seed = function(itemstack, placer, pointed_thing, plantname)
- local pt = pointed_thing
- -- check if pointing at a node
- if not pt then
- return itemstack
- end
- if pt.type ~= "node" then
- return itemstack
- end
- local under = minetest.get_node(pt.under)
- local above = minetest.get_node(pt.above)
- local player_name = placer and placer:get_player_name() or ""
- if minetest.is_protected(pt.under, player_name) then
- minetest.record_protection_violation(pt.under, player_name)
- return
- end
- if minetest.is_protected(pt.above, player_name) then
- minetest.record_protection_violation(pt.above, player_name)
- return
- end
- -- return if any of the nodes is not registered
- if not minetest.registered_nodes[under.name] then
- return itemstack
- end
- if not minetest.registered_nodes[above.name] then
- return itemstack
- end
- -- check if pointing at the top of the node
- if pt.above.y ~= pt.under.y+1 then
- return itemstack
- end
- -- check if you can replace the node above the pointed node
- if not minetest.registered_nodes[above.name].buildable_to then
- return itemstack
- end
- -- check if pointing at soil
- if minetest.get_item_group(under.name, "soil") < 2 then
- return itemstack
- end
- -- add the node and remove 1 item from the itemstack
- minetest.log("action", player_name .. " places node " .. plantname .. " at " ..
- minetest.pos_to_string(pt.above))
- minetest.add_node(pt.above, {name = plantname, param2 = 1})
- tick(pt.above)
- if not (creative and creative.is_enabled_for
- and creative.is_enabled_for(player_name)) then
- itemstack:take_item()
- end
- return itemstack
- end
- farming.grow_plant = function(pos, elapsed)
- local node = minetest.get_node(pos)
- local name = node.name
- local def = minetest.registered_nodes[name]
- if not def.next_plant then
- -- disable timer for fully grown plant
- return
- end
- -- grow seed
- if minetest.get_item_group(node.name, "seed") and def.fertility then
- local soil_node = minetest.get_node_or_nil({x = pos.x, y = pos.y - 1, z = pos.z})
- if not soil_node then
- tick_again(pos)
- return
- end
- -- omitted is a check for light, we assume seeds can germinate in the dark.
- for _, v in pairs(def.fertility) do
- if minetest.get_item_group(soil_node.name, v) ~= 0 then
- local placenode = {name = def.next_plant}
- if def.place_param2 then
- placenode.param2 = def.place_param2
- end
- minetest.swap_node(pos, placenode)
- if minetest.registered_nodes[def.next_plant].next_plant then
- tick(pos)
- return
- end
- end
- end
- return
- end
- -- check if on wet soil
- local below = minetest.get_node({x = pos.x, y = pos.y - 1, z = pos.z})
- if minetest.get_item_group(below.name, "soil") < 3 then
- tick_again(pos)
- return
- end
- -- check light
- local light = minetest.get_node_light(pos)
- if not light or light < def.minlight or light > def.maxlight then
- tick_again(pos)
- return
- end
- -- grow
- local placenode = {name = def.next_plant}
- if def.place_param2 then
- placenode.param2 = def.place_param2
- end
- minetest.swap_node(pos, placenode)
- -- new timer needed?
- if minetest.registered_nodes[def.next_plant].next_plant then
- tick(pos)
- end
- return
- end
- -- Register plants
- farming.register_plant = function(name, def)
- local mname = name:split(":")[1]
- local pname = name:split(":")[2]
- -- Check def table
- if not def.description then
- def.description = S("Seed")
- end
- if not def.harvest_description then
- def.harvest_description = pname:gsub("^%l", string.upper)
- end
- if not def.inventory_image then
- def.inventory_image = "unknown_item.png"
- end
- if not def.steps then
- return nil
- end
- if not def.minlight then
- def.minlight = 1
- end
- if not def.maxlight then
- def.maxlight = 14
- end
- if not def.fertility then
- def.fertility = {}
- end
- farming.registered_plants[pname] = def
- -- Register seed
- local lbm_nodes = {mname .. ":seed_" .. pname}
- local g = {seed = 1, snappy = 3, attached_node = 1, flammable = 2}
- for k, v in pairs(def.fertility) do
- g[v] = 1
- end
- minetest.register_node(":" .. mname .. ":seed_" .. pname, {
- description = def.description,
- tiles = {def.inventory_image},
- inventory_image = def.inventory_image,
- wield_image = def.inventory_image,
- drawtype = "signlike",
- groups = g,
- paramtype = "light",
- paramtype2 = "wallmounted",
- place_param2 = def.place_param2 or nil, -- this isn't actually used for placement
- walkable = false,
- sunlight_propagates = true,
- selection_box = {
- type = "fixed",
- fixed = {-0.5, -0.5, -0.5, 0.5, -5/16, 0.5},
- },
- fertility = def.fertility,
- sounds = default.node_sound_dirt_defaults({
- dig = {name = "", gain = 0},
- dug = {name = "default_grass_footstep", gain = 0.2},
- place = {name = "default_place_node", gain = 0.25},
- }),
- on_place = function(itemstack, placer, pointed_thing)
- local under = pointed_thing.under
- local node = minetest.get_node(under)
- local udef = minetest.registered_nodes[node.name]
- if udef and udef.on_rightclick and
- not (placer and placer:is_player() and
- placer:get_player_control().sneak) then
- return udef.on_rightclick(under, node, placer, itemstack,
- pointed_thing) or itemstack
- end
- return farming.place_seed(itemstack, placer, pointed_thing, mname .. ":seed_" .. pname)
- end,
- next_plant = mname .. ":" .. pname .. "_1",
- on_timer = farming.grow_plant,
- minlight = def.minlight,
- maxlight = def.maxlight,
- })
- -- Register harvest
- minetest.register_craftitem(":" .. mname .. ":" .. pname, {
- description = def.harvest_description,
- inventory_image = mname .. "_" .. pname .. ".png",
- groups = def.groups or {flammable = 2},
- })
- -- Register growing steps
- for i = 1, def.steps do
- local base_rarity = 1
- if def.steps ~= 1 then
- base_rarity = 8 - (i - 1) * 7 / (def.steps - 1)
- end
- local drop = {
- items = {
- {items = {mname .. ":" .. pname}, rarity = base_rarity},
- {items = {mname .. ":" .. pname}, rarity = base_rarity * 2},
- {items = {mname .. ":seed_" .. pname}, rarity = base_rarity},
- {items = {mname .. ":seed_" .. pname}, rarity = base_rarity * 2},
- }
- }
- local nodegroups = {snappy = 3, flammable = 2, plant = 1, not_in_creative_inventory = 1, attached_node = 1}
- nodegroups[pname] = i
- local next_plant = nil
- if i < def.steps then
- next_plant = mname .. ":" .. pname .. "_" .. (i + 1)
- lbm_nodes[#lbm_nodes + 1] = mname .. ":" .. pname .. "_" .. i
- end
- minetest.register_node(":" .. mname .. ":" .. pname .. "_" .. i, {
- drawtype = "plantlike",
- waving = 1,
- tiles = {mname .. "_" .. pname .. "_" .. i .. ".png"},
- paramtype = "light",
- paramtype2 = def.paramtype2 or nil,
- place_param2 = def.place_param2 or nil,
- walkable = false,
- buildable_to = true,
- drop = drop,
- selection_box = {
- type = "fixed",
- fixed = {-0.5, -0.5, -0.5, 0.5, -5/16, 0.5},
- },
- groups = nodegroups,
- sounds = default.node_sound_leaves_defaults(),
- next_plant = next_plant,
- on_timer = farming.grow_plant,
- minlight = def.minlight,
- maxlight = def.maxlight,
- })
- end
- -- replacement LBM for pre-nodetimer plants
- minetest.register_lbm({
- name = ":" .. mname .. ":start_nodetimer_" .. pname,
- nodenames = lbm_nodes,
- action = function(pos, node)
- tick_again(pos)
- end,
- })
- -- Return
- local r = {
- seed = mname .. ":seed_" .. pname,
- harvest = mname .. ":" .. pname
- }
- return r
- end
|