diff --git a/mods-apply-world.mt-regenerate-from-config-file b/mods-apply-world.mt-regenerate-from-config-file index 5834d035..b39dc5f9 100755 --- a/mods-apply-world.mt-regenerate-from-config-file +++ b/mods-apply-world.mt-regenerate-from-config-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 diff --git a/mods-download b/mods-download index cac33f65..6e037ce7 100755 --- a/mods-download +++ b/mods-download @@ -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 diff --git a/mods/biome_lib/API.txt b/mods/biome_lib/API.txt new file mode 100644 index 00000000..0dd15c35 --- /dev/null +++ b/mods/biome_lib/API.txt @@ -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 = + +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) + diff --git a/mods/biome_lib/LICENSE b/mods/biome_lib/LICENSE new file mode 100644 index 00000000..c5885ae9 --- /dev/null +++ b/mods/biome_lib/LICENSE @@ -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. + 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. diff --git a/mods/biome_lib/README.md b/mods/biome_lib/README.md new file mode 100644 index 00000000..ac39750f --- /dev/null +++ b/mods/biome_lib/README.md @@ -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. diff --git a/mods/biome_lib/depends.txt b/mods/biome_lib/depends.txt new file mode 100644 index 00000000..c48fe0d0 --- /dev/null +++ b/mods/biome_lib/depends.txt @@ -0,0 +1,3 @@ +default +intllib? + diff --git a/mods/biome_lib/description.txt b/mods/biome_lib/description.txt new file mode 100644 index 00000000..0412661b --- /dev/null +++ b/mods/biome_lib/description.txt @@ -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. diff --git a/mods/biome_lib/growth.lua b/mods/biome_lib/growth.lua new file mode 100644 index 00000000..807b69c5 --- /dev/null +++ b/mods/biome_lib/growth.lua @@ -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 diff --git a/mods/biome_lib/init.lua b/mods/biome_lib/init.lua new file mode 100644 index 00000000..b8635b9d --- /dev/null +++ b/mods/biome_lib/init.lua @@ -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) + diff --git a/mods/biome_lib/locale/de.txt b/mods/biome_lib/locale/de.txt new file mode 100644 index 00000000..28867868 --- /dev/null +++ b/mods/biome_lib/locale/de.txt @@ -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 diff --git a/mods/biome_lib/locale/fr.txt b/mods/biome_lib/locale/fr.txt new file mode 100644 index 00000000..90709002 --- /dev/null +++ b/mods/biome_lib/locale/fr.txt @@ -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. diff --git a/mods/biome_lib/locale/ru.txt b/mods/biome_lib/locale/ru.txt new file mode 100644 index 00000000..7b3072d0 --- /dev/null +++ b/mods/biome_lib/locale/ru.txt @@ -0,0 +1,5 @@ +# Translation by inpos + +someone = кто-то +Sorry, %s owns that spot. = Извините, но %s уже является владельцем этой точки. +[Plantlife Library] Loaded = [Plantlife Library] Загружена diff --git a/mods/biome_lib/locale/template.txt b/mods/biome_lib/locale/template.txt new file mode 100644 index 00000000..0f5fbbd4 --- /dev/null +++ b/mods/biome_lib/locale/template.txt @@ -0,0 +1,5 @@ +# Template + +someone = +Sorry, %s owns that spot. = +[Plantlife Library] Loaded = diff --git a/mods/biome_lib/locale/tr.txt b/mods/biome_lib/locale/tr.txt new file mode 100644 index 00000000..4b596f40 --- /dev/null +++ b/mods/biome_lib/locale/tr.txt @@ -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 diff --git a/mods/biome_lib/mod.conf b/mods/biome_lib/mod.conf new file mode 100644 index 00000000..033b72e9 --- /dev/null +++ b/mods/biome_lib/mod.conf @@ -0,0 +1,2 @@ +name = biome_lib +min_minetest_version = 5.2.0 diff --git a/mods/biome_lib/search_functions.lua b/mods/biome_lib/search_functions.lua new file mode 100644 index 00000000..d665b5fe --- /dev/null +++ b/mods/biome_lib/search_functions.lua @@ -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) diff --git a/mods/moretrees/.luacheckrc b/mods/moretrees/.luacheckrc new file mode 100644 index 00000000..459b2e2e --- /dev/null +++ b/mods/moretrees/.luacheckrc @@ -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", +} diff --git a/mods/moretrees/LICENSE b/mods/moretrees/LICENSE new file mode 100644 index 00000000..08cda455 --- /dev/null +++ b/mods/moretrees/LICENSE @@ -0,0 +1,620 @@ +Minetest mod moretrees +====================== + +All source code: + © 2013, Vanessa Ezekowitz +Date & cocos palm code (date_palm.lua, cocos_palm.lua) + © 2016, Rogier +All date & date palm textures, date-based food, cocos flower & green coconuts, +and all poplar textures: + © 2016, Rogier + - 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 +All other textures: + © 2013, Vanessa Ezekowitz + +############################################################################### + +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. + 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. diff --git a/mods/moretrees/README.md b/mods/moretrees/README.md new file mode 100644 index 00000000..905cefa4 --- /dev/null +++ b/mods/moretrees/README.md @@ -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: biome_lib and default diff --git a/mods/moretrees/biome_defs.lua b/mods/moretrees/biome_defs.lua new file mode 100644 index 00000000..c080ed01 --- /dev/null +++ b/mods/moretrees/biome_defs.lua @@ -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 +} diff --git a/mods/moretrees/cocos_palm.lua b/mods/moretrees/cocos_palm.lua new file mode 100644 index 00000000..127f3285 --- /dev/null +++ b/mods/moretrees/cocos_palm.lua @@ -0,0 +1,335 @@ +-- © 2016, Rogier +-- 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 + diff --git a/mods/moretrees/crafts.lua b/mods/moretrees/crafts.lua new file mode 100644 index 00000000..360f9848 --- /dev/null +++ b/mods/moretrees/crafts.lua @@ -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", +}) + + diff --git a/mods/moretrees/date_palm.lua b/mods/moretrees/date_palm.lua new file mode 100644 index 00000000..33cd646a --- /dev/null +++ b/mods/moretrees/date_palm.lua @@ -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 + +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 + diff --git a/mods/moretrees/default_settings.txt b/mods/moretrees/default_settings.txt new file mode 100644 index 00000000..a0fae226 --- /dev/null +++ b/mods/moretrees/default_settings.txt @@ -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 diff --git a/mods/moretrees/init.lua b/mods/moretrees/init.lua new file mode 100644 index 00000000..9196852f --- /dev/null +++ b/mods/moretrees/init.lua @@ -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)") diff --git a/mods/moretrees/locale/moretrees.de.tr b/mods/moretrees/locale/moretrees.de.tr new file mode 100644 index 00000000..10980d62 --- /dev/null +++ b/mods/moretrees/locale/moretrees.de.tr @@ -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 diff --git a/mods/moretrees/locale/moretrees.es.tr b/mods/moretrees/locale/moretrees.es.tr new file mode 100644 index 00000000..ccdb42a2 --- /dev/null +++ b/mods/moretrees/locale/moretrees.es.tr @@ -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 diff --git a/mods/moretrees/locale/moretrees.fr.tr b/mods/moretrees/locale/moretrees.fr.tr new file mode 100644 index 00000000..09058f34 --- /dev/null +++ b/mods/moretrees/locale/moretrees.fr.tr @@ -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 diff --git a/mods/moretrees/locale/template.txt b/mods/moretrees/locale/template.txt new file mode 100644 index 00000000..bac4da7d --- /dev/null +++ b/mods/moretrees/locale/template.txt @@ -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= diff --git a/mods/moretrees/mod.conf b/mods/moretrees/mod.conf new file mode 100644 index 00000000..da7e4932 --- /dev/null +++ b/mods/moretrees/mod.conf @@ -0,0 +1,4 @@ +name = moretrees +depends = default, biome_lib, vessels +optional_depends = doors, stairs, moreblocks, farming +min_minetest_version = 5.2.0 diff --git a/mods/moretrees/node_defs.lua b/mods/moretrees/node_defs.lua new file mode 100644 index 00000000..bdc4a2b4 --- /dev/null +++ b/mods/moretrees/node_defs.lua @@ -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") diff --git a/mods/moretrees/saplings.lua b/mods/moretrees/saplings.lua new file mode 100644 index 00000000..72392754 --- /dev/null +++ b/mods/moretrees/saplings.lua @@ -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 diff --git a/mods/moretrees/screenshot.lua b/mods/moretrees/screenshot.lua new file mode 100644 index 00000000..28a8c255 --- /dev/null +++ b/mods/moretrees/screenshot.lua @@ -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 + replaced with the search/replace expression above. + :% + +sed users: Add the minetest log lines to this file, then execute the following command at the shell +prompt with replaced by the search/replace expression above. Don't forget the +single-quotes. + sed '' < 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. +]] + diff --git a/mods/moretrees/screenshot.png b/mods/moretrees/screenshot.png new file mode 100644 index 00000000..b9ab5de1 Binary files /dev/null and b/mods/moretrees/screenshot.png differ diff --git a/mods/moretrees/textures/moretrees_acorn.png b/mods/moretrees/textures/moretrees_acorn.png new file mode 100644 index 00000000..dc2ef329 Binary files /dev/null and b/mods/moretrees/textures/moretrees_acorn.png differ diff --git a/mods/moretrees/textures/moretrees_acorn_muffin.png b/mods/moretrees/textures/moretrees_acorn_muffin.png new file mode 100644 index 00000000..166ca838 Binary files /dev/null and b/mods/moretrees/textures/moretrees_acorn_muffin.png differ diff --git a/mods/moretrees/textures/moretrees_acorn_muffin_batter.png b/mods/moretrees/textures/moretrees_acorn_muffin_batter.png new file mode 100644 index 00000000..b22e7491 Binary files /dev/null and b/mods/moretrees/textures/moretrees_acorn_muffin_batter.png differ diff --git a/mods/moretrees/textures/moretrees_apple_tree_leaves.png b/mods/moretrees/textures/moretrees_apple_tree_leaves.png new file mode 100644 index 00000000..75ec063a Binary files /dev/null and b/mods/moretrees/textures/moretrees_apple_tree_leaves.png differ diff --git a/mods/moretrees/textures/moretrees_apple_tree_sapling.png b/mods/moretrees/textures/moretrees_apple_tree_sapling.png new file mode 100644 index 00000000..04f93fd4 Binary files /dev/null and b/mods/moretrees/textures/moretrees_apple_tree_sapling.png differ diff --git a/mods/moretrees/textures/moretrees_apple_tree_trunk.png b/mods/moretrees/textures/moretrees_apple_tree_trunk.png new file mode 100644 index 00000000..573fd855 Binary files /dev/null and b/mods/moretrees/textures/moretrees_apple_tree_trunk.png differ diff --git a/mods/moretrees/textures/moretrees_apple_tree_trunk_top.png b/mods/moretrees/textures/moretrees_apple_tree_trunk_top.png new file mode 100644 index 00000000..d2617531 Binary files /dev/null and b/mods/moretrees/textures/moretrees_apple_tree_trunk_top.png differ diff --git a/mods/moretrees/textures/moretrees_apple_tree_wood.png b/mods/moretrees/textures/moretrees_apple_tree_wood.png new file mode 100644 index 00000000..242f3ee4 Binary files /dev/null and b/mods/moretrees/textures/moretrees_apple_tree_wood.png differ diff --git a/mods/moretrees/textures/moretrees_beech_leaves.png b/mods/moretrees/textures/moretrees_beech_leaves.png new file mode 100644 index 00000000..8463f530 Binary files /dev/null and b/mods/moretrees/textures/moretrees_beech_leaves.png differ diff --git a/mods/moretrees/textures/moretrees_beech_sapling.png b/mods/moretrees/textures/moretrees_beech_sapling.png new file mode 100644 index 00000000..ff42cc4b Binary files /dev/null and b/mods/moretrees/textures/moretrees_beech_sapling.png differ diff --git a/mods/moretrees/textures/moretrees_beech_trunk.png b/mods/moretrees/textures/moretrees_beech_trunk.png new file mode 100644 index 00000000..06b4ae9c Binary files /dev/null and b/mods/moretrees/textures/moretrees_beech_trunk.png differ diff --git a/mods/moretrees/textures/moretrees_beech_trunk_top.png b/mods/moretrees/textures/moretrees_beech_trunk_top.png new file mode 100644 index 00000000..72859852 Binary files /dev/null and b/mods/moretrees/textures/moretrees_beech_trunk_top.png differ diff --git a/mods/moretrees/textures/moretrees_beech_wood.png b/mods/moretrees/textures/moretrees_beech_wood.png new file mode 100644 index 00000000..d6e3f9d7 Binary files /dev/null and b/mods/moretrees/textures/moretrees_beech_wood.png differ diff --git a/mods/moretrees/textures/moretrees_birch_leaves.png b/mods/moretrees/textures/moretrees_birch_leaves.png new file mode 100644 index 00000000..547f133b Binary files /dev/null and b/mods/moretrees/textures/moretrees_birch_leaves.png differ diff --git a/mods/moretrees/textures/moretrees_birch_sapling.png b/mods/moretrees/textures/moretrees_birch_sapling.png new file mode 100644 index 00000000..afb03f3b Binary files /dev/null and b/mods/moretrees/textures/moretrees_birch_sapling.png differ diff --git a/mods/moretrees/textures/moretrees_birch_trunk.png b/mods/moretrees/textures/moretrees_birch_trunk.png new file mode 100644 index 00000000..2b222f7b Binary files /dev/null and b/mods/moretrees/textures/moretrees_birch_trunk.png differ diff --git a/mods/moretrees/textures/moretrees_birch_trunk_top.png b/mods/moretrees/textures/moretrees_birch_trunk_top.png new file mode 100644 index 00000000..6e5b3bb2 Binary files /dev/null and b/mods/moretrees/textures/moretrees_birch_trunk_top.png differ diff --git a/mods/moretrees/textures/moretrees_birch_wood.png b/mods/moretrees/textures/moretrees_birch_wood.png new file mode 100644 index 00000000..621f8eec Binary files /dev/null and b/mods/moretrees/textures/moretrees_birch_wood.png differ diff --git a/mods/moretrees/textures/moretrees_cedar_cone.png b/mods/moretrees/textures/moretrees_cedar_cone.png new file mode 100644 index 00000000..5e1fae9f Binary files /dev/null and b/mods/moretrees/textures/moretrees_cedar_cone.png differ diff --git a/mods/moretrees/textures/moretrees_cedar_leaves.png b/mods/moretrees/textures/moretrees_cedar_leaves.png new file mode 100644 index 00000000..e6de4829 Binary files /dev/null and b/mods/moretrees/textures/moretrees_cedar_leaves.png differ diff --git a/mods/moretrees/textures/moretrees_cedar_nuts.png b/mods/moretrees/textures/moretrees_cedar_nuts.png new file mode 100644 index 00000000..e39f8954 Binary files /dev/null and b/mods/moretrees/textures/moretrees_cedar_nuts.png differ diff --git a/mods/moretrees/textures/moretrees_cedar_sapling.png b/mods/moretrees/textures/moretrees_cedar_sapling.png new file mode 100644 index 00000000..42f8ecc1 Binary files /dev/null and b/mods/moretrees/textures/moretrees_cedar_sapling.png differ diff --git a/mods/moretrees/textures/moretrees_cedar_trunk.png b/mods/moretrees/textures/moretrees_cedar_trunk.png new file mode 100644 index 00000000..ea685e3a Binary files /dev/null and b/mods/moretrees/textures/moretrees_cedar_trunk.png differ diff --git a/mods/moretrees/textures/moretrees_cedar_trunk_top.png b/mods/moretrees/textures/moretrees_cedar_trunk_top.png new file mode 100644 index 00000000..01aed1d7 Binary files /dev/null and b/mods/moretrees/textures/moretrees_cedar_trunk_top.png differ diff --git a/mods/moretrees/textures/moretrees_cedar_wood.png b/mods/moretrees/textures/moretrees_cedar_wood.png new file mode 100644 index 00000000..8680bd5b Binary files /dev/null and b/mods/moretrees/textures/moretrees_cedar_wood.png differ diff --git a/mods/moretrees/textures/moretrees_coconut.png b/mods/moretrees/textures/moretrees_coconut.png new file mode 100644 index 00000000..2107b5f1 Binary files /dev/null and b/mods/moretrees/textures/moretrees_coconut.png differ diff --git a/mods/moretrees/textures/moretrees_coconut_0.png b/mods/moretrees/textures/moretrees_coconut_0.png new file mode 100644 index 00000000..644a65f8 Binary files /dev/null and b/mods/moretrees/textures/moretrees_coconut_0.png differ diff --git a/mods/moretrees/textures/moretrees_coconut_1.png b/mods/moretrees/textures/moretrees_coconut_1.png new file mode 100644 index 00000000..e2889bce Binary files /dev/null and b/mods/moretrees/textures/moretrees_coconut_1.png differ diff --git a/mods/moretrees/textures/moretrees_coconut_2.png b/mods/moretrees/textures/moretrees_coconut_2.png new file mode 100644 index 00000000..86c8cf5f Binary files /dev/null and b/mods/moretrees/textures/moretrees_coconut_2.png differ diff --git a/mods/moretrees/textures/moretrees_coconut_milk.png b/mods/moretrees/textures/moretrees_coconut_milk.png new file mode 100644 index 00000000..9a54ad8a Binary files /dev/null and b/mods/moretrees/textures/moretrees_coconut_milk.png differ diff --git a/mods/moretrees/textures/moretrees_coconut_milk_inv.png b/mods/moretrees/textures/moretrees_coconut_milk_inv.png new file mode 100644 index 00000000..f6365787 Binary files /dev/null and b/mods/moretrees/textures/moretrees_coconut_milk_inv.png differ diff --git a/mods/moretrees/textures/moretrees_date.png b/mods/moretrees/textures/moretrees_date.png new file mode 100644 index 00000000..ed743b5c Binary files /dev/null and b/mods/moretrees/textures/moretrees_date.png differ diff --git a/mods/moretrees/textures/moretrees_date_nut_bar.png b/mods/moretrees/textures/moretrees_date_nut_bar.png new file mode 100644 index 00000000..68950011 Binary files /dev/null and b/mods/moretrees/textures/moretrees_date_nut_bar.png differ diff --git a/mods/moretrees/textures/moretrees_date_nut_batter.png b/mods/moretrees/textures/moretrees_date_nut_batter.png new file mode 100644 index 00000000..47d8e080 Binary files /dev/null and b/mods/moretrees/textures/moretrees_date_nut_batter.png differ diff --git a/mods/moretrees/textures/moretrees_date_nut_cake.png b/mods/moretrees/textures/moretrees_date_nut_cake.png new file mode 100644 index 00000000..5084e712 Binary files /dev/null and b/mods/moretrees/textures/moretrees_date_nut_cake.png differ diff --git a/mods/moretrees/textures/moretrees_date_nut_snack.png b/mods/moretrees/textures/moretrees_date_nut_snack.png new file mode 100644 index 00000000..1766dab2 Binary files /dev/null and b/mods/moretrees/textures/moretrees_date_nut_snack.png differ diff --git a/mods/moretrees/textures/moretrees_date_palm_leaves.png b/mods/moretrees/textures/moretrees_date_palm_leaves.png new file mode 100644 index 00000000..de0f569d Binary files /dev/null and b/mods/moretrees/textures/moretrees_date_palm_leaves.png differ diff --git a/mods/moretrees/textures/moretrees_date_palm_sapling.png b/mods/moretrees/textures/moretrees_date_palm_sapling.png new file mode 100644 index 00000000..95960288 Binary files /dev/null and b/mods/moretrees/textures/moretrees_date_palm_sapling.png differ diff --git a/mods/moretrees/textures/moretrees_date_palm_trunk.png b/mods/moretrees/textures/moretrees_date_palm_trunk.png new file mode 100644 index 00000000..b8fa9860 Binary files /dev/null and b/mods/moretrees/textures/moretrees_date_palm_trunk.png differ diff --git a/mods/moretrees/textures/moretrees_date_palm_trunk_top.png b/mods/moretrees/textures/moretrees_date_palm_trunk_top.png new file mode 100644 index 00000000..329ba464 Binary files /dev/null and b/mods/moretrees/textures/moretrees_date_palm_trunk_top.png differ diff --git a/mods/moretrees/textures/moretrees_date_palm_wood.png b/mods/moretrees/textures/moretrees_date_palm_wood.png new file mode 100644 index 00000000..c531e3c7 Binary files /dev/null and b/mods/moretrees/textures/moretrees_date_palm_wood.png differ diff --git a/mods/moretrees/textures/moretrees_dates.png b/mods/moretrees/textures/moretrees_dates.png new file mode 100644 index 00000000..cd8d5784 Binary files /dev/null and b/mods/moretrees/textures/moretrees_dates.png differ diff --git a/mods/moretrees/textures/moretrees_dates_f0.png b/mods/moretrees/textures/moretrees_dates_f0.png new file mode 100644 index 00000000..b75d59a3 Binary files /dev/null and b/mods/moretrees/textures/moretrees_dates_f0.png differ diff --git a/mods/moretrees/textures/moretrees_dates_f1.png b/mods/moretrees/textures/moretrees_dates_f1.png new file mode 100644 index 00000000..535150bf Binary files /dev/null and b/mods/moretrees/textures/moretrees_dates_f1.png differ diff --git a/mods/moretrees/textures/moretrees_dates_f2.png b/mods/moretrees/textures/moretrees_dates_f2.png new file mode 100644 index 00000000..e2e299c8 Binary files /dev/null and b/mods/moretrees/textures/moretrees_dates_f2.png differ diff --git a/mods/moretrees/textures/moretrees_dates_f3.png b/mods/moretrees/textures/moretrees_dates_f3.png new file mode 100644 index 00000000..eef43f0b Binary files /dev/null and b/mods/moretrees/textures/moretrees_dates_f3.png differ diff --git a/mods/moretrees/textures/moretrees_dates_f4.png b/mods/moretrees/textures/moretrees_dates_f4.png new file mode 100644 index 00000000..78f38f98 Binary files /dev/null and b/mods/moretrees/textures/moretrees_dates_f4.png differ diff --git a/mods/moretrees/textures/moretrees_dates_fn.png b/mods/moretrees/textures/moretrees_dates_fn.png new file mode 100644 index 00000000..db889130 Binary files /dev/null and b/mods/moretrees/textures/moretrees_dates_fn.png differ diff --git a/mods/moretrees/textures/moretrees_dates_m0.png b/mods/moretrees/textures/moretrees_dates_m0.png new file mode 100644 index 00000000..4ff61e7f Binary files /dev/null and b/mods/moretrees/textures/moretrees_dates_m0.png differ diff --git a/mods/moretrees/textures/moretrees_dates_n.png b/mods/moretrees/textures/moretrees_dates_n.png new file mode 100644 index 00000000..c12a3d99 Binary files /dev/null and b/mods/moretrees/textures/moretrees_dates_n.png differ diff --git a/mods/moretrees/textures/moretrees_fir_cone.png b/mods/moretrees/textures/moretrees_fir_cone.png new file mode 100644 index 00000000..45eef928 Binary files /dev/null and b/mods/moretrees/textures/moretrees_fir_cone.png differ diff --git a/mods/moretrees/textures/moretrees_fir_leaves.png b/mods/moretrees/textures/moretrees_fir_leaves.png new file mode 100644 index 00000000..6643b87b Binary files /dev/null and b/mods/moretrees/textures/moretrees_fir_leaves.png differ diff --git a/mods/moretrees/textures/moretrees_fir_leaves_bright.png b/mods/moretrees/textures/moretrees_fir_leaves_bright.png new file mode 100644 index 00000000..e3b2e6f3 Binary files /dev/null and b/mods/moretrees/textures/moretrees_fir_leaves_bright.png differ diff --git a/mods/moretrees/textures/moretrees_fir_nuts.png b/mods/moretrees/textures/moretrees_fir_nuts.png new file mode 100644 index 00000000..a5341494 Binary files /dev/null and b/mods/moretrees/textures/moretrees_fir_nuts.png differ diff --git a/mods/moretrees/textures/moretrees_fir_sapling.png b/mods/moretrees/textures/moretrees_fir_sapling.png new file mode 100644 index 00000000..642123cd Binary files /dev/null and b/mods/moretrees/textures/moretrees_fir_sapling.png differ diff --git a/mods/moretrees/textures/moretrees_fir_trunk.png b/mods/moretrees/textures/moretrees_fir_trunk.png new file mode 100644 index 00000000..cc0c5596 Binary files /dev/null and b/mods/moretrees/textures/moretrees_fir_trunk.png differ diff --git a/mods/moretrees/textures/moretrees_fir_trunk_top.png b/mods/moretrees/textures/moretrees_fir_trunk_top.png new file mode 100644 index 00000000..d17decf9 Binary files /dev/null and b/mods/moretrees/textures/moretrees_fir_trunk_top.png differ diff --git a/mods/moretrees/textures/moretrees_fir_wood.png b/mods/moretrees/textures/moretrees_fir_wood.png new file mode 100644 index 00000000..7f490797 Binary files /dev/null and b/mods/moretrees/textures/moretrees_fir_wood.png differ diff --git a/mods/moretrees/textures/moretrees_jungletree_leaves_green.png b/mods/moretrees/textures/moretrees_jungletree_leaves_green.png new file mode 100644 index 00000000..52d4a5a4 Binary files /dev/null and b/mods/moretrees/textures/moretrees_jungletree_leaves_green.png differ diff --git a/mods/moretrees/textures/moretrees_jungletree_leaves_red.png b/mods/moretrees/textures/moretrees_jungletree_leaves_red.png new file mode 100644 index 00000000..d26593ee Binary files /dev/null and b/mods/moretrees/textures/moretrees_jungletree_leaves_red.png differ diff --git a/mods/moretrees/textures/moretrees_jungletree_leaves_yellow.png b/mods/moretrees/textures/moretrees_jungletree_leaves_yellow.png new file mode 100644 index 00000000..d116455e Binary files /dev/null and b/mods/moretrees/textures/moretrees_jungletree_leaves_yellow.png differ diff --git a/mods/moretrees/textures/moretrees_oak_leaves.png b/mods/moretrees/textures/moretrees_oak_leaves.png new file mode 100644 index 00000000..aa587c5d Binary files /dev/null and b/mods/moretrees/textures/moretrees_oak_leaves.png differ diff --git a/mods/moretrees/textures/moretrees_oak_sapling.png b/mods/moretrees/textures/moretrees_oak_sapling.png new file mode 100644 index 00000000..eef6a721 Binary files /dev/null and b/mods/moretrees/textures/moretrees_oak_sapling.png differ diff --git a/mods/moretrees/textures/moretrees_oak_trunk.png b/mods/moretrees/textures/moretrees_oak_trunk.png new file mode 100644 index 00000000..b0ca9103 Binary files /dev/null and b/mods/moretrees/textures/moretrees_oak_trunk.png differ diff --git a/mods/moretrees/textures/moretrees_oak_trunk_top.png b/mods/moretrees/textures/moretrees_oak_trunk_top.png new file mode 100644 index 00000000..526d3021 Binary files /dev/null and b/mods/moretrees/textures/moretrees_oak_trunk_top.png differ diff --git a/mods/moretrees/textures/moretrees_oak_wood.png b/mods/moretrees/textures/moretrees_oak_wood.png new file mode 100644 index 00000000..05d02f95 Binary files /dev/null and b/mods/moretrees/textures/moretrees_oak_wood.png differ diff --git a/mods/moretrees/textures/moretrees_palm_leaves.png b/mods/moretrees/textures/moretrees_palm_leaves.png new file mode 100644 index 00000000..90b07002 Binary files /dev/null and b/mods/moretrees/textures/moretrees_palm_leaves.png differ diff --git a/mods/moretrees/textures/moretrees_palm_sapling.png b/mods/moretrees/textures/moretrees_palm_sapling.png new file mode 100644 index 00000000..aaa3415d Binary files /dev/null and b/mods/moretrees/textures/moretrees_palm_sapling.png differ diff --git a/mods/moretrees/textures/moretrees_palm_trunk.png b/mods/moretrees/textures/moretrees_palm_trunk.png new file mode 100644 index 00000000..da255bc6 Binary files /dev/null and b/mods/moretrees/textures/moretrees_palm_trunk.png differ diff --git a/mods/moretrees/textures/moretrees_palm_trunk_top.png b/mods/moretrees/textures/moretrees_palm_trunk_top.png new file mode 100644 index 00000000..fe07ae34 Binary files /dev/null and b/mods/moretrees/textures/moretrees_palm_trunk_top.png differ diff --git a/mods/moretrees/textures/moretrees_palm_wood.png b/mods/moretrees/textures/moretrees_palm_wood.png new file mode 100644 index 00000000..c0c0ed64 Binary files /dev/null and b/mods/moretrees/textures/moretrees_palm_wood.png differ diff --git a/mods/moretrees/textures/moretrees_poplar_leaves.png b/mods/moretrees/textures/moretrees_poplar_leaves.png new file mode 100644 index 00000000..64568bc8 Binary files /dev/null and b/mods/moretrees/textures/moretrees_poplar_leaves.png differ diff --git a/mods/moretrees/textures/moretrees_poplar_sapling.png b/mods/moretrees/textures/moretrees_poplar_sapling.png new file mode 100644 index 00000000..9d5f32a8 Binary files /dev/null and b/mods/moretrees/textures/moretrees_poplar_sapling.png differ diff --git a/mods/moretrees/textures/moretrees_poplar_small_sapling.png b/mods/moretrees/textures/moretrees_poplar_small_sapling.png new file mode 100644 index 00000000..fb9bd030 Binary files /dev/null and b/mods/moretrees/textures/moretrees_poplar_small_sapling.png differ diff --git a/mods/moretrees/textures/moretrees_poplar_trunk-1.png b/mods/moretrees/textures/moretrees_poplar_trunk-1.png new file mode 100644 index 00000000..e4e15405 Binary files /dev/null and b/mods/moretrees/textures/moretrees_poplar_trunk-1.png differ diff --git a/mods/moretrees/textures/moretrees_poplar_trunk.png b/mods/moretrees/textures/moretrees_poplar_trunk.png new file mode 100644 index 00000000..47672fb9 Binary files /dev/null and b/mods/moretrees/textures/moretrees_poplar_trunk.png differ diff --git a/mods/moretrees/textures/moretrees_poplar_trunk_top.png b/mods/moretrees/textures/moretrees_poplar_trunk_top.png new file mode 100644 index 00000000..4c558580 Binary files /dev/null and b/mods/moretrees/textures/moretrees_poplar_trunk_top.png differ diff --git a/mods/moretrees/textures/moretrees_poplar_wood.png b/mods/moretrees/textures/moretrees_poplar_wood.png new file mode 100644 index 00000000..55e6b44e Binary files /dev/null and b/mods/moretrees/textures/moretrees_poplar_wood.png differ diff --git a/mods/moretrees/textures/moretrees_raw_coconut.png b/mods/moretrees/textures/moretrees_raw_coconut.png new file mode 100644 index 00000000..ca318edc Binary files /dev/null and b/mods/moretrees/textures/moretrees_raw_coconut.png differ diff --git a/mods/moretrees/textures/moretrees_rubber_tree_leaves.png b/mods/moretrees/textures/moretrees_rubber_tree_leaves.png new file mode 100644 index 00000000..e35f51bf Binary files /dev/null and b/mods/moretrees/textures/moretrees_rubber_tree_leaves.png differ diff --git a/mods/moretrees/textures/moretrees_rubber_tree_sapling.png b/mods/moretrees/textures/moretrees_rubber_tree_sapling.png new file mode 100644 index 00000000..d2e06d05 Binary files /dev/null and b/mods/moretrees/textures/moretrees_rubber_tree_sapling.png differ diff --git a/mods/moretrees/textures/moretrees_rubber_tree_trunk.png b/mods/moretrees/textures/moretrees_rubber_tree_trunk.png new file mode 100644 index 00000000..c5da574c Binary files /dev/null and b/mods/moretrees/textures/moretrees_rubber_tree_trunk.png differ diff --git a/mods/moretrees/textures/moretrees_rubber_tree_trunk_empty.png b/mods/moretrees/textures/moretrees_rubber_tree_trunk_empty.png new file mode 100644 index 00000000..55423bcf Binary files /dev/null and b/mods/moretrees/textures/moretrees_rubber_tree_trunk_empty.png differ diff --git a/mods/moretrees/textures/moretrees_rubber_tree_trunk_top.png b/mods/moretrees/textures/moretrees_rubber_tree_trunk_top.png new file mode 100644 index 00000000..25b86a92 Binary files /dev/null and b/mods/moretrees/textures/moretrees_rubber_tree_trunk_top.png differ diff --git a/mods/moretrees/textures/moretrees_rubber_tree_wood.png b/mods/moretrees/textures/moretrees_rubber_tree_wood.png new file mode 100644 index 00000000..3c83f0eb Binary files /dev/null and b/mods/moretrees/textures/moretrees_rubber_tree_wood.png differ diff --git a/mods/moretrees/textures/moretrees_sequoia_leaves.png b/mods/moretrees/textures/moretrees_sequoia_leaves.png new file mode 100644 index 00000000..594c9583 Binary files /dev/null and b/mods/moretrees/textures/moretrees_sequoia_leaves.png differ diff --git a/mods/moretrees/textures/moretrees_sequoia_sapling.png b/mods/moretrees/textures/moretrees_sequoia_sapling.png new file mode 100644 index 00000000..b11bc0b7 Binary files /dev/null and b/mods/moretrees/textures/moretrees_sequoia_sapling.png differ diff --git a/mods/moretrees/textures/moretrees_sequoia_trunk.png b/mods/moretrees/textures/moretrees_sequoia_trunk.png new file mode 100644 index 00000000..552cdf55 Binary files /dev/null and b/mods/moretrees/textures/moretrees_sequoia_trunk.png differ diff --git a/mods/moretrees/textures/moretrees_sequoia_trunk_top.png b/mods/moretrees/textures/moretrees_sequoia_trunk_top.png new file mode 100644 index 00000000..d1891fd3 Binary files /dev/null and b/mods/moretrees/textures/moretrees_sequoia_trunk_top.png differ diff --git a/mods/moretrees/textures/moretrees_sequoia_wood.png b/mods/moretrees/textures/moretrees_sequoia_wood.png new file mode 100644 index 00000000..2e43595b Binary files /dev/null and b/mods/moretrees/textures/moretrees_sequoia_wood.png differ diff --git a/mods/moretrees/textures/moretrees_spruce_cone.png b/mods/moretrees/textures/moretrees_spruce_cone.png new file mode 100644 index 00000000..1c9da850 Binary files /dev/null and b/mods/moretrees/textures/moretrees_spruce_cone.png differ diff --git a/mods/moretrees/textures/moretrees_spruce_leaves.png b/mods/moretrees/textures/moretrees_spruce_leaves.png new file mode 100644 index 00000000..6643b87b Binary files /dev/null and b/mods/moretrees/textures/moretrees_spruce_leaves.png differ diff --git a/mods/moretrees/textures/moretrees_spruce_nuts.png b/mods/moretrees/textures/moretrees_spruce_nuts.png new file mode 100644 index 00000000..130c11c8 Binary files /dev/null and b/mods/moretrees/textures/moretrees_spruce_nuts.png differ diff --git a/mods/moretrees/textures/moretrees_spruce_sapling.png b/mods/moretrees/textures/moretrees_spruce_sapling.png new file mode 100644 index 00000000..0275afb5 Binary files /dev/null and b/mods/moretrees/textures/moretrees_spruce_sapling.png differ diff --git a/mods/moretrees/textures/moretrees_spruce_trunk.png b/mods/moretrees/textures/moretrees_spruce_trunk.png new file mode 100644 index 00000000..cc0c5596 Binary files /dev/null and b/mods/moretrees/textures/moretrees_spruce_trunk.png differ diff --git a/mods/moretrees/textures/moretrees_spruce_trunk_top.png b/mods/moretrees/textures/moretrees_spruce_trunk_top.png new file mode 100644 index 00000000..3876c5b3 Binary files /dev/null and b/mods/moretrees/textures/moretrees_spruce_trunk_top.png differ diff --git a/mods/moretrees/textures/moretrees_spruce_wood.png b/mods/moretrees/textures/moretrees_spruce_wood.png new file mode 100644 index 00000000..47aa3262 Binary files /dev/null and b/mods/moretrees/textures/moretrees_spruce_wood.png differ diff --git a/mods/moretrees/textures/moretrees_willow_leaves.png b/mods/moretrees/textures/moretrees_willow_leaves.png new file mode 100644 index 00000000..e1d26d9c Binary files /dev/null and b/mods/moretrees/textures/moretrees_willow_leaves.png differ diff --git a/mods/moretrees/textures/moretrees_willow_sapling.png b/mods/moretrees/textures/moretrees_willow_sapling.png new file mode 100644 index 00000000..18414de4 Binary files /dev/null and b/mods/moretrees/textures/moretrees_willow_sapling.png differ diff --git a/mods/moretrees/textures/moretrees_willow_trunk.png b/mods/moretrees/textures/moretrees_willow_trunk.png new file mode 100644 index 00000000..a3bd5f06 Binary files /dev/null and b/mods/moretrees/textures/moretrees_willow_trunk.png differ diff --git a/mods/moretrees/textures/moretrees_willow_trunk_top.png b/mods/moretrees/textures/moretrees_willow_trunk_top.png new file mode 100644 index 00000000..c54c1820 Binary files /dev/null and b/mods/moretrees/textures/moretrees_willow_trunk_top.png differ diff --git a/mods/moretrees/textures/moretrees_willow_wood.png b/mods/moretrees/textures/moretrees_willow_wood.png new file mode 100644 index 00000000..21c57428 Binary files /dev/null and b/mods/moretrees/textures/moretrees_willow_wood.png differ diff --git a/mods/moretrees/tree_biomes.txt b/mods/moretrees/tree_biomes.txt new file mode 100644 index 00000000..b6a4fd0f --- /dev/null +++ b/mods/moretrees/tree_biomes.txt @@ -0,0 +1,34 @@ + + Elevation Temperature Nearness to Nearby What nodes Perlin Avoid +Tree type (m) (approx., °C) some node water to spawn on seed diff radius +-------------------------------------------------------------------------------------------------------------- +jungle tree - 5 to +10 above +15 water, 20 10 dirt_with_grass 329 5 +fir above +25 -20 to +10 n/a n/a dirt_with_grass 359 8 +firs on snow above +15 -20 to +10 n/a n/a snow:snow 359 8 +palm - 1 to + 1 +15 to +32 water, 15 10 sand 330 5 +date palm - 1 to +10 above +39 water, 20h,20v 100 desert_sand 339 10 +date palm +11 to +30 above +39 water, 1h,30v 1 desert_sand 340 10 +apple + 1 to +10 +23 to +32 n/a n/a dirt_with grass 331 15 +oak 0 to +10 + 4 to +16 n/a n/a dirt_with grass 332 15 +sequoia 0 to +10 -30 to +50 n/a n/a dirt_with grass 333 10 +birch +10 to +15 -20 to +10 n/a n/a dirt_with grass 334 5 +spruce above +20 -20 to +10 n/a n/a dirt_with grass 335 10 +cedar n/a n/a water, 15 5 dirt_with grass 336 10 +willow - 5 to + 5 n/a water, 15 5 dirt_with grass 337 20 +rubber - 5 to + 5 above +32 water, 15 10 dirt_with_grass 338 20 +poplar n/a -10 to +26 water, 15h,5v 1 dirt_with_grass 341,342,343 10 + +beech n/a n/a n/a n/a dirt_with_grass 2 10 + + +Notes: +------ + +Beech trees are meant to replace default trees, but are themselves disabled by default. They grow in the same areas +as the default ones do, and under the same conditions. + +Fir trees appear in a snow biome only with older versions of SPlizard's Snow Biomes mod. In more recent versions, +these trees will not grow, due to an engine bug. + +Cedar trees replace, and are identical to, the original pine trees, as the minetest default game now has (a completely +different type of) pine trees. diff --git a/mods/moretrees/tree_models.lua b/mods/moretrees/tree_models.lua new file mode 100644 index 00000000..eb6541e6 --- /dev/null +++ b/mods/moretrees/tree_models.lua @@ -0,0 +1,275 @@ +moretrees.beech_model={ + axiom="FFFFFBFB", + rules_a="[&&&GGF[++^Fd][--&Fd]//Fd[+^Fd][--&Fd]]////[&&&GGF[++^Fd][--&Fd]//Fd[+^Fd][--&Fd]]////[&&&GGF[++^Fd][--&Fd]//Fd[+^Fd][--&Fdd]]", + rules_b="[&&&F[++^Fd][--&d]//d[+^d][--&d]]////[&&&F[++^Fd][--&d]//d[+^d][--&d]]////[&&&F[++^Fd][--&Fd]//d[+^d][--&d]]", + rules_c="/", + rules_d="F", + trunk="moretrees:beech_trunk", + leaves="moretrees:beech_leaves", + angle=30, + iterations=2, + random_level=0, + trunk_type="single", + thin_branches=true +} + +moretrees.apple_tree_model={ + axiom="FFFFFAFFBF", + rules_a="[&&&FFFFF&&FFFF][&&&++++FFFFF&&FFFF][&&&----FFFFF&&FFFF]", + rules_b="[&&&++FFFFF&&FFFF][&&&--FFFFF&&FFFF][&&&------FFFFF&&FFFF]", + trunk="moretrees:apple_tree_trunk", + leaves="moretrees:apple_tree_leaves", + angle=30, + iterations=2, + random_level=0, + trunk_type="single", + thin_branches=true, + fruit="default:apple", + fruit_chance=15, +} + +moretrees.oak_model={ + axiom="FFFFFFA", + rules_a="[&FFBFA]////[&BFFFA]////[&FBFFA]", + rules_b="[&FFFA]////[&FFFA]////[&FFFA]", + trunk="moretrees:oak_trunk", + leaves="moretrees:oak_leaves", + angle=30, + iterations=5, + random_level=2, + trunk_type="crossed", + thin_branches=false, + fruit="moretrees:acorn", + fruit_chance=3, +} + +moretrees.poplar_model={ + axiom="TTTaaBCCCCCCCCCCCcccBBB[[f]&&G++f++Gf++Gf++Gf++G--]G[[f]&&G++f++Gf++Gf++Gf++G--]Gff", + rules_a="T", + rules_b="[[T]&&G++f++ff++ff++ff++f--]G", + rules_c="[[T]&&G++f++ff++ff++ff++f--G++[d]G[d]G++G[d]G[d]G[d]G++G[d]G[d]G[d]G++G[d]G[d]G[d]G++G[d]G]G", + rules_d="f", + trunk="moretrees:poplar_trunk", + leaves="moretrees:poplar_leaves", + angle=45, + iterations=0, + random_level=0, + trunk_type="single", + thin_branches=false, +} + +moretrees.poplar_small_model={ + axiom="TT[T]BCCCCccBBff", + rules_a="T", + rules_b="[[f]&&G++f++Gf++Gf++Gf++G--]G", + rules_c="[[T]&&G++f++[d]Gf++[d]Gf++[d]Gf++[d]G--]G", + rules_d="f", + trunk="moretrees:poplar_trunk", + leaves="moretrees:poplar_leaves", + angle=45, + iterations=0, + random_level=0, + trunk_type="single", + thin_branches=false, +} + +moretrees.sequoia_model={ + axiom="FFFFFFFFFFddccA///cccFddcFA///ddFcFA/cFFddFcdBddd/A/ccdcddd/ccAddddcFBcccAccFdFcFBcccc/BFdFFcFFdcccc/B", + rules_a="[&&&GGF[++^FFdd][--&Fddd]//Fdd[+^Fd][--&Fdd]]////[&&&GGF[++^FFdd][--&Fddd]//Fdd[+^Fd][--&Fdd]]////[&&&GGF[++^FFdd][--&Fddd]//Fdd[+^Fd][--&Fdd]]", + rules_b="[&&&GGF[++^Fdd][--&Fdd]//dd[+^d][--&Fd]]////[&&&GGF[++^Fdd][--&Fdd]//dd[+^d][--&Fd]]////[&&&GGF[++^Fdd][--&Fdd]//dd[+^d][--&Fd]]", + rules_c="/", + rules_d="F", + trunk="moretrees:sequoia_trunk", + leaves="moretrees:sequoia_leaves", + angle=30, + iterations=2, + random_level=0, + trunk_type="crossed", + thin_branches=true +} + +moretrees.birch_model1={ + axiom="FFFFFdddccA/FFFFFFcA/FFFFFFcB", + rules_a="[&&&dddd^^ddddddd][&&&---dddd^^ddddddd][&&&+++dddd^^ddddddd][&&&++++++dddd^^ddddddd]", + rules_b="[&&&ddd^^ddddd][&&&---ddd^^ddddd][&&&+++ddd^^ddddd][&&&++++++ddd^^ddddd]", + rules_c="/", + rules_d="F", + trunk="moretrees:birch_trunk", + leaves="moretrees:birch_leaves", + angle=30, + iterations=2, + random_level=0, + trunk_type="single", + thin_branches=true +} + +moretrees.birch_model2={ + axiom="FFFdddccA/FFFFFccA/FFFFFccB", + rules_a="[&&&dFFF^^FFFdd][&&&---dFFF^^FFFdd][&&&+++dFFF^^FFFdd][&&&++++++dFFF^^FFFdd]", + rules_b="[&&&dFF^^FFFd][&&&---dFFF^^FFFd][&&&+++dFF^^FFFd][&&&++++++dFF^^FFFd]", + rules_c="/", + rules_d="F", + trunk="moretrees:birch_trunk", + leaves="moretrees:birch_leaves", + angle=30, + iterations=2, + random_level=0, + trunk_type="single", + thin_branches=true +} + +-- Coconuts can't be generated as fruit, because there is no support for the +-- special fruit trunks that allow coconuts to regrow at the correct position +-- in the tree. +-- So, a placeholder fruit trunk is spawned. An ABM will convert it to the final +-- fruit trunk, and generate the actual coconuts. +moretrees.palm_model={ + axiom="FFcccccc&FFFFFdddRA//A//A//A//A//A", + rules_a="[&fb&bbb[++f--&ffff&ff][--f++&ffff&ff]&ffff&bbbb&b]", + rules_b="f", + rules_c="/", + rules_d="F", + trunk="moretrees:palm_trunk", + leaves="moretrees:palm_leaves", + angle=30, + iterations=2, + random_level=0, + trunk_type="single", + thin_branches=true, + fruit="moretrees:palm_fruit_trunk_gen", + fruit_chance=0 +} + +-- Dates can't be generated as fruit, because there is no support for the +-- special (male and female) fruit trunks that allow dates to regrow at the +-- correct position in the tree. +-- So, a generic fruit trunk is spawned. An ABM will convert it to a male +-- or female fruit trunk, and generate the actual dates. +moretrees.date_palm_model={ + axiom="TTTTddddddddddccccccccccRT[TGGGGT]".. + "ccccc[&&a]ccccc[&&a]ccccc[&&a]ccccc[&&a]ccccc[&&a]ccccc[&&a]".. + "GGccccc[&a]ccccc[&a]ccccc[&a]ccccc[&a]ccccc[&a]ccccc[&a]".. + "GGccccc[a]ccccc[a]ccccc[a]ccccc[a]ccccc[a]ccccc[a]", + rules_a="Gffb&bbb[++f--&ffff&ff][--f++&ffff&ff]&ff&ff&bb&bb&bb", + rules_b="f", + rules_c="/", + rules_d="F", + trunk="moretrees:date_palm_trunk", + leaves="moretrees:date_palm_leaves", + angle=18, + iterations=1, + random_level=0, + trunk_type="single", + thin_branches=false, + fruit="moretrees:date_palm_fruit_trunk", + fruit_chance=0 +} + +moretrees.spruce_model1={ + axiom="FFFFFAFFFFFFBFFFFFFCFFFFFFDFFFFFF[&&&F^^FF][&&&++F^^FF][&&&++++F^^FF][&&&++++++F^^FF][&&&--F^^FF][&&&----F^^FF][FFFFf]", + rules_a="[&&&FFFFFF^^FFF][&&&++FFFFFF^^FFF][&&&++++FFFFFF^^FFF][&&&++++++FFFFFF^^FFF][&&&--FFFFFF^^FFF][&&&----FFFFFF^^FFF]", + rules_b="[&&&FFFFF^^FFF][&&&++FFFFF^^FFF][&&&++++FFFFF^^FFF][&&&++++++FFFFF^^FFF][&&&--FFFFF^^FFF][&&&----FFFFF^^FFF]", + rules_c="[&&&FFFF^^FFF][&&&++FFFF^^FFF][&&&++++FFFF^^FFF][&&&++++++FFFF^^FFF][&&&--FFFF^^FFF][&&&----FFFF^^FFF]", + rules_d="[&&&FFF^^FFF][&&&++FFF^^FFF][&&&++++FFF^^FFF][&&&++++++FFF^^FFF][&&&--FFF^^FFF][&&&----FFF^^FFF]", + trunk="moretrees:spruce_trunk", + leaves="moretrees:spruce_leaves", + angle=30, + iterations=2, + random_level=0, + trunk_type="crossed", + thin_branches=true, + fruit="moretrees:spruce_cone", + fruit_chance=8 +} + +moretrees.spruce_model2={ + axiom="FFFFFFBFFFFFFCFFFFFFDFFFFFF[&&&F^^FF][&&&++F^^FF][&&&++++F^^FF][&&&++++++F^^FF][&&&--F^^FF][&&&----F^^FF][FFFFf]", + rules_b="[&&&FFFFF^^FFF][&&&++FFFFF^^FFF][&&&++++FFFFF^^FFF][&&&++++++FFFFF^^FFF][&&&--FFFFF^^FFF][&&&----FFFFF^^FFF]", + rules_c="[&&&FFFF^^FFF][&&&++FFFF^^FFF][&&&++++FFFF^^FFF][&&&++++++FFFF^^FFF][&&&--FFFF^^FFF][&&&----FFFF^^FFF]", + rules_d="[&&&FFF^^FFF][&&&++FFF^^FFF][&&&++++FFF^^FFF][&&&++++++FFF^^FFF][&&&--FFF^^FFF][&&&----FFF^^FFF]", + trunk="moretrees:spruce_trunk", + leaves="moretrees:spruce_leaves", + angle=30, + iterations=2, + random_level=0, + trunk_type="crossed", + thin_branches=true, + fruit="moretrees:spruce_cone", + fruit_chance=8 +} + +moretrees.cedar_model={ + axiom="FFFFFcccdddB///cFdFB////cFdFB///cFdFB///cFdFA///cFdFA///cFdFB[FF]f", + rules_a="[&&&TTTT[++^TFdd][--&TFd]//Tdd[+^Fd][--&Fdd]]", + rules_b="[&&&TTT[++^Fdd][--&Fdd]//dd[+^d][--&Fd]]", + rules_c="/", + rules_d="F", + trunk="moretrees:cedar_trunk", + leaves="moretrees:cedar_leaves", + angle=30, + iterations=2, + random_level=0, + trunk_type="single", + thin_branches=true, + fruit="moretrees:cedar_cone", + fruit_chance=8 +} + +moretrees.willow_model={ + axiom="FFFFFFFFccA", + rules_a="[&FF&FFFF&&F&FFFFFFFdddd][**&FF&FFFF&&F&FFFFFFFdddd][//&FF&FFFF&&F&FFFFFFFdddd][////&FF&FFFF&&F&FFFFFFFdddd][//////&FF&FFFF&&F&FFFFFFFdddd][////////&FF&FFFF&&F&FFFFFFFdddd]", + rules_c="/", + rules_d="F", + trunk="moretrees:willow_trunk", + leaves="moretrees:willow_leaves", + angle=30, + iterations=2, + random_level=0, + trunk_type="crossed", + thin_branches=true +} + +moretrees.rubber_tree_model={ + axiom="FFFFA", + rules_a="[&FFBFA]////[&BFFFA]////[&FBFFA]", + rules_b="[&FFA]////[&FFA]////[&FFA]", + trunk="moretrees:rubber_tree_trunk", + leaves="moretrees:rubber_tree_leaves", + angle=35, + iterations=3, + random_level=1, + trunk_type="double", + thin_branches=true +} + +moretrees.jungletree_model={ + axiom=nil, + rules_a=nil, + rules_b=nil, + trunk="moretrees:jungletree_trunk", + leaves="default:jungleleaves", + leaves2=nil, + leaves2_chance=nil, + angle=45, + iterations=nil, + random_level=2, + trunk_type=nil, + thin_branches=true, + fruit_chance=15, + fruit="vines:vine" +} + +moretrees.fir_model={ + axiom="FFFAF[&&-F][&&+F][&&---F][&&+++F]Fff", + rules_a=nil, + rules_b=nil, + trunk="moretrees:fir_trunk", + leaves=nil, + angle=45, + iterations=7, + random_level=5, + trunk_type="single", + thin_branches=true, + fruit="moretrees:fir_cone", + fruit_chance=8 +} diff --git a/mods/trees_lib/LICENSE.txt b/mods/trees_lib/LICENSE.txt new file mode 100644 index 00000000..e5ab03e1 --- /dev/null +++ b/mods/trees_lib/LICENSE.txt @@ -0,0 +1,502 @@ + GNU LESSER GENERAL PUBLIC LICENSE + Version 2.1, February 1999 + + Copyright (C) 1991, 1999 Free Software Foundation, Inc. + 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301 USA + Everyone is permitted to copy and distribute verbatim copies + of this license document, but changing it is not allowed. + +[This is the first released version of the Lesser GPL. It also counts + as the successor of the GNU Library Public License, version 2, hence + the version number 2.1.] + + Preamble + + The licenses for most software are designed to take away your +freedom to share and change it. By contrast, the GNU General Public +Licenses are intended to guarantee your freedom to share and change +free software--to make sure the software is free for all its users. + + This license, the Lesser General Public License, applies to some +specially designated software packages--typically libraries--of the +Free Software Foundation and other authors who decide to use it. You +can use it too, but we suggest you first think carefully about whether +this license or the ordinary General Public License is the better +strategy to use in any particular case, based on the explanations below. + + When we speak of free software, we are referring to freedom of use, +not price. Our General Public Licenses are designed to make sure that +you have the freedom to distribute copies of free software (and charge +for this service if you wish); that you receive source code or can get +it if you want it; that you can change the software and use pieces of +it in new free programs; and that you are informed that you can do +these things. + + To protect your rights, we need to make restrictions that forbid +distributors to deny you these rights or to ask you to surrender these +rights. These restrictions translate to certain responsibilities for +you if you distribute copies of the library or if you modify it. + + For example, if you distribute copies of the library, whether gratis +or for a fee, you must give the recipients all the rights that we gave +you. You must make sure that they, too, receive or can get the source +code. If you link other code with the library, you must provide +complete object files to the recipients, so that they can relink them +with the library after making changes to the library and recompiling +it. And you must show them these terms so they know their rights. + + We protect your rights with a two-step method: (1) we copyright the +library, and (2) we offer you this license, which gives you legal +permission to copy, distribute and/or modify the library. + + To protect each distributor, we want to make it very clear that +there is no warranty for the free library. Also, if the library is +modified by someone else and passed on, the recipients should know +that what they have is not the original version, so that the original +author's reputation will not be affected by problems that might be +introduced by others. + + Finally, software patents pose a constant threat to the existence of +any free program. We wish to make sure that a company cannot +effectively restrict the users of a free program by obtaining a +restrictive license from a patent holder. Therefore, we insist that +any patent license obtained for a version of the library must be +consistent with the full freedom of use specified in this license. + + Most GNU software, including some libraries, is covered by the +ordinary GNU General Public License. This license, the GNU Lesser +General Public License, applies to certain designated libraries, and +is quite different from the ordinary General Public License. We use +this license for certain libraries in order to permit linking those +libraries into non-free programs. + + When a program is linked with a library, whether statically or using +a shared library, the combination of the two is legally speaking a +combined work, a derivative of the original library. The ordinary +General Public License therefore permits such linking only if the +entire combination fits its criteria of freedom. The Lesser General +Public License permits more lax criteria for linking other code with +the library. + + We call this license the "Lesser" General Public License because it +does Less to protect the user's freedom than the ordinary General +Public License. It also provides other free software developers Less +of an advantage over competing non-free programs. These disadvantages +are the reason we use the ordinary General Public License for many +libraries. However, the Lesser license provides advantages in certain +special circumstances. + + For example, on rare occasions, there may be a special need to +encourage the widest possible use of a certain library, so that it becomes +a de-facto standard. To achieve this, non-free programs must be +allowed to use the library. A more frequent case is that a free +library does the same job as widely used non-free libraries. In this +case, there is little to gain by limiting the free library to free +software only, so we use the Lesser General Public License. + + In other cases, permission to use a particular library in non-free +programs enables a greater number of people to use a large body of +free software. For example, permission to use the GNU C Library in +non-free programs enables many more people to use the whole GNU +operating system, as well as its variant, the GNU/Linux operating +system. + + Although the Lesser General Public License is Less protective of the +users' freedom, it does ensure that the user of a program that is +linked with the Library has the freedom and the wherewithal to run +that program using a modified version of the Library. + + The precise terms and conditions for copying, distribution and +modification follow. Pay close attention to the difference between a +"work based on the library" and a "work that uses the library". The +former contains code derived from the library, whereas the latter must +be combined with the library in order to run. + + GNU LESSER GENERAL PUBLIC LICENSE + TERMS AND CONDITIONS FOR COPYING, DISTRIBUTION AND MODIFICATION + + 0. This License Agreement applies to any software library or other +program which contains a notice placed by the copyright holder or +other authorized party saying it may be distributed under the terms of +this Lesser General Public License (also called "this License"). +Each licensee is addressed as "you". + + A "library" means a collection of software functions and/or data +prepared so as to be conveniently linked with application programs +(which use some of those functions and data) to form executables. + + The "Library", below, refers to any such software library or work +which has been distributed under these terms. A "work based on the +Library" means either the Library or any derivative work under +copyright law: that is to say, a work containing the Library or a +portion of it, either verbatim or with modifications and/or translated +straightforwardly into another language. (Hereinafter, translation is +included without limitation in the term "modification".) + + "Source code" for a work means the preferred form of the work for +making modifications to it. For a library, complete source code means +all the source code for all modules it contains, plus any associated +interface definition files, plus the scripts used to control compilation +and installation of the library. + + Activities other than copying, distribution and modification are not +covered by this License; they are outside its scope. The act of +running a program using the Library is not restricted, and output from +such a program is covered only if its contents constitute a work based +on the Library (independent of the use of the Library in a tool for +writing it). Whether that is true depends on what the Library does +and what the program that uses the Library does. + + 1. You may copy and distribute verbatim copies of the Library's +complete source code as you receive it, in any medium, provided that +you conspicuously and appropriately publish on each copy an +appropriate copyright notice and disclaimer of warranty; keep intact +all the notices that refer to this License and to the absence of any +warranty; and distribute a copy of this License along with the +Library. + + You may charge a fee for the physical act of transferring a copy, +and you may at your option offer warranty protection in exchange for a +fee. + + 2. You may modify your copy or copies of the Library or any portion +of it, thus forming a work based on the Library, and copy and +distribute such modifications or work under the terms of Section 1 +above, provided that you also meet all of these conditions: + + a) The modified work must itself be a software library. + + b) You must cause the files modified to carry prominent notices + stating that you changed the files and the date of any change. + + c) You must cause the whole of the work to be licensed at no + charge to all third parties under the terms of this License. + + d) If a facility in the modified Library refers to a function or a + table of data to be supplied by an application program that uses + the facility, other than as an argument passed when the facility + is invoked, then you must make a good faith effort to ensure that, + in the event an application does not supply such function or + table, the facility still operates, and performs whatever part of + its purpose remains meaningful. + + (For example, a function in a library to compute square roots has + a purpose that is entirely well-defined independent of the + application. Therefore, Subsection 2d requires that any + application-supplied function or table used by this function must + be optional: if the application does not supply it, the square + root function must still compute square roots.) + +These requirements apply to the modified work as a whole. If +identifiable sections of that work are not derived from the Library, +and can be reasonably considered independent and separate works in +themselves, then this License, and its terms, do not apply to those +sections when you distribute them as separate works. But when you +distribute the same sections as part of a whole which is a work based +on the Library, the distribution of the whole must be on the terms of +this License, whose permissions for other licensees extend to the +entire whole, and thus to each and every part regardless of who wrote +it. + +Thus, it is not the intent of this section to claim rights or contest +your rights to work written entirely by you; rather, the intent is to +exercise the right to control the distribution of derivative or +collective works based on the Library. + +In addition, mere aggregation of another work not based on the Library +with the Library (or with a work based on the Library) on a volume of +a storage or distribution medium does not bring the other work under +the scope of this License. + + 3. You may opt to apply the terms of the ordinary GNU General Public +License instead of this License to a given copy of the Library. To do +this, you must alter all the notices that refer to this License, so +that they refer to the ordinary GNU General Public License, version 2, +instead of to this License. (If a newer version than version 2 of the +ordinary GNU General Public License has appeared, then you can specify +that version instead if you wish.) Do not make any other change in +these notices. + + Once this change is made in a given copy, it is irreversible for +that copy, so the ordinary GNU General Public License applies to all +subsequent copies and derivative works made from that copy. + + This option is useful when you wish to copy part of the code of +the Library into a program that is not a library. + + 4. You may copy and distribute the Library (or a portion or +derivative of it, under Section 2) in object code or executable form +under the terms of Sections 1 and 2 above provided that you accompany +it with the complete corresponding machine-readable source code, which +must be distributed under the terms of Sections 1 and 2 above on a +medium customarily used for software interchange. + + If distribution of object code is made by offering access to copy +from a designated place, then offering equivalent access to copy the +source code from the same place satisfies the requirement to +distribute the source code, even though third parties are not +compelled to copy the source along with the object code. + + 5. A program that contains no derivative of any portion of the +Library, but is designed to work with the Library by being compiled or +linked with it, is called a "work that uses the Library". Such a +work, in isolation, is not a derivative work of the Library, and +therefore falls outside the scope of this License. + + However, linking a "work that uses the Library" with the Library +creates an executable that is a derivative of the Library (because it +contains portions of the Library), rather than a "work that uses the +library". The executable is therefore covered by this License. +Section 6 states terms for distribution of such executables. + + When a "work that uses the Library" uses material from a header file +that is part of the Library, the object code for the work may be a +derivative work of the Library even though the source code is not. +Whether this is true is especially significant if the work can be +linked without the Library, or if the work is itself a library. The +threshold for this to be true is not precisely defined by law. + + If such an object file uses only numerical parameters, data +structure layouts and accessors, and small macros and small inline +functions (ten lines or less in length), then the use of the object +file is unrestricted, regardless of whether it is legally a derivative +work. (Executables containing this object code plus portions of the +Library will still fall under Section 6.) + + Otherwise, if the work is a derivative of the Library, you may +distribute the object code for the work under the terms of Section 6. +Any executables containing that work also fall under Section 6, +whether or not they are linked directly with the Library itself. + + 6. As an exception to the Sections above, you may also combine or +link a "work that uses the Library" with the Library to produce a +work containing portions of the Library, and distribute that work +under terms of your choice, provided that the terms permit +modification of the work for the customer's own use and reverse +engineering for debugging such modifications. + + You must give prominent notice with each copy of the work that the +Library is used in it and that the Library and its use are covered by +this License. You must supply a copy of this License. If the work +during execution displays copyright notices, you must include the +copyright notice for the Library among them, as well as a reference +directing the user to the copy of this License. Also, you must do one +of these things: + + a) Accompany the work with the complete corresponding + machine-readable source code for the Library including whatever + changes were used in the work (which must be distributed under + Sections 1 and 2 above); and, if the work is an executable linked + with the Library, with the complete machine-readable "work that + uses the Library", as object code and/or source code, so that the + user can modify the Library and then relink to produce a modified + executable containing the modified Library. (It is understood + that the user who changes the contents of definitions files in the + Library will not necessarily be able to recompile the application + to use the modified definitions.) + + b) Use a suitable shared library mechanism for linking with the + Library. A suitable mechanism is one that (1) uses at run time a + copy of the library already present on the user's computer system, + rather than copying library functions into the executable, and (2) + will operate properly with a modified version of the library, if + the user installs one, as long as the modified version is + interface-compatible with the version that the work was made with. + + c) Accompany the work with a written offer, valid for at + least three years, to give the same user the materials + specified in Subsection 6a, above, for a charge no more + than the cost of performing this distribution. + + d) If distribution of the work is made by offering access to copy + from a designated place, offer equivalent access to copy the above + specified materials from the same place. + + e) Verify that the user has already received a copy of these + materials or that you have already sent this user a copy. + + For an executable, the required form of the "work that uses the +Library" must include any data and utility programs needed for +reproducing the executable from it. However, as a special exception, +the materials to be distributed need not include anything that is +normally distributed (in either source or binary form) with the major +components (compiler, kernel, and so on) of the operating system on +which the executable runs, unless that component itself accompanies +the executable. + + It may happen that this requirement contradicts the license +restrictions of other proprietary libraries that do not normally +accompany the operating system. Such a contradiction means you cannot +use both them and the Library together in an executable that you +distribute. + + 7. 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 not covered by this License, and distribute such a combined +library, provided that the separate distribution of the work based on +the Library and of the other library facilities is otherwise +permitted, and provided that you do these two things: + + a) Accompany the combined library with a copy of the same work + based on the Library, uncombined with any other library + facilities. This must be distributed under the terms of the + Sections above. + + b) Give prominent notice with the combined library of the fact + that part of it is a work based on the Library, and explaining + where to find the accompanying uncombined form of the same work. + + 8. You may not copy, modify, sublicense, link with, or distribute +the Library except as expressly provided under this License. Any +attempt otherwise to copy, modify, sublicense, link with, or +distribute the Library is void, and will automatically terminate your +rights under this License. However, parties who have received copies, +or rights, from you under this License will not have their licenses +terminated so long as such parties remain in full compliance. + + 9. You are not required to accept this License, since you have not +signed it. However, nothing else grants you permission to modify or +distribute the Library or its derivative works. These actions are +prohibited by law if you do not accept this License. Therefore, by +modifying or distributing the Library (or any work based on the +Library), you indicate your acceptance of this License to do so, and +all its terms and conditions for copying, distributing or modifying +the Library or works based on it. + + 10. Each time you redistribute the Library (or any work based on the +Library), the recipient automatically receives a license from the +original licensor to copy, distribute, link with or modify the Library +subject to these terms and conditions. You may not impose any further +restrictions on the recipients' exercise of the rights granted herein. +You are not responsible for enforcing compliance by third parties with +this License. + + 11. If, as a consequence of a court judgment or allegation of patent +infringement or for any other reason (not limited to patent issues), +conditions are imposed on you (whether by court order, agreement or +otherwise) that contradict the conditions of this License, they do not +excuse you from the conditions of this License. If you cannot +distribute so as to satisfy simultaneously your obligations under this +License and any other pertinent obligations, then as a consequence you +may not distribute the Library at all. For example, if a patent +license would not permit royalty-free redistribution of the Library by +all those who receive copies directly or indirectly through you, then +the only way you could satisfy both it and this License would be to +refrain entirely from distribution of the Library. + +If any portion of this section is held invalid or unenforceable under any +particular circumstance, the balance of the section is intended to apply, +and the section as a whole is intended to apply in other circumstances. + +It is not the purpose of this section to induce you to infringe any +patents or other property right claims or to contest validity of any +such claims; this section has the sole purpose of protecting the +integrity of the free software distribution system which is +implemented by public license practices. Many people have made +generous contributions to the wide range of software distributed +through that system in reliance on consistent application of that +system; it is up to the author/donor to decide if he or she is willing +to distribute software through any other system and a licensee cannot +impose that choice. + +This section is intended to make thoroughly clear what is believed to +be a consequence of the rest of this License. + + 12. If the distribution and/or use of the Library is restricted in +certain countries either by patents or by copyrighted interfaces, the +original copyright holder who places the Library under this License may add +an explicit geographical distribution limitation excluding those countries, +so that distribution is permitted only in or among countries not thus +excluded. In such case, this License incorporates the limitation as if +written in the body of this License. + + 13. The Free Software Foundation may publish revised and/or new +versions of the 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 +specifies a version number of this License which applies to it and +"any later version", you have the option of following the terms and +conditions either of that version or of any later version published by +the Free Software Foundation. If the Library does not specify a +license version number, you may choose any version ever published by +the Free Software Foundation. + + 14. If you wish to incorporate parts of the Library into other free +programs whose distribution conditions are incompatible with these, +write to the author to ask for permission. For software which is +copyrighted by the Free Software Foundation, write to the Free +Software Foundation; we sometimes make exceptions for this. Our +decision will be guided by the two goals of preserving the free status +of all derivatives of our free software and of promoting the sharing +and reuse of software generally. + + NO WARRANTY + + 15. BECAUSE THE LIBRARY IS LICENSED FREE OF CHARGE, THERE IS NO +WARRANTY FOR THE LIBRARY, TO THE EXTENT PERMITTED BY APPLICABLE LAW. +EXCEPT WHEN OTHERWISE STATED IN WRITING THE COPYRIGHT HOLDERS AND/OR +OTHER PARTIES PROVIDE THE LIBRARY "AS IS" WITHOUT WARRANTY OF ANY +KIND, EITHER EXPRESSED OR IMPLIED, INCLUDING, BUT NOT LIMITED TO, THE +IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR +PURPOSE. THE ENTIRE RISK AS TO THE QUALITY AND PERFORMANCE OF THE +LIBRARY IS WITH YOU. SHOULD THE LIBRARY PROVE DEFECTIVE, YOU ASSUME +THE COST OF ALL NECESSARY SERVICING, REPAIR OR CORRECTION. + + 16. IN NO EVENT UNLESS REQUIRED BY APPLICABLE LAW OR AGREED TO IN +WRITING WILL ANY COPYRIGHT HOLDER, OR ANY OTHER PARTY WHO MAY MODIFY +AND/OR REDISTRIBUTE THE LIBRARY AS PERMITTED ABOVE, BE LIABLE TO YOU +FOR DAMAGES, INCLUDING ANY GENERAL, SPECIAL, INCIDENTAL OR +CONSEQUENTIAL DAMAGES ARISING OUT OF THE USE OR INABILITY TO USE THE +LIBRARY (INCLUDING BUT NOT LIMITED TO LOSS OF DATA OR DATA BEING +RENDERED INACCURATE OR LOSSES SUSTAINED BY YOU OR THIRD PARTIES OR A +FAILURE OF THE LIBRARY TO OPERATE WITH ANY OTHER SOFTWARE), EVEN IF +SUCH HOLDER OR OTHER PARTY HAS BEEN ADVISED OF THE POSSIBILITY OF SUCH +DAMAGES. + + END OF TERMS AND CONDITIONS + + How to Apply These Terms to Your New Libraries + + If you develop a new library, and you want it to be of the greatest +possible use to the public, we recommend making it free software that +everyone can redistribute and change. You can do so by permitting +redistribution under these terms (or, alternatively, under the terms of the +ordinary General Public License). + + To apply these terms, attach the following notices to the library. It is +safest to attach them to the start of each source file to most effectively +convey the exclusion of warranty; and each file should have at least the +"copyright" line and a pointer to where the full notice is found. + + + Copyright (C) + + This library is free software; you can redistribute it and/or + modify it under the terms of the GNU Lesser General Public + License as published by the Free Software Foundation; either + version 2.1 of the License, or (at your option) any later version. + + This library is distributed in the hope that it will be useful, + but WITHOUT ANY WARRANTY; without even the implied warranty of + MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU + Lesser General Public License for more details. + + You should have received a copy of the GNU Lesser General Public + License along with this library; if not, write to the Free Software + Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301 USA + +Also add information on how to contact you by electronic and paper mail. + +You should also get your employer (if you work as a programmer) or your +school, if any, to sign a "copyright disclaimer" for the library, if +necessary. Here is a sample; alter the names: + + Yoyodyne, Inc., hereby disclaims all copyright interest in the + library `Frob' (a library for tweaking knobs) written by James Random Hacker. + + , 1 April 1990 + Ty Coon, President of Vice + +That's all there is to it! diff --git a/mods/trees_lib/README.md b/mods/trees_lib/README.md new file mode 100644 index 00000000..98b86fe0 --- /dev/null +++ b/mods/trees_lib/README.md @@ -0,0 +1,122 @@ +Trees are common. Yet they are all registered manually so far. And plugging +in to their growing mechanism with mods is difficult. + +Author: Sokomine +Contact: see https://github.com/Sokomine + +License: LGPL (same as minetest_game) for the trees_lib from 11.04.2017 onward + (trees_lib_examples may contain code from other mods) + +List of files: + init.lua The actual trees_lib. + +If you want to see some examples, take a look at + https://github.com/Sokomine/trees_lib_examples +which contains the following additional files: + init.lua Just runs dofile on the other files. + trees_lib_growing_functions.lua Some tree growing functions as examples. + example_tree.lua A complex example for one tree. + trees.lua Replacement for default/trees.lua + +Not covered by trees_lib: +* fuel receipes for the tree, wood, leaves nodes +* crafting of tree into wood (use trees_lib.register_on_new_tree_type for those) +* leafdecay + +If you want to test trees_lib with the default mod, do the following: + +1. (optional) remove/comment out all receipes for tree trunk -> 4 wood in default/crafting.lua +2. (optional) remove/comment out all tree, wood, leaves and fruit nodes in default/nodes.lua + If doing so, also remove/comment out all calls of default.register_leafdecay plus all + leafdecay-related functions in default/functions.lua. +3. (optional) rename the file default/trees.lua in order to create a backup. +4. copy trees_lib_examples/trees.lua to default/trees.lua + +If you want to add a new tree using trees_lib, do the following: + +1. Create a mod (MODNAME) +2. Find a name for your tree (TREENAME) +3. Create the following textures for your new tree: + MODNAME/textures/MODNAME_TREENAME_tree_top.png + MODNAME/textures/MODNAME_TREENAME_tree.png + MODNAME/textures/MODNAME_TREENAME_wood.png + MODNAME/textures/MODNAME_TREENAME_sapling.png + MODNAME/textures/MODNAME_TREENAME_leaves.png + MODNAME/textures/MODNAME_TREENAME_fruit.png +4. Make your mod depend on trees_lib by adding a line trees_lib to + MODNAME/depends.txt +5. Actually register the tree somewhere in your mod: + trees_lib.register_tree( TREENAME, minetest.get_current_modname() ) + All other parameters to trees_lib.register_tree are optional. + + +Important functions: + +register_tree + +trees_lib.register_tree(tree_name, nodes, growing_methods, grows_on_node_type_list, can_grow_function, select_how_to_grow_function, interval, chance ) + * tree_name needs to be unique withhin each mod, but not necessarily + withhin the entire game. This parameter is required. + * nodes may contain further information about the nodes the tree is composed + of (tree, wood, leaves, leaves2, leaves3, leaves4, leaves5, sapling, fruit). + Specify everything you want to override here (i.e. diffrent node name, + textures, drawtype, ...). Specify node_name = "air" (see trees.lua) if you + don't want a particular node (mostly used for trees that have no fruit) + * growing_methods is a list of how the sapling can be grown into a full tree. + Each entry needs one of the following entries: + use_function = function_to_grow_the_sapling + or + use_schematic = path_to_the_schematic_file + or + use_schematic = table_containing_the_schematic + or + use_lsystem = table_containing_lsystem_growth_data + In addition, the following values are usually needed: + xoff = x_offset, zoff = z_offset, yoff = y_offset (how deep burried), + height = height (total height of the tree) + These values describe which area the Voxelmanip needs to load or how + far away from the sapling's position the schematic ought to be placed. + * grows_on_node_type_list is a list of nodenames (or groups in the form + of i.e "group:stone") on which the sapling will grow. + * can_grow_function will be called when the abm for a sapling fires: + if can_grow( pos, node, ground_found ) returns + 1, the tree will grow + 0, the tree will try again next time (i.e. too dark) + -1, the tree really doesn't like this place and fails to grow, + usually turning into dry shrub + * select_how_to_grow_function can modify the way a tree will grow: + select_how_to_grow( pos, node, growing.how_to_grow, ground_found ) + It can either return a number (thus choosing one of the growing methods + from the growing_methods parameter), or its own new growing method. + * interval + The interval parameter for the abm for the growing of the sapling. + Default value is 10. + * chance + The chance parameter for the abm for the growing of the sapling. + Default value is 50. + + +trees_lib.register_on_new_tree_type( new_tree_type_function ) + The function new_tree_type_function will be called once for each registered + tree with the following parameters: + new_tree_type_function( tree_name, mod_prefix, nodes ) + This is useful for i.e. adding craft receipes and further nodes. See + trees.lua for an example. + If trees have allready been registered when the new function is registered, + it will be called for each known tree once, and of course for all + subsequently registered trees. + + +trees_lib.failed_to_grow( pos, node ) + This function is called when a tree failed to grow (i.e. because it does not + like the ground it is placed on). The default action is to turn the sapling + into dry shrub. + +trees_lib.a_tree_has_grown( pos, node, how_to_grow ) + Called whenever a tree has successfully grown. Useful i.e. for logging (see + trees.lua) + +trees_lib.tree_abm_grow_tree( pos, node, sapling_data, how_to_grow, force_grow ) + The actual function that lets the tree grow. + + diff --git a/mods/trees_lib/init.lua b/mods/trees_lib/init.lua new file mode 100644 index 00000000..f32eca2e --- /dev/null +++ b/mods/trees_lib/init.lua @@ -0,0 +1,656 @@ + +trees_lib = {} + +-- place this node if a sapling does not like the environment and refuses +-- to grow into a tree there +trees_lib.place_when_tree_cant_grow = {name="default:dry_shrub"}; + +----------------------------------------------------------------------------- +-- compatibility functions so that trees_lib can work without default mod +----------------------------------------------------------------------------- +trees_lib.sound_leaves = function() + if( default and default.node_sound_leaves_defaults) then + return default.node_sound_leaves_defaults(table) + else + return nil + end +end + +trees_lib.sound_wood = function() + if( default and default.node_sound_wood_defaults) then + return default.node_sound_wood_defaults(table) + else + return nil + end +end + +-- copy of default.after_place_leaves +trees_lib.after_place_leaves = function(pos, placer, itemstack, pointed_thing) + local node = minetest.get_node(pos) + node.param2 = 1 + minetest.set_node(pos, node) +end + +-- generalized function called after placing fruits +trees_lib.after_place_fruit = function(pos, placer, itemstack, pointed_thing) + if placer:is_player() then + -- find out the node name (this function is for all fruits that do not override it) + local node = minetest.get_node( pos ); + if( node and node.name) then + minetest.set_node(pos, {name = node.name, param2 = 1}) + end + end +end + + +----------------------------------------------------------------------------- +-- the various node definitions that are common to all nodes of that type +-- (unless overriden) +----------------------------------------------------------------------------- +trees_lib.node_def_tree = { + --description = "TREENAME Tree", + --tiles = nodes.tree.tiles, + paramtype2 = "facedir", + is_ground_content = false, + -- moretrees uses snappy=1 here as well + groups = {tree = 1, choppy = 2, oddly_breakable_by_hand = 1, flammable = 2}, + sounds = trees_lib.sound_wood, + on_place = minetest.rotate_node + } + +trees_lib.node_def_wood = { + --description = "TREENAME Wood Planks", + --tiles = nodes.wood.tiles, + is_ground_content = false, + -- moretrees uses snappy=1 here + groups = {choppy = 2, oddly_breakable_by_hand = 2, flammable = 3, wood = 1}, + sounds = trees_lib.sound_wood, + } + +trees_lib.node_def_leaves = { + --description = "TREENAME Leaves", + --tiles = nodes[k].tiles, + --special_tiles = nodes[k].special_tiles, + + -- moretrees has some options for this + drawtype = "allfaces_optional", + waving = 1, + visual_scale = 1.3, + paramtype = "light", + is_ground_content = false, + -- moretrees sets moretrees_leaves=1, leafdecay = decay + groups = {snappy = 3, leafdecay = 3, flammable = 2, leaves = 1}, + sounds = trees_lib.sound_leaves, + after_place_node = trees_lib.after_place_leaves, + -- the drop part of the node definition needs to be constructed + -- for each leaf individually + } + + +trees_lib.node_def_fruit = { + --description = "TREENAME Fruit", + drawtype = "plantlike", + visual_scale = 1.0, + --tiles = nodes.fruit.tiles, + --inventory_image = nodes.fruit.tiles[1], + paramtype = "light", + sunlight_propagates = true, + walkable = false, + is_ground_content = false, + selection_box = { + type = "fixed", + fixed = {-0.2, -0.5, -0.2, 0.2, 0, 0.2} + }, + groups = {fleshy = 3, dig_immediate = 3, flammable = 2, + leafdecay = 3, leafdecay_drop = 1}, + sounds = trees_lib.sound_leaves, + -- store that this fruit has been placed manually + after_place_node = trees_lib.after_place_fruit, + -- a fruit that wants to be eatable ought to supply the following line in + -- its fruit definition: + --on_use = minetest.item_eat(food_points), + } + +trees_lib.node_def_sapling = { + --description = "TREENAME sapling", + drawtype = "plantlike", + visual_scale = 1.0, + --tiles = nodes.sapling.tiles, + --inventory_image = nodes.sapling.tiles[1], + --wield_image = nodes.sapling.tiles[1], + paramtype = "light", + sunlight_propagates = true, + walkable = false, + 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 = trees_lib.sound_leaves, + } + +----------------------------------------------------------------------------- +-- internal functions for handling identification of nodes (i.e. what is a +-- trunk, what is a leaf, which nodes can be replaced by new trees) +----------------------------------------------------------------------------- +-- those are helpful for fast lookup (either by name or content id) +trees_lib.is_tree = {} +trees_lib.is_wood = {} +trees_lib.is_leaf = {} +trees_lib.is_sapling = {} +trees_lib.is_fruit = {} +trees_lib.ignore = {} + +-- trees are allowed to replace these nodes when growing +-- (in addition to leaves, saplings and fruits from other trees) +trees_lib.ignore_list = { + "air","ignore", + "default:water_source","default:water_flowing", + "default:snow","default:ice"} + +trees_lib.build_lookup_table = function( node_name, node_type, value, allow_removal_by_other_saplings ) + if( not( node_name ) + or node_name == "" + or not( minetest.registered_nodes[ node_name ]) + or not( trees_lib[ node_type ])) then + return; + end + local id = minetest.get_content_id( node_name ); + -- we store by id and nodename both for faster lookup + trees_lib[ node_type ][ id ] = value; + trees_lib[ node_type ][ node_name ] = value; + -- if this is set, then other saplings can overwrite these nodes during + -- their growth (i.e. replacing leaves with tree trunks) + if( allow_removal_by_other_saplings ) then + trees_lib.ignore[ id ] = value; + trees_lib.ignore[ node_name ] = value; + end +end + +-- actually store the information from the ignore list +for _,v in ipairs( trees_lib.ignore_list ) do + trees_lib.build_lookup_table( v,"ignore", v, 1 ); +end + + + +----------------------------------------------------------------------------- +-- allow to call a function whenever a new tree has been registered +----------------------------------------------------------------------------- +-- contains a list of all functions that need to be called whenever a new tree +-- type is registered using trees_lib.register_tree(..) +trees_lib.register_on_new_tree_type_function_list = {} + +-- the function new_tree_type_function will be called once for each tree type; +-- use this for adding the 1 tree -> 4 wood craft receipe +trees_lib.register_on_new_tree_type = function( new_tree_type_function ) + + -- call the function for all tree types that have been registered up + -- until now + for k,v in pairs( trees_lib.is_sapling) do + new_tree_type_function( v.tree_name, v.mod_prefix, v.nodes ); + end + + -- store the function so that it will get called at all subsequent + -- registrations of new trees + table.insert( trees_lib.register_on_new_tree_type_function_list, + new_tree_type_function ); + +end + + +----------------------------------------------------------------------------- +-- mix basic node definition (see below), default constructed values (which +-- are derived from modname and treename) as fallback and user (=user of the +-- trees_lib) specified node defintion up into one node definition and +-- register the node (provided it does not exist yet) +----------------------------------------------------------------------------- +trees_lib.register_one_node = function( def_common, def_default, def_user, node_type, sapling_node_name, cid ) + if( not( def_user)) then + def_user = {}; + end + -- find out which node we are supposed to register + local node_name = def_user.node_name; + if( not( node_name )) then + node_name = def_default.node_name; + end + -- if the node is alrady registered, then abort + if( minetest.registered_nodes[ node_name ]) then + -- store the content id of this node for this type + cid[ node_type ] = minetest.get_content_id( node_name ); + def_user.node_name = node_name; + return def_user; + end + + -- create the new node definition + local node_def = {}; + -- first, add all entries from def_common + for k,v in pairs( def_common ) do + node_def[ k ] = v; + end + -- then try the default values + for k,v in pairs( def_default) do + node_def[ k ] = v; + end + -- last, apply all user supplied node definitions and thus overwrite + -- common and default definitions + for k,v in pairs( def_user ) do + node_def[ k ] = v; + end + + -- set inventory_image and wield_image for plantlike nodes + if( node_def.drawtype + and node_def.drawtype=="plantlike" + and not( node_def.inventory_image )) then + node_def.inventory_image = node_def.tiles[1]; + node_def.wield_image = node_def.tiles[1]; + end + + -- the node name does not belong into the node definition + node_def.node_name = nil; + + -- actually register the new node + minetest.register_node( node_name, node_def ); + + + -- make sure the node name gets saved + def_user.node_name = node_name; + + -- can this node (in theory) be overwritten by other trees? + local allow_overwrite = nil; + if( node_type=="leaf" or node_type=="fruit" or node_type=="sapling") then + allow_overwrite = 1; + end + -- enter all these node names into a table for fast lookup + -- (without having to resort to checking the group) + -- the trees_lib.is_sapling field will later on contain more helpful information; + -- the sapling needs to be the first node registered for this to work reliably + trees_lib.build_lookup_table( node_name, "is_"..node_type, sapling_node_name, allow_overwrite ); + + -- store the content id of the newly registered node + cid[ node_type ] = minetest.get_content_id( node_name ); + return def_user; +end + + + +----------------------------------------------------------------------------- +-- nodes for the trees: trunk, planks, leaves, sapling and fruit +----------------------------------------------------------------------------- +-- (internal function) +-- * there can be up to 5 diffrent leaves types +-- * Note: craft receipes for fuel (tree, wood, leaves) do not need to be +-- added because default already contains general craft receipes +-- based on the respective groups. +-- * Note: The craft receipe for 1 tree -> 4 wood can be done via +-- trees_lib.register_on_new_tree_type +trees_lib.register_tree_nodes = function( tree_name, mod_prefix, nodes ) + + -- gather all the relevant content ids + local cid = {}; + + local tree_name_upcase = tree_name:gsub("^%l", string.upper); + local texture_prefix = mod_prefix.."_"..tree_name; + + if( not( nodes )) then + nodes = {}; + end + + -- the sapling node name will act as a reference in the lookup table later on; + -- therefore, we need to determine how the node will be called early enough + local sapling_node_name = mod_prefix..':'..tree_name..'_sapling'; + if( nodes.sapling and nodes.sapling.node_name ) then + sapling_node_name = nodes.sapling.node_name; + end + + -- register the sapling + nodes.sapling = trees_lib.register_one_node( trees_lib.node_def_sapling, + { + node_name = sapling_node_name, + description = tree_name_upcase.." Sapling", + tiles = { texture_prefix.."_sapling.png", + }, + }, nodes.sapling, "sapling", sapling_node_name, cid ); + + + -- register the tree trunk + nodes.tree = trees_lib.register_one_node( trees_lib.node_def_tree, + { + node_name = mod_prefix..':'..tree_name..'_tree', + description = tree_name_upcase.." Tree", + tiles = { texture_prefix.."_tree_top.png", + texture_prefix.."_tree_top.png", + texture_prefix.."_tree.png", + }, + }, nodes.tree, "tree", sapling_node_name, cid ); + + -- register the wood that belongs to the tree + nodes.wood = trees_lib.register_one_node( trees_lib.node_def_wood, + { + node_name = mod_prefix..':'..tree_name..'_wood', + description = tree_name_upcase.." Planks", + tiles = { texture_prefix.."_wood.png", + }, + }, nodes.wood, "wood", sapling_node_name, cid ); + + + -- default drop rate for the sapling (1/20) + local sapling_rarity = 20; + if( nodes.sapling and nodes.sapling.rarity ) then + sapling_rarity = nodes.sapling.rarity; + end + + -- register the leaves; some trees may have more than one type of leaves (i.e. moretrees jungletrees) + local leaves_id = {'leaves','leaves2','leaves3','leaves4','leaves5'}; + for _,k in ipairs( leaves_id ) do + -- not all leaf types need to exist; we just expect at least one type of leaves to be there + if( nodes[ k ] or k=='leaves') then + -- we need to determine the node name now as leaves tend to drop themshelves sometimes + local leaves_node_name = mod_prefix..':'..tree_name..'_'..k; + if( nodes[ k ] and nodes[ k ].node_name ) then + leaves_node_name = nodes[ k ].node_name; + end + nodes[ k ] = trees_lib.register_one_node( trees_lib.node_def_leaves, + { + node_name = leaves_node_name, + description = tree_name_upcase.." Leaves", + tiles = { texture_prefix.."_"..k..".png", + }, +-- special_tiles = { texture_prefix.."_"..k.."_simple.png", }, + drop = { + max_items = 1, + items = { + { + -- player will get sapling with 1/20 chance + items = { sapling_node_name}, + rarity = sapling_rarity, + }, + { + -- player will get leaves only if he get no saplings, + -- this is because max_items is 1 + items = { leaves_node_name}, + } + } + }, + }, nodes[ k ], "leaf", sapling_node_name, cid); + + -- also store the content ids of all leaf types + cid[ k ] = cid[ "leaf" ]; + end + end + + -- register the fruit + nodes.fruit = trees_lib.register_one_node( trees_lib.node_def_fruit, + { + node_name = mod_prefix..':'..tree_name..'_fruit', + description = tree_name_upcase.." Fruit", + tiles = { texture_prefix.."_fruit.png", + }, + }, nodes.fruit, "fruit", sapling_node_name, cid ); + + -- return the ids we've gathered + return cid; +end + + + +----------------------------------------------------------------------------- +-- growing of the trees from saplings +----------------------------------------------------------------------------- +-- turn saplings that failed to grow (because they don't like the ground or +-- environment) into dry shrub, thus allowing dry shrub farming; +-- override this function if you don't like this feature +trees_lib.failed_to_grow = function( pos, node ) + minetest.set_node( pos, trees_lib.place_when_tree_cant_grow); +end + +-- this function is called just before a tree actually grows; +-- the function ought to return how_to_grow for normal tree growth; +-- returning another way of growing is also possible (i.e. diffrent +-- model when growing in flower pots/on stone) +trees_lib.change_tree_growth = function( pos, node, how_to_grow ) + return how_to_grow; +end + + +-- this function is called whenever a sapling of type node has grown +-- into a tree using how_to_grow at position pos +trees_lib.a_tree_has_grown = function( pos, node, how_to_grow ) + return; +end + +-- called by the abm running on the saplings; +-- if force is set, the tree will grow even if it usually wouldn't in that +-- environment +trees_lib.tree_abm_called = function( pos, node, active_object_count, active_object_count_wider, force_grow) + -- if we don't have further information about that sapling, then abort + if( not( node ) + or not( node.name ) + or not( trees_lib.is_sapling[ node.name ])) then + -- turn into dry shrub (because we don't know what to do with + -- this sapling) + trees_lib.failed_to_grow( pos, node ); + return; + end + + -- get information about what we're supposed to do with that sapling + local sapling_data = trees_lib.is_sapling[ node.name ]; + + -- the type of ground might be of intrest for further functions (i.e. can_grow, select_how_to_grow) + local ground_found = nil; + -- a quick check of the ground; sapling_data.grows_on has to be a list of all + -- ground types acceptable for the tree + if( not(force_grow) and sapling_data.grows_on and type( sapling_data.grows_on )=="table") then + local node_under = minetest.get_node_or_nil({x = pos.x, y = pos.y - 1, z = pos.z}); + -- abort if this check cannot be done + if( not(node_under) or node_under.name=="ignore") then + return; + end + -- search all acceptable ground names + for _,g in ipairs( sapling_data.grows_on ) do + if( g==node_under.name ) then + ground_found = g; + elseif( not( ground_found) + and string.sub(g,1,6)=="group:" + and minetest.get_item_group( node_under.name, string.sub(g,7))~=0 ) then + ground_found = g; + end + end + -- abort if the tree does not like this type of ground + if( not( ground_found )) then + -- trun into dry shrub + trees_lib.failed_to_grow( pos, node ); + return; + end + end + + -- the tree may come with a more complex function that checks if it can grow there + if( not(force_grow) and sapling_data.can_grow and type( sapling_data.can_grow)=="function" ) then + -- the parameter ground_found is nil if the tree did not specify any demands for a particular ground + local ret = sapling_data.can_grow( pos, node, ground_found ); + if( ret < 1 ) then + -- trun into dry shrub if growing failed finally (and was not just delayed) + if( ret==0 ) then + trees_lib.failed_to_grow( pos, node, ground_found ); + end + return; + end + end + + -- each tree can have several ways of growing + local how_to_grow = nil; + -- the sapling may - depending on the circumstances - choose a specific growth function + -- instead of a random one + if( sapling_data.select_how_to_grow and type( sapling_data.select_how_to_grow)=="function") then + -- ground_found is nil if the tree did not specify any demands for a particular ground + how_to_grow = sapling_data.select_how_to_grow( pos, node, sapling_data.how_to_grow, ground_found ); + -- the select_how_to_grow function may either return a table or a number indicating which + -- growth method to select + if( how_to_grow and type(how_to_grow)=="number" and sapling_data.how_to_grow[ how_to_grow ]) then + how_to_grow = sapling_data.how_to_grow[ how_to_grow ]; + end + else -- else select a random one + how_to_grow = sapling_data.how_to_grow[ math.random( 1, #sapling_data.how_to_grow )]; + end + + -- this function may change the way the tree grows (i.e. select a special method for trees growing in flower pots or on stone ground) + how_to_grow = trees_lib.change_tree_growth( pos, node, how_to_grow ); + + -- actually grow the tree in a seperate function + trees_lib.tree_abm_grow_tree( pos, node, sapling_data, how_to_grow, force_grow ); +end + + +-- actually grow the tree from a sapling +trees_lib.tree_abm_grow_tree = function( pos, node, sapling_data, how_to_grow, force_grow ) + -- abort if no way was found to grow the tree + if( not( how_to_grow ) or type(how_to_grow)~="table") then + trees_lib.failed_to_grow( pos, node ); + return; + + -- grow the tree using a function (like the old apple trees did) + elseif( how_to_grow.use_function and type(how_to_grow.use_function)=="function") then + + -- get the voxelmanip data + local vm = minetest.get_voxel_manip() + local minp, maxp = vm:read_from_map( + {x = pos.x - how_to_grow.xoff, y = pos.y - how_to_grow.yoff, z = pos.z - how_to_grow.zoff}, + {x = pos.x + how_to_grow.xoff, y = pos.y + how_to_grow.height, z = pos.z + how_to_grow.zoff} + ) + local a = VoxelArea:new({MinEdge = minp, MaxEdge = maxp}) + local data = vm:get_data() + + how_to_grow.use_function( data, a, pos, sapling_data, how_to_grow.extra_params ); + + -- write the data back + vm:set_data(data) + vm:write_to_map() + vm:update_map() + + + -- grow the tree using a schematic + elseif( how_to_grow.use_schematic + and (type(how_to_grow.use_schematic)=="string" + or type(how_to_grow.use_schematic)=="table")) then + -- TODO: use voxelmanip + -- remove the sapling + minetest.set_node( pos, {name="air"}); + -- TODO: determine xoff, yoff and zoff when registering the tree + -- (if yoff is not given, then use 0) + minetest.place_schematic( + {x = pos.x - how_to_grow.xoff, + y = pos.y - how_to_grow.yoff, + z = pos.z - how_to_grow.zoff}, + how_to_grow.use_schematic, -- full path to the .mts file + "random", -- rotation + how_to_grow.use_replacements, -- use the same schematic for diffrent trees + false -- no overwriting of existing nodes + ); + + -- grow the tree using L-system + elseif( how_to_grow.use_lsystem and type(how_to_grow.use_lsystem)=="table") then + -- remove the sapling + minetest.set_node( pos, {name="air"}); + -- spawn the l-system tree + minetest.spawn_tree(pos, how_to_grow.use_lsystem ); + + -- else prevent call of success function below + else + return; + end + + trees_lib.a_tree_has_grown( pos, node, how_to_grow ); +end + + +----------------------------------------------------------------------------- +-- register a new tree +----------------------------------------------------------------------------- +trees_lib.register_tree = function( tree_name, nodes, growing_methods, grows_on_node_type_list, can_grow_function, select_how_to_grow_function, interval, chance ) + -- the tree name is the minimum needed in order to register a new tree + if( not( tree_name )) then + return; + end + + -- we may have to register nodes - and those have to be registered under the name of whichever mod called this function and is the "current" mod + local mod_prefix = ""; + -- set it to the current mod - this cannot be done in the line above as that would set mod_prefix to trees_lib and not to the calling mod + mod_prefix = minetest.get_current_modname(); + + + -- register tree trunk, wood, leaves and fruit (provided they are not defined yet) + local cid_list = trees_lib.register_tree_nodes( tree_name, mod_prefix, nodes ); + + -- a sapling will be needed for growing the tree + if( not( nodes.sapling ) + or not( nodes.sapling.node_name ) + or not( growing_methods )) then + return; + end + + -- store information about the new tree type in the sapling table + trees_lib.is_sapling[ nodes.sapling.node_name ] = { + + -- minetest.get_content_id for tree, wood, leaves1..n, sapling, fruit + cid = cid_list, + + -- node name of the sapling + sapling = nodes.sapling.node_name, + + -- values passed on to all functions registered via + -- trees_lib.register_on_new_tree_type = function( new_tree_type_function ) + tree_name = tree_name, + mod_prefix = mod_prefix, + nodes = nodes, + + -- list of node names (can contain groups, i.e. "group:soil") + -- on which the sapling will grow; + -- note: the parameter ground_found to the functions below can only be + -- passed on if grows_on has been specified (else the sapling does + -- not do any ground checks on its own) + grows_on = grows_on_node_type_list, + + -- are all the requirements met for growing at pos? + -- sapling will only grow if + -- growing.can_grow( pos, node, ground_found ) + -- returns a value >0; if 0 is returned, the sapling will fail to grow + -- and be turned into dry shrub; if a value <0 is returned, nothing will + -- happen (the sapling can try again later on) + -- (usful for i.e. requiring water nearby, or other + -- more complex requirements) + can_grow = can_grow_function, + + -- has to be either nil (for selecting a random way) + -- or return a specific growth function like the ones in + -- the list how_to_grow (see below) when called with + -- growing.select_how_to_grow( pos, node, growing.how_to_grow, ground_found ) + select_how_to_grow = select_how_to_grow_function, + + -- list of all methods that can turn the sapling into a + -- tree; can be a function, a file name containing a schematic + -- or a table for L-system trees; + -- this table/list is REQUIRED + how_to_grow = growing_methods, + }; + + -- a new tree was registered - call all functions that want to be told about new trees + for i,new_tree_type_function in ipairs( trees_lib.register_on_new_tree_type_function_list ) do + new_tree_type_function( tree_name, mod_prefix, nodes ); + end + + -- set default values for the tree-growing abm if none are set + if( not( interval)) then + interval = 10; + end + if( not( chance )) then + chance = 50; + end + -- now add the abm that lets the tree grow + minetest.register_abm({ + nodenames = { nodes.sapling.node_name }, + interval = interval, + chance = chance, + action = trees_lib.tree_abm_called, + }); +end diff --git a/mods/vines/.luacheckrc b/mods/vines/.luacheckrc new file mode 100644 index 00000000..bf997801 --- /dev/null +++ b/mods/vines/.luacheckrc @@ -0,0 +1,13 @@ + +unused_args = false + +read_globals = { + "minetest", + "default", + "ItemStack", + "biome_lib", +} + +globals = { + "vines", +} diff --git a/mods/vines/LICENSE.md b/mods/vines/LICENSE.md new file mode 100644 index 00000000..fb677883 --- /dev/null +++ b/mods/vines/LICENSE.md @@ -0,0 +1,4 @@ +License +======= +- Code WTFPL +- Texture CC diff --git a/mods/vines/README.md b/mods/vines/README.md new file mode 100644 index 00000000..89fdb270 --- /dev/null +++ b/mods/vines/README.md @@ -0,0 +1,56 @@ +# Vines + +## Features +- Rope block for spawning rope that slowly drops into the deep. +- Vines are climbable and slowly grow downward. +- Shears that allow the collecting of vines. +- Spawns vines on jungletree leaves. +- Roots on the bottom of dirt and dirt with grass nodes. +- Spawns vines on trees located in swampy area. +- Jungle vines that spawn on the side of jungletrees + +## API +The API is very minimal. It allows the registering of vines and the spawning of +existing vines on nodes of your own. + +If you want vines to spawn on a certain node then you can choose which vine by +adding to the node groups the unique group of that vine. This is determined by +the name of the vine ( see vines.lua ) appended with '_vines'. +An example would be. + +"willow_vines" or "jungle_vines" + +There are two types of vines. One that spawns at the bottom of nodes and uses the +plantlike drawtype, and vines that spawn on the side that use signlike +drawtype. The type is determined by the spawn_on_side property in the biome +table. + +### Example +*taken from mod* + +```lua + + vines.register_vine( name, definitions, biome ) + + --e.g. + + vines.register_vine( 'vine', { + description = "Vines", + average_length = 9 + }, biome ) + +``` + +### definitions +|key| type| description| +|---| ---| ---| +|description| string|The vine's tooltip description| +|average_length|int| The average length of vines| + +For biome definitions please see the [plants_lib API documentation](https://github.com/VanessaE/plantlife_modpack/blob/master/API.txt) + +## Notice +Vines use after_destruct on registered leave nodes to remove vines from which +the leaves are removed. This is done by using the override function. +Malfunctions may occur if other mods override the after_destruct of these nodes +also. diff --git a/mods/vines/aliases.lua b/mods/vines/aliases.lua new file mode 100644 index 00000000..fce72187 --- /dev/null +++ b/mods/vines/aliases.lua @@ -0,0 +1,11 @@ +-- used to remove the old vine nodes. This gives room for the new nodes +minetest.register_alias( 'vines:root', 'air' ) +minetest.register_alias( 'vines:root_rotten', 'air' ) +minetest.register_alias( 'vines:vine', 'air' ) +minetest.register_alias( 'vines:vine_rotten', 'air' ) +minetest.register_alias( 'vines:side', 'air' ) +minetest.register_alias( 'vines:side_rotten', 'air' ) +minetest.register_alias( 'vines:jungle', 'air' ) +minetest.register_alias( 'vines:jungle_rotten', 'air' ) +minetest.register_alias( 'vines:willow', 'air' ) +minetest.register_alias( 'vines:willow_rotten', 'air' ) diff --git a/mods/vines/bower.json b/mods/vines/bower.json new file mode 100644 index 00000000..108a7c16 --- /dev/null +++ b/mods/vines/bower.json @@ -0,0 +1,18 @@ +{ + "name": "vines", + "description": "Vines that spawn on trees and rope", + "keywords": [ + "vines", + "trees", + "rope", + "jungle" + ], + "homepage": "https://github.com/bas080/vines/", + "screenshots": [ + "https://raw.githubusercontent.com/bas080/vines/forum/screenshot.png" + ], + "authors": [ + "bas080" + ], + "license": "WTFPL" +} diff --git a/mods/vines/crafts.lua b/mods/vines/crafts.lua new file mode 100644 index 00000000..19e658b9 --- /dev/null +++ b/mods/vines/crafts.lua @@ -0,0 +1,14 @@ +minetest.register_craft({ + output = 'vines:rope_block', + recipe = vines.recipes['rope_block'] +}) + +minetest.register_craft({ + output = 'vines:shears', + recipe = vines.recipes['shears'] +}) + +minetest.register_craftitem("vines:vines", { + description = "Vines", + inventory_image = "vines_item.png", +}) diff --git a/mods/vines/depends.txt b/mods/vines/depends.txt new file mode 100644 index 00000000..573e6e18 --- /dev/null +++ b/mods/vines/depends.txt @@ -0,0 +1,3 @@ +default +biome_lib +moretrees? diff --git a/mods/vines/description.txt b/mods/vines/description.txt new file mode 100644 index 00000000..3664f432 --- /dev/null +++ b/mods/vines/description.txt @@ -0,0 +1 @@ +Adds climbable vines that are spawned on trees. diff --git a/mods/vines/functions.lua b/mods/vines/functions.lua new file mode 100644 index 00000000..a2f15660 --- /dev/null +++ b/mods/vines/functions.lua @@ -0,0 +1,129 @@ +vines.register_vine = function( name, defs, biome ) + local groups = { vines=1, snappy=3, flammable=2 } + + local vine_name_end = 'vines:'..name..'_end' + local vine_name_middle = 'vines:'..name..'_middle' + + local vine_image_end = "vines_"..name.."_end.png" + local vine_image_middle = "vines_"..name.."_middle.png" + + local drop_node = vine_name_end + + biome.spawn_plants = { vine_name_end } + + local vine_group = 'group:'..name..'_vines' + biome.spawn_surfaces[ #biome.spawn_surfaces + 1 ] = vine_group + + local selection_box = { type = "wallmounted", } + local drawtype = 'signlike' + if ( not biome.spawn_on_side ) then + --different properties for bottom and side vines. + selection_box = { type = "fixed", fixed = { -0.4, -1/2, -0.4, 0.4, 1/2, 0.4 }, } + drawtype = 'plantlike' + end + + minetest.register_node( vine_name_end, { + description = defs.description, + walkable = false, + climbable = true, + wield_image = vine_image_end, + drop = "", + sunlight_propagates = true, + paramtype = "light", + paramtype2 = "wallmounted", + buildable_to = false, + tiles = { vine_image_end }, + drawtype = drawtype, + inventory_image = vine_image_end, + groups = groups, + sounds = default.node_sound_leaves_defaults(), + selection_box = selection_box, + on_construct = function( pos ) + local timer = minetest.get_node_timer( pos ) + timer:start( math.random(5, 10) ) + end, + on_timer = function( pos ) + local node = minetest.get_node( pos ) + local bottom = {x=pos.x, y=pos.y-1, z=pos.z} + local bottom_node = minetest.get_node( bottom ) + if bottom_node.name == "air" then + if not ( math.random( defs.average_length ) == 1 ) then + minetest.set_node( pos, { name = vine_name_middle, param2 = node.param2 } ) + minetest.set_node( bottom, { name = node.name, param2 = node.param2 } ) + local timer = minetest.get_node_timer( bottom_node ) + timer:start( math.random(5, 10) ) + end + end + end, + after_dig_node = function(pos, node, oldmetadata, user) + vines.dig_vine( pos, drop_node, user ) + end + }) + + minetest.register_node( vine_name_middle, { + description = "Matured "..defs.description, + walkable = false, + climbable = true, + drop = "", + sunlight_propagates = true, + paramtype = "light", + paramtype2 = "wallmounted", + buildable_to = false, + tiles = { vine_image_middle }, + wield_image = vine_image_middle, + drawtype = drawtype, + inventory_image = vine_image_middle, + groups = groups, + sounds = default.node_sound_leaves_defaults(), + selection_box = selection_box, + on_destruct = function( pos ) + local bottom = {x=pos.x, y=pos.y-1, z=pos.z} + local bottom_node = minetest.get_node( bottom ) + if minetest.get_item_group( bottom_node.name, "vines") > 0 then + minetest.after( 0, minetest.remove_node, bottom ) + end + end, + after_dig_node = function( pos, node, oldmetadata, user ) + vines.dig_vine( pos, drop_node, user ) + end + }) + + biome_lib:spawn_on_surfaces( biome ) + + local override_nodes = function( nodes, def ) + local function override( index, registered ) + local node = nodes[ index ] + if index > #nodes then return registered end + if minetest.registered_nodes[node] then + minetest.override_item( node, def ) + registered[#registered+1] = node + end + override( index+1, registered ) + end + override( 1, {} ) + end + + override_nodes( biome.spawn_surfaces,{ + on_destruct = function( pos ) + local pos_min = { x = pos.x -1, y = pos.y - 1, z = pos.z - 1 } + local pos_max = { x = pos.x +1, y = pos.y + 1, z = pos.z + 1 } + local positions = minetest.find_nodes_in_area( pos_min, pos_max, "group:vines" ) + for index, position in pairs(positions) do + minetest.remove_node( position ) + end + end + }) + +end + +vines.dig_vine = function( pos, node_name, user ) + --only dig give the vine if shears are used + if not user then return false end + local wielded = user:get_wielded_item() + if 'vines:shears' == wielded:get_name() then + local inv = user:get_inventory() + if inv then + inv:add_item("main", ItemStack( node_name )) + end + end +end diff --git a/mods/vines/init.lua b/mods/vines/init.lua new file mode 100644 index 00000000..72eda930 --- /dev/null +++ b/mods/vines/init.lua @@ -0,0 +1,14 @@ +vines = { + name = 'vines', + recipes = {} +} + +dofile( minetest.get_modpath( vines.name ) .. "/functions.lua" ) +dofile( minetest.get_modpath( vines.name ) .. "/aliases.lua" ) +dofile( minetest.get_modpath( vines.name ) .. "/recipes.lua" ) +dofile( minetest.get_modpath( vines.name ) .. "/crafts.lua" ) +dofile( minetest.get_modpath( vines.name ) .. "/nodes.lua" ) +dofile( minetest.get_modpath( vines.name ) .. "/shear.lua" ) +dofile( minetest.get_modpath( vines.name ) .. "/vines.lua" ) + +print("[Vines] Loaded!") diff --git a/mods/vines/mod.conf b/mods/vines/mod.conf new file mode 100644 index 00000000..39ea365f --- /dev/null +++ b/mods/vines/mod.conf @@ -0,0 +1,2 @@ + +name = vines diff --git a/mods/vines/nodes.lua b/mods/vines/nodes.lua new file mode 100644 index 00000000..6a1ee226 --- /dev/null +++ b/mods/vines/nodes.lua @@ -0,0 +1,83 @@ +minetest.register_node("vines:rope_block", { + description = "Rope", + sunlight_propagates = true, + paramtype = "light", + tiles = { + "default_wood.png^vines_rope.png", + "default_wood.png^vines_rope.png", + "default_wood.png", + "default_wood.png", + "default_wood.png^vines_rope.png", + "default_wood.png^vines_rope.png", + }, + groups = { flammable=2, choppy=2, oddly_breakable_by_hand=1 }, + after_place_node = function(pos) + local p = {x=pos.x, y=pos.y-1, z=pos.z} + local n = minetest.get_node(p) + if n.name == "air" then + minetest.add_node(p, {name="vines:rope_end"}) + end + end, + after_dig_node = function(pos, node, digger) + local p = {x=pos.x, y=pos.y-1, z=pos.z} + local n = minetest.get_node(p) + while ( n.name == 'vines:rope' or n.name == 'vines:rope_end' ) do + minetest.remove_node(p) + p = {x=p.x, y=p.y-1, z=p.z} + n = minetest.get_node(p) + end + end +}) + +minetest.register_node("vines:rope", { + description = "Rope", + walkable = false, + climbable = true, + sunlight_propagates = true, + paramtype = "light", + drop = "", + tiles = { "vines_rope.png" }, + drawtype = "plantlike", + groups = {flammable=2, not_in_creative_inventory=1}, + sounds = default.node_sound_leaves_defaults(), + selection_box = { + type = "fixed", + fixed = {-1/7, -1/2, -1/7, 1/7, 1/2, 1/7}, + }, +}) + +minetest.register_node("vines:rope_end", { + description = "Rope", + walkable = false, + climbable = true, + sunlight_propagates = true, + paramtype = "light", + drop = "", + tiles = { "vines_rope_end.png" }, + drawtype = "plantlike", + groups = {flammable=2, not_in_creative_inventory=1}, + sounds = default.node_sound_leaves_defaults(), + after_place_node = function(pos) + local yesh = {x = pos.x, y= pos.y-1, z=pos.z} + minetest.add_node(yesh, {name="vines:rope"}) + end, + selection_box = { + type = "fixed", + fixed = {-1/7, -1/2, -1/7, 1/7, 1/2, 1/7}, + }, + on_construct = function( pos ) + local timer = minetest.get_node_timer( pos ) + timer:start( 1 ) + end, + on_timer = function( pos, elapsed ) + local p = {x=pos.x, y=pos.y-1, z=pos.z} + local n = minetest.get_node(p) + if n.name == "air" then + minetest.set_node(pos, {name="vines:rope"}) + minetest.add_node(p, {name="vines:rope_end"}) + else + local timer = minetest.get_node_timer( pos ) + timer:start( 1 ) + end + end +}) diff --git a/mods/vines/recipes.lua b/mods/vines/recipes.lua new file mode 100644 index 00000000..d64dcea4 --- /dev/null +++ b/mods/vines/recipes.lua @@ -0,0 +1,12 @@ +vines.recipes['rope_block'] = { + {'', 'group:wood', ''}, + {'', 'group:vines', ''}, + {'', 'group:vines', ''} +} + +vines.recipes['shears'] = { + {'', 'default:steel_ingot', ''}, + {'group:stick', 'group:wood', 'default:steel_ingot'}, + {'', '', 'group:stick'} +} + diff --git a/mods/vines/screenshot.png b/mods/vines/screenshot.png new file mode 100644 index 00000000..b386f694 Binary files /dev/null and b/mods/vines/screenshot.png differ diff --git a/mods/vines/shear.lua b/mods/vines/shear.lua new file mode 100644 index 00000000..b42a3e7c --- /dev/null +++ b/mods/vines/shear.lua @@ -0,0 +1,15 @@ +minetest.register_tool("vines:shears", { + description = "Shears", + inventory_image = "vines_shears.png", + wield_image = "vines_shears.png", + stack_max = 1, + max_drop_level=3, + tool_capabilities = { + full_punch_interval = 1.0, + max_drop_level=0, + groupcaps={ + snappy={times={[3]=0.2}, uses=60, maxlevel=3}, + wool={times={[3]=0.2}, uses=60, maxlevel=3} + } + }, +}) diff --git a/mods/vines/textures/vines_item.png b/mods/vines/textures/vines_item.png new file mode 100644 index 00000000..c66242ef Binary files /dev/null and b/mods/vines/textures/vines_item.png differ diff --git a/mods/vines/textures/vines_jungle_end.png b/mods/vines/textures/vines_jungle_end.png new file mode 100644 index 00000000..6c8d3395 Binary files /dev/null and b/mods/vines/textures/vines_jungle_end.png differ diff --git a/mods/vines/textures/vines_jungle_middle.png b/mods/vines/textures/vines_jungle_middle.png new file mode 100644 index 00000000..bf838a50 Binary files /dev/null and b/mods/vines/textures/vines_jungle_middle.png differ diff --git a/mods/vines/textures/vines_root_end.png b/mods/vines/textures/vines_root_end.png new file mode 100644 index 00000000..4fc3f87a Binary files /dev/null and b/mods/vines/textures/vines_root_end.png differ diff --git a/mods/vines/textures/vines_root_middle.png b/mods/vines/textures/vines_root_middle.png new file mode 100644 index 00000000..49f88c05 Binary files /dev/null and b/mods/vines/textures/vines_root_middle.png differ diff --git a/mods/vines/textures/vines_rope.png b/mods/vines/textures/vines_rope.png new file mode 100644 index 00000000..0045c4c3 Binary files /dev/null and b/mods/vines/textures/vines_rope.png differ diff --git a/mods/vines/textures/vines_rope_end.png b/mods/vines/textures/vines_rope_end.png new file mode 100644 index 00000000..faf2c715 Binary files /dev/null and b/mods/vines/textures/vines_rope_end.png differ diff --git a/mods/vines/textures/vines_shears.png b/mods/vines/textures/vines_shears.png new file mode 100644 index 00000000..c4c39f9f Binary files /dev/null and b/mods/vines/textures/vines_shears.png differ diff --git a/mods/vines/textures/vines_side_end.png b/mods/vines/textures/vines_side_end.png new file mode 100644 index 00000000..5b3b28f7 Binary files /dev/null and b/mods/vines/textures/vines_side_end.png differ diff --git a/mods/vines/textures/vines_side_middle.png b/mods/vines/textures/vines_side_middle.png new file mode 100644 index 00000000..2576e935 Binary files /dev/null and b/mods/vines/textures/vines_side_middle.png differ diff --git a/mods/vines/textures/vines_vine_end.png b/mods/vines/textures/vines_vine_end.png new file mode 100644 index 00000000..062857be Binary files /dev/null and b/mods/vines/textures/vines_vine_end.png differ diff --git a/mods/vines/textures/vines_vine_middle.png b/mods/vines/textures/vines_vine_middle.png new file mode 100644 index 00000000..8afffe89 Binary files /dev/null and b/mods/vines/textures/vines_vine_middle.png differ diff --git a/mods/vines/textures/vines_willow_end.png b/mods/vines/textures/vines_willow_end.png new file mode 100644 index 00000000..b5b8e594 Binary files /dev/null and b/mods/vines/textures/vines_willow_end.png differ diff --git a/mods/vines/textures/vines_willow_middle.png b/mods/vines/textures/vines_willow_middle.png new file mode 100644 index 00000000..ca0b8312 Binary files /dev/null and b/mods/vines/textures/vines_willow_middle.png differ diff --git a/mods/vines/vines.lua b/mods/vines/vines.lua new file mode 100644 index 00000000..42c20d88 --- /dev/null +++ b/mods/vines/vines.lua @@ -0,0 +1,105 @@ +vines.register_vine( 'root', { + description = "Roots", + average_length = 9, +},{ + choose_random_wall = true, + avoid_nodes = {"vines:root_middle"}, + avoid_radius = 5, + spawn_delay = 500, + spawn_chance = 10, + spawn_surfaces = { + "default:dirt_with_grass", + "default:dirt" + }, + spawn_on_bottom = true, + plantlife_limit = -0.6, + humidity_min = 0.4, +}) + +vines.register_vine( 'vine', { + description = "Vines", + average_length = 5, +},{ + choose_random_wall = true, + avoid_nodes = {"group:vines"}, + avoid_radius = 5, + spawn_delay = 500, + spawn_chance = 100, + spawn_surfaces = { + "default:leaves", + "default:jungleleaves", + "moretrees:jungletree_leaves_red", + "moretrees:jungletree_leaves_yellow", + "moretrees:jungletree_leaves_green" + }, + spawn_on_bottom = true, + plantlife_limit = -0.9, + humidity_min = 0.7, +}) + +vines.register_vine( 'side', { + description = "Vines", + average_length = 6, +},{ + choose_random_wall = true, + avoid_nodes = {"group:vines", "default:apple"}, + avoid_radius = 3, + spawn_delay = 500, + spawn_chance = 100, + spawn_surfaces = { + "default:leaves", + "default:jungleleaves", + "moretrees:jungletree_leaves_red", + "moretrees:jungletree_leaves_yellow", + "moretrees:jungletree_leaves_green" + }, + spawn_on_side = true, + plantlife_limit = -0.9, + humidity_min = 0.4, +}) + +vines.register_vine( "jungle", { + description = "Jungle Vines", + average_length = 7, +},{ + choose_random_wall = true, + neighbors = { + "default:jungleleaves", + "moretrees:jungletree_leaves_red", + "moretrees:jungletree_leaves_yellow", + "moretrees:jungletree_leaves_green" + }, + avoid_nodes = { + "vines:jungle_middle", + "vines:jungle_end", + }, + avoid_radius = 5, + spawn_delay = 500, + spawn_chance = 100, + spawn_surfaces = { + "default:jungletree", + "moretrees:jungletree_trunk" + }, + spawn_on_side = true, + plantlife_limit = -0.9, + humidity_min = 0.2, +}) + +vines.register_vine( 'willow', { + description = "Willow Vines", + average_length = 9, +},{ + choose_random_wall = true, + avoid_nodes = { "vines:willow_middle" }, + avoid_radius = 5, + near_nodes = { 'default:water_source' }, + near_nodes_size = 1, + near_nodes_count = 1, + near_nodes_vertical = 7, + plantlife_limit = -0.8, + spawn_chance = 10, + spawn_delay = 500, + spawn_on_side = true, + spawn_surfaces = {"moretrees:willow_leaves"}, + humidity_min = 0.5 +}) diff --git a/reset-map b/reset-map-and-players similarity index 64% rename from reset-map rename to reset-map-and-players index 1ee6b0d4..535e5f83 100644 --- a/reset-map +++ b/reset-map-and-players @@ -6,9 +6,11 @@ systemctl stop minetestsrv echo "Drop and recreate map database" sudo -u postgres dropdb minetest +sudo -u postgres dropdb minetest_players sudo -u postgres createdb minetest -sudo -u postgres psql -U postgres -d postgres -c "alter user minetest with password '$psql_minetest_user_password';" +sudo -u postgres createdb minetest_players sudo -u postgres psql -U postgres -d postgres -c "grant all privileges on database "minetest" to minetest;" +sudo -u postgres psql -U postgres -d postgres -c "grant all privileges on database "minetest_players" to minetest;" echo "Start minetestsrv service" systemctl start minetestsrv diff --git a/setup-mt b/setup-mt index c3a871d3..68aa0115 100755 --- a/setup-mt +++ b/setup-mt @@ -115,6 +115,7 @@ echo "language = "$mt_language"" >> /home/minetest/.minetest/minetest.conf echo "port = "$mt_port"" >> /home/minetest/.minetest/minetest.conf echo "enable_rollback_recording = "$mt_enable_rollback_recording"" >> /home/minetest/.minetest/minetest.conf echo "default_privs = "$mt_default_privs"" >> /home/minetest/.minetest/minetest.conf +echo "mg_name = "$mt_mg_name"" >> /home/minetest/.minetest/minetest.conf echo "Fix privileges on /home/minetest" chown minetest:minetest /home/minetest/ -cR