Trim down plants_lib to one function
parent
9d309c97d1
commit
ed78c12ccd
|
@ -361,9 +361,9 @@ minetest.register_abm({
|
|||
end,
|
||||
})
|
||||
|
||||
|
||||
--spawning
|
||||
-- Spawn vines
|
||||
plantslib:spawn_on_surfaces({
|
||||
label = "Spawn cave vines",
|
||||
avoid_nodes = {"hades_vines:cave"},
|
||||
avoid_radius = 5,
|
||||
spawn_delay = spawn_interval,
|
||||
|
@ -371,10 +371,10 @@ plantslib:spawn_on_surfaces({
|
|||
spawn_chance = 50,
|
||||
spawn_surfaces = {"hades_core:dirt_with_grass","hades_core:dirt_with_grass_l1","hades_core:dirt_with_grass_l2","hades_core:dirt_with_grass_l3","hades_core:dirt"},
|
||||
spawn_on_bottom = true,
|
||||
plantlife_limit = -0.9,
|
||||
})
|
||||
|
||||
plantslib:spawn_on_surfaces({
|
||||
label = "Spawn tropical vines",
|
||||
avoid_nodes = {"hades_vines:cave", "hades_vines:jungle"},
|
||||
avoid_radius = 3,
|
||||
spawn_delay = spawn_interval,
|
||||
|
@ -386,10 +386,10 @@ plantslib:spawn_on_surfaces({
|
|||
near_nodes_size = 10,
|
||||
near_nodes_vertical = 5,
|
||||
near_nodes_count = 3,
|
||||
plantlife_limit = -0.9,
|
||||
})
|
||||
|
||||
plantslib:spawn_on_surfaces({
|
||||
label = "Spawn willow vines",
|
||||
spawn_plants = {"hades_vines:willow"},
|
||||
avoid_radius = 3,
|
||||
spawn_delay = spawn_interval,
|
||||
|
@ -400,7 +400,6 @@ plantslib:spawn_on_surfaces({
|
|||
near_nodes_size = 7,
|
||||
near_nodes_vertical = 4,
|
||||
near_nodes_count = 3,
|
||||
plantlife_limit = -0.9,
|
||||
})
|
||||
|
||||
-- Shears: jojoa1997's shears
|
||||
|
|
|
@ -9,14 +9,8 @@ hades_waterplants = {}
|
|||
|
||||
local SPAWN_DELAY = 1000
|
||||
local SPAWN_CHANCE = 200
|
||||
local waterplants_seed_diff = 329
|
||||
local lilies_max_count = 12
|
||||
local lilies_rarity = 33
|
||||
local seaweed_max_count = 20
|
||||
local seaweed_rarity = 33
|
||||
-- globals
|
||||
local lilypads_max_count = {}
|
||||
local lilypads_rarity = {}
|
||||
local WATERPLANTS_SEED_DIFF = 329
|
||||
local WATERPLANTS_SEED_DIFF2 = 459
|
||||
-- register the various rotations of waterlilies
|
||||
|
||||
|
||||
|
@ -31,6 +25,17 @@ local lilies_list = {
|
|||
{ "s4" , "small_4" , 8, false },
|
||||
}
|
||||
|
||||
local node_is_owned = function(pos, placer)
|
||||
local name = placer:get_player_name()
|
||||
local is_protected = minetest.is_protected(pos, name) and not minetest.check_player_privs(name, "protection_bypass")
|
||||
if is_protected then
|
||||
minetest.record_protection_violation(pos, name)
|
||||
return true
|
||||
else
|
||||
return false
|
||||
end
|
||||
end
|
||||
|
||||
local generate_on_place = function(basename, plant_table)
|
||||
return function(itemstack, placer, pt)
|
||||
local place_pos = nil
|
||||
|
@ -69,7 +74,7 @@ local generate_on_place = function(basename, plant_table)
|
|||
return itemstack
|
||||
end
|
||||
|
||||
if not plantslib:node_is_owned(place_pos, placer) then
|
||||
if not node_is_owned(place_pos, placer) then
|
||||
|
||||
local nodename = basename
|
||||
|
||||
|
@ -238,69 +243,8 @@ for i in ipairs(seaweed_list) do
|
|||
end
|
||||
|
||||
|
||||
-- ongen registrations
|
||||
|
||||
|
||||
hades_waterplants.grow_waterlily = function(pos)
|
||||
local right_here = {x=pos.x, y=pos.y+1, z=pos.z}
|
||||
for i in ipairs(lilies_list) do
|
||||
local chance = math.random(1,8)
|
||||
local ext = ""
|
||||
local num = lilies_list[i][3]
|
||||
|
||||
|
||||
if lilies_list[i][1] ~= nil then
|
||||
ext = "_"..lilies_list[i][1]
|
||||
end
|
||||
|
||||
|
||||
if chance == num then
|
||||
minetest.add_node(right_here, {name="hades_waterplants:waterlily"..ext, param2=math.random(0,3)})
|
||||
end
|
||||
end
|
||||
end
|
||||
|
||||
|
||||
plantslib:register_generate_plant({
|
||||
surface = {"hades_core:water_source"},
|
||||
max_count = lilypads_max_count,
|
||||
rarity = lilypads_rarity,
|
||||
min_elevation = -30,
|
||||
max_elevation = 100,
|
||||
near_nodes = {"hades_core:dirt_with_grass"},
|
||||
near_nodes_size = 4,
|
||||
near_nodes_vertical = 1,
|
||||
near_nodes_count = 1,
|
||||
plantlife_limit = -0.9,
|
||||
temp_max = -0.22,
|
||||
temp_min = 0.22,
|
||||
},
|
||||
"hades_waterplants.grow_waterlily"
|
||||
)
|
||||
|
||||
|
||||
hades_waterplants.grow_seaweed = function(pos)
|
||||
local right_here = {x=pos.x, y=pos.y+1, z=pos.z}
|
||||
minetest.add_node(right_here, {name="hades_waterplants:seaweed_"..math.random(1,4), param2=math.random(1,3)})
|
||||
end
|
||||
|
||||
|
||||
plantslib:register_generate_plant({
|
||||
surface = {"hades_core:water_source"},
|
||||
max_count = seaweed_max_count,
|
||||
rarity = seaweed_rarity,
|
||||
-- min_elevation = 1,
|
||||
max_elevation = 100,
|
||||
near_nodes = {"hades_core:mossystone", "hades_core:dirt_with_grass"},
|
||||
near_nodes_size = 3,
|
||||
near_nodes_vertical = 2,
|
||||
near_nodes_count = 1,
|
||||
plantlife_limit = -1.0,
|
||||
},
|
||||
"hades_waterplants.grow_seaweed"
|
||||
)
|
||||
|
||||
plantslib:spawn_on_surfaces({
|
||||
label = "Spawn waterlilies",
|
||||
spawn_delay = SPAWN_DELAY/2,
|
||||
spawn_plants = {
|
||||
"hades_waterplants:waterlily",
|
||||
|
@ -316,34 +260,34 @@ plantslib:spawn_on_surfaces({
|
|||
spawn_chance = SPAWN_CHANCE*4,
|
||||
spawn_surfaces = {"hades_core:water_source"},
|
||||
avoid_nodes = {"group:flower", "group:flora" },
|
||||
seed_diff = waterplants_seed_diff,
|
||||
seed_diff = WATERPLANTS_SEED_DIFF,
|
||||
light_min = 9,
|
||||
depth_max = 2,
|
||||
random_facedir = {0,3}
|
||||
})
|
||||
|
||||
|
||||
plantslib:spawn_on_surfaces({
|
||||
label = "Spawn seaweed on water",
|
||||
spawn_delay = SPAWN_DELAY*2,
|
||||
spawn_plants = {"hades_waterplants:seaweed"},
|
||||
spawn_chance = SPAWN_CHANCE*2,
|
||||
spawn_surfaces = {"hades_core:water_source"},
|
||||
avoid_nodes = {"group:flower", "group:flora"},
|
||||
seed_diff = waterplants_seed_diff,
|
||||
seed_diff = WATERPLANTS_SEED_DIFF2,
|
||||
light_min = 4,
|
||||
light_max = 10,
|
||||
neighbors = {"hades_core:dirt_with_grass"},
|
||||
facedir = 1
|
||||
})
|
||||
|
||||
|
||||
plantslib:spawn_on_surfaces({
|
||||
label = "Spawn seaweed on dirt with grass",
|
||||
spawn_delay = SPAWN_DELAY*2,
|
||||
spawn_plants = {"hades_waterplants:seaweed"},
|
||||
spawn_chance = SPAWN_CHANCE*2,
|
||||
spawn_surfaces = {"hades_core:dirt_with_grass"},
|
||||
avoid_nodes = {"group:flower", "group:flora" },
|
||||
seed_diff = waterplants_seed_diff,
|
||||
seed_diff = WATERPLANTS_SEED_DIFF2,
|
||||
light_min = 4,
|
||||
light_max = 10,
|
||||
neighbors = {"hades_core:water_source"},
|
||||
|
|
|
@ -1,62 +1,19 @@
|
|||
This document describes the Plantlife API.
|
||||
|
||||
Last revision: 2013-01-30
|
||||
|
||||
This document describes the Hades Plantlife API.
|
||||
|
||||
=========
|
||||
Functions
|
||||
=========
|
||||
|
||||
There are three main functions defined by the main "plants_lib" mod:
|
||||
There is one main function defined:
|
||||
|
||||
spawn_on_surfaces()
|
||||
register_generate_plant()
|
||||
grow_plants()
|
||||
|
||||
There are also several internal, helper functions that can be called if so
|
||||
desired, but they are not really intended for use by other mods and may change
|
||||
at any time. They are briefly described below these main functions, but see
|
||||
init.lua for details.
|
||||
|
||||
All functions in plants lib are declared locally to avoid namespace collisions
|
||||
with other mods. They are accessible via the "plantslib" method, e.g.
|
||||
plantslib:spawn_on_surfaces() and so forth.
|
||||
|
||||
=====
|
||||
spawn_on_surfaces(biome)
|
||||
spawn_on_surfaces(sdelay, splant, sradius, schance, ssurface, savoid)
|
||||
|
||||
This first function is an ABM-based spawner function originally created as
|
||||
part of Ironzorg's flowers mod. It has since been largely extended and
|
||||
expanded. There are two ways to call this function: You can either pass it
|
||||
several individual string and number parameters to use the legacy interface,
|
||||
or you can pass a single biome definition as a table, with all of your options
|
||||
spelled out nicely. This is the preferred method.
|
||||
This first function is an ABM-based spawner function.
|
||||
|
||||
When used with the legacy interface, you must specify the parameters exactly
|
||||
in order, with the first five being mandatory (even if some are set to nil),
|
||||
and the last one being optional:
|
||||
|
||||
sdelay: The value passed to the ABM's interval parameter, in seconds.
|
||||
splant: The node name of the item to spawn (e.g.
|
||||
"flowers:flower_rose"). 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. If set to nil, this check is skipped.
|
||||
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)
|
||||
ssurface: String with the name of the node on which to spawn the plant
|
||||
in question, such as "hades_core:ash" or
|
||||
"hades_core:dirt_with_grass". It is not recommended to put air,
|
||||
stone, or plain dirt here if you can use some other node, as
|
||||
doing so 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", "hades_trees:tree"}.
|
||||
|
||||
When passed a table as the argument, and thus using the modern calling method,
|
||||
you must pass a number of arguments in the form of an ordinary keyed-value
|
||||
You must pass a number of arguments in the form of an ordinary keyed-value
|
||||
table. Below is a list of everything supported by this function:
|
||||
|
||||
biome = {
|
||||
|
@ -67,6 +24,7 @@ biome = {
|
|||
-- should be spawned. As with the single-
|
||||
-- node "ssurface" option in the legacy API,
|
||||
-- you should not put stone, air, etc. here.
|
||||
label = string -- label for the ABM (strongly recommended)
|
||||
|
||||
---- From here down are a number of optional parameters. You will
|
||||
---- most likely want to use at least some of these to limit how and
|
||||
|
@ -235,368 +193,3 @@ skipped.
|
|||
|
||||
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.
|
||||
|
||||
|
||||
=====
|
||||
plantslib:register_generate_plant(biome, node_or_function_or_treedef)
|
||||
|
||||
To register an object to be spawned at mapgen time rather than via an ABM,
|
||||
call this function with two parameters: a table with your object's biome
|
||||
information, and a string or table describing what to do if the engine finds a
|
||||
suitable node (see below).
|
||||
|
||||
The biome table contains quite a number of options, though there are fewer
|
||||
here than are available in the ABM-based spawner, as some stuff doesn't make
|
||||
sense at map-generation time.
|
||||
|
||||
biome = {
|
||||
surface = something, -- What node(s). May be a string such as
|
||||
-- "hades_core:dirt_with_grass" or a table with
|
||||
-- multiple such entries.
|
||||
|
||||
---- Everything else is optional, but you'll definitely want to use
|
||||
---- some of these other fields to limit where and under what
|
||||
---- conditions the objects are spawned.
|
||||
|
||||
below_nodes = {table}, -- List of nodes that must be below the target
|
||||
-- node. Useful in snow biomes to keep
|
||||
-- objects from spawning in snow that's on the
|
||||
-- wrong surface for that object.
|
||||
avoid_nodes = {table}, -- List of nodes or groups to avoid when
|
||||
-- spawning.
|
||||
avoid_radius = num, -- how much distance to leave between the
|
||||
-- object to be added and the objects to be
|
||||
-- avoided. If this or the avoid_nodes value
|
||||
-- is nil or omitted, this check is skipped.
|
||||
-- Avoid using excessively large radii or you
|
||||
-- will slow down the map generator.
|
||||
rarity = num, -- how rare should this object be in its
|
||||
-- biome? Larger values make objects more
|
||||
-- rare, via: math.random(1,100) > this
|
||||
max_count = num, -- The absolute maximum number of your object
|
||||
-- that should be allowed to spawn in a 5x5x5
|
||||
-- mapblock area (80x80x80 nodes). Defaults
|
||||
-- to 5, but be sure you set this to some
|
||||
-- reasonable value depending on your object
|
||||
-- and its size if 5 is insufficient.
|
||||
seed_diff = num, -- perlin seed-diff value. Defaults to 0,
|
||||
-- which causes the function to inherit the
|
||||
-- global value of 329.
|
||||
neighbors = {table}, -- What ground nodes must be right next to and
|
||||
-- at the same elevation as the node to be
|
||||
-- spawned on.
|
||||
ncount = num, -- at least this many of the above nodes must
|
||||
-- be next to the node to spawn on. Any value
|
||||
-- greater than 8 will probably cause the code
|
||||
-- to never spawn anything. Defaults to 0.
|
||||
depth = num, -- how deep/thick of a layer the spawned-on
|
||||
-- node must be. Typically used for water.
|
||||
min_elevation = num, -- minimum elevation in meters/nodes.
|
||||
-- Defaults to -31000 (unlimited).
|
||||
max_elevation = num, -- maximum elevation. Defaults to +31000
|
||||
-- (unlimited).
|
||||
near_nodes = {table}, -- what nodes must be in the general vicinity
|
||||
-- of the object being spawned.
|
||||
near_nodes_size = num, -- how wide of a search area to look for
|
||||
-- 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
|
||||
-- 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
|
||||
-- to spawn (that is, the highest Perlin
|
||||
-- temperature map value).
|
||||
temp_max = num, -- warmest allowable temperature to spawn a
|
||||
-- plant (lowest Perlin temperature value).
|
||||
verticals_list = {table}, -- Same as with the spawn_on_surfaces
|
||||
-- function.
|
||||
check_air = bool, -- Flag to tell the mapgen code to check for
|
||||
-- air above the spawn target. Defaults to
|
||||
-- true if not explicitly set to false.
|
||||
delete_above = bool, -- Flag to tell the mapgen code to delete the
|
||||
-- two nodes directly above the spawn target
|
||||
-- just before adding the plant or tree.
|
||||
-- Useful when generating in snow biomes.
|
||||
-- Defaults to false.
|
||||
delete_above_surround = bool, -- Flag to tell the mapgen code to also
|
||||
-- delete the four nodes surrounding the above
|
||||
-- space, and the four nodes above those,
|
||||
-- resulting in a two-node-deep cross-shaped
|
||||
-- empty region above the spawn target.
|
||||
-- Useful when adding trees to snow biomes.
|
||||
-- Defaults to false.
|
||||
spawn_replace_node = bool -- same as with the ABM spawner.
|
||||
}
|
||||
|
||||
Regarding node_or_function_or_treedef, this must either be table with an
|
||||
L-Systems tree definition, or a string with a node or function name.
|
||||
|
||||
If you specified a string, the code will attempt to determine, as needed,
|
||||
whether that string specifies a node name. If it does, that node will be
|
||||
placed on top of the target position directly.
|
||||
|
||||
If it wasn't a node, the code will assume you meant to specify a function
|
||||
name, in which case that function will be passed a single position parameter
|
||||
(in the usual table format), indicating where the named function should place
|
||||
the object. It is called in the form of "somefunction(pos)", and behaves much
|
||||
like a typical callback.
|
||||
|
||||
If you specified a table, the code assumes this table contains an L-Systems
|
||||
tree definition, then that definition will be passed directly to the
|
||||
spawn_tree() function along with the position to spawn the tree on.
|
||||
|
||||
|
||||
=====
|
||||
plantslib:grow_plants(options)
|
||||
|
||||
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 accepts
|
||||
a biome definition table as the only parameter. These are defined like so:
|
||||
|
||||
options = {
|
||||
grow_plant = "string", -- Name of the node to be grown into something
|
||||
-- else. This value is passed 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. Can also be a table, but note that
|
||||
-- all nodes referenced therein will be grown
|
||||
-- into the same object.
|
||||
grow_delay = num, -- Passed as the ABM "interval" parameter, as
|
||||
-- with spawning.
|
||||
grow_chance = num, -- Passed as the ABM "chance" parameter.
|
||||
grow_result = "string", -- Name of the node into which the grow_plant
|
||||
-- node(s) should transform when the ABM
|
||||
-- executes.
|
||||
|
||||
---- Everything from here down is optional.
|
||||
|
||||
dry_early_node = "string", -- This value is ignored except for jungle
|
||||
-- grass (a corner case needed by that mod),
|
||||
-- where it indicates which node the grass
|
||||
-- must be on in order for it to turn from
|
||||
-- the short size to this node
|
||||
-- instead of the medium size.
|
||||
grow_nodes = {table}, -- One of these nodes 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. This is so that the
|
||||
-- plant can be manually placed on something
|
||||
-- like a flower pot or something without it
|
||||
-- growing and eventually dieing. Defaults to
|
||||
-- "hades_core:dirt_with_grass".
|
||||
facedir = num, -- Same as with spawning a plant.
|
||||
need_wall = bool, -- Set this to true if you the plant needs to
|
||||
-- grow against a wall. Defaults to false.
|
||||
verticals_list = {table}, -- List of nodes that should be considered
|
||||
-- to be wall surfaces when growing the plant
|
||||
-- vertically. If not provided, the walls
|
||||
-- check is skipped.
|
||||
grow_vertically = bool, -- Set this to true if the plant needs to grow
|
||||
-- vertically, as in climbing poison ivy.
|
||||
-- Defaults to false.
|
||||
height_limit = num, -- Set this to limit how tall the desired node
|
||||
-- can grow. The mod will search straight
|
||||
-- down from the position being spawned at to
|
||||
-- find a ground node, set via the parameter
|
||||
-- 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
|
||||
-- "hades_core: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, and the node to
|
||||
be placed is assumed to be specified in the grow_result variable.
|
||||
|
||||
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 in the following general form:
|
||||
|
||||
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.
|
||||
|
||||
|
||||
=====
|
||||
find_adjacent_wall(pos, verticals)
|
||||
|
||||
Of the few helper functions, this one expects a position parameter and a table
|
||||
with the list of nodes that should be considered as walls. The code will
|
||||
search around the given position for a neighboring wall, returning the first
|
||||
one it finds as a facedir value, or nil if there are no adjacent walls.
|
||||
|
||||
|
||||
=====
|
||||
is_node_loaded(pos)
|
||||
|
||||
This acts as a wrapper for the minetest.get_node_or_nil(node_pos)
|
||||
function and accepts a single position parameter. Returns true if the node in
|
||||
question is already loaded, or false if not.
|
||||
|
||||
|
||||
=====
|
||||
dbg(string)
|
||||
|
||||
This is a simple debug output function which takes one string parameter. It
|
||||
just checks if DEBUG is true and outputs the phrase "[Plantlife] " followed by
|
||||
the supplied string, via the print() function, if so.
|
||||
|
||||
=====
|
||||
plantslib:generate_tree(pos, treemodel)
|
||||
plantslib:grow_tree(pos, treemodel)
|
||||
|
||||
In the case of the growing code and the mapgen-based tree generator code,
|
||||
generating a tree is done via the above two calls, which in turn immediately
|
||||
call the usual spawn_tree() functions. This rerouting exists as a way for
|
||||
other mods to hook into plants_lib's tree-growing functions in general,
|
||||
perhaps to execute something extra whenever a tree is spawned.
|
||||
|
||||
plantslib:generate_tree(pos, treemodel) is called any time a
|
||||
tree is spawned at map generation time. 'pos' is the position of the block on
|
||||
which the tree is to be placed. 'treemodel' is the standard L-Systems tree
|
||||
definition table expected by the spawn_tree() function. Refer to the 'trunk'
|
||||
field in that table to derive the name of the tree being spawned.
|
||||
|
||||
plantslib:grow_tree(pos, treemodel) does the same sort of thing whenever a
|
||||
tree is spawned within the abm-based growing code, for example when growing a
|
||||
sapling into a tree.
|
||||
|
||||
|
||||
=====
|
||||
There are other, internal helper functions that are not meant for use by other
|
||||
mods. Don't rely on them, as they are subject to change without notice.
|
||||
|
||||
|
||||
===============
|
||||
Global Settings
|
||||
===============
|
||||
|
||||
Set this to true if you want the mod to spam your console with debug info :-)
|
||||
|
||||
plantlife_debug = false
|
||||
|
||||
|
||||
======================
|
||||
Fertile Ground Mapping
|
||||
======================
|
||||
|
||||
The mod uses Perlin noise to create "biomes" of the various plants, via the
|
||||
minetest.get_perlin() function. At present, there are three layers of
|
||||
Perlin noise used.
|
||||
|
||||
The first one is for a "fertile ground" layer, which I tend to refer to as the
|
||||
generic "stuff can potentially grow here" layer. Its values are hard-coded:
|
||||
|
||||
plantslib.plantlife_seed_diff = 329
|
||||
perlin_octaves = 3
|
||||
perlin_persistence = 0.6
|
||||
perlin_scale = 100
|
||||
|
||||
For more information on how Perlin noise is generated, you will need to search
|
||||
the web, as these default values were from that which is used by minetest_game
|
||||
to spawn jungle grass at mapgen time, and I'm still learning how Perlin noise
|
||||
works. ;-)
|
||||
|
||||
|
||||
===================
|
||||
Temperature Mapping
|
||||
===================
|
||||
|
||||
The second Perlin layer is a temperature map, with values taken from
|
||||
SPlizard's Snow Biomes mod so that the two will be compatible, since that mod
|
||||
appears to be the standard now. Those values are:
|
||||
|
||||
temperature_seeddiff = 112
|
||||
temperature_octaves = 3
|
||||
temperature_persistence = 0.5
|
||||
temperature_scale = 150
|
||||
|
||||
The way Perlin values are used by this mod, in keeping with the snow mod's
|
||||
apparent methods, larger values returned by the Perlin function represent
|
||||
*colder* temperatures. In this mod, the following table gives a rough
|
||||
approximation of how temperature maps to these values, normalized to
|
||||
0.53 = 0 °C and +1.0 = -25 °C.
|
||||
|
||||
Perlin Approx. Temperature
|
||||
-1.0 81 °C ( 178 °F)
|
||||
-0.75 68 °C ( 155 °F)
|
||||
-0.56 58 °C ( 136 °F)
|
||||
-0.5 55 °C ( 131 °F)
|
||||
-0.25 41 °C ( 107 °F)
|
||||
-0.18 38 °C ( 100 °F)
|
||||
0 28 °C ( 83 °F)
|
||||
0.13 21 °C ( 70 °F)
|
||||
0.25 15 °C ( 59 °F)
|
||||
0.5 2 °C ( 35 °F)
|
||||
0.53 0 °C ( 32 °F)
|
||||
0.75 -12 °C ( 11 °F)
|
||||
0.86 -18 °C ( 0 °F)
|
||||
1.0 -25 °C (- 13 °F)
|
||||
|
||||
Included in this table are even 0.25 steps in Perlin values along with some
|
||||
common temperatures on both the Centigrade and Fahrenheit scales. Note that
|
||||
unless you're trying to model the Moon or perhaps Mercury in your mods/maps,
|
||||
you probably won't need to bother with Perlin values of less than -0.56 or so.
|
||||
|
||||
|
||||
================
|
||||
Humidity Mapping
|
||||
================
|
||||
|
||||
Last but not least is a moisture/humidity map. Like the temperature map
|
||||
above, Perlin values can be tested to determine the approximate humidity of
|
||||
the *air* in the area. This humidity map is basically the perlin layer used
|
||||
for deserts.
|
||||
|
||||
A value of -1.0 is very moist (basically a thick fog, if it could be seen), a
|
||||
value of +0.4 represents the edge of a desert as usually seen in the game, and
|
||||
a value of +1.0 is as dry as a bone.
|
||||
|
||||
This does not check for nearby water, just general air humidity, and that
|
||||
being the case, nearby ground does not affect the reported humidity of a
|
||||
region (because this isn't yet possible to calculate yet). Use the near_nodes
|
||||
and avoid_nodes parameters and their related options to check for water and
|
||||
such.
|
||||
|
||||
The Perlin values use for this layer are:
|
||||
|
||||
humidity_seeddiff = 9130
|
||||
humidity_octaves = 3
|
||||
humidity_persistence = 0.5
|
||||
humidity_scale = 250
|
||||
|
||||
And this particular one is mapped slightly differently from the others:
|
||||
|
||||
noise3 = perlin3:get2d({x=p_top.x+150, y=p_top.z+50})
|
||||
|
||||
(Note the +150 and +50 offsets)
|
||||
|
||||
|
|
|
@ -1,317 +0,0 @@
|
|||
|
||||
For the code, Ironzorg's textures, and everything else: MIT License
|
||||
For all of my own textures: CC BY-SA 3.0
|
||||
|
||||
-----------
|
||||
CC BY-SA 3.0 license text
|
||||
-----------
|
||||
|
||||
THE WORK (AS DEFINED BELOW) IS PROVIDED UNDER THE TERMS OF THIS
|
||||
CREATIVE COMMONS PUBLIC LICENSE ("CCPL" OR "LICENSE"). THE WORK IS
|
||||
PROTECTED BY COPYRIGHT AND/OR OTHER APPLICABLE LAW. ANY USE OF THE
|
||||
WORK OTHER THAN AS AUTHORIZED UNDER THIS LICENSE OR COPYRIGHT LAW
|
||||
IS PROHIBITED.
|
||||
|
||||
BY EXERCISING ANY RIGHTS TO THE WORK PROVIDED HERE, YOU ACCEPT AND
|
||||
AGREE TO BE BOUND BY THE TERMS OF THIS LICENSE. TO THE EXTENT THIS
|
||||
LICENSE MAY BE CONSIDERED TO BE A CONTRACT, THE LICENSOR GRANTS
|
||||
YOU THE RIGHTS CONTAINED HERE IN CONSIDERATION OF YOUR ACCEPTANCE
|
||||
OF SUCH TERMS AND CONDITIONS.
|
||||
|
||||
1. Definitions
|
||||
|
||||
"Collective Work" means a work, such as a periodical issue,
|
||||
anthology or encyclopedia, in which the Work in its entirety in
|
||||
unmodified form, along with one or more other contributions,
|
||||
constituting separate and independent works in themselves, are
|
||||
assembled into a collective whole. A work that constitutes a
|
||||
Collective Work will not be considered a Derivative Work (as
|
||||
defined below) for the purposes of this License.
|
||||
"Creative Commons Compatible License" means a license that is
|
||||
listed at http://creativecommons.org/compatiblelicenses that has
|
||||
been approved by Creative Commons as being essentially equivalent
|
||||
to this License, including, at a minimum, because that license:
|
||||
(i) contains terms that have the same purpose, meaning and effect
|
||||
as the License Elements of this License; and, (ii) explicitly
|
||||
permits the relicensing of derivatives of works made available
|
||||
under that license under this License or either a Creative Commons
|
||||
unported license or a Creative Commons jurisdiction license with
|
||||
the same License Elements as this License.
|
||||
"Derivative Work" means a work based upon the Work or upon the
|
||||
Work and other pre-existing works, such as a translation, musical
|
||||
arrangement, dramatization, fictionalization, motion picture
|
||||
version, sound recording, art reproduction, abridgment,
|
||||
condensation, or any other form in which the Work may be recast,
|
||||
transformed, or adapted, except that a work that constitutes a
|
||||
Collective Work will not be considered a Derivative Work for the
|
||||
purpose of this License. For the avoidance of doubt, where the
|
||||
Work is a musical composition or sound recording, the
|
||||
synchronization of the Work in timed-relation with a moving image
|
||||
("synching") will be considered a Derivative Work for the purpose
|
||||
of this License.
|
||||
"License Elements" means the following high-level license
|
||||
attributes as selected by Licensor and indicated in the title of
|
||||
this License: Attribution, ShareAlike.
|
||||
"Licensor" means the individual, individuals, entity or
|
||||
entities that offers the Work under the terms of this License.
|
||||
"Original Author" means the individual, individuals, entity or
|
||||
entities who created the Work.
|
||||
"Work" means the copyrightable work of authorship offered
|
||||
under the terms of this License.
|
||||
"You" means an individual or entity exercising rights under
|
||||
this License who has not previously violated the terms of this
|
||||
License with respect to the Work, or who has received express
|
||||
permission from the Licensor to exercise rights under this License
|
||||
despite a previous violation.
|
||||
|
||||
2. Fair Use Rights. Nothing in this license is intended to reduce,
|
||||
limit, or restrict any rights arising from fair use, first sale or
|
||||
other limitations on the exclusive rights of the copyright owner
|
||||
under copyright law or other applicable laws.
|
||||
|
||||
3. License Grant. Subject to the terms and conditions of this
|
||||
License, Licensor hereby grants You a worldwide, royalty-free,
|
||||
non-exclusive, perpetual (for the duration of the applicable
|
||||
copyright) license to exercise the rights in the Work as stated
|
||||
below:
|
||||
|
||||
to reproduce the Work, to incorporate the Work into one or
|
||||
more Collective Works, and to reproduce the Work as incorporated
|
||||
in the Collective Works;
|
||||
to create and reproduce Derivative Works provided that any
|
||||
such Derivative Work, including any translation in any medium,
|
||||
takes reasonable steps to clearly label, demarcate or otherwise
|
||||
identify that changes were made to the original Work. For example,
|
||||
a translation could be marked "The original work was translated
|
||||
from English to Spanish," or a modification could indicate "The
|
||||
original work has been modified.";
|
||||
to distribute copies or phonorecords of, display publicly,
|
||||
perform publicly, and perform publicly by means of a digital audio
|
||||
transmission the Work including as incorporated in Collective
|
||||
Works;
|
||||
to distribute copies or phonorecords of, display publicly,
|
||||
perform publicly, and perform publicly by means of a digital audio
|
||||
transmission Derivative Works.
|
||||
|
||||
For the avoidance of doubt, where the Work is a musical
|
||||
composition:
|
||||
Performance Royalties Under Blanket Licenses. Licensor
|
||||
waives the exclusive right to collect, whether individually or, in
|
||||
the event that Licensor is a member of a performance rights
|
||||
society (e.g. ASCAP, BMI, SESAC), via that society, royalties for
|
||||
the public performance or public digital performance (e.g.
|
||||
webcast) of the Work.
|
||||
Mechanical Rights and Statutory Royalties. Licensor waives
|
||||
the exclusive right to collect, whether individually or via a
|
||||
music rights agency or designated agent (e.g. Harry Fox Agency),
|
||||
royalties for any phonorecord You create from the Work ("cover
|
||||
version") and distribute, subject to the compulsory license
|
||||
created by 17 USC Section 115 of the US Copyright Act (or the
|
||||
equivalent in other jurisdictions).
|
||||
Webcasting Rights and Statutory Royalties. For the avoidance
|
||||
of doubt, where the Work is a sound recording, Licensor waives the
|
||||
exclusive right to collect, whether individually or via a
|
||||
performance-rights society (e.g. SoundExchange), royalties for the
|
||||
public digital performance (e.g. webcast) of the Work, subject to
|
||||
the compulsory license created by 17 USC Section 114 of the US
|
||||
Copyright Act (or the equivalent in other jurisdictions).
|
||||
|
||||
The above rights may be exercised in all media and formats whether
|
||||
now known or hereafter devised. The above rights include the right
|
||||
to make such modifications as are technically necessary to
|
||||
exercise the rights in other media and formats. All rights not
|
||||
expressly granted by Licensor are hereby reserved.
|
||||
|
||||
4. Restrictions. The license granted in Section 3 above is
|
||||
expressly made subject to and limited by the following
|
||||
restrictions:
|
||||
|
||||
You may distribute, publicly display, publicly perform, or
|
||||
publicly digitally perform the Work only under the terms of this
|
||||
License, and You must include a copy of, or the Uniform Resource
|
||||
Identifier for, this License with every copy or phonorecord of the
|
||||
Work You distribute, publicly display, publicly perform, or
|
||||
publicly digitally perform. You may not offer or impose any terms
|
||||
on the Work that restrict the terms of this License or the ability
|
||||
of a recipient of the Work to exercise of the rights granted to
|
||||
that recipient under the terms of the License. You may not
|
||||
sublicense the Work. You must keep intact all notices that refer
|
||||
to this License and to the disclaimer of warranties. When You
|
||||
distribute, publicly display, publicly perform, or publicly
|
||||
digitally perform the Work, You may not impose any technological
|
||||
measures on the Work that restrict the ability of a recipient of
|
||||
the Work from You to exercise of the rights granted to that
|
||||
recipient under the terms of the License. This Section 4(a)
|
||||
applies to the Work as incorporated in a Collective Work, but this
|
||||
does not require the Collective Work apart from the Work itself to
|
||||
be made subject to the terms of this License. If You create a
|
||||
Collective Work, upon notice from any Licensor You must, to the
|
||||
extent practicable, remove from the Collective Work any credit as
|
||||
required by Section 4(c), as requested. If You create a Derivative
|
||||
Work, upon notice from any Licensor You must, to the extent
|
||||
practicable, remove from the Derivative Work any credit as
|
||||
required by Section 4(c), as requested.
|
||||
You may distribute, publicly display, publicly perform, or
|
||||
publicly digitally perform a Derivative Work only under: (i) the
|
||||
terms of this License; (ii) a later version of this License with
|
||||
the same License Elements as this License; (iii) either the
|
||||
Creative Commons (Unported) license or a Creative Commons
|
||||
jurisdiction license (either this or a later license version) that
|
||||
contains the same License Elements as this License (e.g.
|
||||
Attribution-ShareAlike 3.0 (Unported)); (iv) a Creative Commons
|
||||
Compatible License. If you license the Derivative Work under one
|
||||
of the licenses mentioned in (iv), you must comply with the terms
|
||||
of that license. If you license the Derivative Work under the
|
||||
terms of any of the licenses mentioned in (i), (ii) or (iii) (the
|
||||
"Applicable License"), you must comply with the terms of the
|
||||
Applicable License generally and with the following provisions:
|
||||
(I) You must include a copy of, or the Uniform Resource Identifier
|
||||
for, the Applicable License with every copy or phonorecord of each
|
||||
Derivative Work You distribute, publicly display, publicly
|
||||
perform, or publicly digitally perform; (II) You may not offer or
|
||||
impose any terms on the Derivative Works that restrict the terms
|
||||
of the Applicable License or the ability of a recipient of the
|
||||
Work to exercise the rights granted to that recipient under the
|
||||
terms of the Applicable License; (III) You must keep intact all
|
||||
notices that refer to the Applicable License and to the disclaimer
|
||||
of warranties; and, (IV) when You distribute, publicly display,
|
||||
publicly perform, or publicly digitally perform the Work, You may
|
||||
not impose any technological measures on the Derivative Work that
|
||||
restrict the ability of a recipient of the Derivative Work from
|
||||
You to exercise the rights granted to that recipient under the
|
||||
terms of the Applicable License. This Section 4(b) applies to the
|
||||
Derivative Work as incorporated in a Collective Work, but this
|
||||
does not require the Collective Work apart from the Derivative
|
||||
Work itself to be made subject to the terms of the Applicable
|
||||
License.
|
||||
If You distribute, publicly display, publicly perform, or
|
||||
publicly digitally perform the Work (as defined in Section 1
|
||||
above) or any Derivative Works (as defined in Section 1 above) or
|
||||
Collective Works (as defined in Section 1 above), You must, unless
|
||||
a request has been made pursuant to Section 4(a), keep intact all
|
||||
copyright notices for the Work and provide, reasonable to the
|
||||
medium or means You are utilizing: (i) the name of the Original
|
||||
Author (or pseudonym, if applicable) if supplied, and/or (ii) if
|
||||
the Original Author and/or Licensor designate another party or
|
||||
parties (e.g. a sponsor institute, publishing entity, journal) for
|
||||
attribution ("Attribution Parties") in Licensor's copyright
|
||||
notice, terms of service or by other reasonable means, the name of
|
||||
such party or parties; the title of the Work if supplied; to the
|
||||
extent reasonably practicable, the Uniform Resource Identifier, if
|
||||
any, that Licensor specifies to be associated with the Work,
|
||||
unless such URI does not refer to the copyright notice or
|
||||
licensing information for the Work; and, consistent with Section
|
||||
3(b) in the case of a Derivative Work, a credit identifying the
|
||||
use of the Work in the Derivative Work (e.g., "French translation
|
||||
of the Work by Original Author," or "Screenplay based on original
|
||||
Work by Original Author"). The credit required by this Section
|
||||
4(c) may be implemented in any reasonable manner; provided,
|
||||
however, that in the case of a Derivative Work or Collective Work,
|
||||
at a minimum such credit will appear, if a credit for all
|
||||
contributing authors of the Derivative Work or Collective Work
|
||||
appears, then as part of these credits and in a manner at least as
|
||||
prominent as the credits for the other contributing authors. For
|
||||
the avoidance of doubt, You may only use the credit required by
|
||||
this Section for the purpose of attribution in the manner set out
|
||||
above and, by exercising Your rights under this License, You may
|
||||
not implicitly or explicitly assert or imply any connection with,
|
||||
sponsorship or endorsement by the Original Author, Licensor and/or
|
||||
Attribution Parties, as appropriate, of You or Your use of the
|
||||
Work, without the separate, express prior written permission of
|
||||
the Original Author, Licensor and/or Attribution Parties.
|
||||
|
||||
5. Representations, Warranties and Disclaimer
|
||||
|
||||
UNLESS OTHERWISE MUTUALLY AGREED TO BY THE PARTIES IN WRITING,
|
||||
LICENSOR OFFERS THE WORK AS-IS AND ONLY TO THE EXTENT OF ANY
|
||||
RIGHTS HELD IN THE LICENSED WORK BY THE LICENSOR. THE LICENSOR
|
||||
MAKES NO REPRESENTATIONS OR WARRANTIES OF ANY KIND CONCERNING THE
|
||||
WORK, EXPRESS, IMPLIED, STATUTORY OR OTHERWISE, INCLUDING, WITHOUT
|
||||
LIMITATION, WARRANTIES OF TITLE, MARKETABILITY, MERCHANTIBILITY,
|
||||
FITNESS FOR A PARTICULAR PURPOSE, NONINFRINGEMENT, OR THE ABSENCE
|
||||
OF LATENT OR OTHER DEFECTS, ACCURACY, OR THE PRESENCE OF ABSENCE
|
||||
OF ERRORS, WHETHER OR NOT DISCOVERABLE. SOME JURISDICTIONS DO NOT
|
||||
ALLOW THE EXCLUSION OF IMPLIED WARRANTIES, SO SUCH EXCLUSION MAY
|
||||
NOT APPLY TO YOU.
|
||||
|
||||
6. Limitation on Liability. EXCEPT TO THE EXTENT REQUIRED BY
|
||||
APPLICABLE LAW, IN NO EVENT WILL LICENSOR BE LIABLE TO YOU ON ANY
|
||||
LEGAL THEORY FOR ANY SPECIAL, INCIDENTAL, CONSEQUENTIAL, PUNITIVE
|
||||
OR EXEMPLARY DAMAGES ARISING OUT OF THIS LICENSE OR THE USE OF THE
|
||||
WORK, EVEN IF LICENSOR HAS BEEN ADVISED OF THE POSSIBILITY OF SUCH
|
||||
DAMAGES.
|
||||
|
||||
7. Termination
|
||||
|
||||
This License and the rights granted hereunder will terminate
|
||||
automatically upon any breach by You of the terms of this License.
|
||||
Individuals or entities who have received Derivative Works or
|
||||
Collective Works from You under this License, however, will not
|
||||
have their licenses terminated provided such individuals or
|
||||
entities remain in full compliance with those licenses. Sections
|
||||
1, 2, 5, 6, 7, and 8 will survive any termination of this License.
|
||||
Subject to the above terms and conditions, the license granted
|
||||
here is perpetual (for the duration of the applicable copyright in
|
||||
the Work). Notwithstanding the above, Licensor reserves the right
|
||||
to release the Work under different license terms or to stop
|
||||
distributing the Work at any time; provided, however that any such
|
||||
election will not serve to withdraw this License (or any other
|
||||
license that has been, or is required to be, granted under the
|
||||
terms of this License), and this License will continue in full
|
||||
force and effect unless terminated as stated above.
|
||||
|
||||
8. Miscellaneous
|
||||
|
||||
Each time You distribute or publicly digitally perform the
|
||||
Work (as defined in Section 1 above) or a Collective Work (as
|
||||
defined in Section 1 above), the Licensor offers to the recipient
|
||||
a license to the Work on the same terms and conditions as the
|
||||
license granted to You under this License.
|
||||
Each time You distribute or publicly digitally perform a
|
||||
Derivative Work, Licensor offers to the recipient a license to the
|
||||
original Work on the same terms and conditions as the license
|
||||
granted to You under this License.
|
||||
If any provision of this License is invalid or unenforceable
|
||||
under applicable law, it shall not affect the validity or
|
||||
enforceability of the remainder of the terms of this License, and
|
||||
without further action by the parties to this agreement, such
|
||||
provision shall be reformed to the minimum extent necessary to
|
||||
make such provision valid and enforceable.
|
||||
No term or provision of this License shall be deemed waived
|
||||
and no breach consented to unless such waiver or consent shall be
|
||||
in writing and signed by the party to be charged with such waiver
|
||||
or consent.
|
||||
This License constitutes the entire agreement between the
|
||||
parties with respect to the Work licensed here. There are no
|
||||
understandings, agreements or representations with respect to the
|
||||
Work not specified here. Licensor shall not be bound by any
|
||||
additional provisions that may appear in any communication from
|
||||
You. This License may not be modified without the mutual written
|
||||
agreement of the Licensor and You.
|
||||
|
||||
Creative Commons Notice
|
||||
|
||||
Creative Commons is not a party to this License, and makes no
|
||||
warranty whatsoever in connection with the Work. Creative Commons
|
||||
will not be liable to You or any party on any legal theory for any
|
||||
damages whatsoever, including without limitation any general,
|
||||
special, incidental or consequential damages arising in connection
|
||||
to this license. Notwithstanding the foregoing two (2) sentences,
|
||||
if Creative Commons has expressly identified itself as the
|
||||
Licensor hereunder, it shall have all rights and obligations of
|
||||
Licensor.
|
||||
|
||||
Except for the limited purpose of indicating to the public
|
||||
that the Work is licensed under the CCPL, Creative Commons does
|
||||
not authorize the use by either party of the trademark "Creative
|
||||
Commons" or any related trademark or logo of Creative Commons
|
||||
without the prior written consent of Creative Commons. Any
|
||||
permitted use will be in compliance with Creative Commons'
|
||||
then-current trademark usage guidelines, as may be published on
|
||||
its website or otherwise made available upon request from time to
|
||||
time. For the avoidance of doubt, this trademark restriction does
|
||||
not form part of this License.
|
||||
|
||||
Creative Commons may be contacted at
|
||||
http://creativecommons.org/.
|
||||
|
|
@ -1,94 +1,11 @@
|
|||
README file for Plantlife mod, by Vanessa Ezekowitz
|
||||
README file for Hades Plantlife mod
|
||||
---------------------------------------------------
|
||||
|
||||
Plantlife is a combined form of my Flowers, Jungle Grass, and Poison Ivy mods
|
||||
and has been significantly rewritten and re-organized. This mod supplies all
|
||||
three of these components and should be 100% compatible with mods that used the
|
||||
old versions.
|
||||
|
||||
Its purpose is to add various kinds of flowers, cotton plants, water foliage,
|
||||
poison ivy, and jungle grass in a few sizes. All of these are spawned as
|
||||
normal nodes and can be collected and used in any recipes that depend on the
|
||||
old mods.
|
||||
This mod is a simple framework for plant spawning for Hades Revisited.
|
||||
It is an utility mod for other mods to use in order to spawn plants like
|
||||
vines and waterlilies.
|
||||
|
||||
Spawning of plants is sensitive to the amount of available light. Flowers,
|
||||
cotton, and waterlilies only spawn when there at least a signficant amount of
|
||||
light. Seaweed will grow only in dimly-lit areas. Jungle grass and poison ivy
|
||||
also grow in the daytime, but require less light than flowers.
|
||||
Technically, it's a trimmed-down fork of the Plantlife mod by Vanessa Ezekowitz.
|
||||
|
||||
Growing of jungle grass and poison ivy will only occur for plants that are on
|
||||
the same surface that is necessary for them to spawn on, so they won't grow if
|
||||
placed on e.g. cobble or homedecor flower pot, etc. This doesn't affect
|
||||
wall-climbing poison ivy, since it uses a different growth pattern.
|
||||
|
||||
All plants use perlin noise to keep where they grow under control - no more
|
||||
random spread of plants! In addition, the density of the plants in any region
|
||||
they appear in has been fixed and brought under control.
|
||||
|
||||
Poison ivy is found sparsely among junglegrass, but will not grow near flowers.
|
||||
|
||||
------------------------------------------------------------------------------
|
||||
|
||||
Important details:
|
||||
|
||||
Configuration: Any of the three components of this mod can be disabled by
|
||||
editing plants/init.lua, near the beginning of the file, and changing one or
|
||||
more of these lines to false:
|
||||
|
||||
local enable_flowers = true
|
||||
local enable_junglegrass = true
|
||||
local enable_poisonivy = false
|
||||
|
||||
Dependencies: Just the game's default stuff.
|
||||
|
||||
Recommends: Nothing in particular.
|
||||
|
||||
Conflicts: This mod should not be installed alongside the original Flowers,
|
||||
Jungle Grass, or Poison Ivy mods. If those exist, delete them, as this mod
|
||||
supplies all of their functionality.
|
||||
|
||||
Software Requirements: This mod required Minetest 0.4.4 from January 7, 2013 or
|
||||
later. It will NOT work with any prior version.
|
||||
|
||||
------------------------------------------------------------------------------
|
||||
|
||||
Crafting:
|
||||
|
||||
Only Flowers have crafting recipes. For a flower pot, put three
|
||||
clay bricks in the crafting grid in a "v" shape like so (yields 1):
|
||||
|
||||
- - -
|
||||
B - B
|
||||
- B -
|
||||
|
||||
To put a flower into a pot, just put one of each into the crafting grid.
|
||||
|
||||
------------------------------------------------------------------------------
|
||||
|
||||
Notes:
|
||||
|
||||
Flowers has been completely rewritten, almost from scratch, using the most
|
||||
recent and advanced features the game engine has to offer. It should be
|
||||
significantly faster than the original Ironzorg Flowers mod. Flowers and
|
||||
cotton spawn on grass only, seaweed spawns on water or grass close to the
|
||||
shoreline, or on very small stone islands in water. Waterlilies of course
|
||||
spawn on water.
|
||||
|
||||
There are four different sizes of jungle grasses, all of which yield a single
|
||||
junglegrass object when gathered (so all four sizes may be used where jungle
|
||||
grass is called for). The largest size uses the game's standard jungle grass
|
||||
node, while the others are defined by this mod.
|
||||
|
||||
Junglegrass will spawn on grass, sand, desert sand and the tops of papyrus and
|
||||
cactus (though rarely), and will do so anywhere in the map. Grass on the
|
||||
ground will grow and eventually disappear (die), while grass in the desert will
|
||||
grow and eventually turn into dry shrubs.
|
||||
|
||||
Poison Ivy will spawn on grass and in some cases, on vertical surfaces
|
||||
including trees and jungle trees where they meet the dirt or grass. Ivy
|
||||
previously spawned on the ground taller/thicker or start climbing up said
|
||||
vertical surfaces and trees.
|
||||
|
||||
At present, the poison ivy presents little more than an annoyance - they can
|
||||
only be cut down and either re-planted or thrown away. No damage is done by
|
||||
harvesting them, yet. ;-)
|
||||
Developers, see the API.md text file to learn how to use this mod.
|
||||
|
|
|
@ -1,4 +0,0 @@
|
|||
The plantlife code was modified and is NOT the orginal code.
|
||||
It wouldn't work in other games. Please load the orginal code from the
|
||||
forums if you want use it for other games.
|
||||
All new changes are WTPFL-licensed.
|
|
@ -1,86 +1,30 @@
|
|||
-- Plantlife library mod by Vanessa Ezekowitz
|
||||
-- last revision, 2013-01-24
|
||||
--
|
||||
-- License: MIT License
|
||||
--
|
||||
-- I got the temperature map idea from "hmmmm", values used for it came from
|
||||
-- Splizard's snow mod.
|
||||
--
|
||||
|
||||
|
||||
-- Various settings - most of these probably won't need to be changed
|
||||
|
||||
-- Hades Plantslib mod
|
||||
|
||||
plantslib = {}
|
||||
|
||||
-- Set to true to spam console with debugging info (needs verbose debug level)
|
||||
local DEBUG = false
|
||||
|
||||
plantslib.modpath = minetest.get_modpath("plants_lib")
|
||||
|
||||
|
||||
local S = minetest.get_translator("plantlife")
|
||||
|
||||
local DEBUG = false --... except if you want to spam the console with debugging info :-)
|
||||
|
||||
|
||||
function plantslib:dbg(msg)
|
||||
local function dbg(msg)
|
||||
if DEBUG then
|
||||
minetest.log("verbose", "[Plantlife] "..msg)
|
||||
minetest.log("verbose", "[plants_lib] "..msg)
|
||||
end
|
||||
end
|
||||
|
||||
|
||||
plantslib.plantlife_seed_diff = 329 -- needs to be global so other mods can see it
|
||||
--global
|
||||
local maxp = {}
|
||||
local minp = {}
|
||||
local spawn_plants = {}
|
||||
--
|
||||
local perlin_octaves = 3
|
||||
local perlin_persistence = 0.6
|
||||
local perlin_scale = 100
|
||||
|
||||
|
||||
local temperature_seeddiff = 112
|
||||
local temperature_octaves = 3
|
||||
local temperature_persistence = 0.5
|
||||
local temperature_scale = 150
|
||||
|
||||
|
||||
local humidity_seeddiff = 9130
|
||||
local humidity_octaves = 3
|
||||
local humidity_persistence = 0.5
|
||||
local humidity_scale = 250
|
||||
|
||||
|
||||
local time_scale = 1
|
||||
local time_speed = tonumber(minetest.settings:get("time_speed"))
|
||||
|
||||
|
||||
if time_speed and time_speed > 0 then
|
||||
time_scale = 72 / time_speed
|
||||
end
|
||||
|
||||
|
||||
plantslib:dbg("time_speed = "..dump(time_speed))
|
||||
plantslib:dbg("time_scale = 72 / time_speed = "..dump(time_scale))
|
||||
|
||||
|
||||
--PerlinNoise(seed, octaves, persistence, scale)
|
||||
|
||||
|
||||
plantslib.perlin_temperature = PerlinNoise(temperature_seeddiff, temperature_octaves, temperature_persistence, temperature_scale)
|
||||
plantslib.perlin_humidity = PerlinNoise(humidity_seeddiff, humidity_octaves, humidity_persistence, humidity_scale)
|
||||
|
||||
|
||||
-- Local functions
|
||||
|
||||
|
||||
local function dump_pos(pos)
|
||||
return "{x="..pos.x..",y="..pos.y..",z="..pos.z.."}"
|
||||
end
|
||||
|
||||
|
||||
function plantslib:is_node_loaded(node_pos)
|
||||
local function is_node_loaded (node_pos)
|
||||
local n = minetest.get_node_or_nil(node_pos)
|
||||
if (not n) or (n.name == "ignore") then
|
||||
return false
|
||||
|
@ -88,18 +32,7 @@ function plantslib:is_node_loaded(node_pos)
|
|||
return true
|
||||
end
|
||||
|
||||
|
||||
function plantslib:clone_node(name)
|
||||
node2={}
|
||||
node=minetest.registered_nodes[name]
|
||||
for k,v in pairs(node) do
|
||||
node2[k]=v
|
||||
end
|
||||
return node2
|
||||
end
|
||||
|
||||
|
||||
function plantslib:set_defaults(biome)
|
||||
local function set_defaults(biome)
|
||||
biome.seed_diff = biome.seed_diff or 0
|
||||
biome.min_elevation = biome.min_elevation or -31000
|
||||
biome.max_elevation = biome.max_elevation or 31000
|
||||
|
@ -130,346 +63,10 @@ function plantslib:set_defaults(biome)
|
|||
biome.facedir = biome.facedir or 0
|
||||
end
|
||||
|
||||
|
||||
-- Spawn plants using the map generator
|
||||
|
||||
|
||||
function plantslib:register_generate_plant(biomedef, node_or_function_or_model)
|
||||
plantslib:dbg("Registered mapgen spawner:")
|
||||
plantslib:dbg(dump(biomedef))
|
||||
|
||||
|
||||
minetest.register_on_generated(plantslib:search_for_surfaces(minp, maxp, biomedef, node_or_function_or_model))
|
||||
end
|
||||
|
||||
|
||||
function plantslib:search_for_surfaces(minp, maxp, biomedef, node_or_function_or_model)
|
||||
return function(minp, maxp, blockseed)
|
||||
local t1=os.clock()
|
||||
|
||||
|
||||
local biome = biomedef
|
||||
plantslib:set_defaults(biome)
|
||||
|
||||
|
||||
plantslib:dbg("Started checking generated mapblock volume...")
|
||||
local searchnodes = minetest.find_nodes_in_area(minp, maxp, biome.surface)
|
||||
local in_biome_nodes = {}
|
||||
local num_in_biome_nodes = 0
|
||||
for i in ipairs(searchnodes) do
|
||||
local pos = searchnodes[i]
|
||||
local p_top = { x = pos.x, y = pos.y + 1, z = pos.z }
|
||||
local perlin1 = minetest.get_perlin(biome.seed_diff, perlin_octaves, perlin_persistence, perlin_scale)
|
||||
local noise1 = perlin1:get_2d({x=p_top.x, y=p_top.z})
|
||||
local noise2 = plantslib.perlin_temperature:get_2d({x=p_top.x, y=p_top.z})
|
||||
local noise3 = plantslib.perlin_humidity:get_2d({x=p_top.x+150, y=p_top.z+50})
|
||||
if (not biome.depth or minetest.get_node({ x = pos.x, y = pos.y-biome.depth-1, z = pos.z }).name ~= biome.surface)
|
||||
and (not biome.check_air or (biome.check_air and minetest.get_node(p_top).name == "air"))
|
||||
and pos.y >= biome.min_elevation
|
||||
and pos.y <= biome.max_elevation
|
||||
-- and noise1 > biome.plantlife_limit
|
||||
-- and noise2 <= biome.temp_min
|
||||
-- and noise2 >= biome.temp_max
|
||||
-- and noise3 <= biome.humidity_min
|
||||
-- and noise3 >= biome.humidity_max
|
||||
and (not biome.ncount or table.getn(minetest.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 or table.getn(minetest.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 (not biome.below_nodes or string.find(dump(biome.below_nodes), minetest.get_node({x=pos.x, y=pos.y-1, z=pos.z}).name) )
|
||||
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(s) "..dump(biome.surface).." in 5x5x5 mapblock volume at {"..dump(minp)..":"..dump(maxp).."} to check.")
|
||||
|
||||
|
||||
if num_in_biome_nodes > 0 then
|
||||
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 spawned do
|
||||
local pos = in_biome_nodes[math.random(1, num_in_biome_nodes)]
|
||||
if biome.spawn_replace_node then
|
||||
pos.y = pos.y-1
|
||||
end
|
||||
local p_top = { x = pos.x, y = pos.y + 1, z = pos.z }
|
||||
|
||||
|
||||
if not (biome.avoid_nodes and biome.avoid_radius and minetest.find_node_near(p_top, biome.avoid_radius + math.random(-1.5,2), biome.avoid_nodes)) then
|
||||
if biome.delete_above then
|
||||
minetest.remove_node(p_top)
|
||||
minetest.remove_node({x=p_top.x, y=p_top.y+1, z=p_top.z})
|
||||
end
|
||||
|
||||
|
||||
if biome.delete_above_surround then
|
||||
minetest.remove_node({x=p_top.x-1, y=p_top.y, z=p_top.z})
|
||||
minetest.remove_node({x=p_top.x+1, y=p_top.y, z=p_top.z})
|
||||
minetest.remove_node({x=p_top.x, y=p_top.y, z=p_top.z-1})
|
||||
minetest.remove_node({x=p_top.x, y=p_top.y, z=p_top.z+1})
|
||||
|
||||
|
||||
minetest.remove_node({x=p_top.x-1, y=p_top.y+1, z=p_top.z})
|
||||
minetest.remove_node({x=p_top.x+1, y=p_top.y+1, z=p_top.z})
|
||||
minetest.remove_node({x=p_top.x, y=p_top.y+1, z=p_top.z-1})
|
||||
minetest.remove_node({x=p_top.x, y=p_top.y+1, z=p_top.z+1})
|
||||
end
|
||||
|
||||
|
||||
if biome.spawn_replace_node then
|
||||
minetest.remove_node(pos)
|
||||
end
|
||||
|
||||
|
||||
if type(node_or_function_or_model) == "table" then
|
||||
plantslib:dbg("Spawn tree at {"..dump(pos).."}")
|
||||
plantslib:generate_tree(pos, node_or_function_or_model)
|
||||
|
||||
|
||||
elseif type(node_or_function_or_model) == "string" then
|
||||
if not minetest.registered_nodes[node_or_function_or_model] then
|
||||
plantslib:dbg("Call function: "..node_or_function_or_model.."("..dump_pos(pos)..")")
|
||||
local t2=os.clock()
|
||||
assert(loadstring(node_or_function_or_model.."("..dump_pos(pos)..")"))()
|
||||
plantslib:dbg("Executed that function in ".. (os.clock()-t2)*1000 .."ms")
|
||||
else
|
||||
plantslib:dbg("Add node: "..node_or_function_or_model.." at ("..dump(p_top)..")")
|
||||
minetest.add_node(p_top, { name = node_or_function_or_model })
|
||||
end
|
||||
end
|
||||
spawned = true
|
||||
else
|
||||
tries = tries + 1
|
||||
plantslib:dbg("No room to spawn object at {"..dump(pos).."} -- trying again elsewhere")
|
||||
end
|
||||
end
|
||||
if tries == 2 then
|
||||
plantslib:dbg("Unable to spawn that object. Giving up on it.")
|
||||
end
|
||||
end
|
||||
end
|
||||
plantslib:dbg("Evaluated/populated chunk in ".. (os.clock()-t1)*1000 .."ms")
|
||||
end
|
||||
end
|
||||
|
||||
|
||||
-- The spawning ABM
|
||||
|
||||
|
||||
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.spawn_delay*time_scale >= 1 then
|
||||
biome.interval = biome.spawn_delay*time_scale
|
||||
else
|
||||
biome.interval = 1
|
||||
end
|
||||
|
||||
|
||||
plantslib:set_defaults(biome)
|
||||
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({
|
||||
label = "Plantlife: Spawn plants",
|
||||
nodenames = biome.spawn_surfaces,
|
||||
interval = biome.interval,
|
||||
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.get_node(p_top)
|
||||
local perlin1 = minetest.get_perlin(biome.seed_diff, perlin_octaves, perlin_persistence, perlin_scale)
|
||||
local noise1 = perlin1:get_2d({x=p_top.x, y=p_top.z})
|
||||
local noise2 = plantslib.perlin_temperature:get_2d({x=p_top.x, y=p_top.z})
|
||||
local noise3 = plantslib.perlin_humidity:get_2d({x=p_top.x+150, y=p_top.z+50})
|
||||
-- if noise1 > biome.plantlife_limit
|
||||
if plantslib:is_node_loaded(p_top) then
|
||||
local n_light = minetest.get_node_light(p_top, nil)
|
||||
if not (biome.avoid_nodes and biome.avoid_radius and minetest.find_node_near(p_top, biome.avoid_radius + math.random(-1.5,2), biome.avoid_nodes))
|
||||
and n_light >= biome.light_min
|
||||
and n_light <= biome.light_max
|
||||
and (not(biome.neighbors and biome.ncount) or table.getn(minetest.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.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.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)
|
||||
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.add_node(p_top, { name = biome.alt_wallnode, param2 = walldir })
|
||||
end
|
||||
else
|
||||
local currentsurface = minetest.get_node(pos).name
|
||||
if currentsurface ~= "hades_core:water_source"
|
||||
or (currentsurface == "hades_core:water_source" and table.getn(minetest.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}, {"hades_core:dirt", "hades_core:dirt_with_grass", "hades_core:ash"})) > 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)
|
||||
local fdir = biome.facedir
|
||||
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 type(spawn_plants) == "string" then
|
||||
plantslib:dbg("Call function: "..spawn_plants.."("..dump_pos(pos)..")")
|
||||
assert(loadstring(spawn_plants.."("..dump_pos(pos)..")"))()
|
||||
elseif not biome.spawn_on_side and not biome.spawn_on_bottom and not biome.spawn_replace_node then
|
||||
if n_top.name == "air" then
|
||||
plantslib:dbg("Spawn: "..plant_to_spawn.." on top of ("..dump(pos).."); facedir="..fdir)
|
||||
minetest.add_node(p_top, { name = plant_to_spawn, param2 = fdir })
|
||||
end
|
||||
elseif biome.spawn_replace_node then
|
||||
|
||||
|
||||
plantslib:dbg("Spawn: "..plant_to_spawn.." to replace "..minetest.get_node(pos).name.." at ("..dump(pos)..")")
|
||||
minetest.add_node(pos, { name = plant_to_spawn, param2 = fdir })
|
||||
|
||||
|
||||
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.add_node(onside.newpos, { name = plant_to_spawn, param2 = onside.facedir })
|
||||
end
|
||||
elseif biome.spawn_on_bottom then
|
||||
if minetest.get_node({x=pos.x, y=pos.y-1, z=pos.z}).name == "air" then
|
||||
plantslib:dbg("Spawn: "..plant_to_spawn.." on bottom of ("..dump(pos)..")")
|
||||
minetest.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
|
||||
|
||||
|
||||
-- The growing ABM
|
||||
|
||||
|
||||
function plantslib:grow_plants(opts)
|
||||
|
||||
|
||||
local options = opts
|
||||
|
||||
|
||||
options.height_limit = options.height_limit or 5
|
||||
options.ground_nodes = options.ground_nodes or { "hades_core:dirt_with_grass" }
|
||||
options.grow_nodes = options.grow_nodes or { "hades_core:dirt_with_grass" }
|
||||
options.seed_diff = options.seed_diff or 0
|
||||
|
||||
|
||||
plantslib:dbg("Registered growing ABM:")
|
||||
plantslib:dbg(dump(options))
|
||||
|
||||
|
||||
if options.grow_delay*time_scale >= 1 then
|
||||
options.interval = options.grow_delay*time_scale
|
||||
else
|
||||
options.interval = 1
|
||||
end
|
||||
|
||||
|
||||
minetest.register_abm({
|
||||
label = "Plantlib: Plant growth/death",
|
||||
nodenames = { options.grow_plant },
|
||||
interval = options.interval,
|
||||
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.get_node(p_top)
|
||||
local n_bot = minetest.get_node(p_bot)
|
||||
local root_node = minetest.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 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
|
||||
if 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.add_node(p_top, { name = options.grow_plant, param2 = walldir})
|
||||
end
|
||||
|
||||
|
||||
elseif not options.grow_result and not options.grow_function then
|
||||
plantslib:dbg("Die: "..options.grow_plant.." at ("..dump(pos)..")")
|
||||
minetest.remove_node(pos)
|
||||
|
||||
|
||||
else
|
||||
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.remove_node(pos)
|
||||
plantslib:grow_tree(pos, grow_function)
|
||||
return
|
||||
elseif growtype == "string" then
|
||||
local perlin1 = minetest.get_perlin(seeddiff, perlin_octaves, perlin_persistence, perlin_scale)
|
||||
local noise1 = perlin1:get_2d({x=pos.x, y=pos.z})
|
||||
local noise2 = plantslib.perlin_temperature:get_2d({x=pos.x, y=pos.z})
|
||||
plantslib:dbg("Grow: call function "..grow_function.."("..dump_pos(pos)..","..dump(walldir)..")")
|
||||
assert(loadstring(grow_function.."("..dump_pos(pos)..","..dump(walldir)..")"))()
|
||||
return
|
||||
elseif growtype == "nil" then
|
||||
plantslib:dbg("Grow: place "..replacement.." at ("..dump(pos)..") on wall "..dump(walldir))
|
||||
minetest.add_node(pos, { name = replacement, param2 = walldir})
|
||||
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.
|
||||
|
||||
|
||||
function plantslib:find_adjacent_wall(pos, verticals)
|
||||
local function find_adjacent_wall(pos, verticals)
|
||||
local verts = dump(verticals)
|
||||
if string.find(verts, minetest.get_node({ x=pos.x-1, y=pos.y, z=pos.z }).name) then return 3 end
|
||||
if string.find(verts, minetest.get_node({ x=pos.x+1, y=pos.y, z=pos.z }).name) then return 2 end
|
||||
|
@ -478,23 +75,7 @@ function plantslib:find_adjacent_wall(pos, verticals)
|
|||
return nil
|
||||
end
|
||||
|
||||
|
||||
-- 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:search_downward(pos, heightlimit, ground)
|
||||
for i = 0, heightlimit do
|
||||
if string.find(dump(ground), minetest.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)
|
||||
local function find_open_side(pos)
|
||||
if minetest.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
|
||||
|
@ -510,64 +91,90 @@ function plantslib:find_open_side(pos)
|
|||
return nil
|
||||
end
|
||||
|
||||
-- The spawning ABM
|
||||
|
||||
-- spawn_tree() on generate is routed through here so that other mods can hook
|
||||
-- into it.
|
||||
function plantslib:spawn_on_surfaces(biome)
|
||||
|
||||
|
||||
function plantslib:generate_tree(pos, node_or_function_or_model)
|
||||
local t=os.clock()
|
||||
minetest.spawn_tree(pos, node_or_function_or_model)
|
||||
plantslib:dbg("Generated one tree in ".. (os.clock()-t)*1000 .."ms")
|
||||
end
|
||||
|
||||
|
||||
-- and this one's for the call used in the growing code
|
||||
|
||||
|
||||
function plantslib:grow_tree(pos, node_or_function_or_model)
|
||||
local t=os.clock()
|
||||
minetest.spawn_tree(pos, node_or_function_or_model)
|
||||
plantslib:dbg("Generated one tree in ".. (os.clock()-t)*1000 .."ms")
|
||||
end
|
||||
|
||||
|
||||
-- check if a node is owned before allowing manual placement of a node
|
||||
-- (used by flowers_plus)
|
||||
|
||||
|
||||
function plantslib:node_is_owned(pos, placer)
|
||||
local name = placer:get_player_name()
|
||||
local is_protected = minetest.is_protected(pos, name) and not minetest.check_player_privs(name, "protection_bypass")
|
||||
if is_protected then
|
||||
minetest.record_protection_violation(pos, name)
|
||||
return true
|
||||
if biome.spawn_delay*time_scale >= 1 then
|
||||
biome.interval = biome.spawn_delay*time_scale
|
||||
else
|
||||
return false
|
||||
biome.interval = 1
|
||||
end
|
||||
|
||||
|
||||
set_defaults(biome)
|
||||
biome.spawn_plants_count = table.getn(biome.spawn_plants)
|
||||
|
||||
dbg("Registered spawning ABM:")
|
||||
dbg(dump(biome))
|
||||
dbg("Number of trigger nodes in this ABM: "..biome.spawn_plants_count )
|
||||
|
||||
minetest.register_abm({
|
||||
label = biome.label,
|
||||
nodenames = biome.spawn_surfaces,
|
||||
interval = biome.interval,
|
||||
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.get_node(p_top)
|
||||
if is_node_loaded(p_top) then
|
||||
local n_light = minetest.get_node_light(p_top, nil)
|
||||
if not (biome.avoid_nodes and biome.avoid_radius and minetest.find_node_near(p_top, biome.avoid_radius + math.random(-1.5,2), biome.avoid_nodes))
|
||||
and n_light >= biome.light_min
|
||||
and n_light <= biome.light_max
|
||||
and (not(biome.neighbors and biome.ncount) or table.getn(minetest.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.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.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)
|
||||
then
|
||||
local walldir = find_adjacent_wall(p_top, biome.verticals_list)
|
||||
if biome.alt_wallnode and walldir then
|
||||
if n_top.name == "air" then
|
||||
dbg("Spawn: "..biome.alt_wallnode.." on top of ("..dump(pos)..") against wall "..walldir)
|
||||
minetest.add_node(p_top, { name = biome.alt_wallnode, param2 = walldir })
|
||||
end
|
||||
else
|
||||
local currentsurface = minetest.get_node(pos).name
|
||||
if currentsurface ~= "hades_core:water_source"
|
||||
or (currentsurface == "hades_core:water_source" and table.getn(minetest.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}, {"hades_core:dirt", "hades_core:dirt_with_grass", "hades_core:ash"})) > 0 )
|
||||
then
|
||||
local rnd = math.random(1, biome.spawn_plants_count)
|
||||
local plant_to_spawn = biome.spawn_plants[rnd]
|
||||
dbg("Chose entry number "..rnd.." of "..biome.spawn_plants_count)
|
||||
local fdir = biome.facedir
|
||||
if biome.random_facedir then
|
||||
fdir = math.random(biome.random_facedir[1],biome.random_facedir[2])
|
||||
dbg("Gave it a random facedir: "..fdir)
|
||||
end
|
||||
if not biome.spawn_on_side and not biome.spawn_on_bottom and not biome.spawn_replace_node then
|
||||
if n_top.name == "air" then
|
||||
dbg("Spawn: "..plant_to_spawn.." on top of ("..dump(pos).."); facedir="..fdir)
|
||||
minetest.add_node(p_top, { name = plant_to_spawn, param2 = fdir })
|
||||
end
|
||||
elseif biome.spawn_replace_node then
|
||||
|
||||
|
||||
dbg("Spawn: "..plant_to_spawn.." to replace "..minetest.get_node(pos).name.." at ("..dump(pos)..")")
|
||||
minetest.add_node(pos, { name = plant_to_spawn, param2 = fdir })
|
||||
|
||||
|
||||
elseif biome.spawn_on_side then
|
||||
local onside = find_open_side(pos)
|
||||
if onside then
|
||||
dbg("Spawn: "..plant_to_spawn.." at side of ("..dump(pos).."), facedir "..onside.facedir.."")
|
||||
minetest.add_node(onside.newpos, { name = plant_to_spawn, param2 = onside.facedir })
|
||||
end
|
||||
elseif biome.spawn_on_bottom then
|
||||
if minetest.get_node({x=pos.x, y=pos.y-1, z=pos.z}).name == "air" then
|
||||
dbg("Spawn: "..plant_to_spawn.." on bottom of ("..dump(pos)..")")
|
||||
minetest.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
|
||||
|
||||
|
||||
-- Check for infinite stacks (LEGACY)
|
||||
|
||||
if minetest.get_modpath("unified_inventory") or not minetest.settings:get_bool("creative_mode") then
|
||||
plantslib.expect_infinite_stacks = false
|
||||
else
|
||||
plantslib.expect_infinite_stacks = true
|
||||
end
|
||||
|
||||
|
||||
-- read a field from a node's definition
|
||||
|
||||
|
||||
function plantslib:get_nodedef_field(nodename, fieldname)
|
||||
if not minetest.registered_nodes[nodename] then
|
||||
return nil
|
||||
end
|
||||
return minetest.registered_nodes[nodename][fieldname]
|
||||
end
|
||||
|
||||
|
||||
|
||||
|
||||
minetest.log("action", "[Plantlife Library] Loaded")
|
||||
|
|
|
@ -1,2 +0,0 @@
|
|||
# textdomain:plants_lib
|
||||
Sorry, someone owns that spot.=Tschuldigung, jemanden gehört diese Stelle.
|
|
@ -1,2 +0,0 @@
|
|||
# textdomain:plants_lib
|
||||
Sorry, someone owns that spot.=
|
Loading…
Reference in New Issue