Big code reorganisation, added mgv6 compatibility.
11
README.md
@ -5,7 +5,7 @@ an old 8bits Apple ][ game named "Below the root".
|
||||
|
||||
**Don't use this mod on any server!** It is in a very experimental stage of development.
|
||||
|
||||
![Presentation image of Grunds](screenshot.png)
|
||||
![Presentation image of Grunds](screenshot.jpg)
|
||||
|
||||
**Version**: Alpha
|
||||
|
||||
@ -20,8 +20,11 @@ an old 8bits Apple ][ game named "Below the root".
|
||||
To test Grunds:
|
||||
* create a new world
|
||||
* select *minetest_game* game
|
||||
* choose *v7* map generator (not available on other mapgens yet)
|
||||
* choose *v6*, *v7* or *valleys* map generator (not available on other mapgens)
|
||||
* enable *grunds* mod
|
||||
|
||||
To find a Grund biome to explore, type */find_biome grunds*. This command will
|
||||
show random coordinates in a grund biome. Use */teleport* to go there.
|
||||
To find a Grund biome to explore, type `/find_biome grunds`. This command will
|
||||
show random coordinates in a grund biome. Use `/teleport` to go there.
|
||||
|
||||
A tree can be grown using command `/grow_grund`. The tree will start at the
|
||||
ground level right under (or above) your position.
|
||||
|
@ -1,5 +1,5 @@
|
||||
--[[
|
||||
Grunds - Giant trees biome for Minetest
|
||||
Big tree lib - Giant trees library for Minetest
|
||||
(c) Pierre-Yves Rollo
|
||||
|
||||
This program is free software: you can redistribute it and/or modify
|
||||
@ -16,8 +16,17 @@
|
||||
along with this program. If not, see <http://www.gnu.org/licenses/>.
|
||||
--]]
|
||||
|
||||
-- =============================================================================
|
||||
--
|
||||
-- TREE CREATION
|
||||
--
|
||||
-- Here are function that creates a tree made of segment and tufts, according
|
||||
-- to registered tree settings.
|
||||
--
|
||||
-- =============================================================================
|
||||
|
||||
local pi, cos, sin, sqrt = math.pi, math.cos, math.sin, math.sqrt
|
||||
local max, random = math.max, math.random
|
||||
local ceil, floor, max, random = math.ceil, math.floor, math.max, math.random
|
||||
|
||||
-- Add two random numbers, make it a bit gaussian
|
||||
local function rnd()
|
||||
@ -99,9 +108,21 @@ local function rotate(axis, angle, vect)
|
||||
}
|
||||
end
|
||||
|
||||
function grunds.make_tree(startpos, params, seed)
|
||||
-- Creates a tree made out of segments and tufts. This tree can be rendered.
|
||||
function btlib.build_tree(startpos, params, seed)
|
||||
if seed then math.randomseed(seed) end
|
||||
|
||||
local c_bark = minetest.get_content_id(params.nodes.bark_node)
|
||||
local c_wood_1 = minetest.get_content_id(params.nodes.tree_1_node)
|
||||
local c_wood_2 = minetest.get_content_id(params.nodes.tree_2_node)
|
||||
local c_moisty_barks = {
|
||||
minetest.get_content_id(params.nodes.moisty_bark_nodes[1]),
|
||||
minetest.get_content_id(params.nodes.moisty_bark_nodes[2]),
|
||||
minetest.get_content_id(params.nodes.moisty_bark_nodes[3]),
|
||||
}
|
||||
local c_leaves = minetest.get_content_id(params.nodes.leave_node)
|
||||
local c_twigs = minetest.get_content_id(params.nodes.twigs_node)
|
||||
|
||||
local segments = {}
|
||||
local tufts = {}
|
||||
|
||||
@ -164,6 +185,11 @@ function grunds.make_tree(startpos, params, seed)
|
||||
|
||||
-- Create segment
|
||||
local segment = new_segment(pos, pos2, thickness, thickness2, type)
|
||||
segment.cid_bark = c_bark
|
||||
segment.cid_wood_1 = c_wood_1
|
||||
segment.cid_wood_2 = c_wood_2
|
||||
segment.cid_moisty_barks = c_moisty_barks
|
||||
|
||||
segments[ #segments + 1 ] = segment
|
||||
|
||||
if thickness2 < params.thinckess_min
|
||||
@ -171,6 +197,8 @@ function grunds.make_tree(startpos, params, seed)
|
||||
-- Branch ends
|
||||
if params.tuft then
|
||||
local tuft = new_tuft(pos2, params.tuft.radius, params.tuft.density)
|
||||
tuft.cid_leaves = c_leaves
|
||||
tuft.cid_twigs = c_twigs
|
||||
tufts[ #tufts + 1 ] = tuft
|
||||
end
|
||||
else
|
||||
@ -201,7 +229,13 @@ function grunds.make_tree(startpos, params, seed)
|
||||
|
||||
-- Segment
|
||||
local pos = vector.add(startpos, vector.multiply(dirax, length))
|
||||
segments[1] = new_segment(startpos, pos, thickness, thickness_top, "trunk")
|
||||
|
||||
local segment = new_segment(startpos, pos, thickness, thickness_top, "trunk")
|
||||
segment.cid_bark = c_bark
|
||||
segment.cid_wood_1 = c_wood_1
|
||||
segment.cid_wood_2 = c_wood_2
|
||||
segment.cid_moisty_barks = c_moisty_barks
|
||||
segments[1] = segment
|
||||
|
||||
-- Branches and roots
|
||||
---------------------
|
||||
@ -218,9 +252,41 @@ function grunds.make_tree(startpos, params, seed)
|
||||
}
|
||||
end
|
||||
|
||||
function grunds.intersects(b, minp, maxp)
|
||||
function btlib.intersects(b, minp, maxp)
|
||||
return
|
||||
b.minp.x <= maxp.x and b.maxp.x >= minp.x and
|
||||
b.minp.y <= maxp.y and b.maxp.y >= minp.y and
|
||||
b.minp.z <= maxp.z and b.maxp.z >= minp.z
|
||||
end
|
||||
|
||||
local function adjust_minmaxp(minp, maxp, boxes)
|
||||
for _, b in pairs(boxes) do
|
||||
if not minp.x or minp.x > b.minp.x then
|
||||
minp.x = b.minp.x
|
||||
end
|
||||
if not minp.y or minp.y > b.minp.y then
|
||||
minp.y = b.minp.y
|
||||
end
|
||||
if not minp.z or minp.z > b.minp.z then
|
||||
minp.z = b.minp.z
|
||||
end
|
||||
if not maxp.x or maxp.x < b.maxp.x then
|
||||
maxp.x = b.maxp.x
|
||||
end
|
||||
if not maxp.y or maxp.y < b.maxp.y then
|
||||
maxp.y = b.maxp.y
|
||||
end
|
||||
if not maxp.z or maxp.z < b.maxp.z then
|
||||
maxp.z = b.maxp.z
|
||||
end
|
||||
end
|
||||
end
|
||||
|
||||
function btlib.get_minmaxp(tree)
|
||||
local minp, maxp = {}, {}
|
||||
adjust_minmaxp(minp, maxp, tree.segments or {})
|
||||
adjust_minmaxp(minp, maxp, tree.tufts or {})
|
||||
return
|
||||
{ x = floor(minp.x), y = floor(minp.y), z = floor(minp.z) },
|
||||
{ x = ceil(maxp.x), y = ceil(maxp.y), z = ceil(maxp.z) }
|
||||
end
|
25
bigtreelib/init.lua
Normal file
@ -0,0 +1,25 @@
|
||||
--[[
|
||||
Big tree lib - Giant trees library for Minetest
|
||||
(c) Pierre-Yves Rollo
|
||||
|
||||
This program 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 program 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 General Public License for more details.
|
||||
|
||||
You should have received a copy of the GNU General Public License
|
||||
along with this program. If not, see <http://www.gnu.org/licenses/>.
|
||||
--]]
|
||||
|
||||
btlib = {}
|
||||
btlib.name = minetest.get_current_modname()
|
||||
btlib.path = minetest.get_modpath(minetest.get_current_modname())
|
||||
|
||||
dofile(btlib.path .. "/register.lua")
|
||||
dofile(btlib.path .. "/build.lua")
|
||||
dofile(btlib.path .. "/render.lua")
|
2
bigtreelib/mod.conf
Normal file
@ -0,0 +1,2 @@
|
||||
name = bigtreelib
|
||||
description = A library for building large tree structures
|
78
bigtreelib/notes.md
Normal file
@ -0,0 +1,78 @@
|
||||
# Geometric formulas
|
||||
|
||||
Here are some geometric formulas used in this lib. Some references can be found
|
||||
in code ([\#1], [\#2], ...).
|
||||
|
||||
## Lines
|
||||
|
||||
Spatial representation of a straight line [\#1]:
|
||||
```
|
||||
{
|
||||
x = vx * t + px
|
||||
y = vy * t + py
|
||||
z = vz * t + pz
|
||||
}
|
||||
```
|
||||
|
||||
* `t` is the "parameter". `(x, y, z)` is on line if a `t` exists.
|
||||
* `(vx, vy, vz)` is a vector along the line direction.
|
||||
* `(px, py, pz)` is one of the line point.
|
||||
|
||||
This formula gives coordinates of point from parameter.
|
||||
|
||||
### Segments
|
||||
|
||||
Our segments are quite simple if we take starting point as `(px, py, pz)` and
|
||||
segment vector (from start to end) as `(vx, vy, vz)`.
|
||||
|
||||
The segment is constitued of every point for `t` varying from 0.0 to 1.0.
|
||||
|
||||
### Nearest point
|
||||
|
||||
To determine the parameter of nearest point of line to position `(x0, y0, z0)` is
|
||||
given by:
|
||||
```
|
||||
t = (vx, vy, vz) * ((x0, y0, z0) - (px, py, pz)) / len((vx, vy, vz))
|
||||
```
|
||||
So:
|
||||
```
|
||||
t = (vx * (x0 - px) + vy * (y0 - py) + vz * (z0 + pz)) / (vx² + vy² +vz²)
|
||||
```
|
||||
|
||||
Quotient is not depending on (x0, y0, z0) so it can be computed once when
|
||||
creating segment. Final formula is [\#2] :
|
||||
|
||||
```
|
||||
t = (vx * (x0 - px) + vy * (y0 - py) + vz * (z0 + pz)) * k
|
||||
```
|
||||
|
||||
with `k = 1 / (vx² + vy² +vz²)`
|
||||
|
||||
## Thickness
|
||||
|
||||
Thickness is a simple linear variation from one end of the segment to the other.
|
||||
Formula has this form [\#3]:
|
||||
|
||||
```
|
||||
thickness = thickness1 * t + (thickness2 - thickness1)
|
||||
```
|
||||
|
||||
Thickness is something like the surface of a slice. It is compared to square
|
||||
distances.
|
||||
|
||||
## Distance
|
||||
|
||||
Distance between `(x1, y1, z1)` and `(x2, y2, z2)` is given by [\#4] :
|
||||
|
||||
```
|
||||
d = squareroot( (x2-x1)² + (y2-y1)² + (z2-z1)² )
|
||||
```
|
||||
|
||||
To avoid useless calculation, square distance is used as much as possible. For
|
||||
example, comparing two distances is the same as comparing their squares.
|
||||
|
||||
If exact distance is not required, Manhatan distance can be used (much faster):
|
||||
|
||||
```
|
||||
d = abs(x2-x1) + abs(y2-y1) + abs(z2-z1)
|
||||
```
|
81
bigtreelib/register.lua
Normal file
@ -0,0 +1,81 @@
|
||||
--[[
|
||||
Big tree lib - Giant trees library for Minetest
|
||||
(c) Pierre-Yves Rollo
|
||||
|
||||
This program 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 program 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 General Public License for more details.
|
||||
|
||||
You should have received a copy of the GNU General Public License
|
||||
along with this program. If not, see <http://www.gnu.org/licenses/>.
|
||||
--]]
|
||||
|
||||
--[[
|
||||
Decoration definition:
|
||||
place_under -- Node (or list of nodes) that the decoration can be placed under
|
||||
density = 0.3,
|
||||
noise_point = 1,
|
||||
noise_radius = 1,
|
||||
length_noise_factor = 5,
|
||||
length_min = 2,
|
||||
length_random = 5,
|
||||
start_node = "grunds:vine_middle",
|
||||
middle_node = "grunds:vine_middle",
|
||||
end_node = "grunds:vine_end",
|
||||
]]
|
||||
|
||||
btlib.registered_decorations = {}
|
||||
|
||||
function btlib.register_decoration(def)
|
||||
if not def.place_under then
|
||||
return
|
||||
end
|
||||
|
||||
local nodes = def.place_under
|
||||
|
||||
if type(nodes) == "string" then
|
||||
nodes = { nodes }
|
||||
end
|
||||
|
||||
if type(nodes) ~= "table" then
|
||||
return
|
||||
end
|
||||
|
||||
local def = table.copy(def)
|
||||
def.place_under = nil
|
||||
|
||||
if def.middle_node then
|
||||
def.cid_middle = minetest.get_content_id(def.middle_node)
|
||||
def.cid_start = def.cid_middle
|
||||
def.cid_end = def.cid_middle
|
||||
def.middle_node = nil
|
||||
end
|
||||
|
||||
if def.start_node then
|
||||
def.cid_start = minetest.get_content_id(def.start_node)
|
||||
def.start_node = nil
|
||||
end
|
||||
|
||||
if def.end_node then
|
||||
def.cid_end = minetest.get_content_id(def.end_node)
|
||||
def.end_node = nil
|
||||
end
|
||||
|
||||
for _, node in pairs(nodes) do
|
||||
local cid = minetest.get_content_id(node)
|
||||
if cid then
|
||||
if not btlib.registered_decorations[cid] then
|
||||
btlib.registered_decorations[cid] = {}
|
||||
end
|
||||
|
||||
btlib.registered_decorations[cid][
|
||||
#(btlib.registered_decorations[cid]) + 1] = def
|
||||
end
|
||||
end
|
||||
end
|
@ -1,5 +1,5 @@
|
||||
--[[
|
||||
Grunds - Giant trees biome for Minetest
|
||||
Big tree lib - Giant trees library for Minetest
|
||||
(c) Pierre-Yves Rollo
|
||||
|
||||
This program is free software: you can redistribute it and/or modify
|
||||
@ -16,158 +16,16 @@
|
||||
along with this program. If not, see <http://www.gnu.org/licenses/>.
|
||||
--]]
|
||||
|
||||
local pi, sqrt = math.pi, math.sqrt
|
||||
local min, max, random, floor, abs = math.min, math.max, math.random, math.floor, math.abs
|
||||
-- =============================================================================
|
||||
--
|
||||
-- VOXEL RENDERING
|
||||
--
|
||||
-- =============================================================================
|
||||
|
||||
local soil_node = "default:dirt_with_grass"
|
||||
local res = minetest.register_biome({
|
||||
name = "grunds",
|
||||
-- node_top = "default:dirt_with_rainforest_litter",
|
||||
node_top = soil_node,
|
||||
depth_top = 1,
|
||||
node_filler = "default:dirt",
|
||||
depth_filler = 5,
|
||||
node_riverbed = "default:sand",
|
||||
depth_riverbed = 2,
|
||||
y_max = 50,
|
||||
y_min = 1,
|
||||
vertical_blend = 8,
|
||||
heat_point = 55,
|
||||
humidity_point = 70,
|
||||
})
|
||||
|
||||
minetest.register_decoration({
|
||||
name = "grunds:apple_tree",
|
||||
deco_type = "schematic",
|
||||
place_on = {soil_node},
|
||||
sidelen = 16,
|
||||
noise_params = {
|
||||
offset = 0.026,
|
||||
scale = 0.015,
|
||||
spread = {x = 250, y = 250, z = 250},
|
||||
seed = 2,
|
||||
octaves = 3,
|
||||
persist = 0.66
|
||||
},
|
||||
biomes = {"grunds"},
|
||||
y_max = 31000,
|
||||
y_min = 1,
|
||||
schematic = minetest.get_modpath("default") .. "/schematics/apple_tree.mts",
|
||||
flags = "place_center_x, place_center_z",
|
||||
rotation = "random",
|
||||
})
|
||||
|
||||
minetest.register_decoration({
|
||||
name = "grunds:apple_log",
|
||||
deco_type = "schematic",
|
||||
place_on = {soil_node},
|
||||
place_offset_y = 1,
|
||||
sidelen = 16,
|
||||
noise_params = {
|
||||
offset = 0.0012,
|
||||
scale = 0.0007,
|
||||
spread = {x = 250, y = 250, z = 250},
|
||||
seed = 2,
|
||||
octaves = 3,
|
||||
persist = 0.66
|
||||
},
|
||||
biomes = {"grunds"},
|
||||
y_max = 31000,
|
||||
y_min = 1,
|
||||
schematic = minetest.get_modpath("default") .. "/schematics/apple_log.mts",
|
||||
flags = "place_center_x",
|
||||
rotation = "random",
|
||||
})
|
||||
|
||||
for i = 1,5 do
|
||||
minetest.register_decoration({
|
||||
name = "grunds:grass_"..i,
|
||||
biomes = {"grunds"},
|
||||
deco_type = "simple",
|
||||
place_on = {soil_node},
|
||||
fill_ratio = 0.2,
|
||||
decoration = "default:grass_"..i,
|
||||
})
|
||||
end
|
||||
|
||||
local treeradius = 150 -- Have to look around if any far tree has branches in this chunk
|
||||
local treedistance = 80 -- Minimum tree distance
|
||||
|
||||
local treeparam = {
|
||||
|
||||
trunk = {
|
||||
-- Trunk pitch random. If 0, trunk will start perfectly vertical
|
||||
pitch_rnd = pi/15,
|
||||
|
||||
-- Trunk thickness (value + random) this will give thickness for
|
||||
-- branches and roots
|
||||
thickness = 120,
|
||||
thickness_rnd = 100,
|
||||
thickness_factor = 0.8, -- Factor between base and top thickness
|
||||
thickness_factor_rnd = 0.1,
|
||||
|
||||
altitude = 10,
|
||||
altitude_rnd = 10,
|
||||
|
||||
length_min = 5,
|
||||
length_factor = 4,
|
||||
length_factor_rnd = 1,
|
||||
},
|
||||
|
||||
branches = {
|
||||
rotate_each_node_by = pi/2,
|
||||
rotate_each_node_by_rnd = pi/10,
|
||||
|
||||
yaw_rnd = pi/10,
|
||||
|
||||
pitch = pi,
|
||||
pitch_rnd = pi/10,
|
||||
|
||||
lenght_min = 5,
|
||||
lenght_factor = 2,
|
||||
lenght_factor_rnd = 1,
|
||||
|
||||
thinckess_min = 0.8,
|
||||
|
||||
splits = {
|
||||
{ thickness = 10, random = 2 },
|
||||
{ thickness = 10, random = 10 },
|
||||
-- { thickness = 0, random = 1},
|
||||
},
|
||||
|
||||
gravity_effect = -0.2,
|
||||
tuft = {
|
||||
radius = 8,
|
||||
density = 0.05,
|
||||
}
|
||||
},
|
||||
|
||||
roots = {
|
||||
rotate_each_node_by = pi/2,
|
||||
rotate_each_node_by_rnd = pi/10,
|
||||
|
||||
yaw_rnd = pi/10,
|
||||
|
||||
pitch = 3*pi/4,
|
||||
pitch_rnd = pi/10,
|
||||
|
||||
lenght_min = 5,
|
||||
lenght_factor = 3,
|
||||
lenght_factor_rnd = 0.5,
|
||||
|
||||
thinckess_min = 2,
|
||||
|
||||
gravity_effect = 0.8,
|
||||
|
||||
splits = {
|
||||
{ thickness = 10, random = 5 },
|
||||
{ thickness = 10, random = 5 },
|
||||
{ thickness = 10, random = 5 },
|
||||
},
|
||||
},
|
||||
|
||||
}
|
||||
local min, max, random, floor, abs = math.min, math.max, math.random, math.floor
|
||||
local sqrt, abs = math.sqrt, math.abs
|
||||
|
||||
-->> TODO: All this should be managed by registration
|
||||
local np_decoration = {
|
||||
scale = 1,
|
||||
spread = {x = 16, y = 16, z = 16},
|
||||
@ -175,22 +33,11 @@ local np_decoration = {
|
||||
octaves = 2,
|
||||
persist = 0.5,
|
||||
}
|
||||
--<< END TODO:
|
||||
|
||||
c_air = minetest.get_content_id("air")
|
||||
c_bark = minetest.get_content_id("grunds:bark")
|
||||
c_wood_1 = minetest.get_content_id("grunds:tree_1")
|
||||
c_wood_2 = minetest.get_content_id("grunds:tree_2")
|
||||
c_leaves = minetest.get_content_id("grunds:leaves")
|
||||
c_twigs = minetest.get_content_id("grunds:twigs")
|
||||
c_moisty = {
|
||||
minetest.get_content_id("grunds:bark_moisty_1"),
|
||||
minetest.get_content_id("grunds:bark_moisty_2"),
|
||||
minetest.get_content_id("grunds:bark_moisty_3"),
|
||||
}
|
||||
local c_air = minetest.get_content_id("air")
|
||||
|
||||
local treebuffer = {}
|
||||
local treebuffersize = 50 -- Keep 50 trees in buffer, avoids many computations
|
||||
-- TODO: Impement buffering emptying
|
||||
local decorations = btlib.registered_decorations
|
||||
|
||||
local function inter_coord(objects, coord, value)
|
||||
local result = {}
|
||||
@ -203,33 +50,10 @@ local function inter_coord(objects, coord, value)
|
||||
return result
|
||||
end
|
||||
|
||||
local decorations = {
|
||||
[c_bark] = {
|
||||
{
|
||||
density = 0.3,
|
||||
noise_point = 1,
|
||||
noise_radius = 1,
|
||||
-- length_noise_factor = 5,
|
||||
length_min = 2,
|
||||
length_random = 5,
|
||||
cid = minetest.get_content_id("grunds:vine_middle"),
|
||||
cid_end = minetest.get_content_id("grunds:vine_end"),
|
||||
}, {
|
||||
density = 0.2,
|
||||
noise_point = -1,
|
||||
noise_radius = 0.2,
|
||||
cid = minetest.get_content_id("grunds:red_fruit"),
|
||||
}, {
|
||||
density = 0.3,
|
||||
noise_point = -1,
|
||||
noise_radius = 0.2,
|
||||
cid = minetest.get_content_id("grunds:blue_fruit"),
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
function grunds.render(segments, tufts, minp, maxp, voxelmanip)
|
||||
local maxdiff, t, th, vx, vy, vz, d, dif, s, vmi
|
||||
-- Renders segments and tufts from trees between minp and maxp, in voxelmanip
|
||||
-- Can be used with mapgen and standard voxel manips.
|
||||
function btlib.render(segments, tufts, minp, maxp, voxelmanip)
|
||||
local segment, maxdiff, t, th, vx, vy, vz, d, dif, s, vmi
|
||||
local sv, sp, svx, svy, svz, spx, spy, spz
|
||||
local segmentsx, segmentsxz, tuftsx, tuftsxz
|
||||
local last_cid, cid, old_cid, ndef, branchok, dryrun
|
||||
@ -321,6 +145,7 @@ function grunds.render(segments, tufts, minp, maxp, voxelmanip)
|
||||
-- Get more precise for inside trunc stuff
|
||||
dif = sqrt(th) - sqrt(d)
|
||||
if not maxdiff or (dif > maxdiff) then
|
||||
segment = s
|
||||
maxdiff = dif
|
||||
end
|
||||
end
|
||||
@ -330,12 +155,12 @@ function grunds.render(segments, tufts, minp, maxp, voxelmanip)
|
||||
-- Maxdiff is the maximum distance from outside
|
||||
if maxdiff then
|
||||
if maxdiff < 1.1 then
|
||||
cid = c_bark
|
||||
cid = segment.cid_bark
|
||||
else
|
||||
if (maxdiff % 2 > 1) then
|
||||
cid = c_wood_1
|
||||
cid = segment.cid_wood_1
|
||||
else
|
||||
cid = c_wood_2
|
||||
cid = segment.cid_wood_2
|
||||
end
|
||||
end
|
||||
end
|
||||
@ -357,9 +182,9 @@ function grunds.render(segments, tufts, minp, maxp, voxelmanip)
|
||||
if d < t.radius2 and random() < t.density then
|
||||
dif = t.radius - sqrt(d)
|
||||
if random() * dif < 2 then
|
||||
cid = c_leaves
|
||||
cid = t.cid_leaves
|
||||
else
|
||||
cid = c_twigs
|
||||
cid = t.cid_twigs
|
||||
end
|
||||
break -- No need to check further
|
||||
end
|
||||
@ -410,7 +235,7 @@ function grunds.render(segments, tufts, minp, maxp, voxelmanip)
|
||||
end
|
||||
|
||||
if hanging_len >= (decoration.length_min or hanging_len) then
|
||||
hanging_cid = decoration.cid
|
||||
hanging_cid = decoration.cid_middle
|
||||
hanging_end_cid = decoration.cid_end or hanging_cid
|
||||
cid = decoration.cid_start or hanging_cid
|
||||
hanging_len = hanging_len - 1
|
||||
@ -422,15 +247,18 @@ function grunds.render(segments, tufts, minp, maxp, voxelmanip)
|
||||
end
|
||||
end
|
||||
|
||||
--TODO:MAKE IT A DECORATION
|
||||
--[[
|
||||
-- Top node change
|
||||
if cid == c_bark and
|
||||
(last_cid == c_air or last_cid == c_leaves)
|
||||
then
|
||||
local moisty = floor(decoration_map[z-minp.z+1][y-minp.y+1][x-minp.x+1]*3 + 1)
|
||||
if moisty > 0 then
|
||||
cid = c_moisty[min(moisty, 3)]
|
||||
cid = segment.cid_moisty_barks[min(moisty, 3)]
|
||||
end
|
||||
end
|
||||
]]
|
||||
|
||||
if cid ~= old_cid and y <= maxp.y then
|
||||
node[vmi] = cid
|
||||
@ -460,71 +288,3 @@ function grunds.render(segments, tufts, minp, maxp, voxelmanip)
|
||||
end
|
||||
voxelmanip:set_data(node)
|
||||
end
|
||||
|
||||
local biome_names = { "grunds" }
|
||||
local biomes = {}
|
||||
for _, name in pairs(biome_names) do
|
||||
local id = minetest.get_biome_id(name)
|
||||
if id then
|
||||
biomes[id] = name
|
||||
end
|
||||
end
|
||||
|
||||
minetest.register_on_generated(function (minp, maxp, blockseed)
|
||||
local segments = {}
|
||||
local tufts = {}
|
||||
|
||||
-- Choose random candidate positions evenly distributed for trees
|
||||
local points = grunds.distribute({x = minp.x - treeradius, y = minp.z - treeradius},
|
||||
{x = maxp.x + treeradius, y = maxp.z + treeradius}, treedistance, 1, 40)
|
||||
|
||||
for i = 1, #points do
|
||||
local p = points[i]
|
||||
local x, z = p.x, p.y
|
||||
|
||||
local tree = treebuffer[x.." "..z]
|
||||
|
||||
-- Make tree if it is not already buffered
|
||||
if tree == nil then
|
||||
local seed = grunds.baseseed + x + z * 65498
|
||||
local y = grunds.mg.get_level_at_point(x, z)
|
||||
|
||||
if y and y > grunds.mg.water_level then
|
||||
local biome = minetest.get_biome_data({x=x, y=y, z=z})
|
||||
if biomes[biome.biome] then
|
||||
tree = grunds.make_tree({x=x, y=y, z=z}, treeparam, seed)
|
||||
end
|
||||
end
|
||||
|
||||
-- Bufferize
|
||||
if tree then
|
||||
treebuffer[x.." "..z] = tree
|
||||
else
|
||||
treebuffer[x.." "..z] = false
|
||||
end
|
||||
end
|
||||
|
||||
-- If tree, see what's to be rendered
|
||||
if tree then
|
||||
-- Add intersecting segments to those to be rendered
|
||||
for _, segment in ipairs(tree.segments) do
|
||||
if grunds.intersects(segment, minp, maxp) then
|
||||
segments[#segments + 1] = segment
|
||||
end
|
||||
end
|
||||
-- Add intersecting tufts to those to be rendered
|
||||
for _, tuft in ipairs(tree.tufts) do
|
||||
if grunds.intersects(tuft, minp, maxp) then
|
||||
tufts[#tufts + 1] = tuft
|
||||
end
|
||||
end
|
||||
end
|
||||
end
|
||||
|
||||
-- Now rendering
|
||||
local vm, emin, emax = minetest.get_mapgen_object("voxelmanip")
|
||||
grunds.render(segments, tufts, minp, maxp, vm)
|
||||
vm:set_lighting( {day=0, night=0})
|
||||
vm:calc_lighting()
|
||||
vm:write_to_map()
|
||||
end)
|
132
draft/init.lua
@ -1,132 +0,0 @@
|
||||
-- Try to imitate mapgen_v7.cpp
|
||||
-- Works well except for mountains
|
||||
-- Could be improved to return level also underwater
|
||||
|
||||
local function rangelim(v, min, max)
|
||||
if v < min then return min end
|
||||
if v > max then return max end
|
||||
return v
|
||||
end
|
||||
|
||||
local np_height_select = minetest.get_mapgen_setting_noiseparams("mgv7_np_height_select")
|
||||
local np_terrain_persist = minetest.get_mapgen_setting_noiseparams("mgv7_np_terrain_persist")
|
||||
local np_terrain_base = minetest.get_mapgen_setting_noiseparams("mgv7_np_terrain_base")
|
||||
local np_terrain_alt = minetest.get_mapgen_setting_noiseparams("mgv7_np_terrain_alt")
|
||||
local np_mount_height = minetest.get_mapgen_setting_noiseparams("mgv7_np_mount_height")
|
||||
local np_mountain = minetest.get_mapgen_setting_noiseparams("mgv7_np_mountain")
|
||||
local np_ridge_uwater = minetest.get_mapgen_setting_noiseparams("mgv7_np_ridge_uwater")
|
||||
local mount_zero_level = minetest.get_mapgen_setting("mgv7_mount_zero_level")
|
||||
local spflags = minetest.get_mapgen_setting("mgv7_spflags")
|
||||
local water_level = 0
|
||||
|
||||
-- May have to set 0 during mapgen
|
||||
local seed = minetest.get_mapgen_setting("seed")
|
||||
np_height_select.seed = np_height_select.seed + seed
|
||||
np_terrain_persist.seed = np_terrain_persist.seed + seed
|
||||
np_terrain_base.seed = np_terrain_base.seed + seed
|
||||
np_terrain_alt.seed = np_terrain_alt.seed + seed
|
||||
np_mount_height.seed = np_mount_height.seed + seed
|
||||
np_mountain.seed = np_mountain.seed + seed
|
||||
np_ridge_uwater.seed = np_ridge_uwater.seed + seed
|
||||
|
||||
local function get3dNoise(params, pos3d)
|
||||
-- "The `z` component ... must be must be larger than 1 for 3D noise"
|
||||
local size3d = { x = 1, y = 1, z = 2 }
|
||||
return PerlinNoiseMap(params, size3d):get_3d_map_flat(pos3d)[1]
|
||||
end
|
||||
|
||||
local function get2dNoise(params, pos2d)
|
||||
local size2d = { x = 1, y = 1 }
|
||||
return PerlinNoiseMap(params, size2d):get_2d_map_flat(pos2d)[1]
|
||||
end
|
||||
|
||||
local function v7_baseTerrainLevelAtPoint(x, y)
|
||||
local pos2d = { x = x, y = y }
|
||||
|
||||
local hselect = get2dNoise(np_height_select, pos2d)
|
||||
hselect = rangelim(hselect, 0, 1);
|
||||
|
||||
local persist = get2dNoise(np_terrain_persist, pos2d)
|
||||
|
||||
np_terrain_base.persist = persist;
|
||||
local height_base = get2dNoise(np_terrain_base, pos2d)
|
||||
|
||||
np_terrain_alt.persist = persist;
|
||||
local height_alt = get2dNoise(np_terrain_alt, pos2d)
|
||||
|
||||
if (height_alt > height_base) then
|
||||
return height_alt
|
||||
end
|
||||
|
||||
return (height_base * hselect) + (height_alt * (1 - hselect));
|
||||
end
|
||||
|
||||
local function v7_mountainTerrainAtPoint(x, y, z)
|
||||
local mnt_h_n = get2dNoise(np_mount_height, { x = x, y = z })
|
||||
if mnt_h_n > 1 then mnt_h_n = 1 end
|
||||
|
||||
local density_gradient = - (y - mount_zero_level) / mnt_h_n
|
||||
local mnt_n = get3dNoise(np_mountain, { x = x, y = y, z = z })
|
||||
|
||||
return mnt_n + density_gradient >= 0;
|
||||
end
|
||||
|
||||
local function getLevelAtPoint(x, z)
|
||||
-- if (spflags & MGV7_RIDGES)
|
||||
local uwatern = get2dNoise(np_ridge_uwater, { x = x, y = z })
|
||||
print(dump(np_ridge_uwater))
|
||||
if math.abs(uwatern) <= 0.2 then
|
||||
print("IN RIVER")
|
||||
return nil
|
||||
end
|
||||
-- end
|
||||
|
||||
local y = v7_baseTerrainLevelAtPoint(x, z);
|
||||
|
||||
--if (!(spflags & MGV7_MOUNTAINS)) {
|
||||
--[[
|
||||
if (y <= water_level)
|
||||
return nil
|
||||
|
||||
return y + 2;
|
||||
]]
|
||||
-- end
|
||||
print("Base:", y)
|
||||
|
||||
for i = 1, 256 do
|
||||
if not v7_mountainTerrainAtPoint(x, y + 1, z) then
|
||||
if (y <= water_level) then
|
||||
print("IN WATER")
|
||||
return nil
|
||||
else
|
||||
return y + 1
|
||||
end
|
||||
end
|
||||
y = y + 1
|
||||
end
|
||||
print("IN MOUNTAIN")
|
||||
|
||||
return nil
|
||||
end
|
||||
|
||||
minetest.register_chatcommand("b", {
|
||||
params = "x z",
|
||||
description = "Biome test",
|
||||
func = function(name, param)
|
||||
local x, z = string.match(param, "^([%d.-]+)[, ] *([%d.-]+)$")
|
||||
if x and z then
|
||||
x = tonumber(x)
|
||||
z = tonumber(z)
|
||||
local y = getLevelAtPoint(x, z)
|
||||
if y then
|
||||
minetest.chat_send_player(name, "Level: " .. y)
|
||||
else
|
||||
minetest.chat_send_player(name, "No level found")
|
||||
y = 0
|
||||
end
|
||||
local biome = minetest.get_biome_data({x = x, y = y, z = z})
|
||||
local bname = minetest.get_biome_name(biome.biome)
|
||||
minetest.chat_send_player(name, "Biome: " .. biome.biome.." - ".. bname)
|
||||
end
|
||||
end
|
||||
})
|
44
grundsmg/buffer.lua
Normal file
@ -0,0 +1,44 @@
|
||||
--[[
|
||||
Grunds - Giant trees biome for Minetest
|
||||
(c) Pierre-Yves Rollo
|
||||
|
||||
This program 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 program 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 General Public License for more details.
|
||||
|
||||
You should have received a copy of the GNU General Public License
|
||||
along with this program. If not, see <http://www.gnu.org/licenses/>.
|
||||
--]]
|
||||
|
||||
|
||||
local Buffer = {
|
||||
__newindex = function(self, key, value)
|
||||
self.elements[key] = value;
|
||||
self.keys[#self.keys + 1] = key;
|
||||
|
||||
if #self.keys > self.maxsize then
|
||||
self.elements[table.remove(self.keys, 1)] = nil
|
||||
end
|
||||
end,
|
||||
|
||||
__index = function(self, key)
|
||||
return self.elements[key]
|
||||
end,
|
||||
}
|
||||
|
||||
function grunds.new_buffer(maxsize)
|
||||
local buffer = {
|
||||
maxsize = maxsize,
|
||||
stamp = 1,
|
||||
elements = {},
|
||||
keys = {},
|
||||
}
|
||||
setmetatable(buffer, Buffer)
|
||||
return buffer
|
||||
end
|
54
grundsmg/commands/grow_grund.lua
Normal file
@ -0,0 +1,54 @@
|
||||
--[[
|
||||
Grunds - Giant trees biome for Minetest
|
||||
(c) Pierre-Yves Rollo
|
||||
|
||||
This program 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 program 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 General Public License for more details.
|
||||
|
||||
You should have received a copy of the GNU General Public License
|
||||
along with this program. If not, see <http://www.gnu.org/licenses/>.
|
||||
--]]
|
||||
|
||||
local pi, sqrt = math.pi, math.sqrt
|
||||
local max, random = math.max, math.random
|
||||
|
||||
-- Test function
|
||||
minetest.register_chatcommand("grow_grund", {
|
||||
params = "",
|
||||
description = "Grow a giant grund at your position",
|
||||
func = function(name, param)
|
||||
local player = minetest.get_player_by_name(name)
|
||||
if not player then
|
||||
return false, "Player not found"
|
||||
end
|
||||
local pos = player:get_pos()
|
||||
local pos = {
|
||||
x = math.floor(pos.x),
|
||||
z = math.floor(pos.z),
|
||||
}
|
||||
|
||||
pos.y = mgutils.get_level_at_point(pos.x, pos.z)
|
||||
|
||||
if pos.y == nil then
|
||||
return false, "Not a suitable position for growing a tree"
|
||||
end
|
||||
|
||||
if pos.y < mgutils.water_level then pos.y = mgutils.water_level end
|
||||
|
||||
local tree = btlib.build_tree(pos, grunds.trees.grund)
|
||||
local minp, maxp = btlib.get_minmaxp(tree)
|
||||
local manip = minetest.get_voxel_manip()
|
||||
manip:read_from_map(minp, maxp)
|
||||
btlib.render(tree.segments, tree.tufts, minp, maxp, manip)
|
||||
manip:write_to_map()
|
||||
|
||||
return true, "Tree grown!"
|
||||
end
|
||||
})
|
76
grundsmg/draft/speedtest.lua
Normal file
@ -0,0 +1,76 @@
|
||||
local start
|
||||
local t = {}
|
||||
for i = 0, 1000 do
|
||||
t[i] = i
|
||||
end
|
||||
local t2 = {}
|
||||
for i = 0, 1000 do
|
||||
t2["X"..i] = i
|
||||
end
|
||||
|
||||
print("\nLoops test:")
|
||||
start = os.clock()
|
||||
for i = 1, 1000 do
|
||||
for k,v in pairs(t) do end
|
||||
end
|
||||
io.write(("pairs = %.2fms"):format((os.clock() - start)*1000))
|
||||
start = os.clock()
|
||||
for i = 1, 1000 do
|
||||
for k,v in ipairs(t) do end
|
||||
end
|
||||
io.write((", ipairs = %.2fms"):format((os.clock() - start)*1000))
|
||||
start = os.clock()
|
||||
local tt
|
||||
for i = 1, 1000 do
|
||||
for j = 1, #t do tt = t[j] end
|
||||
end
|
||||
io.write((", index = %.2fms\n"):format((os.clock() - start)*1000))
|
||||
|
||||
|
||||
print("\nInside loop locals vs outsin loop locals.")
|
||||
start = os.clock()
|
||||
for i = 1, 1000000 do
|
||||
local test = i
|
||||
local test2 = test
|
||||
end
|
||||
print(("Local inside loop: %.2fms"):format((os.clock() - start)*1000))
|
||||
|
||||
start = os.clock()
|
||||
local test, test2
|
||||
for i = 1, 1000000 do
|
||||
test = i
|
||||
test2 = test
|
||||
end
|
||||
print(("Local outside loop: %.2fms"):format((os.clock() - start)*1000))
|
||||
|
||||
|
||||
print("\nTable vs local.")
|
||||
start = os.clock()
|
||||
local t = { t = { x = 1 }}
|
||||
for i = 1, 500000 do
|
||||
t.t.x = i
|
||||
end
|
||||
print(("Basic table loop: %.2fms"):format((os.clock() - start)*1000))
|
||||
|
||||
start = os.clock()
|
||||
local t = { t = { x = 1 }}
|
||||
local tt = t.t
|
||||
for i = 1, 500000 do
|
||||
tt.x = i
|
||||
end
|
||||
print(("local table loop: %.2fms"):format((os.clock() - start)*1000))
|
||||
|
||||
print("\nString index vs numeric index.")
|
||||
start = os.clock()
|
||||
local t = { a = 1, b = 2, c = 3, d = 4, e = 5, f = 6, g = 7, h = 8, i = 9, j = 10}
|
||||
for i = 1, 1000000 do
|
||||
t.e = 10
|
||||
end
|
||||
print(("string index: %.2fms"):format((os.clock() - start)*1000))
|
||||
start = os.clock()
|
||||
local t = { 1, 2, 3, 4, 5, 6, 7, 8, 9, 10}
|
||||
local e = 5
|
||||
for i = 1, 1000000 do
|
||||
t[e] = 10
|
||||
end
|
||||
print(("integer index: %.2fms"):format((os.clock() - start)*1000))
|
31
grundsmg/init.lua
Normal file
@ -0,0 +1,31 @@
|
||||
--[[
|
||||
Grunds - Giant trees biome for Minetest
|
||||
(c) Pierre-Yves Rollo
|
||||
|
||||
This program 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 program 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 General Public License for more details.
|
||||
|
||||
You should have received a copy of the GNU General Public License
|
||||
along with this program. If not, see <http://www.gnu.org/licenses/>.
|
||||
--]]
|
||||
|
||||
grunds = {}
|
||||
grunds.name = minetest.get_current_modname()
|
||||
grunds.path = minetest.get_modpath(minetest.get_current_modname())
|
||||
|
||||
dofile(grunds.path .. "/nodes.lua")
|
||||
dofile(grunds.path .. "/distribute.lua")
|
||||
dofile(grunds.path .. "/buffer.lua")
|
||||
dofile(grunds.path .. "/mapgen.lua")
|
||||
|
||||
dofile(grunds.path .. "/commands/find_biome.lua")
|
||||
dofile(grunds.path .. "/commands/grow_grund.lua")
|
||||
|
||||
dofile(grunds.path .. "/treesettings.lua")
|
176
grundsmg/mapgen.lua
Normal file
@ -0,0 +1,176 @@
|
||||
--[[
|
||||
Grunds - Giant trees biome for Minetest
|
||||
(c) Pierre-Yves Rollo
|
||||
|
||||
This program 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 program 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 General Public License for more details.
|
||||
|
||||
You should have received a copy of the GNU General Public License
|
||||
along with this program. If not, see <http://www.gnu.org/licenses/>.
|
||||
--]]
|
||||
|
||||
-- =============================================================================
|
||||
--
|
||||
-- MAPGEN INTEGRATION
|
||||
--
|
||||
-- Creates a biome with one model of giant trees
|
||||
--
|
||||
-- =============================================================================
|
||||
|
||||
-- Big int numbers are truncated by Lua, so adding small int to them results in
|
||||
-- the same number. Baseseed will be added with local seeds
|
||||
grunds.baseseed = minetest.get_mapgen_setting("seed") % (2^32)
|
||||
|
||||
if mgutils.has_biomes then
|
||||
local soil_node = "default:dirt_with_grass"
|
||||
local res = minetest.register_biome({
|
||||
name = "grunds",
|
||||
-- node_top = "default:dirt_with_rainforest_litter",
|
||||
node_top = soil_node,
|
||||
depth_top = 1,
|
||||
node_filler = "default:dirt",
|
||||
depth_filler = 5,
|
||||
node_riverbed = "default:sand",
|
||||
depth_riverbed = 2,
|
||||
y_max = 50,
|
||||
y_min = 1,
|
||||
vertical_blend = 8,
|
||||
heat_point = 55,
|
||||
humidity_point = 70,
|
||||
})
|
||||
|
||||
minetest.register_decoration({
|
||||
name = "grunds:apple_tree",
|
||||
deco_type = "schematic",
|
||||
place_on = {soil_node},
|
||||
sidelen = 16,
|
||||
noise_params = {
|
||||
offset = 0.026,
|
||||
scale = 0.015,
|
||||
spread = {x = 250, y = 250, z = 250},
|
||||
seed = 2,
|
||||
octaves = 3,
|
||||
persist = 0.66
|
||||
},
|
||||
biomes = {"grunds"},
|
||||
y_max = 31000,
|
||||
y_min = 1,
|
||||
schematic = minetest.get_modpath("default") .. "/schematics/apple_tree.mts",
|
||||
flags = "place_center_x, place_center_z",
|
||||
rotation = "random",
|
||||
})
|
||||
|
||||
minetest.register_decoration({
|
||||
name = "grunds:apple_log",
|
||||
deco_type = "schematic",
|
||||
place_on = {soil_node},
|
||||
place_offset_y = 1,
|
||||
sidelen = 16,
|
||||
noise_params = {
|
||||
offset = 0.0012,
|
||||
scale = 0.0007,
|
||||
spread = {x = 250, y = 250, z = 250},
|
||||
seed = 2,
|
||||
octaves = 3,
|
||||
persist = 0.66
|
||||
},
|
||||
biomes = {"grunds"},
|
||||
y_max = 31000,
|
||||
y_min = 1,
|
||||
schematic = minetest.get_modpath("default") .. "/schematics/apple_log.mts",
|
||||
flags = "place_center_x",
|
||||
rotation = "random",
|
||||
})
|
||||
|
||||
for i = 1,5 do
|
||||
minetest.register_decoration({
|
||||
name = "grunds:grass_"..i,
|
||||
biomes = {"grunds"},
|
||||
deco_type = "simple",
|
||||
place_on = {soil_node},
|
||||
fill_ratio = 0.2,
|
||||
decoration = "default:grass_"..i,
|
||||
})
|
||||
end
|
||||
end
|
||||
|
||||
local treeradius = 150 -- Have to look around if any far tree has branches in this chunk
|
||||
local treedistance = 80 -- Minimum tree distance
|
||||
local treebuffer = grunds.new_buffer(50)
|
||||
|
||||
local biome_names = { "grunds" }
|
||||
local biomes = {}
|
||||
for _, name in pairs(biome_names) do
|
||||
local id = minetest.get_biome_id(name)
|
||||
if id then
|
||||
biomes[id] = name
|
||||
end
|
||||
end
|
||||
|
||||
if mgutils.has_biomes then
|
||||
minetest.register_on_generated(function (minp, maxp, blockseed)
|
||||
local segments = {}
|
||||
local tufts = {}
|
||||
|
||||
-- Choose random candidate positions evenly distributed for trees
|
||||
local points = grunds.distribute({x = minp.x - treeradius, y = minp.z - treeradius},
|
||||
{x = maxp.x + treeradius, y = maxp.z + treeradius}, treedistance, 1, 40)
|
||||
|
||||
for i = 1, #points do
|
||||
local p = points[i]
|
||||
local x, z = p.x, p.y
|
||||
|
||||
local tree = treebuffer[x.." "..z]
|
||||
|
||||
-- Make tree if it is not already buffered
|
||||
if tree == nil then
|
||||
local seed = grunds.baseseed + x + z * 65498
|
||||
local y = mgutils.get_level_at_point(x, z)
|
||||
|
||||
if y and y > mgutils.water_level then
|
||||
local biome = minetest.get_biome_data({x=x, y=y, z=z})
|
||||
if biomes[biome.biome] then
|
||||
tree = btlib.build_tree({x=x, y=y, z=z}, grunds.trees.grund, seed)
|
||||
end
|
||||
end
|
||||
|
||||
-- Bufferize
|
||||
if tree then
|
||||
treebuffer[x.." "..z] = tree
|
||||
else
|
||||
treebuffer[x.." "..z] = false
|
||||
end
|
||||
end
|
||||
|
||||
-- If tree, see what's to be rendered
|
||||
if tree then
|
||||
-- Add intersecting segments to those to be rendered
|
||||
for _, segment in ipairs(tree.segments) do
|
||||
if btlib.intersects(segment, minp, maxp) then
|
||||
segments[#segments + 1] = segment
|
||||
end
|
||||
end
|
||||
-- Add intersecting tufts to those to be rendered
|
||||
for _, tuft in ipairs(tree.tufts) do
|
||||
if btlib.intersects(tuft, minp, maxp) then
|
||||
tufts[#tufts + 1] = tuft
|
||||
end
|
||||
end
|
||||
end
|
||||
end
|
||||
|
||||
-- Now rendering
|
||||
local vm, emin, emax = minetest.get_mapgen_object("voxelmanip")
|
||||
btlib.render(segments, tufts, minp, maxp, vm)
|
||||
vm:set_lighting( {day=0, night=0})
|
||||
vm:calc_lighting()
|
||||
vm:write_to_map()
|
||||
end)
|
||||
end
|
@ -1,3 +1,3 @@
|
||||
name = grunds
|
||||
description = A biome with giant trees
|
||||
depends = default
|
||||
depends = default, bigtreelib, mgutils
|
Before Width: | Height: | Size: 510 B After Width: | Height: | Size: 510 B |
Before Width: | Height: | Size: 582 B After Width: | Height: | Size: 582 B |
Before Width: | Height: | Size: 580 B After Width: | Height: | Size: 580 B |
Before Width: | Height: | Size: 588 B After Width: | Height: | Size: 588 B |
Before Width: | Height: | Size: 496 B After Width: | Height: | Size: 496 B |
Before Width: | Height: | Size: 502 B After Width: | Height: | Size: 502 B |
Before Width: | Height: | Size: 530 B After Width: | Height: | Size: 530 B |
Before Width: | Height: | Size: 760 B After Width: | Height: | Size: 760 B |
Before Width: | Height: | Size: 624 B After Width: | Height: | Size: 624 B |
Before Width: | Height: | Size: 904 B After Width: | Height: | Size: 904 B |
Before Width: | Height: | Size: 759 B After Width: | Height: | Size: 759 B |
Before Width: | Height: | Size: 657 B After Width: | Height: | Size: 657 B |
Before Width: | Height: | Size: 883 B After Width: | Height: | Size: 883 B |
Before Width: | Height: | Size: 347 B After Width: | Height: | Size: 347 B |
Before Width: | Height: | Size: 377 B After Width: | Height: | Size: 377 B |
Before Width: | Height: | Size: 718 B After Width: | Height: | Size: 718 B |
Before Width: | Height: | Size: 719 B After Width: | Height: | Size: 719 B |
121
grundsmg/treesettings.lua
Normal file
@ -0,0 +1,121 @@
|
||||
local pi = math.pi
|
||||
|
||||
btlib.register_decoration({
|
||||
place_under = "grunds:bark",
|
||||
density = 0.3,
|
||||
noise_point = 1,
|
||||
noise_radius = 1,
|
||||
-- length_noise_factor = 5,
|
||||
length_min = 2,
|
||||
length_random = 5,
|
||||
middle_node = "grunds:vine_middle",
|
||||
end_node = "grunds:vine_end",
|
||||
})
|
||||
|
||||
btlib.register_decoration({
|
||||
place_under = "grunds:bark",
|
||||
density = 0.2,
|
||||
noise_point = -1,
|
||||
noise_radius = 0.2,
|
||||
middle_node = "grunds:red_fruit",
|
||||
})
|
||||
|
||||
btlib.register_decoration({
|
||||
place_under = "grunds:bark",
|
||||
density = 0.3,
|
||||
noise_point = -1,
|
||||
noise_radius = 0.2,
|
||||
middle_node = "grunds:blue_fruit",
|
||||
})
|
||||
|
||||
grunds.trees = {}
|
||||
grunds.trees.grund = {
|
||||
nodes = {
|
||||
bark_node = "grunds:bark",
|
||||
|
||||
-- TODO: Should be a list
|
||||
tree_1_node = "grunds:tree_1",
|
||||
tree_2_node = "grunds:tree_2",
|
||||
|
||||
-- TODO: Should be a decoration
|
||||
moisty_bark_nodes = {
|
||||
"grunds:bark_moisty_1",
|
||||
"grunds:bark_moisty_2",
|
||||
"grunds:bark_moisty_3"
|
||||
},
|
||||
|
||||
leave_node = "grunds:leaves",
|
||||
twigs_node = "grunds:twigs",
|
||||
},
|
||||
|
||||
trunk = {
|
||||
-- Trunk pitch random. If 0, trunk will start perfectly vertical
|
||||
pitch_rnd = pi/15,
|
||||
|
||||
-- Trunk thickness (value + random) this will give thickness for
|
||||
-- branches and roots
|
||||
thickness = 120,
|
||||
thickness_rnd = 100,
|
||||
thickness_factor = 0.8, -- Factor between base and top thickness
|
||||
thickness_factor_rnd = 0.1,
|
||||
|
||||
altitude = 10,
|
||||
altitude_rnd = 10,
|
||||
|
||||
length_min = 5,
|
||||
length_factor = 4,
|
||||
length_factor_rnd = 1,
|
||||
},
|
||||
|
||||
branches = {
|
||||
rotate_each_node_by = pi/2,
|
||||
rotate_each_node_by_rnd = pi/10,
|
||||
|
||||
yaw_rnd = pi/10,
|
||||
|
||||
pitch = pi,
|
||||
pitch_rnd = pi/10,
|
||||
|
||||
lenght_min = 5,
|
||||
lenght_factor = 2,
|
||||
lenght_factor_rnd = 1,
|
||||
|
||||
thinckess_min = 0.8,
|
||||
|
||||
splits = {
|
||||
{ thickness = 10, random = 2 },
|
||||
{ thickness = 10, random = 10 },
|
||||
},
|
||||
|
||||
gravity_effect = -0.2,
|
||||
tuft = {
|
||||
radius = 8,
|
||||
density = 0.05,
|
||||
}
|
||||
},
|
||||
|
||||
roots = {
|
||||
rotate_each_node_by = pi/2,
|
||||
rotate_each_node_by_rnd = pi/10,
|
||||
|
||||
yaw_rnd = pi/10,
|
||||
|
||||
pitch = 3*pi/4,
|
||||
pitch_rnd = pi/10,
|
||||
|
||||
lenght_min = 5,
|
||||
lenght_factor = 3,
|
||||
lenght_factor_rnd = 0.5,
|
||||
|
||||
thinckess_min = 2,
|
||||
|
||||
gravity_effect = 0.8,
|
||||
|
||||
splits = {
|
||||
{ thickness = 10, random = 5 },
|
||||
{ thickness = 10, random = 5 },
|
||||
{ thickness = 10, random = 5 },
|
||||
},
|
||||
},
|
||||
|
||||
}
|
235
init.lua
@ -1,235 +0,0 @@
|
||||
--[[
|
||||
Grunds - Giant trees biome for Minetest
|
||||
(c) Pierre-Yves Rollo
|
||||
|
||||
This program 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 program 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 General Public License for more details.
|
||||
|
||||
You should have received a copy of the GNU General Public License
|
||||
along with this program. If not, see <http://www.gnu.org/licenses/>.
|
||||
--]]
|
||||
|
||||
grunds = {}
|
||||
grunds.name = minetest.get_current_modname()
|
||||
grunds.path = minetest.get_modpath(minetest.get_current_modname())
|
||||
|
||||
-- Big int numbers are truncated by Lua, so adding small int to them results in
|
||||
-- the same number. Baseseed will be added with local seeds
|
||||
grunds.baseseed = minetest.get_mapgen_setting("seed") % (2^32)
|
||||
|
||||
grunds.mg = dofile(grunds.path .. "/mgutils.lua")
|
||||
dofile(grunds.path .. "/nodes.lua")
|
||||
dofile(grunds.path .. "/distribute.lua")
|
||||
dofile(grunds.path .. "/tree.lua")
|
||||
dofile(grunds.path .. "/biome.lua")
|
||||
dofile(grunds.path .. "/mapgen.lua")
|
||||
|
||||
|
||||
local pi, sqrt = math.pi, math.sqrt
|
||||
local max, random = math.max, math.random
|
||||
|
||||
c_air = minetest.get_content_id("air")
|
||||
c_bark = minetest.get_content_id("grunds:bark")
|
||||
c_wood_1 = minetest.get_content_id("grunds:tree_1")
|
||||
c_wood_2 = minetest.get_content_id("grunds:tree_2")
|
||||
c_leaves = minetest.get_content_id("grunds:leaves")
|
||||
|
||||
local treeparam = {
|
||||
|
||||
trunk = {
|
||||
-- Trunk pitch random. If 0, trunk will start perfectly vertical
|
||||
pitch_rnd = pi/15,
|
||||
|
||||
-- Trunk thickness (value + random) this will give thickness for
|
||||
-- branches and roots
|
||||
thickness = 150,
|
||||
thickness_rnd = 40,
|
||||
thickness_factor = 0.8, -- Factor between base and top thickness
|
||||
thickness_factor_rnd = 0.1,
|
||||
|
||||
altitude = 10,
|
||||
altitude_rnd = 10,
|
||||
|
||||
length_min = 5,
|
||||
length_factor = 4,
|
||||
length_factor_rnd = 1,
|
||||
},
|
||||
|
||||
branches = {
|
||||
rotate_each_node_by = pi/2,
|
||||
rotate_each_node_by_rnd = pi/10,
|
||||
|
||||
yaw_rnd = pi/10,
|
||||
|
||||
pitch = pi,
|
||||
pitch_rnd = pi/10,
|
||||
|
||||
lenght_min = 5,
|
||||
lenght_factor = 2,
|
||||
lenght_factor_rnd = 1,
|
||||
|
||||
thinckess_min = 0.8,
|
||||
|
||||
splits = {
|
||||
{ thickness = 10, random = 2 },
|
||||
{ thickness = 10, random = 10 },
|
||||
-- { thickness = 0, random = 1},
|
||||
},
|
||||
|
||||
gravity_effect = -0.2,
|
||||
tuft = {
|
||||
radius = 9,
|
||||
density = 0.1,
|
||||
}
|
||||
},
|
||||
|
||||
roots = {
|
||||
rotate_each_node_by = pi/2,
|
||||
rotate_each_node_by_rnd = pi/10,
|
||||
|
||||
yaw_rnd = pi/10,
|
||||
|
||||
pitch = 3*pi/4,
|
||||
pitch_rnd = pi/10,
|
||||
|
||||
lenght_min = 5,
|
||||
lenght_factor = 3,
|
||||
lenght_factor_rnd = 0.5,
|
||||
|
||||
thinckess_min = 2,
|
||||
|
||||
gravity_effect = 0.6,
|
||||
|
||||
splits = {
|
||||
{ thickness = 10, random = 5 },
|
||||
{ thickness = 10, random = 5 },
|
||||
{ thickness = 10, random = 5 },
|
||||
},
|
||||
},
|
||||
|
||||
}
|
||||
|
||||
--[[
|
||||
Geometric formulas
|
||||
==================
|
||||
|
||||
-- LINES --
|
||||
|
||||
Spatial representation of a straight line [#1]:
|
||||
{
|
||||
x = vx * t + px
|
||||
y = vy * t + py
|
||||
z = vz * t + pz
|
||||
}
|
||||
|
||||
t is the "parameter". (x, y, z) is on line if a t exists.
|
||||
(vx, vy, vz) is a vector along the line direction.
|
||||
(px, py, pz) is one of the line point.
|
||||
|
||||
This gives coordinates of point from parameter.
|
||||
|
||||
-- SEGMENTS --
|
||||
|
||||
Our segments are quite simple if we take starting point as (px, py, pz) and
|
||||
segment vector (from start to end) as (vx, vy, vz).
|
||||
|
||||
The segment is constitued of every point for t from 0.0 to 1.0.
|
||||
|
||||
-- NEAREST POINT --
|
||||
|
||||
To determine the parameter of nearest point of line to position (x0, y0, z0) is
|
||||
given by :
|
||||
t = (vx, vy, vz) * ((x0, y0, z0) - (px, py, pz)) / len((vx, vy, vz))
|
||||
|
||||
t = (vx * (x0 - px) + vy * (y0 - py) + vz * (z0 + pz)) / (vx² + vy² +vz²)
|
||||
|
||||
Quotient is not depending on (x0, y0, z0) so it can be computed once
|
||||
when creating segment. Final formula is [#2] :
|
||||
|
||||
t = (vx * (x0 - px) + vy * (y0 - py) + vz * (z0 + pz)) * k
|
||||
|
||||
with k = 1 / (vx² + vy² +vz²)
|
||||
|
||||
-- THICKNESS --
|
||||
|
||||
Thickness is a simple linear variation from one end of the segment to the other.
|
||||
Formula has this form [#3]:
|
||||
|
||||
thickness = thickness1 * t + (thickness2 - thickness1)
|
||||
|
||||
Thickness is something like a surface. It is compared to square distances.
|
||||
|
||||
-- DISTANCE --
|
||||
|
||||
Distance between (x1, y1, z1) and (x2, y2, z2) is given by :
|
||||
d = squareroot( (x2-x1)² + (y2-y1)² + (z2-z1)² )
|
||||
|
||||
To avoid useless calculation, square distance is used as much as possible. For
|
||||
example, comparing two distances is the same as comparing their squares.
|
||||
|
||||
]]
|
||||
|
||||
local p = dofile(grunds.path .. "/profile.lua")
|
||||
|
||||
local water_level = tonumber(minetest.get_mapgen_setting("water_level"))
|
||||
|
||||
-- Test function
|
||||
minetest.register_chatcommand("g", {
|
||||
params = "",
|
||||
description = "Grund !",
|
||||
func = function(name, param)
|
||||
local player = minetest.get_player_by_name(name)
|
||||
if not player then
|
||||
return false, "Player not found"
|
||||
end
|
||||
local pos = player:get_pos()
|
||||
local center = {
|
||||
x = math.floor(pos.x),
|
||||
z = math.floor(pos.z),
|
||||
}
|
||||
|
||||
center.y = grunds.getLevelAtPoint(center.x, center.z)
|
||||
|
||||
if center.y == nil then
|
||||
return false, "Not a suitable position for growing a tree"
|
||||
end
|
||||
if center.y < water_level then center.y = water_level end
|
||||
|
||||
p.init()
|
||||
p.start('total')
|
||||
p.start('voxelmanip')
|
||||
local minp = { x = center.x - 80, y = center.y - 20, z = center.z - 80 }
|
||||
local maxp = { x = center.x + 80, y = center.y + 160, z = center.z + 80 }
|
||||
local manip = minetest.get_voxel_manip()
|
||||
p.stop('voxelmanip')
|
||||
|
||||
p.start('maketree')
|
||||
-- center.y = 50
|
||||
local tree = grunds.make_tree(center, treeparam)
|
||||
p.stop('maketree')
|
||||
|
||||
local segments = tree.segments
|
||||
local tufts = tree.tufts
|
||||
|
||||
print("Segments", #segments)
|
||||
print("Tufts", #tufts)
|
||||
|
||||
p.start('rendering')
|
||||
grunds.render(segments, tufts, minp, maxp, manip)
|
||||
p.stop('rendering')
|
||||
p.start('voxelmanip')
|
||||
manip:write_to_map()
|
||||
p.stop('voxelmanip')
|
||||
p.stop('total')
|
||||
p.show()
|
||||
|
||||
return true, "Tree grown!"
|
||||
end
|
||||
})
|
@ -18,7 +18,7 @@
|
||||
|
||||
local enable_test_mg = false -- Set to true only mgutils integration tests. NOT FOR PRODUCTION SERVERS
|
||||
|
||||
local mg = {
|
||||
mgutils = {
|
||||
name = minetest.get_mapgen_setting("mg_name"),
|
||||
defaults = {},
|
||||
water_level = tonumber(minetest.get_mapgen_setting("water_level")),
|
||||
@ -28,43 +28,45 @@ local mg = {
|
||||
get_level_at_point = function(x, z) return nil end,
|
||||
}
|
||||
|
||||
function mg.get_setting(name)
|
||||
function mgutils.get_setting(name)
|
||||
return minetest.get_mapgen_setting(""..name) or
|
||||
mg.defaults[name]
|
||||
mgutils.defaults[name]
|
||||
end
|
||||
|
||||
function mg.get_flags(name)
|
||||
function mgutils.get_flags(name)
|
||||
local flags = {}
|
||||
for flag in string.gmatch(mg.get_setting(name), "[^ ,]+") do
|
||||
for flag in string.gmatch(mgutils.get_setting(name), "[^ ,]+") do
|
||||
flags[flag] = true
|
||||
end
|
||||
return flags
|
||||
end
|
||||
|
||||
function mg.get_noiseparams(name)
|
||||
function mgutils.get_noiseparams(name)
|
||||
return minetest.get_mapgen_setting_noiseparams(""..name) or
|
||||
mg.defaults[name]
|
||||
mgutils.defaults[name]
|
||||
end
|
||||
|
||||
function mg.get_noise(name)
|
||||
local n = minetest.get_perlin(mg.get_noiseparams(name))
|
||||
function mgutils.get_noise(name)
|
||||
local n = minetest.get_perlin(mgutils.get_noiseparams(name))
|
||||
return n
|
||||
end
|
||||
|
||||
-- Load mapgen specific functions and fails if not available
|
||||
local modname = minetest.get_current_modname()
|
||||
local mgscript = minetest.get_modpath(modname) .. "/mgutils/mg_" .. mg.name .. ".lua"
|
||||
local mgscript = minetest.get_modpath(modname) .. "/mg_" ..
|
||||
mgutils.name .. ".lua"
|
||||
|
||||
local mgcode, error = loadfile(mgscript)
|
||||
if not mgcode then
|
||||
minetest.log("error", error)
|
||||
minetest.log("error", "Mod " .. modname .. " is not avialable on mapgen "..mg.name.." (mgutils wont work).")
|
||||
minetest.log("error", "Mod " .. modname .. " is not avialable on mapgen " ..
|
||||
mgutils.name.." (mgutils wont work).")
|
||||
return
|
||||
end
|
||||
|
||||
mgcode(mg)
|
||||
mgcode(mgutils)
|
||||
|
||||
if enable_test_mg then
|
||||
if enable_test_mg and minetest.get_modpath("default") then
|
||||
-- This will create a mese block each 16 nodes, at the altitude given by mgutil
|
||||
-- No block added if altitude not found.
|
||||
-- Mese blocks should be exactly on the top of the map generated terain
|
||||
@ -79,8 +81,8 @@ if enable_test_mg then
|
||||
|
||||
for x = math.ceil(minp.x/16)*16, maxp.x, 16 do
|
||||
for z = math.ceil(minp.z/16)*16, maxp.z, 16 do
|
||||
local y = mg.get_level_at_point(x, z)
|
||||
if y then
|
||||
local y = mgutils.get_level_at_point(x, z)
|
||||
if y and y <= maxp.y and y >= minp.y then
|
||||
data[area:index(x, y, z)] = c_mese
|
||||
end
|
||||
end
|
||||
@ -89,5 +91,3 @@ if enable_test_mg then
|
||||
vm:write_to_map()
|
||||
end)
|
||||
end
|
||||
|
||||
return mg
|
129
mgutils/mg_v6.lua
Normal file
@ -0,0 +1,129 @@
|
||||
--[[
|
||||
Mgutils - Some helper function related to core mapgens
|
||||
(c) Pierre-Yves Rollo
|
||||
|
||||
This program 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 program 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 General Public License for more details.
|
||||
|
||||
You should have received a copy of the GNU General Public License
|
||||
along with this program. If not, see <http://www.gnu.org/licenses/>.
|
||||
--]]
|
||||
|
||||
--------------------------------------------------------------------------------
|
||||
-- Mapgen V6
|
||||
--------------------------------------------------------------------------------
|
||||
|
||||
mgutils.has_biomes = false
|
||||
|
||||
-- Imitation of mapgen_v6.cpp
|
||||
-----------------------------
|
||||
|
||||
local function rangelim(v, min, max)
|
||||
if v < min then return min end
|
||||
if v > max then return max end
|
||||
return v
|
||||
end
|
||||
|
||||
-- Hardcoded default values from mapgen_v7.cpp
|
||||
-- These value are needed when minetest.get_mapgen_setting_noiseparams
|
||||
-- returns nil (unfortunately happends when map_meta have not been saved yet)
|
||||
mgutils.defaults = {
|
||||
mgv6_spflags = "jungles, trees, biomeblend, mudflow",
|
||||
mgv6_np_terrain_base = {offset=-4, scale=20, spread={x=250, y=250, z=250}, seed=82341, octaves=5, persist=0.6, lacunarity=2 },
|
||||
mgv6_np_terrain_higher = {offset=20, scale=16, spread={x=500, y=500, z=500}, seed=85039, octaves=5, persist=0.6, lacunarity=2 },
|
||||
mgv6_np_steepness = {offset=0.85, scale=0.5, spread={x=125, y=125, z=125}, seed=-932, octaves=5, persist=0.7, lacunarity=2 },
|
||||
mgv6_np_height_select = {offset=0, scale=1, spread={x=250, y=250, z=250}, seed=4213, octaves=5, persist=0.69, lacunarity=2 },
|
||||
}
|
||||
|
||||
-- Mapgen parameters
|
||||
local flags = mgutils.get_flags("mgv7_spflags")
|
||||
|
||||
-- Noises parameters
|
||||
local np_terrain_base = mgutils.get_noiseparams("mgv6_np_terrain_base")
|
||||
local np_terrain_higher = mgutils.get_noiseparams("mgv6_np_terrain_higher")
|
||||
local np_steepness = mgutils.get_noiseparams("mgv6_np_steepness")
|
||||
local np_height_select = mgutils.get_noiseparams("mgv6_np_height_select")
|
||||
|
||||
-- Noises
|
||||
local n_terrain_base
|
||||
local n_terrain_higher
|
||||
local n_steepness
|
||||
local n_height_select
|
||||
|
||||
--local intialized = false
|
||||
|
||||
local function init_noises()
|
||||
init_noises = function() end -- Run only once
|
||||
-- if intialized then return end
|
||||
-- intialized = false
|
||||
|
||||
n_terrain_base = minetest.get_perlin(np_terrain_base)
|
||||
n_terrain_higher = minetest.get_perlin(np_terrain_higher)
|
||||
n_steepness = minetest.get_perlin(np_steepness)
|
||||
n_height_select = minetest.get_perlin(np_height_select)
|
||||
end
|
||||
|
||||
local function baseTerrainLevel(terrain_base, terrain_higher,
|
||||
steepness, height_select)
|
||||
|
||||
local base = 1 + terrain_base
|
||||
local higher = 1 + terrain_higher
|
||||
|
||||
-- Limit higher ground level to at least base
|
||||
if higher < base then
|
||||
higher = base
|
||||
end
|
||||
|
||||
-- Steepness factor of cliffs
|
||||
local b = steepness
|
||||
b = rangelim(b, 0.0, 1000.0)
|
||||
b = 5 * b * b * b * b * b * b * b
|
||||
b = rangelim(b, 0.5, 1000.0)
|
||||
|
||||
-- Values 1.5...100 give quite horrible looking slopes
|
||||
if b > 1.5 and b < 100.0 then
|
||||
if b < 10 then
|
||||
b = 1.5
|
||||
else
|
||||
b = 100
|
||||
end
|
||||
end
|
||||
|
||||
local a_off = -0.20 -- Offset to more low
|
||||
local a = 0.5 + b * (a_off + height_select);
|
||||
a = rangelim(a, 0.0, 1.0) -- Limit
|
||||
|
||||
return math.floor(base * (1.0 - a) + higher * a)
|
||||
end
|
||||
|
||||
function mgutils.get_level_at_point(x, z)
|
||||
init_noises()
|
||||
|
||||
if flags.flat then return mgutils.water_level end
|
||||
|
||||
local terrain_base = n_terrain_base:get_2d({
|
||||
x = x + 0.5 * np_terrain_base.spread.x,
|
||||
y = z + 0.5 * np_terrain_base.spread.y})
|
||||
|
||||
local terrain_higher = n_terrain_higher:get_2d({
|
||||
x = x + 0.5 * np_terrain_higher.spread.x,
|
||||
y = z + 0.5 * np_terrain_higher.spread.y})
|
||||
|
||||
local steepness = n_steepness:get_2d({
|
||||
x = x + 0.5 * np_steepness.spread.x,
|
||||
y = z + 0.5 * np_steepness.spread.y})
|
||||
|
||||
local height_select = n_height_select:get_2d({
|
||||
x = x + 0.5 * np_height_select.spread.x,
|
||||
y = z + 0.5 * np_height_select.spread.y})
|
||||
|
||||
return baseTerrainLevel(terrain_base, terrain_higher, steepness,
|
||||
height_select) + 2 -- (Dust)
|
||||
end
|
@ -16,9 +16,11 @@
|
||||
along with this program. If not, see <http://www.gnu.org/licenses/>.
|
||||
--]]
|
||||
|
||||
-- Script argument: table which get stuff from and put stuff to
|
||||
local mg = ...
|
||||
assert(mg or type(mg) ~= "table", "Expected a table argument")
|
||||
--------------------------------------------------------------------------------
|
||||
-- Mapgen V7
|
||||
--------------------------------------------------------------------------------
|
||||
|
||||
mgutils.has_biomes = true
|
||||
|
||||
-- Imitation of mapgen_v7.cpp
|
||||
-----------------------------
|
||||
@ -29,33 +31,29 @@ local function rangelim(v, min, max)
|
||||
return v
|
||||
end
|
||||
|
||||
local function int(x)
|
||||
return math.floor(x)
|
||||
end
|
||||
|
||||
-- Hardcoded default values from mapgen_v7.cpp
|
||||
-- These value are needed when minetest.get_mapgen_setting_noiseparams
|
||||
-- returns nil (unfortunately happends when map_meta have not been saved yet)
|
||||
mg.defaults = {
|
||||
mgutils.defaults = {
|
||||
mgv7_spflags = "mountains, ridges, caverns",
|
||||
mgv7_mount_zero_level = 0,
|
||||
mgv7_np_terrain_base = {offset=4, scale=70, spread={x=600, y=600, z=600 }, seed=82341, octaves=5, persist=0.6, lacunarity=2.0},
|
||||
mgv7_np_terrain_alt = {offset=4, scale=25, spread={x=600, y=600, z=600 }, seed=5934, octaves=5, persist=0.6, lacunarity=2.0},
|
||||
mgv7_np_terrain_persist = {offset=0.6, scale=0.1, spread={x=2000, y=2000, z=2000}, seed=539, octaves=3, persist=0.6, lacunarity=2.0},
|
||||
mgv7_np_height_select = {offset=-8, scale=16, spread={x=500, y=500, z=500 }, seed=4213, octaves=6, persist=0.7, lacunarity=2.0},
|
||||
mgv7_np_mount_height = {offset=256, scale=112, spread={x=1000, y=1000, z=1000}, seed=72449, octaves=3, persist=0.6, lacunarity=2.0},
|
||||
mgv7_np_ridge_uwater = {offset=0, scale=1, spread={x=1000, y=1000, z=1000}, seed=85039, octaves=5, persist=0.6, lacunarity=2.0},
|
||||
mgv7_np_mountain = {offset=-0.6, scale=1, spread={x=250, y=350, z=250 }, seed=5333, octaves=5, persist=0.63, lacunarity=2.0},
|
||||
mgv7_np_terrain_base = {offset=4, scale=70, spread={x=600, y=600, z=600 }, seed=82341, octaves=5, persist=0.6, lacunarity=2 },
|
||||
mgv7_np_terrain_alt = {offset=4, scale=25, spread={x=600, y=600, z=600 }, seed=5934, octaves=5, persist=0.6, lacunarity=2 },
|
||||
mgv7_np_terrain_persist = {offset=0.6, scale=0.1, spread={x=2000, y=2000, z=2000}, seed=539, octaves=3, persist=0.6, lacunarity=2 },
|
||||
mgv7_np_height_select = {offset=-8, scale=16, spread={x=500, y=500, z=500 }, seed=4213, octaves=6, persist=0.7, lacunarity=2 },
|
||||
mgv7_np_mount_height = {offset=256, scale=112, spread={x=1000, y=1000, z=1000}, seed=72449, octaves=3, persist=0.6, lacunarity=2 },
|
||||
mgv7_np_ridge_uwater = {offset=0, scale=1, spread={x=1000, y=1000, z=1000}, seed=85039, octaves=5, persist=0.6, lacunarity=2 },
|
||||
mgv7_np_mountain = {offset=-0.6, scale=1, spread={x=250, y=350, z=250 }, seed=5333, octaves=5, persist=0.63, lacunarity=2 },
|
||||
}
|
||||
|
||||
-- Mapgen parameters
|
||||
local mount_zero_level = mg.get_setting("mgv7_mount_zero_level")
|
||||
local water_level = mg.get_setting("water_level")
|
||||
local flags = mg.get_flags("mgv7_spflags")
|
||||
local mount_zero_level = mgutils.get_setting("mgv7_mount_zero_level")
|
||||
local water_level = mgutils.get_setting("water_level")
|
||||
local flags = mgutils.get_flags("mgv7_spflags")
|
||||
|
||||
-- Noise params
|
||||
local np_terrain_alt = mg.get_noiseparams("mgv7_np_terrain_alt")
|
||||
local np_terrain_base = mg.get_noiseparams("mgv7_np_terrain_base")
|
||||
local np_terrain_alt = mgutils.get_noiseparams("mgv7_np_terrain_alt")
|
||||
local np_terrain_base = mgutils.get_noiseparams("mgv7_np_terrain_base")
|
||||
|
||||
-- Noises
|
||||
local n_height_select
|
||||
@ -70,11 +68,11 @@ local function init_noises()
|
||||
if intialized then return end
|
||||
intialized = false
|
||||
|
||||
n_height_select = mg.get_noise("mgv7_np_height_select")
|
||||
n_terrain_persist = mg.get_noise("mgv7_np_terrain_persist")
|
||||
n_mountain = mg.get_noise("mgv7_np_mountain")
|
||||
n_mount_height = mg.get_noise("mgv7_np_mount_height")
|
||||
n_ridge_uwater = mg.get_noise("mgv7_np_ridge_uwater")
|
||||
n_height_select = mgutils.get_noise("mgv7_np_height_select")
|
||||
n_terrain_persist = mgutils.get_noise("mgv7_np_terrain_persist")
|
||||
n_mountain = mgutils.get_noise("mgv7_np_mountain")
|
||||
n_mount_height = mgutils.get_noise("mgv7_np_mount_height")
|
||||
n_ridge_uwater = mgutils.get_noise("mgv7_np_ridge_uwater")
|
||||
end
|
||||
|
||||
local function v7_baseTerrainLevelAtPoint(x, y)
|
||||
@ -90,10 +88,10 @@ local function v7_baseTerrainLevelAtPoint(x, y)
|
||||
local height_alt = minetest.get_perlin(np_terrain_alt):get_2d(pos2d)
|
||||
|
||||
if (height_alt > height_base) then
|
||||
return int(height_alt)
|
||||
return math.floor(height_alt)
|
||||
end
|
||||
|
||||
return int((height_base * hselect) +
|
||||
return math.floor((height_base * hselect) +
|
||||
(height_alt * (1 - hselect)))
|
||||
end
|
||||
|
||||
@ -107,7 +105,7 @@ local function v7_mountainTerrainAtPoint(x, y, z)
|
||||
return mnt_n + density_gradient >= 0;
|
||||
end
|
||||
|
||||
function mg.get_level_at_point(x, z)
|
||||
function mgutils.get_level_at_point(x, z)
|
||||
init_noises()
|
||||
|
||||
if flags.ridges then
|
||||
|
@ -16,9 +16,11 @@
|
||||
along with this program. If not, see <http://www.gnu.org/licenses/>.
|
||||
--]]
|
||||
|
||||
-- Script argument: table which get stuff from and put stuff to
|
||||
local mg = ...
|
||||
assert(mg or type(mg) ~= "table", "Expected a table argument")
|
||||
--------------------------------------------------------------------------------
|
||||
-- Mapgen Valleys
|
||||
--------------------------------------------------------------------------------
|
||||
|
||||
mgutils.has_biomes = true
|
||||
|
||||
-- Imitation of mapgen_valleys.cpp
|
||||
----------------------------------
|
||||
@ -26,7 +28,7 @@ assert(mg or type(mg) ~= "table", "Expected a table argument")
|
||||
-- Hardcoded default values from mapgen_valleys.cpp
|
||||
-- These value are needed when minetest.get_mapgen_setting_noiseparams
|
||||
-- returns nil (unfortunately happends when map_meta have not been saved yet)
|
||||
mg.defaults = {
|
||||
mgutils.defaults = {
|
||||
mgvalleys_river_size = 5,
|
||||
mgvalleys_np_rivers = { offset=0, scale=1.2, spread={x=256, y=256, z=256 }, seed=1605, octaves=3, persist=0.5, lacunarity=2 },
|
||||
mgvalleys_np_inter_valley_slope = { offset=0, scale=1, spread={x=256, y=512, z=256 }, seed=1993, octaves=6, persist=0.8, lacunarity=2 },
|
||||
@ -37,8 +39,8 @@ mg.defaults = {
|
||||
}
|
||||
|
||||
-- Mapgen parameters
|
||||
local river_size_factor = mg.get_setting("mgvalleys_river_size") / 100
|
||||
local water_level = mg.get_setting("water_level")
|
||||
local river_size_factor = mgutils.get_setting("mgvalleys_river_size") / 100
|
||||
local water_level = mgutils.get_setting("water_level")
|
||||
|
||||
-- Noises
|
||||
local n_rivers
|
||||
@ -54,15 +56,15 @@ local function init_noises()
|
||||
if intialized then return end
|
||||
intialized = false
|
||||
|
||||
n_rivers = mg.get_noise("mgvalleys_np_rivers")
|
||||
n_inter_valley_slope = mg.get_noise("mgvalleys_np_inter_valley_slope")
|
||||
n_terrain_height = mg.get_noise("mgvalleys_np_terrain_height")
|
||||
n_valley_depth = mg.get_noise("mgvalleys_np_valley_depth")
|
||||
n_valley_profile = mg.get_noise("mgvalleys_np_valley_profile")
|
||||
n_inter_valley_fill = mg.get_noise("mgvalleys_np_inter_valley_fill")
|
||||
n_rivers = mgutils.get_noise("mgvalleys_np_rivers")
|
||||
n_inter_valley_slope = mgutils.get_noise("mgvalleys_np_inter_valley_slope")
|
||||
n_terrain_height = mgutils.get_noise("mgvalleys_np_terrain_height")
|
||||
n_valley_depth = mgutils.get_noise("mgvalleys_np_valley_depth")
|
||||
n_valley_profile = mgutils.get_noise("mgvalleys_np_valley_profile")
|
||||
n_inter_valley_fill = mgutils.get_noise("mgvalleys_np_inter_valley_fill")
|
||||
end
|
||||
|
||||
function mg.get_level_at_point(x, z)
|
||||
function mgutils.get_level_at_point(x, z)
|
||||
init_noises()
|
||||
|
||||
-- Check if in a river channel
|
||||
|
3
mgutils/mod.conf
Normal file
@ -0,0 +1,3 @@
|
||||
name = mgutils
|
||||
description = A library providing some mg specific funcitons
|
||||
optional_depends=default
|