From b0de25407dbd4b394d6628c65e7ec6bf751cbf3f Mon Sep 17 00:00:00 2001 From: Vanessa Ezekowitz Date: Wed, 9 Jan 2013 21:33:37 -0500 Subject: [PATCH] Expanded the API to allow for additional biome controls. See API.txt for details. --- API.txt | 206 ++++++++++++++++++++++++++------------------ plants_lib/init.lua | 94 +++++++++++--------- 2 files changed, 172 insertions(+), 128 deletions(-) diff --git a/API.txt b/API.txt index 5bd9c49..42fefc9 100644 --- a/API.txt +++ b/API.txt @@ -15,7 +15,7 @@ dbg() ----- The first of these, spawn_on_surfaces() is defined with quite a large number of variables. All of the variables below, if specified at all, must be -specified exactly in the order given here. +specified exactly in the order given here. This function has no return value. spawn_on_surfaces = function(sdelay, splant, sradius, schance, ssurface, savoid, seed_diff, lightmin, lightmax, nneighbors, @@ -24,103 +24,139 @@ spawn_on_surfaces = function(sdelay, splant, sradius, schance, ssurface, The first several of these are all required, and are from the last version of the flowers mod, so this part of the API should be the same as before. -sdelay: The value passed to the ABM's interval parameter, usually in the - 1000-3000 range. -splant: The node name of the item to spawn (e.g. "flowers:flower_rose"). - Note that if the plant is "poisonivy:seedling", and it's next to - a wall at spawn time, it automatically becomes the wall-climbing - variety. A plant will of course only be spawned if the node about - to be replaced is air. -sradius: Don't spawn within this many nodes of the avoid items mentioned - below. -schance: The value passed to the ABM's chance parameter, normally in the - 10-100 range. -ssurface: Table with the names of the nodes on which to spawn the plant in - question, such as {"default:sand","default:dirt_with_grass"}. It - is not recommended to put "default:dirt" or "default:stone" into - this table if you can do without it, as this will cause the engine - to process potentially large numbers of such nodes when deciding - when to execute the ABM. -savoid: Table with a list of groups and/or node names to avoid when - spawning the plant, such as {"group:flowers","default:tree"}. +sdelay: The value passed to the ABM's interval parameter, usually + in the 1000-3000 range. +splant: The node name of the item to spawn (e.g. + "flowers:flower_rose"). Note that if the plant is + "poisonivy:seedling", and it's next to a wall at spawn + time, it automatically becomes the wall-climbing variety. + A plant will of course only be spawned if the node about + to be replaced is air. +sradius: Don't spawn within this many nodes of the avoid items + mentioned below. +schance: The value passed to the ABM's chance parameter, normally + in the 10-100 range. +ssurface: Table with the names of the nodes on which to spawn the + plant in question, such as {"default:sand", + "default:dirt_with_grass"}. It is not recommended to put + "default:dirt" or "default:stone" into this table if you + can do without it, as this will cause the engine to + process potentially large numbers of such nodes when + deciding when to execute the ABM and where it should + operate. +savoid: Table with a list of groups and/or node names to avoid + when spawning the plant, such as {"group:flowers", + "default:tree"}. From here down are several optional parameters. You can use as many as you need, but you must specify them in order (so if you want lightmax, you need lightmin and seed_diff also, but not the rest). -seed_diff: The perlin seed difference value passed to the - minetest.env:get_perlin() function. Used along with the global - perlin controls below to create the "biome" in which the plants - will spawn. Usually a value of somewhere in the 10 to 100 range - is good. Defaults to 0 if not provided -lightmin: Minimum amount of light necessary to make a plant spawn. Defaults - to 0. -lightmax: Maximum amount of light present to allow a plant to spawn. - Defaults to the engine's MAX_LIGHT value of 14. -nneighbors: Table with a list of neighboring nodes, passed to the ABM as the - "neighbors" parameter, indicating what needs to be next to the - node the plant is about to spawn on, such as - {"default:stone","default:water_source"}. Defaults to the value - of ssurface if not provided. -ocount: There must be at least this many of the above neighbors around the - node the plant is about to spawn on for it to happen. Defaults to - 0. -facedir: The value passed to the param2 variable when adding the plant node - to the map. Defaults to 0. -depthmax: If a node spawns on top of a water source, the water must be at - most this deep. Defaults to 1 node. -altitudemin: Items must be at this altitude or higher to spawn at all. - Defaults to -31000. -altitudemax: But no higher than this altitude. Defaults to +31000. +seed_diff: The perlin seed difference value passed to the + minetest.env:get_perlin() function. Used along with the + global perlin controls below to create the "biome" in + which the plants will spawn. Usually a value of somewhere + in the 10 to 100 range is good. Defaults to 0 if not + provided. +lightmin: Minimum amount of light necessary to make a plant spawn. + Defaults to 0. +lightmax: Maximum amount of light present to allow a plant to spawn. + Defaults to the engine's MAX_LIGHT value of 14. +nneighbors: Table with a list of neighboring nodes, passed to the ABM + as the "neighbors" parameter, indicating what needs to be + next to the node the plant is about to spawn on, such as + {"default:stone","default:water_source"}. Defaults to the + value of ssurface if not provided. +ocount: There must be at least this many of the above neighbors in + the eight spaces immediately surrounding the node the + plant is about to spawn on for it to happen. Defaults to + 0. +facedir: The value passed to the param2 variable when adding the + plant node to the map. Defaults to 0. +depthmax: If a node spawns on top of a water source, the water must + be at most this deep. Defaults to 1 node. +altitudemin: Items must be at this altitude or higher to spawn at all. + Defaults to -31000. +altitudemax: But no higher than this altitude. Defaults to +31000. +sbiome: List of nodes that must be somewhere in the vicinity in + order for the plant to spawn. Typically this would be + something like "default:water_source" or "default:sand". + Defaults to the value of ssurface if not provided. +sbiomesize: How large of an area to check for the above node. + Specifically, this checks a cuboid area centered on the + node to be spawned on, 3 tall and this wide/long. + Defaults to 0. +sbiomecount: How many of the above nodes must be within that radius. + Defaults to 1. + +By default, if a biome node, size, and count are not defined, the biome +checking is disabled. Same holds true for the nneighbors bit above that. ----- -The second function, grow_plants() is defined like so: +The second function, grow_plants() is used to turn the spawned nodes above +into something else over time. This function has no return value, and is +defined like so: grow_plants = function(gdelay, gchance, gplant, gresult, dry_early_node, grow_nodes, facedir, need_wall, grow_vertically, height_limit, - ground_nodes) + ground_nodes, grow_function) -gdelay: Passed as the ABM "interval" parameter, as with spawning. -gchance: Passed as the ABM "chance" parameter. -gplant: Name of the node being grown. This value is passed as the - only item in the table given to the ABM as the nodenames - parameter, so it is the plants themselves that are the ABM - trigger, rather than the ground they spawned on. A plant - will only grow if the node above it is air. -gresult: Name of the node into which the above should transform when - the ABM executes. -dry_early_node: This value is ignored except for jungle grass, where it - indicates which node the grass must be on in order for it to - turn from "short" to default:dry_shrub. -grow_nodes: This node must be under the plant in order for it to grow at - all. Normally this should be the same as the list of - surfaces passed to the spawning ABM as the "nodenames" - parameter, such as - {"default:dirt_with_grass","default:sand"}. This is so that - the plant can be manually placed on something like a flower - pot or something without it growing and eventually dieing. -facedir: Same as with spawning a plant. If supplied, this value is - passed to the param2 variable when changing the plant. If nil - or left out, no new param2 value is applied. -need_wall: Set this to true if you the plant needs to grow against a - wall. Defaults to false. -grow_vertically: Set this to true if the plant needs to grow vertically, as in - climbing poison ivy. Defaults to false. -height_limit: Just how tall can a vertically-growing plant go? Set this - accordingly. The mod will search straight down from the - position being spawned at to find a ground node, below. - Defaults to 62000 (unlimited). -ground_nodes: What nodes should be treated as "the ground" below a - vertically-growing plant. Usually this will be the same as - the grow_nodes table, but might also include, for example, - water or some other surrounding material. Defaults to - "default:dirt_with_grass". +gdelay: Passed as the ABM "interval" parameter, as with spawning. +gchance: Passed as the ABM "chance" parameter. +gplant: Name of the node being grown. This value is passed as the + only item in the table given to the ABM as the nodenames + parameter, so it is the plants themselves that are the ABM + trigger, rather than the ground they spawned on. A plant + will only grow if the node above it is air. +gresult: Name of the node into which the above should transform + when the ABM executes. +dry_early_node: This value is ignored except for jungle grass, where it + indicates which node the grass must be on in order for it + to turn from "short" to default:dry_shrub. +grow_nodes: This node must be under the plant in order for it to grow + at all. Normally this should be the same as the list of + surfaces passed to the spawning ABM as the "nodenames" + parameter, such as {"default:dirt_with_grass", + "default:sand"}. This is so that the plant can be + manually placed on something like a flower pot or + something without it growing and eventually dieing. +facedir: Same as with spawning a plant. If supplied, this value is + passed to the param2 variable when changing the plant. If + nil or left out, no new param2 value is applied. +need_wall: Set this to true if you the plant needs to grow against a + wall. Defaults to false. +grow_vertically: Set this to true if the plant needs to grow vertically, as + in climbing poison ivy. Defaults to false. +height_limit: Just how tall can a vertically-growing plant go? Set this + accordingly. The mod will search straight down from the + position being spawned at to find a ground node, below. + Defaults to 62000 (unlimited). +ground_nodes: What nodes should be treated as "the ground" below a + vertically-growing plant. Usually this will be the same + as the grow_nodes table, but might also include, for + example, water or some other surrounding material. + Defaults to "default:dirt_with_grass". +grow_function: Execute the named function (which must be supplied as just + the name of the function as a string) when growing this + node, rather than using the method provided by the default + growing code. Note that if this is specified, only the + gdelay, gchance, and gplant variables will be used, the + rest will be ignored by the growing ABM. You can still + read them from within the function if you need to. The + function will be passed two parameters in order: The + position of the node to be "grown" (in the usual table + format), and the Perlin noise value at the location in + question. +seed_diff: The perlin seed diff to be use to calculate the noise + value given to the above grow_function. Should be the + same as the seed diff used when first spawning the plant + that's being grown. ----- -plant_valid_wall() expects only a single parameter, "pos", which is a table -indicating the X,Y,Z coordinates to search for nearby adjacent walls. This -function returns the location of the first wall found as a facedir value, or -nil if there are no adjacent walls. +plant_valid_wall() expects only a single parameter, "pos", which is the usual +table indicating the coordinates around which to search for adjacent walls. +This function returns the location of the first wall found as a facedir value, +or nil if there are no adjacent walls. ----- is_node_loaded() is defined in exactly the same manner (that is, "node_pos" is diff --git a/plants_lib/init.lua b/plants_lib/init.lua index c0cb353..f5bcf1b 100644 --- a/plants_lib/init.lua +++ b/plants_lib/init.lua @@ -1,20 +1,13 @@ --- Plantlife mod by Vanessa Ezekowitz --- 2012-11-29 +-- Plantlife library mod by Vanessa Ezekowitz +-- 2013-01-00 -- --- This mod combines all of the functionality from poison ivy, --- flowers, and jungle grass. If you have any of these, you no --- longer need them. --- --- License: --- CC-BY-SA for most textures, except flowers --- WTFPL for the flowers textures --- WTFPL for all code and everything else +-- License: WTFPL -- Various settings - most of these probably won't need to be changed plantlife_seed_diff = 329 -- needs to be global so other mods can see it -local plantlife_debug = false -- ...unless you want the modpack to spam the console ;-) +local plantlife_debug = true -- ...unless you want the modpack to spam the console ;-) local perlin_octaves = 3 local perlin_persistence = 0.6 @@ -42,15 +35,18 @@ end -- The spawning ABM -spawn_on_surfaces = function(sdelay, splant, sradius, schance, ssurface, savoid, seed_diff, lightmin, lightmax, nneighbors, ocount, facedir, depthmax, altmin, altmax) +spawn_on_surfaces = function(sdelay, splant, sradius, schance, ssurface, savoid, seed_diff, lightmin, lightmax, nneighbors, ocount, facedir, depthmax, altmin, altmax, sbiome, sbiomesize, sbiomecount) 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 = 0 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 minetest.register_abm({ nodenames = { ssurface }, interval = sdelay, @@ -66,7 +62,12 @@ spawn_on_surfaces = function(sdelay, splant, sradius, schance, ssurface, savoid, 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 + 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 pos.y >= altmin and pos.y <= altmax then @@ -91,7 +92,7 @@ end -- The growing ABM -grow_plants = function(gdelay, gchance, gplant, gresult, dry_early_node, grow_nodes, facedir, need_wall, grow_vertically, height_limit, ground_nodes) +grow_plants = function(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 @@ -106,39 +107,46 @@ grow_plants = function(gdelay, gchance, gplant, gresult, dry_early_node, grow_no local n_top = minetest.env:get_node(p_top) local n_bot = minetest.env:get_node(p_bot) local groundnode = 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_vertically then - if find_first_node(pos, height_limit, ground_nodes) ~= nil then - if need_wall then - local walldir=plant_valid_wall(p_top) - if walldir ~= nil then - dbg("Grow: "..gplant.." upwards to ("..dump(p_top)..") on wall "..walldir) - minetest.env:add_node(p_top, { name = gplant, param2 = walldir }) + if grow_function == nil then + if string.find(dump(grow_nodes), n_bot.name) ~= nil and n_top.name == "air" then + if grow_vertically then + if find_first_node(pos, height_limit, ground_nodes) ~= nil then + if need_wall then + local walldir=plant_valid_wall(p_top) + if walldir ~= nil then + dbg("Grow: "..gplant.." upwards to ("..dump(p_top)..") on wall "..walldir) + minetest.env:add_node(p_top, { name = gplant, param2 = walldir }) + end + else + dbg("Grow: "..gplant.." upwards to ("..dump(p_top)..")") + minetest.env:add_node(p_top, { name = gplant }) end + end + + -- corner case for changing short junglegrass to dry shrub in desert + elseif n_bot.name == dry_early_node and gplant == "junglegrass:short" then + dbg("Die: "..gplant.." becomes default:dry_shrub at ("..dump(pos)..")") + minetest.env:add_node(pos, { name = "default:dry_shrub" }) + + elseif gresult == nil then + dbg("Die: "..gplant.." at ("..dump(pos)..")") + minetest.env:remove_node(pos) + + elseif gresult ~= nil then + dbg("Grow: "..gplant.." becomes "..gresult.." at ("..dump(pos)..")") + if facedir == nil then + minetest.env:add_node(pos, { name = gresult }) else - dbg("Grow: "..gplant.." upwards to ("..dump(p_top)..")") - minetest.env:add_node(p_top, { name = gplant }) + minetest.env:add_node(pos, { name = gresult, param2 = facedir }) end end - - -- corner case for changing short junglegrass to dry shrub in desert - elseif n_bot.name == dry_early_node and gplant == "junglegrass:short" then - dbg("Die: "..gplant.." becomes default:dry_shrub at ("..dump(pos)..")") - minetest.env:add_node(pos, { name = "default:dry_shrub" }) - - elseif gresult == nil then - dbg("Die: "..gplant.." at ("..dump(pos)..")") - minetest.env:remove_node(pos) - - elseif gresult ~= nil then - 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 end + else + if seed_diff == nil then seed_diff = 0 end + local perlin = minetest.env:get_perlin(seed_diff, perlin_octaves, perlin_persistence, perlin_scale ) + local noise = perlin:get2d({x=pos.x, y=pos.z}) + dbg("Want to execute "..grow_function.."("..dump(pos)..","..noise..")") + assert(loadstring(grow_function.."("..dump(pos)..","..noise..")"))() end end })