Add new mg/ dependency

master
Solebull 2018-12-14 15:59:24 +01:00
parent 4056ffbb58
commit 7e43fcc4ee
44 changed files with 2395 additions and 6 deletions

27
ROADMAP
View File

@ -103,17 +103,32 @@ with exaltion
the player's inventory"
**** TODO [NPC_village] Testing a NPC village mod
CLOCK: [2018-12-14 ven. 15:14]--[2018-12-14 ven. 15:53] => 0:39
CLOCK: [2018-12-13 jeu. 15:56]--[2018-12-13 jeu. 16:13] => 0:17
- [X] Should switch to v 0.4.17.1 : Not yet, still working with 0.4.16
- [X] Must update README.md : no need to download my game, just connect to server
- [ ] Maybe remove mods/ambience/music/sounds/SoundLicenses.txt copyrighted songs
- [ ] Find some female skins
- [ ] May add a NPC village mod : https://github.com/hkzorman/advanced_npc
- [X] Maybe remove mods/ambience/music/sounds/SoundLicenses.txt copyrighted songs
- [-] May add a NPC village mod : https://github.com/hkzorman/advanced_npc
see https://forum.minetest.net/viewtopic.php?t=5120 (best)
or (simpler) https://forum.minetest.net/viewtopic.php?t=5120
- [ ] Generated a new world. Now flying and testing
- [ ] Can't find a NPC village, read further documentation
- [ ] Maybe the mg_villages dependency
- [-] Testing advanced_pc Generated a new world. Now flying and testing
- [ ] Can't find a NPC village, read further documentation
- [X] Maybe the mg_villages dependency https://github.com/Sokomine/mg_villages
- [ ] Now, must install handle_schematics
- [ ] Actual mg_villages error
ServerError: AsyncErr: Lua: finishGenRuntime error from mod 'mg_villages' in callback environment_OnGenerated(): ...inetest/games/minetest-pvp/mods/mg_villages/villages.lua:27: attempt to call method 'get_2d' (a nil value)
stack traceback:
...inetest/games/minetest-pvp/mods/mg_villages/villages.lua:27: in function 'villages_at_point'
....minetest/games/minetest-pvp/mods/mg_villages/mapgen.lua:81: in function 'villages_in_mapchunk'
....minetest/games/minetest-pvp/mods/mg_villages/mapgen.lua:1293: in function <....minetest/games/minetest-pvp/mods/mg_villages/mapgen.lua:1273>
/usr/local/share/minetest/builtin/game/register.lua:412: in function </usr/local/share/minetest/builtin/game/register.lua:392>
- [ ] Find some female skins
- See this error WARNING[Server]: Assignment to undeclared global "p2" inside a function at ...rainbru/.minetest/games/minetest-pvp/mods/ruins/init.lua:99.
**** DONE Must find back my whole mapper
CLOCK: [2018-12-13 jeu. 16:13]--[2018-12-13 jeu. 16:27] => 0:14
*it was a C++ program* downloaded and compiled

1
mods/mg/.gitignore vendored Normal file
View File

@ -0,0 +1 @@
*~

13
mods/mg/README.txt Normal file
View File

@ -0,0 +1,13 @@
mg - Experimental Mapgen for Minetest
A custom Lua-mapgen, with biomes, caves, villages, cliffs and ore generation.
Biomes: Ocean, Dry grasslands, Wet grasslands, Forest, Jungle, Savanna, Desert,
Tundra, Taiga, Beach.
To use, enable the mod before playing a world for the first time (do not use it in an already used world).
License:
LGPL >= 2.1 for the code
CC-BY-SA for the textures

55
mods/mg/buildings.lua Normal file
View File

@ -0,0 +1,55 @@
buildings = {
{sizex= 7, sizez= 7, yoff= 0, ysize= 9, scm="house", orients={2}},
{sizex= 9, sizez= 9, yoff= 0, ysize= 2, scm="wheat_field"},
{sizex= 9, sizez= 9, yoff= 0, ysize= 2, scm="cotton_field"},
{sizex= 3, sizez= 3, yoff= 1, ysize= 4, scm="lamp", weight=1/5, no_rotate=true},
{sizex= 4, sizez= 4, yoff=-5, ysize=11, scm="well", no_rotate=true, pervillage=1},
{sizex= 7, sizez= 7, yoff= 0, ysize= 6, scm="fountain", weight=1/4, pervillage=3},
{sizex= 5, sizez= 5, yoff= 0, ysize= 6, scm="small_house", orients={3}},
{sizex= 6, sizez=12, yoff= 0, ysize= 7, scm="house_with_garden", orients={1}},
{sizex=16, sizez=17, yoff= 0, ysize=12, scm="church", orients={3}, pervillage=1},
{sizex= 5, sizez= 5, yoff= 0, ysize=16, scm="tower", orients={0}, weight=1/7},
{sizex= 8, sizez= 9, yoff= 0, ysize= 6, scm="forge", orients={0}, pervillage=2},
{sizex=11, sizez=12, yoff= 0, ysize= 6, scm="library", orients={1}, pervillage=2},
{sizex=15, sizez= 7, yoff= 0, ysize=12, scm="inn", orients={1}, pervillage=4, weight=1/2},
{sizex=22, sizez=17, yoff= 0, ysize= 7, scm="pub", orients={3}, pervillage=2, weight=1/3},
}
local gravel = minetest.get_content_id("default:gravel")
local rgravel = {}
for i = 1, 2000 do
rgravel[i] = gravel
end
local rgravel2 = {}
for i = 1, 2000 do
rgravel2[i] = rgravel
end
local rair = {}
for i = 1, 2000 do
rair[i] = c_air
end
local rair2 = {}
for i = 1, 2000 do
rair2[i] = rair
end
local road_scm = {rgravel2, rair2}
buildings["road"] = {yoff = 0, ysize = 2, scm = road_scm}
local rwall = {{minetest.get_content_id("default:stonebrick")}}
local wall = {}
for i = 1, 6 do
wall[i] = rwall
end
buildings["wall"] = {yoff = 1, ysize = 6, scm = wall}
local total_weight = 0
for _, i in ipairs(buildings) do
if i.weight == nil then i.weight = 1 end
total_weight = total_weight+i.weight
i.max_weight = total_weight
end
local multiplier = 3000/total_weight
for _,i in ipairs(buildings) do
i.max_weight = i.max_weight*multiplier
end

5
mods/mg/depends.txt Normal file
View File

@ -0,0 +1,5 @@
default
farming
wool
stairs
moretrees?

2
mods/mg/description.txt Normal file
View File

@ -0,0 +1,2 @@
This mod changes the default map generation: it changes the way ores are placed, add new biomes and villages.
Note: do NOT use it in an already generated world!!!

805
mods/mg/init.lua Normal file
View File

