mirror of
https://github.com/sys4-fr/server-nalc.git
synced 2024-11-18 00:08:25 +01:00
Updated farming mod
- Introduced new grow routine to grow plants even with players being away from them
This commit is contained in:
parent
06d1bb053f
commit
752687e1e1
@ -13,6 +13,7 @@ This mod works by adding your new plant to the {growing=1} group and numbering t
|
|||||||
|
|
||||||
Changelog:
|
Changelog:
|
||||||
|
|
||||||
|
1.20 - NEW growing routine added that allows crops to grow while player is away doing other things (thanks prestidigitator)
|
||||||
1.14 - Added Green Beans from Crops mod (thanks sofar), little bushels in the wild but need to be grown using beanpoles crafted with 4 sticks (2 either side)
|
1.14 - Added Green Beans from Crops mod (thanks sofar), little bushels in the wild but need to be grown using beanpoles crafted with 4 sticks (2 either side)
|
||||||
1.13 - Fixed seed double-placement glitch. Mapgen now uses 0.4.12+ for plant generation
|
1.13 - Fixed seed double-placement glitch. Mapgen now uses 0.4.12+ for plant generation
|
||||||
1.12 - Player cannot place seeds in protected area, also growing speeds changed to match defaults
|
1.12 - Player cannot place seeds in protected area, also growing speeds changed to match defaults
|
||||||
|
@ -65,7 +65,7 @@ minetest.register_craft({
|
|||||||
}
|
}
|
||||||
})
|
})
|
||||||
|
|
||||||
-- Define Corn growth stages
|
-- Define Green Bean growth stages
|
||||||
|
|
||||||
minetest.register_node("farming:beanpole_1", {
|
minetest.register_node("farming:beanpole_1", {
|
||||||
drawtype = "plantlike",
|
drawtype = "plantlike",
|
||||||
@ -140,7 +140,7 @@ minetest.register_node("farming:beanpole_4", {
|
|||||||
sounds = default.node_sound_leaves_defaults(),
|
sounds = default.node_sound_leaves_defaults(),
|
||||||
})
|
})
|
||||||
|
|
||||||
-- Last stage of Corn growth doesnnot have growing=1 so abm never has to check these
|
-- Last stage of Green Bean growth does not have growing=1 so abm never has to check these
|
||||||
|
|
||||||
minetest.register_node("farming:beanpole_5", {
|
minetest.register_node("farming:beanpole_5", {
|
||||||
drawtype = "plantlike",
|
drawtype = "plantlike",
|
||||||
|
@ -66,7 +66,7 @@ minetest.register_craft( {
|
|||||||
minetest.register_craftitem("farming:chocolate_dark", {
|
minetest.register_craftitem("farming:chocolate_dark", {
|
||||||
description = "Bar of Dark Chocolate",
|
description = "Bar of Dark Chocolate",
|
||||||
inventory_image = "farming_chocolate_dark.png",
|
inventory_image = "farming_chocolate_dark.png",
|
||||||
on_use = minetest.item_eat(2),
|
on_use = minetest.item_eat(2), --/MFF (Mg|05/26/2015)
|
||||||
})
|
})
|
||||||
|
|
||||||
minetest.register_craft( {
|
minetest.register_craft( {
|
||||||
|
@ -42,6 +42,7 @@ minetest.register_craft({
|
|||||||
{"farming:string", "farming:string", "farming:string"},
|
{"farming:string", "farming:string", "farming:string"},
|
||||||
{"farming:string", "farming:string", "farming:string"},
|
{"farming:string", "farming:string", "farming:string"},
|
||||||
{"farming:string", "farming:string", "farming:string"},
|
{"farming:string", "farming:string", "farming:string"},
|
||||||
|
-- ^ /MFF (Mg|05/26/2015)
|
||||||
}
|
}
|
||||||
})
|
})
|
||||||
|
|
||||||
|
@ -1,6 +1,7 @@
|
|||||||
--[[
|
--[[
|
||||||
Minetest Farming Redo Mod 1.14 (11th May 2015)
|
Minetest Farming Redo Mod 1.20 (20th May 2015)
|
||||||
by TenPlus1
|
by TenPlus1
|
||||||
|
NEW growing routine by prestidigitator
|
||||||
]]
|
]]
|
||||||
|
|
||||||
farming = {}
|
farming = {}
|
||||||
@ -8,6 +9,39 @@ farming.mod = "redo"
|
|||||||
farming.path = minetest.get_modpath("farming")
|
farming.path = minetest.get_modpath("farming")
|
||||||
farming.hoe_on_use = default.hoe_on_use
|
farming.hoe_on_use = default.hoe_on_use
|
||||||
|
|
||||||
|
farming.DEBUG = false
|
||||||
|
-- farming.DEBUG = {} -- Uncomment to turn on profiling code/functions
|
||||||
|
|
||||||
|
local DEBUG_abm_runs = 0
|
||||||
|
local DEBUG_abm_time = 0
|
||||||
|
local DEBUG_timer_runs = 0
|
||||||
|
local DEBUG_timer_time = 0
|
||||||
|
if farming.DEBUG then
|
||||||
|
function farming.DEBUG.reset_times()
|
||||||
|
DEBUG_abm_runs = 0
|
||||||
|
DEBUG_abm_time = 0
|
||||||
|
DEBUG_timer_runs = 0
|
||||||
|
DEBUG_timer_time = 0
|
||||||
|
end
|
||||||
|
|
||||||
|
function farming.DEBUG.report_times()
|
||||||
|
local abm_n = DEBUG_abm_runs
|
||||||
|
local abm_dt = DEBUG_abm_time
|
||||||
|
local abm_avg = (abm_n > 0 and abm_dt / abm_n) or 0
|
||||||
|
local timer_n = DEBUG_timer_runs
|
||||||
|
local timer_dt = DEBUG_timer_time
|
||||||
|
local timer_avg = (timer_n > 0 and timer_dt / timer_n) or 0
|
||||||
|
local dt = abm_dt + timer_dt
|
||||||
|
print("ABM ran for "..abm_dt.."µs over "..abm_n.." runs: "..
|
||||||
|
abm_avg.."µs/run")
|
||||||
|
print("Timer ran for "..timer_dt.."µs over "..timer_n.." runs: "..
|
||||||
|
timer_avg.."µs/run")
|
||||||
|
print("Total farming time: "..dt.."µs")
|
||||||
|
end
|
||||||
|
else
|
||||||
|
end
|
||||||
|
|
||||||
|
local statistics = dofile(farming.path.."/statistics.lua")
|
||||||
dofile(farming.path.."/soil.lua")
|
dofile(farming.path.."/soil.lua")
|
||||||
dofile(farming.path.."/hoes.lua")
|
dofile(farming.path.."/hoes.lua")
|
||||||
dofile(farming.path.."/grass.lua")
|
dofile(farming.path.."/grass.lua")
|
||||||
@ -31,6 +65,319 @@ dofile(farming.path.."/donut.lua")
|
|||||||
dofile(farming.path.."/mapgen.lua")
|
dofile(farming.path.."/mapgen.lua")
|
||||||
dofile(farming.path.."/compatibility.lua") -- Farming Plus compatibility
|
dofile(farming.path.."/compatibility.lua") -- Farming Plus compatibility
|
||||||
|
|
||||||
|
-- Utility Functions
|
||||||
|
|
||||||
|
local time_speed = tonumber(minetest.setting_get("time_speed")) or 72
|
||||||
|
local SECS_PER_CYCLE = (time_speed > 0 and 24 * 60 * 60/time_speed) or nil
|
||||||
|
|
||||||
|
local function clamp(x, min, max)
|
||||||
|
return (x < min and min) or (x > max and max) or x
|
||||||
|
end
|
||||||
|
|
||||||
|
local function in_range(x, min, max)
|
||||||
|
return min <= x and x <= max
|
||||||
|
end
|
||||||
|
|
||||||
|
--- Tests the amount of day or night time between two times.
|
||||||
|
--
|
||||||
|
-- @param t_game
|
||||||
|
-- The current time, as reported by mintest.get_gametime().
|
||||||
|
-- @param t_day
|
||||||
|
-- The current time, as reported by mintest.get_timeofday().
|
||||||
|
-- @param dt
|
||||||
|
-- The amount of elapsed time.
|
||||||
|
-- @param count_day
|
||||||
|
-- If true, count elapsed day time. Otherwise, count elapsed night time.
|
||||||
|
-- @return
|
||||||
|
-- The amount of day or night time that has elapsed.
|
||||||
|
--
|
||||||
|
local function day_or_night_time(t_game, t_day, dt, count_day)
|
||||||
|
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
|
||||||
|
local nc = math.floor(-t1_c)
|
||||||
|
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
|
||||||
|
|
||||||
|
--- Tests the amount of elapsed day time.
|
||||||
|
--
|
||||||
|
-- @param dt
|
||||||
|
-- The amount of elapsed time.
|
||||||
|
-- @return
|
||||||
|
-- The amount of day time that has elapsed.
|
||||||
|
--
|
||||||
|
local function day_time(dt)
|
||||||
|
return day_or_night_time(minetest.get_gametime(), minetest.get_timeofday(), dt, true)
|
||||||
|
end
|
||||||
|
|
||||||
|
--- Tests the amount of elapsed night time.
|
||||||
|
--
|
||||||
|
-- @param dt
|
||||||
|
-- The amount of elapsed time.
|
||||||
|
-- @return
|
||||||
|
-- The amount of night time that has elapsed.
|
||||||
|
--
|
||||||
|
local function night_time(time_game, time_day, dt, count_day)
|
||||||
|
return day_or_night_time(minetest.get_gametime(), minetest.get_timeofday(), dt, false)
|
||||||
|
end
|
||||||
|
|
||||||
|
|
||||||
|
-- Growth Logic
|
||||||
|
|
||||||
|
local STAGE_LENGTH_AVG = 160.0
|
||||||
|
local STAGE_LENGTH_DEV = STAGE_LENGTH_AVG / 6
|
||||||
|
local MIN_LIGHT = 13
|
||||||
|
local MAX_LIGHT = 1000
|
||||||
|
|
||||||
|
--- Determines plant name and stage from node.
|
||||||
|
--
|
||||||
|
-- Separates node name on the last underscore (_).
|
||||||
|
--
|
||||||
|
-- @param node
|
||||||
|
-- Node or position table, or node name.
|
||||||
|
-- @return
|
||||||
|
-- List (plant_name, stage), or nothing (nil) if node isn't loaded
|
||||||
|
--
|
||||||
|
local function plant_name_stage(node)
|
||||||
|
local name
|
||||||
|
if type(node) == 'table' then
|
||||||
|
if node.name then
|
||||||
|
name = node.name
|
||||||
|
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
|
||||||
|
if not name or name == "ignore" then return nil end
|
||||||
|
|
||||||
|
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.
|
||||||
|
--
|
||||||
|
-- @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.
|
||||||
|
--
|
||||||
|
local register_plant_node
|
||||||
|
-- Recursive helper
|
||||||
|
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]
|
||||||
|
if not node_def then return nil end
|
||||||
|
|
||||||
|
local stages = plant_stages[node_name]
|
||||||
|
if stages then return stages end
|
||||||
|
|
||||||
|
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
|
||||||
|
minetest.override_item(node_name,
|
||||||
|
{
|
||||||
|
on_construct = function(pos)
|
||||||
|
if old_constr then old_constr(pos) end
|
||||||
|
farming.handle_growth(pos)
|
||||||
|
end,
|
||||||
|
|
||||||
|
on_destruct = function(pos)
|
||||||
|
minetest.get_node_timer(pos):stop()
|
||||||
|
if old_destr then old_destr(pos) end
|
||||||
|
end,
|
||||||
|
|
||||||
|
on_timer = function(pos, elapsed)
|
||||||
|
return farming.plant_growth_timer(pos, elapsed, node_name)
|
||||||
|
end,
|
||||||
|
})
|
||||||
|
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
|
||||||
|
|
||||||
|
register_plant_node = function(node)
|
||||||
|
local plant_name, stage = plant_name_stage(node)
|
||||||
|
if plant_name then
|
||||||
|
local stages = reg_plant_stages(plant_name, stage, false)
|
||||||
|
return stages and #stages.stages_left
|
||||||
|
else
|
||||||
|
return nil
|
||||||
|
end
|
||||||
|
end
|
||||||
|
|
||||||
|
local function set_growing(pos, stages_left)
|
||||||
|
if not stages_left then return end
|
||||||
|
|
||||||
|
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)
|
||||||
|
timer:set(stage_length, -0.5 * math.random() * STAGE_LENGTH_AVG)
|
||||||
|
end
|
||||||
|
elseif timer:is_started() then
|
||||||
|
timer:stop()
|
||||||
|
end
|
||||||
|
end
|
||||||
|
|
||||||
|
--- Detects a plant type node at the given position, starting or stopping the plant growth timer as appopriate
|
||||||
|
--
|
||||||
|
-- @param pos
|
||||||
|
-- The node's position.
|
||||||
|
-- @param node
|
||||||
|
-- The cached node table if available, or nil.
|
||||||
|
--
|
||||||
|
function farming.handle_growth(pos, node)
|
||||||
|
if not pos then return end
|
||||||
|
local stages_left = register_plant_node(node or pos)
|
||||||
|
if stages_left then set_growing(pos, stages_left) end
|
||||||
|
end
|
||||||
|
|
||||||
|
minetest.after(0,
|
||||||
|
function()
|
||||||
|
for _, node_def in pairs(minetest.registered_nodes) do
|
||||||
|
register_plant_node(node_def)
|
||||||
|
end
|
||||||
|
end)
|
||||||
|
|
||||||
|
local abm_func = farming.handle_growth
|
||||||
|
if farming.DEBUG then
|
||||||
|
local normal_abm_func = abm_func
|
||||||
|
abm_func = function(...)
|
||||||
|
local t0 = minetest.get_us_time()
|
||||||
|
local r = { normal_abm_func(...) }
|
||||||
|
local t1 = minetest.get_us_time()
|
||||||
|
DEBUG_abm_runs = DEBUG_abm_runs + 1
|
||||||
|
DEBUG_abm_time = DEBUG_abm_time + (t1 - t0)
|
||||||
|
return unpack(r)
|
||||||
|
end
|
||||||
|
end
|
||||||
|
|
||||||
|
-- Just in case a growing type or added node is missed (also catches existing
|
||||||
|
-- nodes added to map before timers were incorporated).
|
||||||
|
minetest.register_abm({
|
||||||
|
nodenames = { "group:growing" },
|
||||||
|
interval = 300,
|
||||||
|
chance = 1,
|
||||||
|
action = abm_func})
|
||||||
|
|
||||||
|
--- Plant timer function.
|
||||||
|
--
|
||||||
|
-- Grows plants under the right conditions.
|
||||||
|
--
|
||||||
|
function farming.plant_growth_timer(pos, elapsed, node_name)
|
||||||
|
local stages = plant_stages[node_name]
|
||||||
|
if not stages then return false end
|
||||||
|
|
||||||
|
local max_growth = #stages.stages_left
|
||||||
|
if max_growth <= 0 then return false end
|
||||||
|
|
||||||
|
if stages.plant_name == "farming:cocoa" then
|
||||||
|
if not minetest.find_node_near(pos, 1, { "default:jungletree", "moretrees:jungletree_leaves_green" }) then
|
||||||
|
return true
|
||||||
|
end
|
||||||
|
else
|
||||||
|
local under = minetest.get_node_or_nil({ x = pos.x, y = pos.y - 1, z = pos.z })
|
||||||
|
if not under or under.name ~= "farming:soil_wet" then return true end
|
||||||
|
end
|
||||||
|
|
||||||
|
local growth
|
||||||
|
|
||||||
|
local light_pos = { x = pos.x, y = pos.y + 1, z = pos.z }
|
||||||
|
local lambda = elapsed / STAGE_LENGTH_AVG
|
||||||
|
if lambda < 0.1 then return true end
|
||||||
|
if max_growth == 1 or lambda < 2.0 then
|
||||||
|
local light = (minetest.get_node_light(light_pos) or 0) -- CHANGED
|
||||||
|
if not in_range(light, MIN_LIGHT, MAX_LIGHT) then return true end
|
||||||
|
growth = 1
|
||||||
|
else
|
||||||
|
local night_light = (minetest.get_node_light(light_pos, 0) or 0) -- CHANGED
|
||||||
|
local day_light = (minetest.get_node_light(light_pos, 0.5) or 0) -- ChANGED
|
||||||
|
local night_growth = in_range(night_light, MIN_LIGHT, MAX_LIGHT)
|
||||||
|
local day_growth = in_range(day_light, MIN_LIGHT, MAX_LIGHT)
|
||||||
|
|
||||||
|
if not night_growth then
|
||||||
|
if not day_growth then return true end
|
||||||
|
lambda = day_time(elapsed) / STAGE_LENGTH_AVG
|
||||||
|
elseif not day_growth then
|
||||||
|
lambda = night_time(elapsed) / STAGE_LENGTH_AVG
|
||||||
|
end
|
||||||
|
|
||||||
|
growth = statistics.poisson(lambda, max_growth)
|
||||||
|
if growth < 1 then return true end
|
||||||
|
end
|
||||||
|
|
||||||
|
minetest.swap_node(pos, { name = stages.stages_left[growth] })
|
||||||
|
|
||||||
|
return growth ~= max_growth
|
||||||
|
end
|
||||||
|
|
||||||
|
if farming.DEBUG then
|
||||||
|
local timer_func = farming.plant_growth_timer;
|
||||||
|
farming.plant_growth_timer = function(pos, elapsed, node_name)
|
||||||
|
local t0 = minetest.get_us_time()
|
||||||
|
|
||||||
|
local r = { timer_func(pos, elapsed, node_name) }
|
||||||
|
|
||||||
|
local t1 = minetest.get_us_time()
|
||||||
|
DEBUG_timer_runs = DEBUG_timer_runs + 1
|
||||||
|
DEBUG_timer_time = DEBUG_timer_time + (t1 - t0)
|
||||||
|
return unpack(r)
|
||||||
|
end
|
||||||
|
end
|
||||||
|
|
||||||
|
|
||||||
-- Place Seeds on Soil
|
-- Place Seeds on Soil
|
||||||
|
|
||||||
function farming.place_seed(itemstack, placer, pointed_thing, plantname)
|
function farming.place_seed(itemstack, placer, pointed_thing, plantname)
|
||||||
@ -72,38 +419,6 @@ function farming.place_seed(itemstack, placer, pointed_thing, plantname)
|
|||||||
end
|
end
|
||||||
end
|
end
|
||||||
|
|
||||||
-- Single ABM Handles Growing of All Plants
|
|
||||||
|
|
||||||
minetest.register_abm({
|
|
||||||
nodenames = {"group:growing"},
|
|
||||||
neighbors = {"farming:soil_wet", "default:jungletree"},
|
|
||||||
interval = 80,
|
|
||||||
chance = 2,
|
|
||||||
|
|
||||||
action = function(pos, node)
|
|
||||||
|
|
||||||
-- split plant name (e.g. farming:wheat_1)
|
|
||||||
local plant = node.name:split("_")[1].."_"
|
|
||||||
local numb = node.name:split("_")[2]
|
|
||||||
|
|
||||||
-- fully grown ?
|
|
||||||
if not minetest.registered_nodes[plant..(numb + 1)] then return end
|
|
||||||
|
|
||||||
-- cocoa pod on jungle tree ?
|
|
||||||
if plant ~= "farming:cocoa_" then
|
|
||||||
|
|
||||||
-- growing on wet soil ?
|
|
||||||
if minetest.get_node({x=pos.x,y=pos.y-1,z=pos.z}).name ~= "farming:soil_wet" then return end
|
|
||||||
end
|
|
||||||
|
|
||||||
-- enough light ?
|
|
||||||
if minetest.get_node_light(pos) < 13 then return end
|
|
||||||
|
|
||||||
-- grow
|
|
||||||
minetest.set_node(pos, {name=plant..(numb + 1)})
|
|
||||||
|
|
||||||
end
|
|
||||||
})
|
|
||||||
|
|
||||||
-- Function to register plants (for compatibility)
|
-- Function to register plants (for compatibility)
|
||||||
|
|
||||||
@ -163,7 +478,8 @@ farming.register_plant = function(name, def)
|
|||||||
g = {snappy = 3, flammable = 2, plant = 1, not_in_creative_inventory = 1, attached_node = 1}
|
g = {snappy = 3, flammable = 2, plant = 1, not_in_creative_inventory = 1, attached_node = 1}
|
||||||
end
|
end
|
||||||
|
|
||||||
minetest.register_node(mname .. ":" .. pname .. "_" .. i, {
|
local node_name = mname .. ":" .. pname .. "_" .. i
|
||||||
|
minetest.register_node(node_name, {
|
||||||
drawtype = "plantlike",
|
drawtype = "plantlike",
|
||||||
waving = 1,
|
waving = 1,
|
||||||
tiles = {mname .. "_" .. pname .. "_" .. i .. ".png"},
|
tiles = {mname .. "_" .. pname .. "_" .. i .. ".png"},
|
||||||
@ -176,6 +492,7 @@ farming.register_plant = function(name, def)
|
|||||||
groups = g,
|
groups = g,
|
||||||
sounds = default.node_sound_leaves_defaults(),
|
sounds = default.node_sound_leaves_defaults(),
|
||||||
})
|
})
|
||||||
|
register_plant_node(node_name)
|
||||||
end
|
end
|
||||||
|
|
||||||
-- Return info
|
-- Return info
|
||||||
|
192
mods/farming/init.lua_orig
Normal file
192
mods/farming/init.lua_orig
Normal file
@ -0,0 +1,192 @@
|
|||||||
|
--[[
|
||||||
|
Minetest Farming Redo Mod 1.14 (11th May 2015)
|
||||||
|
by TenPlus1
|
||||||
|
]]
|
||||||
|
|
||||||
|
farming = {}
|
||||||
|
farming.mod = "redo"
|
||||||
|
farming.path = minetest.get_modpath("farming")
|
||||||
|
farming.hoe_on_use = default.hoe_on_use
|
||||||
|
|
||||||
|
dofile(farming.path.."/soil.lua")
|
||||||
|
dofile(farming.path.."/hoes.lua")
|
||||||
|
dofile(farming.path.."/grass.lua")
|
||||||
|
dofile(farming.path.."/wheat.lua")
|
||||||
|
dofile(farming.path.."/cotton.lua")
|
||||||
|
dofile(farming.path.."/carrot.lua")
|
||||||
|
dofile(farming.path.."/potato.lua")
|
||||||
|
dofile(farming.path.."/tomato.lua")
|
||||||
|
dofile(farming.path.."/cucumber.lua")
|
||||||
|
dofile(farming.path.."/corn.lua")
|
||||||
|
dofile(farming.path.."/coffee.lua")
|
||||||
|
dofile(farming.path.."/melon.lua")
|
||||||
|
dofile(farming.path.."/sugar.lua")
|
||||||
|
dofile(farming.path.."/pumpkin.lua")
|
||||||
|
dofile(farming.path.."/cocoa.lua")
|
||||||
|
dofile(farming.path.."/raspberry.lua")
|
||||||
|
dofile(farming.path.."/blueberry.lua")
|
||||||
|
dofile(farming.path.."/rhubarb.lua")
|
||||||
|
dofile(farming.path.."/beanpole.lua")
|
||||||
|
dofile(farming.path.."/donut.lua")
|
||||||
|
dofile(farming.path.."/mapgen.lua")
|
||||||
|
dofile(farming.path.."/compatibility.lua") -- Farming Plus compatibility
|
||||||
|
|
||||||
|
-- Place Seeds on Soil
|
||||||
|
|
||||||
|
function farming.place_seed(itemstack, placer, pointed_thing, plantname)
|
||||||
|
local pt = pointed_thing
|
||||||
|
|
||||||
|
-- check if pointing at a node
|
||||||
|
if not pt and pt.type ~= "node" then
|
||||||
|
return
|
||||||
|
end
|
||||||
|
|
||||||
|
local under = minetest.get_node(pt.under)
|
||||||
|
local above = minetest.get_node(pt.above)
|
||||||
|
|
||||||
|
-- check if pointing at the top of the node
|
||||||
|
if pt.above.y ~= pt.under.y+1 then
|
||||||
|
return
|
||||||
|
end
|
||||||
|
|
||||||
|
-- return if any of the nodes is not registered
|
||||||
|
if not minetest.registered_nodes[under.name]
|
||||||
|
or not minetest.registered_nodes[above.name] then
|
||||||
|
return
|
||||||
|
end
|
||||||
|
|
||||||
|
-- can I replace above node, and am I pointing at soil
|
||||||
|
if not minetest.registered_nodes[above.name].buildable_to
|
||||||
|
or minetest.get_item_group(under.name, "soil") < 2
|
||||||
|
or minetest.get_item_group(above.name, "plant") ~= 0 then -- ADDED this line for multiple seed placement bug
|
||||||
|
return
|
||||||
|
end
|
||||||
|
|
||||||
|
-- add the node and remove 1 item from the itemstack
|
||||||
|
if not minetest.is_protected(pt.above, placer:get_player_name()) then
|
||||||
|
minetest.add_node(pt.above, {name=plantname})
|
||||||
|
if not minetest.setting_getbool("creative_mode") then
|
||||||
|
itemstack:take_item()
|
||||||
|
end
|
||||||
|
return itemstack
|
||||||
|
end
|
||||||
|
end
|
||||||
|
|
||||||
|
-- Single ABM Handles Growing of All Plants
|
||||||
|
|
||||||
|
minetest.register_abm({
|
||||||
|
nodenames = {"group:growing"},
|
||||||
|
neighbors = {"farming:soil_wet", "default:jungletree"},
|
||||||
|
interval = 80,
|
||||||
|
chance = 2,
|
||||||
|
|
||||||
|
action = function(pos, node)
|
||||||
|
|
||||||
|
-- split plant name (e.g. farming:wheat_1)
|
||||||
|
local plant = node.name:split("_")[1].."_"
|
||||||
|
local numb = node.name:split("_")[2]
|
||||||
|
|
||||||
|
-- fully grown ?
|
||||||
|
if not minetest.registered_nodes[plant..(numb + 1)] then return end
|
||||||
|
|
||||||
|
-- cocoa pod on jungle tree ?
|
||||||
|
if plant ~= "farming:cocoa_" then
|
||||||
|
|
||||||
|
-- growing on wet soil ?
|
||||||
|
if minetest.get_node({x=pos.x,y=pos.y-1,z=pos.z}).name ~= "farming:soil_wet" then return end
|
||||||
|
end
|
||||||
|
|
||||||
|
-- enough light ?
|
||||||
|
if minetest.get_node_light(pos) < 13 then return end
|
||||||
|
|
||||||
|
-- grow
|
||||||
|
minetest.set_node(pos, {name=plant..(numb + 1)})
|
||||||
|
|
||||||
|
end
|
||||||
|
})
|
||||||
|
|
||||||
|
-- Function to register plants (for compatibility)
|
||||||
|
|
||||||
|
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
|
||||||
|
|
||||||
|
-- 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",
|
||||||
|
groups = {seed = 1, snappy = 3, attached_node = 1},
|
||||||
|
paramtype = "light",
|
||||||
|
paramtype2 = "wallmounted",
|
||||||
|
walkable = false,
|
||||||
|
sunlight_propagates = true,
|
||||||
|
selection_box = {type = "fixed", fixed = {-0.5, -0.5, -0.5, 0.5, -5/16, 0.5},},
|
||||||
|
on_place = function(itemstack, placer, pointed_thing)
|
||||||
|
return farming.place_seed(itemstack, placer, pointed_thing, mname .. ":"..pname.."_1")
|
||||||
|
end
|
||||||
|
})
|
||||||
|
|
||||||
|
-- Register harvest
|
||||||
|
minetest.register_craftitem(":" .. mname .. ":" .. pname, {
|
||||||
|
description = pname:gsub("^%l", string.upper),
|
||||||
|
inventory_image = mname .. "_" .. pname .. ".png",
|
||||||
|
})
|
||||||
|
|
||||||
|
-- Register growing steps
|
||||||
|
for i=1,def.steps do
|
||||||
|
local drop = {
|
||||||
|
items = {
|
||||||
|
{items = {mname .. ":" .. pname}, rarity = 9 - i},
|
||||||
|
{items = {mname .. ":" .. pname}, rarity= 18 - i * 2},
|
||||||
|
{items = {mname .. ":seed_" .. pname}, rarity = 9 - i},
|
||||||
|
{items = {mname .. ":seed_" .. pname}, rarity = 18 - i * 2},
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
local g = {snappy = 3, flammable = 2, plant = 1, not_in_creative_inventory = 1, attached_node = 1, growing = 1}
|
||||||
|
-- Last step doesn't need growing=1 so Abm never has to check these
|
||||||
|
if i == def.steps then
|
||||||
|
g = {snappy = 3, flammable = 2, plant = 1, not_in_creative_inventory = 1, attached_node = 1}
|
||||||
|
end
|
||||||
|
|
||||||
|
minetest.register_node(mname .. ":" .. pname .. "_" .. i, {
|
||||||
|
drawtype = "plantlike",
|
||||||
|
waving = 1,
|
||||||
|
tiles = {mname .. "_" .. pname .. "_" .. i .. ".png"},
|
||||||
|
paramtype = "light",
|
||||||
|
walkable = false,
|
||||||
|
buildable_to = true,
|
||||||
|
is_ground_content = true,
|
||||||
|
drop = drop,
|
||||||
|
selection_box = {type = "fixed", fixed = {-0.5, -0.5, -0.5, 0.5, -5/16, 0.5},},
|
||||||
|
groups = g,
|
||||||
|
sounds = default.node_sound_leaves_defaults(),
|
||||||
|
})
|
||||||
|
end
|
||||||
|
|
||||||
|
-- Return info
|
||||||
|
local r = {seed = mname .. ":seed_" .. pname, harvest = mname .. ":" .. pname}
|
||||||
|
return r
|
||||||
|
end
|
||||||
|
|
||||||
|
--[[ Cotton (example, is already registered in cotton.lua)
|
||||||
|
farming.register_plant("farming:cotton", {
|
||||||
|
description = "Cotton seed",
|
||||||
|
inventory_image = "farming_cotton_seed.png",
|
||||||
|
steps = 8,
|
||||||
|
})
|
||||||
|
--]]
|
@ -1,8 +1,4 @@
|
|||||||
|
-- normal soil
|
||||||
--= Soil Functions
|
|
||||||
|
|
||||||
-- Normal Soil
|
|
||||||
|
|
||||||
minetest.register_node("farming:soil", {
|
minetest.register_node("farming:soil", {
|
||||||
description = "Soil",
|
description = "Soil",
|
||||||
tiles = {"farming_soil.png", "default_dirt.png"},
|
tiles = {"farming_soil.png", "default_dirt.png"},
|
||||||
@ -11,10 +7,11 @@ minetest.register_node("farming:soil", {
|
|||||||
groups = {crumbly=3, not_in_creative_inventory=1, soil=2},
|
groups = {crumbly=3, not_in_creative_inventory=1, soil=2},
|
||||||
sounds = default.node_sound_dirt_defaults(),
|
sounds = default.node_sound_dirt_defaults(),
|
||||||
})
|
})
|
||||||
|
|
||||||
|
-- sand is not soil, change existing sand-soil to use normal soil
|
||||||
minetest.register_alias("farming:desert_sand_soil", "farming:soil")
|
minetest.register_alias("farming:desert_sand_soil", "farming:soil")
|
||||||
|
|
||||||
-- Wet Soil
|
-- wet soil
|
||||||
|
|
||||||
minetest.register_node("farming:soil_wet", {
|
minetest.register_node("farming:soil_wet", {
|
||||||
description = "Wet Soil",
|
description = "Wet Soil",
|
||||||
tiles = {"farming_soil_wet.png", "farming_soil_wet_side.png"},
|
tiles = {"farming_soil_wet.png", "farming_soil_wet_side.png"},
|
||||||
@ -25,23 +22,21 @@ minetest.register_node("farming:soil_wet", {
|
|||||||
})
|
})
|
||||||
minetest.register_alias("farming:desert_sand_soil_wet", "farming:soil_wet")
|
minetest.register_alias("farming:desert_sand_soil_wet", "farming:soil_wet")
|
||||||
|
|
||||||
-- If Water near Soil then turn into Wet Soil
|
-- if water near soil then change to wet soil
|
||||||
|
|
||||||
minetest.register_abm({
|
minetest.register_abm({
|
||||||
nodenames = {"farming:soil", "farming:soil_wet"},
|
nodenames = {"farming:soil", "farming:soil_wet"},
|
||||||
interval = 15,
|
interval = 15,
|
||||||
chance = 4,
|
chance = 4,
|
||||||
action = function(pos, node)
|
action = function(pos, node)
|
||||||
|
|
||||||
pos.y = pos.y+1
|
local nn = minetest.get_node({x=pos.x,y=pos.y+1,z=pos.z}).name
|
||||||
local nn = minetest.get_node(pos).name
|
|
||||||
pos.y = pos.y-1
|
|
||||||
|
|
||||||
-- what's on top of soil, if solid/not plant change soil to dirt
|
-- what's on top of soil, if solid/not plant change soil to dirt
|
||||||
if minetest.registered_nodes[nn]
|
if minetest.registered_nodes[nn]
|
||||||
and minetest.registered_nodes[nn].walkable
|
and minetest.registered_nodes[nn].walkable
|
||||||
and minetest.get_item_group(nn, "plant") == 0 then
|
and minetest.get_item_group(nn, "plant") == 0 then
|
||||||
minetest.set_node(pos, {name="default:dirt"})
|
minetest.set_node(pos, {name="default:dirt"})
|
||||||
|
return
|
||||||
end
|
end
|
||||||
|
|
||||||
-- if map around soil not loaded then skip until loaded
|
-- if map around soil not loaded then skip until loaded
|
||||||
|
150
mods/farming/statistics.lua
Normal file
150
mods/farming/statistics.lua
Normal file
@ -0,0 +1,150 @@
|
|||||||
|
local statistics = {}
|
||||||
|
|
||||||
|
local ROOT_2 = math.sqrt(2.0)
|
||||||
|
|
||||||
|
-- Approximations for erf(x) and erfInv(x) from
|
||||||
|
-- https://en.wikipedia.org/wiki/Error_function
|
||||||
|
local erf
|
||||||
|
local erf_inv
|
||||||
|
|
||||||
|
local A = 8 * (math.pi - 3.0)/(3.0 * math.pi * (4.0 - math.pi))
|
||||||
|
local B = 4.0 / math.pi
|
||||||
|
local C = 2.0/(math.pi * A)
|
||||||
|
local D = 1.0 / A
|
||||||
|
|
||||||
|
erf = function(x)
|
||||||
|
if x == 0 then return 0; end
|
||||||
|
local xSq = x * x
|
||||||
|
local aXSq = A * xSq
|
||||||
|
local v = math.sqrt(1.0 - math.exp(-xSq * (B + aXSq)/(1.0 + aXSq)))
|
||||||
|
return (x > 0 and v) or -v
|
||||||
|
end
|
||||||
|
|
||||||
|
erf_inv = function(x)
|
||||||
|
if x == 0 then return 0; end
|
||||||
|
if x <= -1 or x >= 1 then return nil; end
|
||||||
|
local y = math.log(1 - x * x)
|
||||||
|
local u = C + 0.5 * y
|
||||||
|
local v = math.sqrt(math.sqrt(u * u - D * y) - u)
|
||||||
|
return (x > 0 and v) or -v
|
||||||
|
end
|
||||||
|
|
||||||
|
local function std_normal(u)
|
||||||
|
return ROOT_2 * erf_inv(2.0 * u - 1.0)
|
||||||
|
end
|
||||||
|
|
||||||
|
local poisson
|
||||||
|
local cdf_table = {}
|
||||||
|
|
||||||
|
local function generate_cdf(lambda_index, lambda)
|
||||||
|
local max = math.ceil(4 * lambda)
|
||||||
|
local pdf = math.exp(-lambda)
|
||||||
|
local cdf = pdf
|
||||||
|
local t = { [0] = pdf }
|
||||||
|
|
||||||
|
for i = 1, max - 1 do
|
||||||
|
pdf = pdf * lambda / i
|
||||||
|
cdf = cdf + pdf
|
||||||
|
t[i] = cdf
|
||||||
|
end
|
||||||
|
|
||||||
|
return t
|
||||||
|
end
|
||||||
|
|
||||||
|
for li = 1, 100 do
|
||||||
|
cdf_table[li] = generate_cdf(li, 0.25 * li)
|
||||||
|
end
|
||||||
|
|
||||||
|
poisson = function(lambda, max)
|
||||||
|
if max < 2 then
|
||||||
|
return (math.random() < math.exp(-lambda) and 0) or 1
|
||||||
|
elseif lambda >= 2 * max then
|
||||||
|
return max
|
||||||
|
end
|
||||||
|
|
||||||
|
local u = math.random()
|
||||||
|
local lambda_index = math.floor(4 * lambda + 0.5)
|
||||||
|
local cdfs = cdf_table[lambda_index]
|
||||||
|
|
||||||
|
if cdfs then
|
||||||
|
lambda = 0.25 * lambda_index
|
||||||
|
|
||||||
|
if u < cdfs[0] then return 0; end
|
||||||
|
if max > #cdfs then max = #cdfs + 1 else max = math.floor(max); end
|
||||||
|
if u >= cdfs[max - 1] then return max; end
|
||||||
|
|
||||||
|
if max > 4 then -- Binary search
|
||||||
|
local s = 0
|
||||||
|
while s + 1 < max do
|
||||||
|
local m = math.floor(0.5 * (s + max))
|
||||||
|
if u < cdfs[m] then max = m; else s = m; end
|
||||||
|
end
|
||||||
|
else
|
||||||
|
for i = 1, max - 1 do
|
||||||
|
if u < cdfs[i] then return i; end
|
||||||
|
end
|
||||||
|
end
|
||||||
|
|
||||||
|
return max
|
||||||
|
else
|
||||||
|
local x = lambda + math.sqrt(lambda) * std_normal(u)
|
||||||
|
return (x < 0.5 and 0) or (x >= max - 0.5 and max) or math.floor(x + 0.5)
|
||||||
|
end
|
||||||
|
end
|
||||||
|
|
||||||
|
-- Error function.
|
||||||
|
statistics.erf = erf
|
||||||
|
|
||||||
|
-- Inverse error function.
|
||||||
|
statistics.erf_inv = erf_inv
|
||||||
|
|
||||||
|
--- Standard normal distribution function (mean 0, standard deviation 1).
|
||||||
|
--
|
||||||
|
-- @return
|
||||||
|
-- Any real number (actually between -3.0 and 3.0).
|
||||||
|
--
|
||||||
|
statistics.std_normal = function()
|
||||||
|
local u = math.random()
|
||||||
|
if u < 0.001 then
|
||||||
|
return -3.0
|
||||||
|
elseif u > 0.999 then
|
||||||
|
return 3.0
|
||||||
|
end
|
||||||
|
return std_normal(u)
|
||||||
|
end
|
||||||
|
|
||||||
|
--- Standard normal distribution function (mean 0, standard deviation 1).
|
||||||
|
--
|
||||||
|
-- @param mu
|
||||||
|
-- The distribution mean.
|
||||||
|
-- @param sigma
|
||||||
|
-- The distribution standard deviation.
|
||||||
|
-- @return
|
||||||
|
-- Any real number (actually between -3*sigma and 3*sigma).
|
||||||
|
--
|
||||||
|
statistics.normal = function(mu, sigma)
|
||||||
|
local u = math.random()
|
||||||
|
if u < 0.001 then
|
||||||
|
return mu - 3.0 * sigma
|
||||||
|
elseif u > 0.999 then
|
||||||
|
return mu + 3.0 * sigma
|
||||||
|
end
|
||||||
|
return mu + sigma * std_normal(u)
|
||||||
|
end
|
||||||
|
|
||||||
|
--- Poisson distribution function.
|
||||||
|
--
|
||||||
|
-- @param lambda
|
||||||
|
-- The distribution mean and variance.
|
||||||
|
-- @param max
|
||||||
|
-- The distribution maximum.
|
||||||
|
-- @return
|
||||||
|
-- An integer between 0 and max (both inclusive).
|
||||||
|
--
|
||||||
|
statistics.poisson = function(lambda, max)
|
||||||
|
lambda, max = tonumber(lambda), tonumber(max)
|
||||||
|
if not lambda or not max or lambda <= 0 or max < 1 then return 0; end
|
||||||
|
return poisson(lambda, max)
|
||||||
|
end
|
||||||
|
|
||||||
|
return statistics
|
Loading…
Reference in New Issue
Block a user