diff --git a/API.txt b/API.txt index 5d3db83..aa92d0a 100644 --- a/API.txt +++ b/API.txt @@ -1,6 +1,6 @@ This document briefly describes the Plantlife API. -Last revision: 2013-01-18 +Last revision: 2013-01-25 ========= Functions @@ -22,91 +22,206 @@ at any time. See init.lua for more. ----- -The first of these, spawn_on_surfaces() is defined with quite a large number -of variables. All of the variables below, if specified at all, must be -specified exactly in the order given here. This function has no return value. +The 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. Either via the legacy +method like that which was used in the Flowers mod: -spawn_on_surfaces = function(sdelay, splant, sradius, schance, ssurface, - savoid, seed_diff, lightmin, lightmax, nneighbors, ocount, facedir, - depthmax, altitudemin, altitudemax, sbiome, sbiomesize, sbiomecount, - airsize, aircount, tempmin, tempmax) +spawn_on_surfaces(sdelay, splant, sradius, schance, ssurface, savoid) -The first several of these are all required, and are from the last version of -the flowers mod, so this part of the API should be the same as before. +Or, you can specify the various options with a single table as the parameter: -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"). Note that if the plant is - "poisonivy:seedling", and it's next to a wall at spawn - time, it automatically becomes the wall-climbing variety. - A plant will of course only be spawned if the node about - to be replaced is air. -sradius: Don't spawn within this many nodes of the avoid items - mentioned below. -schance: The value passed to the ABM's chance parameter, normally - in the 10-100 range (1-in-X chance of operating on a given - node, e.g. 1-in-10). -ssurface: Table with the names of the nodes on which to spawn the - plant in question, such as {"default:sand", - "default:dirt_with_grass"}. It is not recommended to put - "default:dirt" or "default:stone" into this table if you - can do without it, as this will cause the engine to - process potentially large numbers of such nodes when - deciding when to execute the ABM and where it should - operate. -savoid: Table with a list of groups and/or node names to avoid - when spawning the plant, such as {"group:flowers", - "default:tree"}. +spawn_on_surfaces({table of options}) -From here down are several optional parameters. You can use as many as you -need, but you must specify them in order. To keep the default values for -those parameters you don't wish to alter, set them to nil in your function -call. +When used with the legacy interface, you must specify the parameters exactly +in order, with the first five being mandatory and the last one being optional: -seed_diff: The Perlin seed difference value passed to the - minetest.env:get_perlin() function. Used along with the - global Perlin controls below to create the "biome" in - which the plants will spawn. Usually a value of somewhere - in the 10 to 100 range is good. Defaults to 0 if not - provided. -lightmin: Minimum amount of light necessary to make a plant spawn. - Defaults to 0. -lightmax: Maximum amount of light present to allow a plant to spawn. - Defaults to the engine's MAX_LIGHT value of 14. -nneighbors: Table with a list of neighboring nodes, passed to the ABM - as the "neighbors" parameter, indicating what needs to be - next to the node the plant is about to spawn on, such as - {"default:stone","default:water_source"}. Defaults to the - value of ssurface if not provided. -ocount: There must be at least this many of the above neighbors in - the eight spaces immediately surrounding the node the - plant is about to spawn on for it to happen. Defaults to - 0. -facedir: The value passed to the param2 variable when adding the - plant node to the map. Defaults to 0. -depthmax: If a node spawns on top of a water source, the water must - be at most this deep. Defaults to 1 node. -altitudemin: Items must be at this altitude or higher to spawn at all. - Defaults to -31000. -altitudemax: But no higher than this altitude. Defaults to +31000. -sbiome: List of nodes that must be somewhere in the vicinity in - order for the plant to spawn. Typically this would be - something like "default:water_source" or "default:sand". - Defaults to the value of ssurface if not provided. -sbiomesize: How large of an area to check for the above node. - Specifically, this checks a cuboid area centered on the - node to be spawned on, 3 tall and this wide/long. - Defaults to 0. -sbiomecount: How many of the above nodes must be within that radius. - Defaults to 1. -airradius: How large of an area to check for air around the target. - Defaults to 0 (only check the target). -aircount: How many of the surrounding nodes need to be air for the - above check to return true. Defaults to 1. -tempmin: Minimum 2d Perlin value (which has a floating point range of - -1 to +1) needed in the temperature map for the desired - plant to spawn. Defaults to -1 if not supplied. -tempmax: Maximum temperature. Defaults to +1. + 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"). Note that if the plant is + "poisonivy:seedling", and it's next to a wall at spawn + time, it automatically becomes the wall-climbing + variety. A plant will of course only be spawned if the + node about to be replaced is air. + sradius: Don't spawn within this many nodes of the avoid items + mentioned below. 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, e.g. 1-in-10). + 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"}. If not specified, this defaults to + the value of splant. + +When passed a table as the argument, and thus using the modern calling method, +you must pass at least four arguments as regular keyed entries in the table, +in any order: + +plants_lib: spawn_on_surfaces({ + spawn_plants = {table}, -- List of plants to spawn with this ABM call. + -- The program will choose one of these at + -- random each time the ABM executes. 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. + spawn_delay = number, -- same as sdelay + spawn_chance = number, -- same as schance + 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 several optional + -- parameters. + + avoid_nodes = {table}, -- same meaning as savoid, above + avoid_radius = num, -- same as sradius + seed_diff = num -- The Perlin seed difference value passed to + -- the minetest.env:get_perlin() function. + -- Used along with the global Perlin controls + -- below to create the "biome" in which the + -- plants will spawn. Defaults to 0 if not + -- provided. + light_min = num, -- Minimum amount of light necessary to make a + -- plant spawn. Defaults to 0. + light_max = num, -- Maximum amount of light needed to spawn. + -- Defaults to the engine's MAX_LIGHT value of + -- 14. + neighbors = {table}, -- List of neighboring nodes that need to be + -- immediately next to the node the plant is + -- about to spawn on. Can also be a string + -- with a single node name. It is both passed + -- to the ABM as the "neighbors" parameter, + -- and is used to manually check the + -- adjacent nodes. It only takes one of these + -- for the spawn routine to mark the target as + -- spawnable. Defaults to nil (ignored). + ncount = num, -- There must be at least this many of the + -- above neighbors in the eight spaces + -- immediately surrounding the node the plant + -- is about to spawn on for it to happen. If + -- not provided, this check is disabled. + facedir = num, -- The value passed to the param2 variable + -- when adding the node to the map. Defaults + -- to 0. Be sure that the value you use here + -- (and the range thereof) is appropriate for + -- the type of node you're spawning. + random_facedir = {table}, -- If set, the table should contain two + -- values. If they're both provided, the + -- spawned plant will be given a random + -- facedir value in the range specified by + -- these two numbers. Overrides the facedir + -- parameter above, if it exists. Use {0,3} + -- if you want the full range for wallmounted + -- nodes, or {2,5} for most everything else, + -- or any other pair of numbers in the 0 to 5 + -- range, as appropriate for the node you want + -- to spawn. + verticals_list = {table} -- List of nodes that should be considered to + -- be natural walls. + alt_wallnode = "string", -- If specified, this node will be + -- substituted in place of the plant(s) + -- defined by spawn_plants above, if the spawn + -- target has one or more adjacent walls. In + -- such a case, the two above facedir + -- parameters will be ignored. + depth_max = num, -- If the object spawns on top of a water + -- source, the water must be at most this + -- deep. Defaults to 1 node. + min_elevation = num, -- Surface must be at this altitude or higher + -- to spawn at all. Defaults to -31000... + max_elevation = num, -- ...but must be no higher than this + -- altitude. Defaults to +31000. + near_nodes = {table}, -- List of nodes that must be somewhere in the + -- vicinity in order for the plant to spawn. + -- Can also be a string with a single node + -- name. If not provided, this check is + -- disabled. + near_nodes_size = num, -- How large of an area to check for the above + -- node. Specifically, this checks a flat + -- horizontal area centered on the node to be + -- spawned on. Defaults to 0, but is ignored + -- if the above near_nodes value is not set. + near_nodes_vertical = num, -- Used with the size value above, this + -- extends the vertical range of the near + -- nodes search. Basically, this turns the + -- flat region described above into a cuboid + -- region. The area to be checked will extend + -- this high AND this low above/below the + -- target node, centered thereon. Defaults to + -- 1 (check only the layer above, the layer + -- at, and the layer below the target node), + -- but is ignored if near_nodes is not set. + near_nodes_count = num, -- How many of the above nodes must be within + -- that radius. Defaults to 1 but is ignored + -- if near_nodes isn't set. Bear in mind that + -- the total area to be checked is equal to + -- (near_nodes_size^2)*near_nodes_vertical*2. + -- so for example, if size is 10 and vertical + -- is 4 then the area is (10^2)*8 = 800 nodes + -- in size, so you'll want to make sure you + -- specify a value appropriate for the amount + -- in question. + air_size = num, -- How large of an area to check for air + -- above and around the target. If omitted, + -- only the space above the target is checked. + -- This does not check for air at the sides or + -- below the target. + air_count = num, -- How many of the surrounding nodes need to + -- be air for the above check to return true. + -- If omitted, only the space above the target + -- is checked. + plantlife_limit = num, -- The value compared against the generic + -- "plants can grow here" Perlin noise layer. + -- Smaller numbers result in more abundant + -- plants. Range of -1 to +1, with values in + -- the range of about 0 to 0.5 being most + -- useful. Defaults to 0.1. + temp_min = num, -- Minimum temperature needed for the desired + -- object to spawn. This is a 2d Perlin + -- value, which has an inverted range of +1 to + -- -1. Larger values represent *colder* + -- temperatures, so this value is actually the + -- upper end of the desired Perlin range. See + -- the temperature map section at the bottom + -- of this document for details on how these + -- values work. Defaults to +1 (unlimited + -- coldness). + temp_max = num, -- Maximum temperature/lower end of the Perlin + -- range. Defaults to -1 (unlimited heat). + spawn_on_side = bool, -- Set this to true to spawn the node on one + -- side of the target node rather than the + -- top. The code will search for an airspace + -- to the side of the target, then spawn the + -- plant at the first one found. The above + -- facedir and random_facedir parameters are + -- ignored in this case. If the above + -- parameters for selecting generic wall nodes + -- are provided, this option is ignored. + -- Important note: the facedir values assigned + -- by this option only make sense with + -- wallmounted nodes (nodes which don't use + -- facedir won't be affected). + spawn_on_bottom = bool, -- If set to true, spawn the object below the + -- target node instead of above it. The above + -- spawn_on_side variable takes precedence + -- over this one if both happen to be true. + -- When using this option with the random + -- facedir function above, the values given to + -- the facedir parameter are for regular + -- nodes, not wallmounted. +}) By default, if a biome node, size, and count are not defined, the biome checking is disabled. Same holds true for the nneighbors bit above that. @@ -120,7 +235,7 @@ node (see below): plantslib:register_generate_plant(biome, function_or_treedef) -Where "biome" is a table containing about a dozen variables: +Where "biome" is a table containing about a dozen variables. biome = { surface = "string", -- [*] what nodes to spawn on. @@ -153,13 +268,23 @@ biome = { of the object being spawned. near_nodes_size = num, -- how wide of a search area to look for the nodes in that list. + near_nodes_vertical = num, -- How high/low of an area to search from + -- the target node. near_nodes_count = num, -- at least this many of those nodes must be in the area. + plantlife_limit = num, -- The value compared against the generic + -- "plants can grow here" Perlin noise layer. + -- Smaller numbers result in more abundant + -- plants. Range of -1 to +1, with values in + -- the range of about 0 to 0.5 being most + -- useful. Defaults to 0.1. temp_min = num, -- coldest allowable temperature for a plant to spawn (that is, the highest Perlin temperature map value). temp_max = num, -- warmest allowable temperature to spawn a plant (lowest Perlin temperature value). + verticals_list = {table}, -- Same as with the spawn_on_surfaces + -- function. } [*] These entries are required for the spawn code to work. Everything else @@ -179,82 +304,120 @@ with the position to spawn the tree on. ----- The third function, grow_plants() is used to turn the spawned nodes above -into something else over time. This function has no return value, and is -defined like so: +into something else over time. This function has no return value, and accepts +a table as the only parameter: -grow_plants = function(gdelay, gchance, gplant, gresult, dry_early_node, - grow_nodes, facedir, need_wall, grow_vertically, height_limit, - ground_nodes, grow_function, seed_diff) +grow_plants({list of options}) -gdelay: Passed as the ABM "interval" parameter, as with spawning. -gchance: Passed as the ABM "chance" parameter. -gplant: Name of the node being grown. This value is passed as the - only item in the table given to the ABM as the nodenames - parameter, so it is the plants themselves that are the ABM - trigger, rather than the ground they spawned on. A plant - will only grow if the node above it is air. -gresult: Name of the node into which the above should transform - when the ABM executes. -dry_early_node: This value is ignored except for jungle grass, where it - indicates which node the grass must be on in order for it - to turn from "short" to default:dry_shrub. -grow_nodes: One of these nodes must be under the plant in order for it to - grow at all. Normally this should be the same as the list of - surfaces passed to the spawning ABM as the "nodenames" - parameter. This is so that the plant can be manually placed - on something like a flower pot or something without it growing - and eventually dieing. Defaults to "default:dirt_with_grass". -facedir: Same as with spawning a plant. If supplied, this value is - passed to the param2 variable when changing the plant. If - nil or left out, no new param2 value is applied. -need_wall: Set this to true if you the plant needs to grow against a - wall. Defaults to false. -grow_vertically: Set this to true if the plant needs to grow vertically, as - in climbing poison ivy. Defaults to false. -height_limit: Just how tall can a vertically-growing plant go? Set this - accordingly. The mod will search straight down from the - position being spawned at to find a ground node, set via the - parameter below. Defaults to 62000 (unlimited). -ground_nodes: What nodes should be treated as "the ground" below a - vertically-growing plant. Usually this will be the same - as the grow_nodes table, but might also include, for - example, water or some other surrounding material. - Defaults to "default:dirt_with_grass". -grow_function: String indicating what function to use to grow the plant, if - any, or a table with an L-Systems tree model, or nil. If it's - nil, If it's nil, a regular plant will be inserted in place - of the one being grown, per the above variables. If it's a - string, the function named therein is executed and passed a - parameter for the current position, followed by the "can grow - here" and temperature map Perlin values at that location. If - it's a table, the tree described by that table is spawned at - the current position. In both string and table cases, all - parameters from gresult to ground_nodes, except for - grow_nodes, are ignored. -seed_diff: The Perlin seed diff to be use to calculate the first noise - value given to the above grow_function. Should be the same as - the seed diff used when first spawning the plant that's being - grown. +These are defined like so: + +plants_lib:grow_plants({ + + grow_plant = "string", -- Name of the node to be grown into something + -- else. This value is passed to the ABM as + -- the "nodenames" parameter, so it is the + -- plants themselves that are the ABM trigger, + -- rather than the ground they spawned on. A + -- plant will only grow if the node above it + -- is air. Can also be a table, but note that + -- all nodes referenced therein will be grown + -- into the same object. + grow_delay = num, -- Passed as the ABM "interval" parameter, as + -- with spawning. + grow_chance = num, -- Passed as the ABM "chance" parameter. + grow_result = "string", -- Name of the node into which the grow_plant + -- node(s) should transform when the ABM + -- executes. + 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 + -- growing and eventually 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}, -- List of nodes that should be considered + -- to be wall surfaces when growing the plant + -- vertically. If not provided, the walls + -- check is skipped. + grow_vertically = bool, -- Set this to true if the plant needs to grow + -- vertically, as in climbing poison ivy. + -- Defaults to false. + height_limit = num, -- Set this to limit how tall the desired node + -- can grow. The mod will search straight + -- down from the position being spawned at to + -- find a ground node, set via the parameter + -- below. Defaults to 5 nodes. + ground_nodes = {table}, -- What nodes should be treated as "the + -- ground" below a vertically-growing plant. + -- Usually this should be the same as the + -- grow_nodes table, but might also include, + -- for example, water or some other + -- surrounding material. Defaults to + -- "default:dirt_with_grass". + grow_function = something, -- [*] see below. + seed_diff = num, -- [*] see below. +}) + + +[*] grow_function can take one of three possible settings: it can be nil (or + not provided), a string, or a table. + + If it is not provided or it's set to nil, all of the regular growing code + is executed normally. The value of seed_diff, if any, is ignored in this + case. + + If this value is set to a simple string, this is treated as the name of + the function to use to grow the plant. In this case, all of the usual + growing code is executeed, but then instead of a plant being simply added + to the world, grow_result is ignored and the named function is executed + and passed a few parmeters: + + somefunction(pos, perlin1, perlin2) + + These values represent the current position (the usual table), the + Perlin noise value for that spot in the generic "plants can grow here" + map for the seed_diff value above, the Perlin value for that same spot + from the temperature map, and the detected neighboring wall face, if + there was one (or nil if not). If seed_diff is not provided, it + defaults to 0. + + If this variable is instead set to a table, it is treated an an L-Systems + tree definition. All of the growing code is executed in the usual manner, + then the tree described by that definition is spawned at the current + position instead, and grow_result is ignored. ----- -Of the few helper functions, plant_valid_wall() expects only a single -parameter, "pos", which is the usual table indicating the coordinates around -which to search for adjacent walls. This function returns the location of the -first wall found as a facedir value, or nil if there are no adjacent walls. +Of the few helper functions, plantslib:find_adjacent_wall() expects a position +parameter and a table with the list of nodes that should be considered as +walls. The code will search around the given position for a neighboring wall, +returning the first one it finds as a facedir value, or nil if there are no +adjacent walls. ----- -is_node_loaded() is defined in exactly the same manner (that is, "node_pos" is -a set of coordinates), and acts as a wrapper for the +plantslib:is_node_loaded() is defined in exactly the same manner (that is, +"node_pos" is a set of coordinates), and acts as a wrapper for the minetest.env:get_node_or_nil(node_pos) function. Returns true if the node in question is already loaded, or false if not. ----- -dbg() is a simple debug output function which takes one string parameter. It -just checks if plantlife_debug is true and outputs the phrase "[Plantlife] " -followed by the supplied string, via the print() function. +plantslib:dbg() 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. =============== diff --git a/flowers/init.lua b/flowers/init.lua index 77ab1f5..4a02057 100644 --- a/flowers/init.lua +++ b/flowers/init.lua @@ -1,27 +1,25 @@ -- This file supplies flowers for the plantlife modpack +-- Last revision: 2013-01-24 -local spawn_delay = 2000 -- 2000 -local spawn_chance = 100 -- 100 -local flowers_seed_diff = plantslib.plantlife_seed_diff+20 +local SPAWN_DELAY = 1000 +local SPAWN_CHANCE = 200 +local flowers_seed_diff = 349 local flowers_list = { - { "Rose", "rose", spawn_delay, 10, spawn_chance , 10}, - { "Tulip", "tulip", spawn_delay, 10, spawn_chance , 10}, - { "Yellow Dandelion", "dandelion_yellow", spawn_delay, 10, spawn_chance*2 , 10}, - { "White Dandelion", "dandelion_white", spawn_delay, 10, spawn_chance*2 , 10}, - { "Blue Geranium", "geranium", spawn_delay, 10, spawn_chance , 10}, - { "Viola", "viola", spawn_delay, 10, spawn_chance , 10}, - { "Cotton Plant", "cotton", spawn_delay, 10, spawn_chance*2 , 10}, + { "Rose", "rose"}, + { "Tulip", "tulip"}, + { "Yellow Dandelion", "dandelion_yellow"}, + { "White Dandelion", "dandelion_white"}, + { "Blue Geranium", "geranium"}, + { "Viola", "viola"}, + { "Cotton Plant", "cotton"}, } for i in ipairs(flowers_list) do local flowerdesc = flowers_list[i][1] local flower = flowers_list[i][2] - local delay = flowers_list[i][3] - local radius = flowers_list[i][4] - local chance = flowers_list[i][5] - minetest.register_node(":flowers:flower_"..flower, { + minetest.register_node("flowers:flower_"..flower, { description = flowerdesc, drawtype = "plantlike", tiles = { "flower_"..flower..".png" }, @@ -38,7 +36,7 @@ for i in ipairs(flowers_list) do }, }) - minetest.register_node(":flowers:flower_"..flower.."_pot", { + minetest.register_node("flowers:flower_"..flower.."_pot", { description = flowerdesc.." in a pot", drawtype = "plantlike", tiles = { "flower_"..flower.."_pot.png" }, @@ -63,29 +61,100 @@ for i in ipairs(flowers_list) do "flowers:flower_"..flower } }) - - plantslib:spawn_on_surfaces(delay, "flowers:flower_"..flower, radius, chance, "default:dirt_with_grass", {"group:flower", "group:poisonivy"}, flowers_seed_diff) end -minetest.register_node(":flowers:flower_waterlily", { +minetest.register_node("flowers:flower_waterlily", { description = "Waterlily", - drawtype = "raillike", + drawtype = "nodebox", tiles = { "flower_waterlily.png" }, inventory_image = "flower_waterlily.png", wield_image = "flower_waterlily.png", sunlight_propagates = true, paramtype = "light", - paramtype2 = "wallmounted", + paramtype2 = "facedir", walkable = false, groups = { snappy = 3,flammable=2,flower=1 }, sounds = default.node_sound_leaves_defaults(), selection_box = { type = "fixed", fixed = { -0.4, -0.5, -0.4, 0.4, -0.45, 0.4 }, - }, + }, + node_box = { + type = "fixed", + fixed = { -0.5, -0.49, -0.5, 0.5, -0.49, 0.5 }, + }, }) -minetest.register_node(":flowers:flower_seaweed", { +minetest.register_node("flowers:flower_waterlily_225", { + description = "Waterlily", + drawtype = "nodebox", + tiles = { "flower_waterlily_22.5.png" }, + inventory_image = "flower_waterlily.png", + wield_image = "flower_waterlily.png", + sunlight_propagates = true, + paramtype = "light", + paramtype2 = "facedir", + walkable = false, + groups = { snappy = 3,flammable=2,flower=1, not_in_creative_inventory=1 }, + sounds = default.node_sound_leaves_defaults(), + selection_box = { + type = "fixed", + fixed = { -0.4, -0.5, -0.4, 0.4, -0.45, 0.4 }, + }, + node_box = { + type = "fixed", + fixed = { -0.5, -0.49, -0.5, 0.5, -0.49, 0.5 }, + }, + drop = "flowers:flower_waterlily" +}) + +minetest.register_node("flowers:flower_waterlily_45", { + description = "Waterlily", + drawtype = "raillike", + tiles = { "flower_waterlily_45.png" }, + inventory_image = "flower_waterlily.png", + wield_image = "flower_waterlily.png", + sunlight_propagates = true, + paramtype = "light", + paramtype2 = "facedir", + walkable = false, + groups = { snappy = 3,flammable=2,flower=1, not_in_creative_inventory=1 }, + sounds = default.node_sound_leaves_defaults(), + selection_box = { + type = "fixed", + fixed = { -0.4, -0.5, -0.4, 0.4, -0.45, 0.4 }, + }, + node_box = { + type = "fixed", + fixed = { -0.5, -0.49, -0.5, 0.5, -0.49, 0.5 }, + }, + drop = "flowers:flower_waterlily" +}) + +minetest.register_node("flowers:flower_waterlily_675", { + description = "Waterlily", + drawtype = "nodebox", + tiles = { "flower_waterlily_67.5.png" }, + inventory_image = "flower_waterlily.png", + wield_image = "flower_waterlily.png", + sunlight_propagates = true, + paramtype = "light", + paramtype2 = "facedir", + walkable = false, + groups = { snappy = 3,flammable=2,flower=1, not_in_creative_inventory=1 }, + sounds = default.node_sound_leaves_defaults(), + selection_box = { + type = "fixed", + fixed = { -0.4, -0.5, -0.4, 0.4, -0.45, 0.4 }, + }, + node_box = { + type = "fixed", + fixed = { -0.5, -0.49, -0.5, 0.5, -0.49, 0.5 }, + }, + drop = "flowers:flower_waterlily" +}) + +minetest.register_node("flowers:flower_seaweed", { description = "Seaweed", drawtype = "signlike", tiles = { "flower_seaweed.png" }, @@ -103,12 +172,99 @@ minetest.register_node(":flowers:flower_seaweed", { }, }) -plantslib:spawn_on_surfaces(spawn_delay/2, "flowers:flower_waterlily", 3, spawn_chance*2, "default:water_source" , {"group:flower"}, flowers_seed_diff, 10, nil, nil, nil, nil, 4) +-- spawn ABM registrations -plantslib:spawn_on_surfaces(spawn_delay*2, "flowers:flower_seaweed" , 0.1, spawn_chance*2, "default:water_source" , {"group:flower"}, flowers_seed_diff, 4, 10, {"default:dirt_with_grass"}, 0, 1) -plantslib:spawn_on_surfaces(spawn_delay*2, "flowers:flower_seaweed" , 0.1, spawn_chance*2, "default:dirt_with_grass", {"group:flower"}, flowers_seed_diff, 4, 10, {"default:water_source"} , 1, 1) -plantslib:spawn_on_surfaces(spawn_delay*2, "flowers:flower_seaweed" , 0.1, spawn_chance*2, "default:stone" , {"group:flower"}, flowers_seed_diff, 4, 10, {"default:water_source"} , 6, 1) +plantslib:spawn_on_surfaces({ + spawn_delay = SPAWN_DELAY, + spawn_plants = { + "flowers:flower_rose", + "flowers:flower_tulip", + "flowers:flower_geranium", + "flowers:flower_viola", + }, + avoid_radius = 10, + spawn_chance = SPAWN_CHANCE*2, + spawn_surfaces = {"default:dirt_with_grass"}, + avoid_nodes = {"group:flower", "group:poisonivy"}, + seed_diff = flowers_seed_diff, + light_min = 9 +}) +plantslib:spawn_on_surfaces({ + spawn_delay = SPAWN_DELAY, + spawn_plants = { + "flowers:flower_dandelion_yellow", + "flowers:flower_dandelion_white", + "flowers:flower_cotton", + }, + avoid_radius = 7, + spawn_chance = SPAWN_CHANCE, + spawn_surfaces = {"default:dirt_with_grass"}, + avoid_nodes = {"group:flower", "group:poisonivy"}, + seed_diff = flowers_seed_diff, + light_min = 9 +}) + +plantslib:spawn_on_surfaces({ + spawn_delay = SPAWN_DELAY/2, + spawn_plants = { + "flowers:flower_waterlily", + "flowers:flower_waterlily_225", + "flowers:flower_waterlily_45", + "flowers:flower_waterlily_675" + }, + avoid_radius = 2.5, + spawn_chance = SPAWN_CHANCE*4, + spawn_surfaces = {"default:water_source"}, + avoid_nodes = {"group:flower"}, + seed_diff = flowers_seed_diff, + light_min = 9, + depth_max = 2, + random_facedir = {2,5} +}) + +plantslib:spawn_on_surfaces({ + spawn_delay = SPAWN_DELAY*2, + spawn_plants = {"flowers:flower_seaweed"}, + spawn_chance = SPAWN_CHANCE*2, + spawn_surfaces = {"default:water_source"}, + avoid_nodes = {"group:flower"}, + seed_diff = flowers_seed_diff, + light_min = 4, + light_max = 10, + neighbors = {"default:dirt_with_grass"}, + facedir = 1 +}) + +plantslib:spawn_on_surfaces({ + spawn_delay = SPAWN_DELAY*2, + spawn_plants = {"flowers:flower_seaweed"}, + spawn_chance = SPAWN_CHANCE*2, + spawn_surfaces = {"default:dirt_with_grass"}, + avoid_nodes = {"group:flower"}, + seed_diff = flowers_seed_diff, + light_min = 4, + light_max = 10, + neighbors = {"default:water_source"}, + ncount = 1, + facedir = 1 +}) + +plantslib:spawn_on_surfaces({ + spawn_delay = SPAWN_DELAY*2, + spawn_plants = {"flowers:flower_seaweed"}, + spawn_chance = SPAWN_CHANCE*2, + spawn_surfaces = {"default:stone"}, + avoid_nodes = {"group:flower"}, + seed_diff = flowers_seed_diff, + light_min = 4, + light_max = 10, + neighbors = {"default:water_source"}, + ncount = 6, + facedir = 1 +}) + +-- crafting recipes! minetest.register_craftitem(":flowers:flower_pot", { description = "Flower Pot", @@ -124,23 +280,23 @@ minetest.register_craft( { }) minetest.register_craftitem(":flowers:cotton", { - description = "Cotton", - image = "cotton.png", + description = "Cotton", + image = "cotton.png", }) minetest.register_craft({ - output = "flowers:cotton 3", - recipe ={ - {"flowers:flower_cotton"}, - } + output = "flowers:cotton 3", + recipe ={ + {"flowers:flower_cotton"}, + } }) minetest.register_craft({ output = "wool:white 2", recipe = { - {'', '', ''}, {'flowers:cotton', 'flowers:cotton', ''}, {'flowers:cotton', 'flowers:cotton', ''}, } }) +print("[Flowers] Loaded.") diff --git a/flowers/textures/flower_waterlily.png b/flowers/textures/flower_waterlily.png index 0235d84..7a2c034 100644 Binary files a/flowers/textures/flower_waterlily.png and b/flowers/textures/flower_waterlily.png differ diff --git a/flowers/textures/flower_waterlily_22.5.png b/flowers/textures/flower_waterlily_22.5.png new file mode 100644 index 0000000..182110d Binary files /dev/null and b/flowers/textures/flower_waterlily_22.5.png differ diff --git a/flowers/textures/flower_waterlily_45.png b/flowers/textures/flower_waterlily_45.png new file mode 100644 index 0000000..d83a057 Binary files /dev/null and b/flowers/textures/flower_waterlily_45.png differ diff --git a/flowers/textures/flower_waterlily_67.5.png b/flowers/textures/flower_waterlily_67.5.png new file mode 100644 index 0000000..e6b3ba5 Binary files /dev/null and b/flowers/textures/flower_waterlily_67.5.png differ diff --git a/junglegrass/init.lua b/junglegrass/init.lua index 7dfde15..a037435 100644 --- a/junglegrass/init.lua +++ b/junglegrass/init.lua @@ -1,10 +1,11 @@ -- This file supplies jungle grass for the plantlife modpack +-- Last revision: 2013-01-24 -local spawn_delay = 2000 -- 2000 -local spawn_chance = 100 -- 100 -local grow_delay = 1000 -- 1000 -local grow_chance = 10 -- 10 -local junglegrass_seed_diff = plantslib.plantlife_seed_diff +local SPAWN_DELAY = 1000 +local SPAWN_CHANCE = 200 +local GROW_DELAY = 500 +local GROW_CHANCE = 30 +local junglegrass_seed_diff = 329 local grasses_list = { {"junglegrass:shortest","junglegrass:short" }, @@ -13,7 +14,7 @@ local grasses_list = { {"default:junglegrass" , nil} } -minetest.register_node(':junglegrass:medium', { +minetest.register_node('junglegrass:medium', { description = "Jungle Grass (medium height)", drawtype = 'plantlike', tile_images = { 'junglegrass_medium.png' }, @@ -32,7 +33,7 @@ minetest.register_node(':junglegrass:medium', { }, }) -minetest.register_node(':junglegrass:short', { +minetest.register_node('junglegrass:short', { description = "Jungle Grass (short)", drawtype = 'plantlike', tile_images = { 'junglegrass_short.png' }, @@ -50,7 +51,7 @@ minetest.register_node(':junglegrass:short', { }, }) -minetest.register_node(':junglegrass:shortest', { +minetest.register_node('junglegrass:shortest', { description = "Jungle Grass (very short)", drawtype = 'plantlike', tile_images = { 'junglegrass_shortest.png' }, @@ -68,12 +69,48 @@ minetest.register_node(':junglegrass:shortest', { }, }) -plantslib:spawn_on_surfaces(spawn_delay*2, "junglegrass:shortest", 4, spawn_chance, "default:dirt_with_grass", {"group:junglegrass", "default:junglegrass", "default:dry_shrub"}, junglegrass_seed_diff, 5) -plantslib:spawn_on_surfaces(spawn_delay*2, "junglegrass:shortest", 4, spawn_chance*2, "default:sand" , {"group:junglegrass", "default:junglegrass", "default:dry_shrub"}, junglegrass_seed_diff, 5) -plantslib:spawn_on_surfaces(spawn_delay*2, "junglegrass:shortest", 4, spawn_chance*3, "default:desert_sand" , {"group:junglegrass", "default:junglegrass", "default:dry_shrub"}, junglegrass_seed_diff, 5) -plantslib:spawn_on_surfaces(spawn_delay*2, "junglegrass:shortest", 4, spawn_chance*3, "default:desert_sand" , {"group:junglegrass", "default:junglegrass", "default:dry_shrub"}, junglegrass_seed_diff, 5) +plantslib:spawn_on_surfaces({ + spawn_delay = SPAWN_DELAY, + spawn_plants = {"junglegrass:shortest"}, + avoid_radius = 4, + spawn_chance = SPAWN_CHANCE, + spawn_surfaces = {"default:dirt_with_grass", "default:cactus", "default:papyrus"}, + avoid_nodes = {"group:junglegrass", "default:junglegrass", "default:dry_shrub"}, + seed_diff = junglegrass_seed_diff, + light_min = 5 +}) + +plantslib:spawn_on_surfaces({ + spawn_delay = SPAWN_DELAY, + spawn_plants = {"junglegrass:shortest"}, + avoid_radius = 4, + spawn_chance = SPAWN_CHANCE*2, + spawn_surfaces = {"default:sand"}, + avoid_nodes = {"group:junglegrass", "default:junglegrass", "default:dry_shrub"}, + seed_diff = junglegrass_seed_diff, + light_min = 5 +}) + +plantslib:spawn_on_surfaces({ + spawn_delay = SPAWN_DELAY, + spawn_plants = {"junglegrass:shortest"}, + avoid_radius = 4, + spawn_chance = SPAWN_CHANCE*5, + spawn_surfaces = {"default:desert_sand"}, + avoid_nodes = {"group:junglegrass", "default:junglegrass", "default:dry_shrub"}, + seed_diff = junglegrass_seed_diff, + light_min = 5 +}) for i in ipairs(grasses_list) do - plantslib:grow_plants(grow_delay, grow_chance/2, grasses_list[i][1], grasses_list[i][2], "default:desert_sand", {"default:dirt_with_grass", "default:sand", "default:desert_sand"}) + plantslib:grow_plants({ + grow_delay = GROW_DELAY, + grow_chance = GROW_CHANCE/2, + grow_plant = grasses_list[i][1], + grow_result = grasses_list[i][2], + dry_early_node = "default:desert_sand", + grow_nodes = {"default:dirt_with_grass", "default:sand", "default:desert_sand"} + }) end +print("[Junglegrass] Loaded.") diff --git a/plants_lib/init.lua b/plants_lib/init.lua index 273cb29..6206b87 100644 --- a/plants_lib/init.lua +++ b/plants_lib/init.lua @@ -1,5 +1,5 @@ -- Plantlife library mod by Vanessa Ezekowitz --- 2013-01-20 +-- last revision, 2013-01-24 -- -- License: WTFPL -- @@ -24,7 +24,7 @@ local temperature_octaves = 3 local temperature_persistence = 0.5 local temperature_scale = 150 -local plantlife_limit = 0.1 + -- Local functions @@ -47,13 +47,18 @@ end -- Spawn plants using the map generator -function plantslib:register_generate_plant(biome, funct_or_model) - minetest.register_on_generated(plantslib:search_for_surfaces(minp, maxp, biome, funct_or_model)) +function plantslib:register_generate_plant(biomedef, funct_or_model) + plantslib:dbg("Registered mapgen spawner:") + plantslib:dbg(dump(biomedef)) + + minetest.register_on_generated(plantslib:search_for_surfaces(minp, maxp, biomedef, funct_or_model)) end -function plantslib:search_for_surfaces(minp, maxp, biome, funct_or_model) +function plantslib:search_for_surfaces(minp, maxp, biomedef, funct_or_model) return function(minp, maxp, blockseed) + local biome = biomedef + if biome.seed_diff == nil then biome.seed_diff = 0 end if biome.neighbors == nil then biome.neighbors = biome.surface end if biome.min_elevation == nil then biome.min_elevation = -31000 end @@ -64,6 +69,8 @@ function plantslib:search_for_surfaces(minp, maxp, biome, funct_or_model) if biome.temp_max == nil then biome.temp_max = -1 end if biome.rarity == nil then biome.rarity = 50 end if biome.max_count == nil then biome.max_count = 5 end + if biome.plantlife_limit == nil then biome.plantlife_limit = 0.1 end + if biome.near_nodes_vertical == nil then biome.near_nodes_vertical = 1 end plantslib:dbg("Started checking generated mapblock volume...") local searchnodes = minetest.env:find_nodes_in_area(minp, maxp, biome.surface) @@ -80,131 +87,166 @@ function plantslib:search_for_surfaces(minp, maxp, biome, funct_or_model) and minetest.env:get_node(p_top).name == "air" and pos.y >= biome.min_elevation and pos.y <= biome.max_elevation - and noise1 > plantlife_limit + and noise1 > biome.plantlife_limit and noise2 <= biome.temp_min and noise2 >= biome.temp_max and (biome.ncount == nil or table.getn(minetest.env:find_nodes_in_area({x=pos.x-1, y=pos.y, z=pos.z-1}, {x=pos.x+1, y=pos.y, z=pos.z+1}, biome.neighbors)) > biome.ncount) - and (biome.near_nodes == nil or table.getn(minetest.env:find_nodes_in_area({x=pos.x-biome.near_nodes_size, y=pos.y-1, z=pos.z-biome.near_nodes_size}, {x=pos.x+biome.near_nodes_size, y=pos.y+1, z=pos.z+biome.near_nodes_size}, biome.near_nodes)) >= biome.near_nodes_count) + and (biome.near_nodes == nil or table.getn(minetest.env:find_nodes_in_area({x=pos.x-biome.near_nodes_size, y=pos.y-biome.near_nodes_vertical, z=pos.z-biome.near_nodes_size}, {x=pos.x+biome.near_nodes_size, y=pos.y+biome.near_nodes_vertical, z=pos.z+biome.near_nodes_size}, biome.near_nodes)) >= biome.near_nodes_count) and math.random(1,100) > biome.rarity then table.insert(in_biome_nodes, pos) num_in_biome_nodes = num_in_biome_nodes + 1 end end - + + plantslib:dbg("Found "..num_in_biome_nodes.." surface nodes of type "..biome.surface.." in 5x5x5 mapblock volume at {"..dump(minp)..":"..dump(maxp).."} to check.") + if num_in_biome_nodes > 0 then - plantslib:dbg("Found "..num_in_biome_nodes.." surface nodes of type "..biome.surface.." in 5x5x5 mapblock volume at {"..dump(minp)..":"..dump(maxp).."} to check.") - for i = 1,biome.max_count do + plantslib:dbg("Calculated maximum of "..math.min(biome.max_count*3, num_in_biome_nodes).." nodes to be checked in that list.") + for i = 1, math.min(biome.max_count, num_in_biome_nodes) do local tries = 0 local spawned = false - while tries < 2 and not planted do + while tries < 2 and not spawned do local pos = in_biome_nodes[math.random(1, num_in_biome_nodes)] local p_top = { x = pos.x, y = pos.y + 1, z = pos.z } if minetest.env:find_node_near(p_top, biome.avoid_radius + math.random(-1.5,1.5), biome.avoid_nodes) == nil then spawned = true if type(funct_or_model) == "table" then plantslib:dbg("Spawn tree at {"..dump(pos).."}") + + --[[ + for v = 0,10 do + minetest.env:remove_node({ x = pos.x, y = pos.y + v, z = pos.z }) + minetest.env:remove_node({ x = pos.x-1, y = pos.y + v, z = pos.z }) + minetest.env:remove_node({ x = pos.x+1, y = pos.y + v, z = pos.z }) + minetest.env:remove_node({ x = pos.x, y = pos.y + v, z = pos.z-1 }) + minetest.env:remove_node({ x = pos.x, y = pos.y + v, z = pos.z+1 }) + end + ]]-- + minetest.env:spawn_tree(pos, funct_or_model) else - plantslib:dbg("Call function: "..funct_or_model.."("..dump(pos)..")") plantslib:dbg("Call function: "..funct_or_model.."("..dump(pos)..")") assert(loadstring(funct_or_model.."("..dump(pos)..")"))() end else tries = tries + 1 - spawned = false - plantslib:dbg("Couldn't spawn a tree at {"..dump(pos).."} -- trying again elsewhere") + plantslib:dbg("No room to spawn object at {"..dump(pos).."} -- trying again elsewhere") end end - if tries == 2 and spawned == false then - plantslib:dbg("Unable to spawn that tree. Giving up on it.") + if tries == 2 then + plantslib:dbg("Unable to spawn that object. Giving up on it.") end end end + plantslib:dbg("Finished checking generated area.") end end -- The spawning ABM -function plantslib:spawn_on_surfaces( - sdelay, - splant, - sradius, - schance, - ssurface, - savoid, - seed_diff, - lightmin, - lightmax, - nneighbors, - ocount, - facedir, - depthmax, - altmin, - altmax, - sbiome, - sbiomesize, - sbiomecount, - airsize, - aircount, - tempmin, - tempmax) - if seed_diff == nil then seed_diff = 0 end - if lightmin == nil then lightmin = 0 end - if lightmax == nil then lightmax = LIGHT_MAX end - if nneighbors == nil then nneighbors = ssurface end - if ocount == nil then ocount = -1 end - if depthmax == nil then depthmax = 1 end - if altmin == nil then altmin = -31000 end - if altmax == nil then altmax = 31000 end - if sbiome == nil then sbiome = "" end - if sbiomesize == nil then sbiomesize = 0 end - if sbiomecount == nil then sbiomecount = 1 end - if airsize == nil then airsize = 0 end - if aircount == nil then aircount = 1 end - if tempmin == nil then tempmin = -2 end - if tempmax == nil then tempmax = 2 end +function plantslib:spawn_on_surfaces(sd,sp,sr,sc,ss,sa) + + local biome = {} + + if type(sd) ~= "table" then + biome.spawn_delay = sd -- old api expects ABM interval param here. + biome.spawn_plants = {sp} + biome.avoid_radius = sr + biome.spawn_chance = sc + biome.spawn_surfaces = {ss} + biome.avoid_nodes = sa + else + biome = sd + end + + if biome.seed_diff == nil then biome.seed_diff = 0 end + if biome.light_min == nil then biome.light_min = 0 end + if biome.light_max == nil then biome.light_max = 15 end + if biome.depth_max == nil then biome.depth_max = 1 end + if biome.min_elevation == nil then biome.min_elevation = -31000 end + if biome.max_elevation == nil then biome.max_elevation = 31000 end + if biome.temp_min == nil then biome.temp_min = 1 end + if biome.temp_max == nil then biome.temp_max = -1 end + if biome.plantlife_limit == nil then biome.plantlife_limit = 0.1 end + if biome.near_nodes_vertical == nil then biome.near_nodes_vertical = 1 end + + biome.spawn_plants_count = table.getn(biome.spawn_plants) + + plantslib:dbg("Registered spawning ABM:") + plantslib:dbg(dump(biome)) + plantslib:dbg("Number of trigger nodes in this ABM: "..biome.spawn_plants_count ) + minetest.register_abm({ - nodenames = { ssurface }, - interval = sdelay, - chance = schance, - neighbors = nneighbors, + nodenames = biome.spawn_surfaces, + interval = biome.spawn_delay, + chance = biome.spawn_chance, + neighbors = biome.neighbors, action = function(pos, node, active_object_count, active_object_count_wider) local p_top = { x = pos.x, y = pos.y + 1, z = pos.z } local n_top = minetest.env:get_node(p_top) - local perlin1 = minetest.env:get_perlin(seed_diff, perlin_octaves, perlin_persistence, perlin_scale) + local perlin1 = minetest.env:get_perlin(biome.seed_diff, perlin_octaves, perlin_persistence, perlin_scale) local perlin2 = minetest.env:get_perlin(temperature_seeddiff, temperature_octaves, temperature_persistence, temperature_scale) local noise1 = perlin1:get2d({x=p_top.x, y=p_top.z}) local noise2 = perlin2:get2d({x=p_top.x, y=p_top.z}) - if noise1 > plantlife_limit - and noise2 >= tempmin - and noise2 <= tempmax + if noise1 > biome.plantlife_limit + and noise2 <= biome.temp_min + and noise2 >= biome.temp_max and plantslib:is_node_loaded(p_top) then local n_light = minetest.env:get_node_light(p_top, nil) - if minetest.env:find_node_near(p_top, sradius + math.random(-1.5,2), savoid) == nil - and n_light >= lightmin - and n_light <= lightmax - and (table.getn(minetest.env:find_nodes_in_area({x=pos.x-1, y=pos.y, z=pos.z-1}, {x=pos.x+1, y=pos.y, z=pos.z+1}, nneighbors)) > ocount - or ocount == -1) - and (table.getn(minetest.env:find_nodes_in_area({x=pos.x-sbiomesize, y=pos.y-1, z=pos.z-sbiomesize}, {x=pos.x+sbiomesize, y=pos.y+1, z=pos.z+sbiomesize}, sbiome)) >= sbiomecount - or sbiome == "") - and table.getn(minetest.env:find_nodes_in_area({x=p_top.x-airsize, y=p_top.y, z=p_top.z-airsize}, {x=p_top.x+airsize, y=p_top.y, z=p_top.z+airsize}, "air")) >= aircount - and pos.y >= altmin - and pos.y <= altmax - then - local walldir = plantslib:plant_valid_wall(p_top) - if splant == "poisonivy:seedling" and walldir ~= nil then - plantslib:dbg("Spawn: poisonivy:climbing at "..dump(p_top).." on "..ssurface) - minetest.env:add_node(p_top, { name = "poisonivy:climbing", param2 = walldir }) - else - local deepnode = minetest.env:get_node({ x = pos.x, y = pos.y-depthmax-1, z = pos.z }).name - if (ssurface ~= "default:water_source") - or (ssurface == "default:water_source" - and deepnode ~= "default:water_source") then - plantslib:dbg("Spawn: "..splant.." at "..dump(p_top).." on "..ssurface) - minetest.env:add_node(p_top, { name = splant, param2 = facedir }) + if (not(biome.avoid_nodes and biome.avoid_radius) or minetest.env:find_node_near(p_top, biome.avoid_radius + math.random(-1.5,2), biome.avoid_nodes) == nil) + and n_light >= biome.light_min + and n_light <= biome.light_max + and (not(biome.neighbors and biome.ncount) or table.getn(minetest.env:find_nodes_in_area({x=pos.x-1, y=pos.y, z=pos.z-1}, {x=pos.x+1, y=pos.y, z=pos.z+1}, biome.neighbors)) > biome.ncount ) + and (not(biome.near_nodes and biome.near_nodes_count and biome.near_nodes_size) or table.getn(minetest.env:find_nodes_in_area({x=pos.x-biome.near_nodes_size, y=pos.y-biome.near_nodes_vertical, z=pos.z-biome.near_nodes_size}, {x=pos.x+biome.near_nodes_size, y=pos.y+biome.near_nodes_vertical, z=pos.z+biome.near_nodes_size}, biome.near_nodes)) >= biome.near_nodes_count) + and (not(biome.air_count and biome.air_size) or table.getn(minetest.env:find_nodes_in_area({x=p_top.x-biome.air_size, y=p_top.y, z=p_top.z-biome.air_size}, {x=p_top.x+biome.air_size, y=p_top.y, z=p_top.z+biome.air_size}, "air")) >= biome.air_count) + and pos.y >= biome.min_elevation + and pos.y <= biome.max_elevation + then + local walldir = plantslib:find_adjacent_wall(p_top, biome.verticals_list) + if biome.alt_wallnode and walldir then + if n_top.name == "air" then + plantslib:dbg("Spawn: "..biome.alt_wallnode.." on top of ("..dump(pos)..") against wall "..walldir) + minetest.env:add_node(p_top, { name = biome.alt_wallnode, param2 = walldir }) + end + else + local currentsurface = minetest.env:get_node(pos).name + if currentsurface ~= "default:water_source" + or (currentsurface == "default:water_source" and table.getn(minetest.env:find_nodes_in_area({x=pos.x, y=pos.y-biome.depth_max-1, z=pos.z}, {x=pos.x, y=pos.y, z=pos.z}, {"default:dirt", "default:dirt_with_grass", "default:sand"})) > 0 ) + then + local rnd = math.random(1, biome.spawn_plants_count) + local plant_to_spawn = biome.spawn_plants[rnd] + plantslib:dbg("Chose entry number "..rnd.." of "..biome.spawn_plants_count) + + if not biome.spawn_on_side and not biome.spawn_on_bottom then + local fdir = nil + if biome.random_facedir then + fdir = math.random(biome.random_facedir[1],biome.random_facedir[2]) + plantslib:dbg("Gave it a random facedir: "..fdir) + end + if n_top.name == "air" then + plantslib:dbg("Spawn: "..plant_to_spawn.." on top of ("..dump(pos)..")") + minetest.env:add_node(p_top, { name = plant_to_spawn, param2 = fdir }) + end + elseif biome.spawn_on_side then + local onside = plantslib:find_open_side(pos) + if onside then + plantslib:dbg("Spawn: "..plant_to_spawn.." at side of ("..dump(pos).."), facedir "..onside.facedir.."") + minetest.env:add_node(onside.newpos, { name = plant_to_spawn, param2 = onside.facedir }) + end + elseif biome.spawn_on_bottom then + if minetest.env:get_node({x=pos.x, y=pos.y-1, z=pos.z}).name == "air" then + local fdir = nil + if biome.random_facedir then + fdir = math.random(biome.random_facedir[1],biome.random_facedir[2]) + plantslib:dbg("Gave it a random facedir: "..fdir) + end + plantslib:dbg("Spawn: "..plant_to_spawn.." on bottom of ("..dump(pos)..")") + minetest.env:add_node({x=pos.x, y=pos.y-1, z=pos.z}, { name = plant_to_spawn, param2 = fdir} ) + end end end + end end end end @@ -213,134 +255,130 @@ end -- The growing ABM -function plantslib:grow_plants( - gdelay, - gchance, - gplant, - gresult, - dry_early_node, - grow_nodes, - facedir, - need_wall, - grow_vertically, - height_limit, - ground_nodes, - grow_function, - seed_diff) - if need_wall ~= true then need_wall = false end - if grow_vertically ~= true then grow_vertically = false end - if height_limit == nil then height_limit = 62000 end - if ground_nodes == nil then ground_nodes = { "default:dirt_with_grass" } end - if grow_nodes == nil then grow_nodes = { "default:dirt_with_grass" } end +function plantslib:grow_plants(opts) + + local options = opts + + if options.height_limit == nil then options.height_limit = 5 end + if options.ground_nodes == nil then options.ground_nodes = { "default:dirt_with_grass" } end + if options.grow_nodes == nil then options.grow_nodes = { "default:dirt_with_grass" } end + if options.seed_diff == nil then options.seed_diff = 0 end + + plantslib:dbg("Registered growing ABM:") + plantslib:dbg(dump(options)) + minetest.register_abm({ - nodenames = { gplant }, - interval = gdelay, - chance = gchance, + nodenames = { options.grow_plant }, + interval = options.grow_delay, + chance = options.grow_chance, action = function(pos, node, active_object_count, active_object_count_wider) local p_top = {x=pos.x, y=pos.y+1, z=pos.z} local p_bot = {x=pos.x, y=pos.y-1, z=pos.z} local n_top = minetest.env:get_node(p_top) local n_bot = minetest.env:get_node(p_bot) - local root_node = minetest.env:get_node({x=pos.x, y=pos.y-height_limit, z=pos.z}) - if string.find(dump(grow_nodes), n_bot.name) ~= nil and n_top.name == "air" then - if grow_function == nil then - if grow_vertically then - if plantslib:find_first_node(pos, height_limit, ground_nodes) ~= nil then - if need_wall then - local walldir=plantslib:plant_valid_wall(p_top) - if walldir ~= nil then - plantslib:dbg("Grow: "..gplant.." upwards to ("..dump(p_top)..") on wall "..walldir) - minetest.env:add_node(p_top, { name = gplant, param2 = walldir }) - end - else - plantslib:dbg("Grow: "..gplant.." upwards to ("..dump(p_top)..")") - minetest.env:add_node(p_top, { name = gplant }) - end - end + local root_node = minetest.env: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 ~= nil then + walldir = plantslib:find_adjacent_wall(p_top, options.verticals_list) + end + if n_top.name == "air" and (not options.need_wall or (options.need_wall and walldir)) + then + -- corner case for changing short junglegrass + -- to dry shrub in desert + if n_bot.name == options.dry_early_node and options.grow_plant == "junglegrass:short" then + plantslib:dbg("Die: "..options.grow_plant.." becomes default:dry_shrub at ("..dump(pos)..")") + minetest.env:add_node(pos, { name = "default:dry_shrub" }) - -- corner case for changing short junglegrass to dry shrub in desert - elseif n_bot.name == dry_early_node and gplant == "junglegrass:short" then - plantslib:dbg("Die: "..gplant.." becomes default:dry_shrub at ("..dump(pos)..")") - minetest.env:add_node(pos, { name = "default:dry_shrub" }) - - elseif gresult == nil then - plantslib:dbg("Die: "..gplant.." at ("..dump(pos)..")") - minetest.env:remove_node(pos) - - elseif gresult ~= nil then - plantslib:dbg("Grow: "..gplant.." becomes "..gresult.." at ("..dump(pos)..")") - if facedir == nil then - minetest.env:add_node(pos, { name = gresult }) - else - minetest.env:add_node(pos, { name = gresult, param2 = facedir }) - end + elseif options.grow_vertically and walldir then + if plantslib:search_downward(pos, options.height_limit, options.ground_nodes) then + plantslib:dbg("Grow "..options.grow_plant.." vertically to "..dump(p_top)) + minetest.env:add_node(p_top, { name = options.grow_plant, param2 = walldir}) end + + elseif options.grow_result == nil and options.grow_function == nil then + plantslib:dbg("Die: "..options.grow_plant.." at ("..dump(pos)..")") + minetest.env:remove_node(pos) + else - if seed_diff == nil then seed_diff = 0 end - local perlin1 = minetest.env:get_perlin(seed_diff, perlin_octaves, perlin_persistence, perlin_scale) - local perlin2 = minetest.env:get_perlin(temperature_seeddiff, temperature_octaves, temperature_persistence, temperature_scale) - local noise1 = perlin1:get2d({x=p_top.x, y=p_top.z}) - local noise2 = perlin2:get2d({x=p_top.x, y=p_top.z}) - if type(grow_function) == "table" then - plantslib:dbg("Grow sapling into tree at "..dump(pos)) - minetest.env:remove_node(pos) - minetest.env:spawn_tree(pos, grow_function) - else - plantslib:dbg("Call function: "..grow_function.."("..dump(pos)..","..noise1..","..noise2..")") - assert(loadstring(grow_function.."("..dump(pos)..","..noise1..","..noise2..")"))() - end + plantslib:replace_object(pos, options.grow_result, options.grow_function, options.facedir, options.seed_diff) end end end }) end +-- Function to decide how to replace a plant - either grow it, replace it with +-- a tree, run a function, or die with an error. + +function plantslib:replace_object(pos, replacement, grow_function, walldir, seeddiff) + local growtype = type(grow_function) + plantslib:dbg("replace_object called, growtype="..dump(grow_function)) + if growtype == "table" then + plantslib:dbg("Grow: spawn tree at "..dump(pos)) + minetest.env:remove_node(pos) + minetest.env:spawn_tree(pos, grow_function) + return + elseif growtype == "string" then + local perlin1 = minetest.env:get_perlin(seeddiff, perlin_octaves, perlin_persistence, perlin_scale) + local perlin2 = minetest.env:get_perlin(temperature_seeddiff, temperature_octaves, temperature_persistence, temperature_scale) + local noise1 = perlin1:get2d({x=pos.x, y=pos.z}) + local noise2 = perlin2:get2d({x=pos.x, y=pos.z}) + plantslib:dbg("Grow: call function "..grow_function.."("..dump(pos)..","..noise1..","..noise2..","..dump(walldir)..")") + assert(loadstring(grow_function.."("..dump(pos)..","..noise1..","..noise2..","..dump(walldir)..")"))() + return + elseif growtype == "nil" then + if walldir ~= nil then + plantslib:dbg("Grow: place "..replacement.." at ("..dump(pos)..") on wall "..walldir) + minetest.env:add_node(pos, { name = replacement, param2 = walldir}) + else + plantslib:dbg("Grow: place "..replacement.." at ("..dump(pos)..")") + minetest.env:add_node(pos, { name = replacement}) + end + return + elseif growtype ~= "nil" and growtype ~= "string" and growtype ~= "table" then + error("Invalid grow function "..dump(grow_function).." used on object at ("..dump(pos)..")") + end +end + -- function to decide if a node has a wall that's in verticals_list{} -- returns wall direction of valid node, or nil if invalid. -local verticals_list = { - "default:dirt", - "default:dirt_with_grass", - "default:stone", - "default:cobble", - "default:mossycobble", - "default:brick", - "default:tree", - "default:jungletree", - "default:coal", - "default:iron" -} - -function plantslib:plant_valid_wall(wallpos) - local walldir = nil - local verts = dump(verticals_list) - - local testpos = { x = wallpos.x-1, y = wallpos.y, z = wallpos.z } - if string.find(verts, minetest.env:get_node(testpos).name) ~= nil then walldir=3 end - - local testpos = { x = wallpos.x+1, y = wallpos.y, z = wallpos.z } - if string.find(verts, minetest.env:get_node(testpos).name) ~= nil then walldir=2 end - - local testpos = { x = wallpos.x , y = wallpos.y, z = wallpos.z-1 } - if string.find(verts, minetest.env:get_node(testpos).name) ~= nil then walldir=5 end - - local testpos = { x = wallpos.x , y = wallpos.y, z = wallpos.z+1 } - if string.find(verts, minetest.env:get_node(testpos).name) ~= nil then walldir=4 end - - return walldir +function plantslib:find_adjacent_wall(pos, verticals) + local verts = dump(verticals) + if string.find(verts, minetest.env:get_node({ x=pos.x-1, y=pos.y, z=pos.z }).name) then return 3 end + if string.find(verts, minetest.env:get_node({ x=pos.x+1, y=pos.y, z=pos.z }).name) then return 2 end + if string.find(verts, minetest.env:get_node({ x=pos.x , y=pos.y, z=pos.z-1 }).name) then return 5 end + if string.find(verts, minetest.env:get_node({ x=pos.x , y=pos.y, z=pos.z+1 }).name) then return 4 end + return nil end --- Function to search straight down from (pos) to find first node in match list. +-- Function to search downward from the given position, looking for the first +-- node that matches the ground table. Returns the new position, or nil if +-- height limit is exceeded before finding it. -function plantslib:find_first_node(pos, height_limit, nodelist) - for i = 1, height_limit do - n = minetest.env:get_node({x=pos.x, y=pos.y-i, z=pos.z}) - if string.find(dump(nodelist),n.name) ~= nil then - return n.name +function plantslib:search_downward(pos, heightlimit, ground) + for i = 0, heightlimit do + if string.find(dump(ground), minetest.env:get_node({x=pos.x, y=pos.y-i, z = pos.z}).name) then + return {x=pos.x, y=pos.y-i, z = pos.z} end end + return false +end + +function plantslib:find_open_side(pos) + if minetest.env:get_node({ x=pos.x-1, y=pos.y, z=pos.z }).name == "air" then + return {newpos = { x=pos.x-1, y=pos.y, z=pos.z }, facedir = 2} + end + if minetest.env:get_node({ x=pos.x+1, y=pos.y, z=pos.z }).name == "air" then + return {newpos = { x=pos.x+1, y=pos.y, z=pos.z }, facedir = 3} + end + if minetest.env:get_node({ x=pos.x, y=pos.y, z=pos.z-1 }).name == "air" then + return {newpos = { x=pos.x, y=pos.y, z=pos.z-1 }, facedir = 4} + end + if minetest.env:get_node({ x=pos.x, y=pos.y, z=pos.z+1 }).name == "air" then + return {newpos = { x=pos.x, y=pos.y, z=pos.z+1 }, facedir = 5} + end return nil end -print("[Plantlife] Loaded!") - +print("[Plantlife Library] Loaded") diff --git a/poinsonivy/init.lua b/poinsonivy/init.lua deleted file mode 100644 index 7a0386b..0000000 --- a/poinsonivy/init.lua +++ /dev/null @@ -1,57 +0,0 @@ --- This file supplies poison ivy for the plantlife modpack - -local spawn_delay = 2000 -- 2000 -local spawn_chance = 100 -- 100 -local grow_delay = 1000 -- 1000 -local grow_chance = 10 -- 10 -local poisonivy_seed_diff = plantslib.plantlife_seed_diff + 10 - -minetest.register_node(':poisonivy:seedling', { - description = "Poison ivy (seedling)", - drawtype = 'plantlike', - tile_images = { 'poisonivy_seedling.png' }, - inventory_image = 'poisonivy_seedling.png', - wield_image = 'poisonivy_seedling.png', - sunlight_propagates = true, - paramtype = 'light', - walkable = false, - groups = { snappy = 3, poisonivy=1 }, - sounds = default.node_sound_leaves_defaults(), -}) - -minetest.register_node(':poisonivy:sproutling', { - description = "Poison ivy (sproutling)", - drawtype = 'plantlike', - tile_images = { 'poisonivy_sproutling.png' }, - inventory_image = 'poisonivy_sproutling.png', - wield_image = 'poisonivy_sproutling.png', - sunlight_propagates = true, - paramtype = 'light', - walkable = false, - groups = { snappy = 3, poisonivy=1 }, - sounds = default.node_sound_leaves_defaults(), -}) - -minetest.register_node(':poisonivy:climbing', { - description = "Poison ivy (climbing plant)", - drawtype = 'signlike', - tile_images = { 'poisonivy_climbing.png' }, - inventory_image = 'poisonivy_climbing.png', - wield_image = 'poisonivy_climbing.png', - sunlight_propagates = true, - paramtype = 'light', - paramtype2 = 'wallmounted', - walkable = false, - groups = { snappy = 3, poisonivy=1 }, - sounds = default.node_sound_leaves_defaults(), - selection_box = { - type = "wallmounted", - --wall_side = = - }, -}) - -plantslib:spawn_on_surfaces(spawn_delay, "poisonivy:seedling", 10 , spawn_chance/10, "default:dirt_with_grass", {"group:poisonivy","group:flower"}, poisonivy_seed_diff, 7) - -plantslib:grow_plants(spawn_delay, grow_chance, "poisonivy:seedling", "poisonivy:sproutling", nil, {"default:dirt_with_grass"}) -plantslib:grow_plants(spawn_delay, grow_chance*2, "poisonivy:climbing", nil, nil, nil ,nil,true,true,nil,{"default:dirt_with_grass"}) - diff --git a/poinsonivy/depends.txt b/poisonivy/depends.txt similarity index 100% rename from poinsonivy/depends.txt rename to poisonivy/depends.txt diff --git a/poisonivy/init.lua b/poisonivy/init.lua new file mode 100644 index 0000000..dd8f218 --- /dev/null +++ b/poisonivy/init.lua @@ -0,0 +1,96 @@ +-- This file supplies poison ivy for the plantlife modpack +-- Last revision: 2013-01-24 + +local SPAWN_DELAY = 1000 +local SPAWN_CHANCE = 200 +local GROW_DELAY = 500 +local GROW_CHANCE = 30 +local poisonivy_seed_diff = 339 +local walls_list = { + "default:dirt", + "default:dirt_with_grass", + "default:stone", + "default:cobble", + "default:mossycobble", + "default:brick", + "default:tree", + "default:jungletree", + "default:coal", + "default:iron" +}, +minetest.register_node('poisonivy:seedling', { + description = "Poison ivy (seedling)", + drawtype = 'plantlike', + tile_images = { 'poisonivy_seedling.png' }, + inventory_image = 'poisonivy_seedling.png', + wield_image = 'poisonivy_seedling.png', + sunlight_propagates = true, + paramtype = 'light', + walkable = false, + groups = { snappy = 3, poisonivy=1 }, + sounds = default.node_sound_leaves_defaults(), +}) + +minetest.register_node('poisonivy:sproutling', { + description = "Poison ivy (sproutling)", + drawtype = 'plantlike', + tile_images = { 'poisonivy_sproutling.png' }, + inventory_image = 'poisonivy_sproutling.png', + wield_image = 'poisonivy_sproutling.png', + sunlight_propagates = true, + paramtype = 'light', + walkable = false, + groups = { snappy = 3, poisonivy=1 }, + sounds = default.node_sound_leaves_defaults(), +}) + +minetest.register_node('poisonivy:climbing', { + description = "Poison ivy (climbing plant)", + drawtype = 'signlike', + tile_images = { 'poisonivy_climbing.png' }, + inventory_image = 'poisonivy_climbing.png', + wield_image = 'poisonivy_climbing.png', + sunlight_propagates = true, + paramtype = 'light', + paramtype2 = 'wallmounted', + walkable = false, + groups = { snappy = 3, poisonivy=1 }, + sounds = default.node_sound_leaves_defaults(), + selection_box = { + type = "wallmounted", + --wall_side = = + }, +}) + +plantslib:spawn_on_surfaces({ + spawn_delay = SPAWN_DELAY, + spawn_plants = {"poisonivy:seedling"}, + avoid_radius = 10, + spawn_chance = SPAWN_CHANCE/10, + spawn_surfaces = {"default:dirt_with_grass"}, + avoid_nodes = {"group:poisonivy","group:flower"}, + seed_diff = poisonivy_seed_diff, + light_min = 7, + alt_wallnode = "poisonivy:climbing", + verticals_list = walls_list +}) + +plantslib:grow_plants({ + grow_delay = SPAWN_DELAY, + grow_chance = GROW_CHANCE, + grow_plant = "poisonivy:seedling", + grow_result = "poisonivy:sproutling", + grow_nodes = {"default:dirt_with_grass"} +}) + +plantslib:grow_plants({ + grow_delay = GROW_DELAY, + grow_chance = GROW_CHANCE*2, + grow_plant = "poisonivy:climbing", + need_wall = true, + grow_vertically = true, + verticals_list = walls_list, + ground_nodes = {"default:dirt_with_grass"} +}) + +print("[Poison Ivy] Loaded.") diff --git a/poinsonivy/textures/poisonivy_climbing.png b/poisonivy/textures/poisonivy_climbing.png similarity index 100% rename from poinsonivy/textures/poisonivy_climbing.png rename to poisonivy/textures/poisonivy_climbing.png diff --git a/poinsonivy/textures/poisonivy_seedling.png b/poisonivy/textures/poisonivy_seedling.png similarity index 100% rename from poinsonivy/textures/poisonivy_seedling.png rename to poisonivy/textures/poisonivy_seedling.png diff --git a/poinsonivy/textures/poisonivy_sproutling.png b/poisonivy/textures/poisonivy_sproutling.png similarity index 100% rename from poinsonivy/textures/poisonivy_sproutling.png rename to poisonivy/textures/poisonivy_sproutling.png