for hunger mod loaded error,fixed some mod's depedence.

master
LinusHsao 2016-07-09 09:57:31 +00:00
parent b868574c85
commit 0c85dcab10
166 changed files with 4486 additions and 1466 deletions

View File

@ -18,11 +18,11 @@ name = admin
enable_pvp = false
disable_tnt = true
disable_fire = true
enable_damage = true
#skyblock
skyblock.world_bottom_node = default:water_source
#added
disable_anticheat = true

View File

@ -17,11 +17,11 @@ name = admin
enable_pvp = false
disable_tnt = true
disable_fire = true
enable_damage = true
#skyblock
skyblock.world_bottom_node = default:water_source
#added
disable_anticheat = true

View File

@ -246,6 +246,4 @@ mobf_add_mob(npc_prototype)
minetest.log("action","MOD: mob_npc mod version " .. version .. " loaded")
--linus added
dofile (modpath .. "/npc_wasteland.lua")
dofile (modpath .. "/npc_skyisland.lua")
dofile (modpath .. "/npc_LOTR.lua")

View File

@ -1,250 +0,0 @@
-------------------------------------------------------------------------------
-- Mob Framework Mod by Sapier
--
-- You may copy, use, modify or do nearly anything except removing this
-- copyright notice.
-- And of course you are NOT allow to pretend you have written it.
--
--! @file init.lua
--! @brief npc implementation
--! @copyright Sapier
--! @author Sapier
--! @date 2013-01-27
--
-- Contact sapier a t gmx net
-------------------------------------------------------------------------------
-- Boilerplate to support localized strings if intllib mod is installed.
local S
if (minetest.get_modpath("intllib")) then
dofile(minetest.get_modpath("intllib").."/intllib.lua")
S = intllib.Getter(minetest.get_current_modname())
else
S = function ( s ) return s end
end
--minetest.log("action","MOD: mob_npc mod loading ...")
local version = "0.2.1"
local npc_groups = {
not_in_creative_inventory=1
}
local modpath = minetest.get_modpath("mob_npc")
--dofile (modpath .. "/spawn_building.lua")
--[[
local npc_prototype = {
name="npc",
modname="mob_npc",
factions = {
member = {
"npc",
}
},
generic = {
description="NPC",
base_health=40,
kill_result="",
armor_groups= {
fleshy=90,
},
groups = npc_groups,
envid="simple_air",
population_density=0,
},
movement = {
min_accel=0.3,
max_accel=0.7,
max_speed=1.5,
min_speed=0.01,
pattern="stop_and_go",
canfly=false,
},
states = {
{
name = "walking",
movgen = "probab_mov_gen",
typical_state_time = 180,
chance = 0.50,
animation = "walk",
},
{
name = "default",
movgen = "none",
typical_state_time = 180,
chance = 0.00,
animation = "stand",
graphics_3d = {
visual = "mesh",
mesh = "npc_character.b3d",
textures = {"zombie.png"},
collisionbox = {-0.3,-1.0,-0.3, 0.3,0.8,0.3},
visual_size= {x=1, y=1},
},
},
},
animation = {
walk = {
start_frame = 168,
end_frame = 187,
},
stand = {
start_frame = 0,
end_frame = 79,
},
},
}
--]]
local npc_trader_prototype = {
name="npc_trader_LOTR",
modname="mob_npc",
factions = {
member = {
"npc",
}
},
generic = {
description= S("Trader"),
base_health=200,
kill_result="",
armor_groups= {
fleshy=60,
},
groups = npc_groups,
envid="simple_air",
custom_on_activate_handler=mob_inventory.init_trader_inventory,
population_density=0,
},
movement = {
min_accel=0.3,
max_accel=0.7,
max_speed=1.5,
min_speed=0.01,
pattern="stop_and_go",
canfly=false,
},
states = {
{
name = "default",
movgen = "none",
chance = 0,
animation = "stand",
graphics = {
visual = "upright_sprite",
sprite_scale={x=1.5,y=2},
sprite_div = {x=1,y=1},
visible_height = 2,
visible_width = 1,
},
graphics_3d = {
visual = "mesh",
mesh = "npc_character.b3d",
textures = {"mob_npc_trader_mesh.png"},
collisionbox = {-0.3,-1.0,-0.3, 0.3,0.8,0.3},
visual_size= {x=1, y=1},
},
},
},
animation = {
walk = {
start_frame = 168,
end_frame = 187,
},
stand = {
start_frame = 0,
end_frame = 79,
},
},
attention = {
hear_distance = 3,
hear_distance_value = 0.5,
view_angle = nil,
own_view_value = 0,
remote_view = false,
remote_view_value = 0,
attention_distance_value = 0.2,
watch_threshold = 2,
attack_threshold = nil,
attention_distance = 7.5,
attention_max = 10,
},
sound = {
inventory_open = {
name="mob_npc_letstrade",
gain = 0.75,
max_hear_distance = 5,
}
},
trader_inventory = {
goods = {
-- { "currency:minegeld 10", "default:coal_lump 5","default:cobble 30"},
{ "markers:mark 4","","bitchange:minecoin 10"},
{ "currency:shop 1", "", "bitchange:minecoin 10"},
-- { "bags:small 1", "", "bitchange:minecoin 1"},
{ "mapit:maptool 1", "", "bitchange:minecoin 15"},
{ "animalmaterials:fur 1", "", "bitchange:mineninth 2"},
{ "animalmaterials:fur_deer 1", "", "bitchange:mineninth 4"},
-- { "default:mese_crystal 1", "", "bitchange:minecoin 10"},
{ "default:chest_locked 1", "", "bitchange:minecoin 2"},
-- { "gemalde:node_1 1","","bitchange:minecoin 1"},
-- { "default:obsidian 1","","bitchange:minecoin 3"},
-- { "farming:cotton 5","animalmaterials:fur 2","bitchange:mineninth 4"},
{ "default:torch 2","","bitchange:mineninth 2"},
{ "default:apple 2","","bitchange:mineninth 2"},
-- { "animalmaterials:egg 3","","bitchange:mineninth 1"},
{ "farming:bread 1","","bitchange:mineninth 1"},
-- { "mobs:meat_raw 1","","bitchange:mineninth 1"},
},
random_names = { "Hans","Franz","Xaver","Fritz","Thomas","Martin"},
}
}
--[[
mobf_spawner_register("npc_trader_spawner_1",
npc_trader_prototype.modname .. ":" .. npc_trader_prototype.name,
{
spawnee = building_spawner.spawnfunc,
spawn_interval = 120,
spawn_inside = { "air" },
absolute_height =
{
min = 0,
},
mapgen =
{
enabled = true,
retries = 20,
spawntotal = 1,
},
light_around =
{
{ type="TIMED_MIN", distance = 0, threshold=LIGHT_MAX +1,time=0.5 },
},
cyclic_spawning = false,
custom_check = building_spawner.spawn_check,
})
--]]
--register with animals mod
minetest.log("action","\tadding mob "..npc_trader_prototype.name)
mobf_add_mob(npc_trader_prototype)
--[[
minetest.log("action","\tadding mob "..npc_prototype.name)
mobf_add_mob(npc_prototype)
minetest.log("action","MOD: mob_npc mod version " .. version .. " loaded")
--]]

View File

@ -1,250 +0,0 @@
-------------------------------------------------------------------------------
-- Mob Framework Mod by Sapier
--
-- You may copy, use, modify or do nearly anything except removing this
-- copyright notice.
-- And of course you are NOT allow to pretend you have written it.
--
--! @file init.lua
--! @brief npc implementation
--! @copyright Sapier
--! @author Sapier
--! @date 2013-01-27
--
-- Contact sapier a t gmx net
-------------------------------------------------------------------------------
-- Boilerplate to support localized strings if intllib mod is installed.
local S
if (minetest.get_modpath("intllib")) then
dofile(minetest.get_modpath("intllib").."/intllib.lua")
S = intllib.Getter(minetest.get_current_modname())
else
S = function ( s ) return s end
end
--minetest.log("action","MOD: mob_npc mod loading ...")
local version = "0.2.1"
local npc_groups = {
not_in_creative_inventory=1
}
local modpath = minetest.get_modpath("mob_npc")
--dofile (modpath .. "/spawn_building.lua")
--[[
local npc_prototype = {
name="npc",
modname="mob_npc",
factions = {
member = {
"npc",
}
},
generic = {
description="NPC",
base_health=40,
kill_result="",
armor_groups= {
fleshy=90,
},
groups = npc_groups,
envid="simple_air",
population_density=0,
},
movement = {
min_accel=0.3,
max_accel=0.7,
max_speed=1.5,
min_speed=0.01,
pattern="stop_and_go",
canfly=false,
},
states = {
{
name = "walking",
movgen = "probab_mov_gen",
typical_state_time = 180,
chance = 0.50,
animation = "walk",
},
{
name = "default",
movgen = "none",
typical_state_time = 180,
chance = 0.00,
animation = "stand",
graphics_3d = {
visual = "mesh",
mesh = "npc_character.b3d",
textures = {"zombie.png"},
collisionbox = {-0.3,-1.0,-0.3, 0.3,0.8,0.3},
visual_size= {x=1, y=1},
},
},
},
animation = {
walk = {
start_frame = 168,
end_frame = 187,
},
stand = {
start_frame = 0,
end_frame = 79,
},
},
}
--]]
local npc_trader_prototype = {
name="npc_trader_wasteland",
modname="mob_npc",
factions = {
member = {
"npc",
}
},
generic = {
description= S("Trader"),
base_health=200,
kill_result="",
armor_groups= {
fleshy=60,
},
groups = npc_groups,
envid="simple_air",
custom_on_activate_handler=mob_inventory.init_trader_inventory,
population_density=0,
},
movement = {
min_accel=0.3,
max_accel=0.7,
max_speed=1.5,
min_speed=0.01,
pattern="stop_and_go",
canfly=false,
},
states = {
{
name = "default",
movgen = "none",
chance = 0,
animation = "stand",
graphics = {
visual = "upright_sprite",
sprite_scale={x=1.5,y=2},
sprite_div = {x=1,y=1},
visible_height = 2,
visible_width = 1,
},
graphics_3d = {
visual = "mesh",
mesh = "npc_character.b3d",
textures = {"mob_npc_trader_mesh.png"},
collisionbox = {-0.3,-1.0,-0.3, 0.3,0.8,0.3},
visual_size= {x=1, y=1},
},
},
},
animation = {
walk = {
start_frame = 168,
end_frame = 187,
},
stand = {
start_frame = 0,
end_frame = 79,
},
},
attention = {
hear_distance = 3,
hear_distance_value = 0.5,
view_angle = nil,
own_view_value = 0,
remote_view = false,
remote_view_value = 0,
attention_distance_value = 0.2,
watch_threshold = 2,
attack_threshold = nil,
attention_distance = 7.5,
attention_max = 10,
},
sound = {
inventory_open = {
name="mob_npc_letstrade",
gain = 0.75,
max_hear_distance = 5,
}
},
trader_inventory = {
goods = {
{ "markers:mark 4","","bitchange:minecoin 10"},
{ "protector:protect","","bitchange:minecoin 7"},
{ "currency:shop 1", "", "bitchange:minecoin 10"},
{ "bags:small 1", "", "bitchange:minecoin 1"},
{ "mapit:maptool 1", "", "bitchange:minecoin 15"},
{ "animalmaterials:fur 1", "", "bitchange:mineninth 2"},
{ "animalmaterials:fur_deer 1", "", "bitchange:mineninth 4"},
-- { "default:mese_crystal 1", "", "bitchange:minecoin 10"},
{ "default:chest_locked 1", "", "bitchange:minecoin 2"},
-- { "gemalde:node_1 1","","bitchange:minecoin 1"},
-- { "default:obsidian 1","","bitchange:minecoin 3"},
-- { "farming:cotton 5","animalmaterials:fur 2","bitchange:mineninth 4"},
{ "default:torch 2","","bitchange:mineninth 2"},
{ "default:apple 2","","bitchange:mineninth 2"},
-- { "animalmaterials:egg 3","","bitchange:mineninth 1"},
{ "farming:bread 1","","bitchange:mineninth 1"},
-- { "mobs:meat_raw 1","","bitchange:mineninth 1"},
},
random_names = { "Hans","Franz","Xaver","Fritz","Thomas","Martin"},
}
}
--[[
mobf_spawner_register("npc_trader_spawner_1",
npc_trader_prototype.modname .. ":" .. npc_trader_prototype.name,
{
spawnee = building_spawner.spawnfunc,
spawn_interval = 120,
spawn_inside = { "air" },
absolute_height =
{
min = 0,
},
mapgen =
{
enabled = true,
retries = 20,
spawntotal = 1,
},
light_around =
{
{ type="TIMED_MIN", distance = 0, threshold=LIGHT_MAX +1,time=0.5 },
},
cyclic_spawning = false,
custom_check = building_spawner.spawn_check,
})
--]]
--register with animals mod
minetest.log("action","\tadding mob "..npc_trader_prototype.name)
mobf_add_mob(npc_trader_prototype)
--[[
minetest.log("action","\tadding mob "..npc_prototype.name)
mobf_add_mob(npc_prototype)
minetest.log("action","MOD: mob_npc mod version " .. version .. " loaded")
--]]

View File

@ -1 +1 @@
inventory_plus
inventory_plus_linus

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

@ -0,0 +1,579 @@
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.
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 = {
grow_plant = "string", -- Name of the node to be grown into something
-- else. This value is passed to the ABM as the
-- "nodenames" parameter, so it is the plants
-- themselves that are the ABM trigger, rather than
-- the ground they spawned on. A plant will only grow
-- if the node above it is air. Can also be a table,
-- but note that all nodes referenced therein will be
-- grown into the same object.
grow_delay = num, -- Passed as the ABM "interval" parameter, as with
-- spawning.
grow_chance = num, -- Passed as the ABM "chance" parameter.
grow_result = "string", -- Name of the node into which the grow_plant
-- node(s) should transform when the ABM executes.
---- Everything from here down is optional.
dry_early_node = "string", -- This value is ignored except for jungle
-- grass (a corner case needed by that mod), where it
-- indicates which node the grass must be on in order
-- for it to turn from the short size to
-- "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
======================
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)

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

