This commit is contained in:
Milan Meduna 2020-10-25 20:54:52 +01:00
parent 60c2f27a70
commit b0e3380ed8
173 changed files with 8855 additions and 2 deletions

View File

@ -74,8 +74,14 @@ load_mod_unifieddyes = true
load_mod_font_api = true
load_mod_display_api = true
load_mod_basic_materials = true
load_mod_trees_lib = true
load_mod_biome_lib = true
load_mod_moretrees = true
load_mod_vines = true
load_mod_intllib = true
" >> /home/minetest/.minetest/worlds/world/world.mt
chown minetest:minetest /home/minetest/ -cR
echo "Start minetestsrv service"
systemctl start minetestsrv

View File

@ -49,9 +49,13 @@ git clone --depth 1 --branch master https://github.com/minetest-mods/mymasonhamm
git clone --depth 1 --branch master https://github.com/minetest-mods/mywoodslopes.git
git clone --depth 1 --branch master https://github.com/minetest-mods/display_api.git
git clone --depth 1 --branch master https://github.com/minetest-mods/font_api.git
git clone --depth 1 --branch master https://github.com/minetest-mods/intllib.git
git clone --depth 1 --branch master https://gitlab.com/VanessaE/unifieddyes.git
git clone --depth 1 --branch master https://gitlab.com/VanessaE/basic_materials.git
git clone --depth 1 --branch master https://github.com/minetest-mods/trees_lib.git
git clone --depth 1 --branch master https://gitlab.com/VanessaE/biome_lib.git
git clone --depth 1 --branch master https://gitlab.com/VanessaE/moretrees.git
git clone --depth 1 --branch master https://github.com/minetest-mods/intllib.git
git clone --depth 1 --branch master https://github.com/bas080/vines.git
rm */.git -rf
rm */.gitignore -f
rm */.gitattributes -f

590
mods/biome_lib/API.txt Normal file
View File

