diff --git a/mods/ITEMS/mcl_farming/shared_functions.lua b/mods/ITEMS/mcl_farming/shared_functions.lua index e066092c35..6c682f839c 100644 --- a/mods/ITEMS/mcl_farming/shared_functions.lua +++ b/mods/ITEMS/mcl_farming/shared_functions.lua @@ -1,22 +1,74 @@ local plant_lists = {} +local plant_nodename_to_id_list = {} + +local function get_intervals_counter(pos, interval, chance) + local meta = minetest.get_meta(pos) + local time_speed = tonumber(minetest.settings:get('time_speed') or 72) + local current_game_time + if time_speed == nil then + return 1 + end + if (time_speed < 0.1) then + return 1 + end + local time_multiplier = 86400 / time_speed + current_game_time = .0 + ((minetest.get_day_count() + minetest.get_timeofday()) * time_multiplier) + + local approx_interval = math.max(interval, 1) * math.max(chance, 1) + + local last_game_time = meta:get_string("last_gametime") + if last_game_time then + last_game_time = tonumber(last_game_time) + end + if not last_game_time or last_game_time < 1 then + last_game_time = current_game_time - approx_interval / 10 + elseif last_game_time == current_game_time then + current_game_time = current_game_time + approx_interval + end + + local elapsed_game_time = .0 + current_game_time - last_game_time + + meta:set_string("last_gametime", tostring(current_game_time)) + + return elapsed_game_time / approx_interval +end + +local function get_avg_light_level(pos) + local node_light = tonumber(minetest.get_node_light(pos) or 0) + local meta = minetest.get_meta(pos) + local counter = meta:get_int("avg_light_count") + local summary = meta:get_int("avg_light_summary") + if counter > 99 then + counter = 51 + summary = math.ceil((summary + 0.0) / 2.0) + else + counter = counter + 1 + end + summary = summary + node_light + meta:set_int("avg_light_count", counter) + meta:set_int("avg_light_summary", summary) + return math.ceil((summary + 0.0) / counter) +end function mcl_farming:add_plant(identifier, full_grown, names, interval, chance) plant_lists[identifier] = {} plant_lists[identifier].full_grown = full_grown plant_lists[identifier].names = names + plant_lists[identifier].interval = interval + plant_lists[identifier].chance = chance minetest.register_abm({ label = string.format("Farming plant growth (%s)", identifier), nodenames = names, interval = interval, chance = chance, action = function(pos, node) - if minetest.get_node({x=pos.x, y=pos.y-1, z=pos.z}).name ~= "mcl_farming:soil_wet" and math.random(0, 9) > 0 then - return - else - mcl_farming:grow_plant(identifier, pos, node) - end + local low_speed = minetest.get_node({x=pos.x, y=pos.y-1, z=pos.z}).name ~= "mcl_farming:soil_wet" + mcl_farming:grow_plant(identifier, pos, node, false, false, low_speed) end, }) + for _, nodename in pairs(names) do + plant_nodename_to_id_list[nodename] = identifier + end end -- Attempts to advance a plant at pos by one or more growth stages (if possible) @@ -28,15 +80,34 @@ end -- Returns true if plant has been grown by 1 or more stages. -- Returns false if nothing changed. -function mcl_farming:grow_plant(identifier, pos, node, stages, ignore_light) - if not minetest.get_node_light(pos) and not ignore_light then +function mcl_farming:grow_plant(identifier, pos, node, stages, ignore_light, low_speed) + local average_light_level = get_avg_light_level(pos) + local plant_info = plant_lists[identifier] + local intervals_counter = get_intervals_counter(pos, plant_info.interval, plant_info.chance) + local low_speed = low_speed or false + if low_speed then + if intervals_counter < 1.01 and math.random(0, 9) > 0 then + return + else + intervals_counter = intervals_counter / 10 + end + end + if not minetest.get_node_light(pos) and not ignore_light and intervals_counter < 1.5 then return false end - if minetest.get_node_light(pos) < 10 and not ignore_light then + if minetest.get_node_light(pos) < 10 and not ignore_light and intervals_counter < 1.5 then return false end - local plant_info = plant_lists[identifier] + if intervals_counter >= 1.5 then + if average_light_level < 0.1 then + return false + end + if average_light_level < 10 then + intervals_counter = intervals_counter * average_light_level / 10 + end + end + local step = nil for i, name in ipairs(plant_info.names) do @@ -51,6 +122,7 @@ function mcl_farming:grow_plant(identifier, pos, node, stages, ignore_light) if not stages then stages = 1 end + stages = stages + math.ceil(intervals_counter) local new_node = {name = plant_info.names[step+stages]} if new_node.name == nil then new_node.name = plant_info.full_grown @@ -86,6 +158,7 @@ function mcl_farming:place_seed(itemstack, placer, pointed_thing, plantname) if string.find(farmland.name, "mcl_farming:soil") and string.find(place_s.name, "air") then minetest.sound_play(minetest.registered_nodes[plantname].sounds.place, {pos = pos}, true) minetest.add_node(pos, {name=plantname, param2 = minetest.registered_nodes[plantname].place_param2}) + local intervals_counter = get_intervals_counter(pos, 1, 1) else return end @@ -379,3 +452,18 @@ function mcl_farming:stem_color(startcolor, endcolor, step, step_count) local colorstring = string.format("#%02X%02X%02X", color.r, color.g, color.b) return colorstring end + +minetest.register_lbm({ + label = "Add growth for unloaded farming plants", + name = "mcl_farming:growth", + nodenames = {"group:plant"}, + run_at_every_load = true, + action = function(pos, node) + local identifier = plant_nodename_to_id_list[node.name] + if not identifier then + return + end + local low_speed = minetest.get_node({x=pos.x, y=pos.y-1, z=pos.z}).name ~= "mcl_farming:soil_wet" + mcl_farming:grow_plant(identifier, pos, node, false, false, low_speed) + end, +})