@ -0,0 +1,805 @@
mg = {}
local ENABLE_SNOW = false
local DEBUG = false
local DMAX = 20
local AREA_SIZE = 80
dofile(minetest.get_modpath(minetest.get_current_modname()).."/nodes.lua")
local function get_content_id(name)
name = minetest.registered_aliases[name] or name
return minetest.get_content_id(name)
end
c_air = get_content_id("air")
c_ignore = get_content_id("ignore")
c_water = get_content_id("default:water_source")
c_grass = get_content_id("default:dirt_with_grass")
c_dry_grass = get_content_id("mg:dirt_with_dry_grass")
c_dirt_snow = get_content_id("default:dirt_with_snow")
c_snow = get_content_id("default:snow")
c_sapling = get_content_id("default:sapling")
c_tree = get_content_id("default:tree")
c_leaves = get_content_id("default:leaves")
c_junglesapling = get_content_id("default:junglesapling")
c_jungletree = get_content_id("default:jungletree")
c_jungleleaves = get_content_id("default:jungleleaves")
c_savannasapling = get_content_id("mg:savannasapling")
c_savannatree = get_content_id("mg:savannatree")
c_savannaleaves = get_content_id("mg:savannaleaves")
c_pinesapling = get_content_id("mg:pinesapling")
c_pinetree = get_content_id("mg:pinetree")
c_pineleaves = get_content_id("mg:pineleaves")
c_dirt = get_content_id("default:dirt")
c_stone = get_content_id("default:stone")
c_water = get_content_id("default:water_source")
c_ice = get_content_id("default:ice")
c_sand = get_content_id("default:sand")
c_sandstone = get_content_id("default:sandstone")
c_desert_sand = get_content_id("default:desert_sand")
c_desert_stone = get_content_id("default:desert_stone")
c_snowblock = get_content_id("default:snowblock")
c_cactus = get_content_id("default:cactus")
c_grass_1 = get_content_id("default:grass_1")
c_grass_2 = get_content_id("default:grass_2")
c_grass_3 = get_content_id("default:grass_3")
c_grass_4 = get_content_id("default:grass_4")
c_grass_5 = get_content_id("default:grass_5")
c_grasses = {c_grass_1, c_grass_2, c_grass_3, c_grass_4, c_grass_5}
c_jungle_grass = get_content_id("default:junglegrass")
c_dry_shrub = get_content_id("default:dry_shrub")
c_papyrus = get_content_id("default:papyrus")
minetest.register_on_mapgen_init(function(mgparams)
minetest.set_mapgen_params({mgname = "singlenode", flags = "nolight"})
end)
local cache = {}
local function cliff(x, n)
return 0.2*x*x - x + n*x - n*n*x*x - 0.01 * math.abs(x*x*x) + math.abs(x)*100*n*n*n*n
end
local function get_vn(x, z, noise, village)
local vx, vz, vs = village.vx, village.vz, village.vs
return (noise - 2) * 20 +
(40 / (vs * vs)) * ((x - vx) * (x - vx) + (z - vz) * (z - vz))
end
local function get_base_surface_at_point(x, z, vnoise, villages, ni, noise1, noise2, noise3, noise4)
local index = 65536*x+z
if cache[index] ~= nil then return cache[index] end
cache[index] = 25*noise1[ni]+noise2[ni]*noise3[ni]/3
if noise4[ni] > 0.8 then
cache[index] = cliff(cache[index], noise4[ni]-0.8)
end
local s = 0
local t = 0
local noise = vnoise[ni]
for _, village in ipairs(villages) do
local vn = get_vn(x, z, noise, village)
if vn < 40 then
cache[index] = village.vh
return village.vh
elseif vn < 200 then
s = s + ((cache[index] * (vn - 40) + village.vh * (200 - vn)) / 160) / (vn - 40)
t = t + 1 / (vn - 40)
end
end
if t > 0 then
cache[index] = s / t
end
return cache[index]
end
local function surface_at_point(x, z, ...)
return get_base_surface_at_point(x, z, unpack({...}))
end
local SMOOTHED = AREA_SIZE+2*DMAX
local HSMOOTHED = AREA_SIZE+DMAX
local INSIDE = AREA_SIZE-DMAX
local function smooth(x, z, ...)
local s=0
local w=0
for xi=-DMAX, DMAX do
for zi=-DMAX, DMAX do
local d2=xi*xi+zi*zi
if d2<DMAX*DMAX then
local w1 = 1-d2/(DMAX*DMAX)
local w2 = 15/16*w1*w1
w = w+w2
s=s+w2*surface_at_point(x+xi, z+zi, unpack({...}))
end
end
end
return s/w
end
function inside_village(x, z, village, vnoise)
return get_vn(x, z, vnoise:get2d({x = x, y = z}), village) <= 40
end
local wseed
minetest.register_on_mapgen_init(function(mgparams)
wseed = math.floor(mgparams.seed/10000000000)
end)
function get_bseed(minp)
return wseed + math.floor(5*minp.x/47) + math.floor(873*minp.z/91)
end
function get_bseed2(minp)
return wseed + math.floor(87*minp.x/47) + math.floor(73*minp.z/91) + math.floor(31*minp.y/12)
end
local function add_leaves(data, vi, c_leaves, c_snow)
if data[vi]==c_air or data[vi]==c_ignore or data[vi] == c_snow then
data[vi] = c_leaves
end
end
function add_tree(data, a, x, y, z, minp, maxp, pr)
local th = pr:next(3, 4)
for yy=math.max(minp.y, y), math.min(maxp.y, y+th) do
local vi = a:index(x, yy, z)
data[vi] = c_tree
end
local maxy = y+th
for xx=math.max(minp.x, x-1), math.min(maxp.x, x+1) do
for yy=math.max(minp.y, maxy-1), math.min(maxp.y, maxy+1) do
for zz=math.max(minp.z, z-1), math.min(maxp.z, z+1) do
add_leaves(data, a:index(xx, yy, zz), c_leaves)
end
end
end
for i=1,8 do
local xi = pr:next(x-2, x+1)
local yi = pr:next(maxy-1, maxy+1)
local zi = pr:next(z-2, z+1)
for xx=math.max(minp.x, xi), math.min(maxp.x, xi+1) do
for yy=math.max(minp.y, yi), math.min(maxp.y, yi+1) do
for zz=math.max(minp.z, zi), math.min(maxp.z, zi+1) do
add_leaves(data, a:index(xx, yy, zz), c_leaves)
end
end
end
end
end
function add_jungletree(data, a, x, y, z, minp, maxp, pr)
local th = pr:next(7, 11)
for yy=math.max(minp.y, y), math.min(maxp.y, y+th) do
local vi = a:index(x, yy, z)
data[vi] = c_jungletree
end
local maxy = y+th
for xx=math.max(minp.x, x-1), math.min(maxp.x, x+1) do
for yy=math.max(minp.y, maxy-1), math.min(maxp.y, maxy+1) do
for zz=math.max(minp.z, z-1), math.min(maxp.z, z+1) do
add_leaves(data, a:index(xx, yy, zz), c_jungleleaves)
end
end
end
for i=1,30 do
local xi = pr:next(x-3, x+2)
local yi = pr:next(maxy-2, maxy+1)
local zi = pr:next(z-3, z+2)
for xx=math.max(minp.x, xi), math.min(maxp.x, xi+1) do
for yy=math.max(minp.y, yi), math.min(maxp.y, yi+1) do
for zz=math.max(minp.z, zi), math.min(maxp.z, zi+1) do
add_leaves(data, a:index(xx, yy, zz), c_jungleleaves)
end
end
end
end
end
function add_savannatree(data, a, x, y, z, minp, maxp, pr)
local th = pr:next(7, 11)
for yy=math.max(minp.y, y), math.min(maxp.y, y+th) do
local vi = a:index(x, yy, z)
data[vi] = c_savannatree
end
local maxy = y+th
for xx=math.max(minp.x, x-1), math.min(maxp.x, x+1) do
for yy=math.max(minp.y, maxy-1), math.min(maxp.y, maxy+1) do
for zz=math.max(minp.z, z-1), math.min(maxp.z, z+1) do
add_leaves(data, a:index(xx, yy, zz), c_savannaleaves)
end
end
end
for i=1,20 do
local xi = pr:next(x-3, x+2)
local yi = pr:next(maxy-2, maxy)
local zi = pr:next(z-3, z+2)
for xx=math.max(minp.x, xi), math.min(maxp.x, xi+1) do
for yy=math.max(minp.y, yi), math.min(maxp.y, yi+1) do
for zz=math.max(minp.z, zi), math.min(maxp.z, zi+1) do
add_leaves(data, a:index(xx, yy, zz), c_savannaleaves)
end
end
end
end
for i=1,15 do
local xi = pr:next(x-3, x+2)
local yy = pr:next(maxy-6, maxy-5)
local zi = pr:next(z-3, z+2)
for xx=math.max(minp.x, xi), math.min(maxp.x, xi+1) do
for zz=math.max(minp.z, zi), math.min(maxp.z, zi+1) do
if minp.y<=yy and maxp.y>=yy then
add_leaves(data, a:index(xx, yy, zz), c_savannaleaves)
end
end
end
end
end
function add_savannabush(data, a, x, y, z, minp, maxp, pr)
local bh = pr:next(1, 2)
local bw = pr:next(2, 4)
for xx=math.max(minp.x, x-bw), math.min(maxp.x, x+bw) do
for zz=math.max(minp.z, z-bw), math.min(maxp.z, z+bw) do
for yy=math.max(minp.y, y-bh), math.min(maxp.y, y+bh) do
if pr:next(1, 100) < 95 and math.abs(xx-x) < pr:next(bh, bh+2)-math.abs(y-yy) and math.abs(zz-z) < pr:next(bh, bh+2)-math.abs(y-yy) then
add_leaves(data, a:index(xx, yy, zz), c_savannaleaves)
for yyy=math.max(minp.y, yy-2), yy do
add_leaves(data, a:index(xx, yyy, zz), c_savannaleaves)
end
end
end
end
end
if x<=maxp.x and x>=minp.x and y<=maxp.y and y>=minp.y and z<=maxp.z and z>=minp.z then
local vi = a:index(x, y, z)
data[vi] = c_savannatree
end
end
function add_pinetree(data, a, x, y, z, minp, maxp, pr, snow)
if snow == nil then snow = c_snow end
local th = pr:next(9, 13)
for yy=math.max(minp.y, y), math.min(maxp.y, y+th) do
local vi = a:index(x, yy, z)
data[vi] = c_pinetree
end
local maxy = y+th
for xx=math.max(minp.x, x-3), math.min(maxp.x, x+3) do
for yy=math.max(minp.y, maxy-1), math.min(maxp.y, maxy-1) do
for zz=math.max(minp.z, z-3), math.min(maxp.z, z+3) do
if pr:next(1, 100) < 80 then
add_leaves(data, a:index(xx, yy, zz), c_pineleaves, snow)
add_leaves(data, a:index(xx, yy+1, zz), snow)
end
end
end
end
for xx=math.max(minp.x, x-2), math.min(maxp.x, x+2) do
for yy=math.max(minp.y, maxy), math.min(maxp.y, maxy) do
for zz=math.max(minp.z, z-2), math.min(maxp.z, z+2) do
if pr:next(1, 100) < 85 then
add_leaves(data, a:index(xx, yy, zz), c_pineleaves, snow)
add_leaves(data, a:index(xx, yy+1, zz), snow)
end
end
end
end
for xx=math.max(minp.x, x-1), math.min(maxp.x, x+1) do
for yy=math.max(minp.y, maxy+1), math.min(maxp.y, maxy+1) do
for zz=math.max(minp.z, z-1), math.min(maxp.z, z+1) do
if pr:next(1, 100) < 90 then
add_leaves(data, a:index(xx, yy, zz), c_pineleaves, snow)
add_leaves(data, a:index(xx, yy+1, zz), snow)
end
end
end
end
if maxy+1<=maxp.y and maxy+1>=minp.y then
add_leaves(data, a:index(x, maxy+1, z), c_pineleaves, snow)
add_leaves(data, a:index(x, maxy+2, z), snow)
end
local my = 0
for i=1,20 do
local xi = pr:next(x-3, x+2)
local yy = pr:next(maxy-6, maxy-5)
local zi = pr:next(z-3, z+2)
if yy > my then
my = yy
end
for xx=math.max(minp.x, xi), math.min(maxp.x, xi+1) do
for zz=math.max(minp.z, zi), math.min(maxp.z, zi+1) do
if minp.y<=yy and maxp.y>=yy then
add_leaves(data, a:index(xx, yy, zz), c_pineleaves, snow)
add_leaves(data, a:index(xx, yy+1, zz), snow)
end
end
end
end
for xx=math.max(minp.x, x-2), math.min(maxp.x, x+2) do
for yy=math.max(minp.y, my+1), math.min(maxp.y, my+1) do
for zz=math.max(minp.z, z-2), math.min(maxp.z, z+2) do
if pr:next(1, 100) < 85 then
add_leaves(data, a:index(xx, yy, zz), c_pineleaves, snow)
add_leaves(data, a:index(xx, yy+1, zz), snow)
end
end
end
end
for xx=math.max(minp.x, x-1), math.min(maxp.x, x+1) do
for yy=math.max(minp.y, my+2), math.min(maxp.y, my+2) do
for zz=math.max(minp.z, z-1), math.min(maxp.z, z+1) do
if pr:next(1, 100) < 90 then
add_leaves(data, a:index(xx, yy, zz), c_pineleaves, snow)
add_leaves(data, a:index(xx, yy+1, zz), snow)
end
end
end
end
end
dofile(minetest.get_modpath(minetest.get_current_modname()).."/we.lua")
dofile(minetest.get_modpath(minetest.get_current_modname()).."/rotate.lua")
dofile(minetest.get_modpath(minetest.get_current_modname()).."/buildings.lua")
dofile(minetest.get_modpath(minetest.get_current_modname()).."/villages.lua")
dofile(minetest.get_modpath(minetest.get_current_modname()).."/ores.lua")
function get_biome_table(minp, humidity, temperature, range)
if range == nil then range = 1 end
local l = {}
for xi = -range, range do
for zi = -range, range do
local mnp, mxp = {x=minp.x+xi*80,z=minp.z+zi*80}, {x=minp.x+xi*80+80,z=minp.z+zi*80+80}
local pr = PseudoRandom(get_bseed(mnp))
local bxp, bzp = pr:next(mnp.x, mxp.x), pr:next(mnp.z, mxp.z)
local h, t = humidity:get2d({x=bxp, y=bzp}), temperature:get2d({x=bxp, y=bzp})
l[#l+1] = {x=bxp, z=bzp, h=h, t=t}
end
end
return l
end
local function get_distance(x1, x2, z1, z2)
return (x1-x2)*(x1-x2)+(z1-z2)*(z1-z2)
end
function get_nearest_biome(biome_table, x, z)
local m = math.huge
local k = 0
for key, bdef in ipairs(biome_table) do
local dist = get_distance(bdef.x, x, bdef.z, z)
if dist<m then
m=dist
k=key
end
end
return biome_table[k]
end
local function get_perlin_map(seed, octaves, persistance, scale, minp, maxp)
local sidelen = maxp.x - minp.x +1
local pm = minetest.get_perlin_map(
{offset=0, scale=1, spread={x=scale, y=scale, z=scale}, seed=seed, octaves=octaves, persist=persistance},
{x=sidelen, y=sidelen, z=sidelen}
)
return pm:get2dMap_flat({x = minp.x, y = minp.z, z = 0})
end
local function copytable(t)
local t2 = {}
for key, val in pairs(t) do
t2[key] = val
end
return t2
end
local function mg_generate(minp, maxp, emin, emax, vm)
local a = VoxelArea:new{
MinEdge={x=emin.x, y=emin.y, z=emin.z},
MaxEdge={x=emax.x, y=emax.y, z=emax.z},
}
local treemin = {x=emin.x, y=minp.y, z=emin.z}
local treemax = {x=emax.x, y=maxp.y, z=emax.z}
local sidelen = maxp.x-minp.x+1
local noise1 = get_perlin_map(12345, 6, 0.5, 256, minp, maxp)
local noise2 = get_perlin_map(56789, 6, 0.5, 256, minp, maxp)
local noise3 = get_perlin_map(42, 3, 0.5, 32, minp, maxp)
local noise4 = get_perlin_map(8954, 8, 0.5, 1024, minp, maxp)
local noise1raw = minetest.get_perlin(12345, 6, 0.5, 256)
local vcr = VILLAGE_CHECK_RADIUS
local villages = {}
for xi = -vcr, vcr do
for zi = -vcr, vcr do
for _, village in ipairs(villages_at_point({x = minp.x + xi * 80, z = minp.z + zi * 80}, noise1raw)) do
village.to_grow = {}
villages[#villages+1] = village
end
end
end
local pr = PseudoRandom(get_bseed(minp))
local village_noise = minetest.get_perlin(7635, 3, 0.5, 16)
local village_noise_map = get_perlin_map(7635, 3, 0.5, 16, minp, maxp)
local noise_top_layer = get_perlin_map(654, 6, 0.5, 256, minp, maxp)
local noise_second_layer = get_perlin_map(123, 6, 0.5, 256, minp, maxp)
local noise_temperature_raw = minetest.get_perlin(763, 7, 0.5, 512)
local noise_humidity_raw = minetest.get_perlin(834, 7, 0.5, 512)
local noise_temperature = get_perlin_map(763, 7, 0.5, 512, minp, maxp)
local noise_humidity = get_perlin_map(834, 7, 0.5, 512, minp, maxp)
local noise_beach = get_perlin_map(452, 6, 0.5, 256, minp, maxp)
local biome_table = get_biome_table(minp, noise_humidity_raw, noise_temperature_raw)
local data = vm:get_data()
local param2_data = vm:get_param2_data()
local villages_to_grow = {}
local ni = 0
for z = minp.z, maxp.z do
for x = minp.x, maxp.x do
ni = ni + 1
local y = math.floor(surface_at_point(x, z, village_noise_map, villages, ni, noise1, noise2, noise3, noise4))
local humidity = noise_humidity[ni]
local temperature = noise_temperature[ni] - math.max(y, 0) / 50
local biome = get_nearest_biome(biome_table, x, z)
local biome_humidity = biome.h
local biome_temperature = biome.t
local liquid_top
if biome_temperature < -0.4 then
liquid_top = c_ice
else
liquid_top = c_water
end
local above_top, top, top_layer, second_layer
if y < -1 then
above_top = c_air
top = c_dirt
top_layer = c_dirt
second_layer = c_stone
elseif y < 3 and noise_beach[ni] < 0.2 then
above_top = c_air
top = c_sand
top_layer = c_sand
second_layer = c_sandstone
else
above_top = c_air
if biome_temperature > 0.4 then
if biome_humidity < -0.4 then
top = c_desert_sand
top_layer = c_desert_sand
second_layer = c_desert_stone
elseif biome_humidity < 0.4 then
top = c_dry_grass
top_layer = c_dirt
second_layer = c_stone
else
top = c_grass
top_layer = c_dirt
second_layer = c_stone
end
elseif biome_temperature < -0.4 then
above_top = c_snow
top = c_dirt_snow
top_layer = c_dirt
second_layer = c_stone
else
top = c_grass
top_layer = c_dirt
second_layer = c_stone
end
end
if y >= 100 then
above_top = c_air
top = c_snow
top_layer = c_snowblock
end
if y < 0 then
above_top = c_air
end
if y <= maxp.y and y >= minp.y then
local vi = a:index(x, y, z)
if y >= 0 then
data[vi] = top
else
data[vi] = top_layer
end
end
local add_above_top = true
for id, tree in ipairs(mg.registered_trees) do
if tree.min_humidity <= humidity and humidity <= tree.max_humidity
and tree.min_temperature <= temperature and temperature <= tree.max_temperature
and tree.min_biome_humidity <= biome_humidity and biome_humidity <= tree.max_biome_humidity
and tree.min_biome_temperature <= biome_temperature and biome_temperature <= tree.max_biome_temperature
and tree.min_height <= y + 1 and y + 1 <= tree.max_height
and ((not tree.grows_on) or tree.grows_on == top)
and pr:next(1, tree.chance) == 1 then
local in_village = false
for _, village in ipairs(villages) do
if inside_village(x, z, village, village_noise) and not tree.can_be_in_village then
village.to_grow[#village.to_grow+1] = {x = x, y = y + 1, z = z, id = id}
in_village = true
break
end
end
if not in_village then
tree.grow(data, a, x, y + 1, z, minp, maxp, pr)
end
add_above_top = false
break
end
end
if add_above_top and y + 1 <= maxp.y and y + 1 >= minp.y then
local vi = a:index(x, y + 1, z)
data[vi] = above_top
end
if y < 0 and minp.y <= 0 and maxp.y > y then
for yy = math.max(y + 1, minp.y), math.min(0, maxp.y) do
local vi = a:index(x, yy, z)
data[vi] = c_water
end
if maxp.y >= 0 then
data[a:index(x, 0, z)] = liquid_top
end
end
local tl = math.floor((noise_top_layer[ni] + 2.5) * 2)
if y - tl - 1 <= maxp.y and y - 1 >= minp.y then
for yy = math.max(y - tl - 1, minp.y), math.min(y - 1, maxp.y) do
local vi = a:index(x, yy, z)
data[vi] = top_layer
end
end
local sl = math.floor((noise_second_layer[ni] + 5) * 3)
if y - sl - 1 <= maxp.y and y - tl - 2 >= minp.y then
for yy = math.max(y - sl - 1, minp.y), math.min(y - tl - 2, maxp.y) do
local vi = a:index(x, yy, z)
data[vi] = second_layer
end
end
if y - sl - 2 >= minp.y then
for yy = minp.y, math.min(y - sl - 2, maxp.y) do
local vi = a:index(x, yy, z)
data[vi] = c_stone
end
end
end
end
local va = VoxelArea:new{MinEdge=minp, MaxEdge=maxp}
for _, ore_sheet in ipairs(mg.registered_ore_sheets) do
local sidelen = maxp.x - minp.x + 1
local np = copytable(ore_sheet.noise_params)
np.seed = np.seed + minp.y
local pm = minetest.get_perlin_map(np, {x = sidelen, y = sidelen, z = 1})
local map = pm:get2dMap_flat({x = minp.x, y = minp.z})
local ni = 0
local trh = ore_sheet.threshhold
local wherein = minetest.get_content_id(ore_sheet.wherein)
local ore = minetest.get_content_id(ore_sheet.name)
local hmin = ore_sheet.height_min
local hmax = ore_sheet.height_max
local tmin = ore_sheet.tmin
local tmax = ore_sheet.tmax
for z = minp.z, maxp.z do
for x = minp.x, maxp.x do
ni = ni + 1
local noise = map[ni]
if noise > trh then
local thickness = pr:next(tmin, tmax)
local y0 = math.floor(minp.y + (noise - trh) * 4)
for y = math.max(y0, hmin), math.min(y0 + thickness - 1, hmax) do
local vi = a:index(x, y, z)
if data[vi] == wherein or wherein == c_ignore then
data[vi] = ore
end
end
end
end
end
end
for _, ore in ipairs(mg.registered_ores) do
generate_vein(minetest.get_content_id(ore.name), minetest.get_content_id(ore.wherein), minp, maxp, ore.seeddiff, ore, data, a, va)
end
for _, village in ipairs(villages) do
village.to_add = generate_village(village, minp, maxp, data, param2_data, a, village_noise)
end
vm:set_data(data)
vm:set_param2_data(param2_data)
vm:calc_lighting(
{x = minp.x - 16, y = minp.y, z = minp.z - 16},
{x = maxp.x + 16, y = maxp.y, z = maxp.z + 16}
)
vm:write_to_map()
local meta
for _, village in ipairs(villages) do
for _, n in pairs(village.to_add) do
minetest.set_node(n.pos, n.node)
if n.meta ~= nil then
meta = minetest.get_meta(n.pos)
meta:from_table(n.meta)
if n.node.name == "default:chest" then
local inv = meta:get_inventory()
local items = inv:get_list("main")
for i = 1, inv:get_size("main") do
inv:set_stack("main", i, ItemStack(""))
end
local numitems = pr:next(3, 20)
for i = 1, numitems do
local ii = pr:next(1, #items)
local prob = items[ii]:get_count() % 2 ^ 8
local stacksz = math.floor(items[ii]:get_count() / 2 ^ 8)
if pr:next(0, prob) == 0 and stacksz>0 then
local stk = ItemStack({
name = items[ii]:get_name(),
count = pr:next(1, stacksz),
wear = items[ii]:get_wear(),
metadata = items[ii]:get_metadata()
})
local ind = pr:next(1, inv:get_size("main"))
while not inv:get_stack("main", ind):is_empty() do
ind = pr:next(1, inv:get_size("main"))
end
inv:set_stack("main", ind, stk)
end
end
end
end
end
end
end
minetest.register_on_generated(function(minp, maxp, seed)
local vm, emin, emax = minetest.get_mapgen_object("voxelmanip")
mg_generate(minp, maxp, emin, emax, vm)
end)
local function mg_regenerate(pos, name)
local minp = {x = 80 * math.floor((pos.x + 32) / 80) - 32,
y = 80 * math.floor((pos.y + 32) / 80) - 32,
z = 80 * math.floor((pos.z + 32) / 80) - 32}
local maxp = {x = minp.x + 79, y = minp.y + 79, z = minp.z + 79}
local vm = minetest.get_voxel_manip()
local emin, emax = vm:read_from_map(minp, maxp)
local data = {}
for i = 1, (maxp.x - minp.x + 1) * (maxp.y - minp.y + 1) * (maxp.z - minp.z + 1) do
data[i] = c_air
end
vm:set_data(data)
vm:write_to_map()
mg_generate(minp, maxp, emin, emax, vm)
minetest.chat_send_player(name, "Regenerating done, fixing lighting. This may take a while...")
-- Fix lighting
local nodes = minetest.find_nodes_in_area(minp, maxp, "air")
local nnodes = #nodes
local p = math.floor(nnodes / 5)
local dig_node = minetest.dig_node
for i, pos in ipairs(nodes) do
dig_node(pos)
if i % p == 0 then
minetest.chat_send_player(name, math.floor(i / nnodes * 100).."%")
end
end
minetest.chat_send_player(name, "Done")
return minp, maxp
end
minetest.register_chatcommand("mg_regenerate", {
privs = {server = true},
func = function(name, param)
local player = minetest.get_player_by_name(name)
if player then
local pos = player:getpos()
local minp, maxp = mg_regenerate(pos, name)
if minetest.get_modpath("biome_lib") and minp and maxp then
biome_lib.blocklist_aircheck[#biome_lib.blocklist_aircheck + 1] = {minp, maxp}
biome_lib.blocklist_no_aircheck[#biome_lib.blocklist_no_aircheck + 1] = {minp, maxp}
end
end
end,
})
local function spawnplayer(player)
if minetest.setting_get("static_spawnpoint") then return end
local noise1 = minetest.get_perlin(12345, 6, 0.5, 256)
local min_dist = math.huge
local min_pos = {x = 0, y = 3, z = 0}
for bx = -20, 20 do
for bz = -20, 20 do
local minp = {x = -32 + 80 * bx, y = -32, z = -32 + 80 * bz}
for _, village in ipairs(villages_at_point(minp, noise1)) do
if math.abs(village.vx) + math.abs(village.vz) < min_dist then
min_pos = {x = village.vx, y = village.vh + 2, z = village.vz}
min_dist = math.abs(village.vx) + math.abs(village.vz)
end
end
end
end
player:setpos(min_pos)
end
minetest.register_on_newplayer(function(player)
spawnplayer(player)
end)
minetest.register_on_respawnplayer(function(player)
spawnplayer(player)
return true
end)
mg.registered_ores = {}
function mg.register_ore(oredef)
if oredef.wherein == nil then
oredef.wherein = "ignore"
end
if DEBUG then
oredef.wherein = "ignore"
oredef.maxheight = 31000
end
mg.registered_ores[#mg.registered_ores+1] = oredef
end
mg.registered_ore_sheets = {}
function mg.register_ore_sheet(oredef)
if oredef.wherein == nil then
oredef.wherein = "ignore"
end
if DEBUG then
oredef.wherein = "ignore"
oredef.height_max = 31000
end
mg.registered_ore_sheets[#mg.registered_ore_sheets + 1] = oredef
end
mg.registered_trees = {}
function mg.register_tree(treedef)
if treedef.min_humidity == nil then
treedef.min_humidity = -2
end
if treedef.max_humidity == nil then
treedef.max_humidity = 2
end
if treedef.min_biome_humidity == nil then
treedef.min_biome_humidity = -2
end
if treedef.max_biome_humidity == nil then
treedef.max_biome_humidity = 2
end
if treedef.min_temperature == nil then
treedef.min_temperature = -2
end
if treedef.max_temperature == nil then
treedef.max_temperature = 2
end
if treedef.min_biome_temperature == nil then
treedef.min_biome_temperature = -2
end
if treedef.max_biome_temperature == nil then
treedef.max_biome_temperature = 2
end
mg.registered_trees[#mg.registered_trees + 1] = treedef
end
dofile(minetest.get_modpath(minetest.get_current_modname()).."/oredesc.lua")
dofile(minetest.get_modpath(minetest.get_current_modname()).."/trees.lua")
if ENABLE_SNOW then
dofile(minetest.get_modpath(minetest.get_current_modname()).."/snow.lua")
end

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

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

200
mods/mg/nodes.lua Normal file
View File

@ -0,0 +1,200 @@
-------------------------
-- Savanna tree
-------------------------
minetest.register_node("mg:savannatree", {
description = "Savannawood Tree",
tiles = {"mg_dry_tree_top.png", "mg_dry_tree_top.png", "mg_dry_tree.png"},
groups = {tree=1,choppy=2,oddly_breakable_by_hand=1,flammable=2},
sounds = default.node_sound_wood_defaults(),
})
minetest.register_node("mg:savannaleaves", {
description = "Savannawood Leaves",
drawtype = "allfaces_optional",
visual_scale = 1.3,
tiles = {"mg_dry_leaves.png"},
paramtype = "light",
groups = {snappy=3, leafdecay=3, flammable=2, leaves=1},
trunk = "mg:savannatree", -- Support for BASE and Voxelgarden
waving = 1,
drop = {
max_items = 1,
items = {
{
items = {'mg:savannasapling'},
rarity = 20,
},
{
items = {'mg:savannaleaves'},
}
}
},
sounds = default.node_sound_leaves_defaults(),
})
minetest.register_node("mg:savannawood", {
description = "Savannawood Planks",
tiles = {"mg_dry_wood.png"},
groups = {choppy=2,oddly_breakable_by_hand=2,flammable=3,wood=1},
sounds = default.node_sound_wood_defaults(),
})
minetest.register_craft({
output = 'mg:savannawood 4',
recipe = {
{'mg:savannatree'},
}
})
minetest.register_node("mg:savannasapling", {
description = "Savannawood Sapling",
drawtype = "plantlike",
visual_scale = 1.0,
tiles = {"mg_dry_sapling.png"},
inventory_image = "mg_dry_sapling.png",
wield_image = "mg_dry_sapling.png",
paramtype = "light",
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},
sounds = default.node_sound_leaves_defaults(),
})
minetest.register_abm({
nodenames = {"mg:savannasapling"},
interval = 10,
chance = 50,
action = function(pos, node)
local vm = minetest.get_voxel_manip()
local minp, maxp = vm:read_from_map({x=pos.x-10, y=pos.y, z=pos.z-10}, {x=pos.x+10, y=pos.y+20, z=pos.z+10})
local a = VoxelArea:new{MinEdge=minp, MaxEdge=maxp}
local data = vm:get_data()
add_savannatree(data, a, pos.x, pos.y, pos.z, minp, maxp, PseudoRandom(math.random(1,100000)))
vm:set_data(data)
vm:write_to_map()
vm:update_map()
end
})
-------------------------
-- Pine tree
-------------------------
if minetest.registered_nodes["default:pine_tree"] ~= nil then
minetest.register_alias("mg:pinetree", "default:pine_tree")
minetest.register_alias("mg:pineleaves", "default:pine_needles")
minetest.register_alias("mg:pinewood", "default:pine_wood")
minetest.register_alias("mg:pinesapling", "default:pine_sapling")
else
minetest.register_node("mg:pinetree", {
description = "Pine Tree",
tiles = {"mg_pine_tree_top.png", "mg_pine_tree_top.png", "mg_pine_tree.png"},
groups = {tree=1,choppy=2,oddly_breakable_by_hand=1,flammable=2},
sounds = default.node_sound_wood_defaults(),
})
minetest.register_node("mg:pineleaves", {
description = "Pine Leaves",
drawtype = "allfaces_optional",
visual_scale = 1.3,
tiles = {"mg_pine_leaves.png"},
paramtype = "light",
groups = {snappy=3, leafdecay=3, flammable=2, leaves=1},
trunk = "mg:pinetree", -- Support for BASE and Voxelgarden
waving = 1,
drop = {
max_items = 1,
items = {
{
items = {'mg:pinesapling'},
rarity = 20,
},
{
items = {'mg:pineleaves'},
}
}
},
sounds = default.node_sound_leaves_defaults(),
})
minetest.register_node("mg:pinewood", {
description = "Pine Planks",
tiles = {"mg_pine_wood.png"},
groups = {choppy=2,oddly_breakable_by_hand=2,flammable=3,wood=1},
sounds = default.node_sound_wood_defaults(),
})
minetest.register_craft({
output = 'mg:pinewood 4',
recipe = {
{'mg:pinetree'},
}
})
minetest.register_node("mg:pinesapling", {
description = "Pine Sapling",
drawtype = "plantlike",
visual_scale = 1.0,
tiles = {"mg_pine_sapling.png"},
inventory_image = "mg_pine_sapling.png",
wield_image = "mg_pine_sapling.png",
paramtype = "light",
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},
sounds = default.node_sound_leaves_defaults(),
})
minetest.register_abm({
nodenames = {"mg:pinesapling"},
interval = 10,
chance = 50,
action = function(pos, node)
local vm = minetest.get_voxel_manip()
local minp, maxp = vm:read_from_map({x=pos.x-10, y=pos.y, z=pos.z-10}, {x=pos.x+10, y=pos.y+30, z=pos.z+10})
local a = VoxelArea:new{MinEdge=minp, MaxEdge=maxp}
local data = vm:get_data()
add_pinetree(data, a, pos.x, pos.y, pos.z, minp, maxp, PseudoRandom(math.random(1,100000)), c_air)
vm:set_data(data)
vm:write_to_map()
vm:update_map()
end
})
end
-------------------------
-- Other
-------------------------
if minetest.registered_nodes["default:dirt_with_dry_grass"] ~= nil then
minetest.register_alias("mg:dirt_with_dry_grass", "default:dirt_with_dry_grass")
else
minetest.register_node("mg:dirt_with_dry_grass", {
description = "Dry Grass",
tiles = {"mg_dry_grass.png", "default_dirt.png", "default_dirt.png^mg_dry_grass_side.png"},
is_ground_content = true,
groups = {crumbly=3,soil=1},
drop = 'default:dirt',
sounds = default.node_sound_dirt_defaults({
footstep = {name="default_grass_footstep", gain=0.25},
}),
})
end
minetest.register_node("mg:ignore", {
description = "MG Ignore",
drawtype = "airlike",
sunlight_propagates = true,
groups = {snappy=2,not_in_creative_inventory=1},
})

214
mods/mg/oredesc.lua Normal file
View File

@ -0,0 +1,214 @@
mg.register_ore({
name = "air",
seeddiff = 1234,
maxhdistance = 70,
maxvdistance = 70,
maxheight = -3,
seglenghtn = 15,
seglenghtdev = 6,
segincln = 0.2,
segincldev = 0.6,
turnangle = 57,
forkturnangle = 57,
numperblock = 5,
numbranchesn = 2,
numbranchesdev = 0,
mothersizen = -1,
mothersizedev = 0,
sizen = 100,
sizedev = 30,
radius = 2.3
})
mg.register_ore({
name = "default:stone_with_iron",
wherein = "default:stone",
seeddiff = 0,
maxvdistance = 10.5,
maxheight = -16,
seglenghtn = 15,
seglenghtdev = 6,
segincln = 0,
segincldev = 0.6,
turnangle = 57,
forkturnangle = 57,
numperblock = 2.5
})
mg.register_ore({
name = "default:stone_with_coal",
wherein = "default:stone",
seeddiff = 1,
maxvdistance = 10,
sizen = 54,
sizedev = 27,
maxheight = 64,
seglenghtn = 15,
seglenghtdev = 6,
segincln = 0,
segincldev = 0.36,
turnangle = 57,
forkturnangle = 57,
radius = 1,
numperblock = 6
})
mg.register_ore({
name = "default:stone_with_mese",
wherein = "default:stone",
seeddiff = 2,
maxvdistance = 50,
sizen = 7,
sizedev = 3,
maxheight = -128,
seglenghtn = 2,
seglenghtdev = 1,
segincln = 4,
segincldev = 1,
turnangle = 57,
forkturnangle = 57,
numperblock = 0.8,
numbranchesn = 2,
numbranchesdev = 1,
fork_chance = 0.1,
mothersizen = 0,
mothersizedev = 0
})
mg.register_ore({
name = "default:mese",
wherein = "default:stone",
seeddiff = 3,
maxvdistance = 50,
sizen = 3,
sizedev = 1,
maxheight = -1024,
seglenghtn = 2,
seglenghtdev = 1,
segincln = 4,
segincldev = 1,
turnangle = 57,
forkturnangle = 57,
numbranchesn = 2,
numbranchesdev = 1,
fork_chance = 0.1,
radius = 1
})
mg.register_ore({ -- Same parameters exactly as the previous one so it spawns inside
name = "default:lava_source",
wherein = "default:mese",
seeddiff = 3,
maxvdistance = 50,
sizen = 3,
sizedev = 1,
maxheight = -1024,
seglenghtn = 2,
seglenghtdev = 1,
segincln = 4,
segincldev = 1,
turnangle = 57,
forkturnangle = 57,
numbranchesn = 2,
numbranchesdev = 1,
fork_chance = 0.1,
mothersizen = 0,
mothersizedev = 0
})
mg.register_ore({
name = "default:stone_with_copper",
wherein = "default:stone",
seeddiff = 4,
maxvdistance = 10.5,
maxheight = -16,
seglenghtn = 15,
seglenghtdev = 6,
segincln = 0,
segincldev = 0.6,
turnangle = 57,
forkturnangle = 57,
numperblock = 2
})
mg.register_ore({
name = "default:stone_with_diamond",
wherein = "default:stone",
seeddiff = 5,
maxvdistance = 50,
sizen = 20,
sizedev = 5,
maxheight = -256,
seglenghtn = 4,
seglenghtdev = 2,
segincln = 0.3,
segincldev = 0.1,
turnangle = 57,
forkturnangle = 57,
numbranchesn = 2,
numbranchesdev = 1,
fork_chance = 0.1,
radius = 1
})
mg.register_ore({
name = "default:stone_with_gold",
wherein = "default:stone",
seeddiff = 17,
maxvdistance = 10,
sizen = 30,
sizedev = 8,
maxheight = -256,
seglenghtn = 8,
seglenghtdev = 4,
segincln = 0.6,
segincldev = 0.4,
turnangle = 57,
forkturnangle = 57,
numbranchesn = 2,
numbranchesdev = 1,
fork_chance = 0.1,
radius = 1
})
mg.register_ore({
name = "default:clay",
wherein = "default:dirt",
seeddiff = 6,
maxvdistance = 10.5,
maxheight = 0,
minheight = -50,
sizen = 50,
sizedev = 20,
seglenghtn = 15,
seglenghtdev = 6,
segincln = 0,
segincldev = 0.6,
turnangle = 57,
forkturnangle = 57,
numperblock = 1,
radius = 1.5
})
mg.register_ore({
name = "default:lava_source",
seeddiff = 7,
maxhdistance = 20,
maxvdistance = 70,
maxheight = -100,
seglenghtn = 2,
seglenghtdev = 1,
segincln = -5,
segincldev = 2,
turnangle = 57,
forkturnangle = 57,
numperblock = 1,
numbranchesn = 2,
numbranchesdev = 1,
mothersizen = 5,
mothersizedev = 3,
sizen = 8,
sizedev = 2,
radius = 2.3
})

159
mods/mg/ores.lua Normal file
View File

@ -0,0 +1,159 @@
function in_cuboid(pos, minp, maxp)
return (pos.x>=minp.x and pos.y>= minp.y and pos.z>=minp.z and pos.x<=maxp.x and pos.y<=maxp.y and pos.z<=maxp.z)
end
function round_pos(p)
return {x=math.floor(p.x+0.5),y=math.floor(p.y+0.5),z=math.floor(p.z+0.5)}
end
function draw_sphere(name, wherein, center, radius, data, a, insideva)
local rad2 = radius * radius
radius = math.ceil(radius)
local pos0 = {}
for x = -radius, radius do
pos0.x = center.x + x
for y = -radius, radius do
pos0.y = center.y + y
for z = -radius, radius do
pos0.z = center.z + z
if x*x + y*y + z*z <= rad2 and insideva:containsp(pos0) and
((wherein == c_ignore and data[a:indexp(pos0)] ~= c_water) or
data[a:indexp(pos0)] == wherein) then
data[a:indexp(pos0)] = name
end
end
end
end
end
function place_segment(name, wherein, pos1, pos2, minp, maxp, radius, data, a, insideva)
local d = {x = pos2.x - pos1.x, y = pos2.y - pos1.y, z = pos2.z - pos1.z}
local N = math.max(math.abs(d.x), math.abs(d.y), math.abs(d.z))
local s = {x = d.x / N, y = d.y / N, z = d.z / N}
local p = pos1
draw_sphere(name, wherein, pos1, radius, data, a, insideva)
for i = 1, N do
p = {x = p.x + s.x, y = p.y + s.y, z = p.z + s.z}
local p0 = round_pos(p)
if not in_cuboid(p0, minp, maxp) then return end
draw_sphere(name, wherein, p0, radius, data, a, insideva)
end
end
function generate_vein_segment(name, wherein, minp, maxp, pr, pos, angle, rem_size, options, data, a, insideva)
if rem_size <= 0 then return end
local Ln = options.seglenghtn
local Ldev = options.seglenghtdev
local L = pr:next(Ln - Ldev, Ln + Ldev)
local incln = options.segincln * 100
local incldev = options.segincldev * 100
local incl = pr:next(incln - incldev, incln + incldev) / 100
local turnangle = options.turnangle
local forkturnangle = options.forkturnangle
local fork_chance = options.fork_chance * 100
local forkmultn = options.forkmultn * 100
local forkmultdev = options.forkmultdev * 100
local radius = options.radius
local end_pos = {x = pos.x + L * math.cos(angle), y = pos.y - L * incl, z = pos.z + L * math.sin(angle)}
place_segment(name, wherein, round_pos(pos), round_pos(end_pos), minp, maxp, radius, data, a, insideva)
if not in_cuboid(end_pos, minp, maxp) then return end
local new_angle=(math.pi * pr:next(-turnangle, turnangle) / 180) + angle
generate_vein_segment(name, wherein, minp, maxp, pr, end_pos, new_angle, rem_size - L, options, data, a, insideva)
local numforks = math.floor(fork_chance / 100) + 1
fork_chance = fork_chance / numforks
if pr:next(1, 100) <= fork_chance then
for f = 1, numforks do
local new_angle = (math.pi * pr:next(-forkturnangle, forkturnangle) / 180) + angle
local forkmult = pr:next(forkmultn - forkmultdev, forkmultn + forkmultdev) / 100
if forkmult > 1 then forkmult = 1 end
generate_vein_segment(name, wherein, minp, maxp, pr, end_pos, new_angle, forkmult * (rem_size - L), options, data, a, insideva)
end
end
end
function generate_vein(name, wherein, minp, maxp, seeddiff, options, data, a, insideva, second_call)
local seed = get_bseed2(minp) + seeddiff
options = get_or_default(options)
local numperblock = options.numperblock * 1000
local maxhdistance = options.maxhdistance
local maxvdistance = options.maxvdistance
local numbranchesn = options.numbranchesn
local numbranchesdev = options.numbranchesdev
local mothersizen = options.mothersizen * 10
local mothersizedev = options.mothersizedev * 10
local sizen = options.sizen
local sizedev = options.sizedev
if second_call == nil then
local hblocks = math.floor(maxhdistance / 80) + 1
local vblocks = math.floor(maxvdistance / 80) + 1
for xblocksdiff = -hblocks, hblocks do
for yblocksdiff = -vblocks, vblocks do
for zblocksdiff = -hblocks, hblocks do
if xblocksdiff ~= 0 or yblocksdiff ~= 0 or zblocksdiff ~= 0 then
local new_minp = {x = minp.x + xblocksdiff * 80, y = minp.y + yblocksdiff * 80, z = minp.z + zblocksdiff * 80}
local new_maxp = {x = maxp.x + xblocksdiff * 80, y = maxp.y + yblocksdiff * 80, z = maxp.z + zblocksdiff * 80}
generate_vein(name, wherein, new_minp, new_maxp, seeddiff, options, data, a, insideva, true)
end
end
end
end
end
local pr = PseudoRandom(seed)
local numveins = math.floor(numperblock / 1000)
numperblock = numperblock - 1000 * numveins
if pr:next(1,1000) <= numperblock then
numveins = numveins + 1
end
if numveins > 0 then
local min_y = math.max(options.minheight, minp.y)
local max_y = math.min(options.maxheight, maxp.y)
if min_y > max_y then return end
for v = 1, numveins do
local vein_pos = {x = pr:next(minp.x, maxp.x), y = pr:next(min_y, max_y), z = pr:next(minp.z, maxp.z)}
local numbranches = pr:next(numbranchesn - numbranchesdev, numbranchesn + numbranchesdev)
local mothersize = pr:next(mothersizen - mothersizedev, mothersizen + mothersizedev) / 10
if mothersize >= 0 then
draw_sphere(name, wherein,vein_pos, mothersize, data, a, insideva)
end
local minpos = {x = vein_pos.x - maxhdistance, y = vein_pos.y - maxvdistance, z = vein_pos.z - maxhdistance}
local maxpos = {x = vein_pos.x + maxhdistance, y = vein_pos.y + maxvdistance, z = vein_pos.z + maxhdistance}
for i = 1, numbranches do
local start_angle = math.pi * pr:next(0, 359) / 180
local size = pr:next(sizen - sizedev, sizen + sizedev)
generate_vein_segment(name, wherein, minpos, maxpos, pr, vein_pos, start_angle, size, options, data, a, insideva)
end
end
end
end
function get_or_default(options)
if options.numperblock == nil then options.numperblock = 0.3 end
if options.maxhdistance == nil then options.maxhdistance = 32 end
if options.maxvdistance == nil then options.maxvdistance = 32 end
if options.numbranchesn == nil then options.numbranchesn = 3 end
if options.numbranchesdev == nil then options.numbranchesdev = 2 end
if options.mothersizen == nil then options.mothersizen = 1 end
if options.mothersizedev == nil then options.mothersizedev = 0.5 end
if options.sizen == nil then options.sizen = 120 end
if options.sizedev == nil then options.sizedev = 60 end
if options.seglenghtn == nil then options.seglenghtn = 6 end
if options.seglenghtdev == nil then options.seglenghtdev = 2 end
if options.segincln == nil then options.segincln = 0.2 end
if options.segincldev == nil then options.segincldev = 0.1 end
if options.turnangle == nil then options.turnangle = 20 end
if options.forkturnangle == nil then options.forkturnangle = 90 end
if options.fork_chance == nil then options.fork_chance = 0.2 end
if options.forkmultn == nil then options.forkmultn = 0.75 end
if options.forkmultdev == nil then options.forkmultdev = 0.25 end
if options.minheight == nil then options.minheight = -31000 end
if options.maxheight == nil then options.maxheight = 31000 end
if options.radius == nil then options.radius = 0 end
return options
end

58
mods/mg/rotate.lua Normal file
View File

@ -0,0 +1,58 @@
function deepcopy(orig)
return minetest.deserialize(minetest.serialize(orig))
end
function rotate_facedir(facedir)
return ({1, 2, 3, 0,
13, 14, 15, 12,
17, 18, 19, 16,
9, 10, 11, 8,
5, 6, 7, 4,
21, 22, 23, 20})[facedir+1]
end
function rotate_wallmounted(wallmounted)
return ({0, 1, 5, 4, 2, 3})[wallmounted+1]
end
function rotate_scm(scm)
local ysize = #scm
local xsize = #scm[1]
local zsize = #scm[1][1]
local new_scm = {}
for i=1, ysize do
new_scm[i] = {}
for j=1, zsize do
new_scm[i][j] = {}
end
end
for y = 1, ysize do
for x = 1, xsize do
for z = 1, zsize do
local old = scm[y][x][z]
local newx = z
local newz = xsize-x+1
if type(old) ~= "table" or old.rotation == nil then
new_scm[y][newx][newz] = old
elseif old.rotation == "wallmounted" then
local new = deepcopy(old)
new.node.param2 = rotate_wallmounted(new.node.param2)
new_scm[y][newx][newz] = new
elseif old.rotation == "facedir" then
local new = deepcopy(old)
new.node.param2 = rotate_facedir(new.node.param2)
new_scm[y][newx][newz] = new
end
end
end
end
return new_scm
end
function rotate(scm, times)
for i = 1, times do
scm = rotate_scm(scm)
end
return scm
end

1
mods/mg/schems/church.we Normal file

File diff suppressed because one or more lines are too long

File diff suppressed because one or more lines are too long

1
mods/mg/schems/forge.we Normal file

File diff suppressed because one or more lines are too long

File diff suppressed because one or more lines are too long

1
mods/mg/schems/house.we Normal file

File diff suppressed because one or more lines are too long

File diff suppressed because one or more lines are too long

File diff suppressed because one or more lines are too long

1
mods/mg/schems/inn.we Normal file

File diff suppressed because one or more lines are too long

1
mods/mg/schems/lamp.we Normal file

File diff suppressed because one or more lines are too long

File diff suppressed because one or more lines are too long

1
mods/mg/schems/pub.we Normal file

File diff suppressed because one or more lines are too long

File diff suppressed because one or more lines are too long

1
mods/mg/schems/tower.we Normal file

File diff suppressed because one or more lines are too long

1
mods/mg/schems/well.we Normal file

File diff suppressed because one or more lines are too long

File diff suppressed because one or more lines are too long

BIN
mods/mg/screenshot.png Normal file

Binary file not shown.

After

Width:  |  Height:  |  Size: 402 KiB

176
mods/mg/snow.lua Normal file
View File

@ -0,0 +1,176 @@
local function getmp(x)
return (80 * math.floor((x + 32) / 80)) - 32
end
local function get_minp(pos)
return {x=getmp(pos.x), y=getmp(pos.y), z=getmp(pos.z)}
end
--[[local snow_timer = 0
local snow_range = 1
minetest.register_globalstep(function(dtime)
snow_timer = snow_timer + dtime
if snow_timer < 1 then return end
snow_timer = 0
local noise_temperature_raw = minetest.get_perlin(763, 7, 0.5, 512)
local noise_humidity_raw = minetest.get_perlin(834, 7, 0.5, 512)
for _, player in ipairs(minetest.get_connected_players()) do
local pos = player:getpos()
if pos.y > -50 and pos.y < 150 then
--local to_update = {}
--local to_update_index = 1
local minp = get_minp(pos)
local biome_table = get_biome_table(minp, noise_humidity_raw, noise_temperature_raw, snow_range+1)
local vm = minetest.get_voxel_manip()
local eminp, emaxp = vm:read_from_map({x=minp.x-80*snow_range, y=-50, z=minp.z-80*snow_range}, {x=minp.x+79+80*snow_range, y=150, z=minp.z+79+80*snow_range})
--print(dump(eminp), dump(emaxp))
local a = VoxelArea:new{MinEdge=eminp, MaxEdge=emaxp}
local data = vm:get_data()
for i = 1, 80*(snow_range+1)*(snow_range+1) do
local x = math.random(eminp.x, emaxp.x)
local z = math.random(eminp.z, emaxp.z)
local biome = get_nearest_biome(biome_table, x, z)
if biome.t < -0.4 then
local y = emaxp.y
while y >= eminp.y and data[a:index(x, y, z)] == c_air do
y = y - 1
end
if y >= eminp.y and y < emaxp.y then
if data[a:index(x, y, z)] == c_snow then
if minetest.add_node_level({x=x, y=y, z=z}, 7) ~= 0 then
--data[a:index(x, y+1, z)] = c_snow
minetest.set_node({x=x, y=y+1, z=z}, {name = "default:snow"})
end
else
--data[a:index(x, y+1, z)] = c_snow
minetest.set_node({x=x, y=y+1, z=z}, {name = "default:snow"})
end
--to_update[to_update_index] = {x=x,y=y+1,z=z}
--to_update_index = to_update_index+1
end
end
end
--vm:set_data(data)
--vm:write_to_map()
--for _, pos in ipairs(to_update) do
-- nodeupdate(pos)
--end
end
end
end)]]
local function add_snow_level(pos)
local level = minetest.get_node_level(pos)
if level <= 28 then
minetest.add_node_level(pos, 7)
return 0
else
return 7
end
end
local is_snowing = false
local to_snow = {}
local to_snow_index = 0
local SNOW_RANGE = 16
local SNOW_BLOCK_SIZE = 4
local SNOW_STEPS = 10
local SNOW_TIMES_PER_BLOCK = 4
minetest.register_globalstep(function(dtime)
if math.random(1, 5000) == 1 then
is_snowing = not is_snowing
end
if to_snow_index == 0 then
if is_snowing then
for _, player in ipairs(minetest.get_connected_players()) do
local pos = player:getpos()
if pos.y > -50 and pos.y < 150 then
local x = SNOW_BLOCK_SIZE*math.floor((pos.x/SNOW_BLOCK_SIZE)+0.5)
local z = SNOW_BLOCK_SIZE*math.floor((pos.z/SNOW_BLOCK_SIZE)+0.5)
for xi = -SNOW_RANGE, SNOW_RANGE do
for zi = -SNOW_RANGE, SNOW_RANGE do
to_snow_index = to_snow_index + 1
to_snow[to_snow_index] = {x=x+SNOW_BLOCK_SIZE*xi, y=0, z=z+SNOW_BLOCK_SIZE*zi}
end
end
end
end
end
else
local noise_temperature_raw = minetest.get_perlin(763, 7, 0.5, 512)
local noise_humidity_raw = minetest.get_perlin(834, 7, 0.5, 512)
for s = 1, math.min(SNOW_STEPS, to_snow_index) do
local pos = to_snow[to_snow_index]
--print(dump(pos))
to_snow[to_snow_index] = nil
to_snow_index = to_snow_index - 1
local minp = get_minp(pos)
local biome_table = get_biome_table(minp, noise_humidity_raw, noise_temperature_raw)
local vm = minetest.get_voxel_manip()
local eminp, emaxp = vm:read_from_map({x=pos.x, y=-50, z=pos.z}, {x=pos.x + SNOW_BLOCK_SIZE - 1, y=150, z=pos.z + SNOW_BLOCK_SIZE - 1})
--print(eminp.y, emaxp.y)
--print(dump(eminp),dump(emaxp))
local a = VoxelArea:new{MinEdge=eminp, MaxEdge=emaxp}
local data = vm:get_data()
for i = 1, SNOW_TIMES_PER_BLOCK do
local x = math.random(pos.x, pos.x + SNOW_BLOCK_SIZE - 1)
local z = math.random(pos.z, pos.z + SNOW_BLOCK_SIZE - 1)
local biome = get_nearest_biome(biome_table, x, z)
if biome.t < -0.4 then
local y = emaxp.y
while y >= eminp.y and (data[a:index(x, y, z)] == c_air or data[a:index(x, y, z)] == c_ignore) do
y = y - 1
end
if y >= eminp.y and y < emaxp.y then
if data[a:index(x, y, z)] == c_snow then
--if minetest.add_node_level({x=x, y=y, z=z}, 7) ~= 0 then
if add_snow_level({x=x, y=y, z=z}) ~= 0 then
-- do nothing, max stack
--minetest.set_node({x=x, y=y, z=z}, {name = "default:snowblock"})
end
elseif data[a:index(x, y, z)] == c_snowblock or data[a:index(x, y, z)] == c_water then
-- do nothing
else
minetest.set_node({x=x, y=y+1, z=z}, {name = "default:snow"})
end
end
end
end
end
end
end)
minetest.register_abm({
nodenames = {"mg:pineleaves"},
interval = 2,
chance = 4,
action = function(pos, node)
local above = {x=pos.x, y=pos.y+1, z=pos.z}
if minetest.get_node(above).name == "default:snow" then
local level = minetest.get_node_level(above)
if level >= 14 then
for i = 1, 15 do
local p = {x=pos.x, y=pos.y-i, z=pos.z}
local n = minetest.get_node(p).name
if n ~= "air" and n ~= "mg:pineleaves" then
if n == "default:snow" then
--if minetest.add_node_level(p, 7) == 0 then
if add_snow_level(p) == 0 then
minetest.add_node_level(above, -7)
end
else
local above_p = {x=p.x, y=p.y+1, z=p.z}
if minetest.get_node(above_p).name == "air" then
minetest.set_node(above_p, {name = "default:snow"})
minetest.add_node_level(above, -7)
end
end
return
end
end
end
end
end
})

Binary file not shown.

After

Width:  |  Height:  |  Size: 703 B

Binary file not shown.

After

Width:  |  Height:  |  Size: 465 B

Binary file not shown.

After

Width:  |  Height:  |  Size: 468 B

Binary file not shown.

After

Width:  |  Height:  |  Size: 310 B

Binary file not shown.

After

Width:  |  Height:  |  Size: 639 B

Binary file not shown.

After

Width:  |  Height:  |  Size: 754 B

Binary file not shown.

After

Width:  |  Height:  |  Size: 390 B

Binary file not shown.

After

Width:  |  Height:  |  Size: 428 B

Binary file not shown.

After

Width:  |  Height:  |  Size: 290 B

Binary file not shown.

After

Width:  |  Height:  |  Size: 490 B

Binary file not shown.

After

Width:  |  Height:  |  Size: 738 B

Binary file not shown.

After

Width:  |  Height:  |  Size: 388 B

222
mods/mg/trees.lua Normal file
View File

@ -0,0 +1,222 @@
mg.register_tree({
max_biome_humidity = -0.4,
min_biome_temperature = 0.4,
min_height = 4,
max_height = 40,
grows_on = c_desert_sand,
chance = 50,
grow = function(data, a, x, y, z, minp, maxp, pr)
-- Cactus
local ch = pr:next(1, 4)
for yy = math.max(y, minp.y), math.min(y+ch-1, maxp.y) do
data[a:index(x, yy, z)] = c_cactus
end
end
})
mg.register_tree({
max_biome_humidity = -0.4,
min_biome_temperature = 0.4,
min_height = 2,
max_height = 30,
grows_on = c_desert_sand,
chance = 50,
can_be_in_village = true,
grow = function(data, a, x, y, z, minp, maxp, pr)
-- Dry shrub
if minp.y <= y and y <= maxp.y then
data[a:index(x, y, z)] = c_dry_shrub
end
end
})
mg.register_tree({
min_biome_humidity = -0.4,
max_biome_humidity = 0.4,
min_biome_temperature = 0.4,
min_height = 2,
max_height = 12,
grows_on = c_dry_grass,
chance = 1000,
grow = add_savannatree
})
mg.register_tree({
min_biome_humidity = -0.4,
max_biome_humidity = 0.4,
min_biome_temperature = 0.4,
min_height = 13,
max_height = 30,
grows_on = c_dry_grass,
chance = 250,
grow = add_savannatree
})
mg.register_tree({
min_biome_humidity = -0.4,
max_biome_humidity = 0.4,
min_biome_temperature = 0.4,
min_height = 2,
max_height = 40,
grows_on = c_dry_grass,
chance = 1500,
grow = add_savannabush
})
mg.register_tree({
min_biome_humidity = 0.4,
min_biome_temperature = 0.4,
min_height = 1,
max_height = 40,
grows_on = c_grass,
chance = 14,
grow = add_tree
})
mg.register_tree({
min_biome_humidity = 0.4,
min_biome_temperature = 0.4,
min_height = 1,
max_height = 25,
grows_on = c_grass,
chance = 16,
grow = add_jungletree
})
mg.register_tree({
min_biome_humidity = 0.4,
min_biome_temperature = 0.4,
min_height = 1,
max_height = 25,
grows_on = c_grass,
chance = 30,
can_be_in_village = true,
grow = function(data, a, x, y, z, minp, maxp, pr)
-- Jungle grass
if minp.y <= y and y <= maxp.y then
data[a:index(x, y, z)] = c_jungle_grass
end
end
})
mg.register_tree({
min_biome_humidity = -0.4,
max_biome_temperature = -0.4,
min_height = 3,
max_height = 55,
grows_on = c_dirt_snow,
chance = 40,
grow = add_pinetree
})
mg.register_tree({
max_biome_humidity = -0.4,
max_biome_temperature = -0.4,
min_height = 3,
max_height = 55,
grows_on = c_dirt_snow,
chance = 500,
grow = add_pinetree
})
mg.register_tree({
max_biome_humidity = -0.4,
min_biome_temperature = -0.4,
max_biome_temperature = 0.4,
min_height = 1,
max_height = 40,
grows_on = c_grass,
chance = 250,
grow = add_tree
})
mg.register_tree({
max_biome_humidity = -0.4,
min_biome_temperature = -0.4,
max_biome_temperature = 0.4,
min_height = 1,
max_height = 40,
grows_on = c_grass,
chance = 60,
can_be_in_village = true,
grow = function(data, a, x, y, z, minp, maxp, pr)
-- Grass 1-4
if minp.y <= y and y <= maxp.y then
data[a:index(x, y, z)] = c_grasses[pr:next(1, 4)]
end
end
})
mg.register_tree({
min_biome_humidity = 0.4,
min_biome_temperature = -0.4,
max_biome_temperature = 0.4,
min_height = 1,
max_height = 40,
grows_on = c_grass,
chance = 250,
grow = add_tree
})
mg.register_tree({
min_biome_humidity = 0.4,
min_biome_temperature = -0.4,
max_biome_temperature = 0.4,
min_height = 3,
max_height = 40,
grows_on = c_grass,
chance = 3,
can_be_in_village = true,
grow = function(data, a, x, y, z, minp, maxp, pr)
-- Grass 3-5
if minp.y <= y and y <= maxp.y then
data[a:index(x, y, z)] = c_grasses[pr:next(3, 5)]
end
end
})
mg.register_tree({
min_biome_humidity = -0.4,
max_biome_humidity = 0.4,
min_biome_temperature = -0.4,
max_biome_temperature = 0.4,
min_height = 3,
max_height = 40,
grows_on = c_grass,
chance = 20,
grow = add_tree
})
mg.register_tree({
min_height = 1,
max_height = 1,
grows_on = c_grass,
chance = 10,
grow = function(data, a, x, y, z, minp, maxp, pr)
-- Papyrus
local ph = pr:next(2, 4)
for yy = math.max(y, minp.y), math.min(y+ph-1, maxp.y) do
data[a:index(x, yy, z)] = c_papyrus
end
end
})
function mg.get_spawn_tree_func(treedef)
return function(data, a, x, y, z, minp, maxp, pr)
if minp.y <= y and y <= maxp.y then
minetest.after(0, minetest.spawn_tree, {x=x, y=y, z=z}, treedef)
end
end
end
if minetest.get_modpath("moretrees") then
mg.register_tree({
min_humidity = 0,
min_temperature = 0.2,
min_height = 1,
max_height = 5,
grows_on = c_grass,
chance = 800,
grow = mg.get_spawn_tree_func(moretrees.rubber_tree_model)
})
end

343
mods/mg/villages.lua Normal file
View File

@ -0,0 +1,343 @@
VILLAGE_CHECK_RADIUS = 2
VILLAGE_CHECK_COUNT = 1
VILLAGE_CHANCE = 28
VILLAGE_MIN_SIZE = 20
VILLAGE_MAX_SIZE = 40
FIRST_ROADSIZE = 3
BIG_ROAD_CHANCE = 0
-- Enable that for really big villages (there are also really slow to generate)
--[[VILLAGE_CHECK_RADIUS = 3
VILLAGE_CHECK_COUNT = 3
VILLAGE_CHANCE = 28
VILLAGE_MIN_SIZE = 100
VILLAGE_MAX_SIZE = 150
FIRST_ROADSIZE = 5
BIG_ROAD_CHANCE = 50]]
local function is_village_block(minp)
local x, z = math.floor(minp.x/80), math.floor(minp.z/80)
local vcc = VILLAGE_CHECK_COUNT
return (x%vcc == 0) and (z%vcc == 0)
end
function villages_at_point(minp, noise1)
if not is_village_block(minp) then return {} end
local vcr, vcc = VILLAGE_CHECK_RADIUS, VILLAGE_CHECK_COUNT
-- Check if there's another village nearby
for xi = -vcr, vcr, vcc do
for zi = -vcr, 0, vcc do
if xi ~= 0 or zi ~= 0 then
local mp = {x = minp.x + 80*xi, z = minp.z + 80*zi}
local pi = PseudoRandom(get_bseed(mp))
local s = pi:next(1, 400)
local x = pi:next(mp.x, mp.x + 79)
local z = pi:next(mp.z, mp.z + 79)
if s <= VILLAGE_CHANCE and noise1:get2d({x = x, y = z}) >= -0.3 then return {} end
end
end
end
local pr = PseudoRandom(get_bseed(minp))
if pr:next(1, 400) > VILLAGE_CHANCE then return {} end -- No village here
local x = pr:next(minp.x, minp.x + 79)
local z = pr:next(minp.z, minp.z + 79)
if noise1:get2d({x = x, y = z}) < -0.3 then return {} end -- Deep in the ocean
local type = pr:next(1, 1) -- TODO: actually make them
local size = pr:next(VILLAGE_MIN_SIZE, VILLAGE_MAX_SIZE) -- TODO: change to type-dependant sizes
local height = pr:next(5, 20)
--print("A village spawned at: x = "..x..", z = "..z)
return {{vx = x, vz = z, vs = size, vh = height, type = type}}
end
--local function dist_center2(ax, bsizex, az, bsizez)
-- return math.max((ax+bsizex)*(ax+bsizex),ax*ax)+math.max((az+bsizez)*(az+bsizez),az*az)
--end
local function inside_village2(bx, sx, bz, sz, village, vnoise)
return inside_village(bx, bz, village, vnoise) and inside_village(bx+sx, bz, village, vnoise) and inside_village(bx, bz+sz, village, vnoise) and inside_village(bx+sx, bz+sz, village, vnoise)
end
local function choose_building(l, pr)
--::choose::
local btype
while true do
local p = pr:next(1, 3000)
for b, i in ipairs(buildings) do
if i.max_weight >= p then
btype = b
break
end
end
if buildings[btype].pervillage ~= nil then
local n = 0
for j=1, #l do
if l[j].btype == btype then
n = n + 1
end
end
--if n >= buildings[btype].pervillage then
-- goto choose
--end
if n < buildings[btype].pervillage then
return btype
end
else
return btype
end
end
--return btype
end
local function choose_building_rot(l, pr, orient)
local btype = choose_building(l, pr)
local rotation
if buildings[btype].no_rotate then
rotation = 0
else
if buildings[btype].orients == nil then
buildings[btype].orients = {0,1,2,3}
end
rotation = (orient+buildings[btype].orients[pr:next(1, #buildings[btype].orients)])%4
end
local bsizex = buildings[btype].sizex
local bsizez = buildings[btype].sizez
if rotation%2 == 1 then
bsizex, bsizez = bsizez, bsizex
end
return btype, rotation, bsizex, bsizez
end
local function placeable(bx, bz, bsizex, bsizez, l, exclude_roads)
for _, a in ipairs(l) do
if (a.btype ~= "road" or not exclude_roads) and math.abs(bx+bsizex/2-a.x-a.bsizex/2)<=(bsizex+a.bsizex)/2 and math.abs(bz+bsizez/2-a.z-a.bsizez/2)<=(bsizez+a.bsizez)/2 then return false end
end
return true
end
local function road_in_building(rx, rz, rdx, rdz, roadsize, l)
if rdx == 0 then
return not placeable(rx-roadsize+1, rz, 2*roadsize-2, 0, l, true)
else
return not placeable(rx, rz-roadsize+1, 0, 2*roadsize-2, l, true)
end
end
local function when(a, b, c)
if a then return b else return c end
end
local calls
local function generate_road(village, l, pr, roadsize, rx, rz, rdx, rdz, vnoise)
local vx, vz, vh, vs = village.vx, village.vz, village.vh, village.vs
local calls_to_do = {}
local rxx = rx
local rzz = rz
local mx, m2x, mz, m2z, mmx, mmz
mx, m2x, mz, m2z = rx, rx, rz, rz
local orient1, orient2
if rdx == 0 then
orient1 = 0
orient2 = 2
else
orient1 = 3
orient2 = 1
end
while inside_village(rx, rz, village, vnoise) and not road_in_building(rx, rz, rdx, rdz, roadsize, l) do
if roadsize > 1 and pr:next(1, 4) == 1 then
--generate_road(vx, vz, vs, vh, l, pr, roadsize-1, rx, rz, math.abs(rdz), math.abs(rdx))
calls_to_do[#calls_to_do+1] = {rx=rx+(roadsize - 1)*rdx, rz=rz+(roadsize - 1)*rdz, rdx=math.abs(rdz), rdz=math.abs(rdx)}
m2x = rx + (roadsize - 1)*rdx
m2z = rz + (roadsize - 1)*rdz
rx = rx + (2*roadsize - 1)*rdx
rz = rz + (2*roadsize - 1)*rdz
end
--else
--::loop::
local exitloop = false
local tries = 0
local btype, rotation, bsizex, bsizez
local bx, bz
while true do
if not inside_village(rx, rz, village, vnoise) or road_in_building(rx, rz, rdx, rdz, roadsize, l) then
exitloop = true
break
end
btype, rotation, bsizex, bsizez = choose_building_rot(l, pr, orient1)
bx = rx + math.abs(rdz) * (roadsize + 1) - when(rdx == -1, bsizex - 1, 0)
bz = rz + math.abs(rdx) * (roadsize + 1) - when(rdz == -1, bsizez - 1, 0)
if placeable(bx, bz, bsizex, bsizez, l) and inside_village2(bx, bsizex, bz, bsizez, village, vnoise) then
break
end
if tries > 5 then
rx = rx + rdx
rz = rz + rdz
tries = 0
else
tries = tries + 1
end
--goto loop
end
if exitloop then break end
rx = rx + (bsizex + 1) * rdx
rz = rz + (bsizez + 1) * rdz
mx = rx - 2 * rdx
mz = rz - 2 * rdz
l[#l + 1] = {x = bx, y = vh, z = bz, btype = btype, bsizex = bsizex, bsizez = bsizez, brotate = rotation}
--end
end
rx = rxx
rz = rzz
while inside_village(rx, rz, village, vnoise) and not road_in_building(rx, rz, rdx, rdz, roadsize, l) do
if roadsize > 1 and pr:next(1, 4) == 1 then
--generate_road(vx, vz, vs, vh, l, pr, roadsize-1, rx, rz, -math.abs(rdz), -math.abs(rdx))
calls_to_do[#calls_to_do+1] = {rx=rx+(roadsize - 1)*rdx, rz=rz+(roadsize - 1)*rdz, rdx=-math.abs(rdz), rdz=-math.abs(rdx)}
m2x = rx + (roadsize - 1)*rdx
m2z = rz + (roadsize - 1)*rdz
rx = rx + (2*roadsize - 1)*rdx
rz = rz + (2*roadsize - 1)*rdz
end
--else
--::loop::
local exitloop = false
local tries = 0
local btype, rotation, bsizex, bsizez
local bx, bz
while true do
if not inside_village(rx, rz, village, vnoise) or road_in_building(rx, rz, rdx, rdz, roadsize, l) then
exitloop = true
break
end
btype, rotation, bsizex, bsizez = choose_building_rot(l, pr, orient2)
bx = rx - math.abs(rdz) * (bsizex + roadsize) - when(rdx == -1, bsizex - 1, 0)
bz = rz - math.abs(rdx) * (bsizez + roadsize) - when(rdz == -1, bsizez - 1, 0)
if placeable(bx, bz, bsizex, bsizez, l) and inside_village2(bx, bsizex, bz, bsizez, village, vnoise) then
break
end
if tries > 5 then
rx = rx + rdx
rz = rz + rdz
tries = 0
else
tries = tries + 1
end
--goto loop
end
if exitloop then break end
rx = rx + (bsizex + 1) * rdx
rz = rz + (bsizez + 1) * rdz
m2x = rx - 2 * rdx
m2z = rz - 2 * rdz
l[#l + 1] = {x = bx, y = vh, z = bz, btype = btype, bsizex = bsizex, bsizez = bsizez, brotate = rotation}
--end
end
if road_in_building(rx, rz, rdx, rdz, roadsize, l) then
mmx = rx - 2*rdx
mmz = rz - 2*rdz
end
mx = mmx or rdx*math.max(rdx*mx, rdx*m2x)
mz = mmz or rdz*math.max(rdz*mz, rdz*m2z)
local rxmin, rxmax, rzmin, rzmax
if rdx == 0 then
rxmin = rx - roadsize + 1
rxmax = rx + roadsize - 1
rzmin = math.min(rzz, mz)
rzmax = math.max(rzz, mz)
else
rzmin = rz - roadsize + 1
rzmax = rz + roadsize - 1
rxmin = math.min(rxx, mx)
rxmax = math.max(rxx, mx)
end
l[#l + 1] = {x = rxmin, y = vh, z = rzmin, btype = "road",
bsizex = rxmax - rxmin + 1, bsizez = rzmax - rzmin + 1, brotate = 0}
for _, i in ipairs(calls_to_do) do
local new_roadsize = roadsize - 1
if pr:next(1, 100) <= BIG_ROAD_CHANCE then
new_roadsize = roadsize
end
calls[calls.index] = {village, l, pr, new_roadsize, i.rx, i.rz, i.rdx, i.rdz, vnoise}
calls.index = calls.index+1
end
end
local function generate_bpos(village, pr, vnoise)
local vx, vz, vh, vs = village.vx, village.vz, village.vh, village.vs
local l = {}
local rx = vx - vs
local rz = vz
while inside_village(rx, rz, village, vnoise) do
rx = rx - 1
end
rx = rx + 5
calls = {index = 1}
generate_road(village, l, pr, FIRST_ROADSIZE, rx, rz, 1, 0, vnoise)
local i = 1
while i < calls.index do
generate_road(unpack(calls[i]))
i = i + 1
end
return l
end
local function generate_building(pos, minp, maxp, data, param2_data, a, pr, extranodes)
local binfo = buildings[pos.btype]
local scm
if type(binfo.scm) == "string" then
scm = import_scm(binfo.scm)
else
scm = binfo.scm
end
scm = rotate(scm, pos.brotate)
for x = 0, pos.bsizex - 1 do
for y = 0, binfo.ysize - 1 do
for z = 0, pos.bsizez - 1 do
local ax, ay, az = pos.x + x, pos.y + y + binfo.yoff, pos.z + z
if (ax >= minp.x and ax <= maxp.x) and (ay >= minp.y and ay <= maxp.y) and (az >= minp.z and az <= maxp.z) then
local t = scm[y +1][x +1][z + 1]
if type(t) == "table" then
if t.extranode then
table.insert(extranodes, {node = t.node, meta = t.meta, pos = {x = ax, y = ay, z = az}})
else
data[a:index(ax, ay, az)] = t.node.content
param2_data[a:index(ax, ay, az)] = t.node.param2
end
elseif t ~= c_ignore then
data[a:index(ax, ay, az)] = t
end
end
end
end
end
end
local MIN_DIST = 1
local function pos_far_buildings(x, z, l)
for _, a in ipairs(l) do
if a.x - MIN_DIST <= x and x <= a.x + a.bsizex + MIN_DIST and
a.z - MIN_DIST <= z and z <= a.z + a.bsizez + MIN_DIST then
return false
end
end
return true
end
function generate_village(village, minp, maxp, data, param2_data, a, vnoise)
local vx, vz, vs, vh = village.vx, village.vz, village.vs, village.vh
local seed = get_bseed({x=vx, z=vz})
local pr_village = PseudoRandom(seed)
local bpos = generate_bpos(village, pr_village, vnoise)
local pr = PseudoRandom(seed)
for _, g in ipairs(village.to_grow) do
if pos_far_buildings(g.x, g.z, bpos) then
mg.registered_trees[g.id].grow(data, a, g.x, g.y, g.z, minp, maxp, pr)
end
end
local extranodes = {}
for _, pos in ipairs(bpos) do
generate_building(pos, minp, maxp, data, param2_data, a, pr_village, extranodes)
end
return extranodes
end

105
mods/mg/we.lua Normal file
View File

@ -0,0 +1,105 @@
local function numk(tbl)
local i = 0
for a, b in pairs(tbl) do
i = i + 1
end
return i
end
function import_scm(scm)
local c_ignore = minetest.get_content_id("ignore")
local f, err = io.open(minetest.get_modpath("mg").."/schems/"..scm..".we", "r")
if not f then
error("Could not open schematic '" .. scm .. ".we': " .. err)
end
local value = f:read("*a")
f:close()
if value:sub(1, 2) == "5:" then
value = value:sub(3)
end
value = value:gsub("return%s*{", "", 1):gsub("}%s*$", "", 1)
local escaped = value:gsub("\\\\", "@@"):gsub("\\\"", "@@"):gsub("(\"[^\"]*\")", function(s) return string.rep("@", #s) end)
local startpos, startpos1, endpos = 1, 1
local nodes = {}
while true do
startpos, endpos = escaped:find("},%s*{", startpos)
if not startpos then
break
end
local current = value:sub(startpos1, startpos)
table.insert(nodes, minetest.deserialize("return " .. current))
startpos, startpos1 = endpos, endpos
end
table.insert(nodes, minetest.deserialize("return " .. value:sub(startpos1)))
scm = {}
local maxx, maxy, maxz = -1, -1, -1
for i = 1, #nodes do
local ent = nodes[i]
ent.x = ent.x + 1
ent.y = ent.y + 1
ent.z = ent.z + 1
if ent.x > maxx then
maxx = ent.x
end
if ent.y > maxy then
maxy = ent.y
end
if ent.z > maxz then
maxz = ent.z
end
if scm[ent.y] == nil then
scm[ent.y] = {}
end
if scm[ent.y][ent.x] == nil then
scm[ent.y][ent.x] = {}
end
if ent.param2 == nil then
ent.param2 = 0
end
if ent.meta == nil then
ent.meta = {fields={}, inventory={}}
end
local paramtype2 = minetest.registered_nodes[ent.name] and minetest.registered_nodes[ent.name].paramtype2
if ent.name == "mg:ignore" or not paramtype2 then
scm[ent.y][ent.x][ent.z] = c_ignore
elseif numk(ent.meta.fields) == 0 and numk(ent.meta.inventory) == 0 then
if paramtype2 ~= "facedir" and paramtype2 ~= "wallmounted" then
scm[ent.y][ent.x][ent.z] = minetest.get_content_id(ent.name)
else
scm[ent.y][ent.x][ent.z] = {
node = {
content = minetest.get_content_id(ent.name),
param2 = ent.param2},
rotation = paramtype2}
end
else
if paramtype2 ~= "facedir" and paramtype2 ~= "wallmounted" then
scm[ent.y][ent.x][ent.z] = {extranode = true,
node = {name = ent.name, param2 = ent.param2},
meta = ent.meta}
else
scm[ent.y][ent.x][ent.z] = {extranode = true,
node = {name = ent.name, param2 = ent.param2},
meta = ent.meta,
rotation = paramtype2}
end
end
end
local c_air = minetest.get_content_id("air")
for x = 1, maxx do
for y = 1, maxy do
for z = 1, maxz do
if scm[y] == nil then
scm[y] = {}
end
if scm[y][x] == nil then
scm[y][x] = {}
end
if scm[y][x][z] == nil then
scm[y][x][z] = c_air
end
end
end
end
return scm
end