forked from mtcontrib/plantlife_modpack
Changed plants_lib API to require a table argument when not using legacy
calling options. This opens the door for even more features in the future. Changed flowers, junglegrass, poisonivy to match. Made plants lib faster in some places, especially the surface-hunting algorithm, and especially over water. Fixed a few other misc. bugs. Made growth code properly execute all biome-control code before executing any string-named function or spawn_tree(). Tuned flowers settings. Made flowers require at least some light to spawn, made waterlilies require shallower water. Fixed a bug in water depth detection and made water depth depend on whether the bottom of the water area is dirt, dirt with grass, or sand, rather than just anything. Made waterlilies randomly rotate on spawning to break up the patterns (now has 16 orientations with the help of nodeboxes and facedir, requires only 3 new nodes). Smoothed edges of the regular waterlily texture. Made all flowers and water- lilies spawn using only 3 ABM calls instead of 8. Got rid of colon prefix node def overrides on all plants, since this is a modpack now instead of an integrated mod. Fixed a misspelled folder name for poisonivy. Fixed a bug in the wall detection routine - it returned the last wall found, not the first. Made the top-side-check for air only apply when spawning on top of the target rather than its sides/bottom. Many other features and enhancements have been made. Too many to list here. Please see API.txt for details.
This commit is contained in:
@ -1,5 +1,5 @@
|
||||
-- Plantlife library mod by Vanessa Ezekowitz
|
||||
-- 2013-01-20
|
||||
-- last revision, 2013-01-24
|
||||
--
|
||||
-- License: WTFPL
|
||||
--
|
||||
@ -24,7 +24,7 @@ local temperature_octaves = 3
|
||||
local temperature_persistence = 0.5
|
||||
local temperature_scale = 150
|
||||
|
||||
local plantlife_limit = 0.1
|
||||
|
||||
|
||||
-- Local functions
|
||||
|
||||
@ -47,13 +47,18 @@ end
|
||||
|
||||
-- Spawn plants using the map generator
|
||||
|
||||
function plantslib:register_generate_plant(biome, funct_or_model)
|
||||
minetest.register_on_generated(plantslib:search_for_surfaces(minp, maxp, biome, funct_or_model))
|
||||
function plantslib:register_generate_plant(biomedef, funct_or_model)
|
||||
plantslib:dbg("Registered mapgen spawner:")
|
||||
plantslib:dbg(dump(biomedef))
|
||||
|
||||
minetest.register_on_generated(plantslib:search_for_surfaces(minp, maxp, biomedef, funct_or_model))
|
||||
end
|
||||
|
||||
function plantslib:search_for_surfaces(minp, maxp, biome, funct_or_model)
|
||||
function plantslib:search_for_surfaces(minp, maxp, biomedef, funct_or_model)
|
||||
return function(minp, maxp, blockseed)
|
||||
|
||||
local biome = biomedef
|
||||
|
||||
if biome.seed_diff == nil then biome.seed_diff = 0 end
|
||||
if biome.neighbors == nil then biome.neighbors = biome.surface end
|
||||
if biome.min_elevation == nil then biome.min_elevation = -31000 end
|
||||
@ -64,6 +69,8 @@ function plantslib:search_for_surfaces(minp, maxp, biome, funct_or_model)
|
||||
if biome.temp_max == nil then biome.temp_max = -1 end
|
||||
if biome.rarity == nil then biome.rarity = 50 end
|
||||
if biome.max_count == nil then biome.max_count = 5 end
|
||||
if biome.plantlife_limit == nil then biome.plantlife_limit = 0.1 end
|
||||
if biome.near_nodes_vertical == nil then biome.near_nodes_vertical = 1 end
|
||||
|
||||
plantslib:dbg("Started checking generated mapblock volume...")
|
||||
local searchnodes = minetest.env:find_nodes_in_area(minp, maxp, biome.surface)
|
||||
@ -80,131 +87,166 @@ function plantslib:search_for_surfaces(minp, maxp, biome, funct_or_model)
|
||||
and minetest.env:get_node(p_top).name == "air"
|
||||
and pos.y >= biome.min_elevation
|
||||
and pos.y <= biome.max_elevation
|
||||
and noise1 > plantlife_limit
|
||||
and noise1 > biome.plantlife_limit
|
||||
and noise2 <= biome.temp_min
|
||||
and noise2 >= biome.temp_max
|
||||
and (biome.ncount == nil or table.getn(minetest.env:find_nodes_in_area({x=pos.x-1, y=pos.y, z=pos.z-1}, {x=pos.x+1, y=pos.y, z=pos.z+1}, biome.neighbors)) > biome.ncount)
|
||||
and (biome.near_nodes == nil or table.getn(minetest.env:find_nodes_in_area({x=pos.x-biome.near_nodes_size, y=pos.y-1, z=pos.z-biome.near_nodes_size}, {x=pos.x+biome.near_nodes_size, y=pos.y+1, z=pos.z+biome.near_nodes_size}, biome.near_nodes)) >= biome.near_nodes_count)
|
||||
and (biome.near_nodes == nil or table.getn(minetest.env:find_nodes_in_area({x=pos.x-biome.near_nodes_size, y=pos.y-biome.near_nodes_vertical, z=pos.z-biome.near_nodes_size}, {x=pos.x+biome.near_nodes_size, y=pos.y+biome.near_nodes_vertical, z=pos.z+biome.near_nodes_size}, biome.near_nodes)) >= biome.near_nodes_count)
|
||||
and math.random(1,100) > biome.rarity
|
||||
then
|
||||
table.insert(in_biome_nodes, pos)
|
||||
num_in_biome_nodes = num_in_biome_nodes + 1
|
||||
end
|
||||
end
|
||||
|
||||
|
||||
plantslib:dbg("Found "..num_in_biome_nodes.." surface nodes of type "..biome.surface.." in 5x5x5 mapblock volume at {"..dump(minp)..":"..dump(maxp).."} to check.")
|
||||
|
||||
if num_in_biome_nodes > 0 then
|
||||
plantslib:dbg("Found "..num_in_biome_nodes.." surface nodes of type "..biome.surface.." in 5x5x5 mapblock volume at {"..dump(minp)..":"..dump(maxp).."} to check.")
|
||||
for i = 1,biome.max_count do
|
||||
plantslib:dbg("Calculated maximum of "..math.min(biome.max_count*3, num_in_biome_nodes).." nodes to be checked in that list.")
|
||||
for i = 1, math.min(biome.max_count, num_in_biome_nodes) do
|
||||
local tries = 0
|
||||
local spawned = false
|
||||
while tries < 2 and not planted do
|
||||
while tries < 2 and not spawned do
|
||||
local pos = in_biome_nodes[math.random(1, num_in_biome_nodes)]
|
||||
local p_top = { x = pos.x, y = pos.y + 1, z = pos.z }
|
||||
if minetest.env:find_node_near(p_top, biome.avoid_radius + math.random(-1.5,1.5), biome.avoid_nodes) == nil then
|
||||
spawned = true
|
||||
if type(funct_or_model) == "table" then
|
||||
plantslib:dbg("Spawn tree at {"..dump(pos).."}")
|
||||
|
||||
--[[
|
||||
for v = 0,10 do
|
||||
minetest.env:remove_node({ x = pos.x, y = pos.y + v, z = pos.z })
|
||||
minetest.env:remove_node({ x = pos.x-1, y = pos.y + v, z = pos.z })
|
||||
minetest.env:remove_node({ x = pos.x+1, y = pos.y + v, z = pos.z })
|
||||
minetest.env:remove_node({ x = pos.x, y = pos.y + v, z = pos.z-1 })
|
||||
minetest.env:remove_node({ x = pos.x, y = pos.y + v, z = pos.z+1 })
|
||||
end
|
||||
]]--
|
||||
|
||||
minetest.env:spawn_tree(pos, funct_or_model)
|
||||
else
|
||||
plantslib:dbg("Call function: "..funct_or_model.."("..dump(pos)..")")
|
||||
plantslib:dbg("Call function: "..funct_or_model.."("..dump(pos)..")")
|
||||
assert(loadstring(funct_or_model.."("..dump(pos)..")"))()
|
||||
end
|
||||
else
|
||||
tries = tries + 1
|
||||
spawned = false
|
||||
plantslib:dbg("Couldn't spawn a tree at {"..dump(pos).."} -- trying again elsewhere")
|
||||
plantslib:dbg("No room to spawn object at {"..dump(pos).."} -- trying again elsewhere")
|
||||
end
|
||||
end
|
||||
if tries == 2 and spawned == false then
|
||||
plantslib:dbg("Unable to spawn that tree. Giving up on it.")
|
||||
if tries == 2 then
|
||||
plantslib:dbg("Unable to spawn that object. Giving up on it.")
|
||||
end
|
||||
end
|
||||
end
|
||||
plantslib:dbg("Finished checking generated area.")
|
||||
end
|
||||
end
|
||||
|
||||
-- The spawning ABM
|
||||
|
||||
function plantslib:spawn_on_surfaces(
|
||||
sdelay,
|
||||
splant,
|
||||
sradius,
|
||||
schance,
|
||||
ssurface,
|
||||
savoid,
|
||||
seed_diff,
|
||||
lightmin,
|
||||
lightmax,
|
||||
nneighbors,
|
||||
ocount,
|
||||
facedir,
|
||||
depthmax,
|
||||
altmin,
|
||||
altmax,
|
||||
sbiome,
|
||||
sbiomesize,
|
||||
sbiomecount,
|
||||
airsize,
|
||||
aircount,
|
||||
tempmin,
|
||||
tempmax)
|
||||
if seed_diff == nil then seed_diff = 0 end
|
||||
if lightmin == nil then lightmin = 0 end
|
||||
if lightmax == nil then lightmax = LIGHT_MAX end
|
||||
if nneighbors == nil then nneighbors = ssurface end
|
||||
if ocount == nil then ocount = -1 end
|
||||
if depthmax == nil then depthmax = 1 end
|
||||
if altmin == nil then altmin = -31000 end
|
||||
if altmax == nil then altmax = 31000 end
|
||||
if sbiome == nil then sbiome = "" end
|
||||
if sbiomesize == nil then sbiomesize = 0 end
|
||||
if sbiomecount == nil then sbiomecount = 1 end
|
||||
if airsize == nil then airsize = 0 end
|
||||
if aircount == nil then aircount = 1 end
|
||||
if tempmin == nil then tempmin = -2 end
|
||||
if tempmax == nil then tempmax = 2 end
|
||||
function plantslib:spawn_on_surfaces(sd,sp,sr,sc,ss,sa)
|
||||
|
||||
local biome = {}
|
||||
|
||||
if type(sd) ~= "table" then
|
||||
biome.spawn_delay = sd -- old api expects ABM interval param here.
|
||||
biome.spawn_plants = {sp}
|
||||
biome.avoid_radius = sr
|
||||
biome.spawn_chance = sc
|
||||
biome.spawn_surfaces = {ss}
|
||||
biome.avoid_nodes = sa
|
||||
else
|
||||
biome = sd
|
||||
end
|
||||
|
||||
if biome.seed_diff == nil then biome.seed_diff = 0 end
|
||||
if biome.light_min == nil then biome.light_min = 0 end
|
||||
if biome.light_max == nil then biome.light_max = 15 end
|
||||
if biome.depth_max == nil then biome.depth_max = 1 end
|
||||
if biome.min_elevation == nil then biome.min_elevation = -31000 end
|
||||
if biome.max_elevation == nil then biome.max_elevation = 31000 end
|
||||
if biome.temp_min == nil then biome.temp_min = 1 end
|
||||
if biome.temp_max == nil then biome.temp_max = -1 end
|
||||
if biome.plantlife_limit == nil then biome.plantlife_limit = 0.1 end
|
||||
if biome.near_nodes_vertical == nil then biome.near_nodes_vertical = 1 end
|
||||
|
||||
biome.spawn_plants_count = table.getn(biome.spawn_plants)
|
||||
|
||||
plantslib:dbg("Registered spawning ABM:")
|
||||
plantslib:dbg(dump(biome))
|
||||
plantslib:dbg("Number of trigger nodes in this ABM: "..biome.spawn_plants_count )
|
||||
|
||||
minetest.register_abm({
|
||||
nodenames = { ssurface },
|
||||
interval = sdelay,
|
||||
chance = schance,
|
||||
neighbors = nneighbors,
|
||||
nodenames = biome.spawn_surfaces,
|
||||
interval = biome.spawn_delay,
|
||||
chance = biome.spawn_chance,
|
||||
neighbors = biome.neighbors,
|
||||
action = function(pos, node, active_object_count, active_object_count_wider)
|
||||
local p_top = { x = pos.x, y = pos.y + 1, z = pos.z }
|
||||
local n_top = minetest.env:get_node(p_top)
|
||||
local perlin1 = minetest.env:get_perlin(seed_diff, perlin_octaves, perlin_persistence, perlin_scale)
|
||||
local perlin1 = minetest.env:get_perlin(biome.seed_diff, perlin_octaves, perlin_persistence, perlin_scale)
|
||||
local perlin2 = minetest.env:get_perlin(temperature_seeddiff, temperature_octaves, temperature_persistence, temperature_scale)
|
||||
local noise1 = perlin1:get2d({x=p_top.x, y=p_top.z})
|
||||
local noise2 = perlin2:get2d({x=p_top.x, y=p_top.z})
|
||||
if noise1 > plantlife_limit
|
||||
and noise2 >= tempmin
|
||||
and noise2 <= tempmax
|
||||
if noise1 > biome.plantlife_limit
|
||||
and noise2 <= biome.temp_min
|
||||
and noise2 >= biome.temp_max
|
||||
and plantslib:is_node_loaded(p_top) then
|
||||
local n_light = minetest.env:get_node_light(p_top, nil)
|
||||
if minetest.env:find_node_near(p_top, sradius + math.random(-1.5,2), savoid) == nil
|
||||
and n_light >= lightmin
|
||||
and n_light <= lightmax
|
||||
and (table.getn(minetest.env:find_nodes_in_area({x=pos.x-1, y=pos.y, z=pos.z-1}, {x=pos.x+1, y=pos.y, z=pos.z+1}, nneighbors)) > ocount
|
||||
or ocount == -1)
|
||||
and (table.getn(minetest.env:find_nodes_in_area({x=pos.x-sbiomesize, y=pos.y-1, z=pos.z-sbiomesize}, {x=pos.x+sbiomesize, y=pos.y+1, z=pos.z+sbiomesize}, sbiome)) >= sbiomecount
|
||||
or sbiome == "")
|
||||
and table.getn(minetest.env:find_nodes_in_area({x=p_top.x-airsize, y=p_top.y, z=p_top.z-airsize}, {x=p_top.x+airsize, y=p_top.y, z=p_top.z+airsize}, "air")) >= aircount
|
||||
and pos.y >= altmin
|
||||
and pos.y <= altmax
|
||||
then
|
||||
local walldir = plantslib:plant_valid_wall(p_top)
|
||||
if splant == "poisonivy:seedling" and walldir ~= nil then
|
||||
plantslib:dbg("Spawn: poisonivy:climbing at "..dump(p_top).." on "..ssurface)
|
||||
minetest.env:add_node(p_top, { name = "poisonivy:climbing", param2 = walldir })
|
||||
else
|
||||
local deepnode = minetest.env:get_node({ x = pos.x, y = pos.y-depthmax-1, z = pos.z }).name
|
||||
if (ssurface ~= "default:water_source")
|
||||
or (ssurface == "default:water_source"
|
||||
and deepnode ~= "default:water_source") then
|
||||
plantslib:dbg("Spawn: "..splant.." at "..dump(p_top).." on "..ssurface)
|
||||
minetest.env:add_node(p_top, { name = splant, param2 = facedir })
|
||||
if (not(biome.avoid_nodes and biome.avoid_radius) or minetest.env:find_node_near(p_top, biome.avoid_radius + math.random(-1.5,2), biome.avoid_nodes) == nil)
|
||||
and n_light >= biome.light_min
|
||||
and n_light <= biome.light_max
|
||||
and (not(biome.neighbors and biome.ncount) or table.getn(minetest.env:find_nodes_in_area({x=pos.x-1, y=pos.y, z=pos.z-1}, {x=pos.x+1, y=pos.y, z=pos.z+1}, biome.neighbors)) > biome.ncount )
|
||||
and (not(biome.near_nodes and biome.near_nodes_count and biome.near_nodes_size) or table.getn(minetest.env:find_nodes_in_area({x=pos.x-biome.near_nodes_size, y=pos.y-biome.near_nodes_vertical, z=pos.z-biome.near_nodes_size}, {x=pos.x+biome.near_nodes_size, y=pos.y+biome.near_nodes_vertical, z=pos.z+biome.near_nodes_size}, biome.near_nodes)) >= biome.near_nodes_count)
|
||||
and (not(biome.air_count and biome.air_size) or table.getn(minetest.env:find_nodes_in_area({x=p_top.x-biome.air_size, y=p_top.y, z=p_top.z-biome.air_size}, {x=p_top.x+biome.air_size, y=p_top.y, z=p_top.z+biome.air_size}, "air")) >= biome.air_count)
|
||||
and pos.y >= biome.min_elevation
|
||||
and pos.y <= biome.max_elevation
|
||||
then
|
||||
local walldir = plantslib:find_adjacent_wall(p_top, biome.verticals_list)
|
||||
if biome.alt_wallnode and walldir then
|
||||
if n_top.name == "air" then
|
||||
plantslib:dbg("Spawn: "..biome.alt_wallnode.." on top of ("..dump(pos)..") against wall "..walldir)
|
||||
minetest.env:add_node(p_top, { name = biome.alt_wallnode, param2 = walldir })
|
||||
end
|
||||
else
|
||||
local currentsurface = minetest.env:get_node(pos).name
|
||||
if currentsurface ~= "default:water_source"
|
||||
or (currentsurface == "default:water_source" and table.getn(minetest.env:find_nodes_in_area({x=pos.x, y=pos.y-biome.depth_max-1, z=pos.z}, {x=pos.x, y=pos.y, z=pos.z}, {"default:dirt", "default:dirt_with_grass", "default:sand"})) > 0 )
|
||||
then
|
||||
local rnd = math.random(1, biome.spawn_plants_count)
|
||||
local plant_to_spawn = biome.spawn_plants[rnd]
|
||||
plantslib:dbg("Chose entry number "..rnd.." of "..biome.spawn_plants_count)
|
||||
|
||||
if not biome.spawn_on_side and not biome.spawn_on_bottom then
|
||||
local fdir = nil
|
||||
if biome.random_facedir then
|
||||
fdir = math.random(biome.random_facedir[1],biome.random_facedir[2])
|
||||
plantslib:dbg("Gave it a random facedir: "..fdir)
|
||||
end
|
||||
if n_top.name == "air" then
|
||||
plantslib:dbg("Spawn: "..plant_to_spawn.." on top of ("..dump(pos)..")")
|
||||
minetest.env:add_node(p_top, { name = plant_to_spawn, param2 = fdir })
|
||||
end
|
||||
elseif biome.spawn_on_side then
|
||||
local onside = plantslib:find_open_side(pos)
|
||||
if onside then
|
||||
plantslib:dbg("Spawn: "..plant_to_spawn.." at side of ("..dump(pos).."), facedir "..onside.facedir.."")
|
||||
minetest.env:add_node(onside.newpos, { name = plant_to_spawn, param2 = onside.facedir })
|
||||
end
|
||||
elseif biome.spawn_on_bottom then
|
||||
if minetest.env:get_node({x=pos.x, y=pos.y-1, z=pos.z}).name == "air" then
|
||||
local fdir = nil
|
||||
if biome.random_facedir then
|
||||
fdir = math.random(biome.random_facedir[1],biome.random_facedir[2])
|
||||
plantslib:dbg("Gave it a random facedir: "..fdir)
|
||||
end
|
||||
plantslib:dbg("Spawn: "..plant_to_spawn.." on bottom of ("..dump(pos)..")")
|
||||
minetest.env:add_node({x=pos.x, y=pos.y-1, z=pos.z}, { name = plant_to_spawn, param2 = fdir} )
|
||||
end
|
||||
end
|
||||
end
|
||||
end
|
||||
end
|
||||
end
|
||||
end
|
||||
@ -213,134 +255,130 @@ end
|
||||
|
||||
-- The growing ABM
|
||||
|
||||
function plantslib:grow_plants(
|
||||
gdelay,
|
||||
gchance,
|
||||
gplant,
|
||||
gresult,
|
||||
dry_early_node,
|
||||
grow_nodes,
|
||||
facedir,
|
||||
need_wall,
|
||||
grow_vertically,
|
||||
height_limit,
|
||||
ground_nodes,
|
||||
grow_function,
|
||||
seed_diff)
|
||||
if need_wall ~= true then need_wall = false end
|
||||
if grow_vertically ~= true then grow_vertically = false end
|
||||
if height_limit == nil then height_limit = 62000 end
|
||||
if ground_nodes == nil then ground_nodes = { "default:dirt_with_grass" } end
|
||||
if grow_nodes == nil then grow_nodes = { "default:dirt_with_grass" } end
|
||||
function plantslib:grow_plants(opts)
|
||||
|
||||
local options = opts
|
||||
|
||||
if options.height_limit == nil then options.height_limit = 5 end
|
||||
if options.ground_nodes == nil then options.ground_nodes = { "default:dirt_with_grass" } end
|
||||
if options.grow_nodes == nil then options.grow_nodes = { "default:dirt_with_grass" } end
|
||||
if options.seed_diff == nil then options.seed_diff = 0 end
|
||||
|
||||
plantslib:dbg("Registered growing ABM:")
|
||||
plantslib:dbg(dump(options))
|
||||
|
||||
minetest.register_abm({
|
||||
nodenames = { gplant },
|
||||
interval = gdelay,
|
||||
chance = gchance,
|
||||
nodenames = { options.grow_plant },
|
||||
interval = options.grow_delay,
|
||||
chance = options.grow_chance,
|
||||
action = function(pos, node, active_object_count, active_object_count_wider)
|
||||
local p_top = {x=pos.x, y=pos.y+1, z=pos.z}
|
||||
local p_bot = {x=pos.x, y=pos.y-1, z=pos.z}
|
||||
local n_top = minetest.env:get_node(p_top)
|
||||
local n_bot = minetest.env:get_node(p_bot)
|
||||
local root_node = minetest.env:get_node({x=pos.x, y=pos.y-height_limit, z=pos.z})
|
||||
if string.find(dump(grow_nodes), n_bot.name) ~= nil and n_top.name == "air" then
|
||||
if grow_function == nil then
|
||||
if grow_vertically then
|
||||
if plantslib:find_first_node(pos, height_limit, ground_nodes) ~= nil then
|
||||
if need_wall then
|
||||
local walldir=plantslib:plant_valid_wall(p_top)
|
||||
if walldir ~= nil then
|
||||
plantslib:dbg("Grow: "..gplant.." upwards to ("..dump(p_top)..") on wall "..walldir)
|
||||
minetest.env:add_node(p_top, { name = gplant, param2 = walldir })
|
||||
end
|
||||
else
|
||||
plantslib:dbg("Grow: "..gplant.." upwards to ("..dump(p_top)..")")
|
||||
minetest.env:add_node(p_top, { name = gplant })
|
||||
end
|
||||
end
|
||||
local root_node = minetest.env:get_node({x=pos.x, y=pos.y-options.height_limit, z=pos.z})
|
||||
local walldir = nil
|
||||
if options.need_wall and options.verticals_list ~= nil then
|
||||
walldir = plantslib:find_adjacent_wall(p_top, options.verticals_list)
|
||||
end
|
||||
if n_top.name == "air" and (not options.need_wall or (options.need_wall and walldir))
|
||||
then
|
||||
-- corner case for changing short junglegrass
|
||||
-- to dry shrub in desert
|
||||
if n_bot.name == options.dry_early_node and options.grow_plant == "junglegrass:short" then
|
||||
plantslib:dbg("Die: "..options.grow_plant.." becomes default:dry_shrub at ("..dump(pos)..")")
|
||||
minetest.env:add_node(pos, { name = "default:dry_shrub" })
|
||||
|
||||
-- corner case for changing short junglegrass to dry shrub in desert
|
||||
elseif n_bot.name == dry_early_node and gplant == "junglegrass:short" then
|
||||
plantslib:dbg("Die: "..gplant.." becomes default:dry_shrub at ("..dump(pos)..")")
|
||||
minetest.env:add_node(pos, { name = "default:dry_shrub" })
|
||||
|
||||
elseif gresult == nil then
|
||||
plantslib:dbg("Die: "..gplant.." at ("..dump(pos)..")")
|
||||
minetest.env:remove_node(pos)
|
||||
|
||||
elseif gresult ~= nil then
|
||||
plantslib:dbg("Grow: "..gplant.." becomes "..gresult.." at ("..dump(pos)..")")
|
||||
if facedir == nil then
|
||||
minetest.env:add_node(pos, { name = gresult })
|
||||
else
|
||||
minetest.env:add_node(pos, { name = gresult, param2 = facedir })
|
||||
end
|
||||
elseif options.grow_vertically and walldir then
|
||||
if plantslib:search_downward(pos, options.height_limit, options.ground_nodes) then
|
||||
plantslib:dbg("Grow "..options.grow_plant.." vertically to "..dump(p_top))
|
||||
minetest.env:add_node(p_top, { name = options.grow_plant, param2 = walldir})
|
||||
end
|
||||
|
||||
elseif options.grow_result == nil and options.grow_function == nil then
|
||||
plantslib:dbg("Die: "..options.grow_plant.." at ("..dump(pos)..")")
|
||||
minetest.env:remove_node(pos)
|
||||
|
||||
else
|
||||
if seed_diff == nil then seed_diff = 0 end
|
||||
local perlin1 = minetest.env:get_perlin(seed_diff, perlin_octaves, perlin_persistence, perlin_scale)
|
||||
local perlin2 = minetest.env:get_perlin(temperature_seeddiff, temperature_octaves, temperature_persistence, temperature_scale)
|
||||
local noise1 = perlin1:get2d({x=p_top.x, y=p_top.z})
|
||||
local noise2 = perlin2:get2d({x=p_top.x, y=p_top.z})
|
||||
if type(grow_function) == "table" then
|
||||
plantslib:dbg("Grow sapling into tree at "..dump(pos))
|
||||
minetest.env:remove_node(pos)
|
||||
minetest.env:spawn_tree(pos, grow_function)
|
||||
else
|
||||
plantslib:dbg("Call function: "..grow_function.."("..dump(pos)..","..noise1..","..noise2..")")
|
||||
assert(loadstring(grow_function.."("..dump(pos)..","..noise1..","..noise2..")"))()
|
||||
end
|
||||
plantslib:replace_object(pos, options.grow_result, options.grow_function, options.facedir, options.seed_diff)
|
||||
end
|
||||
end
|
||||
end
|
||||
})
|
||||
end
|
||||
|
||||
-- Function to decide how to replace a plant - either grow it, replace it with
|
||||
-- a tree, run a function, or die with an error.
|
||||
|
||||
function plantslib:replace_object(pos, replacement, grow_function, walldir, seeddiff)
|
||||
local growtype = type(grow_function)
|
||||
plantslib:dbg("replace_object called, growtype="..dump(grow_function))
|
||||
if growtype == "table" then
|
||||
plantslib:dbg("Grow: spawn tree at "..dump(pos))
|
||||
minetest.env:remove_node(pos)
|
||||
minetest.env:spawn_tree(pos, grow_function)
|
||||
return
|
||||
elseif growtype == "string" then
|
||||
local perlin1 = minetest.env:get_perlin(seeddiff, perlin_octaves, perlin_persistence, perlin_scale)
|
||||
local perlin2 = minetest.env:get_perlin(temperature_seeddiff, temperature_octaves, temperature_persistence, temperature_scale)
|
||||
local noise1 = perlin1:get2d({x=pos.x, y=pos.z})
|
||||
local noise2 = perlin2:get2d({x=pos.x, y=pos.z})
|
||||
plantslib:dbg("Grow: call function "..grow_function.."("..dump(pos)..","..noise1..","..noise2..","..dump(walldir)..")")
|
||||
assert(loadstring(grow_function.."("..dump(pos)..","..noise1..","..noise2..","..dump(walldir)..")"))()
|
||||
return
|
||||
elseif growtype == "nil" then
|
||||
if walldir ~= nil then
|
||||
plantslib:dbg("Grow: place "..replacement.." at ("..dump(pos)..") on wall "..walldir)
|
||||
minetest.env:add_node(pos, { name = replacement, param2 = walldir})
|
||||
else
|
||||
plantslib:dbg("Grow: place "..replacement.." at ("..dump(pos)..")")
|
||||
minetest.env:add_node(pos, { name = replacement})
|
||||
end
|
||||
return
|
||||
elseif growtype ~= "nil" and growtype ~= "string" and growtype ~= "table" then
|
||||
error("Invalid grow function "..dump(grow_function).." used on object at ("..dump(pos)..")")
|
||||
end
|
||||
end
|
||||
|
||||
-- function to decide if a node has a wall that's in verticals_list{}
|
||||
-- returns wall direction of valid node, or nil if invalid.
|
||||
|
||||
local verticals_list = {
|
||||
"default:dirt",
|
||||
"default:dirt_with_grass",
|
||||
"default:stone",
|
||||
"default:cobble",
|
||||
"default:mossycobble",
|
||||
"default:brick",
|
||||
"default:tree",
|
||||
"default:jungletree",
|
||||
"default:coal",
|
||||
"default:iron"
|
||||
}
|
||||
|
||||
function plantslib:plant_valid_wall(wallpos)
|
||||
local walldir = nil
|
||||
local verts = dump(verticals_list)
|
||||
|
||||
local testpos = { x = wallpos.x-1, y = wallpos.y, z = wallpos.z }
|
||||
if string.find(verts, minetest.env:get_node(testpos).name) ~= nil then walldir=3 end
|
||||
|
||||
local testpos = { x = wallpos.x+1, y = wallpos.y, z = wallpos.z }
|
||||
if string.find(verts, minetest.env:get_node(testpos).name) ~= nil then walldir=2 end
|
||||
|
||||
local testpos = { x = wallpos.x , y = wallpos.y, z = wallpos.z-1 }
|
||||
if string.find(verts, minetest.env:get_node(testpos).name) ~= nil then walldir=5 end
|
||||
|
||||
local testpos = { x = wallpos.x , y = wallpos.y, z = wallpos.z+1 }
|
||||
if string.find(verts, minetest.env:get_node(testpos).name) ~= nil then walldir=4 end
|
||||
|
||||
return walldir
|
||||
function plantslib:find_adjacent_wall(pos, verticals)
|
||||
local verts = dump(verticals)
|
||||
if string.find(verts, minetest.env:get_node({ x=pos.x-1, y=pos.y, z=pos.z }).name) then return 3 end
|
||||
if string.find(verts, minetest.env:get_node({ x=pos.x+1, y=pos.y, z=pos.z }).name) then return 2 end
|
||||
if string.find(verts, minetest.env:get_node({ x=pos.x , y=pos.y, z=pos.z-1 }).name) then return 5 end
|
||||
if string.find(verts, minetest.env:get_node({ x=pos.x , y=pos.y, z=pos.z+1 }).name) then return 4 end
|
||||
return nil
|
||||
end
|
||||
|
||||
-- Function to search straight down from (pos) to find first node in match list.
|
||||
-- Function to search downward from the given position, looking for the first
|
||||
-- node that matches the ground table. Returns the new position, or nil if
|
||||
-- height limit is exceeded before finding it.
|
||||
|
||||
function plantslib:find_first_node(pos, height_limit, nodelist)
|
||||
for i = 1, height_limit do
|
||||
n = minetest.env:get_node({x=pos.x, y=pos.y-i, z=pos.z})
|
||||
if string.find(dump(nodelist),n.name) ~= nil then
|
||||
return n.name
|
||||
function plantslib:search_downward(pos, heightlimit, ground)
|
||||
for i = 0, heightlimit do
|
||||
if string.find(dump(ground), minetest.env:get_node({x=pos.x, y=pos.y-i, z = pos.z}).name) then
|
||||
return {x=pos.x, y=pos.y-i, z = pos.z}
|
||||
end
|
||||
end
|
||||
return false
|
||||
end
|
||||
|
||||
function plantslib:find_open_side(pos)
|
||||
if minetest.env:get_node({ x=pos.x-1, y=pos.y, z=pos.z }).name == "air" then
|
||||
return {newpos = { x=pos.x-1, y=pos.y, z=pos.z }, facedir = 2}
|
||||
end
|
||||
if minetest.env:get_node({ x=pos.x+1, y=pos.y, z=pos.z }).name == "air" then
|
||||
return {newpos = { x=pos.x+1, y=pos.y, z=pos.z }, facedir = 3}
|
||||
end
|
||||
if minetest.env:get_node({ x=pos.x, y=pos.y, z=pos.z-1 }).name == "air" then
|
||||
return {newpos = { x=pos.x, y=pos.y, z=pos.z-1 }, facedir = 4}
|
||||
end
|
||||
if minetest.env:get_node({ x=pos.x, y=pos.y, z=pos.z+1 }).name == "air" then
|
||||
return {newpos = { x=pos.x, y=pos.y, z=pos.z+1 }, facedir = 5}
|
||||
end
|
||||
return nil
|
||||
end
|
||||
|
||||
print("[Plantlife] Loaded!")
|
||||
|
||||
print("[Plantlife Library] Loaded")
|
||||
|
Reference in New Issue
Block a user