2020-10-26 17:38:53 +01:00
|
|
|
--[[
|
2024-12-19 12:55:40 +01:00
|
|
|
Farming Redo Mod by TenPlus1
|
2020-10-26 17:38:53 +01:00
|
|
|
NEW growing routine by prestidigitator
|
|
|
|
auto-refill by crabman77
|
|
|
|
]]
|
|
|
|
|
2024-12-19 12:55:40 +01:00
|
|
|
-- Translation support
|
|
|
|
|
|
|
|
local S = minetest.get_translator("farming")
|
|
|
|
|
|
|
|
-- global
|
|
|
|
|
2020-10-26 17:38:53 +01:00
|
|
|
farming = {
|
|
|
|
mod = "redo",
|
2024-12-19 12:55:40 +01:00
|
|
|
version = "20240924",
|
2020-10-26 17:38:53 +01:00
|
|
|
path = minetest.get_modpath("farming"),
|
2024-12-19 12:55:40 +01:00
|
|
|
select = {type = "fixed", fixed = {-0.5, -0.5, -0.5, 0.5, -5/16, 0.5}},
|
|
|
|
select_final = {type = "fixed", fixed = {-0.5, -0.5, -0.5, 0.5, -2.5/16, 0.5}},
|
2020-12-09 21:59:08 +01:00
|
|
|
registered_plants = {},
|
2024-12-19 12:55:40 +01:00
|
|
|
min_light = 12, max_light = 15,
|
|
|
|
mapgen = minetest.get_mapgen_setting("mg_name"),
|
|
|
|
use_utensils = minetest.settings:get_bool("farming_use_utensils") ~= false,
|
|
|
|
mtg = minetest.get_modpath("default"),
|
|
|
|
eth = minetest.get_modpath("ethereal"),
|
|
|
|
mcl = minetest.get_modpath("mcl_core"),
|
|
|
|
mcl_hardness = 0.01,
|
|
|
|
translate = S
|
2020-10-26 17:38:53 +01:00
|
|
|
}
|
|
|
|
|
2024-12-19 12:55:40 +01:00
|
|
|
-- determine which sounds to use, default or mcl_sounds
|
|
|
|
|
|
|
|
local function sound_helper(snd)
|
|
|
|
|
|
|
|
farming[snd] = (farming.mtg and default[snd]) or (farming.mcl and mcl_sounds[snd])
|
|
|
|
or function() return {} end
|
|
|
|
end
|
|
|
|
|
|
|
|
sound_helper("node_sound_defaults")
|
|
|
|
sound_helper("node_sound_stone_defaults")
|
|
|
|
sound_helper("node_sound_dirt_defaults")
|
|
|
|
sound_helper("node_sound_sand_defaults")
|
|
|
|
sound_helper("node_sound_gravel_defaults")
|
|
|
|
sound_helper("node_sound_wood_defaults")
|
|
|
|
sound_helper("node_sound_leaves_defaults")
|
|
|
|
sound_helper("node_sound_ice_defaults")
|
|
|
|
sound_helper("node_sound_metal_defaults")
|
|
|
|
sound_helper("node_sound_water_defaults")
|
|
|
|
sound_helper("node_sound_snow_defaults")
|
|
|
|
sound_helper("node_sound_glass_defaults")
|
|
|
|
|
|
|
|
-- check for creative mode or priv
|
2020-10-26 17:38:53 +01:00
|
|
|
|
|
|
|
local creative_mode_cache = minetest.settings:get_bool("creative_mode")
|
|
|
|
|
|
|
|
function farming.is_creative(name)
|
|
|
|
return creative_mode_cache or minetest.check_player_privs(name, {creative = true})
|
|
|
|
end
|
|
|
|
|
2024-12-19 12:55:40 +01:00
|
|
|
-- stats, locals, settings, function helper
|
2020-10-26 17:38:53 +01:00
|
|
|
|
|
|
|
local statistics = dofile(farming.path .. "/statistics.lua")
|
2024-12-19 12:55:40 +01:00
|
|
|
local random, floor = math.random, math.floor
|
2020-10-26 17:38:53 +01:00
|
|
|
local time_speed = tonumber(minetest.settings:get("time_speed")) or 72
|
|
|
|
local SECS_PER_CYCLE = (time_speed > 0 and (24 * 60 * 60) / time_speed) or 0
|
2024-12-19 12:55:40 +01:00
|
|
|
local function clamp(x, min, max) return (x < min and min) or (x > max and max) or x end
|
2020-10-26 17:38:53 +01:00
|
|
|
|
|
|
|
-- return amount of day or night that has elapsed
|
|
|
|
-- dt is time elapsed, count_day if true counts day, otherwise night
|
2024-12-19 12:55:40 +01:00
|
|
|
|
2020-10-26 17:38:53 +01:00
|
|
|
local function day_or_night_time(dt, count_day)
|
|
|
|
|
|
|
|
local t_day = minetest.get_timeofday()
|
|
|
|
local t1_day = t_day - dt / SECS_PER_CYCLE
|
|
|
|
local t1_c, t2_c -- t1_c < t2_c and t2_c always in [0, 1)
|
|
|
|
|
|
|
|
if count_day then
|
|
|
|
|
|
|
|
if t_day < 0.25 then
|
|
|
|
t1_c = t1_day + 0.75 -- Relative to sunup, yesterday
|
|
|
|
t2_c = t_day + 0.75
|
|
|
|
else
|
|
|
|
t1_c = t1_day - 0.25 -- Relative to sunup, today
|
|
|
|
t2_c = t_day - 0.25
|
|
|
|
end
|
|
|
|
else
|
|
|
|
if t_day < 0.75 then
|
|
|
|
t1_c = t1_day + 0.25 -- Relative to sundown, yesterday
|
|
|
|
t2_c = t_day + 0.25
|
|
|
|
else
|
|
|
|
t1_c = t1_day - 0.75 -- Relative to sundown, today
|
|
|
|
t2_c = t_day - 0.75
|
|
|
|
end
|
|
|
|
end
|
|
|
|
|
|
|
|
local dt_c = clamp(t2_c, 0, 0.5) - clamp(t1_c, 0, 0.5) -- this cycle
|
|
|
|
|
|
|
|
if t1_c < -0.5 then
|
2024-12-19 12:55:40 +01:00
|
|
|
|
|
|
|
local nc = floor(-t1_c)
|
|
|
|
|
2020-10-26 17:38:53 +01:00
|
|
|
t1_c = t1_c + nc
|
|
|
|
dt_c = dt_c + 0.5 * nc + clamp(-t1_c - 0.5, 0, 0.5)
|
|
|
|
end
|
|
|
|
|
|
|
|
return dt_c * SECS_PER_CYCLE
|
|
|
|
end
|
|
|
|
|
|
|
|
-- Growth Logic
|
2024-12-19 12:55:40 +01:00
|
|
|
|
|
|
|
local STAGE_LENGTH_AVG = tonumber(minetest.settings:get("farming_stage_length")) or 200
|
2020-10-26 17:38:53 +01:00
|
|
|
local STAGE_LENGTH_DEV = STAGE_LENGTH_AVG / 6
|
|
|
|
|
2024-12-19 12:55:40 +01:00
|
|
|
-- quick start seed timer
|
|
|
|
|
|
|
|
farming.start_seed_timer = function(pos)
|
|
|
|
|
|
|
|
local timer = minetest.get_node_timer(pos)
|
|
|
|
local grow_time = floor(random(STAGE_LENGTH_DEV, STAGE_LENGTH_AVG))
|
|
|
|
|
|
|
|
timer:start(grow_time)
|
|
|
|
end
|
2020-10-26 17:38:53 +01:00
|
|
|
|
|
|
|
-- return plant name and stage from node provided
|
2024-12-19 12:55:40 +01:00
|
|
|
|
2020-10-26 17:38:53 +01:00
|
|
|
local function plant_name_stage(node)
|
|
|
|
|
|
|
|
local name
|
|
|
|
|
|
|
|
if type(node) == "table" then
|
|
|
|
|
2024-12-19 12:55:40 +01:00
|
|
|
if node.name then name = node.name
|
2020-10-26 17:38:53 +01:00
|
|
|
elseif node.x and node.y and node.z then
|
|
|
|
node = minetest.get_node_or_nil(node)
|
|
|
|
name = node and node.name
|
|
|
|
end
|
|
|
|
else
|
|
|
|
name = tostring(node)
|
|
|
|
end
|
|
|
|
|
2024-12-19 12:55:40 +01:00
|
|
|
if not name or name == "ignore" then return nil end
|
2020-10-26 17:38:53 +01:00
|
|
|
|
|
|
|
local sep_pos = name:find("_[^_]+$")
|
|
|
|
|
|
|
|
if sep_pos and sep_pos > 1 then
|
|
|
|
|
|
|
|
local stage = tonumber(name:sub(sep_pos + 1))
|
|
|
|
|
|
|
|
if stage and stage >= 0 then
|
|
|
|
return name:sub(1, sep_pos - 1), stage
|
|
|
|
end
|
|
|
|
end
|
|
|
|
|
|
|
|
return name, 0
|
|
|
|
end
|
|
|
|
|
|
|
|
-- Map from node name to
|
|
|
|
-- { plant_name = ..., name = ..., stage = n, stages_left = { node_name, ... } }
|
|
|
|
|
|
|
|
local plant_stages = {}
|
|
|
|
|
|
|
|
farming.plant_stages = plant_stages
|
|
|
|
|
|
|
|
--- Registers the stages of growth of a (possible plant) node.
|
2024-12-19 12:55:40 +01:00
|
|
|
-- @param node - Node or position table, or node name.
|
|
|
|
-- @return - The (possibly zero) number of stages of growth the plant will go through
|
|
|
|
-- before being fully grown, or nil if not a plant.
|
2020-10-26 17:38:53 +01:00
|
|
|
|
|
|
|
-- Recursive helper
|
2024-12-19 12:55:40 +01:00
|
|
|
|
2020-10-26 17:38:53 +01:00
|
|
|
local function reg_plant_stages(plant_name, stage, force_last)
|
|
|
|
|
|
|
|
local node_name = plant_name and plant_name .. "_" .. stage
|
|
|
|
local node_def = node_name and minetest.registered_nodes[node_name]
|
|
|
|
|
2024-12-19 12:55:40 +01:00
|
|
|
if not node_def then return nil end
|
2020-10-26 17:38:53 +01:00
|
|
|
|
|
|
|
local stages = plant_stages[node_name]
|
|
|
|
|
2024-12-19 12:55:40 +01:00
|
|
|
if stages then return stages end
|
2020-10-26 17:38:53 +01:00
|
|
|
|
|
|
|
if minetest.get_item_group(node_name, "growing") > 0 then
|
|
|
|
|
|
|
|
local ns = reg_plant_stages(plant_name, stage + 1, true)
|
|
|
|
local stages_left = (ns and { ns.name, unpack(ns.stages_left) }) or {}
|
|
|
|
|
|
|
|
stages = {
|
|
|
|
plant_name = plant_name,
|
|
|
|
name = node_name,
|
|
|
|
stage = stage,
|
|
|
|
stages_left = stages_left
|
|
|
|
}
|
|
|
|
|
|
|
|
if #stages_left > 0 then
|
|
|
|
|
|
|
|
local old_constr = node_def.on_construct
|
|
|
|
local old_destr = node_def.on_destruct
|
|
|
|
|
2024-12-19 12:55:40 +01:00
|
|
|
minetest.override_item(node_name, {
|
2020-10-26 17:38:53 +01:00
|
|
|
|
2024-12-19 12:55:40 +01:00
|
|
|
on_construct = function(pos)
|
2020-10-26 17:38:53 +01:00
|
|
|
|
2024-12-19 12:55:40 +01:00
|
|
|
if old_constr then old_constr(pos) end
|
2020-10-26 17:38:53 +01:00
|
|
|
|
2024-12-19 12:55:40 +01:00
|
|
|
farming.handle_growth(pos)
|
|
|
|
end,
|
2020-10-26 17:38:53 +01:00
|
|
|
|
2024-12-19 12:55:40 +01:00
|
|
|
on_destruct = function(pos)
|
2020-10-26 17:38:53 +01:00
|
|
|
|
2024-12-19 12:55:40 +01:00
|
|
|
minetest.get_node_timer(pos):stop()
|
2020-10-26 17:38:53 +01:00
|
|
|
|
2024-12-19 12:55:40 +01:00
|
|
|
if old_destr then old_destr(pos) end
|
|
|
|
end,
|
|
|
|
|
|
|
|
on_timer = function(pos, elapsed)
|
|
|
|
return farming.plant_growth_timer(pos, elapsed, node_name)
|
|
|
|
end,
|
|
|
|
})
|
2020-10-26 17:38:53 +01:00
|
|
|
end
|
|
|
|
|
|
|
|
elseif force_last then
|
|
|
|
|
|
|
|
stages = {
|
|
|
|
plant_name = plant_name,
|
|
|
|
name = node_name,
|
|
|
|
stage = stage,
|
|
|
|
stages_left = {}
|
|
|
|
}
|
|
|
|
else
|
|
|
|
return nil
|
|
|
|
end
|
|
|
|
|
|
|
|
plant_stages[node_name] = stages
|
|
|
|
|
|
|
|
return stages
|
|
|
|
end
|
|
|
|
|
2024-12-19 12:55:40 +01:00
|
|
|
-- split name and stage and register crop
|
2020-10-26 17:38:53 +01:00
|
|
|
|
2024-12-19 12:55:40 +01:00
|
|
|
local function register_plant_node(node)
|
2020-10-26 17:38:53 +01:00
|
|
|
|
|
|
|
local plant_name, stage = plant_name_stage(node)
|
|
|
|
|
|
|
|
if plant_name then
|
|
|
|
|
|
|
|
local stages = reg_plant_stages(plant_name, stage, false)
|
2024-12-19 12:55:40 +01:00
|
|
|
|
2020-10-26 17:38:53 +01:00
|
|
|
return stages and #stages.stages_left
|
|
|
|
end
|
|
|
|
end
|
|
|
|
|
2024-12-19 12:55:40 +01:00
|
|
|
-- check for further growth and set or stop timer
|
2020-10-26 17:38:53 +01:00
|
|
|
|
|
|
|
local function set_growing(pos, stages_left)
|
|
|
|
|
2024-12-19 12:55:40 +01:00
|
|
|
if not stages_left then return end
|
2020-10-26 17:38:53 +01:00
|
|
|
|
|
|
|
local timer = minetest.get_node_timer(pos)
|
|
|
|
|
|
|
|
if stages_left > 0 then
|
|
|
|
|
|
|
|
if not timer:is_started() then
|
|
|
|
|
|
|
|
local stage_length = statistics.normal(STAGE_LENGTH_AVG, STAGE_LENGTH_DEV)
|
|
|
|
|
|
|
|
stage_length = clamp(stage_length, 0.5 * STAGE_LENGTH_AVG, 3.0 * STAGE_LENGTH_AVG)
|
|
|
|
|
2024-12-19 12:55:40 +01:00
|
|
|
timer:set(stage_length, -0.5 * random() * STAGE_LENGTH_AVG)
|
2020-10-26 17:38:53 +01:00
|
|
|
end
|
|
|
|
|
|
|
|
elseif timer:is_started() then
|
|
|
|
timer:stop()
|
|
|
|
end
|
|
|
|
end
|
|
|
|
|
|
|
|
-- detects a crop at given position, starting or stopping growth timer when needed
|
2024-12-19 12:55:40 +01:00
|
|
|
|
2020-10-26 17:38:53 +01:00
|
|
|
function farming.handle_growth(pos, node)
|
|
|
|
|
2024-12-19 12:55:40 +01:00
|
|
|
if not pos then return end
|
2020-10-26 17:38:53 +01:00
|
|
|
|
|
|
|
local stages_left = register_plant_node(node or pos)
|
|
|
|
|
2024-12-19 12:55:40 +01:00
|
|
|
if stages_left then set_growing(pos, stages_left) end
|
2020-10-26 17:38:53 +01:00
|
|
|
end
|
|
|
|
|
2024-12-19 12:55:40 +01:00
|
|
|
-- register crops nodes and add timer functions
|
2020-10-26 17:38:53 +01:00
|
|
|
|
|
|
|
minetest.after(0, function()
|
|
|
|
|
|
|
|
for _, node_def in pairs(minetest.registered_nodes) do
|
|
|
|
register_plant_node(node_def)
|
|
|
|
end
|
|
|
|
end)
|
|
|
|
|
|
|
|
-- Just in case a growing type or added node is missed (also catches existing
|
|
|
|
-- nodes added to map before timers were incorporated).
|
2024-12-19 12:55:40 +01:00
|
|
|
|
2020-10-26 17:38:53 +01:00
|
|
|
minetest.register_abm({
|
2024-12-19 12:55:40 +01:00
|
|
|
label = "Start crop timer",
|
2020-10-26 17:38:53 +01:00
|
|
|
nodenames = {"group:growing"},
|
|
|
|
interval = 300,
|
|
|
|
chance = 1,
|
|
|
|
catch_up = false,
|
2024-12-19 12:55:40 +01:00
|
|
|
|
2020-10-26 17:38:53 +01:00
|
|
|
action = function(pos, node)
|
2024-12-19 12:55:40 +01:00
|
|
|
|
|
|
|
-- skip if node timer already active
|
|
|
|
if minetest.get_node_timer(pos):is_started() then return end
|
|
|
|
|
|
|
|
-- check if group:growing node is a seed
|
|
|
|
local def = minetest.registered_nodes[node.name]
|
|
|
|
|
|
|
|
if def and def.groups and def.groups.seed then
|
|
|
|
|
|
|
|
if def.on_timer then -- start node timer if found
|
|
|
|
|
|
|
|
farming.start_seed_timer(pos)
|
|
|
|
|
|
|
|
return
|
|
|
|
end
|
|
|
|
|
|
|
|
local next_stage = def.next_plant
|
|
|
|
|
|
|
|
def = minetest.registered_nodes[next_stage]
|
|
|
|
|
|
|
|
if def then -- switch seed without timer to stage_1 of crop
|
|
|
|
|
|
|
|
local p2 = def.place_param2 or 1
|
|
|
|
|
|
|
|
minetest.set_node(pos, {name = next_stage, param2 = p2})
|
|
|
|
end
|
|
|
|
else
|
|
|
|
farming.handle_growth(pos, node) -- start normal crop timer
|
|
|
|
end
|
2020-10-26 17:38:53 +01:00
|
|
|
end
|
|
|
|
})
|
|
|
|
|
2024-12-19 12:55:40 +01:00
|
|
|
-- default check crop is on wet soil
|
|
|
|
|
|
|
|
farming.can_grow = function(pos)
|
|
|
|
|
|
|
|
local below = minetest.get_node({x = pos.x, y = pos.y -1, z = pos.z})
|
|
|
|
|
|
|
|
return minetest.get_item_group(below.name, "soil") >= 3
|
|
|
|
end
|
2020-10-26 17:38:53 +01:00
|
|
|
|
|
|
|
-- Plant timer function that grows plants under the right conditions.
|
2024-12-19 12:55:40 +01:00
|
|
|
|
2020-10-26 17:38:53 +01:00
|
|
|
function farming.plant_growth_timer(pos, elapsed, node_name)
|
|
|
|
|
|
|
|
local stages = plant_stages[node_name]
|
|
|
|
|
2024-12-19 12:55:40 +01:00
|
|
|
if not stages then return false end
|
2020-10-26 17:38:53 +01:00
|
|
|
|
|
|
|
local max_growth = #stages.stages_left
|
|
|
|
|
2024-12-19 12:55:40 +01:00
|
|
|
if max_growth <= 0 then return false end
|
2020-10-26 17:38:53 +01:00
|
|
|
|
2024-12-19 12:55:40 +01:00
|
|
|
local chk1 = minetest.registered_nodes[node_name].growth_check -- old
|
|
|
|
local chk2 = minetest.registered_nodes[node_name].can_grow -- new
|
2020-10-26 17:38:53 +01:00
|
|
|
|
2024-12-19 12:55:40 +01:00
|
|
|
if chk1 then -- custom farming redo growth_check function
|
2020-10-26 17:38:53 +01:00
|
|
|
|
2024-12-19 12:55:40 +01:00
|
|
|
if not chk1(pos, node_name) then return true end
|
2020-10-26 17:38:53 +01:00
|
|
|
|
2024-12-19 12:55:40 +01:00
|
|
|
elseif chk2 then -- custom mt 5.9x farming can_grow function
|
2020-10-26 17:38:53 +01:00
|
|
|
|
2024-12-19 12:55:40 +01:00
|
|
|
if not chk2(pos) then return true end
|
|
|
|
|
|
|
|
-- default mt 5.9x farming.can_grow function
|
|
|
|
elseif not farming.can_grow(pos) then return true end
|
2020-10-26 17:38:53 +01:00
|
|
|
|
|
|
|
local growth
|
|
|
|
local light_pos = {x = pos.x, y = pos.y, z = pos.z}
|
|
|
|
local lambda = elapsed / STAGE_LENGTH_AVG
|
|
|
|
|
2024-12-19 12:55:40 +01:00
|
|
|
if lambda < 0.1 then return true end
|
2020-10-26 17:38:53 +01:00
|
|
|
|
2020-12-09 21:59:08 +01:00
|
|
|
local MIN_LIGHT = minetest.registered_nodes[node_name].minlight or farming.min_light
|
|
|
|
local MAX_LIGHT = minetest.registered_nodes[node_name].maxlight or farming.max_light
|
2020-10-26 17:38:53 +01:00
|
|
|
|
|
|
|
if max_growth == 1 or lambda < 2.0 then
|
|
|
|
|
|
|
|
local light = (minetest.get_node_light(light_pos) or 0)
|
|
|
|
|
2024-12-19 12:55:40 +01:00
|
|
|
if light < MIN_LIGHT or light > MAX_LIGHT then return true end
|
2020-10-26 17:38:53 +01:00
|
|
|
|
|
|
|
growth = 1
|
|
|
|
else
|
2024-12-19 12:55:40 +01:00
|
|
|
local night_light = (minetest.get_node_light(light_pos, 0) or 0)
|
|
|
|
local day_light = (minetest.get_node_light(light_pos, 0.5) or 0)
|
2020-10-26 17:38:53 +01:00
|
|
|
local night_growth = night_light >= MIN_LIGHT and night_light <= MAX_LIGHT
|
|
|
|
local day_growth = day_light >= MIN_LIGHT and day_light <= MAX_LIGHT
|
|
|
|
|
|
|
|
if not night_growth then
|
|
|
|
|
2024-12-19 12:55:40 +01:00
|
|
|
if not day_growth then return true end
|
2020-10-26 17:38:53 +01:00
|
|
|
|
|
|
|
lambda = day_or_night_time(elapsed, true) / STAGE_LENGTH_AVG
|
|
|
|
|
|
|
|
elseif not day_growth then
|
|
|
|
|
|
|
|
lambda = day_or_night_time(elapsed, false) / STAGE_LENGTH_AVG
|
|
|
|
end
|
|
|
|
|
|
|
|
growth = statistics.poisson(lambda, max_growth)
|
|
|
|
|
2024-12-19 12:55:40 +01:00
|
|
|
if growth < 1 then return true end
|
2020-10-26 17:38:53 +01:00
|
|
|
end
|
|
|
|
|
|
|
|
if minetest.registered_nodes[stages.stages_left[growth]] then
|
|
|
|
|
|
|
|
local p2 = minetest.registered_nodes[stages.stages_left[growth] ].place_param2 or 1
|
|
|
|
|
2024-12-19 12:55:40 +01:00
|
|
|
minetest.set_node(pos, {name = stages.stages_left[growth], param2 = p2})
|
2020-10-26 17:38:53 +01:00
|
|
|
else
|
|
|
|
return true
|
|
|
|
end
|
|
|
|
|
|
|
|
return growth ~= max_growth
|
|
|
|
end
|
|
|
|
|
|
|
|
-- refill placed plant by crabman (26/08/2015) updated by TenPlus1
|
2024-12-19 12:55:40 +01:00
|
|
|
|
2020-10-26 17:38:53 +01:00
|
|
|
function farming.refill_plant(player, plantname, index)
|
|
|
|
|
2024-12-19 12:55:40 +01:00
|
|
|
local inv = player and player:get_inventory() ; if not inv then return end
|
|
|
|
|
2020-10-26 17:38:53 +01:00
|
|
|
local old_stack = inv:get_stack("main", index)
|
|
|
|
|
2024-12-19 12:55:40 +01:00
|
|
|
if old_stack:get_name() ~= "" then return end
|
2020-10-26 17:38:53 +01:00
|
|
|
|
|
|
|
for i, stack in ipairs(inv:get_list("main")) do
|
|
|
|
|
|
|
|
if stack:get_name() == plantname and i ~= index then
|
|
|
|
|
|
|
|
inv:set_stack("main", index, stack)
|
|
|
|
stack:clear()
|
|
|
|
inv:set_stack("main", i, stack)
|
|
|
|
|
|
|
|
return
|
|
|
|
end
|
|
|
|
end
|
|
|
|
end
|
|
|
|
|
|
|
|
-- Place Seeds on Soil
|
2024-12-19 12:55:40 +01:00
|
|
|
|
2020-10-26 17:38:53 +01:00
|
|
|
function farming.place_seed(itemstack, placer, pointed_thing, plantname)
|
|
|
|
|
|
|
|
local pt = pointed_thing
|
|
|
|
|
|
|
|
-- check if pointing at a node
|
2024-12-19 12:55:40 +01:00
|
|
|
if not itemstack or not pt or pt.type ~= "node" then return end
|
2020-10-26 17:38:53 +01:00
|
|
|
|
|
|
|
local under = minetest.get_node(pt.under)
|
|
|
|
|
|
|
|
-- am I right-clicking on something that has a custom on_place set?
|
|
|
|
-- thanks to Krock for helping with this issue :)
|
|
|
|
local def = minetest.registered_nodes[under.name]
|
2024-12-19 12:55:40 +01:00
|
|
|
|
2020-10-26 17:38:53 +01:00
|
|
|
if placer and itemstack and def and def.on_rightclick then
|
2021-12-05 14:17:16 +01:00
|
|
|
return def.on_rightclick(pt.under, under, placer, itemstack, pt)
|
2020-10-26 17:38:53 +01:00
|
|
|
end
|
|
|
|
|
|
|
|
local above = minetest.get_node(pt.above)
|
|
|
|
|
|
|
|
-- check if pointing at the top of the node
|
2024-12-19 12:55:40 +01:00
|
|
|
if pt.above.y ~= pt.under.y + 1 then return end
|
2020-10-26 17:38:53 +01:00
|
|
|
|
|
|
|
-- return if any of the nodes is not registered
|
|
|
|
if not minetest.registered_nodes[under.name]
|
2024-12-19 12:55:40 +01:00
|
|
|
or not minetest.registered_nodes[above.name] then return end
|
2020-10-26 17:38:53 +01:00
|
|
|
|
2024-12-19 12:55:40 +01:00
|
|
|
-- can I replace above node, and am I pointing directly at soil
|
2020-10-26 17:38:53 +01:00
|
|
|
if not minetest.registered_nodes[above.name].buildable_to
|
|
|
|
or minetest.get_item_group(under.name, "soil") < 2
|
2024-12-19 12:55:40 +01:00
|
|
|
or minetest.get_item_group(above.name, "plant") ~= 0 then return end
|
2020-10-26 17:38:53 +01:00
|
|
|
|
|
|
|
-- is player planting seed?
|
|
|
|
local name = placer and placer:get_player_name() or ""
|
|
|
|
|
|
|
|
-- if not protected then add node and remove 1 item from the itemstack
|
|
|
|
if not minetest.is_protected(pt.above, name) then
|
|
|
|
|
|
|
|
local p2 = minetest.registered_nodes[plantname].place_param2 or 1
|
|
|
|
|
|
|
|
minetest.set_node(pt.above, {name = plantname, param2 = p2})
|
|
|
|
|
2024-12-19 12:55:40 +01:00
|
|
|
farming.start_seed_timer(pt.above)
|
2020-10-26 17:38:53 +01:00
|
|
|
|
|
|
|
minetest.sound_play("default_place_node", {pos = pt.above, gain = 1.0})
|
|
|
|
|
2024-12-19 12:55:40 +01:00
|
|
|
minetest.log("action", string.format("%s planted %s at %s",
|
|
|
|
(placer and placer:is_player() and placer:get_player_name() or "A mod"),
|
|
|
|
itemstack:get_name(), minetest.pos_to_string(pt.above)
|
|
|
|
))
|
|
|
|
|
2020-10-26 17:38:53 +01:00
|
|
|
if placer and itemstack
|
|
|
|
and not farming.is_creative(placer:get_player_name()) then
|
|
|
|
|
|
|
|
local name = itemstack:get_name()
|
|
|
|
|
|
|
|
itemstack:take_item()
|
|
|
|
|
|
|
|
-- check for refill
|
|
|
|
if itemstack:get_count() == 0 then
|
|
|
|
|
2024-12-19 12:55:40 +01:00
|
|
|
minetest.after(0.2, farming.refill_plant,
|
|
|
|
placer, name, placer:get_wield_index())
|
2020-10-26 17:38:53 +01:00
|
|
|
end
|
|
|
|
end
|
|
|
|
|
|
|
|
return itemstack
|
|
|
|
end
|
|
|
|
end
|
|
|
|
|
|
|
|
-- Function to register plants (default farming compatibility)
|
2024-12-19 12:55:40 +01:00
|
|
|
|
2020-10-26 17:38:53 +01:00
|
|
|
farming.register_plant = function(name, def)
|
|
|
|
|
2024-12-19 12:55:40 +01:00
|
|
|
if not def.steps then return nil end
|
2020-10-26 17:38:53 +01:00
|
|
|
|
|
|
|
local mname = name:split(":")[1]
|
|
|
|
local pname = name:split(":")[2]
|
|
|
|
|
|
|
|
-- Check def
|
|
|
|
def.description = def.description or S("Seed")
|
|
|
|
def.inventory_image = def.inventory_image or "unknown_item.png"
|
|
|
|
def.minlight = def.minlight or 12
|
|
|
|
def.maxlight = def.maxlight or 15
|
|
|
|
|
|
|
|
-- Register seed
|
|
|
|
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",
|
2024-12-19 12:55:40 +01:00
|
|
|
groups = {
|
|
|
|
seed = 1, snappy = 3, attached_node = 1, flammable = 2, growing = 1,
|
|
|
|
compostability = 65, handy = 1
|
|
|
|
},
|
|
|
|
_mcl_hardness = farming.mcl_hardness,
|
|
|
|
is_ground_content = false,
|
2020-10-26 17:38:53 +01:00
|
|
|
paramtype = "light",
|
|
|
|
paramtype2 = "wallmounted",
|
|
|
|
walkable = false,
|
|
|
|
sunlight_propagates = true,
|
|
|
|
selection_box = farming.select,
|
2024-12-19 12:55:40 +01:00
|
|
|
place_param2 = 1, -- place seed flat
|
2020-10-26 17:38:53 +01:00
|
|
|
next_plant = mname .. ":" .. pname .. "_1",
|
|
|
|
|
2024-12-19 12:55:40 +01:00
|
|
|
on_timer = function(pos, elapsed)
|
|
|
|
|
|
|
|
local def = minetest.registered_nodes[mname .. ":" .. pname .. "_1"]
|
|
|
|
|
|
|
|
if def then
|
|
|
|
minetest.swap_node(pos, {name = def.next_plant, param2 = def.place_param2})
|
|
|
|
end
|
2020-10-26 17:38:53 +01:00
|
|
|
end,
|
2024-12-19 12:55:40 +01:00
|
|
|
|
|
|
|
on_place = function(itemstack, placer, pointed_thing)
|
|
|
|
|
|
|
|
return farming.place_seed(itemstack, placer, pointed_thing,
|
|
|
|
mname .. ":seed_" .. pname)
|
|
|
|
end
|
2020-10-26 17:38:53 +01:00
|
|
|
})
|
|
|
|
|
|
|
|
-- Register harvest
|
|
|
|
minetest.register_craftitem(":" .. mname .. ":" .. pname, {
|
|
|
|
description = pname:gsub("^%l", string.upper),
|
|
|
|
inventory_image = mname .. "_" .. pname .. ".png",
|
|
|
|
groups = def.groups or {flammable = 2},
|
|
|
|
})
|
|
|
|
|
|
|
|
-- Register growing steps
|
|
|
|
for i = 1, def.steps do
|
|
|
|
|
|
|
|
local base_rarity = 1
|
2024-12-19 12:55:40 +01:00
|
|
|
|
2020-10-26 17:38:53 +01:00
|
|
|
if def.steps ~= 1 then
|
|
|
|
base_rarity = 8 - (i - 1) * 7 / (def.steps - 1)
|
|
|
|
end
|
2024-12-19 12:55:40 +01:00
|
|
|
|
2020-10-26 17:38:53 +01:00
|
|
|
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},
|
|
|
|
}
|
|
|
|
}
|
|
|
|
|
2024-12-19 12:55:40 +01:00
|
|
|
local sel = farming.select
|
2020-10-26 17:38:53 +01:00
|
|
|
local g = {
|
2024-12-19 12:55:40 +01:00
|
|
|
handy = 1, snappy = 3, flammable = 2, plant = 1, growing = 1,
|
2020-10-26 17:38:53 +01:00
|
|
|
attached_node = 1, not_in_creative_inventory = 1,
|
|
|
|
}
|
|
|
|
|
|
|
|
-- Last step doesn't need growing=1 so Abm never has to check these
|
2024-12-19 12:55:40 +01:00
|
|
|
-- also increase selection box for visual indication plant has matured
|
2020-10-26 17:38:53 +01:00
|
|
|
if i == def.steps then
|
2024-12-19 12:55:40 +01:00
|
|
|
sel = farming.select_final
|
2020-10-26 17:38:53 +01:00
|
|
|
g.growing = 0
|
|
|
|
end
|
|
|
|
|
|
|
|
local node_name = mname .. ":" .. pname .. "_" .. i
|
|
|
|
|
|
|
|
local next_plant = nil
|
|
|
|
|
|
|
|
if i < def.steps then
|
|
|
|
next_plant = mname .. ":" .. pname .. "_" .. (i + 1)
|
|
|
|
end
|
|
|
|
|
2024-12-19 12:55:40 +01:00
|
|
|
local desc = pname:gsub("^%l", string.upper)
|
|
|
|
|
2020-10-26 17:38:53 +01:00
|
|
|
minetest.register_node(node_name, {
|
2024-12-19 12:55:40 +01:00
|
|
|
description = S(desc) .. S(" Crop"),
|
2020-10-26 17:38:53 +01:00
|
|
|
drawtype = "plantlike",
|
|
|
|
waving = 1,
|
|
|
|
tiles = {mname .. "_" .. pname .. "_" .. i .. ".png"},
|
|
|
|
paramtype = "light",
|
|
|
|
paramtype2 = def.paramtype2,
|
|
|
|
place_param2 = def.place_param2,
|
|
|
|
walkable = false,
|
|
|
|
buildable_to = true,
|
|
|
|
sunlight_propagates = true,
|
|
|
|
drop = drop,
|
2024-12-19 12:55:40 +01:00
|
|
|
selection_box = sel,
|
2020-10-26 17:38:53 +01:00
|
|
|
groups = g,
|
2024-12-19 12:55:40 +01:00
|
|
|
_mcl_hardness = farming.mcl_hardness,
|
|
|
|
is_ground_content = false,
|
|
|
|
sounds = farming.node_sound_leaves_defaults(),
|
2020-10-26 17:38:53 +01:00
|
|
|
minlight = def.minlight,
|
|
|
|
maxlight = def.maxlight,
|
|
|
|
next_plant = next_plant
|
|
|
|
})
|
|
|
|
end
|
|
|
|
|
2024-12-19 12:55:40 +01:00
|
|
|
-- add to farming.registered_plants
|
|
|
|
farming.registered_plants[mname .. ":" .. pname] = {
|
|
|
|
crop = mname .. ":" .. pname,
|
|
|
|
seed = mname .. ":seed_" .. pname,
|
|
|
|
steps = def.steps,
|
|
|
|
minlight = def.minlight,
|
|
|
|
maxlight = def.maxlight
|
|
|
|
}
|
|
|
|
-- print(dump(farming.registered_plants[mname .. ":" .. pname]))
|
|
|
|
|
2020-10-26 17:38:53 +01:00
|
|
|
return {seed = mname .. ":seed_" .. pname, harvest = mname .. ":" .. pname}
|
|
|
|
end
|
|
|
|
|
|
|
|
-- default settings
|
2024-12-19 12:55:40 +01:00
|
|
|
|
|
|
|
farming.asparagus = 0.002
|
|
|
|
farming.eggplant = 0.002
|
|
|
|
farming.spinach = 0.002
|
|
|
|
farming.carrot = 0.002
|
|
|
|
farming.potato = 0.002
|
|
|
|
farming.tomato = 0.002
|
|
|
|
farming.cucumber = 0.002
|
|
|
|
farming.corn = 0.002
|
|
|
|
farming.coffee = 0.002
|
|
|
|
farming.melon = 0.009
|
|
|
|
farming.pumpkin = 0.009
|
2020-10-26 17:38:53 +01:00
|
|
|
farming.cocoa = true
|
2024-12-19 12:55:40 +01:00
|
|
|
farming.raspberry = 0.002
|
|
|
|
farming.blueberry = 0.002
|
|
|
|
farming.rhubarb = 0.002
|
|
|
|
farming.beans = 0.002
|
|
|
|
farming.grapes = 0.002
|
2020-10-26 17:38:53 +01:00
|
|
|
farming.barley = true
|
|
|
|
farming.chili = 0.003
|
|
|
|
farming.hemp = 0.003
|
2024-12-19 12:55:40 +01:00
|
|
|
farming.garlic = 0.002
|
|
|
|
farming.onion = 0.002
|
2020-10-26 17:38:53 +01:00
|
|
|
farming.pepper = 0.002
|
2024-12-19 12:55:40 +01:00
|
|
|
farming.pineapple = 0.003
|
|
|
|
farming.peas = 0.002
|
|
|
|
farming.beetroot = 0.002
|
2020-10-26 17:38:53 +01:00
|
|
|
farming.mint = 0.005
|
2024-12-19 12:55:40 +01:00
|
|
|
farming.cabbage = 0.002
|
2020-12-14 15:12:06 +01:00
|
|
|
farming.blackberry = 0.002
|
2024-12-19 12:55:40 +01:00
|
|
|
farming.soy = 0.002
|
|
|
|
farming.vanilla = 0.002
|
|
|
|
farming.lettuce = 0.002
|
|
|
|
farming.artichoke = 0.002
|
2021-03-17 20:30:38 +01:00
|
|
|
farming.parsley = 0.002
|
2024-12-19 12:55:40 +01:00
|
|
|
farming.sunflower = 0.002
|
|
|
|
farming.ginger = 0.002
|
|
|
|
farming.strawberry = 0.002
|
|
|
|
farming.cotton = 0.003
|
2020-10-26 17:38:53 +01:00
|
|
|
farming.grains = true
|
2021-12-05 14:17:16 +01:00
|
|
|
farming.rice = true
|
2020-10-26 17:38:53 +01:00
|
|
|
|
|
|
|
-- Load new global settings if found inside mod folder
|
2024-12-19 12:55:40 +01:00
|
|
|
|
|
|
|
local input = io.open(farming.path .. "/farming.conf", "r")
|
|
|
|
|
|
|
|
if input then dofile(farming.path .. "/farming.conf") ; input:close() end
|
2020-10-26 17:38:53 +01:00
|
|
|
|
|
|
|
-- load new world-specific settings if found inside world folder
|
2024-12-19 12:55:40 +01:00
|
|
|
|
2020-10-26 17:38:53 +01:00
|
|
|
local worldpath = minetest.get_worldpath()
|
2024-12-19 12:55:40 +01:00
|
|
|
|
|
|
|
input = io.open(worldpath .. "/farming.conf", "r")
|
|
|
|
|
|
|
|
if input then dofile(worldpath .. "/farming.conf") ; input:close() end
|
|
|
|
|
|
|
|
-- helper function to add {eatable} group to food items, also {flammable}
|
|
|
|
|
|
|
|
function farming.add_eatable(item, hp)
|
|
|
|
|
|
|
|
local def = minetest.registered_items[item]
|
|
|
|
|
|
|
|
if def then
|
|
|
|
|
|
|
|
local groups = table.copy(def.groups) or {}
|
|
|
|
|
|
|
|
groups.eatable = hp ; groups.flammable = 2
|
|
|
|
|
|
|
|
minetest.override_item(item, {groups = groups})
|
|
|
|
end
|
2020-10-26 17:38:53 +01:00
|
|
|
end
|
|
|
|
|
2024-12-19 12:55:40 +01:00
|
|
|
-- recipe item list and alternatives
|
|
|
|
|
|
|
|
dofile(farming.path .. "/item_list.lua")
|
|
|
|
|
|
|
|
-- setup soil, register hoes, override grass
|
|
|
|
|
|
|
|
if minetest.get_modpath("default") then
|
|
|
|
dofile(farming.path .. "/soil.lua")
|
|
|
|
dofile(farming.path .. "/hoes.lua")
|
|
|
|
end
|
2020-10-26 17:38:53 +01:00
|
|
|
|
|
|
|
dofile(farming.path.."/grass.lua")
|
|
|
|
|
2024-12-19 12:55:40 +01:00
|
|
|
-- disable crops Mineclone already has
|
|
|
|
|
|
|
|
if farming.mcl then
|
|
|
|
farming.carrot = nil
|
|
|
|
farming.potato = nil
|
|
|
|
farming.melon = nil
|
|
|
|
farming.cocoa = nil
|
|
|
|
farming.beetroot = nil
|
|
|
|
farming.sunflower = nil
|
|
|
|
farming.pumpkin = nil
|
|
|
|
else
|
|
|
|
dofile(farming.path.."/crops/wheat.lua") -- default crop outwith mineclone
|
|
|
|
end
|
2020-10-26 17:38:53 +01:00
|
|
|
|
2024-12-19 12:55:40 +01:00
|
|
|
dofile(farming.path.."/crops/cotton.lua") -- default crop
|
2020-10-26 17:38:53 +01:00
|
|
|
|
|
|
|
-- helper function
|
2024-12-19 12:55:40 +01:00
|
|
|
|
2020-10-26 17:38:53 +01:00
|
|
|
local function ddoo(file, check)
|
|
|
|
|
2024-12-19 12:55:40 +01:00
|
|
|
if check then dofile(farming.path .. "/crops/" .. file) end
|
2020-10-26 17:38:53 +01:00
|
|
|
end
|
|
|
|
|
|
|
|
-- add additional crops and food (if enabled)
|
|
|
|
ddoo("carrot.lua", farming.carrot)
|
|
|
|
ddoo("potato.lua", farming.potato)
|
|
|
|
ddoo("tomato.lua", farming.tomato)
|
|
|
|
ddoo("cucumber.lua", farming.cucumber)
|
|
|
|
ddoo("corn.lua", farming.corn)
|
|
|
|
ddoo("coffee.lua", farming.coffee)
|
|
|
|
ddoo("melon.lua", farming.melon)
|
|
|
|
ddoo("pumpkin.lua", farming.pumpkin)
|
|
|
|
ddoo("cocoa.lua", farming.cocoa)
|
|
|
|
ddoo("raspberry.lua", farming.raspberry)
|
|
|
|
ddoo("blueberry.lua", farming.blueberry)
|
|
|
|
ddoo("rhubarb.lua", farming.rhubarb)
|
|
|
|
ddoo("beans.lua", farming.beans)
|
|
|
|
ddoo("grapes.lua", farming.grapes)
|
|
|
|
ddoo("barley.lua", farming.barley)
|
|
|
|
ddoo("hemp.lua", farming.hemp)
|
|
|
|
ddoo("garlic.lua", farming.garlic)
|
|
|
|
ddoo("onion.lua", farming.onion)
|
|
|
|
ddoo("pepper.lua", farming.pepper)
|
|
|
|
ddoo("pineapple.lua", farming.pineapple)
|
|
|
|
ddoo("peas.lua", farming.peas)
|
|
|
|
ddoo("beetroot.lua", farming.beetroot)
|
|
|
|
ddoo("chili.lua", farming.chili)
|
2024-12-19 12:55:40 +01:00
|
|
|
ddoo("rye_oat.lua", farming.grains)
|
2021-12-05 14:17:16 +01:00
|
|
|
ddoo("rice.lua", farming.rice)
|
2020-10-26 17:38:53 +01:00
|
|
|
ddoo("mint.lua", farming.mint)
|
|
|
|
ddoo("cabbage.lua", farming.cabbage)
|
2020-12-14 15:12:06 +01:00
|
|
|
ddoo("blackberry.lua", farming.blackberry)
|
|
|
|
ddoo("soy.lua", farming.soy)
|
|
|
|
ddoo("vanilla.lua", farming.vanilla)
|
|
|
|
ddoo("lettuce.lua", farming.lettuce)
|
2021-03-17 20:30:38 +01:00
|
|
|
ddoo("artichoke.lua", farming.artichoke)
|
|
|
|
ddoo("parsley.lua", farming.parsley)
|
2021-10-02 11:55:17 +02:00
|
|
|
ddoo("sunflower.lua", farming.sunflower)
|
2024-12-19 12:55:40 +01:00
|
|
|
ddoo("strawberry.lua", farming.strawberry)
|
|
|
|
ddoo("asparagus.lua", farming.asparagus)
|
|
|
|
ddoo("eggplant.lua", farming.eggplant)
|
|
|
|
ddoo("spinach.lua", farming.eggplant)
|
|
|
|
ddoo("ginger.lua", farming.ginger)
|
|
|
|
|
|
|
|
-- register food items, non-food items, recipes and stairs
|
|
|
|
|
|
|
|
dofile(farming.path .. "/item_non_food.lua")
|
|
|
|
dofile(farming.path .. "/item_food.lua")
|
|
|
|
dofile(farming.path .. "/item_recipes.lua")
|
|
|
|
dofile(farming.path .. "/item_stairs.lua")
|
|
|
|
|
|
|
|
if not farming.mcl then
|
|
|
|
dofile(farming.path .. "/compatibility.lua") -- Farming Plus compatibility
|
|
|
|
end
|
|
|
|
|
|
|
|
if minetest.get_modpath("lucky_block") then
|
|
|
|
dofile(farming.path .. "/lucky_block.lua")
|
|
|
|
end
|
2020-10-26 17:38:53 +01:00
|
|
|
|
2024-12-19 12:55:40 +01:00
|
|
|
print("[MOD] Farming Redo loaded")
|