@ -0,0 +1,590 @@
This document describes the Plantlife mod API.
Last revision: 2015-02-16
=========
Functions
=========
There are three main functions defined by the main "biome_lib" mod:
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.
Most functions in plants lib are declared locally to avoid namespace
collisions with other mods. They are accessible via the "biome_lib" method,
e.g. biome_lib: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.
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 "default:sand" or
"default: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", "default: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
table. Below is a list of everything supported by this function:
biome = {
spawn_plants = something, -- [*] String or table; see below.
spawn_delay = number, -- same as sdelay, above.
spawn_chance = number, -- same as schance, above.
spawn_surfaces = {table}, -- List of node names on which the plants
-- should be spawned. As with the single-node "ssurface"
-- option in the legacy API, you should not put stone, air,
-- etc. here.
---- 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
---- where your objects are spawned.
label = string, -- set this to identify the ABM for Minetest's profiler
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.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 appropriate for the node you want to spawn.
depth_max = num, -- If the object spawns on top of a water source, the
-- water must be at most this deep. Defaults to 1.
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 (only
-- check 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
-- 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 size of the area being tested.
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).
humidity_min = num, -- Minimum humidity for the plant to spawn in. Like
-- the temperature map, this is a Perlin value where
-- lower numbers mean more humidity in the area.
-- Defaults to +1 (0% humidity).
humidity_max = num, -- Maximum humidity for the plant to spawn at.
-- Defaults to -1 (100% humidity).
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.
spawn_on_side = bool, -- Set this to true to immediately 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).
choose_random_wall = bool, -- if set to true, and searching for walls is
-- being done, just pick any random wall if there is
-- one, rather than returning the first one.
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.
spawn_replace_node = bool, -- If set to true, the target node itself is
-- replaced by the spawned object. Overrides the
-- spawn_on_bottom and spawn_on_side settings.
}
[*] spawn_plants must be either a table or a string. If it's a table, the
values therein are treated as a list of nodenames to pick from randomly on
each application of the ABM code. The more nodes you can pack into this
parameter to avoid making too many calls to this function, the lower the CPU
load will likely be.
You can also specify a string containing the name of a function to execute.
In this case, the function will be passed a single position parameter
indicating where the function should place the desired object, and the checks
for spawning on top vs. sides vs. bottom vs. replacing the target node will be
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.
=====
biome_lib:register_generate_plant(biome, nodes_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, function, or table describing what to do if the
engine finds a suitable surface 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
-- "default: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 to avoid when spawning. Groups are
-- not supported here.
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/omitted, this check is
-- skipped. Avoid using excessively large radii.
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, -- Max 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 largest Perlin value).
temp_max = num, -- warmest allowable temperature to spawn a plant
-- (lowest Perlin 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. Set this to false VERY
-- SPARINGLY, as it will slow the map generator down.
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 five nodes surrounding the above space,
-- and the five nodes above those, resulting in a two-
-- node-deep cross-shaped empty region above/around
-- the spawn target. Useful when adding trees to snow
-- biomes. Defaults to false.
spawn_replace_node = bool, -- same as with the ABM spawner.
random_facedir = {table}, -- same as with the ABM spawner.
}
Regarding nodes_or_function_or_treedef, this must either be a string naming
a node to spawn, a table with a list of nodes to choose from, a table with an
L-Systems tree definition, or a function.
If you specified a string, the code will attempt to determine whether that
string specifies a valid node name. If it does, that node will be placed on
top of the target position directly (unless one of the other mapgen options
directs the code to do otherwise).
If you specified a table and there is no "axiom" field, the code assumes that
it is a list of nodes. Simply name one node per entry in the list, e.g.
{"default:junglegrass", "default:dry_shrub"} and so on, for as many nodes as
you want to list. A random node from the list will be chosen each time the
code goes to place a node.
If you specified a table, and there *is* an "axiom" field, the code assumes
that this table contains an L-Systems tree definition, which will be passed
directly to the engine's spawn_tree() function along with the position on
which to spawn the tree.
You can also supply a function to be directly executed, which is given the
current node position (the usual "pos" table format) as its sole argument. It
will be called in the form:
somefunction(pos)
=====
biome_lib: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 = {
label = string, -- set this to identify the ABM for Minetest's
-- profiler. If not set, biome_lib will set it to
-- "biome_lib grow_plants(): " appended with the node
-- in grow_plant (or the first item if it's a table)
grow_plant = "string" or {table}, -- Name(s) of the node(s) to be grown
-- into something else. This value is passed to the
-- ABM as the "nodenames" parameter, so the plants
-- themselves are the ABM trigger, rather than
-- the ground they spawned on. A plant will only grow
-- if the node above it is air. If you use a table,
-- note that all nodes referenced therein will be
-- grown into the same final 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
-- "default:dry_shrub" 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
-- necessarily growing and perhaps dieing. Defaults
-- to "default: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}, -- same as with spawning a plant.
choose_random_wall = bool, -- same as with spawning a plant.
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 field 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, 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, randomflag)
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.
If randomflag is set to true, the function will just return the facedir of any
random wall it finds adjacent to the target position. Defaults to false if
not specified.
=====
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.
=====
biome_lib:generate_tree(pos, treemodel)
biome_lib: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 biome_lib's tree-growing functions in general,
perhaps to execute something extra whenever a tree is spawned.
biome_lib: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.
biome_lib: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
To slow down the playback of the queue (e.g. for really slow machines where
the 0.2 second max limiter isn't enough), set:
biome_lib_queue_run_ratio = <some value 1 to 100>
Default is 100 (basically percent of maximum runtime)
======================
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:
biome_lib.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 roughly +0.25 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)

600
mods/biome_lib/LICENSE Normal file
View File

@ -0,0 +1,600 @@
License for code: LGPL 3.0
License for media and all other assets: CC-by-SA 4.0
###############################################################################
GNU LESSER GENERAL PUBLIC LICENSE
Version 3, 29 June 2007
Copyright (C) 2007 Free Software Foundation, Inc. <https://fsf.org/>
Everyone is permitted to copy and distribute verbatim copies
of this license document, but changing it is not allowed.
This version of the GNU Lesser General Public License incorporates
the terms and conditions of version 3 of the GNU General Public
License, supplemented by the additional permissions listed below.
0. Additional Definitions.
As used herein, "this License" refers to version 3 of the GNU Lesser
General Public License, and the "GNU GPL" refers to version 3 of the GNU
General Public License.
"The Library" refers to a covered work governed by this License,
other than an Application or a Combined Work as defined below.
An "Application" is any work that makes use of an interface provided
by the Library, but which is not otherwise based on the Library.
Defining a subclass of a class defined by the Library is deemed a mode
of using an interface provided by the Library.
A "Combined Work" is a work produced by combining or linking an
Application with the Library. The particular version of the Library
with which the Combined Work was made is also called the "Linked
Version".
The "Minimal Corresponding Source" for a Combined Work means the
Corresponding Source for the Combined Work, excluding any source code
for portions of the Combined Work that, considered in isolation, are
based on the Application, and not on the Linked Version.
The "Corresponding Application Code" for a Combined Work means the
object code and/or source code for the Application, including any data
and utility programs needed for reproducing the Combined Work from the
Application, but excluding the System Libraries of the Combined Work.
1. Exception to Section 3 of the GNU GPL.
You may convey a covered work under sections 3 and 4 of this License
without being bound by section 3 of the GNU GPL.
2. Conveying Modified Versions.
If you modify a copy of the Library, and, in your modifications, a
facility refers to a function or data to be supplied by an Application
that uses the facility (other than as an argument passed when the
facility is invoked), then you may convey a copy of the modified
version:
a) under this License, provided that you make a good faith effort to
ensure that, in the event an Application does not supply the
function or data, the facility still operates, and performs
whatever part of its purpose remains meaningful, or
b) under the GNU GPL, with none of the additional permissions of
this License applicable to that copy.
3. Object Code Incorporating Material from Library Header Files.
The object code form of an Application may incorporate material from
a header file that is part of the Library. You may convey such object
code under terms of your choice, provided that, if the incorporated
material is not limited to numerical parameters, data structure
layouts and accessors, or small macros, inline functions and templates
(ten or fewer lines in length), you do both of the following:
a) Give prominent notice with each copy of the object code that the
Library is used in it and that the Library and its use are
covered by this License.
b) Accompany the object code with a copy of the GNU GPL and this license
document.
4. Combined Works.
You may convey a Combined Work under terms of your choice that,
taken together, effectively do not restrict modification of the
portions of the Library contained in the Combined Work and reverse
engineering for debugging such modifications, if you also do each of
the following:
a) Give prominent notice with each copy of the Combined Work that
the Library is used in it and that the Library and its use are
covered by this License.
b) Accompany the Combined Work with a copy of the GNU GPL and this license
document.
c) For a Combined Work that displays copyright notices during
execution, include the copyright notice for the Library among
these notices, as well as a reference directing the user to the
copies of the GNU GPL and this license document.
d) Do one of the following:
0) Convey the Minimal Corresponding Source under the terms of this
License, and the Corresponding Application Code in a form
suitable for, and under terms that permit, the user to
recombine or relink the Application with a modified version of
the Linked Version to produce a modified Combined Work, in the
manner specified by section 6 of the GNU GPL for conveying
Corresponding Source.
1) Use a suitable shared library mechanism for linking with the
Library. A suitable mechanism is one that (a) uses at run time
a copy of the Library already present on the user's computer
system, and (b) will operate properly with a modified version
of the Library that is interface-compatible with the Linked
Version.
e) Provide Installation Information, but only if you would otherwise
be required to provide such information under section 6 of the
GNU GPL, and only to the extent that such information is
necessary to install and execute a modified version of the
Combined Work produced by recombining or relinking the
Application with a modified version of the Linked Version. (If
you use option 4d0, the Installation Information must accompany
the Minimal Corresponding Source and Corresponding Application
Code. If you use option 4d1, you must provide the Installation
Information in the manner specified by section 6 of the GNU GPL
for conveying Corresponding Source.)
5. Combined Libraries.
You may place library facilities that are a work based on the
Library side by side in a single library together with other library
facilities that are not Applications and are not covered by this
License, and convey such a combined library under terms of your
choice, if you do both of the following:
a) Accompany the combined library with a copy of the same work based
on the Library, uncombined with any other library facilities,
conveyed under the terms of this License.
b) Give prominent notice with the combined library that part of it
is a work based on the Library, and explaining where to find the
accompanying uncombined form of the same work.
6. Revised Versions of the GNU Lesser General Public License.
The Free Software Foundation may publish revised and/or new versions
of the GNU Lesser General Public License from time to time. Such new
versions will be similar in spirit to the present version, but may
differ in detail to address new problems or concerns.
Each version is given a distinguishing version number. If the
Library as you received it specifies that a certain numbered version
of the GNU Lesser General Public License "or any later version"
applies to it, you have the option of following the terms and
conditions either of that published version or of any later version
published by the Free Software Foundation. If the Library as you
received it does not specify a version number of the GNU Lesser
General Public License, you may choose any version of the GNU Lesser
General Public License ever published by the Free Software Foundation.
If the Library as you received it specifies that a proxy can decide
whether future versions of the GNU Lesser General Public License shall
apply, that proxy's public statement of acceptance of any version is
permanent authorization for you to choose that version for the
Library.
###############################################################################
Attribution-ShareAlike 4.0 International
=======================================================================
Creative Commons Corporation ("Creative Commons") is not a law firm and
does not provide legal services or legal advice. Distribution of
Creative Commons public licenses does not create a lawyer-client or
other relationship. Creative Commons makes its licenses and related
information available on an "as-is" basis. Creative Commons gives no
warranties regarding its licenses, any material licensed under their
terms and conditions, or any related information. Creative Commons
disclaims all liability for damages resulting from their use to the
fullest extent possible.
Using Creative Commons Public Licenses
Creative Commons public licenses provide a standard set of terms and
conditions that creators and other rights holders may use to share
original works of authorship and other material subject to copyright
and certain other rights specified in the public license below. The
following considerations are for informational purposes only, are not
exhaustive, and do not form part of our licenses.
Considerations for licensors: Our public licenses are
intended for use by those authorized to give the public
permission to use material in ways otherwise restricted by
copyright and certain other rights. Our licenses are
irrevocable. Licensors should read and understand the terms
and conditions of the license they choose before applying it.
Licensors should also secure all rights necessary before
applying our licenses so that the public can reuse the
material as expected. Licensors should clearly mark any
material not subject to the license. This includes other CC-
licensed material, or material used under an exception or
limitation to copyright. More considerations for licensors:
wiki.creativecommons.org/Considerations_for_licensors
Considerations for the public: By using one of our public
licenses, a licensor grants the public permission to use the
licensed material under specified terms and conditions. If
the licensor's permission is not necessary for any reason--for
example, because of any applicable exception or limitation to
copyright--then that use is not regulated by the license. Our
licenses grant only permissions under copyright and certain
other rights that a licensor has authority to grant. Use of
the licensed material may still be restricted for other
reasons, including because others have copyright or other
rights in the material. A licensor may make special requests,
such as asking that all changes be marked or described.
Although not required by our licenses, you are encouraged to
respect those requests where reasonable. More considerations
for the public:
wiki.creativecommons.org/Considerations_for_licensees
=======================================================================
Creative Commons Attribution-ShareAlike 4.0 International Public
License
By exercising the Licensed Rights (defined below), You accept and agree
to be bound by the terms and conditions of this Creative Commons
Attribution-ShareAlike 4.0 International Public License ("Public
License"). To the extent this Public License may be interpreted as a
contract, You are granted the Licensed Rights in consideration of Your
acceptance of these terms and conditions, and the Licensor grants You
such rights in consideration of benefits the Licensor receives from
making the Licensed Material available under these terms and
conditions.
Section 1 -- Definitions.
a. Adapted Material means material subject to Copyright and Similar
Rights that is derived from or based upon the Licensed Material
and in which the Licensed Material is translated, altered,
arranged, transformed, or otherwise modified in a manner requiring
permission under the Copyright and Similar Rights held by the
Licensor. For purposes of this Public License, where the Licensed
Material is a musical work, performance, or sound recording,
Adapted Material is always produced where the Licensed Material is
synched in timed relation with a moving image.
b. Adapter's License means the license You apply to Your Copyright
and Similar Rights in Your contributions to Adapted Material in
accordance with the terms and conditions of this Public License.
c. BY-SA Compatible License means a license listed at
creativecommons.org/compatiblelicenses, approved by Creative
Commons as essentially the equivalent of this Public License.
d. Copyright and Similar Rights means copyright and/or similar rights
closely related to copyright including, without limitation,
performance, broadcast, sound recording, and Sui Generis Database
Rights, without regard to how the rights are labeled or
categorized. For purposes of this Public License, the rights
specified in Section 2(b)(1)-(2) are not Copyright and Similar
Rights.
e. Effective Technological Measures means those measures that, in the
absence of proper authority, may not be circumvented under laws
fulfilling obligations under Article 11 of the WIPO Copyright
Treaty adopted on December 20, 1996, and/or similar international
agreements.
f. Exceptions and Limitations means fair use, fair dealing, and/or
any other exception or limitation to Copyright and Similar Rights
that applies to Your use of the Licensed Material.
g. License Elements means the license attributes listed in the name
of a Creative Commons Public License. The License Elements of this
Public License are Attribution and ShareAlike.
h. Licensed Material means the artistic or literary work, database,
or other material to which the Licensor applied this Public
License.
i. Licensed Rights means the rights granted to You subject to the
terms and conditions of this Public License, which are limited to
all Copyright and Similar Rights that apply to Your use of the
Licensed Material and that the Licensor has authority to license.
j. Licensor means the individual(s) or entity(ies) granting rights
under this Public License.
k. Share means to provide material to the public by any means or
process that requires permission under the Licensed Rights, such
as reproduction, public display, public performance, distribution,
dissemination, communication, or importation, and to make material
available to the public including in ways that members of the
public may access the material from a place and at a time
individually chosen by them.
l. Sui Generis Database Rights means rights other than copyright
resulting from Directive 96/9/EC of the European Parliament and of
the Council of 11 March 1996 on the legal protection of databases,
as amended and/or succeeded, as well as other essentially
equivalent rights anywhere in the world.
m. You means the individual or entity exercising the Licensed Rights
under this Public License. Your has a corresponding meaning.
Section 2 -- Scope.
a. License grant.
1. Subject to the terms and conditions of this Public License,
the Licensor hereby grants You a worldwide, royalty-free,
non-sublicensable, non-exclusive, irrevocable license to
exercise the Licensed Rights in the Licensed Material to:
a. reproduce and Share the Licensed Material, in whole or
in part; and
b. produce, reproduce, and Share Adapted Material.
2. Exceptions and Limitations. For the avoidance of doubt, where
Exceptions and Limitations apply to Your use, this Public
License does not apply, and You do not need to comply with
its terms and conditions.
3. Term. The term of this Public License is specified in Section
6(a).
4. Media and formats; technical modifications allowed. The
Licensor authorizes You to exercise the Licensed Rights in
all media and formats whether now known or hereafter created,
and to make technical modifications necessary to do so. The
Licensor waives and/or agrees not to assert any right or
authority to forbid You from making technical modifications
necessary to exercise the Licensed Rights, including
technical modifications necessary to circumvent Effective
Technological Measures. For purposes of this Public License,
simply making modifications authorized by this Section 2(a)
(4) never produces Adapted Material.
5. Downstream recipients.
a. Offer from the Licensor -- Licensed Material. Every
recipient of the Licensed Material automatically
receives an offer from the Licensor to exercise the
Licensed Rights under the terms and conditions of this
Public License.
b. Additional offer from the Licensor -- Adapted Material.
Every recipient of Adapted Material from You
automatically receives an offer from the Licensor to
exercise the Licensed Rights in the Adapted Material
under the conditions of the Adapter's License You apply.
c. No downstream restrictions. You may not offer or impose
any additional or different terms or conditions on, or
apply any Effective Technological Measures to, the
Licensed Material if doing so restricts exercise of the
Licensed Rights by any recipient of the Licensed
Material.
6. No endorsement. Nothing in this Public License constitutes or
may be construed as permission to assert or imply that You
are, or that Your use of the Licensed Material is, connected
with, or sponsored, endorsed, or granted official status by,
the Licensor or others designated to receive attribution as
provided in Section 3(a)(1)(A)(i).
b. Other rights.
1. Moral rights, such as the right of integrity, are not
licensed under this Public License, nor are publicity,
privacy, and/or other similar personality rights; however, to
the extent possible, the Licensor waives and/or agrees not to
assert any such rights held by the Licensor to the limited
extent necessary to allow You to exercise the Licensed
Rights, but not otherwise.
2. Patent and trademark rights are not licensed under this
Public License.
3. To the extent possible, the Licensor waives any right to
collect royalties from You for the exercise of the Licensed
Rights, whether directly or through a collecting society
under any voluntary or waivable statutory or compulsory
licensing scheme. In all other cases the Licensor expressly
reserves any right to collect such royalties.
Section 3 -- License Conditions.
Your exercise of the Licensed Rights is expressly made subject to the
following conditions.
a. Attribution.
1. If You Share the Licensed Material (including in modified
form), You must:
a. retain the following if it is supplied by the Licensor
with the Licensed Material:
i. identification of the creator(s) of the Licensed
Material and any others designated to receive
attribution, in any reasonable manner requested by
the Licensor (including by pseudonym if
designated);
ii. a copyright notice;
iii. a notice that refers to this Public License;
iv. a notice that refers to the disclaimer of
warranties;
v. a URI or hyperlink to the Licensed Material to the
extent reasonably practicable;
b. indicate if You modified the Licensed Material and
retain an indication of any previous modifications; and
c. indicate the Licensed Material is licensed under this
Public License, and include the text of, or the URI or
hyperlink to, this Public License.
2. You may satisfy the conditions in Section 3(a)(1) in any
reasonable manner based on the medium, means, and context in
which You Share the Licensed Material. For example, it may be
reasonable to satisfy the conditions by providing a URI or
hyperlink to a resource that includes the required
information.
3. If requested by the Licensor, You must remove any of the
information required by Section 3(a)(1)(A) to the extent
reasonably practicable.
b. ShareAlike.
In addition to the conditions in Section 3(a), if You Share
Adapted Material You produce, the following conditions also apply.
1. The Adapter's License You apply must be a Creative Commons
license with the same License Elements, this version or
later, or a BY-SA Compatible License.
2. You must include the text of, or the URI or hyperlink to, the
Adapter's License You apply. You may satisfy this condition
in any reasonable manner based on the medium, means, and
context in which You Share Adapted Material.
3. You may not offer or impose any additional or different terms
or conditions on, or apply any Effective Technological
Measures to, Adapted Material that restrict exercise of the
rights granted under the Adapter's License You apply.
Section 4 -- Sui Generis Database Rights.
Where the Licensed Rights include Sui Generis Database Rights that
apply to Your use of the Licensed Material:
a. for the avoidance of doubt, Section 2(a)(1) grants You the right
to extract, reuse, reproduce, and Share all or a substantial
portion of the contents of the database;
b. if You include all or a substantial portion of the database
contents in a database in which You have Sui Generis Database
Rights, then the database in which You have Sui Generis Database
Rights (but not its individual contents) is Adapted Material,
including for purposes of Section 3(b); and
c. You must comply with the conditions in Section 3(a) if You Share
all or a substantial portion of the contents of the database.
For the avoidance of doubt, this Section 4 supplements and does not
replace Your obligations under this Public License where the Licensed
Rights include other Copyright and Similar Rights.
Section 5 -- Disclaimer of Warranties and Limitation of Liability.
a. UNLESS OTHERWISE SEPARATELY UNDERTAKEN BY THE LICENSOR, TO THE
EXTENT POSSIBLE, THE LICENSOR OFFERS THE LICENSED MATERIAL AS-IS
AND AS-AVAILABLE, AND MAKES NO REPRESENTATIONS OR WARRANTIES OF
ANY KIND CONCERNING THE LICENSED MATERIAL, WHETHER EXPRESS,
IMPLIED, STATUTORY, OR OTHER. THIS INCLUDES, WITHOUT LIMITATION,
WARRANTIES OF TITLE, MERCHANTABILITY, FITNESS FOR A PARTICULAR
PURPOSE, NON-INFRINGEMENT, ABSENCE OF LATENT OR OTHER DEFECTS,
ACCURACY, OR THE PRESENCE OR ABSENCE OF ERRORS, WHETHER OR NOT
KNOWN OR DISCOVERABLE. WHERE DISCLAIMERS OF WARRANTIES ARE NOT
ALLOWED IN FULL OR IN PART, THIS DISCLAIMER MAY NOT APPLY TO YOU.
b. TO THE EXTENT POSSIBLE, IN NO EVENT WILL THE LICENSOR BE LIABLE
TO YOU ON ANY LEGAL THEORY (INCLUDING, WITHOUT LIMITATION,
NEGLIGENCE) OR OTHERWISE FOR ANY DIRECT, SPECIAL, INDIRECT,
INCIDENTAL, CONSEQUENTIAL, PUNITIVE, EXEMPLARY, OR OTHER LOSSES,
COSTS, EXPENSES, OR DAMAGES ARISING OUT OF THIS PUBLIC LICENSE OR
USE OF THE LICENSED MATERIAL, EVEN IF THE LICENSOR HAS BEEN
ADVISED OF THE POSSIBILITY OF SUCH LOSSES, COSTS, EXPENSES, OR
DAMAGES. WHERE A LIMITATION OF LIABILITY IS NOT ALLOWED IN FULL OR
IN PART, THIS LIMITATION MAY NOT APPLY TO YOU.
c. The disclaimer of warranties and limitation of liability provided
above shall be interpreted in a manner that, to the extent
possible, most closely approximates an absolute disclaimer and
waiver of all liability.
Section 6 -- Term and Termination.
a. This Public License applies for the term of the Copyright and
Similar Rights licensed here. However, if You fail to comply with
this Public License, then Your rights under this Public License
terminate automatically.
b. Where Your right to use the Licensed Material has terminated under
Section 6(a), it reinstates:
1. automatically as of the date the violation is cured, provided
it is cured within 30 days of Your discovery of the
violation; or
2. upon express reinstatement by the Licensor.
For the avoidance of doubt, this Section 6(b) does not affect any
right the Licensor may have to seek remedies for Your violations
of this Public License.
c. For the avoidance of doubt, the Licensor may also offer the
Licensed Material under separate terms or conditions or stop
distributing the Licensed Material at any time; however, doing so
will not terminate this Public License.
d. Sections 1, 5, 6, 7, and 8 survive termination of this Public
License.
Section 7 -- Other Terms and Conditions.
a. The Licensor shall not be bound by any additional or different
terms or conditions communicated by You unless expressly agreed.
b. Any arrangements, understandings, or agreements regarding the
Licensed Material not stated herein are separate from and
independent of the terms and conditions of this Public License.
Section 8 -- Interpretation.
a. For the avoidance of doubt, this Public License does not, and
shall not be interpreted to, reduce, limit, restrict, or impose
conditions on any use of the Licensed Material that could lawfully
be made without permission under this Public License.
b. To the extent possible, if any provision of this Public License is
deemed unenforceable, it shall be automatically reformed to the
minimum extent necessary to make it enforceable. If the provision
cannot be reformed, it shall be severed from this Public License
without affecting the enforceability of the remaining terms and
conditions.
c. No term or condition of this Public License will be waived and no
failure to comply consented to unless expressly agreed to by the
Licensor.
d. Nothing in this Public License constitutes or may be interpreted
as a limitation upon, or waiver of, any privileges and immunities
that apply to the Licensor or You, including from the legal
processes of any jurisdiction or authority.
=======================================================================
Creative Commons is not a party to its public
licenses. Notwithstanding, Creative Commons may elect to apply one of
its public licenses to material it publishes and in those instances
will be considered the “Licensor.” The text of the Creative Commons
public licenses is dedicated to the public domain under the CC0 Public
Domain Dedication. Except for the limited purpose of indicating that
material is shared under a Creative Commons public license or as
otherwise permitted by the Creative Commons policies published at
creativecommons.org/policies, Creative Commons does not authorize the
use of the trademark "Creative Commons" or any other trademark or logo
of Creative Commons without its prior written consent including,
without limitation, in connection with any unauthorized modifications
to any of its public licenses or any other arrangements,
understandings, or agreements concerning use of licensed material. For
the avoidance of doubt, this paragraph does not form part of the
public licenses.
Creative Commons may be contacted at creativecommons.org.

28
mods/biome_lib/README.md Normal file
View File

@ -0,0 +1,28 @@
# Biome Lib
This library's purpose is to allow other mods to add growing things to the map in a straightforward, simple manner. It contains all the core functions needed by mods and modpacks such as More Trees, Tiny Trees, Plantlife, and others.
Spawning of plants is optionally sensitive to the amount of available light, elevation, nearness to other nodes, plant-to-plant density, water depth, and a whole host of controls.
All objects spawned or generated using this mod use Perlin noise to stay within simple biomes, rather than just letting everything just spread around the map randomly.
This library also features a basic temperature map, which should blend in nicely with SPlizard's Snow Biomes mod (the same Perlin settings are used, with the assumption that the edge of a snow biome is 0° Centigrade).
Both mapgen-based spawning and ABM-based spawning is supported. Growing code is strictly ABM-based. L-system trees can be spawned at mapgen time via the engine's spawn_tree() function and are quite fast.
It is primarily intended for mapgen v6, but it should work fine when used with mapgen v7.
**Dependencies**: default from minetest_game
**Recommends**: [Plantlife Modpack](https://github.com/minetest-mods/plantlife_modpack),
[More Trees](https://github.com/minetest-mods/moretrees)
**API**: This mod supplies a small number of very powerful functions. They are, briefly:
* biome_lib:register_generate_plant()
* biome_lib:spawn_on_surfaces()
* biome_lib:grow_plants()
* biome_lib:find_valid_wall()
* biome_lib:is_node_loaded()
For a complete description of these functions as well as several of the internal variables within the mod, [read the API.txt document](https://raw.githubusercontent.com/minetest-mods/biome_lib/master/API.txt) included in this package.

View File

@ -0,0 +1,3 @@
default
intllib?

View File

@ -0,0 +1 @@
The biome spawning and management library for Plantlife, Moretrees, Tiny Trees, and other mods that originally depended on plants_lib from the plantlife modpack.

90
mods/biome_lib/growth.lua Normal file
View File

@ -0,0 +1,90 @@
local time_scale = ...
-- The growing ABM
function biome_lib.check_surface(name, nodes)
if not nodes then return true end
if type(nodes) == "string" then return nodes == name end
if nodes.set and nodes[name] then
return true
else
for _, n in ipairs(nodes) do
if name == n then return true end
end
end
return false
end
function biome_lib:grow_plants(opts)
local options = opts
options.height_limit = options.height_limit or 5
options.ground_nodes = options.ground_nodes or { "default:dirt_with_grass" }
options.grow_nodes = options.grow_nodes or { "default:dirt_with_grass" }
options.seed_diff = options.seed_diff or 0
local n
if type(options.grow_plant) == "table" then
n = "multi: "..options.grow_plant[1]..", ..."
else
n = options.grow_plant
end
options.label = options.label or "biome_lib grow_plants(): "..n
if options.grow_delay*time_scale >= 1 then
options.interval = options.grow_delay*time_scale
else
options.interval = 1
end
minetest.register_abm({
nodenames = { options.grow_plant },
interval = options.interval,
chance = options.grow_chance,
label = options.label,
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 = biome_lib:find_adjacent_wall(p_top, options.verticals_list, options.choose_random_wall)
end
if (n_top.name == "air" or n_top.name == "default:snow")
and (not options.need_wall or (options.need_wall and walldir)) then
if options.grow_vertically and walldir then
if biome_lib:search_downward(pos, options.height_limit, options.ground_nodes) then
minetest.swap_node(p_top, { name = options.grow_plant, param2 = walldir})
end
elseif biome_lib.check_surface(n_bot.name, options.grow_nodes) then
if not options.grow_result and not options.grow_function then
minetest.swap_node(pos, biome_lib.air)
else
biome_lib:replace_object(pos, options.grow_result, options.grow_function, options.facedir, options.seed_diff)
end
end
end
end
})
end
-- spawn_tree() on generate is routed through here so that other mods can hook
-- into it.
function biome_lib:generate_tree(pos, nodes_or_function_or_model)
minetest.spawn_tree(pos, nodes_or_function_or_model)
end
-- and this one's for the call used in the growing code
function biome_lib:grow_tree(pos, nodes_or_function_or_model)
minetest.spawn_tree(pos, nodes_or_function_or_model)
end

736
mods/biome_lib/init.lua Normal file
View File

@ -0,0 +1,736 @@
-- Biome library mod by Vanessa Ezekowitz
--
-- 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
biome_lib = {}
biome_lib.air = {name = "air"}
plantslib = setmetatable({}, { __index=function(t,k) print("Use of deprecated function:", k) return biome_lib[k] end })
biome_lib.blocklist_aircheck = {}
biome_lib.blocklist_no_aircheck = {}
biome_lib.surface_nodes_aircheck = {}
biome_lib.surface_nodes_no_aircheck = {}
biome_lib.surfaceslist_aircheck = {}
biome_lib.surfaceslist_no_aircheck = {}
biome_lib.actioncount_aircheck = {}
biome_lib.actioncount_no_aircheck = {}
biome_lib.actionslist_aircheck = {}
biome_lib.actionslist_no_aircheck = {}
biome_lib.modpath = minetest.get_modpath("biome_lib")
biome_lib.total_no_aircheck_calls = 0
biome_lib.queue_run_ratio = tonumber(minetest.settings:get("biome_lib_queue_run_ratio")) or 100
-- Boilerplate to support localized strings if intllib mod is installed.
local S
if minetest.global_exists("intllib") then
if intllib.make_gettext_pair then
S = intllib.make_gettext_pair()
else
S = intllib.Getter()
end
else
S = function(s) return s end
end
biome_lib.intllib = S
local DEBUG = false --... except if you want to spam the console with debugging info :-)
function biome_lib:dbg(msg)
if DEBUG then
print("[Plantlife] "..msg)
minetest.log("verbose", "[Plantlife] "..msg)
end
end
biome_lib.plantlife_seed_diff = 329 -- needs to be global so other mods can see it
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
--PerlinNoise(seed, octaves, persistence, scale)
biome_lib.perlin_temperature = PerlinNoise(temperature_seeddiff, temperature_octaves, temperature_persistence, temperature_scale)
biome_lib.perlin_humidity = PerlinNoise(humidity_seeddiff, humidity_octaves, humidity_persistence, humidity_scale)
-- Local functions
local function get_biome_data(pos, perlin_fertile)
local fertility = perlin_fertile:get_2d({x=pos.x, y=pos.z})
if type(minetest.get_biome_data) == "function" then
local data = minetest.get_biome_data(pos)
if data then
return fertility, data.heat / 100, data.humidity / 100
end
end
local temperature = biome_lib.perlin_temperature:get2d({x=pos.x, y=pos.z})
local humidity = biome_lib.perlin_humidity:get2d({x=pos.x+150, y=pos.z+50})
return fertility, temperature, humidity
end
function biome_lib:is_node_loaded(node_pos)
local n = minetest.get_node_or_nil(node_pos)
if (not n) or (n.name == "ignore") then
return false
end
return true
end
function biome_lib: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
biome.temp_min = biome.temp_min or 1
biome.temp_max = biome.temp_max or -1
biome.humidity_min = biome.humidity_min or 1
biome.humidity_max = biome.humidity_max or -1
biome.plantlife_limit = biome.plantlife_limit or 0.1
biome.near_nodes_vertical = biome.near_nodes_vertical or 1
-- specific to on-generate
biome.neighbors = biome.neighbors or biome.surface
biome.near_nodes_size = biome.near_nodes_size or 0
biome.near_nodes_count = biome.near_nodes_count or 1
biome.rarity = biome.rarity or 50
biome.max_count = biome.max_count or 5
if biome.check_air ~= false then biome.check_air = true end
-- specific to abm spawner
biome.seed_diff = biome.seed_diff or 0
biome.light_min = biome.light_min or 0
biome.light_max = biome.light_max or 15
biome.depth_max = biome.depth_max or 1
biome.facedir = biome.facedir or 0
end
local function search_table(t, s)
for i = 1, #t do
if t[i] == s then return true end
end
return false
end
-- register the list of surfaces to spawn stuff on, filtering out all duplicates.
-- separate the items by air-checking or non-air-checking map eval methods
function biome_lib:register_generate_plant(biomedef, nodes_or_function_or_model)
-- if calling code passes an undefined node for a surface or
-- as a node to be spawned, don't register an action for it.
if type(nodes_or_function_or_model) == "string"
and string.find(nodes_or_function_or_model, ":")
and not minetest.registered_nodes[nodes_or_function_or_model] then
biome_lib:dbg("Warning: Ignored registration for undefined spawn node: "..dump(nodes_or_function_or_model))
return
end
if type(nodes_or_function_or_model) == "string"
and not string.find(nodes_or_function_or_model, ":") then
biome_lib:dbg("Warning: Registered function call using deprecated string method: "..dump(nodes_or_function_or_model))
end
if biomedef.check_air == false then
biome_lib:dbg("Register no-air-check mapgen hook: "..dump(nodes_or_function_or_model))
biome_lib.actionslist_no_aircheck[#biome_lib.actionslist_no_aircheck + 1] = { biomedef, nodes_or_function_or_model }
local s = biomedef.surface
if type(s) == "string" then
if s and (string.find(s, "^group:") or minetest.registered_nodes[s]) then
if not search_table(biome_lib.surfaceslist_no_aircheck, s) then
biome_lib.surfaceslist_no_aircheck[#biome_lib.surfaceslist_no_aircheck + 1] = s
end
else
biome_lib:dbg("Warning: Ignored no-air-check registration for undefined surface node: "..dump(s))
end
else
for i = 1, #biomedef.surface do
local s = biomedef.surface[i]
if s and (string.find(s, "^group:") or minetest.registered_nodes[s]) then
if not search_table(biome_lib.surfaceslist_no_aircheck, s) then
biome_lib.surfaceslist_no_aircheck[#biome_lib.surfaceslist_no_aircheck + 1] = s
end
else
biome_lib:dbg("Warning: Ignored no-air-check registration for undefined surface node: "..dump(s))
end
end
end
else
biome_lib:dbg("Register with-air-checking mapgen hook: "..dump(nodes_or_function_or_model))
biome_lib.actionslist_aircheck[#biome_lib.actionslist_aircheck + 1] = { biomedef, nodes_or_function_or_model }
local s = biomedef.surface
if type(s) == "string" then
if s and (string.find(s, "^group:") or minetest.registered_nodes[s]) then
if not search_table(biome_lib.surfaceslist_aircheck, s) then
biome_lib.surfaceslist_aircheck[#biome_lib.surfaceslist_aircheck + 1] = s
end
else
biome_lib:dbg("Warning: Ignored with-air-checking registration for undefined surface node: "..dump(s))
end
else
for i = 1, #biomedef.surface do
local s = biomedef.surface[i]
if s and (string.find(s, "^group:") or minetest.registered_nodes[s]) then
if not search_table(biome_lib.surfaceslist_aircheck, s) then
biome_lib.surfaceslist_aircheck[#biome_lib.surfaceslist_aircheck + 1] = s
end
else
biome_lib:dbg("Warning: Ignored with-air-checking registration for undefined surface node: "..dump(s))
end
end
end
end
end
-- Function to check whether a position matches the given biome definition
-- Returns true when the surface can be populated
local function populate_single_surface(biome, pos, perlin_fertile_area, checkair)
local p_top = { x = pos.x, y = pos.y + 1, z = pos.z }
if math.random(1, 100) <= biome.rarity then
return
end
local fertility, temperature, humidity = get_biome_data(pos, perlin_fertile_area)
local pos_biome_ok = pos.y >= biome.min_elevation and pos.y <= biome.max_elevation
and fertility > biome.plantlife_limit
and temperature <= biome.temp_min and temperature >= biome.temp_max
and humidity <= biome.humidity_min and humidity >= biome.humidity_max
if not pos_biome_ok then
return -- Y position mismatch, outside of biome
end
local biome_surfaces_string = dump(biome.surface)
local surface_ok = false
if not biome.depth then
local dest_node = minetest.get_node(pos)
if string.find(biome_surfaces_string, dest_node.name) then
surface_ok = true
else
if string.find(biome_surfaces_string, "group:") then
for j = 1, #biome.surface do
if string.find(biome.surface[j], "^group:")
and minetest.get_item_group(dest_node.name, biome.surface[j]) then
surface_ok = true
break
end
end
end
end
elseif not string.find(biome_surfaces_string,
minetest.get_node({ x = pos.x, y = pos.y-biome.depth-1, z = pos.z }).name) then
surface_ok = true
end
if not surface_ok then
return -- Surface does not match the given node group/name
end
if checkair and minetest.get_node(p_top).name ~= "air" then
return
end
if biome.below_nodes and
not string.find(dump(biome.below_nodes),
minetest.get_node({x=pos.x, y=pos.y-1, z=pos.z}).name
) then
return -- Node below does not match
end
if biome.ncount and
#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 then
return -- Not enough similar biome nodes around
end
if biome.near_nodes and
#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 then
return -- Long distance neighbours do not match
end
-- Position fits into given biome
return true
end
function biome_lib:populate_surfaces(biome, nodes_or_function_or_model, snodes, checkair)
biome_lib:set_defaults(biome)
-- filter stage 1 - find nodes from the supplied surfaces that are within the current biome.
local in_biome_nodes = {}
local perlin_fertile_area = minetest.get_perlin(biome.seed_diff, perlin_octaves, perlin_persistence, perlin_scale)
for i = 1, #snodes do
local pos = vector.new(snodes[i])
if populate_single_surface(biome, pos, perlin_fertile_area, checkair) then
in_biome_nodes[#in_biome_nodes + 1] = pos
end
end
-- filter stage 2 - find places within that biome area to place the plants.
local num_in_biome_nodes = #in_biome_nodes
if num_in_biome_nodes == 0 then
return
end
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.swap_node(p_top, biome_lib.air)
minetest.swap_node({x=p_top.x, y=p_top.y+1, z=p_top.z}, biome_lib.air)
end
if biome.delete_above_surround then
minetest.swap_node({x=p_top.x-1, y=p_top.y, z=p_top.z}, biome_lib.air)
minetest.swap_node({x=p_top.x+1, y=p_top.y, z=p_top.z}, biome_lib.air)
minetest.swap_node({x=p_top.x, y=p_top.y, z=p_top.z-1}, biome_lib.air)
minetest.swap_node({x=p_top.x, y=p_top.y, z=p_top.z+1}, biome_lib.air)
minetest.swap_node({x=p_top.x-1, y=p_top.y+1, z=p_top.z}, biome_lib.air)
minetest.swap_node({x=p_top.x+1, y=p_top.y+1, z=p_top.z}, biome_lib.air)
minetest.swap_node({x=p_top.x, y=p_top.y+1, z=p_top.z-1}, biome_lib.air)
minetest.swap_node({x=p_top.x, y=p_top.y+1, z=p_top.z+1}, biome_lib.air)
end
if biome.spawn_replace_node then
minetest.swap_node(pos, biome_lib.air)
end
local objtype = type(nodes_or_function_or_model)
if objtype == "table" then
if nodes_or_function_or_model.axiom then
biome_lib:generate_tree(p_top, nodes_or_function_or_model)
spawned = true
else
local fdir = nil
if biome.random_facedir then
fdir = math.random(biome.random_facedir[1], biome.random_facedir[2])
end
minetest.swap_node(p_top, { name = nodes_or_function_or_model[math.random(#nodes_or_function_or_model)], param2 = fdir })
spawned = true
end
elseif objtype == "string" and
minetest.registered_nodes[nodes_or_function_or_model] then
local fdir = nil
if biome.random_facedir then
fdir = math.random(biome.random_facedir[1], biome.random_facedir[2])
end
minetest.swap_node(p_top, { name = nodes_or_function_or_model, param2 = fdir })
spawned = true
elseif objtype == "function" then
nodes_or_function_or_model(pos)
spawned = true
elseif objtype == "string" and pcall(loadstring(("return %s(...)"):
format(nodes_or_function_or_model)),pos) then
spawned = true
else
biome_lib:dbg("Warning: Ignored invalid definition for object "..dump(nodes_or_function_or_model).." that was pointed at {"..dump(pos).."}")
end
else
tries = tries + 1
end
end
end
end
-- Primary mapgen spawner, for mods that can work with air checking enabled on
-- a surface during the initial map read stage.
function biome_lib:generate_block_with_air_checking()
if #biome_lib.blocklist_aircheck == 0 then
return
end
local minp = biome_lib.blocklist_aircheck[1][1]
local maxp = biome_lib.blocklist_aircheck[1][2]
-- use the block hash as a unique key into the surface nodes
-- tables, so that we can write the tables thread-safely.
local blockhash = minetest.hash_node_position(minp)
if not biome_lib.surface_nodes_aircheck.blockhash then
if type(minetest.find_nodes_in_area_under_air) == "function" then -- use newer API call
biome_lib.surface_nodes_aircheck.blockhash =
minetest.find_nodes_in_area_under_air(minp, maxp, biome_lib.surfaceslist_aircheck)
else
local search_area = minetest.find_nodes_in_area(minp, maxp, biome_lib.surfaceslist_aircheck)
-- search the generated block for air-bounded surfaces the slow way.
biome_lib.surface_nodes_aircheck.blockhash = {}
for i = 1, #search_area do
local pos = search_area[i]
local p_top = { x=pos.x, y=pos.y+1, z=pos.z }
if minetest.get_node(p_top).name == "air" then
biome_lib.surface_nodes_aircheck.blockhash[#biome_lib.surface_nodes_aircheck.blockhash + 1] = pos
end
end
end
biome_lib.actioncount_aircheck.blockhash = 1
else
if biome_lib.actioncount_aircheck.blockhash <= #biome_lib.actionslist_aircheck then
-- [1] is biome, [2] is node/function/model
biome_lib:populate_surfaces(
biome_lib.actionslist_aircheck[biome_lib.actioncount_aircheck.blockhash][1],
biome_lib.actionslist_aircheck[biome_lib.actioncount_aircheck.blockhash][2],
biome_lib.surface_nodes_aircheck.blockhash, true)
biome_lib.actioncount_aircheck.blockhash = biome_lib.actioncount_aircheck.blockhash + 1
else
if biome_lib.surface_nodes_aircheck.blockhash then
table.remove(biome_lib.blocklist_aircheck, 1)
biome_lib.surface_nodes_aircheck.blockhash = nil
end
end
end
end
-- Secondary mapgen spawner, for mods that require disabling of
-- checking for air during the initial map read stage.
function biome_lib:generate_block_no_aircheck()
if #biome_lib.blocklist_no_aircheck == 0 then
return
end
local minp = biome_lib.blocklist_no_aircheck[1][1]
local maxp = biome_lib.blocklist_no_aircheck[1][2]
local blockhash = minetest.hash_node_position(minp)
if not biome_lib.surface_nodes_no_aircheck.blockhash then
-- directly read the block to be searched into the chunk cache
biome_lib.surface_nodes_no_aircheck.blockhash =
minetest.find_nodes_in_area(minp, maxp, biome_lib.surfaceslist_no_aircheck)
biome_lib.actioncount_no_aircheck.blockhash = 1
else
if biome_lib.actioncount_no_aircheck.blockhash <= #biome_lib.actionslist_no_aircheck then
biome_lib:populate_surfaces(
biome_lib.actionslist_no_aircheck[biome_lib.actioncount_no_aircheck.blockhash][1],
biome_lib.actionslist_no_aircheck[biome_lib.actioncount_no_aircheck.blockhash][2],
biome_lib.surface_nodes_no_aircheck.blockhash, false)
biome_lib.actioncount_no_aircheck.blockhash = biome_lib.actioncount_no_aircheck.blockhash + 1
else
if biome_lib.surface_nodes_no_aircheck.blockhash then
table.remove(biome_lib.blocklist_no_aircheck, 1)
biome_lib.surface_nodes_no_aircheck.blockhash = nil
end
end
end
end
-- "Play" them back, populating them with new stuff in the process
local step_duration = tonumber(minetest.settings:get("dedicated_server_step"))
minetest.register_globalstep(function(dtime)
if dtime >= step_duration + 0.1 -- don't attempt to populate if lag is already too high
or math.random(100) > biome_lib.queue_run_ratio
or (#biome_lib.blocklist_aircheck == 0 and #biome_lib.blocklist_no_aircheck == 0) then
return
end
biome_lib.globalstep_start_time = minetest.get_us_time()
biome_lib.globalstep_runtime = 0
while (#biome_lib.blocklist_aircheck > 0 or #biome_lib.blocklist_no_aircheck > 0)
and biome_lib.globalstep_runtime < 200000 do -- 0.2 seconds, in uS.
if #biome_lib.blocklist_aircheck > 0 then
biome_lib:generate_block_with_air_checking()
end
if #biome_lib.blocklist_no_aircheck > 0 then
biome_lib:generate_block_no_aircheck()
end
biome_lib.globalstep_runtime = minetest.get_us_time() - biome_lib.globalstep_start_time
end
end)
-- Play out the entire log all at once on shutdown
-- to prevent unpopulated map areas
minetest.register_on_shutdown(function()
if #biome_lib.blocklist_aircheck == 0 then
return
end
print("[biome_lib] Stand by, playing out the rest of the aircheck mapblock log")
print("(there are "..#biome_lib.blocklist_aircheck.." entries)...")
while #biome_lib.blocklist_aircheck > 0 do
biome_lib:generate_block_with_air_checking(0.1)
end
end)
minetest.register_on_shutdown(function()
if #biome_lib.blocklist_aircheck == 0 then
return
end
print("[biome_lib] Stand by, playing out the rest of the no-aircheck mapblock log")
print("(there are "..#biome_lib.blocklist_no_aircheck.." entries)...")
while #biome_lib.blocklist_no_aircheck > 0 do
biome_lib:generate_block_no_aircheck(0.1)
end
end)
-- The spawning ABM
function biome_lib: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
biome_lib:set_defaults(biome)
biome.spawn_plants_count = #(biome.spawn_plants)
local n
if type(biome.spawn_plants) == "table" then
n = "random: "..biome.spawn_plants[1]..", ..."
else
n = biome.spawn_plants
end
biome.label = biome.label or "biome_lib spawn_on_surfaces(): "..n
minetest.register_abm({
nodenames = biome.spawn_surfaces,
interval = biome.interval,
chance = biome.spawn_chance,
neighbors = biome.neighbors,
label = biome.label,
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 perlin_fertile_area = minetest.get_perlin(biome.seed_diff, perlin_octaves, perlin_persistence, perlin_scale)
local fertility, temperature, humidity = get_biome_data(pos, perlin_fertile_area)
local pos_biome_ok = pos.y >= biome.min_elevation and pos.y <= biome.max_elevation
and fertility > biome.plantlife_limit
and temperature <= biome.temp_min and temperature >= biome.temp_max
and humidity <= biome.humidity_min and humidity >= biome.humidity_max
and biome_lib:is_node_loaded(p_top)
if not pos_biome_ok then
return -- Outside of biome
end
local n_light = minetest.get_node_light(p_top, nil)
if n_light < biome.light_min or n_light > biome.light_max then
return -- Too dark or too bright
end
if 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
return -- Nodes to avoid are nearby
end
if biome.neighbors and biome.ncount and
#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 then
return -- Near neighbour nodes are not present
end
local NEAR_DST = biome.near_nodes_size
if biome.near_nodes and biome.near_nodes_count and biome.near_nodes_size and
#minetest.find_nodes_in_area(
{x=pos.x-NEAR_DST, y=pos.y-biome.near_nodes_vertical, z=pos.z-NEAR_DST},
{x=pos.x+NEAR_DST, y=pos.y+biome.near_nodes_vertical, z=pos.z+NEAR_DST},
biome.near_nodes
) < biome.near_nodes_count then
return -- Far neighbour nodes are not present
end
if (biome.air_count and biome.air_size) and
#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
return -- Not enough air
end
local walldir = biome_lib:find_adjacent_wall(p_top, biome.verticals_list, biome.choose_random_wall)
if biome.alt_wallnode and walldir then
if n_top.name == "air" then
minetest.swap_node(p_top, { name = biome.alt_wallnode, param2 = walldir })
end
return
end
local currentsurface = minetest.get_node(pos).name
if currentsurface == "default:water_source" and
#minetest.find_nodes_in_area(
{x=pos.x, y=pos.y-biome.depth_max-1, z=pos.z},
vector.new(pos),
{"default:dirt", "default:dirt_with_grass", "default:sand"}
) == 0 then
return -- On water but no ground nearby
end
local rnd = math.random(1, biome.spawn_plants_count)
local plant_to_spawn = biome.spawn_plants[rnd]
local fdir = biome.facedir
if biome.random_facedir then
fdir = math.random(biome.random_facedir[1],biome.random_facedir[2])
end
if type(biome.spawn_plants) == "string" then
assert(loadstring(biome.spawn_plants.."(...)"))(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
minetest.swap_node(p_top, { name = plant_to_spawn, param2 = fdir })
end
elseif biome.spawn_replace_node then
minetest.swap_node(pos, { name = plant_to_spawn, param2 = fdir })
elseif biome.spawn_on_side then
local onside = biome_lib:find_open_side(pos)
if onside then
minetest.swap_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
minetest.swap_node({x=pos.x, y=pos.y-1, z=pos.z}, { name = plant_to_spawn, param2 = fdir} )
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 biome_lib:replace_object(pos, replacement, grow_function, walldir, seeddiff)
local growtype = type(grow_function)
if growtype == "table" then
minetest.swap_node(pos, biome_lib.air)
biome_lib:grow_tree(pos, grow_function)
return
elseif growtype == "function" then
local perlin_fertile_area = minetest.get_perlin(seeddiff, perlin_octaves, perlin_persistence, perlin_scale)
local fertility, temperature, _ = get_biome_data(pos, perlin_fertile_area)
grow_function(pos, fertility, temperature, walldir)
return
elseif growtype == "string" then
local perlin_fertile_area = minetest.get_perlin(seeddiff, perlin_octaves, perlin_persistence, perlin_scale)
local fertility, temperature, _ = get_biome_data(pos, perlin_fertile_area)
assert(loadstring(grow_function.."(...)"))(pos, fertility, temperature, walldir)
return
elseif growtype == "nil" then
minetest.swap_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
dofile(biome_lib.modpath .. "/search_functions.lua")
assert(loadfile(biome_lib.modpath .. "/growth.lua"))(time_scale)
-- Check for infinite stacks
if minetest.get_modpath("unified_inventory") or not minetest.settings:get_bool("creative_mode") then
biome_lib.expect_infinite_stacks = false
else
biome_lib.expect_infinite_stacks = true
end
-- read a field from a node's definition
function biome_lib:get_nodedef_field(nodename, fieldname)
if not minetest.registered_nodes[nodename] then
return nil
end
return minetest.registered_nodes[nodename][fieldname]
end
print("[Biome Lib] Loaded")
minetest.after(0, function()
print("[Biome Lib] Registered a total of "..(#biome_lib.surfaceslist_aircheck)+(#biome_lib.surfaceslist_no_aircheck).." surface types to be evaluated, spread")
print("[Biome Lib] across "..#biome_lib.actionslist_aircheck.." actions with air-checking and "..#biome_lib.actionslist_no_aircheck.." actions without.")
end)

View File

@ -0,0 +1,5 @@
# Translation by Xanthin
someone = jemand
Sorry, %s owns that spot. = Entschuldige, %s gehoert diese Stelle.
[Plantlife Library] Loaded = [Plantlife Library] Geladen

View File

@ -0,0 +1,5 @@
# Template
someone = quelqu'un
Sorry, %s owns that spot. = Désolé, %s possède cet endroit.
[Plantlife Library] Loaded = [Librairie Plantlife] Chargée.

View File

@ -0,0 +1,5 @@
# Translation by inpos
someone = кто-то
Sorry, %s owns that spot. = Извините, но %s уже является владельцем этой точки.
[Plantlife Library] Loaded = [Plantlife Library] Загружена

View File

@ -0,0 +1,5 @@
# Template
someone =
Sorry, %s owns that spot. =
[Plantlife Library] Loaded =

View File

@ -0,0 +1,5 @@
# Turkish translation by mahmutelmas06
someone = birisi
Sorry, %s owns that spot. = Üzgünüm, buranın sahibi %s.
[Plantlife Library] Loaded = [Plantlife Library] yüklendi

2
mods/biome_lib/mod.conf Normal file
View File

@ -0,0 +1,2 @@
name = biome_lib
min_minetest_version = 5.2.0

View File

@ -0,0 +1,60 @@
-- 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 biome_lib:find_adjacent_wall(pos, verticals, randomflag)
local verts = dump(verticals)
if randomflag then
local walltab = {}
if string.find(verts, minetest.get_node({ x=pos.x-1, y=pos.y, z=pos.z }).name) then walltab[#walltab + 1] = 3 end
if string.find(verts, minetest.get_node({ x=pos.x+1, y=pos.y, z=pos.z }).name) then walltab[#walltab + 1] = 2 end
if string.find(verts, minetest.get_node({ x=pos.x , y=pos.y, z=pos.z-1 }).name) then walltab[#walltab + 1] = 5 end
if string.find(verts, minetest.get_node({ x=pos.x , y=pos.y, z=pos.z+1 }).name) then walltab[#walltab + 1] = 4 end
if #walltab > 0 then return walltab[math.random(1, #walltab)] end
else
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
if string.find(verts, minetest.get_node({ x=pos.x , y=pos.y, z=pos.z-1 }).name) then return 5 end
if string.find(verts, minetest.get_node({ x=pos.x , y=pos.y, z=pos.z+1 }).name) then return 4 end
end
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 biome_lib: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 biome_lib: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
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 = 3}
end
if minetest.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.get_node({ x=pos.x, y=pos.y, z=pos.z+1 }).name == "air" then
return {newpos = { x=pos.x, y=pos.y, z=pos.z+1 }, facedir = 5}
end
return nil
end
-- "Record" the chunks being generated by the core mapgen
minetest.register_on_generated(function(minp, maxp, blockseed)
biome_lib.blocklist_aircheck[#biome_lib.blocklist_aircheck + 1] = { minp, maxp }
biome_lib.blocklist_no_aircheck[#biome_lib.blocklist_no_aircheck + 1] = { minp, maxp }
end)

View File

@ -0,0 +1,30 @@
std = "lua51+minetest"
unused_args = false
allow_defined_top = true
max_line_length = 999
max_comment_line_length = 999
stds.minetest = {
read_globals = {
"minetest",
"vector",
"VoxelManip",
"VoxelArea",
"PseudoRandom",
"ItemStack",
"default",
table = {
fields = {
"copy",
},
},
"dump",
}
}
read_globals = {
"biome_lib",
"stairsplus",
"stairs",
"doors",
}

620
mods/moretrees/LICENSE Normal file
View File

@ -0,0 +1,620 @@
Minetest mod moretrees
======================
All source code:
© 2013, Vanessa Ezekowitz <vanessaezekowitz@gmail.com>
Date & cocos palm code (date_palm.lua, cocos_palm.lua)
© 2016, Rogier <rogier777@gmail.com>
All date & date palm textures, date-based food, cocos flower & green coconuts,
and all poplar textures:
© 2016, Rogier <rogier777@gmail.com>
- Three of the date palm textures are modifications of existing moretrees textures
- The green coconuts are a modification of the brown coconut
- The date cake batter is a modification of the acorn muffin batter
All other sapling textures (textures/*_sapling.png):
© 2013, Tim Huppertz <mitroman@naturalnet.de>
All other textures:
© 2013, Vanessa Ezekowitz <vanessaezekowitz@gmail.com>
###############################################################################
License for all code: LGPL 3.0
License for all media and all other assets: CC-by-SA 4.0
###############################################################################
GNU LESSER GENERAL PUBLIC LICENSE
Version 3, 29 June 2007
Copyright (C) 2007 Free Software Foundation, Inc. <https://fsf.org/>
Everyone is permitted to copy and distribute verbatim copies
of this license document, but changing it is not allowed.
This version of the GNU Lesser General Public License incorporates
the terms and conditions of version 3 of the GNU General Public
License, supplemented by the additional permissions listed below.
0. Additional Definitions.
As used herein, "this License" refers to version 3 of the GNU Lesser
General Public License, and the "GNU GPL" refers to version 3 of the GNU
General Public License.
"The Library" refers to a covered work governed by this License,
other than an Application or a Combined Work as defined below.
An "Application" is any work that makes use of an interface provided
by the Library, but which is not otherwise based on the Library.
Defining a subclass of a class defined by the Library is deemed a mode
of using an interface provided by the Library.
A "Combined Work" is a work produced by combining or linking an
Application with the Library. The particular version of the Library
with which the Combined Work was made is also called the "Linked
Version".
The "Minimal Corresponding Source" for a Combined Work means the
Corresponding Source for the Combined Work, excluding any source code
for portions of the Combined Work that, considered in isolation, are
based on the Application, and not on the Linked Version.
The "Corresponding Application Code" for a Combined Work means the
object code and/or source code for the Application, including any data
and utility programs needed for reproducing the Combined Work from the
Application, but excluding the System Libraries of the Combined Work.
1. Exception to Section 3 of the GNU GPL.
You may convey a covered work under sections 3 and 4 of this License
without being bound by section 3 of the GNU GPL.
2. Conveying Modified Versions.
If you modify a copy of the Library, and, in your modifications, a
facility refers to a function or data to be supplied by an Application
that uses the facility (other than as an argument passed when the
facility is invoked), then you may convey a copy of the modified
version:
a) under this License, provided that you make a good faith effort to
ensure that, in the event an Application does not supply the
function or data, the facility still operates, and performs
whatever part of its purpose remains meaningful, or
b) under the GNU GPL, with none of the additional permissions of
this License applicable to that copy.
3. Object Code Incorporating Material from Library Header Files.
The object code form of an Application may incorporate material from
a header file that is part of the Library. You may convey such object
code under terms of your choice, provided that, if the incorporated
material is not limited to numerical parameters, data structure
layouts and accessors, or small macros, inline functions and templates
(ten or fewer lines in length), you do both of the following:
a) Give prominent notice with each copy of the object code that the
Library is used in it and that the Library and its use are
covered by this License.
b) Accompany the object code with a copy of the GNU GPL and this license
document.
4. Combined Works.
You may convey a Combined Work under terms of your choice that,
taken together, effectively do not restrict modification of the
portions of the Library contained in the Combined Work and reverse
engineering for debugging such modifications, if you also do each of
the following:
a) Give prominent notice with each copy of the Combined Work that
the Library is used in it and that the Library and its use are
covered by this License.
b) Accompany the Combined Work with a copy of the GNU GPL and this license
document.
c) For a Combined Work that displays copyright notices during
execution, include the copyright notice for the Library among
these notices, as well as a reference directing the user to the
copies of the GNU GPL and this license document.
d) Do one of the following:
0) Convey the Minimal Corresponding Source under the terms of this
License, and the Corresponding Application Code in a form
suitable for, and under terms that permit, the user to
recombine or relink the Application with a modified version of
the Linked Version to produce a modified Combined Work, in the
manner specified by section 6 of the GNU GPL for conveying
Corresponding Source.
1) Use a suitable shared library mechanism for linking with the
Library. A suitable mechanism is one that (a) uses at run time
a copy of the Library already present on the user's computer
system, and (b) will operate properly with a modified version
of the Library that is interface-compatible with the Linked
Version.
e) Provide Installation Information, but only if you would otherwise
be required to provide such information under section 6 of the
GNU GPL, and only to the extent that such information is
necessary to install and execute a modified version of the
Combined Work produced by recombining or relinking the
Application with a modified version of the Linked Version. (If
you use option 4d0, the Installation Information must accompany
the Minimal Corresponding Source and Corresponding Application
Code. If you use option 4d1, you must provide the Installation
Information in the manner specified by section 6 of the GNU GPL
for conveying Corresponding Source.)
5. Combined Libraries.
You may place library facilities that are a work based on the
Library side by side in a single library together with other library
facilities that are not Applications and are not covered by this
License, and convey such a combined library under terms of your
choice, if you do both of the following:
a) Accompany the combined library with a copy of the same work based
on the Library, uncombined with any other library facilities,
conveyed under the terms of this License.
b) Give prominent notice with the combined library that part of it
is a work based on the Library, and explaining where to find the
accompanying uncombined form of the same work.
6. Revised Versions of the GNU Lesser General Public License.
The Free Software Foundation may publish revised and/or new versions
of the GNU Lesser General Public License from time to time. Such new
versions will be similar in spirit to the present version, but may
differ in detail to address new problems or concerns.
Each version is given a distinguishing version number. If the
Library as you received it specifies that a certain numbered version
of the GNU Lesser General Public License "or any later version"
applies to it, you have the option of following the terms and
conditions either of that published version or of any later version
published by the Free Software Foundation. If the Library as you
received it does not specify a version number of the GNU Lesser
General Public License, you may choose any version of the GNU Lesser
General Public License ever published by the Free Software Foundation.
If the Library as you received it specifies that a proxy can decide
whether future versions of the GNU Lesser General Public License shall
apply, that proxy's public statement of acceptance of any version is
permanent authorization for you to choose that version for the
Library.
###############################################################################
Attribution-ShareAlike 4.0 International
=======================================================================
Creative Commons Corporation ("Creative Commons") is not a law firm and
does not provide legal services or legal advice. Distribution of
Creative Commons public licenses does not create a lawyer-client or
other relationship. Creative Commons makes its licenses and related
information available on an "as-is" basis. Creative Commons gives no
warranties regarding its licenses, any material licensed under their
terms and conditions, or any related information. Creative Commons
disclaims all liability for damages resulting from their use to the
fullest extent possible.
Using Creative Commons Public Licenses
Creative Commons public licenses provide a standard set of terms and
conditions that creators and other rights holders may use to share
original works of authorship and other material subject to copyright
and certain other rights specified in the public license below. The
following considerations are for informational purposes only, are not
exhaustive, and do not form part of our licenses.
Considerations for licensors: Our public licenses are
intended for use by those authorized to give the public
permission to use material in ways otherwise restricted by
copyright and certain other rights. Our licenses are
irrevocable. Licensors should read and understand the terms
and conditions of the license they choose before applying it.
Licensors should also secure all rights necessary before
applying our licenses so that the public can reuse the
material as expected. Licensors should clearly mark any
material not subject to the license. This includes other CC-
licensed material, or material used under an exception or
limitation to copyright. More considerations for licensors:
wiki.creativecommons.org/Considerations_for_licensors
Considerations for the public: By using one of our public
licenses, a licensor grants the public permission to use the
licensed material under specified terms and conditions. If
the licensor's permission is not necessary for any reason--for
example, because of any applicable exception or limitation to
copyright--then that use is not regulated by the license. Our
licenses grant only permissions under copyright and certain
other rights that a licensor has authority to grant. Use of
the licensed material may still be restricted for other
reasons, including because others have copyright or other
rights in the material. A licensor may make special requests,
such as asking that all changes be marked or described.
Although not required by our licenses, you are encouraged to
respect those requests where reasonable. More considerations
for the public:
wiki.creativecommons.org/Considerations_for_licensees
=======================================================================
Creative Commons Attribution-ShareAlike 4.0 International Public
License
By exercising the Licensed Rights (defined below), You accept and agree
to be bound by the terms and conditions of this Creative Commons
Attribution-ShareAlike 4.0 International Public License ("Public
License"). To the extent this Public License may be interpreted as a
contract, You are granted the Licensed Rights in consideration of Your
acceptance of these terms and conditions, and the Licensor grants You
such rights in consideration of benefits the Licensor receives from
making the Licensed Material available under these terms and
conditions.
Section 1 -- Definitions.
a. Adapted Material means material subject to Copyright and Similar
Rights that is derived from or based upon the Licensed Material
and in which the Licensed Material is translated, altered,
arranged, transformed, or otherwise modified in a manner requiring
permission under the Copyright and Similar Rights held by the
Licensor. For purposes of this Public License, where the Licensed
Material is a musical work, performance, or sound recording,
Adapted Material is always produced where the Licensed Material is
synched in timed relation with a moving image.
b. Adapter's License means the license You apply to Your Copyright
and Similar Rights in Your contributions to Adapted Material in
accordance with the terms and conditions of this Public License.
c. BY-SA Compatible License means a license listed at
creativecommons.org/compatiblelicenses, approved by Creative
Commons as essentially the equivalent of this Public License.
d. Copyright and Similar Rights means copyright and/or similar rights
closely related to copyright including, without limitation,
performance, broadcast, sound recording, and Sui Generis Database
Rights, without regard to how the rights are labeled or
categorized. For purposes of this Public License, the rights
specified in Section 2(b)(1)-(2) are not Copyright and Similar
Rights.
e. Effective Technological Measures means those measures that, in the
absence of proper authority, may not be circumvented under laws
fulfilling obligations under Article 11 of the WIPO Copyright
Treaty adopted on December 20, 1996, and/or similar international
agreements.
f. Exceptions and Limitations means fair use, fair dealing, and/or
any other exception or limitation to Copyright and Similar Rights
that applies to Your use of the Licensed Material.
g. License Elements means the license attributes listed in the name
of a Creative Commons Public License. The License Elements of this
Public License are Attribution and ShareAlike.
h. Licensed Material means the artistic or literary work, database,
or other material to which the Licensor applied this Public
License.
i. Licensed Rights means the rights granted to You subject to the
terms and conditions of this Public License, which are limited to
all Copyright and Similar Rights that apply to Your use of the
Licensed Material and that the Licensor has authority to license.
j. Licensor means the individual(s) or entity(ies) granting rights
under this Public License.
k. Share means to provide material to the public by any means or
process that requires permission under the Licensed Rights, such
as reproduction, public display, public performance, distribution,
dissemination, communication, or importation, and to make material
available to the public including in ways that members of the
public may access the material from a place and at a time
individually chosen by them.
l. Sui Generis Database Rights means rights other than copyright
resulting from Directive 96/9/EC of the European Parliament and of
the Council of 11 March 1996 on the legal protection of databases,
as amended and/or succeeded, as well as other essentially
equivalent rights anywhere in the world.
m. You means the individual or entity exercising the Licensed Rights
under this Public License. Your has a corresponding meaning.
Section 2 -- Scope.
a. License grant.
1. Subject to the terms and conditions of this Public License,
the Licensor hereby grants You a worldwide, royalty-free,
non-sublicensable, non-exclusive, irrevocable license to
exercise the Licensed Rights in the Licensed Material to:
a. reproduce and Share the Licensed Material, in whole or
in part; and
b. produce, reproduce, and Share Adapted Material.
2. Exceptions and Limitations. For the avoidance of doubt, where
Exceptions and Limitations apply to Your use, this Public
License does not apply, and You do not need to comply with
its terms and conditions.
3. Term. The term of this Public License is specified in Section
6(a).
4. Media and formats; technical modifications allowed. The
Licensor authorizes You to exercise the Licensed Rights in
all media and formats whether now known or hereafter created,
and to make technical modifications necessary to do so. The
Licensor waives and/or agrees not to assert any right or
authority to forbid You from making technical modifications
necessary to exercise the Licensed Rights, including
technical modifications necessary to circumvent Effective
Technological Measures. For purposes of this Public License,
simply making modifications authorized by this Section 2(a)
(4) never produces Adapted Material.
5. Downstream recipients.
a. Offer from the Licensor -- Licensed Material. Every
recipient of the Licensed Material automatically
receives an offer from the Licensor to exercise the
Licensed Rights under the terms and conditions of this
Public License.
b. Additional offer from the Licensor -- Adapted Material.
Every recipient of Adapted Material from You
automatically receives an offer from the Licensor to
exercise the Licensed Rights in the Adapted Material
under the conditions of the Adapter's License You apply.
c. No downstream restrictions. You may not offer or impose
any additional or different terms or conditions on, or
apply any Effective Technological Measures to, the
Licensed Material if doing so restricts exercise of the
Licensed Rights by any recipient of the Licensed
Material.
6. No endorsement. Nothing in this Public License constitutes or
may be construed as permission to assert or imply that You
are, or that Your use of the Licensed Material is, connected
with, or sponsored, endorsed, or granted official status by,
the Licensor or others designated to receive attribution as
provided in Section 3(a)(1)(A)(i).
b. Other rights.
1. Moral rights, such as the right of integrity, are not
licensed under this Public License, nor are publicity,
privacy, and/or other similar personality rights; however, to
the extent possible, the Licensor waives and/or agrees not to
assert any such rights held by the Licensor to the limited
extent necessary to allow You to exercise the Licensed
Rights, but not otherwise.
2. Patent and trademark rights are not licensed under this
Public License.
3. To the extent possible, the Licensor waives any right to
collect royalties from You for the exercise of the Licensed
Rights, whether directly or through a collecting society
under any voluntary or waivable statutory or compulsory
licensing scheme. In all other cases the Licensor expressly
reserves any right to collect such royalties.
Section 3 -- License Conditions.
Your exercise of the Licensed Rights is expressly made subject to the
following conditions.
a. Attribution.
1. If You Share the Licensed Material (including in modified
form), You must:
a. retain the following if it is supplied by the Licensor
with the Licensed Material:
i. identification of the creator(s) of the Licensed
Material and any others designated to receive
attribution, in any reasonable manner requested by
the Licensor (including by pseudonym if
designated);
ii. a copyright notice;
iii. a notice that refers to this Public License;
iv. a notice that refers to the disclaimer of
warranties;
v. a URI or hyperlink to the Licensed Material to the
extent reasonably practicable;
b. indicate if You modified the Licensed Material and
retain an indication of any previous modifications; and
c. indicate the Licensed Material is licensed under this
Public License, and include the text of, or the URI or
hyperlink to, this Public License.
2. You may satisfy the conditions in Section 3(a)(1) in any
reasonable manner based on the medium, means, and context in
which You Share the Licensed Material. For example, it may be
reasonable to satisfy the conditions by providing a URI or
hyperlink to a resource that includes the required
information.
3. If requested by the Licensor, You must remove any of the
information required by Section 3(a)(1)(A) to the extent
reasonably practicable.
b. ShareAlike.
In addition to the conditions in Section 3(a), if You Share
Adapted Material You produce, the following conditions also apply.
1. The Adapter's License You apply must be a Creative Commons
license with the same License Elements, this version or
later, or a BY-SA Compatible License.
2. You must include the text of, or the URI or hyperlink to, the
Adapter's License You apply. You may satisfy this condition
in any reasonable manner based on the medium, means, and
context in which You Share Adapted Material.
3. You may not offer or impose any additional or different terms
or conditions on, or apply any Effective Technological
Measures to, Adapted Material that restrict exercise of the
rights granted under the Adapter's License You apply.
Section 4 -- Sui Generis Database Rights.
Where the Licensed Rights include Sui Generis Database Rights that
apply to Your use of the Licensed Material:
a. for the avoidance of doubt, Section 2(a)(1) grants You the right
to extract, reuse, reproduce, and Share all or a substantial
portion of the contents of the database;
b. if You include all or a substantial portion of the database
contents in a database in which You have Sui Generis Database
Rights, then the database in which You have Sui Generis Database
Rights (but not its individual contents) is Adapted Material,
including for purposes of Section 3(b); and
c. You must comply with the conditions in Section 3(a) if You Share
all or a substantial portion of the contents of the database.
For the avoidance of doubt, this Section 4 supplements and does not
replace Your obligations under this Public License where the Licensed
Rights include other Copyright and Similar Rights.
Section 5 -- Disclaimer of Warranties and Limitation of Liability.
a. UNLESS OTHERWISE SEPARATELY UNDERTAKEN BY THE LICENSOR, TO THE
EXTENT POSSIBLE, THE LICENSOR OFFERS THE LICENSED MATERIAL AS-IS
AND AS-AVAILABLE, AND MAKES NO REPRESENTATIONS OR WARRANTIES OF
ANY KIND CONCERNING THE LICENSED MATERIAL, WHETHER EXPRESS,
IMPLIED, STATUTORY, OR OTHER. THIS INCLUDES, WITHOUT LIMITATION,
WARRANTIES OF TITLE, MERCHANTABILITY, FITNESS FOR A PARTICULAR
PURPOSE, NON-INFRINGEMENT, ABSENCE OF LATENT OR OTHER DEFECTS,
ACCURACY, OR THE PRESENCE OR ABSENCE OF ERRORS, WHETHER OR NOT
KNOWN OR DISCOVERABLE. WHERE DISCLAIMERS OF WARRANTIES ARE NOT
ALLOWED IN FULL OR IN PART, THIS DISCLAIMER MAY NOT APPLY TO YOU.
b. TO THE EXTENT POSSIBLE, IN NO EVENT WILL THE LICENSOR BE LIABLE
TO YOU ON ANY LEGAL THEORY (INCLUDING, WITHOUT LIMITATION,
NEGLIGENCE) OR OTHERWISE FOR ANY DIRECT, SPECIAL, INDIRECT,
INCIDENTAL, CONSEQUENTIAL, PUNITIVE, EXEMPLARY, OR OTHER LOSSES,
COSTS, EXPENSES, OR DAMAGES ARISING OUT OF THIS PUBLIC LICENSE OR
USE OF THE LICENSED MATERIAL, EVEN IF THE LICENSOR HAS BEEN
ADVISED OF THE POSSIBILITY OF SUCH LOSSES, COSTS, EXPENSES, OR
DAMAGES. WHERE A LIMITATION OF LIABILITY IS NOT ALLOWED IN FULL OR
IN PART, THIS LIMITATION MAY NOT APPLY TO YOU.
c. The disclaimer of warranties and limitation of liability provided
above shall be interpreted in a manner that, to the extent
possible, most closely approximates an absolute disclaimer and
waiver of all liability.
Section 6 -- Term and Termination.
a. This Public License applies for the term of the Copyright and
Similar Rights licensed here. However, if You fail to comply with
this Public License, then Your rights under this Public License
terminate automatically.
b. Where Your right to use the Licensed Material has terminated under
Section 6(a), it reinstates:
1. automatically as of the date the violation is cured, provided
it is cured within 30 days of Your discovery of the
violation; or
2. upon express reinstatement by the Licensor.
For the avoidance of doubt, this Section 6(b) does not affect any
right the Licensor may have to seek remedies for Your violations
of this Public License.
c. For the avoidance of doubt, the Licensor may also offer the
Licensed Material under separate terms or conditions or stop
distributing the Licensed Material at any time; however, doing so
will not terminate this Public License.
d. Sections 1, 5, 6, 7, and 8 survive termination of this Public
License.
Section 7 -- Other Terms and Conditions.
a. The Licensor shall not be bound by any additional or different
terms or conditions communicated by You unless expressly agreed.
b. Any arrangements, understandings, or agreements regarding the
Licensed Material not stated herein are separate from and
independent of the terms and conditions of this Public License.
Section 8 -- Interpretation.
a. For the avoidance of doubt, this Public License does not, and
shall not be interpreted to, reduce, limit, restrict, or impose
conditions on any use of the Licensed Material that could lawfully
be made without permission under this Public License.
b. To the extent possible, if any provision of this Public License is
deemed unenforceable, it shall be automatically reformed to the
minimum extent necessary to make it enforceable. If the provision
cannot be reformed, it shall be severed from this Public License
without affecting the enforceability of the remaining terms and
conditions.
c. No term or condition of this Public License will be waived and no
failure to comply consented to unless expressly agreed to by the
Licensor.
d. Nothing in this Public License constitutes or may be interpreted
as a limitation upon, or waiver of, any privileges and immunities
that apply to the Licensor or You, including from the legal
processes of any jurisdiction or authority.
=======================================================================
Creative Commons is not a party to its public
licenses. Notwithstanding, Creative Commons may elect to apply one of
its public licenses to material it publishes and in those instances
will be considered the “Licensor.” The text of the Creative Commons
public licenses is dedicated to the public domain under the CC0 Public
Domain Dedication. Except for the limited purpose of indicating that
material is shared under a Creative Commons public license or as
otherwise permitted by the Creative Commons policies published at
creativecommons.org/policies, Creative Commons does not authorize the
use of the trademark "Creative Commons" or any other trademark or logo
of Creative Commons without its prior written consent including,
without limitation, in connection with any unauthorized modifications
to any of its public licenses or any other arrangements,
understandings, or agreements concerning use of licensed material. For
the avoidance of doubt, this paragraph does not form part of the
public licenses.
Creative Commons may be contacted at creativecommons.org.

11
mods/moretrees/README.md Normal file
View File

@ -0,0 +1,11 @@
More trees!
This mod adds a whole bunch of new types of trees to the game
Much of the code here came from cisoun's conifers mod and bas080's
jungle trees mod, and big contributions by RealBadAngel.
Brought together into one mod and made L-systems compatible by Vanessa
Ezekowitz.
Dependencies: <a href="https://forum.minetest.net/viewtopic.php?f=11&t=12999">biome_lib</a> and default

View File

@ -0,0 +1,301 @@
moretrees.beech_biome = {
surface = "default:dirt_with_grass",
avoid_nodes = moretrees.avoidnodes,
avoid_radius = 8,
seed_diff = 2,
rarity = 50,
max_count = 20,
}
moretrees.palm_biome = {
surface = "default:sand",
avoid_nodes = moretrees.avoidnodes,
avoid_radius = 5,
seed_diff = 330,
min_elevation = -1,
max_elevation = 1,
near_nodes = {"default:water_source"},
near_nodes_size = 15,
near_nodes_count = 10,
temp_min = 0.25,
temp_max = -0.15,
rarity = 50,
max_count = 10,
}
moretrees.date_palm_biome = {
surface = "default:desert_sand",
avoid_nodes = moretrees.avoidnodes,
avoid_radius = 10,
seed_diff = 339,
min_elevation = -1,
max_elevation = 10,
near_nodes = {"default:water_source"},
near_nodes_size = 20,
near_nodes_count = 100,
near_nodes_vertical = 20,
temp_min = -0.20,
humidity_max = 0.20,
rarity = 10,
max_count = 30,
}
moretrees.date_palm_biome_2 = {
surface = "default:desert_sand",
avoid_nodes = moretrees.avoidnodes,
avoid_radius = 10,
seed_diff = 340,
min_elevation = 11,
max_elevation = 30,
near_nodes = {"default:water_source"},
near_nodes_size = 1,
near_nodes_count = 1,
near_nodes_vertical = 30,
temp_min = -0.20,
humidity_max = 0.20,
rarity = 10,
max_count = 30,
}
moretrees.apple_tree_biome = {
surface = "default:dirt_with_grass",
avoid_nodes = moretrees.avoidnodes,
avoid_radius = 10,
seed_diff = 331,
min_elevation = 1,
max_elevation = 10,
temp_min = 0.1,
temp_max = -0.15,
rarity = 75,
max_count = 5,
}
moretrees.oak_biome = {
surface = "default:dirt_with_grass",
avoid_nodes = moretrees.avoidnodes,
avoid_radius = 15,
seed_diff = 332,
min_elevation = 0,
max_elevation = 10,
temp_min = 0.4,
temp_max = 0.2,
rarity = 50,
max_count = 5,
}
moretrees.sequoia_biome = {
surface = "default:dirt_with_grass",
avoid_nodes = moretrees.avoidnodes,
avoid_radius = 10,
seed_diff = 333,
min_elevation = 0,
max_elevation = 10,
temp_min = 1,
temp_max = -0.4,
rarity = 90,
max_count = 5,
}
moretrees.birch_biome = {
surface = "default:dirt_with_grass",
avoid_nodes = moretrees.avoidnodes,
avoid_radius = 5,
seed_diff = 334,
min_elevation = 10,
max_elevation = 15,
temp_min = 0.9,
temp_max = 0.3,
rarity = 50,
max_count = 10,
}
moretrees.willow_biome = {
surface = "default:dirt_with_grass",
avoid_nodes = moretrees.avoidnodes,
avoid_radius = 10,
seed_diff = 337,
min_elevation = -5,
max_elevation = 5,
near_nodes = {"default:water_source"},
near_nodes_size = 15,
near_nodes_count = 5,
rarity = 75,
max_count = 5,
}
moretrees.rubber_tree_biome = {
surface = "default:dirt_with_grass",
avoid_nodes = moretrees.avoidnodes,
avoid_radius = 10,
seed_diff = 338,
min_elevation = -5,
max_elevation = 5,
near_nodes = {"default:water_source"},
near_nodes_size = 15,
near_nodes_count = 10,
temp_min = -0.15,
rarity = 75,
max_count = 10,
}
moretrees.jungletree_biome = {
surface = {
"default:dirt",
"default:dirt_with_grass",
"woodsoils:dirt_with_leaves_1",
"woodsoils:grass_with_leaves_1",
"woodsoils:grass_with_leaves_2"
},
avoid_nodes = {"moretrees:jungletree_trunk"},
max_count = 12,
avoid_radius = 3,
rarity = 85,
seed_diff = 329,
min_elevation = 1,
near_nodes = {"default:jungletree"},
near_nodes_size = 6,
near_nodes_vertical = 2,
near_nodes_count = 1,
plantlife_limit = -0.9,
}
moretrees.spruce_biome = {
surface = "default:dirt_with_grass",
avoid_nodes = moretrees.avoidnodes,
avoid_radius = 10,
seed_diff = 335,
min_elevation = 20,
temp_min = 0.9,
temp_max = 0.7,
rarity = 50,
max_count = 5,
}
moretrees.cedar_biome = {
surface = "default:dirt_with_grass",
avoid_nodes = moretrees.avoidnodes,
avoid_radius = 10,
seed_diff = 336,
near_nodes = {"default:water_source"},
near_nodes_size = 15,
near_nodes_count = 5,
rarity = 50,
max_count = 10,
}
-- Poplar requires a lot of water.
moretrees.poplar_biome = {
surface = "default:dirt_with_grass",
avoid_nodes = moretrees.avoidnodes,
avoid_radius = 6,
seed_diff = 341,
min_elevation = 0,
max_elevation = 50,
near_nodes = {"default:water_source"},
near_nodes_size = 15,
near_nodes_vertical = 5,
near_nodes_count = 1,
humidity_min = -0.7,
humidity_max = -1,
rarity = 50,
max_count = 15,
}
-- The humidity requirement it quite restrictive (apparently).
-- Spawn an occasional poplar elsewhere.
moretrees.poplar_biome_2 = {
surface = "default:dirt_with_grass",
avoid_nodes = moretrees.avoidnodes,
avoid_radius = 6,
seed_diff = 341,
min_elevation = 0,
max_elevation = 50,
near_nodes = {"default:water_source"},
near_nodes_size = 15,
near_nodes_vertical = 4,
near_nodes_count = 10,
humidity_min = 0.1,
humidity_max = -0.6,
rarity = 50,
max_count = 1,
}
-- Subterranean lakes provide enough water for poplars to grow
moretrees.poplar_biome_3 = {
surface = "default:dirt_with_grass",
avoid_nodes = moretrees.avoidnodes,
avoid_radius = 6,
seed_diff = 342,
min_elevation = 0,
max_elevation = 50,
near_nodes = {"default:water_source"},
near_nodes_size = 1,
near_nodes_vertical = 25,
near_nodes_count = 1,
humidity_min = -0.5,
humidity_max = -1,
rarity = 0,
max_count = 30,
}
moretrees.poplar_small_biome = {
surface = "default:dirt_with_grass",
avoid_nodes = moretrees.avoidnodes,
avoid_radius = 4,
seed_diff = 343,
min_elevation = 0,
max_elevation = 50,
near_nodes = {"default:water_source"},
near_nodes_size = 10,
near_nodes_vertical = 5,
near_nodes_count = 1,
humidity_min = -0.7,
humidity_max = -1,
rarity = 50,
max_count = 10,
}
moretrees.poplar_small_biome_2 = {
surface = "default:dirt_with_grass",
avoid_nodes = moretrees.avoidnodes,
avoid_radius = 4,
seed_diff = 343,
min_elevation = 0,
max_elevation = 50,
near_nodes = {"default:water_source"},
near_nodes_size = 10,
near_nodes_vertical = 4,
near_nodes_count = 5,
humidity_min = 0.1,
humidity_max = -0.6,
rarity = 50,
max_count = 3,
}
moretrees.fir_biome = {
surface = "default:dirt_with_grass",
avoid_nodes = moretrees.avoidnodes,
avoid_radius = 10,
seed_diff = 359,
min_elevation = 25,
temp_min = 0.9,
temp_max = 0.3,
rarity = 50,
max_count = 10,
}
moretrees.fir_biome_snow = {
surface = {"snow:dirt_with_snow", "snow:snow"},
below_nodes = {"default:dirt", "default:dirt_with_grass", "snow:dirt_with_snow"},
avoid_nodes = moretrees.avoidnodes,
avoid_radius = 10,
seed_diff = 359,
rarity = 50,
max_count = 10,
check_air = false,
delete_above = true,
spawn_replace_node = true
}

View File

@ -0,0 +1,335 @@
-- © 2016, Rogier <rogier777@gmail.com>
-- Translation support
local S = minetest.get_translator("moretrees")
-- Some constants
local coconut_drop_ichance = 8
-- Make the cocos palm fruit trunk a real trunk (it is generated as a fruit)
local trunk = minetest.registered_nodes["moretrees:palm_trunk"]
local ftrunk = {}
local gftrunk = {}
for k,v in pairs(trunk) do
ftrunk[k] = v
gftrunk[k] = v
end
ftrunk.tiles = {}
gftrunk.tiles = {}
for k,v in pairs(trunk.tiles) do
ftrunk.tiles[k] = v
gftrunk.tiles[k] = v
end
ftrunk.drop = "moretrees:palm_trunk"
gftrunk.drop = "moretrees:palm_trunk"
ftrunk.after_destruct = function(pos, oldnode)
local coconuts = 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},
{"group:moretrees_coconut"}
)
for _,coconutpos in pairs(coconuts) do
-- minetest.dig_node(coconutpos) does not cause nearby coconuts to be dropped :-( ...
--minetest.dig_node(coconutpos)
local items = minetest.get_node_drops(minetest.get_node(coconutpos).name)
minetest.swap_node(coconutpos, biome_lib.air)
for _, itemname in pairs(items) do
minetest.add_item(coconutpos, itemname)
end
end
end
-- Make the different trunk types distinguishable (but barely)
ftrunk.tiles[1] = "moretrees_palm_trunk_top.png^[transformR90"
gftrunk.tiles[1] = "moretrees_palm_trunk_top.png^[transformR180"
gftrunk.description = gftrunk.description.." (gen)"
minetest.register_node("moretrees:palm_fruit_trunk", ftrunk)
minetest.register_node("moretrees:palm_fruit_trunk_gen", gftrunk)
local coconut_regrow_abm_spec = {
nodenames = { "moretrees:palm_fruit_trunk" },
interval = moretrees.coconut_flower_interval,
chance = moretrees.coconut_flower_chance,
action = function(pos, node, active_object_count, active_object_count_wider)
local coconuts = 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},
"group:moretrees_coconut"
)
-- Expected growth interval increases exponentially with number of coconuts already hanging.
-- Also: if more coconuts are hanging, the chance of picking an empty spot decreases as well...
if math.random(2^#coconuts) <= 2 then
-- Grow in area of 3x3 round trunk
local dx=math.floor(math.random(3)-2)
local dz=math.floor(math.random(3)-2)
local coconutpos = {x=pos.x+dx, y=pos.y, z=pos.z+dz}
local coconutnode = minetest.get_node(coconutpos)
if coconutnode.name == "air" then
minetest.swap_node(coconutpos, {name="moretrees:coconut_0"})
end
end
end
}
if moretrees.coconuts_regrow then
minetest.register_abm(coconut_regrow_abm_spec)
end
-- Spawn initial coconuts
-- Spawn initial coconuts
-- (Instead of coconuts, a generated-palm fruit trunk is generated with the tree. This
-- ABM converts the trunk to a regular fruit trunk, and spawns some coconuts)
minetest.register_abm({
nodenames = { "moretrees:palm_fruit_trunk_gen" },
interval = 1,
chance = 1,
action = function(pos, node, active_object_count, active_object_count_wider)
minetest.swap_node(pos, {name="moretrees:palm_fruit_trunk"})
local poslist = 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},
"air"
)
local genlist = {}
for k,v in pairs(poslist) do
genlist[k] = {x = math.random(100), pos = v}
end
table.sort(genlist, function(a, b) return a.x < b.x; end)
local count = 0
for _, gen in pairs(genlist) do
minetest.swap_node(gen.pos, {name = "moretrees:coconut_3"})
count = count + 1
if count == 4 then
break
end
end
end,
})
-- Register coconuts, and make them regrow
local coconut_growfn = function(pos, elapsed)
local node = minetest.get_node(pos)
local delay = moretrees.coconut_grow_interval
if not node then
return
elseif not moretrees.coconuts_regrow then
-- Regrowing has been turned off. Make coconust grow instantly
minetest.swap_node(pos, {name="moretrees:coconut_3"})
return
elseif node.name == "moretrees:coconut_3" then
-- Drop coconuts (i.e. remove them), so that new coconuts can grow.
-- Coconuts will drop as items with a small chance
if math.random(coconut_drop_ichance) == 1 then
if moretrees.coconut_item_drop_ichance > 0
and math.random(moretrees.coconut_item_drop_ichance) == 1 then
local items = minetest.get_node_drops(minetest.get_node(pos).name)
for _, itemname in pairs(items) do
minetest.add_item(pos, itemname)
end
end
minetest.swap_node(pos, biome_lib.air)
end
else
-- Grow coconuts to the next stage
local offset = string.len("moretrees:coconut_x")
local n = string.sub(node.name, offset)
minetest.swap_node(pos, {name=string.sub(node.name, 1, offset-1)..n+1})
end
-- Don't catch up when elapsed time is large. Regular visits are needed for growth...
local timer = minetest.get_node_timer(pos)
timer:start(delay + math.random(moretrees.coconut_grow_interval))
end
local coconut_starttimer = function(pos, elapsed)
local timer = minetest.get_node_timer(pos)
local base_interval = moretrees.coconut_grow_interval * 2 / 3
timer:set(base_interval + math.random(base_interval), elapsed or 0)
end
for _,suffix in ipairs({"_0", "_1", "_2", "_3", ""}) do
local name
if suffix == "_0" then
name = S("Coconut Flower")
else
name = S("Coconut")
end
local drop = ""
local coco_group = 1
local tile = "moretrees_coconut"..suffix..".png"
local timerfn = coconut_growfn
local constructfn = coconut_starttimer
if suffix == "_3" then
drop = "moretrees:coconut"
tile = "moretrees_coconut.png"
elseif suffix == "" then
drop = nil
coco_group = nil
timerfn = nil
constructfn = nil
end
local coconutdef = {
description = name,
tiles = {tile},
drawtype = "plantlike",
paramtype = "light",
sunlight_propagates = true,
walkable = false,
groups = { fleshy=3, dig_immediate=3, flammable=2, moretrees_coconut=coco_group },
inventory_image = tile.."^[transformR180",
wield_image = tile.."^[transformR180",
sounds = default.node_sound_defaults(),
drop = drop,
selection_box = {
type = "fixed",
fixed = {-0.3, -0.3, -0.3, 0.3, 0.3, 0.3}
},
on_timer = timerfn,
on_construct = constructfn,
}
minetest.register_node("moretrees:coconut"..suffix, coconutdef)
end
-- convert exisiting cocos palms. This is a bit tricky...
-- Try to make sure that this is indeed a generated tree, and not manually-placed trunks and/or coconuts
if moretrees.coconuts_convert_existing_palms then
local spec = {
name = "moretrees:convert_existing_cocos_palms_to_regrow_coconuts",
nodenames = "moretrees:coconut",
action = function(pos, node, active_object_count, active_object_count_wider)
local trunks
local cvtrunks
local leaves
local coconuts
-- One regular trunk must be adjacent to the coconut
trunks = 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},
"moretrees:palm_trunk"
)
if #trunks ~= 1 then
return
end
local tpos = trunks[1]
-- 1 or 2 other trunks must be one level below to the trunk being converted.
trunks = minetest.find_nodes_in_area(
{x=tpos.x-1, y=tpos.y-1, z=tpos.z-1},
{x=tpos.x+1, y=tpos.y-1, z=tpos.z+1},
"moretrees:palm_trunk"
)
if #trunks < 1 or #trunks > 2 then
return
end
-- 1 or 2 other trunks must be two levels below to the trunk being converted.
trunks = minetest.find_nodes_in_area(
{x=tpos.x-1, y=tpos.y-2, z=tpos.z-1},
{x=tpos.x+1, y=tpos.y-2, z=tpos.z+1},
"moretrees:palm_trunk"
)
if #trunks < 1 or #trunks > 2 then
return
end
-- 1 or 2 trunks must at the level of the trunk being converted.
cvtrunks = minetest.find_nodes_in_area(
{x=tpos.x-1, y=tpos.y, z=tpos.z-1},
{x=tpos.x+1, y=tpos.y, z=tpos.z+1},
"moretrees:palm_trunk"
)
if #cvtrunks < 1 or #cvtrunks > 2 then
return
end
-- No trunks may be one level above the trunk being converted.
trunks = minetest.find_nodes_in_area(
{x=tpos.x-1, y=tpos.y+1, z=tpos.z-1},
{x=tpos.x+1, y=tpos.y+1, z=tpos.z+1},
"moretrees:palm_trunk"
)
if #trunks ~= 0 then
return
end
-- Leaves must be one level above the trunk being converted.
leaves = minetest.find_nodes_in_area(
{x=tpos.x-1, y=tpos.y+1, z=tpos.z-1},
{x=tpos.x+1, y=tpos.y+1, z=tpos.z+1},
"moretrees:palm_leaves"
)
if #leaves == 0 then
return
end
-- Leaves must be two levels above the trunk being converted.
leaves = minetest.find_nodes_in_area(
{x=tpos.x-1, y=tpos.y+2, z=tpos.z-1},
{x=tpos.x+1, y=tpos.y+2, z=tpos.z+1},
"moretrees:palm_leaves"
)
if #leaves == 0 then
return
end
-- No cocos fruit trunk may already be adjacent to the coconut
trunks = 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},
"moretrees:palm_fruit_trunk"
)
if #trunks ~= 0 then
return
end
-- No cocos fruit trunk may be adjacent to or below the trunk being converted.
trunks = minetest.find_nodes_in_area(
{x=tpos.x-1, y=tpos.y-2, z=tpos.z-1},
{x=tpos.x+1, y=tpos.y, z=tpos.z+1},
"moretrees:palm_fruit_trunk"
)
if #trunks ~= 0 then
return
end
-- Convert trunk and all coconuts nearby. Maybe convert 2 trunks, just in case...
for _, tpos_1 in pairs(cvtrunks) do
minetest.swap_node(tpos_1, {name = "moretrees:palm_fruit_trunk"})
coconuts = minetest.find_nodes_in_area(
{x=tpos_1.x-1, y=tpos_1.y, z=tpos_1.z-1},
{x=tpos_1.x+1, y=tpos_1.y, z=tpos_1.z+1},
"moretrees:coconut"
)
for _, coconutpos in pairs(coconuts) do
minetest.swap_node(coconutpos, {name = "moretrees:coconut_3"})
end
end
end,
}
if minetest.register_lbm then
minetest.register_lbm(spec)
else
spec.interval = 3691
spec.chance = 10
minetest.register_abm(spec)
end
end
-- If regrowing was previously disabled, but is enabled now, make sure timers are started for existing coconuts
if moretrees.coconuts_regrow then
local spec = {
name = "moretrees:restart_coconut_regrow_timer",
nodenames = "group:moretrees_coconut",
action = function(pos, node, active_object_count, active_object_count_wider)
local timer = minetest.get_node_timer(pos)
if not timer:is_started() then
coconut_starttimer(pos)
else
local timeout = timer:get_timeout()
local elapsed = timer:get_elapsed()
if timeout - elapsed > moretrees.coconut_grow_interval * 4/3 then
coconut_starttimer(pos, math.random(moretrees.coconut_grow_interval * 4/3))
end
end
end,
}
if minetest.register_lbm then
minetest.register_lbm(spec)
else
spec.interval = 3659
spec.chance = 10
minetest.register_abm(spec)
end
end

271
mods/moretrees/crafts.lua Normal file
View File

@ -0,0 +1,271 @@
local S = minetest.get_translator("moretrees")
for i in ipairs(moretrees.treelist) do
local treename = moretrees.treelist[i][1]
minetest.register_craft({
type = "shapeless",
output = "moretrees:"..treename.."_planks 4",
recipe = {
"moretrees:"..treename.."_trunk"
}
})
minetest.register_craft({
type = "fuel",
recipe = "moretrees:"..treename.."_sapling",
burntime = 10,
})
end
minetest.register_craft({
type = "shapeless",
output = "moretrees:rubber_tree_planks 4",
recipe = {
"moretrees:rubber_tree_trunk_empty"
}
})
minetest.register_craft({
type = "fuel",
recipe = "group:moretrees_leaves",
burntime = 1,
})
-- Food recipes!
minetest.register_craftitem("moretrees:coconut_milk", {
description = S("Coconut Milk"),
inventory_image = "moretrees_coconut_milk_inv.png",
wield_image = "moretrees_coconut_milk.png",
on_use = minetest.item_eat(2, "vessels:drinking_glass"),
groups = {vessel = 1},
})
minetest.register_craftitem("moretrees:raw_coconut", {
description = S("Raw Coconut"),
inventory_image = "moretrees_raw_coconut.png",
on_use = minetest.item_eat(4),
})
minetest.register_craftitem("moretrees:date", {
description = S("Date"),
inventory_image = "moretrees_date.png",
on_use = minetest.item_eat(1),
})
minetest.register_craftitem("moretrees:date_nut_snack", {
description = S("Date & nut snack"),
inventory_image = "moretrees_date_nut_snack.png",
on_use = minetest.item_eat(4),
})
minetest.register_craftitem("moretrees:date_nut_batter", {
description = S("Date-nut cake batter"),
inventory_image = "moretrees_date_nut_batter.png",
})
minetest.register_craftitem("moretrees:date_nut_cake", {
description = S("Date-nut cake"),
inventory_image = "moretrees_date_nut_cake.png",
on_use = minetest.item_eat(32),
})
minetest.register_craftitem("moretrees:date_nut_bar", {
description = S("Date-nut energy bar"),
inventory_image = "moretrees_date_nut_bar.png",
on_use = minetest.item_eat(4),
})
minetest.register_craftitem("moretrees:acorn_muffin_batter", {
description = S("Acorn Muffin batter"),
inventory_image = "moretrees_acorn_muffin_batter.png",
})
minetest.register_craftitem("moretrees:acorn_muffin", {
description = S("Acorn Muffin"),
inventory_image = "moretrees_acorn_muffin.png",
on_use = minetest.item_eat(4),
})
minetest.register_craftitem("moretrees:spruce_nuts", {
description = S("Roasted Spruce Cone Nuts"),
inventory_image = "moretrees_spruce_nuts.png",
on_use = minetest.item_eat(1),
})
minetest.register_craftitem("moretrees:cedar_nuts", {
description = S("Roasted Cedar Cone Nuts"),
inventory_image = "moretrees_cedar_nuts.png",
on_use = minetest.item_eat(1),
})
minetest.register_craftitem("moretrees:fir_nuts", {
description = S("Roasted Fir Cone Nuts"),
inventory_image = "moretrees_fir_nuts.png",
on_use = minetest.item_eat(1),
})
for i in ipairs(moretrees.cutting_tools) do
local tool = moretrees.cutting_tools[i]
minetest.register_craft({
type = "shapeless",
output = "moretrees:coconut_milk",
recipe = {
"moretrees:coconut",
"vessels:drinking_glass",
tool
},
replacements = {
{ "moretrees:coconut", "moretrees:raw_coconut" },
}
})
end
-- give tool back with wear preserved
minetest.register_on_craft(function(itemstack, player, old_craft_grid, craft_inv)
if (itemstack:get_name() == "moretrees:coconut_milk") then
for i, j in pairs(old_craft_grid) do
-- find tool used to do the craft
local ocg_name = j:get_name()
if ((ocg_name ~= "") and (ocg_name ~= "moretrees:coconut") and (ocg_name ~= "vessels:drinking_glass")) then
-- abort if using cutting board
if minetest.get_item_group(ocg_name, "food_cutting_board") == 1 then
return
end
-- create a new tool and set wear
local t = ItemStack(ocg_name)
local w = j:get_wear()
-- works if tool used is an axe
local uses = j:get_tool_capabilities().groupcaps.choppy.uses or 0
if (w == 0 and uses ~= 0) then
-- tool has never been used
-- use tool once
t:set_wear(65535/(9*(uses - 1)))
else
-- set wear back
t:set_wear(w)
-- use tool once
if (uses ~= 0) then
t:add_wear(65535/(9*(uses - 1)))
end
end
-- add to craft inventory
craft_inv:add_item("craft", t)
end
end
end
end)
-- coconut milk using food_cutting_board from farming redo
if minetest.registered_items["farming:cutting_board"] then
minetest.register_craft({
type = "shapeless",
output = "moretrees:coconut_milk",
recipe = {
"moretrees:coconut",
"vessels:drinking_glass",
"group:food_cutting_board",
},
replacements = {
{ "moretrees:coconut", "moretrees:raw_coconut" },
{ "group:food_cutting_board", "farming:cutting_board" },
}
})
end
minetest.register_craft({
type = "shapeless",
output = "moretrees:date_nut_snack",
recipe = {
"moretrees:date",
"moretrees:date",
"moretrees:date",
"moretrees:spruce_nuts",
"moretrees:cedar_nuts",
"moretrees:fir_nuts",
}
})
-- The date-nut cake is an exceptional food item due to its highly
-- concentrated nature (32 food units). Because of that, it requires
-- many different ingredients, and, starting from the base ingredients
-- found or harvested in nature, it requires many steps to prepare.
local flour
if minetest.registered_nodes["farming:flour"] then
flour = "farming:flour"
else
flour = "moretrees:acorn_muffin_batter"
end
minetest.register_craft({
type = "shapeless",
output = "moretrees:date_nut_batter",
recipe = {
"moretrees:date_nut_snack",
"moretrees:date_nut_snack",
"moretrees:date_nut_snack",
"moretrees:coconut_milk",
"moretrees:date_nut_snack",
"moretrees:raw_coconut",
"moretrees:coconut_milk",
flour,
"moretrees:raw_coconut",
},
replacements = {
{ "moretrees:coconut_milk", "vessels:drinking_glass 2" }
}
})
minetest.register_craft({
type = "cooking",
output = "moretrees:date_nut_cake",
recipe = "moretrees:date_nut_batter",
})
minetest.register_craft({
type = "shapeless",
output = "moretrees:date_nut_bar 8",
recipe = {"moretrees:date_nut_cake"},
})
minetest.register_craft({
type = "shapeless",
output = "moretrees:acorn_muffin_batter",
recipe = {
"moretrees:acorn",
"moretrees:acorn",
"moretrees:acorn",
"moretrees:acorn",
"moretrees:coconut_milk",
},
replacements = {
{ "moretrees:coconut_milk", "vessels:drinking_glass" }
}
})
minetest.register_craft({
type = "cooking",
output = "moretrees:acorn_muffin 4",
recipe = "moretrees:acorn_muffin_batter",
})
minetest.register_craft({
type = "cooking",
output = "moretrees:spruce_nuts 4",
recipe = "moretrees:spruce_cone",
})
minetest.register_craft({
type = "cooking",
output = "moretrees:cedar_nuts 4",
recipe = "moretrees:cedar_cone",
})
minetest.register_craft({
type = "cooking",
output = "moretrees:fir_nuts 4",
recipe = "moretrees:fir_cone",
})

View File

@ -0,0 +1,762 @@
-- Date palms.
--
-- Date palms grow in hot and dry desert, but they require water. This makes them
-- a bit harder to find. If found in the middle of the desert, their presence
-- indicates a water source below the surface.
--
-- As an additional feature (which can be disabled), dates automatically regrow after
-- harvesting (provided a male tree is sufficiently nearby).
-- If regrowing is enabled, then ripe dates will not hang forever. Most will disappear
-- (e.g. eaten by birds, ...), and a small fraction will drop as items.
-- © 2016, Rogier <rogier777@gmail.com>
local S = minetest.get_translator("moretrees")
-- Some constants
local dates_drop_ichance = 4
local stems_drop_ichance = 4
local flowers_wither_ichance = 3
-- implementation
local dates_regrow_prob
if moretrees.dates_regrow_unpollinated_percent <= 0 then
dates_regrow_prob = 0
elseif moretrees.dates_regrow_unpollinated_percent >= 100 then
dates_regrow_prob = 1
else
dates_regrow_prob = 1 - math.pow(moretrees.dates_regrow_unpollinated_percent/100, 1/flowers_wither_ichance)
end
-- Make the date palm fruit trunk a real trunk (it is generated as a fruit)
local trunk = minetest.registered_nodes["moretrees:date_palm_trunk"]
local ftrunk = {}
local fftrunk = {}
local mftrunk = {}
for k,v in pairs(trunk) do
ftrunk[k] = v
end
ftrunk.tiles = {}
for k,v in pairs(trunk.tiles) do
ftrunk.tiles[k] = v
end
ftrunk.drop = "moretrees:date_palm_trunk"
ftrunk.after_destruct = function(pos, oldnode)
local dates = minetest.find_nodes_in_area(
{x=pos.x-2, y=pos.y, z=pos.z-2},
{x=pos.x+2, y=pos.y, z=pos.z+2},
{"group:moretrees_dates"}
)
for _,datespos in pairs(dates) do
-- minetest.dig_node(datespos) does not cause nearby dates to be dropped :-( ...
local items = minetest.get_node_drops(minetest.get_node(datespos).name)
minetest.swap_node(datespos, biome_lib.air)
for _, itemname in pairs(items) do
minetest.add_item(datespos, itemname)
end
end
end
for k,v in pairs(ftrunk) do
mftrunk[k] = v
fftrunk[k] = v
end
fftrunk.tiles = {}
mftrunk.tiles = {}
for k,v in pairs(trunk.tiles) do
fftrunk.tiles[k] = v
mftrunk.tiles[k] = v
end
-- Make the different types of trunk distinguishable (but not too easily)
ftrunk.tiles[1] = "moretrees_date_palm_trunk_top.png^[transformR180"
ftrunk.description = ftrunk.description.." (gen)"
fftrunk.tiles[1] = "moretrees_date_palm_trunk_top.png^[transformR90"
mftrunk.tiles[1] = "moretrees_date_palm_trunk_top.png^[transformR-90"
minetest.register_node("moretrees:date_palm_fruit_trunk", ftrunk)
minetest.register_node("moretrees:date_palm_ffruit_trunk", fftrunk)
minetest.register_node("moretrees:date_palm_mfruit_trunk", mftrunk)
-- ABM to grow new date blossoms
local date_regrow_abm_spec = {
nodenames = { "moretrees:date_palm_ffruit_trunk", "moretrees:date_palm_mfruit_trunk" },
interval = moretrees.dates_flower_interval,
chance = moretrees.dates_flower_chance,
action = function(pos, node, active_object_count, active_object_count_wider)
local dates = minetest.find_nodes_in_area({x=pos.x-2, y=pos.y, z=pos.z-2}, {x=pos.x+2, y=pos.y, z=pos.z+2}, "group:moretrees_dates")
-- New blossom interval increases exponentially with number of dates already hanging
-- In addition: if more dates are hanging, the chance of picking an empty spot decreases as well...
if math.random(2^#dates) <= 2 then
-- Grow in area of 5x5 round trunk; higher probability in 3x3 area close to trunk
local dx=math.floor((math.random(50)-18)/16)
local dz=math.floor((math.random(50)-18)/16)
local datepos = {x=pos.x+dx, y=pos.y, z=pos.z+dz}
local datenode = minetest.get_node(datepos)
if datenode.name == "air" then
if node.name == "moretrees:date_palm_ffruit_trunk" then
minetest.swap_node(datepos, {name="moretrees:dates_f0"})
else
minetest.swap_node(datepos, {name="moretrees:dates_m0"})
end
end
end
end
}
if moretrees.dates_regrow_pollinated or moretrees.dates_regrow_unpollinated_percent > 0 then
minetest.register_abm(date_regrow_abm_spec)
end
-- Choose male or female palm, and spawn initial dates
-- (Instead of dates, a dates fruit trunk is generated with the tree. This
-- ABM converts the trunk to a female or male fruit trunk, and spawns some
-- hanging dates)
minetest.register_abm({
nodenames = { "moretrees:date_palm_fruit_trunk" },
interval = 1,
chance = 1,
action = function(pos, node, active_object_count, active_object_count_wider)
local type
if math.random(100) <= moretrees.dates_female_percent then
type = "f"
minetest.swap_node(pos, {name="moretrees:date_palm_ffruit_trunk"})
else
type = "m"
minetest.swap_node(pos, {name="moretrees:date_palm_mfruit_trunk"})
end
local dates1 = 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},
"air"
)
for _,genpos in pairs(dates1) do
if math.random(100) <= 20 then
if type == "m" then
minetest.swap_node(genpos, {name = "moretrees:dates_n"})
else
minetest.swap_node(genpos, {name = "moretrees:dates_f4"})
end
end
end
local dates2 = minetest.find_nodes_in_area(
{x=pos.x-2, y=pos.y, z=pos.z-2},
{x=pos.x+2, y=pos.y, z=pos.z+2},
"air"
)
for _,genpos in pairs(dates2) do
if math.random(100) <= 5 then
if type == "m" then
minetest.swap_node(genpos, {name = "moretrees:dates_n"})
else
minetest.swap_node(genpos, {name = "moretrees:dates_f4"})
end
end
end
end,
})
-- Dates growing functions.
-- This is a bit complex, as the purpose is to find male flowers at horizontal distances of over
-- 100 nodes. As searching such a large area is time consuming, this is optimized in four ways:
-- - The search result (the locations of male trees) is cached, so that it can be used again
-- - Only 1/9th of the desired area is searched at a time. A new search is only performed if no male
-- flowers are found in the previously searched parts.
-- - Search results are shared with other female palms nearby.
-- - If previous searches for male palms have consumed too much CPU time, the search is skipped
-- (This means no male palms will be found, and the pollination of the flowers affected will be
-- delayed. If this happens repeatedly, eventually, the female flowers will wither...)
-- A caching method was selected that is suited for the case where most date trees are long-lived,
-- and where the number of trees nearby is limited:
-- - Locations of male palms are stored as metadata for every female palm. This means that a player
-- visiting a remote area with some date palms will not cause extensive searches for male palms as
-- long overdue blossoming ABMs are triggered for every date palm.
-- - Even when male palms *are* cut down, a cache refill will only be performed if the cached results do not
-- contain a male palm with blossoms.
-- The method will probably perform suboptimally:
-- - If female palms are frequently chopped down and replanted.
-- Freshly grown palms will need to search for male palms again
-- (this is mitigated by the long blossoming interval, which increases the chance that search
-- results have already been shared)
-- - If an area contains a large number of male and female palms.
-- In this area, every female palm will have an almost identical list of male palm locations
-- as metadata.
-- - If all male palms within range of a number of female palms have been chopped down (with possibly
-- new ones planted). Although an attempt was made to share search results in this case as well,
-- a number of similar searches will unavoidably be performed by the different female palms.
-- - If no male palms are in range of a female palm. In that case, there will be frequent searches
-- for newly-grown male palms.
-- Search statistics - used to limit the search load.
local sect_search_stats = {} -- Search statistics - server-wide
local function reset_sect_search_stats()
sect_search_stats.count = 0 -- # of searches
sect_search_stats.skip = 0 -- # of times skipped
sect_search_stats.sum = 0 -- total time spent
sect_search_stats.min = 999999999 -- min time spent
sect_search_stats.max = 0 -- max time spent
end
reset_sect_search_stats()
sect_search_stats.last_us = 0 -- last time a search was done (microseconds, max: 2^32)
sect_search_stats.last_s = 0 -- last time a search was done (system time in seconds)
-- Find male trunks in one section (=1/9 th) of the searchable area.
-- sect is -4 to 4, where 0 is the center section
local function find_fruit_trunks_near(ftpos, sect)
local r = moretrees.dates_pollination_distance + 2 * math.sqrt(2)
local sect_hr = math.floor(r / 3 + 0.9999)
local sect_vr = math.floor(r / 2 + 0.9999)
local t0us = minetest.get_us_time()
local t0s = os.time()
-- Compute elapsed time since last search.
-- Unfortunately, the time value wraps after about 71 minutes (2^32 microseconds),
-- so it must be corrected to obtain the actual elapsed time.
if t0us < sect_search_stats.last_us then
-- Correct a simple wraparound.
-- This is not sufficient, as the time value may have wrapped more than once...
sect_search_stats.last_us = sect_search_stats.last_us - 2^32
end
if t0s - sect_search_stats.last_s > 2^32/1000000 then
-- One additional correction is enough for our purposes.
-- For exact results, more corrections may be needed though...
-- (and even not applying this correction at all would still only yield
-- a minimal risk of a non-serious miscalculation...)
sect_search_stats.last_us = sect_search_stats.last_us - 2^32
end
-- Skip the search if it is consuming too much CPU time
if sect_search_stats.count > 0 and moretrees.dates_blossom_search_iload > 0
and sect_search_stats.sum / sect_search_stats.count > moretrees.dates_blossom_search_time_treshold
and t0us - sect_search_stats.last_us < moretrees.dates_blossom_search_iload * (sect_search_stats.sum / sect_search_stats.count) then
sect_search_stats.skip = sect_search_stats.skip + 1
return nil
end
local basevec = { x = ftpos.x + 2 * sect.x * sect_hr,
y = ftpos.y,
z = ftpos.z + 2 * sect.z * sect_hr}
-- find_nodes_in_area is limited to 82^3, make sure to not overrun it
local sizevec = { x = sect_hr, y = sect_vr, z = sect_hr }
if sect_hr * sect_hr * sect_vr > 41^3 then
sizevec = vector.apply(sizevec, function(a) return math.min(a, 41) end)
end
local all_palms = minetest.find_nodes_in_area(
vector.subtract(basevec, sizevec),
vector.add(basevec, sizevec),
{"moretrees:date_palm_mfruit_trunk", "moretrees:date_palm_ffruit_trunk"})
-- Collect different palms in separate lists.
local female_palms = {}
local male_palms = {}
local all_male_palms = {}
for _, pos in pairs(all_palms) do
if pos.x ~= ftpos.x or pos.y ~= ftpos.y or pos.z ~= ftpos.z then
local node = minetest.get_node(pos)
if node and node.name == "moretrees:date_palm_ffruit_trunk" then
table.insert(female_palms,pos)
elseif node then
table.insert(all_male_palms,pos)
-- In sector 0, all palms are of interest.
-- In other sectors, forget about palms that are too far away.
if sect == 0 then
table.insert(male_palms,pos)
else
local ssq = 0
for _, c in pairs({"x", "z"}) do
local dc = pos[c] - ftpos[c]
ssq = ssq + dc * dc
end
if math.sqrt(ssq) <= r then
table.insert(male_palms,pos)
end
end
end
end
end
-- Update search statistics
local t1us = minetest.get_us_time()
if t1us < t0us then
-- Wraparound. Assume the search lasted less than 2^32 microseconds (~71 min)
-- (so no need to apply another correction)
t0us = t0us - 2^32
end
sect_search_stats.last_us = t0us
sect_search_stats.last_s = t0s
sect_search_stats.count = sect_search_stats.count + 1
sect_search_stats.sum = sect_search_stats.sum + t1us-t0us
if t1us - t0us < sect_search_stats.min then
sect_search_stats.min = t1us - t0us
end
if t1us - t0us > sect_search_stats.max then
sect_search_stats.max = t1us - t0us
end
return male_palms, female_palms, all_male_palms
end
local function dates_print_search_stats(log)
local stats
if sect_search_stats.count > 0 then
stats = string.format("Male date tree searching stats: searches: %d/%d: average: %d µs (%d..%d)",
sect_search_stats.count, sect_search_stats.count + sect_search_stats.skip,
sect_search_stats.sum/sect_search_stats.count, sect_search_stats.min, sect_search_stats.max)
else
stats = string.format("Male date tree searching stats: searches: 0/0: average: (no searches yet)")
end
if log then
minetest.log("action", "[moretrees] " .. stats)
end
return true, stats
end
minetest.register_chatcommand("dates_stats", {
description = "Print male date palm search statistics",
params = "|chat|log|reset",
privs = { server = true },
func = function(name, param)
param = string.lower(param:gsub("%s+", ""))
if param == "" or param == "chat" then
return dates_print_search_stats(false)
elseif param == "log" then
return dates_print_search_stats(true)
elseif param == "reset" then
reset_sect_search_stats()
return true
else
return false, "Invalid subcommand; expected: '' or 'chat' or 'log' or 'reset'"
end
end,
})
-- Find the female trunk near the female flowers to be pollinated
local function find_female_trunk(fbpos)
local trunks = minetest.find_nodes_in_area({x=fbpos.x-2, y=fbpos.y, z=fbpos.z-2},
{x=fbpos.x+2, y=fbpos.y, z=fbpos.z+2},
"moretrees:date_palm_ffruit_trunk")
local ftpos
local d = 99
for x, pos in pairs(trunks) do
local ssq = 0
for _, c in pairs({"x", "z"}) do
local dc = pos[c] - fbpos[c]
ssq = ssq + dc * dc
end
if math.sqrt(ssq) < d then
ftpos = pos
d = math.sqrt(ssq)
end
end
return ftpos
end
-- Find male blossom near a male trunk,
-- the male blossom must be in range of a specific female blossom as well
local function find_male_blossom_near_trunk(fbpos, mtpos)
local r = moretrees.dates_pollination_distance
local blossoms = minetest.find_nodes_in_area({x=mtpos.x-2, y=mtpos.y, z=mtpos.z-2},
{x=mtpos.x+2, y=mtpos.y, z=mtpos.z+2},
"moretrees:dates_m0")
for x, mbpos in pairs(blossoms) do
local ssq = 0
for _, c in pairs({"x", "z"}) do
local dc = mbpos[c] - fbpos[c]
ssq = ssq + dc * dc
end
if math.sqrt(ssq) <= r then
return mbpos
end
end
end
-- Find a male blossom in range of a specific female blossom,
-- using a nested list of male blossom positions
local function find_male_blossom_in_mpalms(ftpos, fbpos, mpalms)
-- Process the elements of mpalms.sect (index -4 .. 4) in random order
-- First, compute the order in which the sectors will be searched
local sect_index = {}
local sect_rnd = {}
for i = -4,4 do
local n = math.random(1023)
sect_index[n] = i
table.insert(sect_rnd, n)
end
table.sort(sect_rnd)
-- Search the sectors
local sect_old = 0
local sect_time = minetest.get_gametime()
for _, n in pairs(sect_rnd) do
-- Record the oldest sector, so that it can be searched if no male
-- blossoms were found
if not mpalms.sect_time[sect_index[n]] then
sect_old = sect_index[n]
sect_time = 0
elseif mpalms.sect_time[sect_index[n]] < sect_time then
sect_old = sect_index[n]
sect_time = mpalms.sect_time[sect_index[n]]
end
if mpalms.sect[sect_index[n]] and #mpalms.sect[sect_index[n]] then
for px, mtpos in pairs(mpalms.sect[sect_index[n]]) do
local node = minetest.get_node(mtpos)
if node and node.name == "moretrees:date_palm_mfruit_trunk" then
local mbpos = find_male_blossom_near_trunk(fbpos, mtpos)
if mbpos then
return mbpos
end
elseif node and node.name ~= "ignore" then
-- no more male trunk here.
mpalms.sect[sect_index[n]][px] = nil
end
end
end
end
return nil, sect_old
end
-- Find a male blossom in range of a specific female blossom,
-- using the cache associated with the given female trunk
-- If necessary, recompute part of the cache
local last_search_result = {}
local function find_male_blossom_with_ftrunk(fbpos,ftpos)
local meta = minetest.get_meta(ftpos)
local mpalms
local cache_changed = true
-- Load cache. If distance has changed, start with empty cache instead.
local mpalms_dist = meta:get_int("male_palms_dist")
if mpalms_dist and mpalms_dist == moretrees.dates_pollination_distance then
mpalms = meta:get_string("male_palms")
if mpalms and mpalms ~= "" then
mpalms = minetest.deserialize(mpalms)
cache_changed = false
end
end
if not mpalms or not mpalms.sect then
mpalms = {}
mpalms.sect = {}
mpalms.sect_time = {}
meta:set_int("male_palms_dist", moretrees.dates_pollination_distance)
cache_changed = true
end
local fpalms_list
local all_mpalms_list
local sector0_searched = false
-- Always make sure that sector 0 is cached
if not mpalms.sect[0] then
mpalms.sect[0], fpalms_list, all_mpalms_list = find_fruit_trunks_near(ftpos, {x = 0, z = 0})
mpalms.sect_time[0] = minetest.get_gametime()
sector0_searched = true
cache_changed = true
last_search_result.female = fpalms_list
last_search_result.male = all_mpalms_list
end
-- Find male palms
local mbpos, sect_old = find_male_blossom_in_mpalms(ftpos, fbpos, mpalms)
-- If not found, (re)generate the cache for an additional sector. But don't search it yet (for performance reasons)
-- (Use the globally cached results if possible)
if not mbpos and not sector0_searched then
if not mpalms.sect_time[0] or mpalms.sect_time[0] == 0 or math.random(3) == 1 then
-- Higher probability of re-searching the center sector
sect_old = 0
end
-- Use globally cached result if possible
mpalms.sect[sect_old] = nil
if sect_old == 0 and mpalms.sect_time[0] and mpalms.sect_time[0] > 0
and last_search_result.male and #last_search_result.male then
for _, pos in pairs(last_search_result.female) do
if pos.x == ftpos.x and pos.y == ftpos.y and pos.z == ftpos.z then
mpalms.sect[sect_old] = last_search_result.male
-- Next time, don't use the cached result
mpalms.sect_time[sect_old] = nil
cache_changed = true
end
end
end
-- Else do a new search
if not mpalms.sect[sect_old] then
mpalms.sect[sect_old], fpalms_list, all_mpalms_list = find_fruit_trunks_near(ftpos, {x = (sect_old + 4) % 3 - 1, z = (sect_old + 4) / 3 - 1})
cache_changed = true
if sect_old == 0 then
-- Save the results if it is sector 0
-- (chance of reusing results from another sector are smaller)
last_search_result.female = fpalms_list
last_search_result.male = all_mpalms_list
end
if mpalms.sect[sect_old] then
mpalms.sect_time[sect_old] = minetest.get_gametime()
else
mpalms.sect_time[sect_old] = nil
end
end
end
-- Share search results with other female trunks in the same area
-- Note that the list of female trunks doesn't (shouldn't :-) contain the current female trunk.
if fpalms_list and #fpalms_list and #all_mpalms_list then
local all_mpalms = {}
all_mpalms.sect = {}
all_mpalms.sect_time = {}
all_mpalms.sect[0] = all_mpalms_list
-- Don't set sect_time[0], so that the cached sector will be re-searched soon (if necessary)
local all_mpalms_serialized = minetest.serialize(all_mpalms)
for _, pos in pairs(fpalms_list) do
local fmeta = minetest.get_meta(pos)
local fdist = fmeta:get_int("male_palms_dist")
if not fdist or fdist ~= moretrees.dates_pollination_distance then
fmeta:set_string("male_palms", all_mpalms_serialized)
fmeta:set_int("male_palms_dist", moretrees.dates_pollination_distance)
end
end
end
-- Save cache.
if cache_changed then
meta:set_string("male_palms", minetest.serialize(mpalms))
end
return mbpos
end
-- Find a male blossom in range of a specific female blossom
local function find_male_blossom(fbpos)
local ftpos = find_female_trunk(fbpos)
if ftpos then
return find_male_blossom_with_ftrunk(fbpos, ftpos)
end
return nil
end
-- Growing function for dates
local dates_growfn = function(pos, elapsed)
local node = minetest.get_node(pos)
local delay = moretrees.dates_grow_interval
local action
if not node then
return
elseif not moretrees.dates_regrow_pollinated and dates_regrow_prob == 0 then
-- Regrowing of dates is disabled.
if string.find(node.name, "moretrees:dates_f") then
minetest.swap_node(pos, {name="moretrees:dates_f4"})
elseif string.find(node.name, "moretrees:dates_m") then
minetest.swap_node(pos, {name="moretrees:dates_n"})
else
minetest.swap_node(pos, biome_lib.air)
end
return
elseif node.name == "moretrees:dates_f0" and math.random(100) <= 100 * dates_regrow_prob then
-- Dates grow unpollinated
minetest.swap_node(pos, {name="moretrees:dates_f1"})
action = "nopollinate"
elseif node.name == "moretrees:dates_f0" and moretrees.dates_regrow_pollinated and find_male_blossom(pos) then
-- Pollinate flowers
minetest.swap_node(pos, {name="moretrees:dates_f1"})
action = "pollinate"
elseif string.match(node.name, "0$") then
-- Make female unpollinated and male flowers last a bit longer
if math.random(flowers_wither_ichance) == 1 then
if node.name == "moretrees:dates_f0" then
minetest.swap_node(pos, {name="moretrees:dates_fn"})
else
minetest.swap_node(pos, {name="moretrees:dates_n"})
end
action = "wither"
else
action = "nowither"
end
elseif node.name == "moretrees:dates_f4" then
-- Remove dates, and optionally drop them as items
if math.random(dates_drop_ichance) == 1 then
if moretrees.dates_item_drop_ichance > 0 and math.random(moretrees.dates_item_drop_ichance) == 1 then
local items = minetest.get_node_drops(minetest.get_node(pos).name)
for _, itemname in pairs(items) do
minetest.add_item(pos, itemname)
end
end
minetest.swap_node(pos, {name="moretrees:dates_n"})
action = "drop"
else
action = "nodrop"
end
elseif string.match(node.name, "n$") then
-- Remove stems.
if math.random(stems_drop_ichance) == 1 then
minetest.swap_node(pos, biome_lib.air)
return "stemdrop"
end
action = "nostemdrop"
else
-- Grow dates
local offset = 18
local n = string.sub(node.name, offset)
minetest.swap_node(pos, {name=string.sub(node.name, 1, offset-1)..n+1})
action = "grow"
end
-- Don't catch up when elapsed time is large. Regular visits are needed for growth...
local timer = minetest.get_node_timer(pos)
timer:start(delay + math.random(moretrees.dates_grow_interval))
return action
end
--[[
-- Alternate growth function for dates.
-- It calls the primary growth function, but also measures CPU time consumed.
-- Use this function to analyze date growing performance.
local stat = {}
stat.count = 0
local dates_growfn_profiling = function(pos, elapsed)
local t0 = minetest.get_us_time()
local action = dates_growfn(pos, elapsed)
local t1 = minetest.get_us_time()
if t1 < t0 then
t1 = t1 + 2^32
end
stat.count = stat.count + 1
if not stat[action] then
stat[action] = {}
stat[action].count = 0
stat[action].sum = 0
stat[action].min = 9999999999
stat[action].max = 0
end
stat[action].count = stat[action].count + 1
stat[action].sum = stat[action].sum + t1-t0
if t1-t0 < stat[action].min then
stat[action].min = t1-t0
end
if t1-t0 > stat[action].max then
stat[action].max = t1-t0
end
if stat.count % 10 == 0 then
io.write(".")
io.flush()
end
if stat.count % 100 == 0 then
print(string.format("Date grow statistics %5d:", stat.count))
local sum = 0
local count = 0
if sect_search_stats.count > 0 and stat.pollinate and stat.pollinate.count > 0 then
print(string.format("\t%-12s: %6d (%4.1f%%): %6dus (%d..%d)",
"search", sect_search_stats.count,
100*sect_search_stats.count/stat.pollinate.count,
sect_search_stats.sum/sect_search_stats.count,
sect_search_stats.min, sect_search_stats.max))
else
print(string.format("\t%-12s: %6d (%4.1f%%): %6dus (%d..%d)",
"search", sect_search_stats.count,
0, 0, 0, 0))
end
for action,data in pairs(stat) do
if action ~= "count" then
count = count + data.count
sum = sum + data.sum
print(string.format("\t%-12s: %6d (%4.1f%%): %6dus (%d..%d)",
action, data.count,
100*data.count/stat.count, data.sum/data.count,
data.min, data.max))
end
end
print(string.format("\t%-12s: %6d ( 100%%): %6dus",
"TOTAL", count, sum/count))
end
end
--]]
-- Register dates
local dates_starttimer = function(pos, elapsed)
local timer = minetest.get_node_timer(pos)
local base_interval = moretrees.dates_grow_interval * 2 / 3
timer:set(base_interval + math.random(base_interval), elapsed or 0)
end
local dates_drop = {
items = {
{items = { "moretrees:date" }},
{items = { "moretrees:date" }},
{items = { "moretrees:date" }},
{items = { "moretrees:date" }},
{items = { "moretrees:date" }, rarity = 2 },
{items = { "moretrees:date" }, rarity = 2 },
{items = { "moretrees:date" }, rarity = 2 },
{items = { "moretrees:date" }, rarity = 2 },
{items = { "moretrees:date" }, rarity = 5 },
{items = { "moretrees:date" }, rarity = 5 },
{items = { "moretrees:date" }, rarity = 5 },
{items = { "moretrees:date" }, rarity = 5 },
{items = { "moretrees:date" }, rarity = 20 },
{items = { "moretrees:date" }, rarity = 20 },
{items = { "moretrees:date" }, rarity = 20 },
{items = { "moretrees:date" }, rarity = 20 },
}
}
for _,suffix in ipairs({"f0", "f1", "f2", "f3", "f4", "m0", "fn", "n"}) do
local name
if suffix == "f0" or suffix == "m0" then
name = S("Date Flowers")
elseif suffix == "n" or suffix == "fn" then
name = S("Date Stem")
else
name = S("Dates")
end
local dropfn = suffix == "f4" and dates_drop or ""
local datedef = {
description = name,
tiles = {"moretrees_dates_"..suffix..".png"},
visual_scale = 2,
drawtype = "plantlike",
paramtype = "light",
sunlight_propagates = true,
walkable = false,
groups = { fleshy=3, dig_immediate=3, flammable=2, moretrees_dates=1 },
inventory_image = "moretrees_dates_"..suffix..".png^[transformR0",
wield_image = "moretrees_dates_"..suffix..".png^[transformR90",
sounds = default.node_sound_defaults(),
drop = dropfn,
selection_box = {
type = "fixed",
fixed = {-0.3, -0.3, -0.3, 0.3, 3.5, 0.3}
},
on_timer = dates_growfn,
on_construct = (moretrees.dates_regrow_pollinated or moretrees.dates_regrow_unpollinated_percent > 0)
and dates_starttimer,
}
minetest.register_node("moretrees:dates_"..suffix, datedef)
end
-- If regrowing was previously disabled, but is enabled now, make sure timers are started for existing dates
if moretrees.dates_regrow_pollinated or moretrees.dates_regrow_unpollinated_percent > 0 then
local spec = {
name = "moretrees:restart_dates_regrow_timer",
nodenames = "group:moretrees_dates",
action = function(pos, node, active_object_count, active_object_count_wider)
local timer = minetest.get_node_timer(pos)
if not timer:is_started() then
dates_starttimer(pos)
else
local timeout = timer:get_timeout()
local elapsed = timer:get_elapsed()
if timeout - elapsed > moretrees.dates_grow_interval * 4/3 then
dates_starttimer(pos, math.random(moretrees.dates_grow_interval * 4/3))
end
end
end,
}
if minetest.register_lbm then
minetest.register_lbm(spec)
else
spec.interval = 3557
spec.chance = 10
minetest.register_abm(spec)
end
end

View File

@ -0,0 +1,135 @@
-- Global configuration variables
-- Enable the various kinds of trees.
moretrees.enable_apple_tree = true
moretrees.enable_oak = true
moretrees.enable_sequoia = true
moretrees.enable_palm = true
moretrees.enable_date_palm = true
moretrees.enable_cedar = true
moretrees.enable_rubber_tree = true
moretrees.enable_willow = true
moretrees.enable_birch = true
moretrees.enable_spruce = true
moretrees.enable_jungle_tree = true
moretrees.enable_fir = true
moretrees.enable_poplar = true
moretrees.enable_beech = false
-- set this to true to make moretrees spawn saplings at mapgen time instead
-- of fully-grown trees, which will grow into full trees after a very short
-- delay. This reduces mapgen lag in some situations, and fixes situations
-- where the mapgen conflicts with the tree generator.
moretrees.spawn_saplings = true
-- Set this to true to allow defining stairs/slabs/etc. If Moreblocks is
-- installed, this will use that mod's Stairs Plus component. Otherwise, it
-- will use the default stairs mod in minetest_game, if present
moretrees.enable_stairs = true
-- If this variable is set to true, register fences for moretrees wood
moretrees.enable_fences = false
-- Set this to true if you want the plantlike drawtype for leaves, which
-- improves some peoples' framerates without resorting to making leaf nodes opaque.
-- Affects default leaves and default jungle leaves also.
moretrees.plantlike_leaves = false
-- Enable this if you want moretrees to redefine default apples so that they
-- fall when leaves decay/are dug.
moretrees.enable_redefine_apple = true
-- Set this to true to enable leaf decay of all trees except the default ones.
moretrees.enable_leafdecay = true
-- various related settings to configure leaf decay.
moretrees.leafdecay_delay = 2
moretrees.leafdecay_chance = 5
moretrees.leafdecay_radius = 5
moretrees.palm_leafdecay_radius = 10
-- Change these settings if you want default trees to be gradually cut down
-- above the elevation where firs normally generate.
moretrees.firs_remove_default_trees = false
moretrees.firs_remove_interval = 2
moretrees.firs_remove_chance = 150
-- Cocos palm settings
moretrees.coconuts_regrow = true
moretrees.coconuts_convert_existing_palms = true -- Converting existing palm trees will make coconuts regrow on them as well
-- Else, they will only regrow on newly-spawned palms
-- However, conversion is not an exact science, and although an attempt is
-- made to detect whether a trunk belongs to an actual palm, some coconut trunks
-- and some coconuts may be incorrectly converted.
moretrees.coconut_flower_interval = 59
moretrees.coconut_flower_chance = 67
moretrees.coconut_grow_interval = 2 * moretrees.coconut_flower_interval * moretrees.coconut_flower_chance
-- Actual interval will randomly vary between 67% and 133% of this value
-- 2 * 59 * 67 ~ 2 hours. So flowers become coconuts in about 6 hours
moretrees.coconut_item_drop_ichance = 10 -- inverse probability of ripe coconuts dropping as items (instead of disappearing)
-- Date palm settings
-- Suggested configuration alternatives:
-- - Dates grow only when pollinated:
-- - Set dates_regrow_pollinated to true
-- - Set dates_regrow_unpollinated_percent to 0
-- - Dates grow without pollination. Pollination disabled:
-- - Set dates_regrow_pollinated to false
-- - Set dates_regrow_unpollinated_percent to some larger positive value, e.g. 95
-- - Dates grow, but more and faster if male flowers are nearby
-- - Set dates_regrow_pollinated to true
-- - Set dates_regrow_unpollinated_percent to some small positive value, e.g. 33
-- - Optional but recommended: Reduce the pollination distance, e.g. to 30
-- Note that it should not be necessary to disable pollination for performance
-- reasons. A lot of effort has gone into ensuring that date growing will not cause lag.
--
-- If lag is suspected, use the chat command '/dates_stats' to obtain the male dates
-- search time, as well as the counts of total number of searches requested and the
-- number of searches actually performed.
moretrees.dates_regrow_pollinated = true -- Enable pollination. If enabled, male trees are required for dates to grow.
-- If disabled, dates_regrow_unpollinated_percent must be non-zero for dates to regrow.
moretrees.dates_regrow_unpollinated_percent = 0 -- Percentage of female dates becoming dates without being pollinated.
-- If 0, dates_regrow_pollinated must be enabled for dates to grow.
moretrees.dates_female_percent = 57 -- Ratio of female to male trees - tune this to improve # of generated trees that actually bear fruit
-- ~57% gives near optimal results for groups of 3 random trees, while it is only slightly suboptimal
-- for groups of 2 and 4 random trees (~2% less fruit than optimal).
-- Optimal values per group size: 2: 50%, 3: 57.78%, 4: 63%, 5: 66.9%, 6: 69.9%, [...], 12: 79.8%
-- So 57% is optimal for small groups of trees. As larger groups have more female palms anyway, a
-- less than optimal proportion of female to male trees is not a problem.
moretrees.dates_pollination_distance = 120
moretrees.dates_blossom_search_time_treshold = 1000 -- If average male blossom search time (in microseconds) exceeds this, start limiting the search load.
moretrees.dates_blossom_search_iload = 10 -- Inverse fraction of CPU time that male blossom searching search may consume.
-- As searching a large area (radius: dates_pollination_distance/3 per attempt) can cause lag,
-- this limits the search frequency server-wide so that the impact on server lag is minimised
-- For personal servers, this can be set lower, or even to 1 or 0 (0 disables load limiting).
-- Obtain the current average search time using /dates_stats
moretrees.dates_flower_interval = 59
moretrees.dates_flower_chance = 181
moretrees.dates_grow_interval = 2 * moretrees.dates_flower_interval * moretrees.dates_flower_chance
-- As date palms have a high yield, don't grow dates too fast
-- The actual interval will vary randomly between 67% and 133% of this value.
-- 2 * 59 * 181 ~ 6 hours. So by default flowers become dates in about one (human) day.
moretrees.dates_item_drop_ichance = 10 -- inverse probability of ripe dates dropping as items (instead of disappearing)
-- Sapling settings
moretrees.sapling_interval = 100
moretrees.sapling_chance = 5
-- If this variable is set to true, drop leaves out as entities during leaf
-- decay, rather than just disappearing them.
moretrees.decay_leaves_as_items = false

329
mods/moretrees/init.lua Normal file
View File

@ -0,0 +1,329 @@
-- More trees! 2013-04-07
--
-- This mod adds more types of trees to the game
--
-- Some of the node definitions and textures came from cisoun's conifers mod
-- and bas080's jungle trees mod.
--
-- Brought together into one mod and made L-systems compatible by Vanessa
-- Ezekowitz.
--
-- Firs and Jungle tree axioms/rules by Vanessa Dannenberg, with the
-- latter having been tweaked by RealBadAngel, most other axioms/rules written
-- by RealBadAngel.
--
moretrees = {}
minetest.override_item("default:sapling", {
description = "Sapling"
})
minetest.override_item("default:tree", {
description = "Tree"
})
minetest.override_item("default:wood", {
description = "Wooden Planks"
})
minetest.override_item("default:leaves", {
description = "Leaves"
})
minetest.override_item("default:fence_wood", {
description = "Wooden Fence"
})
minetest.override_item("default:fence_rail_wood", {
description = "Wooden Fence Rail"
})
if minetest.get_modpath("doors") then
minetest.override_item("doors:gate_wood_closed", {
description = "Wooden Fence Gate"
})
minetest.override_item("doors:gate_wood_open", {
description = "Wooden Fence Gate"
})
end
-- Read the default config file (and if necessary, copy it to the world folder).
local worldpath=minetest.get_worldpath()
local modpath=minetest.get_modpath("moretrees")
dofile(modpath.."/default_settings.txt")
if io.open(worldpath.."/moretrees_settings.txt","r") then
io.close()
dofile(worldpath.."/moretrees_settings.txt")
end
-- infinite stacks checking
if minetest.get_modpath("unified_inventory") or not
minetest.settings:get_bool("creative_mode") then
moretrees.expect_infinite_stacks = false
else
moretrees.expect_infinite_stacks = true
end
-- tables, load other files
moretrees.cutting_tools = {
"default:axe_bronze",
"default:axe_diamond",
"default:axe_mese",
"default:axe_steel",
"glooptest:axe_alatro",
"glooptest:axe_arol",
"moreores:axe_mithril",
"moreores:axe_silver",
"titanium:axe",
}
dofile(modpath.."/tree_models.lua")
dofile(modpath.."/node_defs.lua")
dofile(modpath.."/date_palm.lua")
dofile(modpath.."/cocos_palm.lua")
dofile(modpath.."/biome_defs.lua")
dofile(modpath.."/saplings.lua")
dofile(modpath.."/crafts.lua")
-- tree spawning setup
if moretrees.spawn_saplings then
moretrees.spawn_beech_object = "moretrees:beech_sapling_ongen"
moretrees.spawn_apple_tree_object = "moretrees:apple_tree_sapling_ongen"
moretrees.spawn_oak_object = "moretrees:oak_sapling_ongen"
moretrees.spawn_sequoia_object = "moretrees:sequoia_sapling_ongen"
moretrees.spawn_palm_object = "moretrees:palm_sapling_ongen"
moretrees.spawn_date_palm_object = "moretrees:date_palm_sapling_ongen"
moretrees.spawn_cedar_object = "moretrees:cedar_sapling_ongen"
moretrees.spawn_rubber_tree_object = "moretrees:rubber_tree_sapling_ongen"
moretrees.spawn_willow_object = "moretrees:willow_sapling_ongen"
moretrees.spawn_birch_object = "moretrees:birch_sapling_ongen"
moretrees.spawn_spruce_object = "moretrees:spruce_sapling_ongen"
moretrees.spawn_jungletree_object = "moretrees:jungletree_sapling_ongen"
moretrees.spawn_fir_object = "moretrees:fir_sapling_ongen"
moretrees.spawn_fir_snow_object = "snow:sapling_pine"
moretrees.spawn_poplar_object = "moretrees:poplar_sapling_ongen"
moretrees.spawn_poplar_small_object = "moretrees:poplar_small_sapling_ongen"
else
moretrees.spawn_beech_object = moretrees.beech_model
moretrees.spawn_apple_tree_object = moretrees.apple_tree_model
moretrees.spawn_oak_object = moretrees.oak_model
moretrees.spawn_sequoia_object = moretrees.sequoia_model
moretrees.spawn_palm_object = moretrees.palm_model
moretrees.spawn_date_palm_object = moretrees.date_palm_model
moretrees.spawn_cedar_object = moretrees.cedar_model
moretrees.spawn_rubber_tree_object = moretrees.rubber_tree_model
moretrees.spawn_willow_object = moretrees.willow_model
moretrees.spawn_birch_object = "moretrees.grow_birch"
moretrees.spawn_spruce_object = "moretrees.grow_spruce"
moretrees.spawn_jungletree_object = "moretrees.grow_jungletree"
moretrees.spawn_fir_object = "moretrees.grow_fir"
moretrees.spawn_fir_snow_object = "moretrees.grow_fir_snow"
moretrees.spawn_poplar_object = moretrees.poplar_model
moretrees.spawn_poplar_small_object = moretrees.poplar_small_model
end
if moretrees.enable_beech then
biome_lib:register_generate_plant(moretrees.beech_biome, moretrees.spawn_beech_object)
end
if moretrees.enable_apple_tree then
biome_lib:register_generate_plant(moretrees.apple_tree_biome, moretrees.spawn_apple_tree_object)
end
if moretrees.enable_oak then
biome_lib:register_generate_plant(moretrees.oak_biome, moretrees.spawn_oak_object)
end
if moretrees.enable_sequoia then
biome_lib:register_generate_plant(moretrees.sequoia_biome, moretrees.spawn_sequoia_object)
end
if moretrees.enable_palm then
biome_lib:register_generate_plant(moretrees.palm_biome, moretrees.spawn_palm_object)
end
if moretrees.enable_date_palm then
biome_lib:register_generate_plant(moretrees.date_palm_biome, moretrees.spawn_date_palm_object)
biome_lib:register_generate_plant(moretrees.date_palm_biome_2, moretrees.spawn_date_palm_object)
end
if moretrees.enable_cedar then
biome_lib:register_generate_plant(moretrees.cedar_biome, moretrees.spawn_cedar_object)
end
if moretrees.enable_rubber_tree then
biome_lib:register_generate_plant(moretrees.rubber_tree_biome, moretrees.spawn_rubber_tree_object)
end
if moretrees.enable_willow then
biome_lib:register_generate_plant(moretrees.willow_biome, moretrees.spawn_willow_object)
end
if moretrees.enable_birch then
biome_lib:register_generate_plant(moretrees.birch_biome, moretrees.spawn_birch_object)
end
if moretrees.enable_spruce then
biome_lib:register_generate_plant(moretrees.spruce_biome, moretrees.spawn_spruce_object)
end
if moretrees.enable_jungle_tree then
biome_lib:register_generate_plant(moretrees.jungletree_biome, moretrees.spawn_jungletree_object)
end
if moretrees.enable_fir then
biome_lib:register_generate_plant(moretrees.fir_biome, moretrees.spawn_fir_object)
if minetest.get_modpath("snow") then
biome_lib:register_generate_plant(moretrees.fir_biome_snow, moretrees.spawn_fir_snow_object)
end
end
if moretrees.enable_poplar then
biome_lib:register_generate_plant(moretrees.poplar_biome, moretrees.spawn_poplar_object)
biome_lib:register_generate_plant(moretrees.poplar_biome_2, moretrees.spawn_poplar_object)
biome_lib:register_generate_plant(moretrees.poplar_biome_3, moretrees.spawn_poplar_object)
biome_lib:register_generate_plant(moretrees.poplar_small_biome, moretrees.spawn_poplar_small_object)
biome_lib:register_generate_plant(moretrees.poplar_small_biome_2, moretrees.spawn_poplar_small_object)
end
-- Code to spawn a birch tree
function moretrees.grow_birch(pos)
minetest.swap_node(pos, biome_lib.air)
if math.random(1,2) == 1 then
minetest.spawn_tree(pos, moretrees.birch_model1)
else
minetest.spawn_tree(pos, moretrees.birch_model2)
end
end
-- Code to spawn a spruce tree
function moretrees.grow_spruce(pos)
minetest.swap_node(pos, biome_lib.air)
if math.random(1,2) == 1 then
minetest.spawn_tree(pos, moretrees.spruce_model1)
else
minetest.spawn_tree(pos, moretrees.spruce_model2)
end
end
-- Code to spawn jungle trees
moretrees.jt_axiom1 = "FFFA"
moretrees.jt_rules_a1 = "FFF[&&-FBf[&&&Ff]^^^Ff][&&+FBFf[&&&FFf]^^^Ff][&&---FBFf[&&&Ff]^^^Ff][&&+++FBFf[&&&Ff]^^^Ff]F/A"
moretrees.jt_rules_b1 = "[-Ff&f][+Ff&f]B"
moretrees.jt_axiom2 = "FFFFFA"
moretrees.jt_rules_a2 = "FFFFF[&&-FFFBF[&&&FFff]^^^FFf][&&+FFFBFF[&&&FFff]^^^FFf][&&---FFFBFF[&&&FFff]^^^FFf][&&+++FFFBFF[&&&FFff]^^^FFf]FF/A"
moretrees.jt_rules_b2 = "[-FFf&ff][+FFf&ff]B"
moretrees.ct_rules_a1 = "FF[FF][&&-FBF][&&+FBF][&&---FBF][&&+++FBF]F/A"
moretrees.ct_rules_b1 = "[-FBf][+FBf]"
moretrees.ct_rules_a2 = "FF[FF][&&-FBF][&&+FBF][&&---FBF][&&+++FBF]F/A"
moretrees.ct_rules_b2 = "[-fB][+fB]"
function moretrees.grow_jungletree(pos)
local r1 = math.random(2)
local r2 = math.random(3)
if r1 == 1 then
moretrees.jungletree_model.leaves2 = "moretrees:jungletree_leaves_red"
else
moretrees.jungletree_model.leaves2 = "moretrees:jungletree_leaves_yellow"
end
moretrees.jungletree_model.leaves2_chance = math.random(25, 75)
if r2 == 1 then
moretrees.jungletree_model.trunk_type = "single"
moretrees.jungletree_model.iterations = 2
moretrees.jungletree_model.axiom = moretrees.jt_axiom1
moretrees.jungletree_model.rules_a = moretrees.jt_rules_a1
moretrees.jungletree_model.rules_b = moretrees.jt_rules_b1
elseif r2 == 2 then
moretrees.jungletree_model.trunk_type = "double"
moretrees.jungletree_model.iterations = 4
moretrees.jungletree_model.axiom = moretrees.jt_axiom2
moretrees.jungletree_model.rules_a = moretrees.jt_rules_a2
moretrees.jungletree_model.rules_b = moretrees.jt_rules_b2
elseif r2 == 3 then
moretrees.jungletree_model.trunk_type = "crossed"
moretrees.jungletree_model.iterations = 4
moretrees.jungletree_model.axiom = moretrees.jt_axiom2
moretrees.jungletree_model.rules_a = moretrees.jt_rules_a2
moretrees.jungletree_model.rules_b = moretrees.jt_rules_b2
end
minetest.swap_node(pos, biome_lib.air)
local leaves = minetest.find_nodes_in_area({x = pos.x-1, y = pos.y, z = pos.z-1}, {x = pos.x+1, y = pos.y+10, z = pos.z+1}, "default:leaves")
for leaf in ipairs(leaves) do
minetest.swap_node(leaves[leaf], biome_lib.air)
end
minetest.spawn_tree(pos, moretrees.jungletree_model)
end
-- code to spawn fir trees
function moretrees.grow_fir(pos)
if math.random(2) == 1 then
moretrees.fir_model.leaves="moretrees:fir_leaves"
else
moretrees.fir_model.leaves="moretrees:fir_leaves_bright"
end
if math.random(2) == 1 then
moretrees.fir_model.rules_a = moretrees.ct_rules_a1
moretrees.fir_model.rules_b = moretrees.ct_rules_b1
else
moretrees.fir_model.rules_a = moretrees.ct_rules_a2
moretrees.fir_model.rules_b = moretrees.ct_rules_b2
end
moretrees.fir_model.iterations = 7
moretrees.fir_model.random_level = 5
minetest.swap_node(pos, biome_lib.air)
local leaves = minetest.find_nodes_in_area({x = pos.x, y = pos.y, z = pos.z}, {x = pos.x, y = pos.y+5, z = pos.z}, "default:leaves")
for leaf in ipairs(leaves) do
minetest.swap_node(leaves[leaf], biome_lib.air)
end
minetest.spawn_tree(pos,moretrees.fir_model)
end
-- same thing, but a smaller version that grows only in snow biomes
function moretrees.grow_fir_snow(pos)
if math.random(2) == 1 then
moretrees.fir_model.leaves="moretrees:fir_leaves"
else
moretrees.fir_model.leaves="moretrees:fir_leaves_bright"
end
if math.random(2) == 1 then
moretrees.fir_model.rules_a = moretrees.ct_rules_a1
moretrees.fir_model.rules_b = moretrees.ct_rules_b1
else
moretrees.fir_model.rules_a = moretrees.ct_rules_a2
moretrees.fir_model.rules_b = moretrees.ct_rules_b2
end
moretrees.fir_model.iterations = 2
moretrees.fir_model.random_level = 2
minetest.swap_node(pos, biome_lib.air)
local leaves = minetest.find_nodes_in_area({x = pos.x, y = pos.y, z = pos.z}, {x = pos.x, y = pos.y+5, z = pos.z}, "default:leaves")
for leaf in ipairs(leaves) do
minetest.swap_node(leaves[leaf], biome_lib.air)
end
minetest.spawn_tree(pos,moretrees.fir_model)
end
print("[Moretrees] Loaded (2013-02-11)")

View File

@ -0,0 +1,211 @@
# textdomain: moretrees
# Translation by Xanthin
### cocos_palm.lua ###
Coconut=Kokosnuss
Coconut Flower=
### crafts.lua ###
Acorn Muffin=Eichelmuffin
Acorn Muffin batter=Eichelmuffinteig
Coconut Milk=Kokosnussmilch
Date=
Date & nut snack=
Date-nut cake=
Date-nut cake batter=
Date-nut energy bar=
Raw Coconut=Kokosnussfleisch
Roasted Cedar Cone Nuts=
Roasted Fir Cone Nuts=Geroestete Tannenzapfen
Roasted Spruce Cone Nuts=Geroestete Fichtenzapfen
### date_palm.lua ###
Date Flowers=
Date Stem=
Dates=
### node_defs.lua ###
@1 (fast growth)=
Acorn=Eichel
Apple Tree=
Apple Tree Fence=
Apple Tree Fence Gate=
Apple Tree Fence Rail=
Apple Tree Leaves=Apfelbaumlaub
Apple Tree Planks=Apfelbaumbretter
Apple Tree Planks Slab=
Apple Tree Planks Stair=
Apple Tree Sapling=Apfelbaumsetzling
Apple Tree Trunk=Apfelbaumstamm
Apple Tree Trunk Slab=
Apple Tree Trunk Stair=
Beech Tree=
Beech Tree Fence=
Beech Tree Fence Gate=
Beech Tree Fence Rail=
Beech Tree Leaves=Buchenlaub
Beech Tree Planks=Buchebretter
Beech Tree Planks Slab=
Beech Tree Planks Stair=
Beech Tree Sapling=Buchesetzling
Beech Tree Trunk=Buchenstamm
Beech Tree Trunk Slab=
Beech Tree Trunk Stair=
Birch Tree=
Birch Tree Fence=
Birch Tree Fence Gate=
Birch Tree Fence Rail=
Birch Tree Leaves=Birkenlaub
Birch Tree Planks=Birkebretter
Birch Tree Planks Slab=
Birch Tree Planks Stair=
Birch Tree Sapling=Birkensetzling
Birch Tree Trunk=Birkenstamm
Birch Tree Trunk Slab=
Birch Tree Trunk Stair=
Cedar Cone=
Cedar Tree=
Cedar Tree Fence=
Cedar Tree Fence Gate=
Cedar Tree Fence Rail=
Cedar Tree Leaves=
Cedar Tree Planks=
Cedar Tree Planks Slab=
Cedar Tree Planks Stair=
Cedar Tree Sapling=
Cedar Tree Trunk=
Cedar Tree Trunk Slab=
Cedar Tree Trunk Stair=
Date Palm Tree=
Date Palm Tree Fence=
Date Palm Tree Fence Gate=
Date Palm Tree Fence Rail=
Date Palm Tree Leaves=
Date Palm Tree Planks=
Date Palm Tree Planks Slab=
Date Palm Tree Planks Stair=
Date Palm Tree Sapling=
Date Palm Tree Trunk=
Date Palm Tree Trunk Slab=
Date Palm Tree Trunk Stair=
Douglas Fir=
Douglas Fir Fence=
Douglas Fir Fence Gate=
Douglas Fir Fence Rail=
Douglas Fir Leaves=Douglasiennadeln
Douglas Fir Leaves (Bright)=Douglasiennadeln (breit)
Douglas Fir Planks=Douglasienbretter
Douglas Fir Planks Slab=
Douglas Fir Planks Stair=
Douglas Fir Sapling=Douglasiensetzling
Douglas Fir Trunk=Douglasienstamm
Douglas Fir Trunk Slab=
Douglas Fir Trunk Stair=
Fir Cone=Tannenzapfen
Giant Sequoia=
Giant Sequoia Fence=
Giant Sequoia Fence Gate=
Giant Sequoia Fence Rail=
Giant Sequoia Leaves=Riesenmammutbaumlaub
Giant Sequoia Planks=Riesenmammutbaumbretter
Giant Sequoia Planks Slab=
Giant Sequoia Planks Stair=
Giant Sequoia Sapling=Riesenmammutbaumsetzling
Giant Sequoia Trunk=Riesenmammutbaumstamm
Giant Sequoia Trunk Slab=
Giant Sequoia Trunk Stair=
Jungle Tree=
Jungle Tree Fence=
Jungle Tree Fence Gate=
Jungle Tree Fence Rail=
Jungle Tree Leaves=Tropenbaumlaub
Jungle Tree Leaves (@1)=Tropenbaumlaub (@1)
Jungle Tree Planks=Tropenholzbretter
Jungle Tree Planks Slab=
Jungle Tree Planks Stair=
Jungle Tree Sapling=Tropenbaumsetzling
Jungle Tree Trunk=Tropenbaumstamm
Jungle Tree Trunk Slab=
Jungle Tree Trunk Stair=
Oak Tree=
Oak Tree Fence=
Oak Tree Fence Gate=
Oak Tree Fence Rail=
Oak Tree Leaves=Eichenlaub
Oak Tree Planks=Eichenbretter
Oak Tree Planks Slab=
Oak Tree Planks Stair=
Oak Tree Sapling=Eichensetzling
Oak Tree Trunk=Eichenstamm
Oak Tree Trunk Slab=
Oak Tree Trunk Stair=
Palm Tree=
Palm Tree Fence=
Palm Tree Fence Gate=
Palm Tree Fence Rail=
Palm Tree Leaves=Palmenlaub
Palm Tree Planks=Palmenbretter
Palm Tree Planks Slab=
Palm Tree Planks Stair=
Palm Tree Sapling=Palmensetzling
Palm Tree Trunk=Palmenstamm
Palm Tree Trunk Slab=
Palm Tree Trunk Stair=
Poplar Tree=
Poplar Tree Fence=
Poplar Tree Fence Gate=
Poplar Tree Fence Rail=
Poplar Tree Leaves=
Poplar Tree Planks=
Poplar Tree Planks Slab=
Poplar Tree Planks Stair=
Poplar Tree Sapling=
Poplar Tree Trunk=
Poplar Tree Trunk Slab=
Poplar Tree Trunk Stair=
Red=rot
Rubber Tree=
Rubber Tree Fence=
Rubber Tree Fence Gate=
Rubber Tree Fence Rail=
Rubber Tree Leaves=Gummibaumlaub
Rubber Tree Planks=Gummibaumbretter
Rubber Tree Planks Slab=
Rubber Tree Planks Stair=
Rubber Tree Sapling=Gummibaumsetzling
Rubber Tree Trunk=Gummibaumstamm
Rubber Tree Trunk (Empty)=Gummibaumstamm (leer)
Rubber Tree Trunk Slab=
Rubber Tree Trunk Stair=
Small poplar Tree Sapling=
Spruce Cone=Fichtenzapfen
Spruce Tree=
Spruce Tree Fence=
Spruce Tree Fence Gate=
Spruce Tree Fence Rail=
Spruce Tree Leaves=Fichtennadeln
Spruce Tree Planks=Fichtenbretter
Spruce Tree Planks Slab=
Spruce Tree Planks Stair=
Spruce Tree Sapling=Fichtensetzling
Spruce Tree Trunk=Fichtenstamm
Spruce Tree Trunk Slab=
Spruce Tree Trunk Stair=
Willow Tree=
Willow Tree Fence=
Willow Tree Fence Gate=
Willow Tree Fence Rail=
Willow Tree Leaves=Weidenlaub
Willow Tree Planks=Weidenbretter
Willow Tree Planks Slab=
Willow Tree Planks Stair=
Willow Tree Sapling=Weidensetzling
Willow Tree Trunk=Weidenstamm
Willow Tree Trunk Slab=
Willow Tree Trunk Stair=
Yellow=gelb

View File

@ -0,0 +1,211 @@
# textdomain: moretrees
# Translation by Carlos Barraza
### cocos_palm.lua ###
Coconut=Coco
Coconut Flower=
### crafts.lua ###
Acorn Muffin=Mollete de Bellota
Acorn Muffin batter= Masa de Mollete de Bellota
Coconut Milk=Leche de Coco
Date=Datilera
Date & nut snack=Datilera y Nueces
Date-nut cake=Pastel de Datilera
Date-nut cake batter=Pasta de torta de Datilera
Date-nut energy bar=Barra energetica de Datilera
Raw Coconut=Coco crudo
Roasted Cedar Cone Nuts=Coco de Alamo Tostado
Roasted Fir Cone Nuts=Cono de Abeto Tostado
Roasted Spruce Cone Nuts=Cono de Picea Tostado
### date_palm.lua ###
Date Flowers=Flores de Datilera
Date Stem=Tallo de Datilera
Dates=Datilera
### node_defs.lua ###
@1 (fast growth)=
Acorn=Bellota
Apple Tree=
Apple Tree Fence=
Apple Tree Fence Gate=
Apple Tree Fence Rail=
Apple Tree Leaves=Hojas de Arbol de Manzana
Apple Tree Planks=Madera de Arbol de Manzana
Apple Tree Planks Slab=
Apple Tree Planks Stair=
Apple Tree Sapling=Retoño de Arbol de Manzana
Apple Tree Trunk=Tronco de Arbol de Manzana
Apple Tree Trunk Slab=
Apple Tree Trunk Stair=
Beech Tree=
Beech Tree Fence=
Beech Tree Fence Gate=
Beech Tree Fence Rail=
Beech Tree Leaves=Hojas de Arbol de Haya
Beech Tree Planks=Madera de Arbol de Haya
Beech Tree Planks Slab=
Beech Tree Planks Stair=
Beech Tree Sapling=Retoño de Arbol de Haya
Beech Tree Trunk=Tronco de Arbol de Haya
Beech Tree Trunk Slab=
Beech Tree Trunk Stair=
Birch Tree=
Birch Tree Fence=
Birch Tree Fence Gate=
Birch Tree Fence Rail=
Birch Tree Leaves=Hojas de Arbol de Abedul
Birch Tree Planks=Madera de Arbol de Abedul
Birch Tree Planks Slab=
Birch Tree Planks Stair=
Birch Tree Sapling=Retoño de Arbol de Abedul
Birch Tree Trunk=Tronco de Arbol de Abedul
Birch Tree Trunk Slab=
Birch Tree Trunk Stair=
Cedar Cone=Coco de Alamo
Cedar Tree=
Cedar Tree Fence=
Cedar Tree Fence Gate=
Cedar Tree Fence Rail=
Cedar Tree Leaves=Hojas de Arbol de Cedro
Cedar Tree Planks=Madera de Arbol de Cedro
Cedar Tree Planks Slab=
Cedar Tree Planks Stair=
Cedar Tree Sapling=Retoño de Arbol de Cedro
Cedar Tree Trunk=Tronco de Arbol de Cedro
Cedar Tree Trunk Slab=
Cedar Tree Trunk Stair=
Date Palm Tree=
Date Palm Tree Fence=
Date Palm Tree Fence Gate=
Date Palm Tree Fence Rail=
Date Palm Tree Leaves=
Date Palm Tree Planks=Madera de Palmera Datilera
Date Palm Tree Planks Slab=
Date Palm Tree Planks Stair=
Date Palm Tree Sapling=
Date Palm Tree Trunk=Tronco de Palmera Datilera
Date Palm Tree Trunk Slab=
Date Palm Tree Trunk Stair=
Douglas Fir=
Douglas Fir Fence=
Douglas Fir Fence Gate=
Douglas Fir Fence Rail=
Douglas Fir Leaves=Hojas de Arbol de Abeto de Douglas
Douglas Fir Leaves (Bright)=Hojas de Arbol de Abeto de Douglas (Brillante)
Douglas Fir Planks=Madera de Arbol de Abeto de Douglas
Douglas Fir Planks Slab=
Douglas Fir Planks Stair=
Douglas Fir Sapling=Retoño de Arbol de Abeto de Douglas
Douglas Fir Trunk=Tronco de Arbol de Abeto de Douglas
Douglas Fir Trunk Slab=
Douglas Fir Trunk Stair=
Fir Cone=Coco de Abeto
Giant Sequoia=
Giant Sequoia Fence=
Giant Sequoia Fence Gate=
Giant Sequoia Fence Rail=
Giant Sequoia Leaves=Hojas de Sequoia Gigante
Giant Sequoia Planks=Madera de Sequoia Gigante
Giant Sequoia Planks Slab=
Giant Sequoia Planks Stair=
Giant Sequoia Sapling=Retoño de Arbol de Sequoia Gigante
Giant Sequoia Trunk=Tronco de Sequoia Gigante
Giant Sequoia Trunk Slab=
Giant Sequoia Trunk Stair=
Jungle Tree=Tronco de Arbol de Arbol de la Selva
Jungle Tree Fence=
Jungle Tree Fence Gate=
Jungle Tree Fence Rail=
Jungle Tree Leaves=Hojas de Arbol de la Selva
Jungle Tree Leaves (@1)=Hojas de Arbol de la Selva (@1)
Jungle Tree Planks=
Jungle Tree Planks Slab=
Jungle Tree Planks Stair=
Jungle Tree Sapling=
Jungle Tree Trunk=
Jungle Tree Trunk Slab=
Jungle Tree Trunk Stair=
Oak Tree=
Oak Tree Fence=
Oak Tree Fence Gate=
Oak Tree Fence Rail=
Oak Tree Leaves=Hojas de Arbol de Roble
Oak Tree Planks=Madera de Arbol de Roble
Oak Tree Planks Slab=
Oak Tree Planks Stair=
Oak Tree Sapling=Retoño de Arbol de Roble
Oak Tree Trunk=Tronco de Arbol de Roble
Oak Tree Trunk Slab=
Oak Tree Trunk Stair=
Palm Tree=
Palm Tree Fence=
Palm Tree Fence Gate=
Palm Tree Fence Rail=
Palm Tree Leaves=Hojas de Palmera
Palm Tree Planks=Madera de Palmera
Palm Tree Planks Slab=
Palm Tree Planks Stair=
Palm Tree Sapling=Retoño de Palmera
Palm Tree Trunk=Tronco de Palmera
Palm Tree Trunk Slab=
Palm Tree Trunk Stair=
Poplar Tree=
Poplar Tree Fence=
Poplar Tree Fence Gate=
Poplar Tree Fence Rail=
Poplar Tree Leaves=Hojas de Arbol de Alamo
Poplar Tree Planks=Madera de Arbol de Alamo
Poplar Tree Planks Slab=
Poplar Tree Planks Stair=
Poplar Tree Sapling=Retoño de Arbol de Alamo
Poplar Tree Trunk=Tronco de Arbol de Alamo
Poplar Tree Trunk Slab=
Poplar Tree Trunk Stair=
Red=Roja
Rubber Tree=
Rubber Tree Fence=
Rubber Tree Fence Gate=
Rubber Tree Fence Rail=
Rubber Tree Leaves=Hojas de Arbol de Arbol de Goma
Rubber Tree Planks=Madera de Arbol de Arbol de Goma
Rubber Tree Planks Slab=
Rubber Tree Planks Stair=
Rubber Tree Sapling=Retoño de Arbol de Arbol de Goma
Rubber Tree Trunk=Tronco de Arbol de Arbol de Goma
Rubber Tree Trunk (Empty)=Tronco de Arbol de Goma (Vacio)
Rubber Tree Trunk Slab=
Rubber Tree Trunk Stair=
Small poplar Tree Sapling=
Spruce Cone=Coco de Picea
Spruce Tree=
Spruce Tree Fence=
Spruce Tree Fence Gate=
Spruce Tree Fence Rail=
Spruce Tree Leaves=Hojas de Arbol de Abeto
Spruce Tree Planks=Madera de Arbol de Abeto
Spruce Tree Planks Slab=
Spruce Tree Planks Stair=
Spruce Tree Sapling=Retoño de Arbol de Abeto
Spruce Tree Trunk=Tronco de Arbol de Abeto
Spruce Tree Trunk Slab=
Spruce Tree Trunk Stair=
Willow Tree=
Willow Tree Fence=
Willow Tree Fence Gate=
Willow Tree Fence Rail=
Willow Tree Leaves=Hojas de Arbol de Sauce
Willow Tree Planks=Madera de Arbol de Sauce
Willow Tree Planks Slab=
Willow Tree Planks Stair=
Willow Tree Sapling=Retoño de Arbol de Sauce
Willow Tree Trunk=Tronco de Arbol de Sauce
Willow Tree Trunk Slab=
Willow Tree Trunk Stair=
Yellow=Amarilla

View File

@ -0,0 +1,211 @@
# textdomain: moretrees
# Translation by Yoan31 and Louis Royer
### cocos_palm.lua ###
Coconut=Noix de coco
Coconut Flower=Fleur de coco
### crafts.lua ###
Acorn Muffin=Muffins au gland
Acorn Muffin batter=Pate à muffins au Gland
Coconut Milk=Lait de coco
Date=Datte
Date & nut snack=Collation aux dattes et aux noix
Date-nut cake=Gâteau datte-noix
Date-nut cake batter=Pâte à gâteau datte-noix
Date-nut energy bar=Barre énergétique datte-noix
Raw Coconut=Noix de coco crue
Roasted Cedar Cone Nuts=Noix de pomme de pin roties
Roasted Fir Cone Nuts=Noix de cône de sapin roties
Roasted Spruce Cone Nuts=Noix de cône de sapin roties
### date_palm.lua ###
Date Flowers=Fleurs de datte
Date Stem=Tige de datte
Dates=Dattes
### node_defs.lua ###
@1 (fast growth)=@1 (croissance rapide)
Acorn=Gland
Apple Tree=Pommier
Apple Tree Fence=Barrière en bois de pommier
Apple Tree Fence Gate=Porte de clôture en bois de pommier
Apple Tree Fence Rail=Clôture en bois de pommier
Apple Tree Leaves=Feuilles de pommier
Apple Tree Planks=Planches de pommier
Apple Tree Planks Slab=Dalle en bois de pommier
Apple Tree Planks Stair=Escaliers en bois de pommier
Apple Tree Sapling=Pousse d'arbre de pommier
Apple Tree Trunk=Tronc d'arbre de pommier
Apple Tree Trunk Slab=Dalle en tronc de pommier
Apple Tree Trunk Stair=Escalier en tronc de pommier
Beech Tree=Hêtre
Beech Tree Fence=Barrière en bois de hêtre
Beech Tree Fence Gate=Porte de clôture en bois de hêtre
Beech Tree Fence Rail=Clôture en bois de hêtre
Beech Tree Leaves=Feuilles de hêtre
Beech Tree Planks=Planches de hêtre
Beech Tree Planks Slab=Dalle en bois de hêtre
Beech Tree Planks Stair=Escalier en bois de hêtre
Beech Tree Sapling=Pousse d'arbre de hêtre
Beech Tree Trunk=Tronc d'arbre de hêtre
Beech Tree Trunk Slab=Dalle en tronc de hêtre
Beech Tree Trunk Stair=Escalier en tronc de hêtre
Birch Tree=Bouleau
Birch Tree Fence=Barrière en bois de bouleau
Birch Tree Fence Gate=Porte de clôture en bois de bouleau
Birch Tree Fence Rail=Clôture en bois de bouleau
Birch Tree Leaves=Feuilles de bouleau
Birch Tree Planks=Planches d'arbre de bouleau
Birch Tree Planks Slab=Dalle en bois de bouleau
Birch Tree Planks Stair=Escalier en bois de bouleau
Birch Tree Sapling=Pousse d'arbre de bouleau
Birch Tree Trunk=Tronc d'arbre de bouleau
Birch Tree Trunk Slab=Dalle en tronc de bouleau
Birch Tree Trunk Stair=Escalier en tronc de bouleau
Cedar Cone=Pomme de pin
Cedar Tree=Pin
Cedar Tree Fence=Barrière en bois de pin
Cedar Tree Fence Gate=Porte de clôture en bois de pin
Cedar Tree Fence Rail=Clôture en bois de pin
Cedar Tree Leaves=Feuilles de pin
Cedar Tree Planks=Planches d'arbre de pin
Cedar Tree Planks Slab=Dalle en bois de pin
Cedar Tree Planks Stair=Escalier en bois de pin
Cedar Tree Sapling=Pousse d'arbre de pin
Cedar Tree Trunk=Tronc d'arbre de pin
Cedar Tree Trunk Slab=Dalle en tronc de pin
Cedar Tree Trunk Stair=Escalier en tronc de pin
Date Palm Tree=Dattier
Date Palm Tree Fence=Barrière en bois de dattier
Date Palm Tree Fence Gate=Porte de clôture en bois de dattier
Date Palm Tree Fence Rail=Clôture en bois de dattier
Date Palm Tree Leaves=Feuille de dattier
Date Palm Tree Planks=Planches de dattier
Date Palm Tree Planks Slab=Dalle en bois de dattier
Date Palm Tree Planks Stair=Escalier en bois de dattier
Date Palm Tree Sapling=Pousse de dattier
Date Palm Tree Trunk=Tronc de dattier
Date Palm Tree Trunk Slab=Dalle en tronc de dattier
Date Palm Tree Trunk Stair=Escalier en tronc de dattier
Douglas Fir=Sapin de Douglas
Douglas Fir Fence=Barrière en bois de sapin de Douglas
Douglas Fir Fence Gate=Porte de clôture en bois de sapin de Douglas
Douglas Fir Fence Rail=Clôture en bois de sapin de Douglas
Douglas Fir Leaves=Feuilles de sapin de Douglas
Douglas Fir Leaves (Bright)=Feuille de sapin de Douglas (brillant)
Douglas Fir Planks=Planches de sapin de Douglas
Douglas Fir Planks Slab=Dalle en bois de sapin de Douglas
Douglas Fir Planks Stair=Escalier en bois de sapin de Douglas
Douglas Fir Sapling=Pousse de sapin de Douglas
Douglas Fir Trunk=Tronc de sapin de Douglas
Douglas Fir Trunk Slab=Dalle en tronc de sapin de Douglas
Douglas Fir Trunk Stair=Escalier en tronc de sapin de Douglas
Fir Cone=Pomme de sapin
Giant Sequoia=Séquoia géant
Giant Sequoia Fence=Barrière en bois de séquoia géant
Giant Sequoia Fence Gate=Porte de clôture en bois de séquoia géant
Giant Sequoia Fence Rail=Clôture en bois de séquoia géant
Giant Sequoia Leaves=Feuilles de séquoia géant
Giant Sequoia Planks=Planches de séquoia géant
Giant Sequoia Planks Slab=Dalle en bois de séquoia géant
Giant Sequoia Planks Stair=Escalier en bois de séquoia géant
Giant Sequoia Sapling=Pousse de séquoia géant
Giant Sequoia Trunk=Tronc de séquoia géant
Giant Sequoia Trunk Slab=Dalle en tronc de séquoia géant
Giant Sequoia Trunk Stair=Escalier en tronc de séquoia géant
Jungle Tree=Arbre de la jungle
Jungle Tree Fence=Barrière en bois d'arbre de la jungle
Jungle Tree Fence Gate=Porte de clôture en bois d'arbre de la jungle
Jungle Tree Fence Rail=Clôture en bois d'arbre de la jungle
Jungle Tree Leaves=Feuilles d'arbre de la jungle
Jungle Tree Leaves (@1)=Feuilles d'arbre de la jungle (@1)
Jungle Tree Planks=Planches d'arbre de la jungle
Jungle Tree Planks Slab=Dalle en bois d'arbre de la jungle
Jungle Tree Planks Stair=Escalier en bois d'arbre de la jungle
Jungle Tree Sapling=Pousse d'arbre de la jungle
Jungle Tree Trunk=Tronc d'arbre de la jungle
Jungle Tree Trunk Slab=Dalle en tronc d'arbre de la jungle
Jungle Tree Trunk Stair=Escalier en tronc d'arbre de la jungle
Oak Tree=Chêne
Oak Tree Fence=Barrière en bois de chêne
Oak Tree Fence Gate=Porte de clôture en bois de chêne
Oak Tree Fence Rail=Clôture en bois de chêne
Oak Tree Leaves=Feuilles de chêne
Oak Tree Planks=Planches de chêne
Oak Tree Planks Slab=Dalle en bois de chêne
Oak Tree Planks Stair=Escalier en bois de chêne
Oak Tree Sapling=Pousse d'arbre de chêne
Oak Tree Trunk=Tronc d'arbre de chêne
Oak Tree Trunk Slab=Dalle en tronc de chêne
Oak Tree Trunk Stair=Escalier en tronc de chêne
Palm Tree=Palmier
Palm Tree Fence=Barrière en bois de palmier
Palm Tree Fence Gate=Porte de clôture en bois de palmier
Palm Tree Fence Rail=Clôture en bois de palmier
Palm Tree Leaves=Feuilles de palmier
Palm Tree Planks=Planches de palmier
Palm Tree Planks Slab=Dalle en bois de palmier
Palm Tree Planks Stair=Escalier en bois de palmier
Palm Tree Sapling=Pousse d'arbre de palmier
Palm Tree Trunk=Tronc d'arbre de palmier
Palm Tree Trunk Slab=Dalle en tronc de palmier
Palm Tree Trunk Stair=Escalier en tronc de palmier
Poplar Tree=Peuplier
Poplar Tree Fence=Barrière en bois de peuplier
Poplar Tree Fence Gate=Porte de clôture en bois de peuplier
Poplar Tree Fence Rail=Clôture en bois de peuplier
Poplar Tree Leaves=Feuilles de peuplier
Poplar Tree Planks=Plances de peuplier
Poplar Tree Planks Slab=Dalle en bois de peuplier
Poplar Tree Planks Stair=Escalier en bois de peuplier
Poplar Tree Sapling=Pousse de peuplier
Poplar Tree Trunk=Tronc de peuplier
Poplar Tree Trunk Slab=Dalle en tronc de peuplier
Poplar Tree Trunk Stair=Escalier en tronc de peuplier
Red=rouge
Rubber Tree=Arbre à caoutchouc
Rubber Tree Fence=Barrière en bois d'arbre à caoutchouc
Rubber Tree Fence Gate=Porte de clôture en bois d'arbre à caoutchouc
Rubber Tree Fence Rail=Clôture en bois d'arbre à caoutchouc
Rubber Tree Leaves=Feuilles d'arbre à caoutchouc
Rubber Tree Planks=Planches d'arbre à caoutchouc
Rubber Tree Planks Slab=Dalle en bois d'arbre à caoutchouc
Rubber Tree Planks Stair=Escalier en bois d'arbre à caoutchouc
Rubber Tree Sapling=Pousse d'arbre à caoutchouc
Rubber Tree Trunk=Tronc d'arbre a caoutchouc
Rubber Tree Trunk (Empty)=Tronc d'arbre à caoutchouc (vide)
Rubber Tree Trunk Slab=Dalle en tronc d'arbre à caoutchouc
Rubber Tree Trunk Stair=Escalier en tronc d'arbre à caoutchouc
Small poplar Tree Sapling=Pousse de petit peuplier
Spruce Cone=Cône de sapin
Spruce Tree=Épicéa
Spruce Tree Fence=Barrière en bois d'épicéa
Spruce Tree Fence Gate=Porte de clôture en bois d'épicéa
Spruce Tree Fence Rail=Clôture en bois d'épicéa
Spruce Tree Leaves=Feuilles d'épicéa
Spruce Tree Planks=Planches d'arbre d'épicéa
Spruce Tree Planks Slab=Dalle en bois d'épicéa
Spruce Tree Planks Stair=Escalier en bois d'épicéa
Spruce Tree Sapling=Pousse d'arbre d'épicéa
Spruce Tree Trunk=Tronc d'arbre d'épicéa
Spruce Tree Trunk Slab=Dalle en tronc d'épicéa
Spruce Tree Trunk Stair=Escalier en tronc d'épicéa
Willow Tree=Saule
Willow Tree Fence=Barrière en bois de saule
Willow Tree Fence Gate=Porte de clôture en bois de saule
Willow Tree Fence Rail=Clôture en bois de saule
Willow Tree Leaves=Feuilles de saule
Willow Tree Planks=Planches de saule
Willow Tree Planks Slab=Dalle en bois de saule
Willow Tree Planks Stair=Escalier en bois de saule
Willow Tree Sapling=Pousse de saule
Willow Tree Trunk=Tronc d'arbre de saule
Willow Tree Trunk Slab=Dalle en tronc de saule
Willow Tree Trunk Stair=Escalier en tronc de saule
Yellow=jaune

View File

@ -0,0 +1,210 @@
# textdomain: moretrees
### cocos_palm.lua ###
Coconut=
Coconut Flower=
### crafts.lua ###
Acorn Muffin=
Acorn Muffin batter=
Coconut Milk=
Date=
Date & nut snack=
Date-nut cake=
Date-nut cake batter=
Date-nut energy bar=
Raw Coconut=
Roasted Cedar Cone Nuts=
Roasted Fir Cone Nuts=
Roasted Spruce Cone Nuts=
### date_palm.lua ###
Date Flowers=
Date Stem=
Dates=
### node_defs.lua ###
@1 (fast growth)=
Acorn=
Apple Tree=
Apple Tree Fence=
Apple Tree Fence Gate=
Apple Tree Fence Rail=
Apple Tree Leaves=
Apple Tree Planks=
Apple Tree Planks Slab=
Apple Tree Planks Stair=
Apple Tree Sapling=
Apple Tree Trunk=
Apple Tree Trunk Slab=
Apple Tree Trunk Stair=
Beech Tree=
Beech Tree Fence=
Beech Tree Fence Gate=
Beech Tree Fence Rail=
Beech Tree Leaves=
Beech Tree Planks=
Beech Tree Planks Slab=
Beech Tree Planks Stair=
Beech Tree Sapling=
Beech Tree Trunk=
Beech Tree Trunk Slab=
Beech Tree Trunk Stair=
Birch Tree=
Birch Tree Fence=
Birch Tree Fence Gate=
Birch Tree Fence Rail=
Birch Tree Leaves=
Birch Tree Planks=
Birch Tree Planks Slab=
Birch Tree Planks Stair=
Birch Tree Sapling=
Birch Tree Trunk=
Birch Tree Trunk Slab=
Birch Tree Trunk Stair=
Cedar Cone=
Cedar Tree=
Cedar Tree Fence=
Cedar Tree Fence Gate=
Cedar Tree Fence Rail=
Cedar Tree Leaves=
Cedar Tree Planks=
Cedar Tree Planks Slab=
Cedar Tree Planks Stair=
Cedar Tree Sapling=
Cedar Tree Trunk=
Cedar Tree Trunk Slab=
Cedar Tree Trunk Stair=
Date Palm Tree=
Date Palm Tree Fence=
Date Palm Tree Fence Gate=
Date Palm Tree Fence Rail=
Date Palm Tree Leaves=
Date Palm Tree Planks=
Date Palm Tree Planks Slab=
Date Palm Tree Planks Stair=
Date Palm Tree Sapling=
Date Palm Tree Trunk=
Date Palm Tree Trunk Slab=
Date Palm Tree Trunk Stair=
Douglas Fir=
Douglas Fir Fence=
Douglas Fir Fence Gate=
Douglas Fir Fence Rail=
Douglas Fir Leaves=
Douglas Fir Leaves (Bright)=
Douglas Fir Planks=
Douglas Fir Planks Slab=
Douglas Fir Planks Stair=
Douglas Fir Sapling=
Douglas Fir Trunk=
Douglas Fir Trunk Slab=
Douglas Fir Trunk Stair=
Fir Cone=
Giant Sequoia=
Giant Sequoia Fence=
Giant Sequoia Fence Gate=
Giant Sequoia Fence Rail=
Giant Sequoia Leaves=
Giant Sequoia Planks=
Giant Sequoia Planks Slab=
Giant Sequoia Planks Stair=
Giant Sequoia Sapling=
Giant Sequoia Trunk=
Giant Sequoia Trunk Slab=
Giant Sequoia Trunk Stair=
Jungle Tree=
Jungle Tree Fence=
Jungle Tree Fence Gate=
Jungle Tree Fence Rail=
Jungle Tree Leaves=
Jungle Tree Leaves (@1)=
Jungle Tree Planks=
Jungle Tree Planks Slab=
Jungle Tree Planks Stair=
Jungle Tree Sapling=
Jungle Tree Trunk=
Jungle Tree Trunk Slab=
Jungle Tree Trunk Stair=
Oak Tree=
Oak Tree Fence=
Oak Tree Fence Gate=
Oak Tree Fence Rail=
Oak Tree Leaves=
Oak Tree Planks=
Oak Tree Planks Slab=
Oak Tree Planks Stair=
Oak Tree Sapling=
Oak Tree Trunk=
Oak Tree Trunk Slab=
Oak Tree Trunk Stair=
Palm Tree=
Palm Tree Fence=
Palm Tree Fence Gate=
Palm Tree Fence Rail=
Palm Tree Leaves=
Palm Tree Planks=
Palm Tree Planks Slab=
Palm Tree Planks Stair=
Palm Tree Sapling=
Palm Tree Trunk=
Palm Tree Trunk Slab=
Palm Tree Trunk Stair=
Poplar Tree=
Poplar Tree Fence=
Poplar Tree Fence Gate=
Poplar Tree Fence Rail=
Poplar Tree Leaves=
Poplar Tree Planks=
Poplar Tree Planks Slab=
Poplar Tree Planks Stair=
Poplar Tree Sapling=
Poplar Tree Trunk=
Poplar Tree Trunk Slab=
Poplar Tree Trunk Stair=
Red=
Rubber Tree=
Rubber Tree Fence=
Rubber Tree Fence Gate=
Rubber Tree Fence Rail=
Rubber Tree Leaves=
Rubber Tree Planks=
Rubber Tree Planks Slab=
Rubber Tree Planks Stair=
Rubber Tree Sapling=
Rubber Tree Trunk=
Rubber Tree Trunk (Empty)=
Rubber Tree Trunk Slab=
Rubber Tree Trunk Stair=
Small poplar Tree Sapling=
Spruce Cone=
Spruce Tree=
Spruce Tree Fence=
Spruce Tree Fence Gate=
Spruce Tree Fence Rail=
Spruce Tree Leaves=
Spruce Tree Planks=
Spruce Tree Planks Slab=
Spruce Tree Planks Stair=
Spruce Tree Sapling=
Spruce Tree Trunk=
Spruce Tree Trunk Slab=
Spruce Tree Trunk Stair=
Willow Tree=
Willow Tree Fence=
Willow Tree Fence Gate=
Willow Tree Fence Rail=
Willow Tree Leaves=
Willow Tree Planks=
Willow Tree Planks Slab=
Willow Tree Planks Stair=
Willow Tree Sapling=
Willow Tree Trunk=
Willow Tree Trunk Slab=
Willow Tree Trunk Stair=
Yellow=

4
mods/moretrees/mod.conf Normal file
View File

@ -0,0 +1,4 @@
name = moretrees
depends = default, biome_lib, vessels
optional_depends = doors, stairs, moreblocks, farming
min_minetest_version = 5.2.0

View File

@ -0,0 +1,743 @@
local S = minetest.get_translator("moretrees")
moretrees.avoidnodes = {}
moretrees.treelist = {
{"beech", S("Beech Tree")},
{"apple_tree", S("Apple Tree")},
{"oak", S("Oak Tree"), "acorn", S("Acorn"), {-0.2, -0.5, -0.2, 0.2, 0, 0.2}, 0.8 },
{"sequoia", S("Giant Sequoia")},
{"birch", S("Birch Tree")},
{"palm", S("Palm Tree"), "palm_fruit_trunk_gen", S("Palm Tree"), {-0.2, -0.5, -0.2, 0.2, 0, 0.2}, 1.0 },
{"date_palm", S("Date Palm Tree"), "date_palm_fruit_trunk", S("Date Palm Tree"), {0, 0, 0, 0, 0, 0}, 0.0 },
{"spruce", S("Spruce Tree"), "spruce_cone", S("Spruce Cone"), {-0.2, -0.5, -0.2, 0.2, 0, 0.2}, 0.8 },
{"cedar", S("Cedar Tree"), "cedar_cone", S("Cedar Cone"), {-0.2, -0.5, -0.2, 0.2, 0, 0.2}, 0.8 },
{"poplar", S("Poplar Tree")},
{"poplar_small", S("Poplar Tree")},
{"willow", S("Willow Tree")},
{"rubber_tree", S("Rubber Tree")},
{"fir", S("Douglas Fir"), "fir_cone", S("Fir Cone"), {-0.2, -0.5, -0.2, 0.2, 0, 0.2}, 0.8 },
{"jungletree", S("Jungle Tree"), nil, nil, nil, nil, "default_junglesapling.png" },
}
moretrees.treedesc = {
beech = {
trunk = S("Beech Tree Trunk"),
planks = S("Beech Tree Planks"),
sapling = S("Beech Tree Sapling"),
leaves = S("Beech Tree Leaves"),
trunk_stair = S("Beech Tree Trunk Stair"),
trunk_slab = S("Beech Tree Trunk Slab"),
planks_stair = S("Beech Tree Planks Stair"),
planks_slab = S("Beech Tree Planks Slab"),
fence = S("Beech Tree Fence"),
fence_rail = S("Beech Tree Fence Rail"),
fence_gate = S("Beech Tree Fence Gate"),
},
apple_tree = {
trunk = S("Apple Tree Trunk"),
planks = S("Apple Tree Planks"),
sapling = S("Apple Tree Sapling"),
leaves = S("Apple Tree Leaves"),
trunk_stair = S("Apple Tree Trunk Stair"),
trunk_slab = S("Apple Tree Trunk Slab"),
planks_stair = S("Apple Tree Planks Stair"),
planks_slab = S("Apple Tree Planks Slab"),
fence = S("Apple Tree Fence"),
fence_rail = S("Apple Tree Fence Rail"),
fence_gate = S("Apple Tree Fence Gate"),
},
oak = {
trunk = S("Oak Tree Trunk"),
planks = S("Oak Tree Planks"),
sapling = S("Oak Tree Sapling"),
leaves = S("Oak Tree Leaves"),
trunk_stair = S("Oak Tree Trunk Stair"),
trunk_slab = S("Oak Tree Trunk Slab"),
planks_stair = S("Oak Tree Planks Stair"),
planks_slab = S("Oak Tree Planks Slab"),
fence = S("Oak Tree Fence"),
fence_rail = S("Oak Tree Fence Rail"),
fence_gate = S("Oak Tree Fence Gate"),
},
sequoia = {
trunk = S("Giant Sequoia Trunk"),
planks = S("Giant Sequoia Planks"),
sapling = S("Giant Sequoia Sapling"),
leaves = S("Giant Sequoia Leaves"),
trunk_stair = S("Giant Sequoia Trunk Stair"),
trunk_slab = S("Giant Sequoia Trunk Slab"),
planks_stair = S("Giant Sequoia Planks Stair"),
planks_slab = S("Giant Sequoia Planks Slab"),
fence = S("Giant Sequoia Fence"),
fence_rail = S("Giant Sequoia Fence Rail"),
fence_gate = S("Giant Sequoia Fence Gate"),
},
birch = {
trunk = S("Birch Tree Trunk"),
planks = S("Birch Tree Planks"),
sapling = S("Birch Tree Sapling"),
leaves = S("Birch Tree Leaves"),
trunk_stair = S("Birch Tree Trunk Stair"),
trunk_slab = S("Birch Tree Trunk Slab"),
planks_stair = S("Birch Tree Planks Stair"),
planks_slab = S("Birch Tree Planks Slab"),
fence = S("Birch Tree Fence"),
fence_rail = S("Birch Tree Fence Rail"),
fence_gate = S("Birch Tree Fence Gate"),
},
palm = {
trunk = S("Palm Tree Trunk"),
planks = S("Palm Tree Planks"),
sapling = S("Palm Tree Sapling"),
leaves = S("Palm Tree Leaves"),
trunk_stair = S("Palm Tree Trunk Stair"),
trunk_slab = S("Palm Tree Trunk Slab"),
planks_stair = S("Palm Tree Planks Stair"),
planks_slab = S("Palm Tree Planks Slab"),
fence = S("Palm Tree Fence"),
fence_rail = S("Palm Tree Fence Rail"),
fence_gate = S("Palm Tree Fence Gate"),
},
date_palm = {
trunk = S("Date Palm Tree Trunk"),
planks = S("Date Palm Tree Planks"),
sapling = S("Date Palm Tree Sapling"),
leaves = S("Date Palm Tree Leaves"),
trunk_stair = S("Date Palm Tree Trunk Stair"),
trunk_slab = S("Date Palm Tree Trunk Slab"),
planks_stair = S("Date Palm Tree Planks Stair"),
planks_slab = S("Date Palm Tree Planks Slab"),
fence = S("Date Palm Tree Fence"),
fence_rail = S("Date Palm Tree Fence Rail"),
fence_gate = S("Date Palm Tree Fence Gate"),
},
spruce = {
trunk = S("Spruce Tree Trunk"),
planks = S("Spruce Tree Planks"),
sapling = S("Spruce Tree Sapling"),
leaves = S("Spruce Tree Leaves"),
trunk_stair = S("Spruce Tree Trunk Stair"),
trunk_slab = S("Spruce Tree Trunk Slab"),
planks_stair = S("Spruce Tree Planks Stair"),
planks_slab = S("Spruce Tree Planks Slab"),
fence = S("Spruce Tree Fence"),
fence_rail = S("Spruce Tree Fence Rail"),
fence_gate = S("Spruce Tree Fence Gate"),
},
cedar = {
trunk = S("Cedar Tree Trunk"),
planks = S("Cedar Tree Planks"),
sapling = S("Cedar Tree Sapling"),
leaves = S("Cedar Tree Leaves"),
trunk_stair = S("Cedar Tree Trunk Stair"),
trunk_slab = S("Cedar Tree Trunk Slab"),
planks_stair = S("Cedar Tree Planks Stair"),
planks_slab = S("Cedar Tree Planks Slab"),
fence = S("Cedar Tree Fence"),
fence_rail = S("Cedar Tree Fence Rail"),
fence_gate = S("Cedar Tree Fence Gate"),
},
poplar = {
trunk = S("Poplar Tree Trunk"),
planks = S("Poplar Tree Planks"),
sapling = S("Poplar Tree Sapling"),
leaves = S("Poplar Tree Leaves"),
trunk_stair = S("Poplar Tree Trunk Stair"),
trunk_slab = S("Poplar Tree Trunk Slab"),
planks_stair = S("Poplar Tree Planks Stair"),
planks_slab = S("Poplar Tree Planks Slab"),
fence = S("Poplar Tree Fence"),
fence_rail = S("Poplar Tree Fence Rail"),
fence_gate = S("Poplar Tree Fence Gate"),
},
poplar_small = {
sapling = S("Small poplar Tree Sapling"),
},
willow = {
trunk = S("Willow Tree Trunk"),
planks = S("Willow Tree Planks"),
sapling = S("Willow Tree Sapling"),
leaves = S("Willow Tree Leaves"),
trunk_stair = S("Willow Tree Trunk Stair"),
trunk_slab = S("Willow Tree Trunk Slab"),
planks_stair = S("Willow Tree Planks Stair"),
planks_slab = S("Willow Tree Planks Slab"),
fence = S("Willow Tree Fence"),
fence_rail = S("Willow Tree Fence Rail"),
fence_gate = S("Willow Tree Fence Gate"),
},
rubber_tree = {
trunk = S("Rubber Tree Trunk"),
planks = S("Rubber Tree Planks"),
sapling = S("Rubber Tree Sapling"),
leaves = S("Rubber Tree Leaves"),
trunk_stair = S("Rubber Tree Trunk Stair"),
trunk_slab = S("Rubber Tree Trunk Slab"),
planks_stair = S("Rubber Tree Planks Stair"),
planks_slab = S("Rubber Tree Planks Slab"),
fence = S("Rubber Tree Fence"),
fence_rail = S("Rubber Tree Fence Rail"),
fence_gate = S("Rubber Tree Fence Gate"),
},
fir = {
trunk = S("Douglas Fir Trunk"),
planks = S("Douglas Fir Planks"),
sapling = S("Douglas Fir Sapling"),
leaves = S("Douglas Fir Leaves"),
trunk_stair = S("Douglas Fir Trunk Stair"),
trunk_slab = S("Douglas Fir Trunk Slab"),
planks_stair = S("Douglas Fir Planks Stair"),
planks_slab = S("Douglas Fir Planks Slab"),
fence = S("Douglas Fir Fence"),
fence_rail = S("Douglas Fir Fence Rail"),
fence_gate = S("Douglas Fir Fence Gate"),
},
jungletree = {
trunk = S("Jungle Tree Trunk"),
planks = S("Jungle Tree Planks"),
sapling = S("Jungle Tree Sapling"),
leaves = S("Jungle Tree Leaves"),
trunk_stair = S("Jungle Tree Trunk Stair"),
trunk_slab = S("Jungle Tree Trunk Slab"),
planks_stair = S("Jungle Tree Planks Stair"),
planks_slab = S("Jungle Tree Planks Slab"),
fence = S("Jungle Tree Fence"),
fence_rail = S("Jungle Tree Fence Rail"),
fence_gate = S("Jungle Tree Fence Gate"),
},
}
-- local dirs1 = { 21, 20, 23, 22, 21 }
local dirs2 = { 12, 9, 18, 7, 12 }
-- local dirs3 = { 14, 11, 16, 5, 14 }
local moretrees_new_leaves_drawtype = "allfaces_optional"
local moretrees_plantlike_leaves_visual_scale = 1
if moretrees.plantlike_leaves then
moretrees_new_leaves_drawtype = "plantlike"
moretrees_plantlike_leaves_visual_scale = math.sqrt(2)
end
-- redefine default leaves to handle plantlike and/or leaf decay options
if moretrees.plantlike_leaves then
minetest.override_item("default:leaves", {
inventory_image = minetest.inventorycube("default_leaves.png"),
drawtype = "plantlike",
visual_scale = math.sqrt(2)
})
end
-- redefine default jungle leaves for same
if moretrees.plantlike_leaves then
minetest.override_item("default:jungleleaves", {
inventory_image = minetest.inventorycube("default_jungleleaves.png"),
drawtype = "plantlike",
visual_scale = math.sqrt(2)
})
end
for i in ipairs(moretrees.treelist) do
local treename = moretrees.treelist[i][1]
local fruit = moretrees.treelist[i][3]
local fruitdesc = moretrees.treelist[i][4]
local selbox = moretrees.treelist[i][5]
local vscale = moretrees.treelist[i][6]
local saptex = moretrees.treelist[i][7]
-- player will get a sapling with 1/100 chance
-- player will get leaves only if he/she gets no saplings,
-- this is because max_items is 1
local droprarity = 100
local decay = moretrees.leafdecay_radius
if treename == "palm" then
droprarity = 20
decay = moretrees.palm_leafdecay_radius
elseif treename == "date_palm" then
decay = moretrees.palm_leafdecay_radius
end
if treename ~= "jungletree" -- the default game provides jungle tree and pine trunk/planks nodes.
and treename ~= "poplar_small"
and treename ~= "pine" then
saptex = "moretrees_"..treename.."_sapling.png"
minetest.register_node("moretrees:"..treename.."_trunk", {
description = moretrees.treedesc[treename].trunk,
tiles = {
"moretrees_"..treename.."_trunk_top.png",
"moretrees_"..treename.."_trunk_top.png",
"moretrees_"..treename.."_trunk.png"
},
paramtype2 = "facedir",
is_ground_content = false,
groups = {tree=1,snappy=1,choppy=2,oddly_breakable_by_hand=1,flammable=2},
sounds = default.node_sound_wood_defaults(),
on_place = minetest.rotate_node,
})
minetest.register_node("moretrees:"..treename.."_planks", {
description = moretrees.treedesc[treename].planks,
tiles = {"moretrees_"..treename.."_wood.png"},
is_ground_content = false,
groups = {snappy=1,choppy=2,oddly_breakable_by_hand=2,flammable=3,wood=1},
sounds = default.node_sound_wood_defaults(),
})
minetest.register_node("moretrees:"..treename.."_sapling", {
description = moretrees.treedesc[treename].sapling,
drawtype = "plantlike",
tiles = {saptex},
inventory_image = saptex,
paramtype = "light",
paramtype2 = "waving",
walkable = false,
is_ground_content = true,
selection_box = {
type = "fixed",
fixed = {-0.3, -0.5, -0.3, 0.3, 0.35, 0.3}
},
groups = {snappy=2,dig_immediate=3,flammable=2,attached_node=1,sapling=1},
sounds = default.node_sound_defaults(),
on_place = function(itemstack, placer, pointed_thing)
itemstack = default.sapling_on_place(itemstack, placer, pointed_thing,
"moretrees:" ..treename.. "_sapling",
-- minp, maxp to be checked, relative to sapling pos
-- minp_relative.y = 1 because sapling pos has been checked
{x = -3, y = 1, z = -3},
{x = 3, y = 6, z = 3},
-- maximum interval of interior volume check
4)
return itemstack
end,
})
local moretrees_leaves_inventory_image = nil
local moretrees_new_leaves_waving = nil
if moretrees.plantlike_leaves then
moretrees_leaves_inventory_image = minetest.inventorycube("moretrees_"..treename.."_leaves.png")
else
moretrees_new_leaves_waving = 1
end
minetest.register_node("moretrees:"..treename.."_leaves", {
description = moretrees.treedesc[treename].leaves,
drawtype = moretrees_new_leaves_drawtype,
waving = moretrees_new_leaves_waving,
visual_scale = moretrees_plantlike_leaves_visual_scale,
tiles = { "moretrees_"..treename.."_leaves.png" },
inventory_image = moretrees_leaves_inventory_image,
paramtype = "light",
is_ground_content = false,
groups = {snappy = 3, flammable = 2, leaves = 1, moretrees_leaves = 1, leafdecay = 1},
sounds = default.node_sound_leaves_defaults(),
drop = {
max_items = 1,
items = {
{items = {"moretrees:"..treename.."_sapling"}, rarity = droprarity },
{items = {"moretrees:"..treename.."_leaves"} }
}
},
})
if moretrees.enable_stairs then
if minetest.get_modpath("moreblocks") then
-- stairsplus:register_all(modname, subname, recipeitem, {fields})
stairsplus:register_all(
"moretrees",
treename.."_trunk",
"moretrees:"..treename.."_trunk",
{
groups = { snappy=1, choppy=2, oddly_breakable_by_hand=1, flammable=2, not_in_creative_inventory=1 },
tiles = {
"moretrees_"..treename.."_trunk_top.png",
"moretrees_"..treename.."_trunk_top.png",
"moretrees_"..treename.."_trunk.png"
},
description = moretrees.treedesc[treename].trunk,
drop = treename.."_trunk",
}
)
stairsplus:register_all(
"moretrees",
treename.."_planks",
"moretrees:"..treename.."_planks",
{
groups = { snappy=1, choppy=2, oddly_breakable_by_hand=2, flammable=3, not_in_creative_inventory=1 },
tiles = { "moretrees_"..treename.."_wood.png" },
description = moretrees.treedesc[treename].planks,
drop = treename.."_planks",
}
)
elseif minetest.get_modpath("stairs") then
stairs.register_stair_and_slab(
"moretrees_"..treename.."_trunk",
"moretrees:"..treename.."_trunk",
{ snappy=1, choppy=2, oddly_breakable_by_hand=1, flammable=2 },
{ "moretrees_"..treename.."_trunk_top.png",
"moretrees_"..treename.."_trunk_top.png",
"moretrees_"..treename.."_trunk.png"
},
moretrees.treedesc[treename].trunk_stair,
moretrees.treedesc[treename].trunk_slab,
default.node_sound_wood_defaults()
)
stairs.register_stair_and_slab(
"moretrees_"..treename.."_planks",
"moretrees:"..treename.."_planks",
{ snappy=1, choppy=2, oddly_breakable_by_hand=2, flammable=3 },
{ "moretrees_"..treename.."_wood.png" },
moretrees.treedesc[treename].planks_stair,
moretrees.treedesc[treename].planks_slab,
default.node_sound_wood_defaults()
)
end
end
if moretrees.enable_fences then
local planks_name = "moretrees:" .. treename .. "_planks"
local planks_tile = "moretrees_" .. treename .. "_wood.png"
default.register_fence("moretrees:" .. treename .. "_fence", {
description = moretrees.treedesc[treename].fence,
texture = planks_tile,
inventory_image = "default_fence_overlay.png^" .. planks_tile ..
"^default_fence_overlay.png^[makealpha:255,126,126",
wield_image = "default_fence_overlay.png^" .. planks_tile ..
"^default_fence_overlay.png^[makealpha:255,126,126",
material = planks_name,
groups = {choppy = 2, oddly_breakable_by_hand = 2, flammable = 2},
sounds = default.node_sound_wood_defaults()
})
default.register_fence_rail("moretrees:" .. treename .. "_fence_rail", {
description = moretrees.treedesc[treename].fence_rail,
texture = planks_tile,
inventory_image = "default_fence_rail_overlay.png^" .. planks_tile ..
"^default_fence_rail_overlay.png^[makealpha:255,126,126",
wield_image = "default_fence_rail_overlay.png^" .. planks_tile ..
"^default_fence_rail_overlay.png^[makealpha:255,126,126",
material = planks_name,
groups = {choppy = 2, oddly_breakable_by_hand = 2, flammable = 2},
sounds = default.node_sound_wood_defaults()
})
if minetest.global_exists("doors") then
doors.register_fencegate("moretrees:" .. treename .. "_gate", {
description = moretrees.treedesc[treename].fence_gate,
texture = planks_tile,
material = planks_name,
groups = {choppy = 2, oddly_breakable_by_hand = 2, flammable = 2}
})
end
end
end
minetest.register_node("moretrees:"..treename.."_sapling_ongen", {
description = S("@1 (fast growth)", moretrees.treedesc[treename].sapling),
drawtype = "plantlike",
tiles = {saptex},
inventory_image = saptex,
paramtype = "light",
paramtype2 = "waving",
walkable = false,
is_ground_content = true,
selection_box = {
type = "fixed",
fixed = {-0.3, -0.5, -0.3, 0.3, 0.35, 0.3}
},
groups = {snappy=2,dig_immediate=3,flammable=2,attached_node=1,sapling=1},
sounds = default.node_sound_defaults(),
drop = "moretrees:"..treename.."_sapling",
on_place = function(itemstack, placer, pointed_thing)
itemstack = default.sapling_on_place(itemstack, placer, pointed_thing,
"moretrees:" ..treename.. "_sapling_ongen",
-- minp, maxp to be checked, relative to sapling pos
-- minp_relative.y = 1 because sapling pos has been checked
{x = -3, y = 1, z = -3},
{x = 3, y = 6, z = 3},
-- maximum interval of interior volume check
4)
return itemstack
end,
})
local fruitname = nil
if fruit then
fruitname = "moretrees:"..fruit
minetest.register_node(fruitname, {
description = fruitdesc,
drawtype = "plantlike",
tiles = { "moretrees_"..fruit..".png" },
inventory_image = "moretrees_"..fruit..".png^[transformR180",
wield_image = "moretrees_"..fruit..".png^[transformR180",
visual_scale = vscale,
paramtype = "light",
sunlight_propagates = true,
is_ground_content = false,
walkable = false,
selection_box = {
type = "fixed",
fixed = selbox
},
groups = {fleshy=3,dig_immediate=3,flammable=2, attached_node=1, leafdecay = 1, leafdecay_drop = 1},
sounds = default.node_sound_defaults(),
})
end
if treename ~= "jungletree"
and treename ~= "poplar_small"
and treename ~= "pine" then
default.register_leafdecay({
trunks = { "moretrees:"..treename.."_trunk" },
leaves = { "moretrees:"..treename.."_leaves", fruitname },
radius = decay,
})
end
minetest.register_abm({
nodenames = { "moretrees:"..treename.."_trunk_sideways" },
interval = 1,
chance = 1,
action = function(pos, node, active_object_count, active_object_count_wider)
local fdir = node.param2 or 0
local nfdir = dirs2[fdir+1]
minetest.add_node(pos, {name = "moretrees:"..treename.."_trunk", param2 = nfdir})
end,
})
table.insert(moretrees.avoidnodes, "moretrees:"..treename.."_trunk")
if moretrees.spawn_saplings then
table.insert(moretrees.avoidnodes, "moretrees:"..treename.."_sapling")
table.insert(moretrees.avoidnodes, "moretrees:"..treename.."_sapling_ongen")
end
end
-- Add small poplar saplings
local poplar_sapling = minetest.registered_nodes["moretrees:poplar_sapling"]
local poplar_sapling_ongen = minetest.registered_nodes["moretrees:poplar_sapling_ongen"]
local poplar_small_sapling = {}
local poplar_small_sapling_ongen = {}
for k,v in pairs(poplar_sapling) do
poplar_small_sapling[k] = v
end
for k,v in pairs(poplar_sapling_ongen) do
poplar_small_sapling_ongen[k] = v
end
poplar_small_sapling.tiles = {"moretrees_poplar_small_sapling.png"}
poplar_small_sapling.inventory_image = "moretrees_poplar_small_sapling.png"
poplar_small_sapling.is_ground_content = true
poplar_small_sapling_ongen.tiles_ongen = {"moretrees_poplar_small_sapling.png"}
poplar_small_sapling_ongen.inventory_image_ongen = "moretrees_poplar_small_sapling.png"
poplar_small_sapling_ongen.drop = "moretrees:poplar_small_sapling"
poplar_small_sapling_ongen.is_ground_content = true
minetest.register_node("moretrees:poplar_small_sapling", poplar_small_sapling)
minetest.register_node("moretrees:poplar_small_sapling_ongen", poplar_small_sapling_ongen)
if moretrees.spawn_saplings then
table.insert(moretrees.avoidnodes, "moretrees:poplar_sapling")
table.insert(moretrees.avoidnodes, "moretrees:poplar_small_sapling_ongen")
end
local poplar_leaves_drop = minetest.registered_nodes["moretrees:poplar_leaves"].drop
minetest.override_item("moretrees:poplar_leaves", {
drop = {
max_items = poplar_leaves_drop.maxitems,
items = {
{items = {"moretrees:poplar_sapling"}, rarity = 1.33 * poplar_leaves_drop.items[1].rarity },
{items = {"moretrees:poplar_small_sapling"}, rarity = 1.33 * poplar_leaves_drop.items[1].rarity },
{items = {"moretrees:poplar_leaves"} }
}
}
})
-- Extra nodes for jungle trees:
local jungleleaves = {"yellow","red"}
local jungleleavesnames = {S("Yellow"), S("Red")}
for color = 1, #jungleleaves do
local leave_name = "moretrees:jungletree_leaves_"..jungleleaves[color]
local moretrees_leaves_inventory_image = nil
if moretrees.plantlike_leaves then
moretrees_leaves_inventory_image = minetest.inventorycube("moretrees_jungletree_leaves_"..jungleleaves[color]..".png")
else
moretrees_new_leaves_waving = 1
end
minetest.register_node(leave_name, {
description = S("Jungle Tree Leaves (@1)", jungleleavesnames[color]),
drawtype = moretrees_new_leaves_drawtype,
waving = moretrees_new_leaves_waving,
visual_scale = moretrees_plantlike_leaves_visual_scale,
tiles = {"moretrees_jungletree_leaves_"..jungleleaves[color]..".png"},
inventory_image = moretrees_leaves_inventory_image,
paramtype = "light",
is_ground_content = false,
groups = {snappy = 3, flammable = 2, leaves = 1, moretrees_leaves = 1, leafdecay = 3 },
drop = {
max_items = 1,
items = {
{items = {"default:junglesapling"}, rarity = 100 },
{items = {"moretrees:jungletree_leaves_"..jungleleaves[color]} }
}
},
sounds = default.node_sound_leaves_defaults(),
})
end
-- To get Moretrees to generate its own jungle trees among the default mapgen
-- we need our own copy of that node, which moretrees will match against.
local jungle_tree = table.copy(minetest.registered_nodes["default:jungletree"])
jungle_tree.drop = "default:jungletree"
minetest.register_node("moretrees:jungletree_trunk", jungle_tree)
default.register_leafdecay({
trunks = { "default:jungletree", "moretrees:jungletree_trunk" },
leaves = { "default:jungleleaves", "moretrees:jungletree_leaves_yellow", "moretrees:jungletree_leaves_red" },
radius = moretrees.leafdecay_radius,
})
-- Extra needles for firs
local moretrees_leaves_inventory_image = nil
if moretrees.plantlike_leaves then
moretrees_leaves_inventory_image = minetest.inventorycube("moretrees_fir_leaves_bright.png")
end
minetest.register_node("moretrees:fir_leaves_bright", {
drawtype = moretrees_new_leaves_drawtype,
waving = moretrees_new_leaves_waving,
visual_scale = moretrees_plantlike_leaves_visual_scale,
description = S("Douglas Fir Leaves (Bright)"),
tiles = { "moretrees_fir_leaves_bright.png" },
inventory_image = moretrees_leaves_inventory_image,
paramtype = "light",
is_ground_content = false,
groups = {snappy = 3, flammable = 2, leaves = 1, moretrees_leaves = 1, leafdecay = 3 },
drop = {
max_items = 1,
items = {
{items = {'moretrees:fir_sapling'}, rarity = 100 },
{items = {'moretrees:fir_leaves_bright'} }
}
},
sounds = default.node_sound_leaves_defaults()
})
default.register_leafdecay({
trunks = { "moretrees:fir_trunk" },
leaves = { "moretrees:fir_leaves", "moretrees:fir_leaves_bright" },
radius = moretrees.leafdecay_radius,
})
if moretrees.enable_redefine_apple then
local appledef = table.copy(minetest.registered_nodes["default:apple"])
appledef.groups.attached_node = 1
minetest.register_node(":default:apple", appledef)
end
table.insert(moretrees.avoidnodes, "default:jungletree")
table.insert(moretrees.avoidnodes, "default:pine_tree")
table.insert(moretrees.avoidnodes, "default:acacia_tree")
table.insert(moretrees.avoidnodes, "moretrees:fir_trunk")
table.insert(moretrees.avoidnodes, "default:tree")
if moretrees.spawn_saplings then
table.insert(moretrees.avoidnodes, "snow:sapling_pine")
table.insert(moretrees.avoidnodes, "default:junglesapling")
table.insert(moretrees.avoidnodes, "default:pine_sapling")
end
-- "empty" (tapped) rubber tree nodes
minetest.register_node("moretrees:rubber_tree_trunk_empty", {
description = S("Rubber Tree Trunk (Empty)"),
tiles = {
"moretrees_rubber_tree_trunk_top.png",
"moretrees_rubber_tree_trunk_top.png",
"moretrees_rubber_tree_trunk_empty.png"
},
groups = {tree=1,snappy=1,choppy=2,oddly_breakable_by_hand=1,flammable=2},
sounds = default.node_sound_wood_defaults(),
paramtype2 = "facedir",
is_ground_content = false,
on_place = minetest.rotate_node,
})
minetest.register_abm({
nodenames = { "moretrees:rubber_tree_trunk_empty_sideways" },
interval = 1,
chance = 1,
action = function(pos, node, active_object_count, active_object_count_wider)
local fdir = node.param2 or 0
local nfdir = dirs2[fdir+1]
minetest.add_node(pos, {name = "moretrees:rubber_tree_trunk_empty", param2 = nfdir})
end,
})
-- For compatibility with old nodes, recently-changed nodes, and default nodes
minetest.register_alias("technic:rubber_tree_full", "moretrees:rubber_tree_trunk")
minetest.register_alias("farming_plus:rubber_tree_full", "moretrees:rubber_tree_trunk")
minetest.register_alias("farming:rubber_tree_full", "moretrees:rubber_tree_trunk")
minetest.register_alias("technic:rubber_leaves", "moretrees:rubber_tree_leaves")
minetest.register_alias("farming_plus:rubber_leaves", "moretrees:rubber_tree_leaves")
minetest.register_alias("farming:rubber_leaves", "moretrees:rubber_tree_leaves")
minetest.register_alias("technic:rubber_tree_sapling", "moretrees:rubber_tree_sapling")
minetest.register_alias("farming_plus:rubber_sapling", "moretrees:rubber_tree_sapling")
minetest.register_alias("farming:rubber_sapling", "moretrees:rubber_tree_sapling")
minetest.register_alias("moretrees:conifer_trunk", "moretrees:fir_trunk")
minetest.register_alias("moretrees:conifer_trunk_sideways", "moretrees:fir_trunk_sideways")
minetest.register_alias("moretrees:conifer_leaves", "moretrees:fir_leaves")
minetest.register_alias("moretrees:conifer_leaves_bright", "moretrees:fir_leaves_bright")
minetest.register_alias("moretrees:conifer_sapling", "moretrees:fir_sapling")
minetest.register_alias("conifers:trunk", "moretrees:fir_trunk")
minetest.register_alias("conifers:trunk_reversed", "moretrees:fir_trunk_sideways")
minetest.register_alias("conifers:leaves", "moretrees:fir_leaves")
minetest.register_alias("conifers:leaves_special", "moretrees:fir_leaves_bright")
minetest.register_alias("conifers:sapling", "moretrees:fir_sapling")
minetest.register_alias("moretrees:jungletree_sapling", "default:junglesapling")
minetest.register_alias("moretrees:jungletree_trunk_sideways", "moreblocks:horizontal_jungle_tree")
minetest.register_alias("moretrees:jungletree_planks", "default:junglewood")
minetest.register_alias("moretrees:jungletree_leaves_green", "default:jungleleaves")
minetest.register_alias("moretrees:acacia_trunk", "default:acacia_tree")
minetest.register_alias("moretrees:acacia_planks", "default:acacia_wood")
minetest.register_alias("moretrees:acacia_sapling", "default:acacia_sapling")
minetest.register_alias("moretrees:acacia_leaves", "default:acacia_leaves")
minetest.register_alias("moretrees:pine_trunk", "moretrees:cedar_trunk")
minetest.register_alias("moretrees:pine_planks", "moretrees:cedar_planks")
minetest.register_alias("moretrees:pine_sapling", "moretrees:cedar_sapling")
minetest.register_alias("moretrees:pine_leaves", "moretrees:cedar_leaves")
minetest.register_alias("moretrees:pine_cone", "moretrees:cedar_cone")
minetest.register_alias("moretrees:pine_nuts", "moretrees:cedar_nuts")
minetest.register_alias("moretrees:pine_sapling_ongen", "moretrees:cedar_sapling_ongen")
minetest.register_alias("moretrees:dates", "moretrees:dates_f4")

View File

@ -0,0 +1,84 @@
-- sapling growth
-- these tables only affect hand-placed saplings
-- mapgen-placed always use their biome def settings, which are much more
-- limited, in the interest of speed.
local dirt_surfaces = {
set = true,
["default:dirt"] = true,
["default:dirt_with_grass"] = true,
["default:dirt_with_dry_grass"] = true,
["default:dirt_with_coniferous_litter"] = true,
["default:dirt_with_rainforest_litter"] = true,
["woodsoils:dirt_with_leaves_1"] = true,
["woodsoils:dirt_with_leaves_2"] = true,
["woodsoils:grass_with_leaves_1"] = true,
["woodsoils:grass_with_leaves_2"] = true
}
local conifer_surfaces = {
set = true,
["default:dirt"] = true,
["default:dirt_with_grass"] = true,
["default:dirt_with_dry_grass"] = true,
["default:dirt_with_coniferous_litter"] = true,
["default:dirt_with_rainforest_litter"] = true,
["woodsoils:dirt_with_leaves_1"] = true,
["woodsoils:dirt_with_leaves_2"] = true,
["woodsoils:grass_with_leaves_1"] = true,
["woodsoils:grass_with_leaves_2"] = true,
["default:dirt_with_snow"] = true
}
local sand_surfaces = {
set = true,
["default:sand"] = true,
["default:desert_sand"] = true,
["cottages:loam"] = true,
-- note, no silver sand here.
-- too cold for a palm, too... well... sandy for anything else.
}
for i in ipairs(moretrees.treelist) do
local treename = moretrees.treelist[i][1]
local tree_model = treename.."_model"
local tree_biome = treename.."_biome"
local surfaces
local grow_function = moretrees[tree_model]
if treename == "spruce"
or treename == "fir"
or treename == "cedar"
or treename == "pine" then
surfaces = conifer_surfaces
elseif string.find(treename, "palm") then
surfaces = sand_surfaces
else
surfaces = dirt_surfaces
end
if treename == "spruce"
or treename == "fir"
or treename == "birch"
or treename == "jungletree" then
grow_function = "moretrees.grow_"..treename
end
biome_lib:dbg(dump(moretrees[tree_biome].surface))
biome_lib:grow_plants({
grow_delay = moretrees.sapling_interval,
grow_chance = moretrees.sapling_chance,
grow_plant = "moretrees:"..treename.."_sapling",
grow_nodes = surfaces,
grow_function = grow_function,
})
biome_lib:grow_plants({
grow_delay = 2,
grow_chance = 1,
grow_plant = "moretrees:"..treename.."_sapling_ongen",
grow_nodes = surfaces,
grow_function = grow_function,
})
end

View File

@ -0,0 +1,168 @@
-- Usage:
-- - Create a new world
-- - Set world mapgen: v6
-- - Set world seed: 2625051331357512570
-- - Enable the moretrees mod
-- - Edit the moretrees source
-- - Disable all trees in default_settings.lua
-- - Recommended: make saplings grow fast in default_settings.lua:
-- sapling_interval = 5
-- sapling_chance = 1
-- - Apply the patch below to moretrees
-- (so that jungle trees are always large, and differently-colored):
-- use 'git apply --ignore-space-change'
-- - Make sure this file (you are reading) will be loaded when minetest starts !
-- (e.g. add 'dofile(modpath.."/screenshot.lua")' to init.lua)
-- - Start minetest
-- - Goto 700,y,-280 (approximately)
-- - Make sure the world is loaded between x = 650 .. 780 and z = -350 .. -180
-- - Give the chat command '/make-scene'
-- - Wait & walk/fly around until all trees have grown
-- - goto the platform at 780, 30, -277
-- - Set the viewing range to 300, with fog enabled
-- - Take a screenshot.
-- Patch to apply to moretrees
--[[
diff --git a/init.lua b/init.lua
index 8189ffd..afd4644 100644
--- a/init.lua
+++ b/init.lua
@@ -225,9 +225,12 @@ moretrees.ct_rules_b1 = "[-FBf][+FBf]"
moretrees.ct_rules_a2 = "FF[FF][&&-FBF][&&+FBF][&&---FBF][&&+++FBF]F/A"
moretrees.ct_rules_b2 = "[-fB][+fB]"
+local jleaves = 1
function moretrees.grow_jungletree(pos)
local r1 = math.random(2)
local r2 = math.random(3)
+ r1 = jleaves
+ jleaves = jleaves % 2 + 1
if r1 == 1 then
moretrees.jungletree_model.leaves2 = "moretrees:jungletree_leaves_red"
else
@@ -235,6 +238,7 @@ function moretrees.grow_jungletree(pos)
end
moretrees.jungletree_model.leaves2_chance = math.random(25, 75)
+ r2=3
if r2 == 1 then
moretrees.jungletree_model.trunk_type = "single"
moretrees.jungletree_model.iterations = 2
]]
minetest.register_chatcommand("make-scene", {
func = function()
minetest.place_node({x=780, y=30, z=-277}, {name="default:obsidian"})
minetest.place_node({x=780, y=30, z=-278}, {name="default:obsidian"})
minetest.place_node({x=781, y=30, z=-277}, {name="default:obsidian"})
minetest.place_node({x=781, y=30, z=-278}, {name="default:obsidian"})
minetest.place_node({x=781, y=30, z=-276}, {name="default:obsidian"})
minetest.place_node({x=780, y=30, z=-276}, {name="default:obsidian"})
for z = -360, -300 do
local dy=2
for x = 630 + (-z - 360)/3, 660 + (-z - 300)/3 do
for y = 5, 22 do
minetest.place_node({x=x, y=y, z=z}, {name="default:desert_stone"})
end
for y = 23, 25 + dy do
minetest.place_node({x=x, y=y, z=z}, {name="default:desert_sand"})
end
dy = 0
end
end
minetest.place_node({x=717, y=2, z=-298}, {name = "moretrees:palm_sapling"})
minetest.place_node({x=713, y=2, z=-302}, {name = "moretrees:palm_sapling"})
minetest.place_node({x=713, y=2, z=-307}, {name = "moretrees:palm_sapling"})
minetest.place_node({x=717, y=2, z=-318}, {name = "moretrees:palm_sapling"})
minetest.place_node({x=723, y=2, z=-320}, {name = "moretrees:palm_sapling"})
minetest.place_node({x=645, y=26, z=-314}, {name="moretrees:date_palm_sapling"})
minetest.place_node({x=653, y=26, z=-322}, {name="moretrees:date_palm_sapling"})
minetest.place_node({x=649, y=26, z=-334}, {name="moretrees:date_palm_sapling"})
minetest.place_node({x=662, y=26, z=-342}, {name="moretrees:date_palm_sapling"})
minetest.place_node({x=672, y=5, z=-305}, {name="moretrees:oak_sapling"})
minetest.place_node({x=690, y=6, z=-322}, {name="moretrees:oak_sapling"})
minetest.place_node({x=695, y=7, z=-335}, {name="moretrees:oak_sapling"})
minetest.place_node({x=699, y=4, z=-301}, {name="moretrees:oak_sapling"})
minetest.place_node({x=751, y=5, z=-254}, {name="moretrees:apple_tree_sapling"})
minetest.place_node({x=729, y=3, z=-275}, {name="moretrees:apple_tree_sapling"})
minetest.place_node({x=747, y=4, z=-270}, {name="moretrees:apple_tree_sapling"})
minetest.place_node({x=671, y=5, z=-283}, {name="default:junglesapling"})
minetest.place_node({x=680, y=4, z=-287}, {name="default:junglesapling"})
minetest.place_node({x=702, y=4, z=-288}, {name="default:junglesapling"})
minetest.place_node({x=646, y=12, z=-199}, {name="moretrees:spruce_sapling"})
minetest.place_node({x=644, y=14, z=-177}, {name="moretrees:spruce_sapling"})
minetest.place_node({x=678, y=9, z=-211}, {name="moretrees:spruce_sapling"})
minetest.place_node({x=663, y=10, z=-215}, {name="moretrees:spruce_sapling"})
minetest.place_node({x=637, y=3, z=-263}, {name="moretrees:sequoia_sapling"})
minetest.place_node({x=625, y=3, z=-250}, {name="moretrees:sequoia_sapling"})
minetest.place_node({x=616, y=3, z=-233}, {name="moretrees:sequoia_sapling"})
minetest.place_node({x=635, y=3, z=-276}, {name="moretrees:sequoia_sapling"})
minetest.place_node({x=681, y=11, z=-260}, {name="moretrees:sequoia_sapling"})
minetest.place_node({x=682, y=10, z=-247}, {name="moretrees:sequoia_sapling"})
minetest.place_node({x=737, y=7, z=-195}, {name="moretrees:cedar_sapling"})
minetest.place_node({x=720, y=8, z=-189}, {name="moretrees:cedar_sapling"})
minetest.place_node({x=704, y=7, z=-187}, {name="moretrees:cedar_sapling"})
minetest.place_node({x=731, y=2, z=-227}, {name="moretrees:poplar_sapling"})
minetest.place_node({x=721, y=2, z=-233}, {name="moretrees:poplar_sapling"})
minetest.place_node({x=712, y=1, z=-237}, {name="moretrees:poplar_sapling"})
minetest.place_node({x=743, y=3, z=-228}, {name="moretrees:poplar_small_sapling"})
minetest.place_node({x=750, y=3, z=-230}, {name="moretrees:poplar_small_sapling"})
minetest.place_node({x=731, y=5, z=-233}, {name="moretrees:poplar_small_sapling"})
minetest.place_node({x=702, y=2, z=-274}, {name="moretrees:birch_sapling"})
minetest.place_node({x=697, y=2, z=-271}, {name="moretrees:birch_sapling"})
minetest.place_node({x=696, y=2, z=-264}, {name="moretrees:birch_sapling"})
minetest.place_node({x=710, y=2, z=-265}, {name="moretrees:birch_sapling"})
minetest.place_node({x=707, y=8, z=-247}, {name="moretrees:fir_sapling"})
minetest.place_node({x=699, y=10, z=-254}, {name="moretrees:fir_sapling"})
minetest.place_node({x=729, y=5, z=-261}, {name="moretrees:fir_sapling"})
minetest.place_node({x=732, y=5, z=-252}, {name="moretrees:fir_sapling"})
minetest.place_node({x=741, y=4, z=-262}, {name="moretrees:fir_sapling"})
minetest.place_node({x=751, y=2, z=-286}, {name="moretrees:willow_sapling"})
minetest.place_node({x=760, y=5, z=-223}, {name="moretrees:rubber_tree_sapling"})
minetest.place_node({x=762, y=5, z=-230}, {name="moretrees:rubber_tree_sapling"})
minetest.place_node({x=766, y=5, z=-243}, {name="moretrees:rubber_tree_sapling"})
minetest.place_node({x=764, y=6, z=-252}, {name="moretrees:rubber_tree_sapling"})
end
})
--[[
The following is a search/replace command suitable for vi (/vim) or sed, to convert minetest log
messages to equivalent lua commands:
s/.*\(\(moretrees\|default\)[^ ]*\) at (\([-0-9]\+\),\([-0-9]\+\),\([-0-9]\+\)).*/\t\tminetest.place_node({x=\3, y=\4, z=\5}, {name="\1"})/
E.g. a minetest log line of the following kind:
2016-07-03 11:30:50: ACTION[Server]: singleplayer places node moretrees:rubber_tree_sapling at (760,5,-223)
Becomes:
minetest.place_node({x=760, y=5, z=-223}, {name="moretrees:rubber_tree_sapling"})
(Except that the example log line above has an extra space added, so it won't be converted)
vi/vim users: Add the minetest log lines to this file, then enter the following command, with
<expression> replaced with the search/replace expression above.
:%<expression>
sed users: Add the minetest log lines to this file, then execute the following command at the shell
prompt with <expression> replaced by the search/replace expression above. Don't forget the
single-quotes.
sed '<expression>' < screenshot.lua > screenshot-new.lua
Windows users: You're probably out of luck. And the effort of doing such a thing is probably
larger anyway than the effort of copying an existing line and typing things manually.
]]

Binary file not shown.

After

Width:  |  Height:  |  Size: 101 KiB

Binary file not shown.

After

Width:  |  Height:  |  Size: 417 B

Binary file not shown.

After

Width:  |  Height:  |  Size: 782 B

Binary file not shown.

After

Width:  |  Height:  |  Size: 619 B

Binary file not shown.

After

Width:  |  Height:  |  Size: 351 B

Binary file not shown.

After

Width:  |  Height:  |  Size: 183 B

Binary file not shown.

After

Width:  |  Height:  |  Size: 1.0 KiB

Binary file not shown.

After

Width:  |  Height:  |  Size: 503 B

Binary file not shown.

After

Width:  |  Height:  |  Size: 464 B

Binary file not shown.

After

Width:  |  Height:  |  Size: 201 B

Binary file not shown.

After

Width:  |  Height:  |  Size: 177 B

Binary file not shown.

After

Width:  |  Height:  |  Size: 980 B

Binary file not shown.

After

Width:  |  Height:  |  Size: 926 B

Binary file not shown.

After

Width:  |  Height:  |  Size: 175 B

Binary file not shown.

After

Width:  |  Height:  |  Size: 459 B

Binary file not shown.

After

Width:  |  Height:  |  Size: 208 B

Binary file not shown.

After

Width:  |  Height:  |  Size: 975 B

Binary file not shown.

After

Width:  |  Height:  |  Size: 811 B

Binary file not shown.

After

Width:  |  Height:  |  Size: 1.0 KiB

Binary file not shown.

After

Width:  |  Height:  |  Size: 315 B

Binary file not shown.

After

Width:  |  Height:  |  Size: 205 B

Binary file not shown.

After

Width:  |  Height:  |  Size: 369 B

Binary file not shown.

After

Width:  |  Height:  |  Size: 202 B

Binary file not shown.

After

Width:  |  Height:  |  Size: 1.0 KiB

Binary file not shown.

After

Width:  |  Height:  |  Size: 451 B

Binary file not shown.

After

Width:  |  Height:  |  Size: 648 B

Binary file not shown.

After

Width:  |  Height:  |  Size: 963 B

Binary file not shown.

After

Width:  |  Height:  |  Size: 877 B

Binary file not shown.

After

Width:  |  Height:  |  Size: 429 B

Binary file not shown.

After

Width:  |  Height:  |  Size: 1009 B

Binary file not shown.

After

Width:  |  Height:  |  Size: 227 B

Binary file not shown.

After

Width:  |  Height:  |  Size: 199 B

Binary file not shown.

After

Width:  |  Height:  |  Size: 2.1 KiB

Binary file not shown.

After

Width:  |  Height:  |  Size: 685 B

Binary file not shown.

After

Width:  |  Height:  |  Size: 608 B

Binary file not shown.

After

Width:  |  Height:  |  Size: 695 B

Binary file not shown.

After

Width:  |  Height:  |  Size: 450 B

Binary file not shown.

After

Width:  |  Height:  |  Size: 757 B

Binary file not shown.

After

Width:  |  Height:  |  Size: 261 B

Binary file not shown.

After

Width:  |  Height:  |  Size: 1.2 KiB

Binary file not shown.

After

Width:  |  Height:  |  Size: 673 B

Binary file not shown.

After

Width:  |  Height:  |  Size: 735 B

Binary file not shown.

After

Width:  |  Height:  |  Size: 9.2 KiB

Binary file not shown.

After

Width:  |  Height:  |  Size: 3.8 KiB

Binary file not shown.

After

Width:  |  Height:  |  Size: 4.0 KiB

Binary file not shown.

After

Width:  |  Height:  |  Size: 8.9 KiB

Binary file not shown.

After

Width:  |  Height:  |  Size: 8.1 KiB

Binary file not shown.

After

Width:  |  Height:  |  Size: 9.0 KiB

Binary file not shown.

After

Width:  |  Height:  |  Size: 2.5 KiB

Binary file not shown.

After

Width:  |  Height:  |  Size: 4.0 KiB

Binary file not shown.

After

Width:  |  Height:  |  Size: 2.1 KiB

Binary file not shown.

After

Width:  |  Height:  |  Size: 244 B

Binary file not shown.

After

Width:  |  Height:  |  Size: 205 B

Binary file not shown.

After

Width:  |  Height:  |  Size: 205 B

Binary file not shown.

After

Width:  |  Height:  |  Size: 361 B

Binary file not shown.

After

Width:  |  Height:  |  Size: 166 B

Binary file not shown.

After

Width:  |  Height:  |  Size: 753 B

Binary file not shown.

After

Width:  |  Height:  |  Size: 924 B

Binary file not shown.

After

Width:  |  Height:  |  Size: 1.0 KiB

Binary file not shown.

After

Width:  |  Height:  |  Size: 201 B

Binary file not shown.

After

Width:  |  Height:  |  Size: 201 B

Binary file not shown.

After

Width:  |  Height:  |  Size: 201 B

Binary file not shown.

After

Width:  |  Height:  |  Size: 730 B

Binary file not shown.

After

Width:  |  Height:  |  Size: 172 B

Binary file not shown.

After

Width:  |  Height:  |  Size: 998 B

Binary file not shown.

After

Width:  |  Height:  |  Size: 519 B

Binary file not shown.

After

Width:  |  Height:  |  Size: 618 B

Some files were not shown because too many files have changed in this diff Show More