@ -0,0 +1,30 @@
# 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)
**License**: WTFPL
**API**: This mod supplies a small number of very powerful functions. They are, briefly:
* biome_lib:register_generate_plant()
* biome_lib:spawn_on_surfaces()
* biome_lib:grow_plants()
* biome_lib:find_valid_wall()
* biome_lib:is_node_loaded()
For a complete description of these functions as well as several of the internal variables within the mod, [read the API.txt document](https://raw.githubusercontent.com/minetest-mods/biome_lib/master/API.txt) included in this package.

View File

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

View File

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

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

@ -0,0 +1,737 @@
-- Plantlife library mod by Vanessa Ezekowitz
--
-- License: WTFPL
--
-- 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 = {}
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
-- Boilerplate to support localized strings if intllib mod is installed.
local S
if minetest.get_modpath("intllib") then
S = intllib.Getter()
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.setting_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
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 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 = snodes[i]
local p_top = { x = pos.x, y = pos.y + 1, z = pos.z }
local noise1 = perlin_fertile_area:get2d({x=pos.x, y=pos.z})
local noise2 = biome_lib.perlin_temperature:get2d({x=pos.x, y=pos.z})
local noise3 = biome_lib.perlin_humidity:get2d({x=pos.x+150, y=pos.z+50})
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 surface_ok
and (not checkair or minetest.get_node(p_top).name == "air")
and pos.y >= biome.min_elevation
and pos.y <= biome.max_elevation
and noise1 > biome.plantlife_limit
and noise2 <= biome.temp_min
and noise2 >= biome.temp_max
and noise3 <= biome.humidity_min
and noise3 >= biome.humidity_max
and (not biome.ncount or #(minetest.find_nodes_in_area({x=pos.x-1, y=pos.y, z=pos.z-1}, {x=pos.x+1, y=pos.y, z=pos.z+1}, biome.neighbors)) > biome.ncount)
and (not biome.near_nodes or #(minetest.find_nodes_in_area({x=pos.x-biome.near_nodes_size, y=pos.y-biome.near_nodes_vertical, z=pos.z-biome.near_nodes_size}, {x=pos.x+biome.near_nodes_size, y=pos.y+biome.near_nodes_vertical, z=pos.z+biome.near_nodes_size}, biome.near_nodes)) >= biome.near_nodes_count)
and math.random(1,100) > biome.rarity
and (not biome.below_nodes or string.find(dump(biome.below_nodes), minetest.get_node({x=pos.x, y=pos.y-1, z=pos.z}).name) )
then
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
for i = 1, math.min(biome.max_count, num_in_biome_nodes) do
local tries = 0
local spawned = false
while tries < 2 and not spawned do
local pos = in_biome_nodes[math.random(1, num_in_biome_nodes)]
if biome.spawn_replace_node then
pos.y = pos.y-1
end
local p_top = { x = pos.x, y = pos.y + 1, z = pos.z }
if not (biome.avoid_nodes and biome.avoid_radius and minetest.find_node_near(p_top, biome.avoid_radius + math.random(-1.5,2), biome.avoid_nodes)) then
if biome.delete_above then
minetest.remove_node(p_top)
minetest.remove_node({x=p_top.x, y=p_top.y+1, z=p_top.z})
end
if biome.delete_above_surround then
minetest.remove_node({x=p_top.x-1, y=p_top.y, z=p_top.z})
minetest.remove_node({x=p_top.x+1, y=p_top.y, z=p_top.z})
minetest.remove_node({x=p_top.x, y=p_top.y, z=p_top.z-1})
minetest.remove_node({x=p_top.x, y=p_top.y, z=p_top.z+1})
minetest.remove_node({x=p_top.x-1, y=p_top.y+1, z=p_top.z})
minetest.remove_node({x=p_top.x+1, y=p_top.y+1, z=p_top.z})
minetest.remove_node({x=p_top.x, y=p_top.y+1, z=p_top.z-1})
minetest.remove_node({x=p_top.x, y=p_top.y+1, z=p_top.z+1})
end
if biome.spawn_replace_node then
minetest.remove_node(pos)
end
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.set_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.set_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
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
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
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
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
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 }
end)
minetest.register_on_generated(function(minp, maxp, blockseed)
biome_lib.blocklist_no_aircheck[#biome_lib.blocklist_no_aircheck + 1] = { minp, maxp }
end)
-- "Play" them back, populating them with new stuff in the process
minetest.register_globalstep(function(dtime)
if dtime < 0.2 and -- don't attempt to populate if lag is already too high
(#biome_lib.blocklist_aircheck > 0 or #biome_lib.blocklist_no_aircheck > 0) then
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
end)
-- Play out the entire log all at once on shutdown
-- to prevent unpopulated map areas
minetest.register_on_shutdown(function()
print("[biome_lib] Stand by, playing out the rest of the aircheck mapblock log")
print("(there are "..#biome_lib.blocklist_aircheck.." entries)...")
while true do
biome_lib:generate_block_with_air_checking(0.1)
if #biome_lib.blocklist_aircheck == 0 then return end
end
end)
minetest.register_on_shutdown(function()
print("[biome_lib] Stand by, playing out the rest of the no-aircheck mapblock log")
print("(there are "..#biome_lib.blocklist_aircheck.." entries)...")
while true do
biome_lib:generate_block_no_aircheck(0.1)
if #biome_lib.blocklist_no_aircheck == 0 then return end
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)
minetest.register_abm({
nodenames = biome.spawn_surfaces,
interval = biome.interval,
chance = biome.spawn_chance,
neighbors = biome.neighbors,
action = function(pos, node, active_object_count, active_object_count_wider)
local p_top = { x = pos.x, y = pos.y + 1, z = pos.z }
local n_top = minetest.get_node(p_top)
local perlin_fertile_area = minetest.get_perlin(biome.seed_diff, perlin_octaves, perlin_persistence, perlin_scale)
local noise1 = perlin_fertile_area:get2d({x=p_top.x, y=p_top.z})
local noise2 = biome_lib.perlin_temperature:get2d({x=p_top.x, y=p_top.z})
local noise3 = biome_lib.perlin_humidity:get2d({x=p_top.x+150, y=p_top.z+50})
if noise1 > biome.plantlife_limit
and noise2 <= biome.temp_min
and noise2 >= biome.temp_max
and noise3 <= biome.humidity_min
and noise3 >= biome.humidity_max
and biome_lib:is_node_loaded(p_top) then
local n_light = minetest.get_node_light(p_top, nil)
if not (biome.avoid_nodes and biome.avoid_radius and minetest.find_node_near(p_top, biome.avoid_radius + math.random(-1.5,2), biome.avoid_nodes))
and n_light >= biome.light_min
and n_light <= biome.light_max
and (not(biome.neighbors and biome.ncount) or #(minetest.find_nodes_in_area({x=pos.x-1, y=pos.y, z=pos.z-1}, {x=pos.x+1, y=pos.y, z=pos.z+1}, biome.neighbors)) > biome.ncount )
and (not(biome.near_nodes and biome.near_nodes_count and biome.near_nodes_size) or #(minetest.find_nodes_in_area({x=pos.x-biome.near_nodes_size, y=pos.y-biome.near_nodes_vertical, z=pos.z-biome.near_nodes_size}, {x=pos.x+biome.near_nodes_size, y=pos.y+biome.near_nodes_vertical, z=pos.z+biome.near_nodes_size}, biome.near_nodes)) >= biome.near_nodes_count)
and (not(biome.air_count and biome.air_size) or #(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)
and pos.y >= biome.min_elevation
and pos.y <= biome.max_elevation
then
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.set_node(p_top, { name = biome.alt_wallnode, param2 = walldir })
end
else
local currentsurface = minetest.get_node(pos).name
if currentsurface ~= "default:water_source"
or (currentsurface == "default:water_source" and #(minetest.find_nodes_in_area({x=pos.x, y=pos.y-biome.depth_max-1, z=pos.z}, {x=pos.x, y=pos.y, z=pos.z}, {"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]
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.set_node(p_top, { name = plant_to_spawn, param2 = fdir })
end
elseif biome.spawn_replace_node then
minetest.set_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.set_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.set_node({x=pos.x, y=pos.y-1, z=pos.z}, { name = plant_to_spawn, param2 = fdir} )
end
end
end
end
end
end
end
})
end
-- The growing ABM
function 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
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,
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
-- 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
minetest.set_node(pos, { name = "default:dry_shrub" })
elseif options.grow_vertically and walldir then
if biome_lib:search_downward(pos, options.height_limit, options.ground_nodes) then
minetest.set_node(p_top, { name = options.grow_plant, param2 = walldir})
end
elseif not options.grow_result and not options.grow_function then
minetest.remove_node(pos)
else
biome_lib: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 biome_lib:replace_object(pos, replacement, grow_function, walldir, seeddiff)
local growtype = type(grow_function)
if growtype == "table" then
minetest.remove_node(pos)
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 noise1 = perlin_fertile_area:get2d({x=pos.x, y=pos.z})
local noise2 = biome_lib.perlin_temperature:get2d({x=pos.x, y=pos.z})
grow_function(pos,noise1,noise2,walldir)
return
elseif growtype == "string" then
local perlin_fertile_area = minetest.get_perlin(seeddiff, perlin_octaves, perlin_persistence, perlin_scale)
local noise1 = perlin_fertile_area:get2d({x=pos.x, y=pos.z})
local noise2 = biome_lib.perlin_temperature:get2d({x=pos.x, y=pos.z})
assert(loadstring(grow_function.."(...)"))(pos,noise1,noise2,walldir)
return
elseif growtype == "nil" then
minetest.set_node(pos, { name = replacement, param2 = walldir})
return
elseif growtype ~= "nil" and growtype ~= "string" and growtype ~= "table" then
error("Invalid grow function "..dump(grow_function).." used on object at ("..dump(pos)..")")
end
end
-- function to decide if a node has a wall that's in verticals_list{}
-- returns wall direction of valid node, or nil if invalid.
function 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
-- 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
-- Check for infinite stacks
if minetest.get_modpath("unified_inventory") or not minetest.setting_getbool("creative_mode") then
biome_lib.expect_infinite_stacks = false
else
biome_lib.expect_infinite_stacks = true
end
-- read a field from a node's definition
function biome_lib:get_nodedef_field(nodename, fieldname)
if not minetest.registered_nodes[nodename] then
return nil
end
return minetest.registered_nodes[nodename][fieldname]
end
print("[Biome Lib] Loaded")
minetest.after(0, function()
print("[Biome Lib] Registered a total of "..(#biome_lib.surfaceslist_aircheck)+(#biome_lib.surfaceslist_no_aircheck).." surface types to be evaluated, spread")
print("[Biome Lib] across "..#biome_lib.actionslist_aircheck.." actions with air-checking and "..#biome_lib.actionslist_no_aircheck.." actions without.")
end)

View File

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

View File

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

View File

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

View File

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

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

@ -0,0 +1 @@
name = biome_lib

54
mods/hud_hunger/API.txt Normal file
View File

@ -0,0 +1,54 @@
HUD API
=======
hud.register(name, def)
-- name: statbar name (health, air, hunger, armor already used by default)
-- def: <HUD item definition> (see below)
hud.change_item(player, name, def)
-- player: player object
-- name: statbar name
-- def: table containing new values
-- currently supported: number, text and offset
hud.swap_statbar(player, name1, name2) -- swaps position and offset of statbar with name1 with statbar with name2
-- player: player object
-- name1: statbar name
-- name2: statbar name
hud.remove_item(player, name)
HUD item definition
{
hud_elem_type = "statbar", -- currently only supported type (same as in lua-api.txt)
position = {x=<x>, y=<y>}, -- position of statbar (same as in lua-api.txt)
size = {x=24, y=24}, -- statbar texture size (default 24x24), needed to be scaled correctly
text = "hud_heart_fg.png", -- texture name (same as in lua-api.txt)
number = 20, -- number/2 = number of full textures(e.g. hearts)
max = 20, -- used to prevent "overflow" of statbars
alignment = {x=-1,y=-1}, -- alignment on screen (same as in lua-api.txt)
offset = HUD_HEALTH_OFFSET,
background = "hud_heart_bg.png", -- statbar background texture name
autohide_bg = false, -- hide statbar background textures when number = 0
events = { -- called on events "damage" and "breath_changed" of players
{
type = "damage",
func = function(player)
-- do something here
end
}
},
}
HUNGER API
==========
-- Register food with given values to change eating actions
hunger.register_food(name, saturation, replace_with_item, poisen, heal, sound)
-- name: item name, e.g. "default:apple"
-- saturation: amount of added saturation
-- replace_with_item: item name that get returned after eating (can be nil)
-- poisen: duration in seconds (1hp damage per second, player can't die) (can be nil)
-- heal: added HP when eating this food (can be nil)
-- sound: costum eating sound (replaces default eating sound) (can be nil)

502
mods/hud_hunger/LICENSE.txt Normal file
View File

@ -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.
<one line to give the library's name and a brief idea of what it does.>
Copyright (C) <year> <name of author>
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.
<signature of Ty Coon>, 1 April 1990
Ty Coon, President of Vice
That's all there is to it!

105
mods/hud_hunger/README.txt Normal file
View File

@ -0,0 +1,105 @@
Modpack "Better HUD and hunger"
===============================
ModPack-Version: 2.x.1
Copyright (c) 2013-2016 BlockMen <blockmen2015@gmail.com>
About this mod:
~~~~~~~~~~~~~~~
This Modpack includes two mods, "Better HUD" (hud) and "Hunger"(hunger).
HUD:
The hud mod improves the HUD of Minetest and adds statbars for Hunger and Armor (hidden by default).
Also it provides an API to add new statbars easily, see API.txt for more informations.
Changes in builtin HUD items:
- Adds background for Health bar
- Uses better textures for Hotbar
- Uses texture for crosshair
- Positions of builtin statbars can be changed via "hud.conf" file
- Experimental "ItemWheel" that replaces the hotbar (must be enabled by adding "hud_item_wheel = true" in minetest.conf)
This mod supports the 3d_armor mod by stu (https://github.com/stujones11/minetest-3d_armor)
Hunger:
The hunger mod adds hunger mechanics to Minetest, which are based on player actions and on time.
Also it changes the eating in Minetest, e.g. an Apple does not restore Health, but it rises your saturation.
Example: 1 apple fills up the hunger bar by 1 "bread" (statbar symbol).
Although the statbar show 20 hunger points (10 breads) on the HUD you can fill it up to 30 points.
By default it supports a lot of food already (see full list below) and food that for registered via the API.
For more information how to register more food see API.txt
License:
~~~~~~~~
(c) Copyright BlockMen (2013-2016)
Code:
Licensed under the GNU LGPL version 2.1 or higher.
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;
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
See LICENSE.txt and http://www.gnu.org/licenses/lgpl-2.1.txt
Textures:
see README.txt in each submodule
Github:
~~~~~~~
https://github.com/BlockMen/hud_hunger
Forum:
~~~~~~
https://forum.minetest.net/viewtopic.php?id=6342
Changelog:
~~~~~~~~~~
see changelog.txt in each submodule
Dependencies (hunger):
~~~~~~~~~~~~~
- default
- farming
- flowers
- hud
Supported food/mods:
~~~~~~~~~~~~~~~~~~~~
- Apples (default)
- Animalmaterials (mobf modpack)
- Bread (default)
- Bushes
- bushes_classic
- Creatures
- Dwarves (beer and such)
- Docfarming
- Fishing
- Farming plus
- Farming (default and Tenplus1's fork)
- Food
- fruit
- Glooptest
- JKMod
- kpgmobs
- Mobfcooking
- Mooretrees
- Mtfoods
- mushroom
- mush45
- Seaplants (sea)
- Simple mobs

Binary file not shown.

View File

@ -1,13 +1,18 @@
function hud.register(name, def)
hud.register(name, def)
-- name: statbar name (health, air, hunger, armor already used by default)
-- def: <HUD item definition> (see below)
hud.change_item(player, name, def)
-- player: player object
-- name: statbar name (health, air, hunger, armor already used by default)
-- name: statbar name
-- def: table containing new values
-- currently supported: number, text and offset
hud.swap_statbar(player, name1, name2) -- swaps position and offset of statbar with name1 with statbar with name2
-- player: player object
-- name1: statbar name
-- name2: statbar name
hud.remove_item(player, name)
HUD item definition

View File

@ -1,8 +1,8 @@
Minetest mod "Better HUD"
=========================
Version: 2.1.2
Version: 2.1.5
(c) Copyright BlockMen (2013-2015)
(c) Copyright BlockMen (2013-2016)
About this mod:
@ -26,7 +26,7 @@ This mod supports the 3d_armor mod by stu (https://github.com/stujones11/minetes
License:
~~~~~~~~
(c) Copyright BlockMen (2013-2015)
(c) Copyright BlockMen (2013-2016)
Code:

View File

@ -66,6 +66,59 @@ function hud.register(name, def)
return true
end
-- swaps stabar positions
function hud.swap_statbar(player, item1, item2)
if not player or not item1 or not item2 then
throw_error("Not enough parameters given to swap statbars")
return false
end
local def1 = items[item1] or nil
local def2 = items[item2] or nil
if not def1 or not def2 then
throw_error("Can't swap statbars. Given statbars are not correct")
return false
end
local pos_swap = false
local p_name = player:get_player_name()
local elem1 = hud_id[p_name.."_"..item1]
local elem2 = hud_id[p_name.."_"..item2]
if not elem1 or not elem2 or not elem1.id or not elem2.id then
return false
end
player:hud_change(elem2.id, "offset", def1.offset)
player:hud_change(elem1.id, "offset", def2.offset)
if def1.position.x ~= def2.position.x or def1.position.y ~= def2.position.y then
player:hud_change(elem2.id, "position", def1.position)
player:hud_change(elem1.id, "position", def2.position)
pos_swap = true
end
-- do the items have backgrounds? if so, swap them aswell
local bg1 = hud_id[p_name.."_"..item1.."_bg"] or nil
local bg2 = hud_id[p_name.."_"..item2.."_bg"] or nil
if bg1 ~= nil and bg1.id then
player:hud_change(bg1.id, "offset", def2.offset)
if pos_swap == true then
player:hud_change(bg1.id, "position", def2.position)
end
end
if bg2 ~= nil and bg2.id then
player:hud_change(bg2.id, "offset", def1.offset)
if pos_swap == true then
player:hud_change(bg2.id, "position", def1.position)
end
end
return true
end
function hud.change_item(player, name, def)
if not player or not player:is_player() or not name or not def then
throw_error("Not enough parameters given to change HUD item")
@ -106,6 +159,7 @@ function hud.change_item(player, name, def)
if bg and bg.max and bg.max < 1 and def.max and def.max > bg.max then
player:hud_change(bg.id, "number", def.max)
bg.max = def.max
bg.number = def.max
end
end
end
@ -119,27 +173,9 @@ function hud.change_item(player, name, def)
if def.offset and elem.offset then
if def.item_name and def.offset == "item" then
local i_name2 = player:get_player_name().."_"..def.item_name
local elem2 = hud_id[i_name2]
if elem2 then
local p2 = elem2.offset
local p1 = elem.offset
player:hud_change(elem2.id, "offset", p1)
player:hud_change(elem.id, "offset", p2)
elem2.offset = p1
elem.offset = p2
if elem.background then
local elem3 = hud_id[i_name.."_bg"]
if elem3 and elem3.offset then
player:hud_change(elem3.id, "offset", p2)
elem3.offset = p2
local elem4 = hud_id[i_name2.."_bg"]
if elem4 and elem4.offset then
player:hud_change(elem4.id, "offset", p1)
elem4.offset = p1
end
end
end
-- for legacy reasons
if def.item_name then
hud.swap_statbar(player, name, def.item_name)
end
else
player:hud_change(elem.id, "offset", def.offset)
@ -190,7 +226,7 @@ minetest.register_on_joinplayer(function(player)
hud_flags.breathbar = false
player:hud_set_flags(hud_flags)
-- now add the backgrounds (e.g. for statbars)
-- now add the backgrounds for statbars
for _,item in pairs(sb_bg) do
add_hud_item(player, _.."_bg", item)
end

View File

@ -42,73 +42,72 @@ if (enable_hunger == true or HUD_ENABLE_HUNGER == true) and not hud.show_hunger
hud.notify_hunger(5)
end
damage_enable = true
if damage_enabled then
if damage_enabled then
hud.register("health", {
hud_elem_type = "statbar",
position = HUD_HEALTH_POS,
size = HUD_SB_SIZE,
text = "hud_heart_fg.png",
number = 20,
alignment = {x = -1, y = -1},
offset = HUD_HEALTH_OFFSET,
background = "hud_heart_bg.png",
events = {
{
type = "damage",
func = function(player)
hud.change_item(player, "health", {number = player:get_hp()})
end
}
},
hud_elem_type = "statbar",
position = HUD_HEALTH_POS,
size = HUD_SB_SIZE,
text = "hud_heart_fg.png",
number = 20,
alignment = {x = -1, y = -1},
offset = HUD_HEALTH_OFFSET,
background = "hud_heart_bg.png",
events = {
{
type = "damage",
func = function(player)
hud.change_item(player, "health", {number = player:get_hp()})
end
}
},
})
hud.register("air", {
hud_elem_type = "statbar",
position = HUD_AIR_POS,
size = HUD_SB_SIZE,
text = "hud_air_fg.png",
number = 0,
alignment = {x = -1, y = -1},
offset = HUD_AIR_OFFSET,
background = nil,
events = {
{
type = "breath",
func = function(player)
local air = player:get_breath()
if air > 10 then
air = 0
hud_elem_type = "statbar",
position = HUD_AIR_POS,
size = HUD_SB_SIZE,
text = "hud_air_fg.png",
number = 0,
alignment = {x = -1, y = -1},
offset = HUD_AIR_OFFSET,
background = nil,
events = {
{
type = "breath",
func = function(player)
local air = player:get_breath()
if air > 10 then
air = 0
end
hud.change_item(player, "air", {number = air * 2})
end
hud.change_item(player, "air", {number = air * 2})
end
}
},
}
},
})
hud.register("armor", {
hud_elem_type = "statbar",
position = HUD_ARMOR_POS,
size = HUD_SB_SIZE,
text = "hud_armor_fg.png",
number = 0,
alignment = {x = -1, y = -1},
offset = HUD_ARMOR_OFFSET,
background = "hud_armor_bg.png",
autohide_bg = true,
max = 20,
hud_elem_type = "statbar",
position = HUD_ARMOR_POS,
size = HUD_SB_SIZE,
text = "hud_armor_fg.png",
number = 0,
alignment = {x = -1, y = -1},
offset = HUD_ARMOR_OFFSET,
background = "hud_armor_bg.png",
autohide_bg = true,
max = 20,
})
hud.register("hunger", {
hud_elem_type = "statbar",
position = HUD_HUNGER_POS,
size = HUD_SB_SIZE,
text = "hud_hunger_fg.png",
number = 0,
alignment = {x = -1, y = -1},
offset = HUD_HUNGER_OFFSET,
background = "hud_hunger_bg.png",
max = 0,
hud_elem_type = "statbar",
position = HUD_HUNGER_POS,
size = HUD_SB_SIZE,
text = "hud_hunger_fg.png",
number = 0,
alignment = {x = -1, y = -1},
offset = HUD_HUNGER_OFFSET,
background = "hud_hunger_bg.png",
max = 0,
})
else
hud.show_armor = false

View File

@ -1,114 +0,0 @@
HUD_IW_MAX = 8
HUD_IW_TICK = 0.4
if minetest.is_singleplayer() == true then
HUD_IW_TICK = 0.2
end
HUD_SB_SIZE = {x = 24, y = 24}
HUD_HEALTH_POS = {x = 0.5,y = 1}
HUD_HEALTH_OFFSET = {x = -262, y = -87}
HUD_AIR_POS = {x = 0.5, y = 1}
HUD_AIR_OFFSET = {x = 15, y = -87}
HUD_HUNGER_POS = {x = 0.5, y = 1}
HUD_HUNGER_OFFSET = {x = 15, y = -110}
HUD_ARMOR_POS = {x = 0.5, y = 1}
HUD_ARMOR_OFFSET = {x = -262, y = -110}
-- Reorder everything when using ItemWeel
hud.item_wheel = minetest.setting_getbool("hud_item_wheel")
if hud.item_wheel then
HUD_HEALTH_POS = {x = 0.5,y = 1}
HUD_HEALTH_OFFSET = {x = -385, y = -77}
HUD_AIR_POS = {x = 0.5, y = 1}
HUD_AIR_OFFSET = {x = 150, y = -77}
HUD_HUNGER_POS = {x = 0.5, y = 1}
HUD_HUNGER_OFFSET = {x = 180, y = -44}
HUD_ARMOR_POS = {x = 0.5, y = 1}
HUD_ARMOR_OFFSET = {x = -415, y = -44}
end
-- read hud.conf settings
hud.read_conf()
local damage_enabled = minetest.setting_getbool("enable_damage")
hud.show_hunger = minetest.get_modpath("hunger") ~= nil
hud.show_armor = minetest.get_modpath("3d_armor") ~= nil
-- check if some settings are invalid
local enable_hunger = minetest.setting_getbool("hud_hunger_enable")
if (enable_hunger == true or HUD_ENABLE_HUNGER == true) and not hud.show_hunger then
hud.notify_hunger(5)
end
if damage_enabled then
hud.register("health", {
hud_elem_type = "statbar",
position = HUD_HEALTH_POS,
size = HUD_SB_SIZE,
text = "hud_heart_fg.png",
number = 20,
alignment = {x = -1, y = -1},
offset = HUD_HEALTH_OFFSET,
background = "hud_heart_bg.png",
events = {
{
type = "damage",
func = function(player)
hud.change_item(player, "health", {number = player:get_hp()})
end
}
},
})
hud.register("air", {
hud_elem_type = "statbar",
position = HUD_AIR_POS,
size = HUD_SB_SIZE,
text = "hud_air_fg.png",
number = 0,
alignment = {x = -1, y = -1},
offset = HUD_AIR_OFFSET,
background = nil,
events = {
{
type = "breath",
func = function(player)
local air = player:get_breath()
if air > 10 then
air = 0
end
hud.change_item(player, "air", {number = air * 2})
end
}
},
})
hud.register("armor", {
hud_elem_type = "statbar",
position = HUD_ARMOR_POS,
size = HUD_SB_SIZE,
text = "hud_armor_fg.png",
number = 0,
alignment = {x = -1, y = -1},
offset = HUD_ARMOR_OFFSET,
background = "hud_armor_bg.png",
autohide_bg = true,
max = 20,
})
hud.register("hunger", {
hud_elem_type = "statbar",
position = HUD_HUNGER_POS,
size = HUD_SB_SIZE,
text = "hud_hunger_fg.png",
number = 0,
alignment = {x = -1, y = -1},
offset = HUD_HUNGER_OFFSET,
background = "hud_hunger_bg.png",
max = 0,
})
else
hud.show_armor = false
end

View File

@ -1,3 +1,16 @@
2.1.5
-----
- Fixed armor not being updated correct due armor mod changes
2.1.4
-----
- Fixed unhandled exception in hud.swap_statbar()
2.1.3
-----
- Added hud.swap_statbar() and fix wrong behavior of previous workaround
- Fixed missing background of some statbars in multiplayer
2.1.2
-----
- Fixed crash caused by animated nodes (reported by Krock)

View File

@ -3,59 +3,60 @@ function hud.set_armor()
end
if hud.show_armor then
local shields = minetest.get_modpath("shields") ~= nil
local armor_org_func = armor.update_armor
local shields = minetest.get_modpath("shields") ~= nil
local armor_org_func = armor.set_player_armor
local function get_armor_lvl(def)
-- items/protection based display
local lvl = def.level or 0
local max = 63 -- full diamond armor
if shields then
max = 84.14 -- full diamond armor + diamond shield
end
-- TODO: is there a sane way to read out max values?
local ret = lvl/max
if ret > 1 then
ret = 1
end
return tonumber(20 * ret)
local function get_armor_lvl(def)
-- items/protection based display
local lvl = def.level or 0
local max = 63 -- full diamond armor
if shields then
max = 84.14 -- full diamond armor + diamond shield
end
-- TODO: is there a sane way to read out max values?
local ret = lvl/max
if ret > 1 then
ret = 1
end
function armor.update_armor(self, player)
armor_org_func(self, player)
local name = player:get_player_name()
local def = self.def
local armor_lvl = 0
if def[name] and def[name].level then
armor_lvl = get_armor_lvl(def[name])
end
hud.change_item(player, "armor", {number = armor_lvl})
return tonumber(20 * ret)
end
function armor.set_player_armor(self, player)
armor_org_func(self, player)
local name = player:get_player_name()
local def = self.def
local armor_lvl = 0
if def[name] and def[name].level then
armor_lvl = get_armor_lvl(def[name])
end
hud.change_item(player, "armor", {number = armor_lvl})
end
end
-- Hunger related functions
if not hud.show_hunger then
function hud.set_hunger()
hud.notify_hunger(1, true)
end
function hud.set_hunger()
hud.notify_hunger(1, true)
end
function hud.get_hunger()
hud.notify_hunger(1, true)
end
function hud.get_hunger()
hud.notify_hunger(1, true)
end
function hud.item_eat(hp_change, replace_with_item)
return function(itemstack, user, pointed_thing)
hud.notify_hunger(1, true)
local func = minetest.item_eat(hp_change, replace_with_item)
return func(itemstack, user, pointed_thing)
end
function hud.item_eat(hp_change, replace_with_item)
return function(itemstack, user, pointed_thing)
hud.notify_hunger(1, true)
local func = minetest.item_eat(hp_change, replace_with_item)
return func(itemstack, user, pointed_thing)
end
end
function hud.save_hunger()
hud.notify_hunger(1, true)
end
function hud.load_hunger(player)
hud.notify_hunger(1, true)
end
function hud.save_hunger()
hud.notify_hunger(1, true)
end
function hud.load_hunger(player)
hud.notify_hunger(1, true)
end
end

View File

@ -1,6 +1,6 @@
Minetest mod "Hunger"
=====================
Version: 1.0
Version: 1.1.3
(c) Copyright BlockMen (2015)
@ -19,6 +19,12 @@ Information:
This mod depends on the "Better HUD" mod (https://github.com/BlockMen/hud) to provide information about your current saturation.
For Modders:
~~~~~~~~~~~~
This mod alters the behavior of minetest.item_eat().
All callbacks that are registered via minetest.register_on_item_eat() are called AFTER this mod actions, so the itemstack
will have changed already when callbacks are called. You can get the original itemstack as 6th parameter of your function then.
License:
~~~~~~~~
(c) Copyright BlockMen (2015)

View File

@ -4,3 +4,25 @@
- Added API to register food
- Added eating sounds
- Hungerbar image changes when poisend
1.1
---
- Fixed healing after death
- Fixed healing while drowning
- Fixed crashed caused by Pipeworks mod
- Added wrapper for minetest.item_eat(). see Readme.txt for more informations
- Updated HUD-API usage
- Added beans of Farming Redo
1.1.1
-----
- Fixed unhandled exception (reported by Martin_Devil)
- Added support for mtg mushrooms
1.1.2
-----
- Fixed crash on invalid values given
1.1.3
-----
- Prevent server crash caused by specific usernames (by beyondlimits)

View File

@ -13,6 +13,7 @@ farming?
farming_plus?
ferns?
fishing?
flowers?
fruit?
glooptest?
jkanimals?

View File

@ -6,6 +6,11 @@ if minetest.get_modpath("farming") ~= nil then
register_food("farming:bread", 4)
end
if minetest.get_modpath("flowers") ~= nil then
register_food("flowers:mushroom_brown", 1)
register_food("flowers:mushroom_red", 1, "", 3)
end
if minetest.get_modpath("mobs") ~= nil then
if mobs.mod ~= nil and mobs.mod == "redo" then
register_food("mobs:cheese", 4)
@ -18,7 +23,7 @@ if minetest.get_modpath("mobs") ~= nil then
register_food("mobs:chicken_cooked", 6)
register_food("mobs:chicken_raw", 2, "", 3)
register_food("mobs:chicken_egg_fried", 2)
if minetest.get_modpath("bucket") then
if minetest.get_modpath("bucket") then
register_food("mobs:bucket_milk", 3, "bucket:bucket_empty")
end
else
@ -253,6 +258,7 @@ if minetest.get_modpath("farming") and farming.mod == "redo" then
end
register_food("farming:rhubarb", 1)
register_food("farming:rhubarb_pie", 6)
register_food("farming:beans", 1)
end
if minetest.get_modpath("kpgmobs") ~= nil then

View File

@ -20,7 +20,7 @@ end
function hunger.save(player)
local inv = player:get_inventory()
local name = player:get_player_name()
local value = hunger[name].lvl
local value = hunger.players[name].lvl
if not inv or not value then
return nil
end
@ -40,17 +40,17 @@ function hunger.update_hunger(player, new_lvl)
return false
end
if minetest.setting_getbool("enable_damage") == false then
hunger[name] = 20
hunger.players[name] = 20
return
end
local lvl = hunger[name].lvl
local lvl = hunger.players[name].lvl
if new_lvl then
lvl = new_lvl
end
if lvl > HUNGER_MAX then
lvl = HUNGER_MAX
end
hunger[name].lvl = lvl
hunger.players[name].lvl = lvl
if lvl > 20 then
lvl = 20
end
@ -65,9 +65,13 @@ function hunger.handle_node_actions(pos, oldnode, player, ext)
return
end
local name = player:get_player_name()
local exhaus = hunger[name].exhaus
if not name or not hunger.players[name] then
return
end
local exhaus = hunger.players[name].exhaus
if not exhaus then
hunger[name].exhaus = 0
hunger.players[name].exhaus = 0
--return
end
@ -87,21 +91,22 @@ function hunger.handle_node_actions(pos, oldnode, player, ext)
if exhaus > HUNGER_EXHAUST_LVL then
exhaus = 0
local h = tonumber(hunger[name].lvl)
local h = tonumber(hunger.players[name].lvl)
if h > 0 then
update_hunger(player, h - 1)
end
end
hunger[name].exhaus = exhaus
hunger.players[name].exhaus = exhaus
end
-- Time based hunger functions
if minetest.setting_getbool("enable_damage") then
local hunger_timer = 0
local health_timer = 0
local action_timer = 0
minetest.register_globalstep(function(dtime)
local hunger_timer = 0
local health_timer = 0
local action_timer = 0
local function hunger_globaltimer(dtime)
hunger_timer = hunger_timer + dtime
health_timer = health_timer + dtime
action_timer = action_timer + dtime
@ -121,7 +126,7 @@ if minetest.setting_getbool("enable_damage") then
if hunger_timer > HUNGER_TICK then
for _,player in ipairs(minetest.get_connected_players()) do
local name = player:get_player_name()
local tab = hunger[name]
local tab = hunger.players[name]
if tab then
local hunger = tab.lvl
if hunger > 0 then
@ -136,13 +141,13 @@ if minetest.setting_getbool("enable_damage") then
if health_timer > HUNGER_HEALTH_TICK then
for _,player in ipairs(minetest.get_connected_players()) do
local name = player:get_player_name()
local tab = hunger[name]
local tab = hunger.players[name]
if tab then
local air = player:get_breath() or 0
local hp = player:get_hp()
-- heal player by 1 hp if not dead and saturation is > 15 (of 30)
if tonumber(tab.lvl) > HUNGER_HEAL_LVL and air > 0 then
-- heal player by 1 hp if not dead and saturation is > 15 (of 30) player is not drowning
if tonumber(tab.lvl) > HUNGER_HEAL_LVL and hp > 0 and air > 0 then
player:set_hp(hp + HUNGER_HEAL)
end
@ -155,7 +160,10 @@ if minetest.setting_getbool("enable_damage") then
health_timer = 0
end
end)
end
if minetest.setting_getbool("enable_damage") then
minetest.register_globalstep(hunger_globaltimer)
end
@ -166,9 +174,9 @@ function hunger.register_food(name, hunger_change, replace_with_item, poisen, he
food[name] = {}
food[name].saturation = hunger_change -- hunger points added
food[name].replace = replace_with_item -- what item is given back after eating
food[name].poisen = poisen -- time its poisening
food[name].healing = heal -- amount of HP
food[name].sound = sound -- special sound that is played when eating
food[name].poisen = poisen -- time its poisening
food[name].healing = heal -- amount of HP
food[name].sound = sound -- special sound that is played when eating
end
-- Poison player
@ -185,11 +193,29 @@ local function poisenp(tick, time, time_left, player)
end
end
-- wrapper for minetest.item_eat (this way we make sure other mods can't break this one)
local org_eat = core.do_item_eat
core.do_item_eat = function(hp_change, replace_with_item, itemstack, user, pointed_thing)
local old_itemstack = itemstack
itemstack = hunger.eat(hp_change, replace_with_item, itemstack, user, pointed_thing)
for _, callback in pairs(core.registered_on_item_eats) do
local result = callback(hp_change, replace_with_item, itemstack, user, pointed_thing, old_itemstack)
if result then
return result
end
end
return itemstack
end
function hunger.eat(hp_change, replace_with_item, itemstack, user, pointed_thing)
local item = itemstack:get_name()
local def = food[item]
if not def then
def = {}
if type(hp_change) ~= "number" then
hp_change = 1
core.log("error", "Wrong on_use() definition for item '" .. item .. "'")
end
def.saturation = hp_change * 1.3
def.replace = replace_with_item
end
@ -201,7 +227,10 @@ function hunger.item_eat(hunger_change, replace_with_item, poisen, heal, sound)
return function(itemstack, user, pointed_thing)
if itemstack:take_item() ~= nil and user ~= nil then
local name = user:get_player_name()
local sat = tonumber(hunger[name].lvl)
if not hunger.players[name] then
return itemstack
end
local sat = tonumber(hunger.players[name].lvl or 0)
local hp = user:get_hp()
-- Saturation
if sat < HUNGER_MAX and hunger_change then
@ -228,7 +257,20 @@ function hunger.item_eat(hunger_change, replace_with_item, poisen, heal, sound)
end
minetest.sound_play(sound, {to_player = name, gain = 0.7})
itemstack:add_item(replace_with_item)
if replace_with_item then
if itemstack:is_empty() then
itemstack:add_item(replace_with_item)
else
local inv = user:get_inventory()
if inv:room_for_item("main", {name=replace_with_item}) then
inv:add_item("main", replace_with_item)
else
local pos = user:getpos()
pos.y = math.floor(pos.y + 0.5)
core.add_item(pos, replace_with_item)
end
end
end
end
return itemstack

View File

@ -1,7 +1,8 @@
hunger = {}
hunger.players = {}
hunger.food = {}
HUNGER_TICK = 300 -- time in seconds after that 1 hunger point is taken
HUNGER_TICK = 800 -- time in seconds after that 1 hunger point is taken
HUNGER_HEALTH_TICK = 4 -- time in seconds after player gets healed/damaged
HUNGER_MOVE_TICK = 0.5 -- time in seconds after the movement is checked
@ -10,12 +11,12 @@ HUNGER_EXHAUST_PLACE = 1 -- exhaustion increased this value after placed
HUNGER_EXHAUST_MOVE = 1.5 -- exhaustion increased this value if player movement detected
HUNGER_EXHAUST_LVL = 160 -- at what exhaustion player saturation gets lowered
HUNGER_HEAL = 1 -- number of HP player gets healed after HUNGER_HEALTH_TICK
HUNGER_HEAL = 1 -- number of HP player gets healed after HUNGER_HEALTH_TICK
HUNGER_HEAL_LVL = 15 -- lower level of saturation needed to get healed
HUNGER_STARVE = 1 -- number of HP player gets damaged by hunger after HUNGER_HEALTH_TICK
HUNGER_STARVE = 1 -- number of HP player gets damaged by hunger after HUNGER_HEALTH_TICK
HUNGER_STARVE_LVL = 3 -- level of staturation that causes starving
HUNGER_MAX = 30 -- maximum level of saturation
HUNGER_MAX = 30 -- maximum level of saturation
local modpath = minetest.get_modpath("hunger")
@ -31,15 +32,15 @@ if minetest.setting_getbool("enable_damage") then
inv:set_size("hunger", 1)
local name = player:get_player_name()
hunger[name] = {}
hunger[name].lvl = hunger.read(player)
hunger[name].exhaus = 0
local lvl = hunger[name].lvl
hunger.players[name] = {}
hunger.players[name].lvl = hunger.read(player)
hunger.players[name].exhaus = 0
local lvl = hunger.players[name].lvl
if lvl > 20 then
lvl = 20
end
minetest.after(0.8, function()
hud.change_item(player, "hunger", {offset = "item", item_name = "air"})
hud.swap_statbar(player, "hunger", "air")
hud.change_item(player, "hunger", {number = lvl, max = 20})
end)
end)
@ -47,7 +48,6 @@ if minetest.setting_getbool("enable_damage") then
-- for exhaustion
minetest.register_on_placenode(hunger.handle_node_actions)
minetest.register_on_dignode(hunger.handle_node_actions)
minetest.register_on_item_eat(hunger.eat)
minetest.register_on_respawnplayer(function(player)
hunger.update_hunger(player, 20)
end)

View File

@ -1,54 +0,0 @@
hunger = {}
hunger.food = {}
HUNGER_TICK = 800 -- time in seconds after that 1 hunger point is taken
HUNGER_HEALTH_TICK = 4 -- time in seconds after player gets healed/damaged
HUNGER_MOVE_TICK = 0.5 -- time in seconds after the movement is checked
HUNGER_EXHAUST_DIG = 3 -- exhaustion increased this value after digged node
HUNGER_EXHAUST_PLACE = 1 -- exhaustion increased this value after placed
HUNGER_EXHAUST_MOVE = 1.5 -- exhaustion increased this value if player movement detected
HUNGER_EXHAUST_LVL = 160 -- at what exhaustion player saturation gets lowered
HUNGER_HEAL = 1 -- number of HP player gets healed after HUNGER_HEALTH_TICK
HUNGER_HEAL_LVL = 15 -- lower level of saturation needed to get healed
HUNGER_STARVE = 1 -- number of HP player gets damaged by hunger after HUNGER_HEALTH_TICK
HUNGER_STARVE_LVL = 3 -- level of staturation that causes starving
HUNGER_MAX = 30 -- maximum level of saturation
local modpath = minetest.get_modpath("hunger")
dofile(modpath .. "/functions.lua")
dofile(modpath .. "/food.lua")
dofile(modpath .. "/legacy.lua")
-- Callbacks
if minetest.setting_getbool("enable_damage") then
minetest.register_on_joinplayer(function(player)
local inv = player:get_inventory()
inv:set_size("hunger", 1)
local name = player:get_player_name()
hunger[name] = {}
hunger[name].lvl = hunger.read(player)
hunger[name].exhaus = 0
local lvl = hunger[name].lvl
if lvl > 20 then
lvl = 20
end
minetest.after(0.8, function()
hud.change_item(player, "hunger", {offset = "item", item_name = "air"})
hud.change_item(player, "hunger", {number = lvl, max = 20})
end)
end)
-- for exhaustion
minetest.register_on_placenode(hunger.handle_node_actions)
minetest.register_on_dignode(hunger.handle_node_actions)
minetest.register_on_item_eat(hunger.eat)
minetest.register_on_respawnplayer(function(player)
hunger.update_hunger(player, 20)
end)
end

View File

@ -4,7 +4,17 @@ Minetest mod moretrees
All source code:
© 2013, Vanessa Ezekowitz <vanessaezekowitz@gmail.com>
Published under the terms and conditions of the WTFPL.
All sapling textures (textures/*_sapling.png):
Date & cocos palm code (date_palm.lua, cocos_palm.lua)
© 2016, Rogier <rogier777@gmail.com>
Published under the terms and conditions of the WTFPL.
All date & date palm textures, date-based food, cocos flower & green coconuts,
and all poplar textures:
© 2016, Rogier <rogier777@gmail.com>
Published under the terms and conditions of CC-BY-SA-3.0 Unported.
- Three of the date palm textures are modifications of existing moretrees textures
- The green coconuts are a modification of the brown coconut
- The date cake batter is a modification of the acorn muffin batter
All other sapling textures (textures/*_sapling.png):
© 2013, Tim Huppertz <mitroman@naturalnet.de>
Published under the terms and conditions of CC-BY-SA-3.0 Unported.
All other textures:

View File

@ -8,4 +8,4 @@ jungle trees mod, and big contributions by RealBadAngel.
Brought together into one mod and made L-systems compatible by Vanessa
Ezekowitz.
Dependencies: <a href="https://github.com/VanessaE/plantlife">plants_lib</a> and default
Dependencies: <a href="https://forum.minetest.net/viewtopic.php?f=11&t=12999">biome_lib</a> and default

View File

@ -24,6 +24,40 @@ moretrees.palm_biome = {
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,
@ -90,6 +124,18 @@ moretrees.willow_biome = {
max_count = 5,
}
moretrees.acacia_biome = {
surface = { "default:dirt_with_grass", "default:dirt_with_dry_grass", "default:desert_sand" },
avoid_nodes = moretrees.avoidnodes,
avoid_radius = 15,
seed_diff = 1,
rarity = 50,
max_count = 15,
plantlife_limit = -1,
humidity_min = 0.3,
humidity_max = 0,
}
moretrees.rubber_tree_biome = {
surface = "default:dirt_with_grass",
avoid_nodes = moretrees.avoidnodes,
@ -106,18 +152,24 @@ moretrees.rubber_tree_biome = {
}
moretrees.jungletree_biome = {
surface = "default:dirt_with_grass",
avoid_nodes = moretrees.avoidnodes,
avoid_radius = 5,
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 = -5,
max_elevation = 10,
temp_min = 0.25,
near_nodes = {"default:water_source"},
near_nodes_size = 20,
near_nodes_count = 7,
rarity = 10,
max_count = 10,
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 = {
@ -132,7 +184,7 @@ moretrees.spruce_biome = {
max_count = 5,
}
moretrees.pine_biome = {
moretrees.cedar_biome = {
surface = "default:dirt_with_grass",
avoid_nodes = moretrees.avoidnodes,
avoid_radius = 10,
@ -144,6 +196,97 @@ moretrees.pine_biome = {
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,

View File

@ -0,0 +1,283 @@
local S = moretrees.intllib
-- © 2016, Rogier <rogier777@gmail.com>
-- 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.remove_node(coconutpos)
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.set_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 gen
local count = 0
for _,gen in pairs(genlist) do
minetest.set_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.remove_node(pos)
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 in pairs(cvtrunks) do
minetest.swap_node(tpos, {name = "moretrees:palm_fruit_trunk"})
coconuts = 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:coconut")
for _, coconutpos in pairs(coconuts) do
minetest.set_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

View File

@ -1,3 +1,4 @@
local S = moretrees.intllib
for i in ipairs(moretrees.treelist) do
local treename = moretrees.treelist[i][1]
@ -50,43 +51,72 @@ minetest.register_craft({
-- Food recipes!
minetest.register_craftitem("moretrees:coconut_milk", {
description = "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),
})
minetest.register_craftitem("moretrees:raw_coconut", {
description = "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 = "Acorn Muffin batter",
description = S("Acorn Muffin batter"),
inventory_image = "moretrees_acorn_muffin_batter.png",
})
minetest.register_craftitem("moretrees:acorn_muffin", {
description = "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 = "Roasted Spruce Cone Nuts",
description = S("Roasted Spruce Cone Nuts"),
inventory_image = "moretrees_spruce_nuts.png",
on_use = minetest.item_eat(1),
})
minetest.register_craftitem("moretrees:pine_nuts", {
description = "Roasted Pine Cone Nuts",
inventory_image = "moretrees_pine_nuts.png",
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 = "Roasted Fir Cone Nuts",
description = S("Roasted Fir Cone Nuts"),
inventory_image = "moretrees_fir_nuts.png",
on_use = minetest.item_eat(1),
})
@ -108,6 +138,60 @@ for i in ipairs(moretrees.cutting_tools) do
})
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",
@ -137,8 +221,8 @@ minetest.register_craft({
minetest.register_craft({
type = "cooking",
output = "moretrees:pine_nuts 4",
recipe = "moretrees:pine_cone",
output = "moretrees:cedar_nuts 4",
recipe = "moretrees:cedar_cone",
})
minetest.register_craft({

View File

@ -0,0 +1,746 @@
-- Date palms.
--
-- Date palms grow in hot and dry desert, but they require water. This makes them
-- a bit harder to find. If found in the middle of the desert, their presence
-- indicates a water source below the surface.
--
-- As an additional feature (which can be disabled), dates automatically regrow after
-- harvesting (provided a male tree is sufficiently nearby).
-- If regrowing is enabled, then ripe dates will not hang forever. Most will disappear
-- (e.g. eaten by birds, ...), and a small fraction will drop as items.
-- © 2016, Rogier <rogier777@gmail.com>
-- License: WTFPL
local S = moretrees.intllib
-- 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.remove_node(datespos)
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.set_node(datepos, {name="moretrees:dates_f0"})
else
minetest.set_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")
local genpos
for _,genpos in pairs(dates1) do
if math.random(100) <= 20 then
if type == "m" then
minetest.set_node(genpos, {name = "moretrees:dates_n"})
else
minetest.set_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.set_node(genpos, {name = "moretrees:dates_n"})
else
minetest.set_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 = core.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 all_palms = minetest.find_nodes_in_area(
{ x = ftpos.x + 2 * sect.x * sect_hr - sect_hr,
y = ftpos.y - sect_vr,
z = ftpos.z + 2 * sect.z * sect_hr - sect_hr },
{ x = ftpos.x + 2 * sect.x * sect_hr + sect_hr,
y = ftpos.y + sect_vr,
z = ftpos.z + 2 * sect.z * sect_hr + sect_hr },
{"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 = core.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(string.trim(param))
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 r = moretrees.dates_pollination_distance
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.remove_node(pos)
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.remove_node(pos)
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 = core.get_us_time()
local action = dates_growfn(pos, elapsed)
local t1 = core.get_us_time()
if t1 < t0 then
t1 = t1 + 2^32
end
stat.count = stat.count + 1
if not stat[action] then
stat[action] = {}
stat[action].count = 0
stat[action].sum = 0
stat[action].min = 9999999999
stat[action].max = 0
end
stat[action].count = stat[action].count + 1
stat[action].sum = stat[action].sum + t1-t0
if t1-t0 < stat[action].min then
stat[action].min = t1-t0
end
if t1-t0 > stat[action].max then
stat[action].max = t1-t0
end
if stat.count % 10 == 0 then
io.write(".")
io.flush()
end
if stat.count % 100 == 0 then
print(string.format("Date grow statistics %5d:", stat.count))
local sum = 0
local count = 0
if sect_search_stats.count > 0 and stat.pollinate and stat.pollinate.count > 0 then
print(string.format("\t%-12s: %6d (%4.1f%%): %6dus (%d..%d)",
"search", sect_search_stats.count,
100*sect_search_stats.count/stat.pollinate.count,
sect_search_stats.sum/sect_search_stats.count,
sect_search_stats.min, sect_search_stats.max))
else
print(string.format("\t%-12s: %6d (%4.1f%%): %6dus (%d..%d)",
"search", sect_search_stats.count,
0, 0, 0, 0))
end
for action,data in pairs(stat) do
if action ~= "count" then
count = count + data.count
sum = sum + data.sum
print(string.format("\t%-12s: %6d (%4.1f%%): %6dus (%d..%d)",
action, data.count,
100*data.count/stat.count, data.sum/data.count,
data.min, data.max))
end
end
print(string.format("\t%-12s: %6d ( 100%%): %6dus",
"TOTAL", count, sum/count))
end
end
-- Register dates
local dates_starttimer = function(pos, elapsed)
local timer = minetest.get_node_timer(pos)
local base_interval = moretrees.dates_grow_interval * 2 / 3
timer:set(base_interval + math.random(base_interval), elapsed or 0)
end
local dates_drop = {
items = {
{items = { "moretrees:date" }},
{items = { "moretrees:date" }},
{items = { "moretrees:date" }},
{items = { "moretrees:date" }},
{items = { "moretrees:date" }, rarity = 2 },
{items = { "moretrees:date" }, rarity = 2 },
{items = { "moretrees:date" }, rarity = 2 },
{items = { "moretrees:date" }, rarity = 2 },
{items = { "moretrees:date" }, rarity = 5 },
{items = { "moretrees:date" }, rarity = 5 },
{items = { "moretrees:date" }, rarity = 5 },
{items = { "moretrees:date" }, rarity = 5 },
{items = { "moretrees:date" }, rarity = 20 },
{items = { "moretrees:date" }, rarity = 20 },
{items = { "moretrees:date" }, rarity = 20 },
{items = { "moretrees:date" }, rarity = 20 },
}
}
for _,suffix in ipairs({"f0", "f1", "f2", "f3", "f4", "m0", "fn", "n"}) do
local name
if suffix == "f0" or suffix == "m0" then
name = S("Date Flowers")
elseif suffix == "n" or suffix == "fn" then
name = S("Date Stem")
else
name = S("Dates")
end
local dropfn = suffix == "f4" and dates_drop or ""
local datedef = {
description = name,
tiles = {"moretrees_dates_"..suffix..".png"},
visual_scale = 2,
drawtype = "plantlike",
paramtype = "light",
sunlight_propagates = true,
walkable = false,
groups = { fleshy=3, dig_immediate=3, flammable=2, moretrees_dates=1 },
inventory_image = "moretrees_dates_"..suffix..".png^[transformR0",
wield_image = "moretrees_dates_"..suffix..".png^[transformR90",
sounds = default.node_sound_defaults(),
drop = dropfn,
selection_box = {
type = "fixed",
fixed = {-0.3, -0.3, -0.3, 0.3, 3.5, 0.3}
},
on_timer = dates_growfn,
on_construct = (moretrees.dates_regrow_pollinated or moretrees.dates_regrow_unpollinated_percent > 0)
and dates_starttimer,
}
minetest.register_node("moretrees:dates_"..suffix, datedef)
end
-- If regrowing was previously disabled, but is enabled now, make sure timers are started for existing dates
if moretrees.dates_regrow_pollinated or moretrees.dates_regrow_unpollinated_percent > 0 then
local spec = {
name = "moretrees:restart_dates_regrow_timer",
nodenames = "group:moretrees_dates",
action = function(pos, node, active_object_count, active_object_count_wider)
local timer = minetest.get_node_timer(pos)
if not timer:is_started() then
dates_starttimer(pos)
else
local timeout = timer:get_timeout()
local elapsed = timer:get_elapsed()
if timeout - elapsed > moretrees.dates_grow_interval * 4/3 then
dates_starttimer(pos, math.random(moretrees.dates_grow_interval * 4/3))
end
end
end,
}
if minetest.register_lbm then
minetest.register_lbm(spec)
else
spec.interval = 3557
spec.chance = 10
minetest.register_abm(spec)
end
end

View File

@ -6,25 +6,29 @@ moretrees.enable_apple_tree = true
moretrees.enable_oak = true
moretrees.enable_sequoia = true
moretrees.enable_palm = true
moretrees.enable_pine = true
moretrees.enable_rubber_tree = true
moretrees.enable_date_palm = true
moretrees.enable_cedar = true
moretrees.enable_rubber_tree = true
moretrees.enable_willow = true
moretrees.enable_acacia = true
moretrees.enable_birch = true
moretrees.enable_spruce = true
moretrees.enable_jungle_tree = 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 very quickly. This will
-- greatly reduce mapgen lag, at the expense of having to wait several seconds for
-- the trees to grow via an ABM.
-- of fully-grown trees, which will grow into full trees after a very short
-- delay. This reduces mapgen lag in some situations.
moretrees.spawn_saplings = true
moretrees.spawn_saplings = false
-- Set this to true to allow usage of the stairsplus mod in moreblocks
-- 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_stairsplus = true
moretrees.enable_stairs = true
-- Set this to true if you want the plantlike drawtype for leaves, which
-- improves some peoples' framerates without resorting to making leaf nodes opaque.
@ -32,42 +36,21 @@ moretrees.enable_stairsplus = true
moretrees.plantlike_leaves = false
-- Set this to true to enable leaf decay of all trees except the default ones.
moretrees.enable_leafdecay = true
-- Enable this one if you want this mod's leafdecay code to affect the old
-- default trees too; this setting is independent of the one above. You'll
-- want to manually disable the default leafdecay code in minetest_game if
-- you enable this, otherwise you'll have two sets of leaf decay code running
-- at the same time, which will just waste CPU for no benefit.
moretrees.enable_default_leafdecay = true
-- Enable this one for default *jungle* leaves
moretrees.enable_default_jungle_leafdecay = true
-- Enable this if you want moretrees to redefine default apples so that they
-- fall when leaves decay/are dug.
moretrees.enable_redefine_apple = true
-- various settings to configure default and default-jungle leaf decay.
-- 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 = 100
moretrees.leafdecay_chance = 5
moretrees.leafdecay_radius = 5
moretrees.default_jungle_leafdecay_delay = 2
moretrees.default_jungle_leafdecay_chance = 100
moretrees.default_jungle_leafdecay_radius = 5
moretrees.palm_leafdecay_radius = 15
moretrees.default_leafdecay_delay = 3
moretrees.default_leafdecay_chance = 50
moretrees.default_leafdecay_radius = 4
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.
@ -76,7 +59,73 @@ 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 = 500
moretrees.sapling_chance = 20
-- 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

View File

@ -1,4 +1,8 @@
default
plants_lib
biome_lib
vessels
stairs?
moreblocks?
intllib?
farming?

View File

@ -0,0 +1 @@
This mod adds a whole bunch of new types of trees to the game

View File

@ -13,8 +13,7 @@
-- by RealBadAngel.
--
-- License: WTFPL for all parts (code and textures, including those copied
-- from the jungletree and conifers mods) except the default jungle tree trunk
-- texture, which is CC-By-SA.
-- from the the old jungletree and conifers mods).
moretrees = {}
@ -25,34 +24,30 @@ local modpath=minetest.get_modpath("moretrees")
dofile(modpath.."/default_settings.txt")
if io.open(worldpath.."/moretrees_settings.txt","r") == nil then
io.input(modpath.."/default_settings.txt")
io.output(worldpath.."/moretrees_settings.txt")
local size = 2^13 -- good buffer size (8K)
while true do
local block = io.read(size)
if not block then
io.close()
break
end
io.write(block)
end
else
if io.open(worldpath.."/moretrees_settings.txt","r") then
io.close()
dofile(worldpath.."/moretrees_settings.txt")
end
-- Boilerplate to support localized strings if intllib mod is installed.
local S
if moretrees.intllib_modpath then
dofile(moretrees.intllib_modpath.."/intllib.lua")
S = intllib.Getter(minetest.get_current_modname())
if minetest.get_modpath("intllib") then
S = intllib.Getter()
else
S = function ( s ) return s end
S = function(s) return s end
end
moretrees.intllib = S
-- clone node
function moretrees.clone_node(name)
local node2 = {}
local node = minetest.registered_nodes[name]
for k,v in pairs(node) do
node2[k]=v
end
return node2
end
moretrees.gettext = S
-- infinite stacks checking
@ -62,17 +57,6 @@ else
moretrees.expect_infinite_stacks = true
end
-- node clone, for redefining stuff
function moretrees:clone_node(name)
node2={}
node=minetest.registered_nodes[name]
for k,v in pairs(node) do
node2[k]=v
end
return node2
end
-- tables, load other files
moretrees.cutting_tools = {
@ -89,10 +73,11 @@ moretrees.cutting_tools = {
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")
dofile(modpath.."/leafdecay.lua")
-- tree spawning setup
@ -102,83 +87,109 @@ if moretrees.spawn_saplings then
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_pine_object = "moretrees:pine_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_acacia_object = "moretrees:acacia_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_pine_object = moretrees.pine_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_acacia_object = moretrees.acacia_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
plantslib:register_generate_plant(moretrees.beech_biome, moretrees.spawn_beech_object)
biome_lib:register_generate_plant(moretrees.beech_biome, moretrees.spawn_beech_object)
end
if moretrees.enable_apple_tree then
plantslib:register_generate_plant(moretrees.apple_tree_biome, moretrees.spawn_apple_tree_object)
biome_lib:register_generate_plant(moretrees.apple_tree_biome, moretrees.spawn_apple_tree_object)
end
if moretrees.enable_oak then
plantslib:register_generate_plant(moretrees.oak_biome, moretrees.spawn_oak_object)
biome_lib:register_generate_plant(moretrees.oak_biome, moretrees.spawn_oak_object)
end
if moretrees.enable_sequoia then
plantslib:register_generate_plant(moretrees.sequoia_biome, moretrees.spawn_sequoia_object)
biome_lib:register_generate_plant(moretrees.sequoia_biome, moretrees.spawn_sequoia_object)
end
if moretrees.enable_palm then
plantslib:register_generate_plant(moretrees.palm_biome, moretrees.spawn_palm_object)
biome_lib:register_generate_plant(moretrees.palm_biome, moretrees.spawn_palm_object)
end
if moretrees.enable_pine then
plantslib:register_generate_plant(moretrees.pine_biome, moretrees.spawn_pine_object)
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
plantslib:register_generate_plant(moretrees.rubber_tree_biome, moretrees.spawn_rubber_tree_object)
biome_lib:register_generate_plant(moretrees.rubber_tree_biome, moretrees.spawn_rubber_tree_object)
end
if moretrees.enable_willow then
plantslib:register_generate_plant(moretrees.willow_biome, moretrees.spawn_willow_object)
biome_lib:register_generate_plant(moretrees.willow_biome, moretrees.spawn_willow_object)
end
if moretrees.enable_acacia then
biome_lib:register_generate_plant(moretrees.acacia_biome, moretrees.spawn_acacia_object)
end
if moretrees.enable_birch then
plantslib:register_generate_plant(moretrees.birch_biome, moretrees.spawn_birch_object)
biome_lib:register_generate_plant(moretrees.birch_biome, moretrees.spawn_birch_object)
end
if moretrees.enable_spruce then
plantslib:register_generate_plant(moretrees.spruce_biome, moretrees.spawn_spruce_object)
biome_lib:register_generate_plant(moretrees.spruce_biome, moretrees.spawn_spruce_object)
end
if moretrees.enable_jungle_tree then
plantslib:register_generate_plant(moretrees.jungletree_biome, moretrees.spawn_jungletree_object)
biome_lib:register_generate_plant(moretrees.jungletree_biome, moretrees.spawn_jungletree_object)
end
if moretrees.enable_fir then
plantslib:register_generate_plant(moretrees.fir_biome, moretrees.spawn_fir_object)
plantslib:register_generate_plant(moretrees.fir_biome_snow, moretrees.spawn_fir_snow_object)
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)
function moretrees.grow_birch(pos)
minetest.remove_node(pos)
if math.random(1,2) == 1 then
minetest.spawn_tree(pos, moretrees.birch_model1)
@ -189,7 +200,7 @@ end
-- Code to spawn a spruce tree
function moretrees:grow_spruce(pos)
function moretrees.grow_spruce(pos)
minetest.remove_node(pos)
if math.random(1,2) == 1 then
minetest.spawn_tree(pos, moretrees.spruce_model1)
@ -214,7 +225,7 @@ 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)
function moretrees.grow_jungletree(pos)
local r1 = math.random(2)
local r2 = math.random(3)
if r1 == 1 then
@ -254,7 +265,7 @@ end
-- code to spawn fir trees
function moretrees:grow_fir(pos)
function moretrees.grow_fir(pos)
if math.random(2) == 1 then
moretrees.fir_model.leaves="moretrees:fir_leaves"
else
@ -281,7 +292,7 @@ end
-- same thing, but a smaller version that grows only in snow biomes
function moretrees:grow_fir_snow(pos)
function moretrees.grow_fir_snow(pos)
if math.random(2) == 1 then
moretrees.fir_model.leaves="moretrees:fir_leaves"
else
@ -306,4 +317,4 @@ function moretrees:grow_fir_snow(pos)
minetest.spawn_tree(pos,moretrees.fir_model)
end
print("[Moretrees] Loaded (2013-02-11)")
print(S("[Moretrees] Loaded (2013-02-11)"))

View File

@ -1,108 +0,0 @@
-- leaf decay
-- this function is based on the default leafdecay code
local process_drops = function(pos, name)
local drops = minetest.get_node_drops(name)
for _,dropitem in ipairs(drops) do
if dropitem ~= name then
local newpos = {
x=pos.x + math.random() - 0.5,
y=pos.y + math.random() - 0.5,
z=pos.z + math.random() - 0.5
}
minetest.add_item(newpos, dropitem)
end
end
end
if moretrees.enable_leafdecay then
for i in ipairs(moretrees.treelist) do
local treename = moretrees.treelist[i][1]
if treename ~= "jungletree" and treename ~= "fir" then
minetest.register_abm({
nodenames = "moretrees:"..treename.."_leaves",
interval = moretrees.leafdecay_delay,
chance = moretrees.leafdecay_chance,
action = function(pos, node, active_object_count, active_object_count_wider)
if minetest.find_node_near(pos, moretrees.leafdecay_radius, "moretrees:"..treename.."_trunk") then return end
if minetest.find_node_near(pos, moretrees.leafdecay_radius, "ignore") then return end
process_drops(pos, node.name)
minetest.remove_node(pos)
nodeupdate(pos)
end
})
end
end
minetest.register_abm({
nodenames = {"moretrees:jungletree_leaves_red","moretrees:jungletree_leaves_green","moretrees:jungletree_leaves_yellow"},
interval = moretrees.leafdecay_delay,
chance = moretrees.leafdecay_chance,
action = function(pos, node, active_object_count, active_object_count_wider)
if minetest.find_node_near(pos, moretrees.leafdecay_radius, {"default:jungletree", "moretrees:jungletree_trunk"}) then return end
if minetest.find_node_near(pos, moretrees.leafdecay_radius, "ignore") then return end
process_drops(pos, node.name)
minetest.remove_node(pos)
nodeupdate(pos)
end
})
minetest.register_abm({
nodenames = {"moretrees:fir_leaves", "moretrees:fir_leaves_bright"},
interval = moretrees.leafdecay_delay,
chance = moretrees.leafdecay_chance,
action = function(pos, node, active_object_count, active_object_count_wider)
if minetest.find_node_near(pos, moretrees.leafdecay_radius, "moretrees:fir_trunk") then return end
if minetest.find_node_near(pos, moretrees.leafdecay_radius, "ignore") then return end
process_drops(pos, node.name)
minetest.remove_node(pos)
nodeupdate(pos)
end
})
minetest.register_abm({
nodenames = "moretrees:palm_leaves",
interval = moretrees.leafdecay_delay,
chance = moretrees.leafdecay_chance,
action = function(pos, node, active_object_count, active_object_count_wider)
if minetest.find_node_near(pos, moretrees.palm_leafdecay_radius, "moretrees:palm_trunk") then return end
if minetest.find_node_near(pos, moretrees.palm_leafdecay_radius, "ignore") then return end
process_drops(pos, node.name)
minetest.remove_node(pos)
nodeupdate(pos)
end
})
end
if moretrees.enable_default_leafdecay then
minetest.register_abm({
nodenames = "default:leaves",
interval = moretrees.default_leafdecay_delay,
chance = moretrees.default_leafdecay_chance,
action = function(pos, node, active_object_count, active_object_count_wider)
if minetest.find_node_near(pos, moretrees.default_leafdecay_radius, "default:tree") then return end
if minetest.find_node_near(pos, moretrees.default_leafdecay_radius, "ignore") then return end
process_drops(pos, node.name)
minetest.remove_node(pos)
nodeupdate(pos)
end
})
end
if moretrees.enable_default_jungle_leafdecay then
minetest.register_abm({
nodenames = "default:jungleleaves",
interval = moretrees.default_jungle_leafdecay_delay,
chance = moretrees.default_jungle_leafdecay_chance,
action = function(pos, node, active_object_count, active_object_count_wider)
if minetest.find_node_near(pos, moretrees.default_jungle_leafdecay_radius, "default:jungletree") then return end
if minetest.find_node_near(pos, moretrees.default_jungle_leafdecay_radius, "ignore") then return end
process_drops(pos, node.name)
minetest.remove_node(pos)
nodeupdate(pos)
end
})
end

View File

@ -1,108 +0,0 @@
-- leaf decay
-- this function is based on the default leafdecay code
local process_drops = function(pos, name)
local drops = minetest.get_node_drops(name)
for _,dropitem in ipairs(drops) do
if dropitem ~= name then
local newpos = {
x=pos.x + math.random() - 0.5,
y=pos.y + math.random() - 0.5,
z=pos.z + math.random() - 0.5
}
minetest.add_item(newpos, dropitem)
end
end
end
if moretrees.enable_leafdecay then
for i in ipairs(moretrees.treelist) do
local treename = moretrees.treelist[i][1]
if treename ~= "jungletree" and treename ~= "fir" then
minetest.register_abm({
nodenames = "moretrees:"..treename.."_leaves",
interval = moretrees.leafdecay_delay,
chance = moretrees.leafdecay_chance,
action = function(pos, node, active_object_count, active_object_count_wider)
if minetest.find_node_near(pos, moretrees.leafdecay_radius, "moretrees:"..treename.."_trunk") then return end
if minetest.find_node_near(pos, moretrees.leafdecay_radius, "ignore") then return end
process_drops(pos, node.name)
minetest.remove_node(pos)
nodeupdate(pos)
end
})
end
end
minetest.register_abm({
nodenames = {"moretrees:jungletree_leaves_red","moretrees:jungletree_leaves_green","moretrees:jungletree_leaves_yellow"},
interval = moretrees.leafdecay_delay,
chance = moretrees.leafdecay_chance,
action = function(pos, node, active_object_count, active_object_count_wider)
if minetest.find_node_near(pos, moretrees.leafdecay_radius, {"default:jungletree", "moretrees:jungletree_trunk"}) then return end
if minetest.find_node_near(pos, moretrees.leafdecay_radius, "ignore") then return end
process_drops(pos, node.name)
minetest.remove_node(pos)
nodeupdate(pos)
end
})
minetest.register_abm({
nodenames = {"moretrees:fir_leaves", "moretrees:fir_leaves_bright"},
interval = moretrees.leafdecay_delay,
chance = moretrees.leafdecay_chance,
action = function(pos, node, active_object_count, active_object_count_wider)
if minetest.find_node_near(pos, moretrees.leafdecay_radius, "moretrees:fir_trunk") then return end
if minetest.find_node_near(pos, moretrees.leafdecay_radius, "ignore") then return end
process_drops(pos, node.name)
minetest.remove_node(pos)
nodeupdate(pos)
end
})
minetest.register_abm({
nodenames = "moretrees:palm_leaves",
interval = moretrees.leafdecay_delay,
chance = moretrees.leafdecay_chance,
action = function(pos, node, active_object_count, active_object_count_wider)
if minetest.find_node_near(pos, moretrees.palm_leafdecay_radius, "moretrees:palm_trunk") then return end
if minetest.find_node_near(pos, moretrees.palm_leafdecay_radius, "ignore") then return end
process_drops(pos, node.name)
minetest.remove_node(pos)
nodeupdate(pos)
end
})
end
if moretrees.enable_default_leafdecay then
minetest.register_abm({
nodenames = "default:leaves",
interval = moretrees.default_leafdecay_delay,
chance = moretrees.default_leafdecay_chance,
action = function(pos, node, active_object_count, active_object_count_wider)
if minetest.find_node_near(pos, moretrees.default_leafdecay_radius, "default:tree") then return end
if minetest.find_node_near(pos, moretrees.default_leafdecay_radius, "ignore") then return end
process_drops(pos, node.name)
minetest.remove_node(pos)
nodeupdate(pos)
end
})
end
if moretrees.enable_default_jungle_leafdecay then
minetest.register_abm({
nodenames = "default:jungleleaves",
interval = moretrees.default_jungle_leafdecay_delay,
chance = moretrees.default_jungle_leafdecay_chance,
action = function(pos, node, active_object_count, active_object_count_wider)
if minetest.find_node_near(pos, moretrees.default_jungle_leafdecay_radius, "default:jungletree") then return end
if minetest.find_node_near(pos, moretrees.default_jungle_leafdecay_radius, "ignore") then return end
process_drops(pos, node.name)
minetest.remove_node(pos)
nodeupdate(pos)
end
})
end

View File

@ -0,0 +1,73 @@
# Translation by Xanthin
### crafts.lua ###
Coconut Milk = Kokosnussmilch
Raw Coconut = Kokosnussfleisch
Acorn Muffin batter = Eichelmuffinteig
Acorn Muffin = Eichelmuffin
Roasted Spruce Cone Nuts = Geroestete Fichtenzapfen
Roasted Pine Cone Nuts = Geroestete Kiefernzapfen
Roasted Fir Cone Nuts = Geroestete Tannenzapfen
### node_defs.lua ###
Beech Tree Trunk = Buchenstamm
Apple Tree Trunk = Apfelbaumstamm
Oak Tree Trunk = Eichenstamm
Giant Sequoia Trunk = Riesenmammutbaumstamm
Birch Tree Trunk = Birkenstamm
Palm Tree Trunk = Palmenstamm
Spruce Tree Trunk = Fichtenstamm
Pine Tree Trunk = Kiefernstamm
Willow Tree Trunk = Weidenstamm
Rubber Tree Trunk = Gummibaumstamm
Jungle Tree Trunk = Tropenbaumstamm
Douglas Fir Trunk = Douglasienstamm
Beech Tree Planks = Buchebretter
Apple Tree Planks = Apfelbaumbretter
Oak Tree Planks = Eichenbretter
Giant Sequoia Planks = Riesenmammutbaumbretter
Birch Tree Planks = Birkebretter
Palm Tree Planks = Palmenbretter
Spruce Tree Planks = Fichtenbretter
Pine Tree Planks = Kiefernbretter
Willow Tree Planks = Weidenbretter
Rubber Tree Planks = Gummibaumbretter
Jungle Tree Planks = Tropenholzbretter
Douglas Fir Planks = Douglasienbretter
Beech Tree Sapling = Buchesetzling
Apple Tree Sapling = Apfelbaumsetzling
Oak Tree Sapling = Eichensetzling
Giant Sequoia Sapling = Riesenmammutbaumsetzling
Birch Tree Sapling = Birkensetzling
Palm Tree Sapling = Palmensetzling
Spruce Tree Sapling = Fichtensetzling
Pine Tree Sapling = Kiefernsetzling
Willow Tree Sapling = Weidensetzling
Rubber Tree Sapling = Gummibaumsetzling
Jungle Tree Sapling = Tropenbaumsetzling
Douglas Fir Sapling = Douglasiensetzling
Beech Tree Leaves = Buchenlaub
Apple Tree Leaves = Apfelbaumlaub
Oak Tree Leaves = Eichenlaub
Giant Sequoia Leaves = Riesenmammutbaumlaub
Birch Tree Leaves = Birkenlaub
Palm Tree Leaves = Palmenlaub
Spruce Tree Leaves = Fichtennadeln
Pine Tree Leaves = Kiefernnadeln
Willow Tree Leaves = Weidenlaub
Rubber Tree Leaves = Gummibaumlaub
Jungle Tree Leaves = Tropenbaumlaub
Douglas Fir Leaves = Douglasiennadeln
Acorn = Eichel
Coconut = Kokosnuss
Spruce Cone = Fichtenzapfen
Pine Cone = Kiefernzapfen
Fir Cone = Tannenzapfen
Jungle Sapling = Tropenbaumsetzling
Jungle Tree Leaves (Yellow) = Tropenbaumlaub (gelb)
Jungle Tree Leaves (Red) = Tropenbaumlaub (rot)
Douglas Fir Leaves (Bright) = Douglasiennadeln (breit)
Rubber Tree Trunk (Empty) = Gummibaumstamm (leer)
[Moretrees] Loaded (2013-02-11) = [Moretrees] geladen (2013-02-11)

View File

@ -0,0 +1,73 @@
# Template
### crafts.lua ###
Coconut Milk =
Raw Coconut =
Acorn Muffin batter =
Acorn Muffin =
Roasted Spruce Cone Nuts =
Roasted Pine Cone Nuts =
Roasted Fir Cone Nuts =
### node_defs.lua ###
Beech Tree Trunk =
Apple Tree Trunk =
Oak Tree Trunk =
Giant Sequoia Trunk =
Birch Tree Trunk =
Palm Tree Trunk =
Spruce Tree Trunk =
Pine Tree Trunk =
Willow Tree Trunk =
Rubber Tree Trunk =
Jungle Tree Trunk =
Douglas Fir Trunk =
Beech Tree Planks =
Apple Tree Planks =
Oak Tree Planks =
Giant Sequoia Planks =
Birch Tree Planks =
Palm Tree Planks =
Spruce Tree Planks =
Pine Tree Planks =
Willow Tree Planks =
Rubber Tree Planks =
Jungle Tree Planks =
Douglas Fir Planks =
Beech Tree Sapling =
Apple Tree Sapling =
Oak Tree Sapling =
Giant Sequoia Sapling =
Birch Tree Sapling =
Palm Tree Sapling =
Spruce Tree Sapling =
Pine Tree Sapling =
Willow Tree Sapling =
Rubber Tree Sapling =
Jungle Tree Sapling =
Douglas Fir Sapling =
Beech Tree Leaves =
Apple Tree Leaves =
Oak Tree Leaves =
Giant Sequoia Leaves =
Birch Tree Leaves =
Palm Tree Leaves =
Spruce Tree Leaves =
Pine Tree Leaves =
Willow Tree Leaves =
Rubber Tree Leaves =
Jungle Tree Leaves =
Douglas Fir Leaves =
Acorn =
Coconut =
Spruce Cone =
Pine Cone =
Fir Cone =
Jungle Sapling =
Jungle Tree Leaves (Yellow) =
Jungle Tree Leaves (Red) =
Douglas Fir Leaves (Bright) =
Rubber Tree Trunk (Empty) =
[Moretrees] Loaded (2013-02-11) =

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

@ -0,0 +1 @@
name = moretrees

View File

@ -1,18 +1,25 @@
local S = moretrees.intllib
moretrees.avoidnodes = {}
moretrees.treelist = {
{"beech", "Beech Tree"},
{"beech", "Beech Tree"},
{"apple_tree", "Apple Tree"},
{"oak", "Oak Tree", "acorn", "Acorn", {-0.2, -0.5, -0.2, 0.2, 0, 0.2}, 0.8 },
{"sequoia", "Giant Sequoia"},
{"birch", "Birch Tree"},
{"palm", "Palm Tree", "coconut", "Coconut", {-0.2, -0.5, -0.2, 0.2, 0, 0.2}, 1.0 },
{"spruce", "Spruce Tree", "spruce_cone", "Spruce Cone", {-0.2, -0.5, -0.2, 0.2, 0, 0.2}, 0.8 },
{"pine", "Pine Tree", "pine_cone", "Pine Cone", {-0.2, -0.5, -0.2, 0.2, 0, 0.2}, 0.8 },
{"willow", "Willow Tree"},
{"oak", "Oak Tree", "acorn", "Acorn", {-0.2, -0.5, -0.2, 0.2, 0, 0.2}, 0.8 },
{"sequoia", "Giant Sequoia"},
{"birch", "Birch Tree"},
{"palm", "Palm Tree", "palm_fruit_trunk_gen", "Palm Tree", {-0.2, -0.5, -0.2, 0.2, 0, 0.2}, 1.0 },
{"date_palm", "Date Palm Tree", "date_palm_fruit_trunk", "Date Palm Tree", {0, 0, 0, 0, 0, 0}, 0.0 },
{"spruce", "Spruce Tree", "spruce_cone", "Spruce Cone", {-0.2, -0.5, -0.2, 0.2, 0, 0.2}, 0.8 },
{"cedar", "Cedar Tree", "cedar_cone", "Cedar Cone", {-0.2, -0.5, -0.2, 0.2, 0, 0.2}, 0.8 },
{"poplar", "Poplar Tree"},
{"poplar_small", "Poplar Tree"},
{"willow", "Willow Tree"},
{"rubber_tree", "Rubber Tree"},
{"jungletree", "Jungle Tree"},
{"fir", "Douglas Fir", "fir_cone", "Fir Cone", {-0.2, -0.5, -0.2, 0.2, 0, 0.2}, 0.8 },
{"fir", "Douglas Fir", "fir_cone", "Fir Cone", {-0.2, -0.5, -0.2, 0.2, 0, 0.2}, 0.8 },
{"jungletree", "Jungle Tree", nil, nil, nil, nil, "default_junglesapling.png" },
{"acacia", "Acacia Tree", nil, nil, nil, nil, "default_acacia_sapling.png" },
}
local dirs1 = { 21, 20, 23, 22, 21 }
@ -20,46 +27,40 @@ local dirs2 = { 12, 9, 18, 7, 12 }
local dirs3 = { 14, 11, 16, 5, 14 }
local moretrees_new_leaves_drawtype = "allfaces_optional"
local moretrees_new_leaves_extension = ".png"
local moretrees_plantlike_leaves_visual_scale = 1
if moretrees.plantlike_leaves then
moretrees_new_leaves_drawtype = "plantlike"
moretrees_new_leaves_extension = "_plantlike.png"
moretrees_plantlike_leaves_visual_scale = 1.189
end
local new_default_leaves = moretrees:clone_node("default:leaves")
if moretrees.enable_default_leafdecay then
new_default_leaves.groups = {snappy=3, flammable=2, leaves=1}
end
if moretrees.plantlike_leaves then
new_default_leaves.inventory_image = minetest.inventorycube("default_leaves.png")
new_default_leaves.drawtype = "plantlike"
new_default_leaves.visual_scale = moretrees_plantlike_leaves_visual_scale
new_default_leaves.tiles = {"default_leaves_plantlike.png"}
else
new_default_leaves.waving = 1
end
if moretrees.enable_default_leafdecay or moretrees.plantlike_leaves then
minetest.register_node(":default:leaves", new_default_leaves)
end
-- redefine default leaves to handle plantlike and/or leaf decay options
local new_default_jungleleaves = moretrees:clone_node("default:jungleleaves")
if moretrees.enable_default_leafdecay then
new_default_jungleleaves.groups = {snappy=3, flammable=2, leaves=1}
end
if moretrees.plantlike_leaves then
new_default_jungleleaves.inventory_image = minetest.inventorycube("default_jungleleaves.png")
new_default_jungleleaves.drawtype = "plantlike"
new_default_jungleleaves.visual_scale = moretrees_plantlike_leaves_visual_scale
new_default_jungleleaves.tiles = {"default_jungleleaves_plantlike.png"}
else
new_default_jungleleaves.waving = 1
end
if moretrees.enable_default_leafdecay or moretrees.plantlike_leaves then
minetest.register_node(":default:jungleleaves", new_default_jungleleaves)
end
if moretrees.plantlike_leaves then
minetest.override_item("default:leaves", {
inventory_image = minetest.inventorycube("default_leaves.png"),
drawtype = "plantlike",
visual_scale = 1.189
})
else
minetest.override_item("default:leaves", {
waving = 1
})
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 = 1.189
})
else
minetest.override_item("default:jungleleaves", {
waving = 1
})
end
for i in ipairs(moretrees.treelist) do
local treename = moretrees.treelist[i][1]
@ -69,10 +70,17 @@ for i in ipairs(moretrees.treelist) do
local selbox = moretrees.treelist[i][5]
local vscale = moretrees.treelist[i][6]
if treename ~= "jungletree" then -- the default game provides jungle tree trunk/planks nodes.
local saptex = moretrees.treelist[i][7]
if treename ~= "jungletree" -- the default game provides jungle tree, acacia, and pine trunk/planks nodes.
and treename ~= "acacia"
and treename ~= "poplar_small"
and treename ~= "pine" then
saptex = "moretrees_"..treename.."_sapling.png"
minetest.register_node("moretrees:"..treename.."_trunk", {
description = treedesc.." Trunk",
description = S(treedesc.." Trunk"),
tiles = {
"moretrees_"..treename.."_trunk_top.png",
"moretrees_"..treename.."_trunk_top.png",
@ -86,7 +94,7 @@ for i in ipairs(moretrees.treelist) do
})
minetest.register_node("moretrees:"..treename.."_planks", {
description = treedesc.." Planks",
description = S(treedesc.." Planks"),
tiles = {"moretrees_"..treename.."_wood.png"},
is_ground_content = true,
groups = {snappy=1,choppy=2,oddly_breakable_by_hand=2,flammable=3,wood=1},
@ -94,10 +102,10 @@ for i in ipairs(moretrees.treelist) do
})
minetest.register_node("moretrees:"..treename.."_sapling", {
description = treedesc.." Sapling",
description = S(treedesc.." Sapling"),
drawtype = "plantlike",
tiles = {"moretrees_"..treename.."_sapling.png"},
inventory_image = "moretrees_"..treename.."_sapling.png",
tiles = {saptex},
inventory_image = saptex,
paramtype = "light",
paramtype2 = "waving",
walkable = false,
@ -109,32 +117,18 @@ for i in ipairs(moretrees.treelist) do
sounds = default.node_sound_defaults(),
})
minetest.register_node("moretrees:"..treename.."_sapling_ongen", {
description = treedesc.." Sapling",
drawtype = "plantlike",
tiles = {"moretrees_"..treename.."_sapling.png"},
inventory_image = "moretrees_"..treename.."_sapling.png",
paramtype = "light",
paramtype2 = "waving",
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,not_in_creative_inventory=1,sapling=1},
sounds = default.node_sound_defaults(),
drop = "moretrees:"..treename.."_sapling"
})
-- 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
local moretrees_leaves_inventory_image = nil
@ -147,14 +141,14 @@ for i in ipairs(moretrees.treelist) do
end
minetest.register_node("moretrees:"..treename.."_leaves", {
description = treedesc.." Leaves",
description = S(treedesc.." Leaves"),
drawtype = moretrees_new_leaves_drawtype,
waving = moretrees_new_leaves_waving,
visual_scale = moretrees_plantlike_leaves_visual_scale,
tiles = { "moretrees_"..treename.."_leaves"..moretrees_new_leaves_extension },
tiles = { "moretrees_"..treename.."_leaves.png" },
inventory_image = moretrees_leaves_inventory_image,
paramtype = "light",
groups = {snappy=3, flammable=2, leaves=1, moretrees_leaves=1},
groups = {snappy = 3, flammable = 2, leaves = 1, moretrees_leaves = 1, leafdecay = decay},
sounds = default.node_sound_leaves_defaults(),
drop = {
@ -166,117 +160,86 @@ for i in ipairs(moretrees.treelist) do
},
})
if minetest.get_modpath("moreblocks") and moretrees.enable_stairsplus then
if moretrees.enable_stairs then
if minetest.get_modpath("moreblocks") then
register_stair(
"moretrees",
treename.."_trunk",
"moretrees:"..treename.."_trunk",
{ snappy=1,choppy=2,oddly_breakable_by_hand=1,flammable=2, not_in_creative_inventory=1, tree_stair=1 },
{ "moretrees_"..treename.."_trunk_top.png",
"moretrees_"..treename.."_trunk_top.png",
"moretrees_"..treename.."_trunk.png"
},
treedesc.." Trunk",
treename.."_trunk",
0
)
-- stairsplus:register_all(modname, subname, recipeitem, {fields})
register_slab(
"moretrees",
treename.."_trunk",
"moretrees:"..treename.."_trunk",
{ snappy=1,choppy=2,oddly_breakable_by_hand=1,flammable=2, not_in_creative_inventory=1, tree_slab=1 },
{ "moretrees_"..treename.."_trunk_top.png",
"moretrees_"..treename.."_trunk_top.png",
"moretrees_"..treename.."_trunk.png"
},
treedesc.." Trunk",
treename.."_trunk",
0
)
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 = S(treedesc.." Trunk"),
drop = treename.."_trunk",
}
)
register_panel(
"moretrees",
treename.."_trunk",
"moretrees:"..treename.."_trunk",
{ snappy=1,choppy=2,oddly_breakable_by_hand=1,flammable=2, not_in_creative_inventory=1, tree_panel=1 },
{ "moretrees_"..treename.."_trunk_top.png",
"moretrees_"..treename.."_trunk_top.png",
"moretrees_"..treename.."_trunk.png"
},
treedesc.." Trunk",
treename.."_trunk",
0
)
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 = S(treedesc.." 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"
},
S(treedesc.." Trunk Stair"),
S(treedesc.." Trunk Slab"),
default.node_sound_wood_defaults()
)
register_micro(
"moretrees",
treename.."_trunk",
"moretrees:"..treename.."_trunk",
{ snappy=1,choppy=2,oddly_breakable_by_hand=1,flammable=2, not_in_creative_inventory=1, tree_micro=1 },
{ "moretrees_"..treename.."_trunk_top.png",
"moretrees_"..treename.."_trunk_top.png",
"moretrees_"..treename.."_trunk.png"
},
treedesc.." Trunk",
treename.."_trunk",
0
)
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" },
S(treedesc.." Planks Stair"),
S(treedesc.." Planks Slab"),
default.node_sound_wood_defaults()
)
register_stair(
"moretrees",
treename.."_planks",
"moretrees:"..treename.."_planks",
{ snappy=1,choppy=2,oddly_breakable_by_hand=2,flammable=3, not_in_creative_inventory=1, wood_stair=1 },
{ "moretrees_"..treename.."_wood.png" },
treedesc.." Planks",
treename.."_planks",
0
)
register_slab(
"moretrees",
treename.."_planks",
"moretrees:"..treename.."_planks",
{ snappy=1,choppy=2,oddly_breakable_by_hand=2,flammable=3, not_in_creative_inventory=1, wood_slab=1 },
{ "moretrees_"..treename.."_wood.png" },
treedesc.." Planks",
treename.."_planks",
0
)
register_panel(
"moretrees",
treename.."_planks",
"moretrees:"..treename.."_planks",
{ snappy=1,choppy=2,oddly_breakable_by_hand=2,flammable=3, not_in_creative_inventory=1, wood_panel=1 },
{ "moretrees_"..treename.."_wood.png" },
treedesc.." Planks",
treename.."_planks",
0
)
register_micro(
"moretrees",
treename.."_planks",
"moretrees:"..treename.."_planks",
{ snappy=1,choppy=2,oddly_breakable_by_hand=2,flammable=3, not_in_creative_inventory=1, wood_micro=1 },
{ "moretrees_"..treename.."_wood.png" },
treedesc.." Planks",
treename.."_planks",
0
)
table.insert(circular_saw.known_stairs, "moretrees:"..treename.."_trunk")
table.insert(circular_saw.known_stairs, "moretrees:"..treename.."_planks")
end
end
end
minetest.register_node("moretrees:"..treename.."_sapling_ongen", {
description = S(treedesc.." Sapling"),
drawtype = "plantlike",
tiles = {saptex},
inventory_image = saptex,
paramtype = "light",
paramtype2 = "waving",
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,not_in_creative_inventory=1,sapling=1},
sounds = default.node_sound_defaults(),
drop = "moretrees:"..treename.."_sapling"
})
if fruit then
minetest.register_node("moretrees:"..fruit, {
description = fruitdesc,
description = S(fruitdesc),
drawtype = "plantlike",
tiles = { "moretrees_"..fruit..".png" },
inventory_image = "moretrees_"..fruit..".png^[transformR180",
@ -313,48 +276,48 @@ for i in ipairs(moretrees.treelist) do
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_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"
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:
minetest.register_node("moretrees:jungletree_sapling", {
description = "Jungle Sapling",
drawtype = "plantlike",
visual_scale = 1.0,
tiles = {"default_junglesapling.png"},
inventory_image = "default_junglesapling.png",
wield_image = "default_junglesapling.png",
paramtype = "light",
paramtype2 = "waving",
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 = default.node_sound_leaves_defaults(),
})
minetest.register_node("moretrees:jungletree_sapling_ongen", {
description = "Jungle Sapling",
drawtype = "plantlike",
visual_scale = 1.0,
tiles = {"default_junglesapling.png"},
inventory_image = "default_junglesapling.png",
wield_image = "default_junglesapling.png",
paramtype = "light",
paramtype2 = "waving",
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,not_in_creative_inventory=1,sapling=1},
sounds = default.node_sound_leaves_defaults(),
drop = "moretrees:jungletree_sapling"
})
local jungleleaves = {"green","yellow","red"}
local jungleleavesnames = {"Green", "Yellow", "Red"}
for color = 1, 3 do
local jungleleaves = {"yellow","red"}
local jungleleavesnames = {"Yellow", "Red"}
for color = 1, #jungleleaves do
local leave_name = "moretrees:jungletree_leaves_"..jungleleaves[color]
local moretrees_leaves_inventory_image = nil
@ -366,18 +329,18 @@ for color = 1, 3 do
end
minetest.register_node(leave_name, {
description = "Jungle Tree Leaves ("..jungleleavesnames[color]..")",
description = S("Jungle Tree Leaves ("..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]..moretrees_new_leaves_extension},
tiles = {"moretrees_jungletree_leaves_"..jungleleaves[color]..".png"},
inventory_image = moretrees_leaves_inventory_image,
paramtype = "light",
groups = {snappy=3, flammable=2, leaves=1, moretrees_leaves=1},
groups = {snappy = 3, flammable = 2, leaves = 1, moretrees_leaves = 1, leafdecay = moretrees.leafdecay_radius },
drop = {
max_items = 1,
items = {
{items = {'moretrees:jungletree_sapling'}, rarity = 100 },
{items = {"default:junglesapling"}, rarity = 100 },
{items = {"moretrees:jungletree_leaves_"..jungleleaves[color]} }
}
},
@ -397,43 +360,44 @@ 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 = "Douglas Fir Leaves (Bright)",
tiles = { "moretrees_fir_leaves_bright"..moretrees_new_leaves_extension },
description = S("Douglas Fir Leaves (Bright)"),
tiles = { "moretrees_fir_leaves_bright.png" },
inventory_image = moretrees_leaves_inventory_image,
paramtype = "light",
groups = {snappy=3, flammable=2, leaves=1, moretrees_leaves=1 },
groups = {snappy = 3, flammable = 2, leaves = 1, moretrees_leaves = 1, leafdecay = moretrees.leafdecay_radius },
drop = {
max_items = 1,
items = {
{items = {'moretrees:fir_sapling'}, rarity = 100 },
{items = {'moretrees:fir_leaves'} }
{items = {'moretrees:fir_leaves_bright'} }
}
},
sounds = default.node_sound_leaves_defaults()
})
if moretrees.enable_redefine_apple then
local new_default_apple = moretrees:clone_node("default:apple")
new_default_apple.groups.attached_node = 1
minetest.register_node(":default:apple", new_default_apple)
local appledef = moretrees.clone_node("default:apple")
appledef.groups.attached_node = 1
minetest.register_node(":default:apple", appledef)
end
table.insert(moretrees.avoidnodes, "default:jungletree")
table.insert(moretrees.avoidnodes, "moretrees:jungletree_trunk")
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, "moretrees:jungle_tree_sapling")
table.insert(moretrees.avoidnodes, "moretrees:jungle_tree_sapling_ongen")
table.insert(moretrees.avoidnodes, "default:pine_sapling")
table.insert(moretrees.avoidnodes, "default:acacia_sapling")
end
-- "empty" (tapped) rubber tree nodes
minetest.register_node("moretrees:rubber_tree_trunk_empty", {
description = "Rubber Tree Trunk (Empty)",
description = S("Rubber Tree Trunk (Empty)"),
tiles = {
"moretrees_rubber_tree_trunk_top.png",
"moretrees_rubber_tree_trunk_top.png",
@ -444,10 +408,6 @@ minetest.register_node("moretrees:rubber_tree_trunk_empty", {
sounds = default.node_sound_wood_defaults(),
paramtype2 = "facedir",
on_place = minetest.rotate_node,
after_place_node = function(pos, placer, itemstack)
local meta = minetest.get_meta(pos)
meta:set_int("placed", 1)
end
})
minetest.register_abm({
@ -461,33 +421,57 @@ minetest.register_abm({
end,
})
-- For compatibility with old nodes and recently-changed nodes.
-- 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.
minetest.register_alias("technic:rubber_tree_full", "moretrees:rubber_tree_trunk")
minetest.register_alias("farming_plus:rubber_tree_full", "moretrees:rubber_tree_trunk")
local jungle_tree = moretrees.clone_node("default:jungletree")
minetest.register_node("moretrees:jungletree_trunk", jungle_tree)
minetest.register_alias("technic:rubber_leaves", "moretrees:rubber_tree_leaves")
minetest.register_alias("farming_plus:rubber_leaves", "moretrees:rubber_tree_leaves")
-- For compatibility with old nodes, recently-changed nodes, and default nodes
minetest.register_alias("farming_plus:rubber_sapling", "moretrees:rubber_tree_sapling")
minetest.register_alias("technic:rubber_tree_sapling", "moretrees:rubber_tree_sapling")
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("default:junglesapling","moretrees:jungletree_sapling")
minetest.register_alias("moretrees:jungletree_trunk_sideways", "moreblocks:horizontal_jungle_tree")
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("jungletree:leaves_green", "moretrees:jungletree_leaves_green")
minetest.register_alias("jungletree:leaves_red", "moretrees:jungletree_leaves_red")
minetest.register_alias("jungletree:leaves_yellow", "moretrees:jungletree_leaves_yellow")
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("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("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("jungletree:leaves_green", "default:jungleleaves")
minetest.register_alias("jungletree:leaves_red", "moretrees:jungletree_leaves_red")
minetest.register_alias("jungletree:leaves_yellow", "moretrees:jungletree_leaves_yellow")
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:dates", "moretrees:dates_f4")

View File

@ -7,8 +7,8 @@ for i in ipairs(moretrees.treelist) do
if treename ~= "birch" and treename ~= "spruce" and treename ~= "fir" and treename ~= "jungletree" then
plantslib:dbg(dump(moretrees[tree_biome].surface))
plantslib:grow_plants({
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",
@ -16,7 +16,7 @@ for i in ipairs(moretrees.treelist) do
grow_function = moretrees[tree_model],
})
plantslib:grow_plants({
biome_lib:grow_plants({
grow_delay = 2,
grow_chance = 30,
grow_plant = "moretrees:"..treename.."_sapling_ongen",
@ -27,67 +27,67 @@ for i in ipairs(moretrees.treelist) do
end
end
plantslib:grow_plants({
biome_lib:grow_plants({
grow_delay = moretrees.sapling_interval,
grow_chance = moretrees.sapling_chance,
grow_plant = "moretrees:birch_sapling",
grow_nodes = moretrees.birch_biome.surface,
grow_function = "moretrees:grow_birch"
grow_function = "moretrees.grow_birch"
})
plantslib:grow_plants({
biome_lib:grow_plants({
grow_delay = 2,
grow_chance = 30,
grow_plant = "moretrees:birch_sapling_ongen",
grow_nodes = moretrees.birch_biome.surface,
grow_function = "moretrees:grow_birch"
grow_function = "moretrees.grow_birch"
})
plantslib:grow_plants({
biome_lib:grow_plants({
grow_delay = moretrees.sapling_interval,
grow_chance = moretrees.sapling_chance,
grow_plant = "moretrees:spruce_sapling",
grow_nodes = moretrees.spruce_biome.surface,
grow_function = "moretrees:grow_spruce"
grow_function = "moretrees.grow_spruce"
})
plantslib:grow_plants({
biome_lib:grow_plants({
grow_delay = 2,
grow_chance = 30,
grow_plant = "moretrees:spruce_sapling_ongen",
grow_nodes = moretrees.spruce_biome.surface,
grow_function = "moretrees:grow_spruce"
grow_function = "moretrees.grow_spruce"
})
plantslib:grow_plants({
biome_lib:grow_plants({
grow_delay = moretrees.sapling_interval,
grow_chance = moretrees.sapling_chance,
grow_plant = "moretrees:fir_sapling",
grow_nodes = moretrees.fir_biome.surface,
grow_function = "moretrees:grow_fir"
grow_function = "moretrees.grow_fir"
})
plantslib:grow_plants({
biome_lib:grow_plants({
grow_delay = 2,
grow_chance = 30,
grow_plant = "moretrees:fir_sapling_ongen",
grow_nodes = moretrees.fir_biome.surface,
grow_function = "moretrees:grow_fir"
grow_function = "moretrees.grow_fir"
})
plantslib:grow_plants({
biome_lib:grow_plants({
grow_delay = moretrees.sapling_interval,
grow_chance = moretrees.sapling_chance,
grow_plant = "moretrees:jungletree_sapling",
grow_plant = "default:junglesapling",
grow_nodes = moretrees.jungletree_biome.surface,
grow_function = "moretrees:grow_jungletree"
grow_function = "moretrees.grow_jungletree"
})
plantslib:grow_plants({
biome_lib:grow_plants({
grow_delay = 2,
grow_chance = 30,
grow_plant = "moretrees:jungletree_sapling_ongen",
grow_nodes = moretrees.jungletree_biome.surface,
grow_function = "moretrees:grow_jungletree"
grow_function = "moretrees.grow_jungletree"
})

View File

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

Binary file not shown.

After

Width:  |  Height:  |  Size: 101 KiB

Binary file not shown.

Before

Width:  |  Height:  |  Size: 390 B

Binary file not shown.

Before

Width:  |  Height:  |  Size: 404 B

Binary file not shown.

Before

Width:  |  Height:  |  Size: 385 B

After

Width:  |  Height:  |  Size: 351 B

Binary file not shown.

Before

Width:  |  Height:  |  Size: 338 B

Binary file not shown.

Before

Width:  |  Height:  |  Size: 375 B

After

Width:  |  Height:  |  Size: 183 B

Binary file not shown.

Before

Width:  |  Height:  |  Size: 1.1 KiB

After

Width:  |  Height:  |  Size: 1.0 KiB

Binary file not shown.

Before

Width:  |  Height:  |  Size: 525 B

After

Width:  |  Height:  |  Size: 503 B

Binary file not shown.

Before

Width:  |  Height:  |  Size: 481 B

After

Width:  |  Height:  |  Size: 464 B

Binary file not shown.

Before

Width:  |  Height:  |  Size: 220 B

After

Width:  |  Height:  |  Size: 201 B

Binary file not shown.

Before

Width:  |  Height:  |  Size: 404 B

Binary file not shown.

Before

Width:  |  Height:  |  Size: 372 B

After

Width:  |  Height:  |  Size: 177 B

Binary file not shown.

Before

Width:  |  Height:  |  Size: 947 B

After

Width:  |  Height:  |  Size: 926 B

Binary file not shown.

Before

Width:  |  Height:  |  Size: 197 B

After

Width:  |  Height:  |  Size: 175 B

Binary file not shown.

Before

Width:  |  Height:  |  Size: 496 B

After

Width:  |  Height:  |  Size: 459 B

Binary file not shown.

Before

Width:  |  Height:  |  Size: 433 B

Binary file not shown.

Before

Width:  |  Height:  |  Size: 465 B

After

Width:  |  Height:  |  Size: 208 B

Binary file not shown.

Before

Width:  |  Height:  |  Size: 832 B

After

Width:  |  Height:  |  Size: 811 B

Binary file not shown.

Before

Width:  |  Height:  |  Size: 1.1 KiB

After

Width:  |  Height:  |  Size: 1.0 KiB

Binary file not shown.

After

Width:  |  Height:  |  Size: 315 B

Binary file not shown.

After

Width:  |  Height:  |  Size: 205 B

Binary file not shown.

After

Width:  |  Height:  |  Size: 369 B

Binary file not shown.

After

Width:  |  Height:  |  Size: 202 B

Binary file not shown.

After

Width:  |  Height:  |  Size: 1.0 KiB

Binary file not shown.

After

Width:  |  Height:  |  Size: 451 B

View File

Before

Width:  |  Height:  |  Size: 648 B

After

Width:  |  Height:  |  Size: 648 B

Binary file not shown.

Before

Width:  |  Height:  |  Size: 985 B

After

Width:  |  Height:  |  Size: 963 B

Binary file not shown.

After

Width:  |  Height:  |  Size: 877 B

Binary file not shown.

After

Width:  |  Height:  |  Size: 429 B

Binary file not shown.

After

Width:  |  Height:  |  Size: 1009 B

Binary file not shown.

Before

Width:  |  Height:  |  Size: 275 B

After

Width:  |  Height:  |  Size: 199 B

Binary file not shown.

After

Width:  |  Height:  |  Size: 2.1 KiB

Binary file not shown.

After

Width:  |  Height:  |  Size: 685 B

Binary file not shown.

After

Width:  |  Height:  |  Size: 608 B

Binary file not shown.

After

Width:  |  Height:  |  Size: 695 B

Binary file not shown.

After

Width:  |  Height:  |  Size: 450 B

Binary file not shown.

After

Width:  |  Height:  |  Size: 757 B

Binary file not shown.

After

Width:  |  Height:  |  Size: 261 B

Binary file not shown.

After

Width:  |  Height:  |  Size: 1.2 KiB

Binary file not shown.

After

Width:  |  Height:  |  Size: 673 B

Binary file not shown.

After

Width:  |  Height:  |  Size: 735 B

Binary file not shown.

After

Width:  |  Height:  |  Size: 9.2 KiB

Binary file not shown.

After

Width:  |  Height:  |  Size: 3.8 KiB

Binary file not shown.

After

Width:  |  Height:  |  Size: 4.0 KiB

Binary file not shown.

After

Width:  |  Height:  |  Size: 8.9 KiB

Binary file not shown.

After

Width:  |  Height:  |  Size: 8.1 KiB

Binary file not shown.

After

Width:  |  Height:  |  Size: 9.0 KiB

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