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:
Vanessa Ezekowitz 2013-01-24 23:21:57 -05:00
parent 3024c78c2b
commit 68a6ce43a7
14 changed files with 870 additions and 437 deletions

453
API.txt
View File

@ -1,6 +1,6 @@
This document briefly describes the Plantlife API. This document briefly describes the Plantlife API.
Last revision: 2013-01-18 Last revision: 2013-01-25
========= =========
Functions Functions
@ -22,91 +22,206 @@ at any time. See init.lua for more.
----- -----
The first of these, spawn_on_surfaces() is defined with quite a large number The first function is an ABM-based spawner function originally created as
of variables. All of the variables below, if specified at all, must be part of Ironzorg's flowers mod. It has since been largely extended and
specified exactly in the order given here. This function has no return value. expanded. There are two ways to call this function. Either via the legacy
method like that which was used in the Flowers mod:
spawn_on_surfaces = function(sdelay, splant, sradius, schance, ssurface, spawn_on_surfaces(sdelay, splant, sradius, schance, ssurface, savoid)
savoid, seed_diff, lightmin, lightmax, nneighbors, ocount, facedir,
depthmax, altitudemin, altitudemax, sbiome, sbiomesize, sbiomecount,
airsize, aircount, tempmin, tempmax)
The first several of these are all required, and are from the last version of Or, you can specify the various options with a single table as the parameter:
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, in seconds. spawn_on_surfaces({table of options})
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 (1-in-X chance of operating on a given
node, e.g. 1-in-10).
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 When used with the legacy interface, you must specify the parameters exactly
need, but you must specify them in order. To keep the default values for in order, with the first five being mandatory and the last one being optional:
those parameters you don't wish to alter, set them to nil in your function
call.
seed_diff: The Perlin seed difference value passed to the sdelay: The value passed to the ABM's interval parameter, in
minetest.env:get_perlin() function. Used along with the seconds.
global Perlin controls below to create the "biome" in splant: The node name of the item to spawn (e.g.
which the plants will spawn. Usually a value of somewhere "flowers:flower_rose"). Note that if the plant is
in the 10 to 100 range is good. Defaults to 0 if not "poisonivy:seedling", and it's next to a wall at spawn
provided. time, it automatically becomes the wall-climbing
lightmin: Minimum amount of light necessary to make a plant spawn. variety. A plant will of course only be spawned if the
Defaults to 0. node about to be replaced is air.
lightmax: Maximum amount of light present to allow a plant to spawn. sradius: Don't spawn within this many nodes of the avoid items
Defaults to the engine's MAX_LIGHT value of 14. mentioned below. If set to nil, this check is
nneighbors: Table with a list of neighboring nodes, passed to the ABM skipped.
as the "neighbors" parameter, indicating what needs to be schance: The value passed to the ABM's chance parameter,
next to the node the plant is about to spawn on, such as normally in the 10-100 range (1-in-X chance of
{"default:stone","default:water_source"}. Defaults to the operating on a given node, e.g. 1-in-10).
value of ssurface if not provided. ssurface: String with the name of the node on which to spawn
ocount: There must be at least this many of the above neighbors in the plant in question, such as "default:sand" or
the eight spaces immediately surrounding the node the "default:dirt_with_grass". It is not recommended to
plant is about to spawn on for it to happen. Defaults to put air, stone, or plain dirt here if you can use some
0. other node, as doing so will cause the engine to
facedir: The value passed to the param2 variable when adding the process potentially large numbers of such nodes when
plant node to the map. Defaults to 0. deciding when to execute the ABM and where it should
depthmax: If a node spawns on top of a water source, the water must operate.
be at most this deep. Defaults to 1 node. savoid: Table with a list of groups and/or node names to avoid
altitudemin: Items must be at this altitude or higher to spawn at all. when spawning the plant, such as {"group:flowers",
Defaults to -31000. "default:tree"}. If not specified, this defaults to
altitudemax: But no higher than this altitude. Defaults to +31000. the value of splant.
sbiome: List of nodes that must be somewhere in the vicinity in
order for the plant to spawn. Typically this would be When passed a table as the argument, and thus using the modern calling method,
something like "default:water_source" or "default:sand". you must pass at least four arguments as regular keyed entries in the table,
Defaults to the value of ssurface if not provided. in any order:
sbiomesize: How large of an area to check for the above node.
Specifically, this checks a cuboid area centered on the plants_lib: spawn_on_surfaces({
node to be spawned on, 3 tall and this wide/long. spawn_plants = {table}, -- List of plants to spawn with this ABM call.
Defaults to 0. -- The program will choose one of these at
sbiomecount: How many of the above nodes must be within that radius. -- random each time the ABM executes. The
Defaults to 1. -- more nodes you can pack into this parameter
airradius: How large of an area to check for air around the target. -- to avoid making too many calls to this
Defaults to 0 (only check the target). -- function, the lower the CPU load will
aircount: How many of the surrounding nodes need to be air for the -- likely be.
above check to return true. Defaults to 1. spawn_delay = number, -- same as sdelay
tempmin: Minimum 2d Perlin value (which has a floating point range of spawn_chance = number, -- same as schance
-1 to +1) needed in the temperature map for the desired spawn_surfaces = {table} -- List of node names on which the plants
plant to spawn. Defaults to -1 if not supplied. -- should be spawned. As with the single-
tempmax: Maximum temperature. Defaults to +1. -- node "ssurface" option in the legacy API,
-- you should not put stone, air, etc. here.
-- From here down are several optional
-- parameters.
avoid_nodes = {table}, -- same meaning as savoid, above
avoid_radius = num, -- same as sradius
seed_diff = num -- 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. Defaults to 0 if not
-- provided.
light_min = num, -- Minimum amount of light necessary to make a
-- plant spawn. Defaults to 0.
light_max = num, -- Maximum amount of light needed to spawn.
-- Defaults to the engine's MAX_LIGHT value of
-- 14.
neighbors = {table}, -- List of neighboring nodes that need to be
-- immediately next to the node the plant is
-- about to spawn on. Can also be a string
-- with a single node name. It is both passed
-- to the ABM as the "neighbors" parameter,
-- and is used to manually check the
-- adjacent nodes. It only takes one of these
-- for the spawn routine to mark the target as
-- spawnable. Defaults to nil (ignored).
ncount = num, -- 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. If
-- not provided, this check is disabled.
facedir = num, -- The value passed to the param2 variable
-- when adding the node to the map. Defaults
-- to 0. Be sure that the value you use here
-- (and the range thereof) is appropriate for
-- the type of node you're spawning.
random_facedir = {table}, -- If set, the table should contain two
-- values. If they're both provided, the
-- spawned plant will be given a random
-- facedir value in the range specified by
-- these two numbers. Overrides the facedir
-- parameter above, if it exists. Use {0,3}
-- if you want the full range for wallmounted
-- nodes, or {2,5} for most everything else,
-- or any other pair of numbers in the 0 to 5
-- range, as appropriate for the node you want
-- to spawn.
verticals_list = {table} -- List of nodes that should be considered to
-- be natural walls.
alt_wallnode = "string", -- If specified, this node will be
-- substituted in place of the plant(s)
-- defined by spawn_plants above, if the spawn
-- target has one or more adjacent walls. In
-- such a case, the two above facedir
-- parameters will be ignored.
depth_max = num, -- If the object spawns on top of a water
-- source, the water must be at most this
-- deep. Defaults to 1 node.
min_elevation = num, -- Surface must be at this altitude or higher
-- to spawn at all. Defaults to -31000...
max_elevation = num, -- ...but must be no higher than this
-- altitude. Defaults to +31000.
near_nodes = {table}, -- List of nodes that must be somewhere in the
-- vicinity in order for the plant to spawn.
-- Can also be a string with a single node
-- name. If not provided, this check is
-- disabled.
near_nodes_size = num, -- How large of an area to check for the above
-- node. Specifically, this checks a flat
-- horizontal area centered on the node to be
-- spawned on. Defaults to 0, but is ignored
-- if the above near_nodes value is not set.
near_nodes_vertical = num, -- Used with the size value above, this
-- extends the vertical range of the near
-- nodes search. Basically, this turns the
-- flat region described above into a cuboid
-- region. The area to be checked will extend
-- this high AND this low above/below the
-- target node, centered thereon. Defaults to
-- 1 (check only the layer above, the layer
-- at, and the layer below the target node),
-- but is ignored if near_nodes is not set.
near_nodes_count = num, -- How many of the above nodes must be within
-- that radius. Defaults to 1 but is ignored
-- if near_nodes isn't set. Bear in mind that
-- the total area to be checked is equal to
-- (near_nodes_size^2)*near_nodes_vertical*2.
-- so for example, if size is 10 and vertical
-- is 4 then the area is (10^2)*8 = 800 nodes
-- in size, so you'll want to make sure you
-- specify a value appropriate for the amount
-- in question.
air_size = num, -- How large of an area to check for air
-- above and around the target. If omitted,
-- only the space above the target is checked.
-- This does not check for air at the sides or
-- below the target.
air_count = num, -- How many of the surrounding nodes need to
-- be air for the above check to return true.
-- If omitted, only the space above the target
-- is checked.
plantlife_limit = num, -- The value compared against the generic
-- "plants can grow here" Perlin noise layer.
-- Smaller numbers result in more abundant
-- plants. Range of -1 to +1, with values in
-- the range of about 0 to 0.5 being most
-- useful. Defaults to 0.1.
temp_min = num, -- Minimum temperature needed for the desired
-- object to spawn. This is a 2d Perlin
-- value, which has an inverted range of +1 to
-- -1. Larger values represent *colder*
-- temperatures, so this value is actually the
-- upper end of the desired Perlin range. See
-- the temperature map section at the bottom
-- of this document for details on how these
-- values work. Defaults to +1 (unlimited
-- coldness).
temp_max = num, -- Maximum temperature/lower end of the Perlin
-- range. Defaults to -1 (unlimited heat).
spawn_on_side = bool, -- Set this to true to spawn the node on one
-- side of the target node rather than the
-- top. The code will search for an airspace
-- to the side of the target, then spawn the
-- plant at the first one found. The above
-- facedir and random_facedir parameters are
-- ignored in this case. If the above
-- parameters for selecting generic wall nodes
-- are provided, this option is ignored.
-- Important note: the facedir values assigned
-- by this option only make sense with
-- wallmounted nodes (nodes which don't use
-- facedir won't be affected).
spawn_on_bottom = bool, -- If set to true, spawn the object below the
-- target node instead of above it. The above
-- spawn_on_side variable takes precedence
-- over this one if both happen to be true.
-- When using this option with the random
-- facedir function above, the values given to
-- the facedir parameter are for regular
-- nodes, not wallmounted.
})
By default, if a biome node, size, and count are not defined, the biome 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. checking is disabled. Same holds true for the nneighbors bit above that.
@ -120,7 +235,7 @@ node (see below):
plantslib:register_generate_plant(biome, function_or_treedef) plantslib:register_generate_plant(biome, function_or_treedef)
Where "biome" is a table containing about a dozen variables: Where "biome" is a table containing about a dozen variables.
biome = { biome = {
surface = "string", -- [*] what nodes to spawn on. surface = "string", -- [*] what nodes to spawn on.
@ -153,13 +268,23 @@ biome = {
of the object being spawned. of the object being spawned.
near_nodes_size = num, -- how wide of a search area to look for near_nodes_size = num, -- how wide of a search area to look for
the nodes in that list. the nodes in that list.
near_nodes_vertical = num, -- How high/low of an area to search from
-- the target node.
near_nodes_count = num, -- at least this many of those nodes must be near_nodes_count = num, -- at least this many of those nodes must be
in the area. in the area.
plantlife_limit = num, -- The value compared against the generic
-- "plants can grow here" Perlin noise layer.
-- Smaller numbers result in more abundant
-- plants. Range of -1 to +1, with values in
-- the range of about 0 to 0.5 being most
-- useful. Defaults to 0.1.
temp_min = num, -- coldest allowable temperature for a plant temp_min = num, -- coldest allowable temperature for a plant
to spawn (that is, the highest Perlin to spawn (that is, the highest Perlin
temperature map value). temperature map value).
temp_max = num, -- warmest allowable temperature to spawn a temp_max = num, -- warmest allowable temperature to spawn a
plant (lowest Perlin temperature value). plant (lowest Perlin temperature value).
verticals_list = {table}, -- Same as with the spawn_on_surfaces
-- function.
} }
[*] These entries are required for the spawn code to work. Everything else [*] These entries are required for the spawn code to work. Everything else
@ -179,82 +304,120 @@ with the position to spawn the tree on.
----- -----
The third function, grow_plants() is used to turn the spawned nodes above The third function, grow_plants() is used to turn the spawned nodes above
into something else over time. This function has no return value, and is into something else over time. This function has no return value, and accepts
defined like so: a table as the only parameter:
grow_plants = function(gdelay, gchance, gplant, gresult, dry_early_node, grow_plants({list of options})
grow_nodes, facedir, need_wall, grow_vertically, height_limit,
ground_nodes, grow_function, seed_diff)
gdelay: Passed as the ABM "interval" parameter, as with spawning. These are defined like so:
gchance: Passed as the ABM "chance" parameter.
gplant: Name of the node being grown. This value is passed as the plants_lib:grow_plants({
only item in the table given to the ABM as the nodenames
parameter, so it is the plants themselves that are the ABM grow_plant = "string", -- Name of the node to be grown into something
trigger, rather than the ground they spawned on. A plant -- else. This value is passed to the ABM as
will only grow if the node above it is air. -- the "nodenames" parameter, so it is the
gresult: Name of the node into which the above should transform -- plants themselves that are the ABM trigger,
when the ABM executes. -- rather than the ground they spawned on. A
dry_early_node: This value is ignored except for jungle grass, where it -- plant will only grow if the node above it
indicates which node the grass must be on in order for it -- is air. Can also be a table, but note that
to turn from "short" to default:dry_shrub. -- all nodes referenced therein will be grown
grow_nodes: One of these nodes must be under the plant in order for it to -- into the same object.
grow at all. Normally this should be the same as the list of grow_delay = num, -- Passed as the ABM "interval" parameter, as
surfaces passed to the spawning ABM as the "nodenames" -- with spawning.
parameter. This is so that the plant can be manually placed grow_chance = num, -- Passed as the ABM "chance" parameter.
on something like a flower pot or something without it growing grow_result = "string", -- Name of the node into which the grow_plant
and eventually dieing. Defaults to "default:dirt_with_grass". -- node(s) should transform when the ABM
facedir: Same as with spawning a plant. If supplied, this value is -- executes.
passed to the param2 variable when changing the plant. If dry_early_node = "string" -- This value is ignored except for jungle
nil or left out, no new param2 value is applied. -- grass (a corner case needed by that mod),
need_wall: Set this to true if you the plant needs to grow against a -- where it indicates which node the grass
wall. Defaults to false. -- must be on in order for it to turn from
grow_vertically: Set this to true if the plant needs to grow vertically, as -- the short size to "default:dry_shrub"
in climbing poison ivy. Defaults to false. -- instead of the medium size.
height_limit: Just how tall can a vertically-growing plant go? Set this grow_nodes = {table}, -- One of these nodes must be under the plant
accordingly. The mod will search straight down from the -- in order for it to grow at all. Normally
position being spawned at to find a ground node, set via the -- this should be the same as the list of
parameter below. Defaults to 62000 (unlimited). -- surfaces passed to the spawning ABM as the
ground_nodes: What nodes should be treated as "the ground" below a -- "nodenames" parameter. This is so that the
vertically-growing plant. Usually this will be the same -- plant can be manually placed on something
as the grow_nodes table, but might also include, for -- like a flower pot or something without it
example, water or some other surrounding material. -- growing and eventually dieing. Defaults to
Defaults to "default:dirt_with_grass". -- "default:dirt_with_grass".
grow_function: String indicating what function to use to grow the plant, if facedir = num, -- Same as with spawning a plant.
any, or a table with an L-Systems tree model, or nil. If it's need_wall = bool, -- Set this to true if you the plant needs to
nil, If it's nil, a regular plant will be inserted in place -- grow against a wall. Defaults to false.
of the one being grown, per the above variables. If it's a verticals_list = {table}, -- List of nodes that should be considered
string, the function named therein is executed and passed a -- to be wall surfaces when growing the plant
parameter for the current position, followed by the "can grow -- vertically. If not provided, the walls
here" and temperature map Perlin values at that location. If -- check is skipped.
it's a table, the tree described by that table is spawned at grow_vertically = bool, -- Set this to true if the plant needs to grow
the current position. In both string and table cases, all -- vertically, as in climbing poison ivy.
parameters from gresult to ground_nodes, except for -- Defaults to false.
grow_nodes, are ignored. height_limit = num, -- Set this to limit how tall the desired node
seed_diff: The Perlin seed diff to be use to calculate the first noise -- can grow. The mod will search straight
value given to the above grow_function. Should be the same as -- down from the position being spawned at to
the seed diff used when first spawning the plant that's being -- find a ground node, set via the parameter
grown. -- below. Defaults to 5 nodes.
ground_nodes = {table}, -- What nodes should be treated as "the
-- ground" below a vertically-growing plant.
-- Usually this should 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 = something, -- [*] see below.
seed_diff = num, -- [*] see below.
})
[*] grow_function can take one of three possible settings: it can be nil (or
not provided), a string, or a table.
If it is not provided or it's set to nil, all of the regular growing code
is executed normally. The value of seed_diff, if any, is ignored in this
case.
If this value is set to a simple string, this is treated as the name of
the function to use to grow the plant. In this case, all of the usual
growing code is executeed, but then instead of a plant being simply added
to the world, grow_result is ignored and the named function is executed
and passed a few parmeters:
somefunction(pos, perlin1, perlin2)
These values represent the current position (the usual table), the
Perlin noise value for that spot in the generic "plants can grow here"
map for the seed_diff value above, the Perlin value for that same spot
from the temperature map, and the detected neighboring wall face, if
there was one (or nil if not). If seed_diff is not provided, it
defaults to 0.
If this variable is instead set to a table, it is treated an an L-Systems
tree definition. All of the growing code is executed in the usual manner,
then the tree described by that definition is spawned at the current
position instead, and grow_result is ignored.
----- -----
Of the few helper functions, plant_valid_wall() expects only a single Of the few helper functions, plantslib:find_adjacent_wall() expects a position
parameter, "pos", which is the usual table indicating the coordinates around parameter and a table with the list of nodes that should be considered as
which to search for adjacent walls. This function returns the location of the walls. The code will search around the given position for a neighboring wall,
first wall found as a facedir value, or nil if there are no adjacent walls. returning the first one it finds 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 plantslib:is_node_loaded() is defined in exactly the same manner (that is,
a set of coordinates), and acts as a wrapper for the "node_pos" is a set of coordinates), and acts as a wrapper for the
minetest.env:get_node_or_nil(node_pos) function. Returns true if the node in minetest.env:get_node_or_nil(node_pos) function. Returns true if the node in
question is already loaded, or false if not. question is already loaded, or false if not.
----- -----
dbg() is a simple debug output function which takes one string parameter. It plantslib:dbg() is a simple debug output function which takes one string
just checks if plantlife_debug is true and outputs the phrase "[Plantlife] " parameter. It just checks if DEBUG is true and outputs the phrase
followed by the supplied string, via the print() function. "[Plantlife] " followed by the supplied string, via the print() function, if
so.
=============== ===============

View File

@ -1,27 +1,25 @@
-- This file supplies flowers for the plantlife modpack -- This file supplies flowers for the plantlife modpack
-- Last revision: 2013-01-24
local spawn_delay = 2000 -- 2000 local SPAWN_DELAY = 1000
local spawn_chance = 100 -- 100 local SPAWN_CHANCE = 200
local flowers_seed_diff = plantslib.plantlife_seed_diff+20 local flowers_seed_diff = 349
local flowers_list = { local flowers_list = {
{ "Rose", "rose", spawn_delay, 10, spawn_chance , 10}, { "Rose", "rose"},
{ "Tulip", "tulip", spawn_delay, 10, spawn_chance , 10}, { "Tulip", "tulip"},
{ "Yellow Dandelion", "dandelion_yellow", spawn_delay, 10, spawn_chance*2 , 10}, { "Yellow Dandelion", "dandelion_yellow"},
{ "White Dandelion", "dandelion_white", spawn_delay, 10, spawn_chance*2 , 10}, { "White Dandelion", "dandelion_white"},
{ "Blue Geranium", "geranium", spawn_delay, 10, spawn_chance , 10}, { "Blue Geranium", "geranium"},
{ "Viola", "viola", spawn_delay, 10, spawn_chance , 10}, { "Viola", "viola"},
{ "Cotton Plant", "cotton", spawn_delay, 10, spawn_chance*2 , 10}, { "Cotton Plant", "cotton"},
} }
for i in ipairs(flowers_list) do for i in ipairs(flowers_list) do
local flowerdesc = flowers_list[i][1] local flowerdesc = flowers_list[i][1]
local flower = flowers_list[i][2] local flower = flowers_list[i][2]
local delay = flowers_list[i][3]
local radius = flowers_list[i][4]
local chance = flowers_list[i][5]
minetest.register_node(":flowers:flower_"..flower, { minetest.register_node("flowers:flower_"..flower, {
description = flowerdesc, description = flowerdesc,
drawtype = "plantlike", drawtype = "plantlike",
tiles = { "flower_"..flower..".png" }, tiles = { "flower_"..flower..".png" },
@ -38,7 +36,7 @@ for i in ipairs(flowers_list) do
}, },
}) })
minetest.register_node(":flowers:flower_"..flower.."_pot", { minetest.register_node("flowers:flower_"..flower.."_pot", {
description = flowerdesc.." in a pot", description = flowerdesc.." in a pot",
drawtype = "plantlike", drawtype = "plantlike",
tiles = { "flower_"..flower.."_pot.png" }, tiles = { "flower_"..flower.."_pot.png" },
@ -63,29 +61,100 @@ for i in ipairs(flowers_list) do
"flowers:flower_"..flower "flowers:flower_"..flower
} }
}) })
plantslib:spawn_on_surfaces(delay, "flowers:flower_"..flower, radius, chance, "default:dirt_with_grass", {"group:flower", "group:poisonivy"}, flowers_seed_diff)
end end
minetest.register_node(":flowers:flower_waterlily", { minetest.register_node("flowers:flower_waterlily", {
description = "Waterlily", description = "Waterlily",
drawtype = "raillike", drawtype = "nodebox",
tiles = { "flower_waterlily.png" }, tiles = { "flower_waterlily.png" },
inventory_image = "flower_waterlily.png", inventory_image = "flower_waterlily.png",
wield_image = "flower_waterlily.png", wield_image = "flower_waterlily.png",
sunlight_propagates = true, sunlight_propagates = true,
paramtype = "light", paramtype = "light",
paramtype2 = "wallmounted", paramtype2 = "facedir",
walkable = false, walkable = false,
groups = { snappy = 3,flammable=2,flower=1 }, groups = { snappy = 3,flammable=2,flower=1 },
sounds = default.node_sound_leaves_defaults(), sounds = default.node_sound_leaves_defaults(),
selection_box = { selection_box = {
type = "fixed", type = "fixed",
fixed = { -0.4, -0.5, -0.4, 0.4, -0.45, 0.4 }, fixed = { -0.4, -0.5, -0.4, 0.4, -0.45, 0.4 },
}, },
node_box = {
type = "fixed",
fixed = { -0.5, -0.49, -0.5, 0.5, -0.49, 0.5 },
},
}) })
minetest.register_node(":flowers:flower_seaweed", { minetest.register_node("flowers:flower_waterlily_225", {
description = "Waterlily",
drawtype = "nodebox",
tiles = { "flower_waterlily_22.5.png" },
inventory_image = "flower_waterlily.png",
wield_image = "flower_waterlily.png",
sunlight_propagates = true,
paramtype = "light",
paramtype2 = "facedir",
walkable = false,
groups = { snappy = 3,flammable=2,flower=1, not_in_creative_inventory=1 },
sounds = default.node_sound_leaves_defaults(),
selection_box = {
type = "fixed",
fixed = { -0.4, -0.5, -0.4, 0.4, -0.45, 0.4 },
},
node_box = {
type = "fixed",
fixed = { -0.5, -0.49, -0.5, 0.5, -0.49, 0.5 },
},
drop = "flowers:flower_waterlily"
})
minetest.register_node("flowers:flower_waterlily_45", {
description = "Waterlily",
drawtype = "raillike",
tiles = { "flower_waterlily_45.png" },
inventory_image = "flower_waterlily.png",
wield_image = "flower_waterlily.png",
sunlight_propagates = true,
paramtype = "light",
paramtype2 = "facedir",
walkable = false,
groups = { snappy = 3,flammable=2,flower=1, not_in_creative_inventory=1 },
sounds = default.node_sound_leaves_defaults(),
selection_box = {
type = "fixed",
fixed = { -0.4, -0.5, -0.4, 0.4, -0.45, 0.4 },
},
node_box = {
type = "fixed",
fixed = { -0.5, -0.49, -0.5, 0.5, -0.49, 0.5 },
},
drop = "flowers:flower_waterlily"
})
minetest.register_node("flowers:flower_waterlily_675", {
description = "Waterlily",
drawtype = "nodebox",
tiles = { "flower_waterlily_67.5.png" },
inventory_image = "flower_waterlily.png",
wield_image = "flower_waterlily.png",
sunlight_propagates = true,
paramtype = "light",
paramtype2 = "facedir",
walkable = false,
groups = { snappy = 3,flammable=2,flower=1, not_in_creative_inventory=1 },
sounds = default.node_sound_leaves_defaults(),
selection_box = {
type = "fixed",
fixed = { -0.4, -0.5, -0.4, 0.4, -0.45, 0.4 },
},
node_box = {
type = "fixed",
fixed = { -0.5, -0.49, -0.5, 0.5, -0.49, 0.5 },
},
drop = "flowers:flower_waterlily"
})
minetest.register_node("flowers:flower_seaweed", {
description = "Seaweed", description = "Seaweed",
drawtype = "signlike", drawtype = "signlike",
tiles = { "flower_seaweed.png" }, tiles = { "flower_seaweed.png" },
@ -103,12 +172,99 @@ minetest.register_node(":flowers:flower_seaweed", {
}, },
}) })
plantslib:spawn_on_surfaces(spawn_delay/2, "flowers:flower_waterlily", 3, spawn_chance*2, "default:water_source" , {"group:flower"}, flowers_seed_diff, 10, nil, nil, nil, nil, 4) -- spawn ABM registrations
plantslib:spawn_on_surfaces(spawn_delay*2, "flowers:flower_seaweed" , 0.1, spawn_chance*2, "default:water_source" , {"group:flower"}, flowers_seed_diff, 4, 10, {"default:dirt_with_grass"}, 0, 1) plantslib:spawn_on_surfaces({
plantslib:spawn_on_surfaces(spawn_delay*2, "flowers:flower_seaweed" , 0.1, spawn_chance*2, "default:dirt_with_grass", {"group:flower"}, flowers_seed_diff, 4, 10, {"default:water_source"} , 1, 1) spawn_delay = SPAWN_DELAY,
plantslib:spawn_on_surfaces(spawn_delay*2, "flowers:flower_seaweed" , 0.1, spawn_chance*2, "default:stone" , {"group:flower"}, flowers_seed_diff, 4, 10, {"default:water_source"} , 6, 1) spawn_plants = {
"flowers:flower_rose",
"flowers:flower_tulip",
"flowers:flower_geranium",
"flowers:flower_viola",
},
avoid_radius = 10,
spawn_chance = SPAWN_CHANCE*2,
spawn_surfaces = {"default:dirt_with_grass"},
avoid_nodes = {"group:flower", "group:poisonivy"},
seed_diff = flowers_seed_diff,
light_min = 9
})
plantslib:spawn_on_surfaces({
spawn_delay = SPAWN_DELAY,
spawn_plants = {
"flowers:flower_dandelion_yellow",
"flowers:flower_dandelion_white",
"flowers:flower_cotton",
},
avoid_radius = 7,
spawn_chance = SPAWN_CHANCE,
spawn_surfaces = {"default:dirt_with_grass"},
avoid_nodes = {"group:flower", "group:poisonivy"},
seed_diff = flowers_seed_diff,
light_min = 9
})
plantslib:spawn_on_surfaces({
spawn_delay = SPAWN_DELAY/2,
spawn_plants = {
"flowers:flower_waterlily",
"flowers:flower_waterlily_225",
"flowers:flower_waterlily_45",
"flowers:flower_waterlily_675"
},
avoid_radius = 2.5,
spawn_chance = SPAWN_CHANCE*4,
spawn_surfaces = {"default:water_source"},
avoid_nodes = {"group:flower"},
seed_diff = flowers_seed_diff,
light_min = 9,
depth_max = 2,
random_facedir = {2,5}
})
plantslib:spawn_on_surfaces({
spawn_delay = SPAWN_DELAY*2,
spawn_plants = {"flowers:flower_seaweed"},
spawn_chance = SPAWN_CHANCE*2,
spawn_surfaces = {"default:water_source"},
avoid_nodes = {"group:flower"},
seed_diff = flowers_seed_diff,
light_min = 4,
light_max = 10,
neighbors = {"default:dirt_with_grass"},
facedir = 1
})
plantslib:spawn_on_surfaces({
spawn_delay = SPAWN_DELAY*2,
spawn_plants = {"flowers:flower_seaweed"},
spawn_chance = SPAWN_CHANCE*2,
spawn_surfaces = {"default:dirt_with_grass"},
avoid_nodes = {"group:flower"},
seed_diff = flowers_seed_diff,
light_min = 4,
light_max = 10,
neighbors = {"default:water_source"},
ncount = 1,
facedir = 1
})
plantslib:spawn_on_surfaces({
spawn_delay = SPAWN_DELAY*2,
spawn_plants = {"flowers:flower_seaweed"},
spawn_chance = SPAWN_CHANCE*2,
spawn_surfaces = {"default:stone"},
avoid_nodes = {"group:flower"},
seed_diff = flowers_seed_diff,
light_min = 4,
light_max = 10,
neighbors = {"default:water_source"},
ncount = 6,
facedir = 1
})
-- crafting recipes!
minetest.register_craftitem(":flowers:flower_pot", { minetest.register_craftitem(":flowers:flower_pot", {
description = "Flower Pot", description = "Flower Pot",
@ -124,23 +280,23 @@ minetest.register_craft( {
}) })
minetest.register_craftitem(":flowers:cotton", { minetest.register_craftitem(":flowers:cotton", {
description = "Cotton", description = "Cotton",
image = "cotton.png", image = "cotton.png",
}) })
minetest.register_craft({ minetest.register_craft({
output = "flowers:cotton 3", output = "flowers:cotton 3",
recipe ={ recipe ={
{"flowers:flower_cotton"}, {"flowers:flower_cotton"},
} }
}) })
minetest.register_craft({ minetest.register_craft({
output = "wool:white 2", output = "wool:white 2",
recipe = { recipe = {
{'', '', ''},
{'flowers:cotton', 'flowers:cotton', ''}, {'flowers:cotton', 'flowers:cotton', ''},
{'flowers:cotton', 'flowers:cotton', ''}, {'flowers:cotton', 'flowers:cotton', ''},
} }
}) })
print("[Flowers] Loaded.")

Binary file not shown.

Before

Width:  |  Height:  |  Size: 221 B

After

Width:  |  Height:  |  Size: 413 B

Binary file not shown.

After

Width:  |  Height:  |  Size: 491 B

Binary file not shown.

After

Width:  |  Height:  |  Size: 502 B

Binary file not shown.

After

Width:  |  Height:  |  Size: 471 B

View File

@ -1,10 +1,11 @@
-- This file supplies jungle grass for the plantlife modpack -- This file supplies jungle grass for the plantlife modpack
-- Last revision: 2013-01-24
local spawn_delay = 2000 -- 2000 local SPAWN_DELAY = 1000
local spawn_chance = 100 -- 100 local SPAWN_CHANCE = 200
local grow_delay = 1000 -- 1000 local GROW_DELAY = 500
local grow_chance = 10 -- 10 local GROW_CHANCE = 30
local junglegrass_seed_diff = plantslib.plantlife_seed_diff local junglegrass_seed_diff = 329
local grasses_list = { local grasses_list = {
{"junglegrass:shortest","junglegrass:short" }, {"junglegrass:shortest","junglegrass:short" },
@ -13,7 +14,7 @@ local grasses_list = {
{"default:junglegrass" , nil} {"default:junglegrass" , nil}
} }
minetest.register_node(':junglegrass:medium', { minetest.register_node('junglegrass:medium', {
description = "Jungle Grass (medium height)", description = "Jungle Grass (medium height)",
drawtype = 'plantlike', drawtype = 'plantlike',
tile_images = { 'junglegrass_medium.png' }, tile_images = { 'junglegrass_medium.png' },
@ -32,7 +33,7 @@ minetest.register_node(':junglegrass:medium', {
}, },
}) })
minetest.register_node(':junglegrass:short', { minetest.register_node('junglegrass:short', {
description = "Jungle Grass (short)", description = "Jungle Grass (short)",
drawtype = 'plantlike', drawtype = 'plantlike',
tile_images = { 'junglegrass_short.png' }, tile_images = { 'junglegrass_short.png' },
@ -50,7 +51,7 @@ minetest.register_node(':junglegrass:short', {
}, },
}) })
minetest.register_node(':junglegrass:shortest', { minetest.register_node('junglegrass:shortest', {
description = "Jungle Grass (very short)", description = "Jungle Grass (very short)",
drawtype = 'plantlike', drawtype = 'plantlike',
tile_images = { 'junglegrass_shortest.png' }, tile_images = { 'junglegrass_shortest.png' },
@ -68,12 +69,48 @@ minetest.register_node(':junglegrass:shortest', {
}, },
}) })
plantslib:spawn_on_surfaces(spawn_delay*2, "junglegrass:shortest", 4, spawn_chance, "default:dirt_with_grass", {"group:junglegrass", "default:junglegrass", "default:dry_shrub"}, junglegrass_seed_diff, 5) plantslib:spawn_on_surfaces({
plantslib:spawn_on_surfaces(spawn_delay*2, "junglegrass:shortest", 4, spawn_chance*2, "default:sand" , {"group:junglegrass", "default:junglegrass", "default:dry_shrub"}, junglegrass_seed_diff, 5) spawn_delay = SPAWN_DELAY,
plantslib:spawn_on_surfaces(spawn_delay*2, "junglegrass:shortest", 4, spawn_chance*3, "default:desert_sand" , {"group:junglegrass", "default:junglegrass", "default:dry_shrub"}, junglegrass_seed_diff, 5) spawn_plants = {"junglegrass:shortest"},
plantslib:spawn_on_surfaces(spawn_delay*2, "junglegrass:shortest", 4, spawn_chance*3, "default:desert_sand" , {"group:junglegrass", "default:junglegrass", "default:dry_shrub"}, junglegrass_seed_diff, 5) avoid_radius = 4,
spawn_chance = SPAWN_CHANCE,
spawn_surfaces = {"default:dirt_with_grass", "default:cactus", "default:papyrus"},
avoid_nodes = {"group:junglegrass", "default:junglegrass", "default:dry_shrub"},
seed_diff = junglegrass_seed_diff,
light_min = 5
})
plantslib:spawn_on_surfaces({
spawn_delay = SPAWN_DELAY,
spawn_plants = {"junglegrass:shortest"},
avoid_radius = 4,
spawn_chance = SPAWN_CHANCE*2,
spawn_surfaces = {"default:sand"},
avoid_nodes = {"group:junglegrass", "default:junglegrass", "default:dry_shrub"},
seed_diff = junglegrass_seed_diff,
light_min = 5
})
plantslib:spawn_on_surfaces({
spawn_delay = SPAWN_DELAY,
spawn_plants = {"junglegrass:shortest"},
avoid_radius = 4,
spawn_chance = SPAWN_CHANCE*5,
spawn_surfaces = {"default:desert_sand"},
avoid_nodes = {"group:junglegrass", "default:junglegrass", "default:dry_shrub"},
seed_diff = junglegrass_seed_diff,
light_min = 5
})
for i in ipairs(grasses_list) do for i in ipairs(grasses_list) do
plantslib:grow_plants(grow_delay, grow_chance/2, grasses_list[i][1], grasses_list[i][2], "default:desert_sand", {"default:dirt_with_grass", "default:sand", "default:desert_sand"}) plantslib:grow_plants({
grow_delay = GROW_DELAY,
grow_chance = GROW_CHANCE/2,
grow_plant = grasses_list[i][1],
grow_result = grasses_list[i][2],
dry_early_node = "default:desert_sand",
grow_nodes = {"default:dirt_with_grass", "default:sand", "default:desert_sand"}
})
end end
print("[Junglegrass] Loaded.")

View File

@ -1,5 +1,5 @@
-- Plantlife library mod by Vanessa Ezekowitz -- Plantlife library mod by Vanessa Ezekowitz
-- 2013-01-20 -- last revision, 2013-01-24
-- --
-- License: WTFPL -- License: WTFPL
-- --
@ -24,7 +24,7 @@ local temperature_octaves = 3
local temperature_persistence = 0.5 local temperature_persistence = 0.5
local temperature_scale = 150 local temperature_scale = 150
local plantlife_limit = 0.1
-- Local functions -- Local functions
@ -47,13 +47,18 @@ end
-- Spawn plants using the map generator -- Spawn plants using the map generator
function plantslib:register_generate_plant(biome, funct_or_model) function plantslib:register_generate_plant(biomedef, funct_or_model)
minetest.register_on_generated(plantslib:search_for_surfaces(minp, maxp, biome, 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 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) return function(minp, maxp, blockseed)
local biome = biomedef
if biome.seed_diff == nil then biome.seed_diff = 0 end if biome.seed_diff == nil then biome.seed_diff = 0 end
if biome.neighbors == nil then biome.neighbors = biome.surface end if biome.neighbors == nil then biome.neighbors = biome.surface end
if biome.min_elevation == nil then biome.min_elevation = -31000 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.temp_max == nil then biome.temp_max = -1 end
if biome.rarity == nil then biome.rarity = 50 end if biome.rarity == nil then biome.rarity = 50 end
if biome.max_count == nil then biome.max_count = 5 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...") plantslib:dbg("Started checking generated mapblock volume...")
local searchnodes = minetest.env:find_nodes_in_area(minp, maxp, biome.surface) 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 minetest.env:get_node(p_top).name == "air"
and pos.y >= biome.min_elevation and pos.y >= biome.min_elevation
and pos.y <= biome.max_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_min
and noise2 >= biome.temp_max 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.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 and math.random(1,100) > biome.rarity
then then
table.insert(in_biome_nodes, pos) table.insert(in_biome_nodes, pos)
num_in_biome_nodes = num_in_biome_nodes + 1 num_in_biome_nodes = num_in_biome_nodes + 1
end end
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 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.") 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,biome.max_count do for i = 1, math.min(biome.max_count, num_in_biome_nodes) do
local tries = 0 local tries = 0
local spawned = false 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 pos = in_biome_nodes[math.random(1, num_in_biome_nodes)]
local p_top = { x = pos.x, y = pos.y + 1, z = pos.z } 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 if minetest.env:find_node_near(p_top, biome.avoid_radius + math.random(-1.5,1.5), biome.avoid_nodes) == nil then
spawned = true spawned = true
if type(funct_or_model) == "table" then if type(funct_or_model) == "table" then
plantslib:dbg("Spawn tree at {"..dump(pos).."}") 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) minetest.env:spawn_tree(pos, funct_or_model)
else else
plantslib:dbg("Call function: "..funct_or_model.."("..dump(pos)..")")
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)..")"))() assert(loadstring(funct_or_model.."("..dump(pos)..")"))()
end end
else else
tries = tries + 1 tries = tries + 1
spawned = false plantslib:dbg("No room to spawn object at {"..dump(pos).."} -- trying again elsewhere")
plantslib:dbg("Couldn't spawn a tree at {"..dump(pos).."} -- trying again elsewhere")
end end
end end
if tries == 2 and spawned == false then if tries == 2 then
plantslib:dbg("Unable to spawn that tree. Giving up on it.") plantslib:dbg("Unable to spawn that object. Giving up on it.")
end end
end end
end end
plantslib:dbg("Finished checking generated area.")
end end
end end
-- The spawning ABM -- The spawning ABM
function plantslib:spawn_on_surfaces( function plantslib:spawn_on_surfaces(sd,sp,sr,sc,ss,sa)
sdelay,
splant, local biome = {}
sradius,
schance, if type(sd) ~= "table" then
ssurface, biome.spawn_delay = sd -- old api expects ABM interval param here.
savoid, biome.spawn_plants = {sp}
seed_diff, biome.avoid_radius = sr
lightmin, biome.spawn_chance = sc
lightmax, biome.spawn_surfaces = {ss}
nneighbors, biome.avoid_nodes = sa
ocount, else
facedir, biome = sd
depthmax, end
altmin,
altmax, if biome.seed_diff == nil then biome.seed_diff = 0 end
sbiome, if biome.light_min == nil then biome.light_min = 0 end
sbiomesize, if biome.light_max == nil then biome.light_max = 15 end
sbiomecount, if biome.depth_max == nil then biome.depth_max = 1 end
airsize, if biome.min_elevation == nil then biome.min_elevation = -31000 end
aircount, if biome.max_elevation == nil then biome.max_elevation = 31000 end
tempmin, if biome.temp_min == nil then biome.temp_min = 1 end
tempmax) if biome.temp_max == nil then biome.temp_max = -1 end
if seed_diff == nil then seed_diff = 0 end if biome.plantlife_limit == nil then biome.plantlife_limit = 0.1 end
if lightmin == nil then lightmin = 0 end if biome.near_nodes_vertical == nil then biome.near_nodes_vertical = 1 end
if lightmax == nil then lightmax = LIGHT_MAX end
if nneighbors == nil then nneighbors = ssurface end biome.spawn_plants_count = table.getn(biome.spawn_plants)
if ocount == nil then ocount = -1 end
if depthmax == nil then depthmax = 1 end plantslib:dbg("Registered spawning ABM:")
if altmin == nil then altmin = -31000 end plantslib:dbg(dump(biome))
if altmax == nil then altmax = 31000 end plantslib:dbg("Number of trigger nodes in this ABM: "..biome.spawn_plants_count )
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
minetest.register_abm({ minetest.register_abm({
nodenames = { ssurface }, nodenames = biome.spawn_surfaces,
interval = sdelay, interval = biome.spawn_delay,
chance = schance, chance = biome.spawn_chance,
neighbors = nneighbors, neighbors = biome.neighbors,
action = function(pos, node, active_object_count, active_object_count_wider) 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_top = { x = pos.x, y = pos.y + 1, z = pos.z }
local n_top = minetest.env:get_node(p_top) 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 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 noise1 = perlin1:get2d({x=p_top.x, y=p_top.z})
local noise2 = perlin2: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 if noise1 > biome.plantlife_limit
and noise2 >= tempmin and noise2 <= biome.temp_min
and noise2 <= tempmax and noise2 >= biome.temp_max
and plantslib:is_node_loaded(p_top) then and plantslib:is_node_loaded(p_top) then
local n_light = minetest.env:get_node_light(p_top, nil) 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 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 >= lightmin and n_light >= biome.light_min
and n_light <= lightmax and n_light <= biome.light_max
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 (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 )
or ocount == -1) 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 (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 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)
or sbiome == "") and pos.y >= biome.min_elevation
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 <= biome.max_elevation
and pos.y >= altmin then
and pos.y <= altmax local walldir = plantslib:find_adjacent_wall(p_top, biome.verticals_list)
then if biome.alt_wallnode and walldir then
local walldir = plantslib:plant_valid_wall(p_top) if n_top.name == "air" then
if splant == "poisonivy:seedling" and walldir ~= nil then plantslib:dbg("Spawn: "..biome.alt_wallnode.." on top of ("..dump(pos)..") against wall "..walldir)
plantslib:dbg("Spawn: poisonivy:climbing at "..dump(p_top).." on "..ssurface) minetest.env:add_node(p_top, { name = biome.alt_wallnode, param2 = walldir })
minetest.env:add_node(p_top, { name = "poisonivy:climbing", param2 = walldir }) end
else else
local deepnode = minetest.env:get_node({ x = pos.x, y = pos.y-depthmax-1, z = pos.z }).name local currentsurface = minetest.env:get_node(pos).name
if (ssurface ~= "default:water_source") if currentsurface ~= "default:water_source"
or (ssurface == "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 )
and deepnode ~= "default:water_source") then then
plantslib:dbg("Spawn: "..splant.." at "..dump(p_top).." on "..ssurface) local rnd = math.random(1, biome.spawn_plants_count)
minetest.env:add_node(p_top, { name = splant, param2 = facedir }) 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 end
end end
end end
@ -213,134 +255,130 @@ end
-- The growing ABM -- The growing ABM
function plantslib:grow_plants( function plantslib:grow_plants(opts)
gdelay,
gchance, local options = opts
gplant,
gresult, if options.height_limit == nil then options.height_limit = 5 end
dry_early_node, if options.ground_nodes == nil then options.ground_nodes = { "default:dirt_with_grass" } end
grow_nodes, if options.grow_nodes == nil then options.grow_nodes = { "default:dirt_with_grass" } end
facedir, if options.seed_diff == nil then options.seed_diff = 0 end
need_wall,
grow_vertically, plantslib:dbg("Registered growing ABM:")
height_limit, plantslib:dbg(dump(options))
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
minetest.register_abm({ minetest.register_abm({
nodenames = { gplant }, nodenames = { options.grow_plant },
interval = gdelay, interval = options.grow_delay,
chance = gchance, chance = options.grow_chance,
action = function(pos, node, active_object_count, active_object_count_wider) 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_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 p_bot = {x=pos.x, y=pos.y-1, z=pos.z}
local n_top = minetest.env:get_node(p_top) local n_top = minetest.env:get_node(p_top)
local n_bot = minetest.env:get_node(p_bot) 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}) local root_node = minetest.env:get_node({x=pos.x, y=pos.y-options.height_limit, z=pos.z})
if string.find(dump(grow_nodes), n_bot.name) ~= nil and n_top.name == "air" then local walldir = nil
if grow_function == nil then if options.need_wall and options.verticals_list ~= nil then
if grow_vertically then walldir = plantslib:find_adjacent_wall(p_top, options.verticals_list)
if plantslib:find_first_node(pos, height_limit, ground_nodes) ~= nil then end
if need_wall then if n_top.name == "air" and (not options.need_wall or (options.need_wall and walldir))
local walldir=plantslib:plant_valid_wall(p_top) then
if walldir ~= nil then -- corner case for changing short junglegrass
plantslib:dbg("Grow: "..gplant.." upwards to ("..dump(p_top)..") on wall "..walldir) -- to dry shrub in desert
minetest.env:add_node(p_top, { name = gplant, param2 = walldir }) if n_bot.name == options.dry_early_node and options.grow_plant == "junglegrass:short" then
end plantslib:dbg("Die: "..options.grow_plant.." becomes default:dry_shrub at ("..dump(pos)..")")
else minetest.env:add_node(pos, { name = "default:dry_shrub" })
plantslib: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 options.grow_vertically and walldir then
elseif n_bot.name == dry_early_node and gplant == "junglegrass:short" then if plantslib:search_downward(pos, options.height_limit, options.ground_nodes) then
plantslib:dbg("Die: "..gplant.." becomes default:dry_shrub at ("..dump(pos)..")") plantslib:dbg("Grow "..options.grow_plant.." vertically to "..dump(p_top))
minetest.env:add_node(pos, { name = "default:dry_shrub" }) minetest.env:add_node(p_top, { name = options.grow_plant, param2 = walldir})
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
end 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 else
if seed_diff == nil then seed_diff = 0 end plantslib:replace_object(pos, options.grow_result, options.grow_function, options.facedir, options.seed_diff)
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
end end
end end
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{} -- function to decide if a node has a wall that's in verticals_list{}
-- returns wall direction of valid node, or nil if invalid. -- returns wall direction of valid node, or nil if invalid.
local verticals_list = { function plantslib:find_adjacent_wall(pos, verticals)
"default:dirt", local verts = dump(verticals)
"default:dirt_with_grass", if string.find(verts, minetest.env:get_node({ x=pos.x-1, y=pos.y, z=pos.z }).name) then return 3 end
"default:stone", if string.find(verts, minetest.env:get_node({ x=pos.x+1, y=pos.y, z=pos.z }).name) then return 2 end
"default:cobble", if string.find(verts, minetest.env:get_node({ x=pos.x , y=pos.y, z=pos.z-1 }).name) then return 5 end
"default:mossycobble", if string.find(verts, minetest.env:get_node({ x=pos.x , y=pos.y, z=pos.z+1 }).name) then return 4 end
"default:brick", return nil
"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
end 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) function plantslib:search_downward(pos, heightlimit, ground)
for i = 1, height_limit do for i = 0, heightlimit do
n = minetest.env:get_node({x=pos.x, y=pos.y-i, z=pos.z}) if string.find(dump(ground), minetest.env:get_node({x=pos.x, y=pos.y-i, z = pos.z}).name) then
if string.find(dump(nodelist),n.name) ~= nil then return {x=pos.x, y=pos.y-i, z = pos.z}
return n.name
end end
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 return nil
end end
print("[Plantlife] Loaded!") print("[Plantlife Library] Loaded")

View File

@ -1,57 +0,0 @@
-- This file supplies poison ivy for the plantlife modpack
local spawn_delay = 2000 -- 2000
local spawn_chance = 100 -- 100
local grow_delay = 1000 -- 1000
local grow_chance = 10 -- 10
local poisonivy_seed_diff = plantslib.plantlife_seed_diff + 10
minetest.register_node(':poisonivy:seedling', {
description = "Poison ivy (seedling)",
drawtype = 'plantlike',
tile_images = { 'poisonivy_seedling.png' },
inventory_image = 'poisonivy_seedling.png',
wield_image = 'poisonivy_seedling.png',
sunlight_propagates = true,
paramtype = 'light',
walkable = false,
groups = { snappy = 3, poisonivy=1 },
sounds = default.node_sound_leaves_defaults(),
})
minetest.register_node(':poisonivy:sproutling', {
description = "Poison ivy (sproutling)",
drawtype = 'plantlike',
tile_images = { 'poisonivy_sproutling.png' },
inventory_image = 'poisonivy_sproutling.png',
wield_image = 'poisonivy_sproutling.png',
sunlight_propagates = true,
paramtype = 'light',
walkable = false,
groups = { snappy = 3, poisonivy=1 },
sounds = default.node_sound_leaves_defaults(),
})
minetest.register_node(':poisonivy:climbing', {
description = "Poison ivy (climbing plant)",
drawtype = 'signlike',
tile_images = { 'poisonivy_climbing.png' },
inventory_image = 'poisonivy_climbing.png',
wield_image = 'poisonivy_climbing.png',
sunlight_propagates = true,
paramtype = 'light',
paramtype2 = 'wallmounted',
walkable = false,
groups = { snappy = 3, poisonivy=1 },
sounds = default.node_sound_leaves_defaults(),
selection_box = {
type = "wallmounted",
--wall_side = = <default>
},
})
plantslib:spawn_on_surfaces(spawn_delay, "poisonivy:seedling", 10 , spawn_chance/10, "default:dirt_with_grass", {"group:poisonivy","group:flower"}, poisonivy_seed_diff, 7)
plantslib:grow_plants(spawn_delay, grow_chance, "poisonivy:seedling", "poisonivy:sproutling", nil, {"default:dirt_with_grass"})
plantslib:grow_plants(spawn_delay, grow_chance*2, "poisonivy:climbing", nil, nil, nil ,nil,true,true,nil,{"default:dirt_with_grass"})

96
poisonivy/init.lua Normal file
View File

@ -0,0 +1,96 @@
-- This file supplies poison ivy for the plantlife modpack
-- Last revision: 2013-01-24
local SPAWN_DELAY = 1000
local SPAWN_CHANCE = 200
local GROW_DELAY = 500
local GROW_CHANCE = 30
local poisonivy_seed_diff = 339
local walls_list = {
"default:dirt",
"default:dirt_with_grass",
"default:stone",
"default:cobble",
"default:mossycobble",
"default:brick",
"default:tree",
"default:jungletree",
"default:coal",
"default:iron"
},
minetest.register_node('poisonivy:seedling', {
description = "Poison ivy (seedling)",
drawtype = 'plantlike',
tile_images = { 'poisonivy_seedling.png' },
inventory_image = 'poisonivy_seedling.png',
wield_image = 'poisonivy_seedling.png',
sunlight_propagates = true,
paramtype = 'light',
walkable = false,
groups = { snappy = 3, poisonivy=1 },
sounds = default.node_sound_leaves_defaults(),
})
minetest.register_node('poisonivy:sproutling', {
description = "Poison ivy (sproutling)",
drawtype = 'plantlike',
tile_images = { 'poisonivy_sproutling.png' },
inventory_image = 'poisonivy_sproutling.png',
wield_image = 'poisonivy_sproutling.png',
sunlight_propagates = true,
paramtype = 'light',
walkable = false,
groups = { snappy = 3, poisonivy=1 },
sounds = default.node_sound_leaves_defaults(),
})
minetest.register_node('poisonivy:climbing', {
description = "Poison ivy (climbing plant)",
drawtype = 'signlike',
tile_images = { 'poisonivy_climbing.png' },
inventory_image = 'poisonivy_climbing.png',
wield_image = 'poisonivy_climbing.png',
sunlight_propagates = true,
paramtype = 'light',
paramtype2 = 'wallmounted',
walkable = false,
groups = { snappy = 3, poisonivy=1 },
sounds = default.node_sound_leaves_defaults(),
selection_box = {
type = "wallmounted",
--wall_side = = <default>
},
})
plantslib:spawn_on_surfaces({
spawn_delay = SPAWN_DELAY,
spawn_plants = {"poisonivy:seedling"},
avoid_radius = 10,
spawn_chance = SPAWN_CHANCE/10,
spawn_surfaces = {"default:dirt_with_grass"},
avoid_nodes = {"group:poisonivy","group:flower"},
seed_diff = poisonivy_seed_diff,
light_min = 7,
alt_wallnode = "poisonivy:climbing",
verticals_list = walls_list
})
plantslib:grow_plants({
grow_delay = SPAWN_DELAY,
grow_chance = GROW_CHANCE,
grow_plant = "poisonivy:seedling",
grow_result = "poisonivy:sproutling",
grow_nodes = {"default:dirt_with_grass"}
})
plantslib:grow_plants({
grow_delay = GROW_DELAY,
grow_chance = GROW_CHANCE*2,
grow_plant = "poisonivy:climbing",
need_wall = true,
grow_vertically = true,
verticals_list = walls_list,
ground_nodes = {"default:dirt_with_grass"}
})
print("[Poison Ivy] Loaded.")

View File

Before

Width:  |  Height:  |  Size: 456 B

After

Width:  |  Height:  |  Size: 456 B

View File

Before

Width:  |  Height:  |  Size: 270 B

After

Width:  |  Height:  |  Size: 270 B

View File

Before

Width:  |  Height:  |  Size: 426 B

After

Width:  |  Height:  |  Size: 426 B