mirror of
https://github.com/minetest/minetest_game.git
synced 2024-12-23 15:20:19 +01:00
78c632ebd4
- beds - boats - carts - key/skeleton key - seeds All these had on_place handlers that did not allow nodes with an on_rightclick() handler to be used first (if not using sneak). This code is taken from the torches mod and applied everywhere. This allows all these items to e.g. be inserted into the `frame` mod's item frames.
403 lines
10 KiB
Lua
403 lines
10 KiB
Lua
|
|
-- 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,
|
|
})
|
|
|
|
if not minetest.setting_getbool("creative_mode") 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})
|
|
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 = "Hoe"
|
|
end
|
|
if def.inventory_image == nil then
|
|
def.inventory_image = "unknown_item.png"
|
|
end
|
|
if def.recipe == nil then
|
|
def.recipe = {
|
|
{"air","air",""},
|
|
{"","group:stick",""},
|
|
{"","group:stick",""}
|
|
}
|
|
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.material == nil then
|
|
minetest.register_craft({
|
|
output = name:sub(2),
|
|
recipe = def.recipe
|
|
})
|
|
else
|
|
minetest.register_craft({
|
|
output = name:sub(2),
|
|
recipe = {
|
|
{def.material, def.material, ""},
|
|
{"", "group:stick", ""},
|
|
{"", "group:stick", ""}
|
|
}
|
|
})
|
|
-- Reverse Recipe
|
|
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)
|
|
|
|
if minetest.is_protected(pt.under, placer:get_player_name()) then
|
|
minetest.record_protection_violation(pt.under, placer:get_player_name())
|
|
return
|
|
end
|
|
if minetest.is_protected(pt.above, placer:get_player_name()) then
|
|
minetest.record_protection_violation(pt.above, placer:get_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.add_node(pt.above, {name = plantname, param2 = 1})
|
|
tick(pt.above)
|
|
if not minetest.setting_getbool("creative_mode") 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 = "Seed"
|
|
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: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 = pname:gsub("^%l", string.upper),
|
|
inventory_image = mname .. "_" .. pname .. ".png",
|
|
groups = {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
|