updated a few mods, added Goblins
|
@ -56,7 +56,7 @@ minetest.register_node('food:smoker', { --This will allow for smoking meats
|
|||
--]]
|
||||
if inv:contains_item('fuel', 'default:tree') or inv:contains_item('fuel', 'default:jungletree') then
|
||||
minetest.swap_node(pos, {name = 'food:smoker_on', param2=node.param2})
|
||||
timer:start(8*60) --eight minutes to smoke meat
|
||||
timer:start(10) --eight minutes to smoke meat
|
||||
meta:set_string('infotext', 'Burning Smoker')
|
||||
meta:set_string('formspec',
|
||||
'size[8,7]'..
|
||||
|
@ -66,6 +66,16 @@ minetest.register_node('food:smoker', { --This will allow for smoking meats
|
|||
'list[current_player;main;0,3;8,4;]')
|
||||
end
|
||||
end,
|
||||
--[[ allow_metadata_inventory_put = function(pos, listname, index, stack, player)
|
||||
if listname == 'meat' then
|
||||
if stack:get_name() == ('food:steak_raw') then
|
||||
return 1
|
||||
else
|
||||
return 0
|
||||
end
|
||||
end
|
||||
end,
|
||||
--]]
|
||||
})
|
||||
|
||||
minetest.register_node('food:smoker_on', { --Just a change in textures.
|
||||
|
@ -84,6 +94,17 @@ minetest.register_node('food:smoker_on', { --Just a change in textures.
|
|||
type = 'fixed',
|
||||
fixed = {-.5, -.5, -.4, .5, .5, .4},
|
||||
},
|
||||
on_timer = function(pos, elapsed)
|
||||
local meta = minetest.env:get_meta(pos)
|
||||
local inv = meta:get_inventory()
|
||||
local timer = minetest.get_node_timer(pos)
|
||||
if inv:contains_item('meat', 'food:steak_raw') then --make sure the bucket is still there
|
||||
inv:set_stack('meat', 6 ,'food:steak_smoked')
|
||||
meta:set_string('infotext', 'bucket filled with sap, please replace.')
|
||||
timer:stop()
|
||||
return
|
||||
end
|
||||
end,
|
||||
})
|
||||
|
||||
--Craft Recipes
|
||||
|
|
|
@ -0,0 +1,8 @@
|
|||
minetest.register_craft({
|
||||
output = 'furniture:bedside_cabinet',
|
||||
recipe = {
|
||||
{'group:wood', 'group:wood', 'group:wood'},
|
||||
{'group:wood', 'default:chest', 'group:wood'},
|
||||
{'group:wood', 'default:chest', 'group:wood'},
|
||||
}
|
||||
})
|
|
@ -0,0 +1 @@
|
|||
default
|
|
@ -0,0 +1,2 @@
|
|||
dofile(minetest.get_modpath('furniture')..'/crafts.lua')
|
||||
dofile(minetest.get_modpath('furniture')..'/nodes.lua')
|
|
@ -0,0 +1,298 @@
|
|||
# Blender v2.75 (sub 4) OBJ File: 'nightstand.blend'
|
||||
# www.blender.org
|
||||
o Cube_Cube.001
|
||||
v 0.355439 0.041130 -0.382276
|
||||
v 0.355439 0.362854 -0.382276
|
||||
v 0.355439 0.041130 -0.337600
|
||||
v 0.355439 0.362854 -0.337600
|
||||
v -0.355439 0.041130 -0.382276
|
||||
v -0.355439 0.362854 -0.382276
|
||||
v -0.355439 0.041130 -0.337600
|
||||
v -0.355439 0.362854 -0.337600
|
||||
v 0.116264 0.149374 -0.392572
|
||||
v 0.116264 0.254610 -0.392572
|
||||
v 0.116264 0.149374 -0.377958
|
||||
v 0.116264 0.254610 -0.377958
|
||||
v -0.116264 0.149374 -0.392572
|
||||
v -0.116264 0.254610 -0.392572
|
||||
v -0.116264 0.149374 -0.377958
|
||||
v -0.116264 0.254610 -0.377958
|
||||
v 0.355439 -0.358870 -0.382276
|
||||
v 0.355439 -0.037146 -0.382276
|
||||
v 0.355439 -0.358870 -0.337600
|
||||
v 0.355439 -0.037146 -0.337600
|
||||
v -0.355439 -0.358870 -0.382276
|
||||
v -0.355439 -0.037146 -0.382276
|
||||
v -0.355439 -0.358870 -0.337600
|
||||
v -0.355439 -0.037146 -0.337600
|
||||
v 0.116264 -0.250626 -0.392572
|
||||
v 0.116264 -0.145390 -0.392572
|
||||
v 0.116264 -0.250626 -0.377958
|
||||
v 0.116264 -0.145390 -0.377958
|
||||
v -0.116264 -0.250626 -0.392572
|
||||
v -0.116264 -0.145390 -0.392572
|
||||
v -0.116264 -0.250626 -0.377958
|
||||
v -0.116264 -0.145390 -0.377958
|
||||
v 0.409091 -0.500000 -0.342386
|
||||
v 0.409091 0.500000 -0.342386
|
||||
v 0.409091 -0.500000 0.478737
|
||||
v 0.409091 0.500000 0.478737
|
||||
v -0.409091 -0.500000 -0.342386
|
||||
v -0.409091 0.500000 -0.342386
|
||||
v -0.409091 -0.500000 0.478737
|
||||
v -0.409091 0.500000 0.478737
|
||||
v 0.450000 -0.400000 -0.342386
|
||||
v 0.450000 0.400000 -0.342386
|
||||
v 0.450000 0.400000 0.478737
|
||||
v 0.450000 -0.400000 0.478737
|
||||
v -0.450000 0.400000 0.478737
|
||||
v -0.450000 -0.400000 0.478737
|
||||
v -0.450000 0.400000 -0.342386
|
||||
v -0.450000 -0.400000 -0.342386
|
||||
v -0.500000 -0.400000 0.478737
|
||||
v -0.500000 -0.500000 0.478737
|
||||
v -0.500000 0.500000 0.478737
|
||||
v -0.500000 0.500000 -0.342386
|
||||
v -0.500000 -0.400000 -0.342386
|
||||
v -0.500000 -0.500000 -0.342386
|
||||
v -0.500000 0.400000 0.478737
|
||||
v -0.500000 0.400000 -0.342386
|
||||
v 0.500000 0.400000 -0.342386
|
||||
v 0.500000 0.500000 -0.342386
|
||||
v 0.500000 0.500000 0.478737
|
||||
v 0.500000 -0.400000 0.478737
|
||||
v 0.500000 -0.500000 0.478737
|
||||
v 0.500000 -0.500000 -0.342386
|
||||
v 0.500000 -0.400000 -0.342386
|
||||
v 0.500000 0.400000 0.478737
|
||||
v 0.409091 0.400000 -0.433622
|
||||
v 0.409091 0.500000 -0.433622
|
||||
v -0.409091 -0.400000 -0.433622
|
||||
v -0.409091 -0.500000 -0.433622
|
||||
v -0.409091 0.500000 -0.433622
|
||||
v 0.409091 -0.500000 -0.433622
|
||||
v 0.409091 -0.400000 -0.433622
|
||||
v -0.409091 0.400000 -0.433622
|
||||
v -0.500000 -0.400000 -0.433622
|
||||
v -0.500000 -0.500000 -0.433622
|
||||
v -0.500000 0.500000 -0.433622
|
||||
v -0.500000 0.400000 -0.433622
|
||||
v 0.500000 0.400000 -0.433622
|
||||
v 0.500000 0.500000 -0.433622
|
||||
v 0.500000 -0.500000 -0.433622
|
||||
v 0.500000 -0.400000 -0.433622
|
||||
vt 1.995605 -1.091383
|
||||
vt 2.044429 -1.091383
|
||||
vt 2.044430 -0.740654
|
||||
vt 1.995605 -0.740654
|
||||
vt 2.044429 -0.389925
|
||||
vt 1.995605 -0.389925
|
||||
vt 0.523367 1.485645
|
||||
vt -0.254387 1.485646
|
||||
vt -0.254387 1.134051
|
||||
vt 0.523367 1.134050
|
||||
vt 0.998535 1.874522
|
||||
vt 0.949710 1.874522
|
||||
vt 0.949710 1.096769
|
||||
vt 0.998535 1.096769
|
||||
vt 1.921638 1.096769
|
||||
vt 1.970463 1.096769
|
||||
vt 1.970463 1.874522
|
||||
vt 1.921638 1.874522
|
||||
vt -0.094313 0.511501
|
||||
vt -0.078343 0.511501
|
||||
vt -0.078343 0.626225
|
||||
vt -0.094313 0.626225
|
||||
vt -0.078343 0.740948
|
||||
vt -0.094313 0.740948
|
||||
vt 2.027966 1.408676
|
||||
vt 1.773562 1.408676
|
||||
vt 1.773562 1.293669
|
||||
vt 2.027966 1.293669
|
||||
vt -0.063330 0.002693
|
||||
vt -0.047360 0.002693
|
||||
vt -0.047360 0.257097
|
||||
vt -0.063330 0.257097
|
||||
vt -0.062372 0.511501
|
||||
vt -0.078343 0.257097
|
||||
vt -0.062372 0.257097
|
||||
vt 1.970463 1.605577
|
||||
vt 2.019287 1.605577
|
||||
vt 2.019287 1.956306
|
||||
vt 1.970463 1.956306
|
||||
vt 2.044429 -0.039196
|
||||
vt 1.995605 -0.039196
|
||||
vt 0.523367 1.837240
|
||||
vt -0.254387 1.837241
|
||||
vt 0.001465 0.780447
|
||||
vt -0.047360 0.780447
|
||||
vt 0.001465 0.002693
|
||||
vt 1.872813 1.096769
|
||||
vt 1.872813 1.874522
|
||||
vt -0.062372 0.626225
|
||||
vt -0.062372 0.740948
|
||||
vt 2.282370 1.408676
|
||||
vt 2.282370 1.293669
|
||||
vt -0.094313 0.002693
|
||||
vt -0.078343 0.002693
|
||||
vt -0.094313 0.257097
|
||||
vt -0.982098 -1.036679
|
||||
vt -1.091383 -0.991922
|
||||
vt -1.091383 -1.091383
|
||||
vt -0.982098 -1.091383
|
||||
vt -0.982098 -0.052011
|
||||
vt -1.091383 -0.096769
|
||||
vt 1.098242 -0.052011
|
||||
vt 1.995605 -0.052011
|
||||
vt 1.995605 0.002693
|
||||
vt 1.098242 0.002693
|
||||
vt 1.098242 -1.091383
|
||||
vt 1.098242 -1.036679
|
||||
vt 0.998535 -0.991922
|
||||
vt 0.998535 -1.091383
|
||||
vt 0.898828 -0.096769
|
||||
vt 0.001465 -0.096769
|
||||
vt 0.001465 -0.991921
|
||||
vt 0.898828 -0.991922
|
||||
vt 0.101172 0.102154
|
||||
vt 0.998535 0.102154
|
||||
vt 0.998535 0.997307
|
||||
vt 0.101172 0.997307
|
||||
vt -0.991676 0.002693
|
||||
vt -0.991676 0.057397
|
||||
vt -1.091383 0.102154
|
||||
vt -1.091383 0.002693
|
||||
vt 1.882759 0.002693
|
||||
vt 1.882759 0.987361
|
||||
vt 1.008481 0.987361
|
||||
vt 1.008481 0.002693
|
||||
vt 0.898828 0.002693
|
||||
vt 0.998535 -0.096769
|
||||
vt 0.998535 0.002693
|
||||
vt -1.091383 1.991922
|
||||
vt -1.091383 1.096769
|
||||
vt -0.217105 1.096769
|
||||
vt -0.217105 1.991922
|
||||
vt -0.107820 -0.052011
|
||||
vt -0.107820 -1.036679
|
||||
vt 1.995605 -1.036679
|
||||
vt 0.998535 1.882514
|
||||
vt 0.998535 0.987361
|
||||
vt 1.872813 0.987361
|
||||
vt 1.872813 1.882514
|
||||
vt 0.813940 2.091383
|
||||
vt 0.813940 1.196230
|
||||
vt 0.923225 1.196230
|
||||
vt 0.923225 2.091383
|
||||
vt 0.704655 2.091383
|
||||
vt 0.704655 1.196230
|
||||
vt 0.001465 -1.091383
|
||||
vt 0.898828 -1.091383
|
||||
vt 0.595370 1.991922
|
||||
vt 0.704655 1.991922
|
||||
vt 0.595370 2.091383
|
||||
vt 0.101172 0.002693
|
||||
vt -0.107820 0.002693
|
||||
vt -0.982098 0.002693
|
||||
vt -0.094313 0.057397
|
||||
vt 0.486085 1.991922
|
||||
vt 0.486085 1.096769
|
||||
vt 0.595370 1.096769
|
||||
vt 0.704655 1.096769
|
||||
vt -0.991676 1.042065
|
||||
vt -0.094313 1.042065
|
||||
vt -0.094313 1.096768
|
||||
vt -0.991676 1.096769
|
||||
vt -0.107820 -1.091383
|
||||
vt -1.091383 0.997307
|
||||
vt 0.101172 1.096769
|
||||
vt 1.982098 0.102154
|
||||
vt 1.982098 0.997307
|
||||
vt 1.872813 0.997307
|
||||
vt 1.872813 0.102154
|
||||
vt 2.091383 0.102154
|
||||
vt 2.091383 0.997307
|
||||
vt 1.872813 0.002693
|
||||
vt 1.982098 0.002693
|
||||
vt 2.091383 0.002693
|
||||
vt 2.091383 1.096769
|
||||
vt 1.982099 1.096769
|
||||
vt 0.813940 1.096769
|
||||
vt 0.923225 1.096769
|
||||
vt 0.001465 0.997307
|
||||
vt 0.001465 0.102154
|
||||
vt 0.486085 2.091383
|
||||
vt 0.001465 1.096769
|
||||
vn 1.000000 0.000000 0.000000
|
||||
vn -1.000000 0.000000 0.000000
|
||||
vn -0.000000 0.000000 -1.000000
|
||||
vn 0.000000 -1.000000 0.000000
|
||||
vn 0.000000 1.000000 0.000000
|
||||
vn 0.000000 0.000000 1.000000
|
||||
s off
|
||||
f 2/1/1 4/2/1 3/3/1 1/4/1
|
||||
f 8/5/2 6/6/2 5/4/2 7/3/2
|
||||
f 6/7/3 2/8/3 1/9/3 5/10/3
|
||||
f 1/11/4 3/12/4 7/13/4 5/14/4
|
||||
f 6/15/5 8/16/5 4/17/5 2/18/5
|
||||
f 10/19/1 12/20/1 11/21/1 9/22/1
|
||||
f 16/22/2 14/21/2 13/23/2 15/24/2
|
||||
f 14/25/3 10/26/3 9/27/3 13/28/3
|
||||
f 9/29/4 11/30/4 15/31/4 13/32/4
|
||||
f 14/33/5 16/20/5 12/34/5 10/35/5
|
||||
f 18/36/1 20/37/1 19/38/1 17/39/1
|
||||
f 24/40/2 22/41/2 21/6/2 23/5/2
|
||||
f 22/42/3 18/43/3 17/8/3 21/7/3
|
||||
f 17/44/4 19/45/4 23/30/4 21/46/4
|
||||
f 22/47/5 24/15/5 20/18/5 18/48/5
|
||||
f 26/20/1 28/33/1 27/49/1 25/21/1
|
||||
f 32/21/2 30/49/2 29/50/2 31/23/2
|
||||
f 30/51/3 26/25/3 25/28/3 29/52/3
|
||||
f 25/53/4 27/54/4 31/34/4 29/55/4
|
||||
f 30/20/5 32/19/5 28/55/5 26/34/5
|
||||
f 44/56/6 35/57/6 61/58/6 60/59/6
|
||||
f 44/56/6 46/60/6 39/61/6 35/57/6
|
||||
f 47/62/4 45/63/4 55/64/4 56/65/4
|
||||
f 57/66/4 42/67/4 65/68/4 77/69/4
|
||||
f 33/70/4 35/71/4 39/72/4 37/73/4
|
||||
f 38/74/5 40/75/5 36/76/5 34/77/5
|
||||
f 53/78/5 48/79/5 67/80/5 73/81/5
|
||||
f 47/82/3 42/83/3 41/84/3 48/85/3
|
||||
f 62/86/4 33/70/4 70/87/4 79/88/4
|
||||
f 45/89/2 47/90/2 48/91/2 46/92/2
|
||||
f 36/72/6 40/71/6 45/93/6 43/94/6
|
||||
f 43/94/6 45/93/6 46/60/6 44/56/6
|
||||
f 43/95/4 42/67/4 57/66/4 64/1/4
|
||||
f 42/96/1 43/97/1 44/98/1 41/99/1
|
||||
f 49/100/2 53/101/2 54/102/2 50/103/2
|
||||
f 51/104/2 52/105/2 56/101/2 55/100/2
|
||||
f 37/73/4 39/72/4 50/106/4 54/107/4
|
||||
f 58/108/1 57/109/1 77/104/1 78/110/1
|
||||
f 40/75/5 38/74/5 52/111/5 51/88/5
|
||||
f 45/93/6 40/71/6 51/46/6 55/112/6
|
||||
f 39/61/6 46/60/6 49/113/6 50/81/6
|
||||
f 46/114/5 48/79/5 53/78/5 49/53/5
|
||||
f 63/115/1 60/116/1 61/117/1 62/108/1
|
||||
f 58/108/1 59/117/1 64/118/1 57/109/1
|
||||
f 37/73/4 54/107/4 74/69/4 68/68/4
|
||||
f 41/119/5 44/120/5 60/121/5 63/122/5
|
||||
f 36/72/6 43/94/6 64/123/6 59/106/6
|
||||
f 35/71/4 33/70/4 62/86/4 61/46/4
|
||||
f 48/79/5 41/119/5 71/124/5 67/80/5
|
||||
f 34/77/5 36/76/5 59/14/5 58/125/5
|
||||
f 67/126/3 71/127/3 70/128/3 68/129/3
|
||||
f 69/130/3 66/131/3 65/127/3 72/126/3
|
||||
f 67/126/3 68/129/3 74/132/3 73/133/3
|
||||
f 69/130/3 72/126/3 76/133/3 75/134/3
|
||||
f 65/127/3 66/131/3 78/135/3 77/136/3
|
||||
f 70/128/3 71/127/3 80/136/3 79/47/3
|
||||
f 54/102/2 53/101/2 73/137/2 74/138/2
|
||||
f 47/62/4 56/65/4 76/88/4 72/87/4
|
||||
f 38/74/5 34/77/5 66/139/5 69/140/5
|
||||
f 56/101/2 52/105/2 75/118/2 76/137/2
|
||||
f 33/70/4 37/73/4 68/68/4 70/87/4
|
||||
f 63/115/1 62/108/1 79/110/1 80/141/1
|
||||
f 52/111/5 38/74/5 69/140/5 75/46/5
|
||||
f 34/77/5 58/125/5 78/142/5 66/139/5
|
||||
f 41/119/5 63/122/5 80/90/5 71/124/5
|
||||
f 42/67/4 47/62/4 72/87/4 65/68/4
|
|
@ -0,0 +1,31 @@
|
|||
minetest.register_node('furniture:bedside_cabinet', {
|
||||
description = 'Nightstand',
|
||||
drawtype = 'mesh',
|
||||
mesh = 'furniture_nightstand.obj',
|
||||
tiles = {'default_wood.png'},
|
||||
groups = {choppy=2,oddly_breakable_by_hand=2, furn=1},
|
||||
inventory_image = "furniture_nightstand.png",
|
||||
paramtype = 'light',
|
||||
paramtype2 = 'facedir',
|
||||
sounds = default.node_sound_wood_defaults(),
|
||||
on_construct = function(pos)
|
||||
local meta = minetest.env:get_meta(pos)
|
||||
local inv = meta:get_inventory()
|
||||
inv:set_size('main', 8*4)
|
||||
inv:set_size('storage', 3*3)
|
||||
inv:set_size('storage1', 9*3)
|
||||
meta:set_string('formspec',
|
||||
'size [9,10.5]'..
|
||||
'bgcolor[#00000000;false]'..
|
||||
'background[9,10.5;0,0;nightstand.png;true]'..
|
||||
'list[current_name;storage;3,0;3,3;]'..
|
||||
'list[current_name;storage1;0,3;9,3]'..
|
||||
'list[current_player;main;0.5,6.5;8,4;]')
|
||||
meta:set_string('infotext', 'Bedside Cabinet')
|
||||
end,
|
||||
can_dig = function(pos,player)
|
||||
local meta = minetest.get_meta(pos);
|
||||
local inv = meta:get_inventory()
|
||||
return inv:is_empty('storage') and inv:is_empty('storage1')
|
||||
end,
|
||||
})
|
After Width: | Height: | Size: 916 B |
After Width: | Height: | Size: 1021 B |
|
@ -10,7 +10,7 @@ local function merge(a, b)
|
|||
end
|
||||
|
||||
function firstToUpper(str)
|
||||
return (str:gsub("^%l", string.upper))
|
||||
return (str:gsub("^%l", string.upper))
|
||||
end
|
||||
|
||||
local basic_properties = {
|
||||
|
@ -26,7 +26,7 @@ local basic_properties = {
|
|||
wall_bottom = {-0.4375, -0.5, -0.3125, 0.4375, -0.4375, 0.3125},
|
||||
wall_side = {-0.5, -0.3125, -0.4375, -0.4375, 0.3125, 0.4375},
|
||||
},
|
||||
groups = {snappy=1}, --2,dig_immediate=2,attached_node=1},
|
||||
groups = {snappy=1, oddly_breakable_by_hand=2, attached_node=1},
|
||||
legacy_wallmounted = true,
|
||||
--sounds = default.node_sound_defaults(),
|
||||
on_construct = function(pos)
|
||||
|
@ -132,35 +132,27 @@ minetest.register_craft({
|
|||
}
|
||||
})
|
||||
|
||||
minetest.register_craft({
|
||||
output = "hiking:"..colour.."_arrow_left",
|
||||
recipe = {
|
||||
{"dye:"..colour,"hiking:"..colour.."_sign"}
|
||||
}
|
||||
})
|
||||
|
||||
minetest.register_craft({
|
||||
output = "hiking:illuminated_"..colour.."_sign",
|
||||
type = "shapeless",
|
||||
type = "shapeless",
|
||||
recipe = { "default:torch", "hiking:"..colour.."_sign" }
|
||||
})
|
||||
|
||||
minetest.register_craft({
|
||||
output = "hiking:illuminated_"..colour.."_arrow_left",
|
||||
type = "shapeless",
|
||||
type = "shapeless",
|
||||
recipe = { "default:torch", "hiking:"..colour.."_arrow_left" }
|
||||
})
|
||||
|
||||
minetest.register_craft({
|
||||
output = "hiking:illuminated_"..colour.."_arrow_right",
|
||||
type = "shapeless",
|
||||
type = "shapeless",
|
||||
recipe = { "default:torch", "hiking:"..colour.."_arrow_right" }
|
||||
})
|
||||
|
||||
end
|
||||
|
||||
local hiking_pole_common = {
|
||||
groups = {snappy=1, oddly_breakable_by_hand=2, },
|
||||
--sounds = default.node_sound_stone_defaults(),
|
||||
paramtype = "light",
|
||||
sunlight_propagates = true,
|
||||
|
@ -171,17 +163,22 @@ local hiking_pole_common = {
|
|||
},
|
||||
}
|
||||
local hiking_pole_bottom = merge(hiking_pole_common, {
|
||||
buildable_to = true,
|
||||
buildable_to = true,
|
||||
groups = {snappy=1, oddly_breakable_by_hand=2, not_in_creative_inventory=0},
|
||||
})
|
||||
local hiking_pole_middle = merge(hiking_pole_common, {
|
||||
buildable_to = false,
|
||||
buildable_to = false,
|
||||
groups = {snappy=1, oddly_breakable_by_hand=2, not_in_creative_inventory=1},
|
||||
})
|
||||
local hiking_pole_top = merge(hiking_pole_common, {
|
||||
buildable_to = false,
|
||||
buildable_to = false,
|
||||
groups = {snappy=1, oddly_breakable_by_hand=2, not_in_creative_inventory=1},
|
||||
})
|
||||
|
||||
local function mk_hiking_pole(id, name, top_face, moreprops, image)
|
||||
minetest.register_node("hiking:"..id.."_bottom", merge(merge(hiking_pole_bottom, {
|
||||
local ntop = "hiking:"..id.."_top"
|
||||
local nbottom = "hiking:"..id.."_bottom"
|
||||
minetest.register_node(nbottom, merge(merge(hiking_pole_bottom, {
|
||||
-- TODO: this should be always on ground
|
||||
description = name.." (bottom)",
|
||||
tiles = {"hiking_pole_sign_cap.png", "hiking_pole_sign_cap.png", "hiking_pole_sign_bottom_.png", "hiking_pole_sign_bottom_.png", "hiking_pole_sign_bottom_.png", "hiking_pole_sign_bottom_.png", },
|
||||
|
@ -191,7 +188,7 @@ minetest.register_node("hiking:"..id.."_bottom", merge(merge(hiking_pole_bottom,
|
|||
after_place_node = function(pos, placer, itemstack)
|
||||
local node = minetest.env:get_node(pos)
|
||||
local p = {x=pos.x, y=pos.y+1, z=pos.z}
|
||||
node.name = "hiking:"..id.."_top"
|
||||
node.name = ntop
|
||||
if minetest.registered_nodes[minetest.env:get_node(p).name].buildable_to then
|
||||
minetest.env:set_node(p, node)
|
||||
else
|
||||
|
@ -202,31 +199,54 @@ minetest.register_node("hiking:"..id.."_bottom", merge(merge(hiking_pole_bottom,
|
|||
|
||||
after_destruct = function(pos, _)
|
||||
local p = {x=pos.x, y=pos.y+1, z=pos.z}
|
||||
if ( minetest.env:get_node(p).name == "hiking:"..id.."_top" ) then
|
||||
if ( minetest.env:get_node(p).name == ntop ) then
|
||||
minetest.env:remove_node(p)
|
||||
end
|
||||
end,
|
||||
|
||||
}), moreprops))
|
||||
|
||||
minetest.register_node("hiking:"..id.."_top", merge(merge(hiking_pole_bottom, {
|
||||
minetest.register_node(ntop, merge(merge(hiking_pole_top, {
|
||||
-- TODO: one should not build on top of this
|
||||
-- TODO: should be always on top of pole_bottom
|
||||
description = name.." (top)",
|
||||
tiles = {"hiking_pole_sign_cap.png", "hiking_pole_sign_cap.png", top_face, top_face, top_face, top_face, },
|
||||
|
||||
on_dig = function(pos, _, _)
|
||||
|
||||
on_dig = function(pos, _, digger)
|
||||
local p = {x=pos.x, y=pos.y-1, z=pos.z}
|
||||
if ( minetest.env:get_node(p).name == "hiking:"..id.."_bottom" ) then
|
||||
minetest.env:remove_node(p)
|
||||
local n = minetest.env:get_node(p)
|
||||
local nn = n.name
|
||||
if ( nn == nbottom ) then
|
||||
minetest.node_dig(p, n, digger)
|
||||
else
|
||||
minetest.log('error', "WARNING: top of hiking pole at "..minetest.pos_to_string(pos).." found on top of '"..nn.."'? This should not happen!")
|
||||
minetest.env:remove_node(pos)
|
||||
end
|
||||
end,
|
||||
end,
|
||||
}), moreprops))
|
||||
end
|
||||
|
||||
local function mk_tall_hiking_pole(id, name, top_face, moreprops, image, height)
|
||||
local h = math.max(height, 2)
|
||||
minetest.register_node("hiking:"..id.."_bottom", merge(merge(hiking_pole_bottom, {
|
||||
local ntop = "hiking:"..id.."_top"
|
||||
local nmiddle = "hiking:"..id.."_middle"
|
||||
local nbottom = "hiking:"..id.."_bottom"
|
||||
local function rm_tall_hiking_pole(pos)
|
||||
local i
|
||||
local p = {x=pos.x, y=pos.y, z=pos.z}
|
||||
local nn
|
||||
for i = 1, h-1 do
|
||||
nn = minetest.env:get_node(p).name
|
||||
if ( nn == ntop or nn == nmiddle ) then
|
||||
minetest.env:remove_node(p)
|
||||
if ( nn == ntop ) then return end
|
||||
p.y = p.y + 1
|
||||
else
|
||||
return
|
||||
end
|
||||
end
|
||||
end
|
||||
minetest.register_node(nbottom, merge(merge(hiking_pole_bottom, {
|
||||
-- TODO: this should be always on ground
|
||||
description = name.." (bottom)",
|
||||
tiles = {"hiking_pole_sign_cap.png", "hiking_pole_sign_cap.png", "hiking_pole_sign_bottom_.png", "hiking_pole_sign_bottom_.png", "hiking_pole_sign_bottom_.png", "hiking_pole_sign_bottom_.png", },
|
||||
|
@ -246,7 +266,7 @@ minetest.register_node("hiking:"..id.."_bottom", merge(merge(hiking_pole_bottom,
|
|||
end
|
||||
for i = 1, h-2 do
|
||||
p = {x=pos.x, y=pos.y+i, z=pos.z}
|
||||
node.name = "hiking:"..id.."_middle"
|
||||
node.name = nmiddle
|
||||
if minetest.registered_nodes[minetest.env:get_node(p).name].buildable_to then
|
||||
minetest.env:set_node(p, node)
|
||||
else
|
||||
|
@ -255,7 +275,7 @@ minetest.register_node("hiking:"..id.."_bottom", merge(merge(hiking_pole_bottom,
|
|||
end
|
||||
end
|
||||
p = {x=pos.x, y=pos.y+h-1, z=pos.z}
|
||||
node.name = "hiking:"..id.."_top"
|
||||
node.name = ntop
|
||||
if minetest.registered_nodes[minetest.env:get_node(p).name].buildable_to then
|
||||
minetest.env:set_node(p, node)
|
||||
else
|
||||
|
@ -267,9 +287,11 @@ minetest.register_node("hiking:"..id.."_bottom", merge(merge(hiking_pole_bottom,
|
|||
after_destruct = function(pos, _)
|
||||
local i
|
||||
local p
|
||||
local nn
|
||||
for i = 1, h-1 do
|
||||
p = {x=pos.x, y=pos.y+i, z=pos.z}
|
||||
if ( minetest.env:get_node(p).name == "hiking:"..id.."_top" or minetest.env:get_node(p).name == "hiking:"..id.."_middle" ) then
|
||||
nn = minetest.env:get_node(p).name
|
||||
if ( nn == ntop or nn == nmiddle ) then
|
||||
minetest.env:remove_node(p)
|
||||
else
|
||||
return
|
||||
|
@ -279,50 +301,57 @@ minetest.register_node("hiking:"..id.."_bottom", merge(merge(hiking_pole_bottom,
|
|||
|
||||
}), moreprops))
|
||||
|
||||
minetest.register_node("hiking:"..id.."_middle", merge(merge(hiking_pole_middle, {
|
||||
minetest.register_node(nmiddle, merge(merge(hiking_pole_middle, {
|
||||
-- TODO: one should not build on top of this
|
||||
-- TODO: should be always on top of pole_bottom
|
||||
description = name.." (middle)",
|
||||
tiles = {"hiking_pole_sign_cap.png", "hiking_pole_sign_cap.png", "hiking_pole_sign_bottom_.png", "hiking_pole_sign_bottom_.png", "hiking_pole_sign_bottom_.png", "hiking_pole_sign_bottom_.png", },
|
||||
|
||||
on_dig = function(pos, _, _)
|
||||
on_dig = function(pos, _, digger)
|
||||
local i
|
||||
local p
|
||||
local n
|
||||
local nn
|
||||
for i = 1, h-2 do
|
||||
p = {x=pos.x, y=pos.y-i, z=pos.z}
|
||||
local n = minetest.env:get_node(p).name
|
||||
if ( n == "hiking:"..id.."_bottom" ) then
|
||||
minetest.env:remove_node(p)
|
||||
n = minetest.env:get_node(p)
|
||||
nn = n.name
|
||||
if ( nn == nbottom ) then
|
||||
minetest.node_dig(p, n, digger)
|
||||
return
|
||||
elseif not ( n == "hiking:"..id.."_middle" ) then
|
||||
-- TODO: ERROR!
|
||||
elseif not ( nn == nmiddle ) then
|
||||
minetest.log('error', "WARNING: middle of hiking pole at "..minetest.pos_to_string(pos).." found on top of '"..nn.."'? This should not happen!")
|
||||
rm_tall_hiking_pole({x=p.x, y=p.y+i, z=p.z})
|
||||
return
|
||||
end
|
||||
end
|
||||
end,
|
||||
end,
|
||||
}), moreprops))
|
||||
|
||||
minetest.register_node("hiking:"..id.."_top", merge(merge(hiking_pole_bottom, {
|
||||
minetest.register_node(ntop, merge(merge(hiking_pole_top, {
|
||||
-- TODO: one should not build on top of this
|
||||
-- TODO: should be always on top of pole_bottom
|
||||
description = name.." (top)",
|
||||
tiles = {"hiking_pole_sign_cap.png", "hiking_pole_sign_cap.png", top_face, top_face, top_face, top_face, },
|
||||
|
||||
on_dig = function(pos, _, _)
|
||||
on_dig = function(pos, _, digger)
|
||||
local i
|
||||
local p
|
||||
local n
|
||||
local nn
|
||||
for i = 1, h-1 do
|
||||
p = {x=pos.x, y=pos.y-i, z=pos.z}
|
||||
local n = minetest.env:get_node(p).name
|
||||
if ( n == "hiking:"..id.."_bottom" ) then
|
||||
minetest.env:remove_node(p)
|
||||
n = minetest.env:get_node(p)
|
||||
nn = n.name
|
||||
if ( nn == nbottom ) then
|
||||
minetest.node_dig(p, n, digger)
|
||||
return
|
||||
elseif not ( n == "hiking:"..id.."_middle" ) then
|
||||
-- TODO: ERROR!
|
||||
elseif not ( nn == nmiddle ) then
|
||||
minetest.log('error', "WARNING: top of hiking pole at "..minetest.pos_to_string(pos).." found on top of '"..nn.."'? This should not happen!")
|
||||
rm_tall_hiking_pole({x=p.x, y=p.y+i, z=p.z})
|
||||
return
|
||||
end
|
||||
end
|
||||
end,
|
||||
end,
|
||||
}), moreprops))
|
||||
end
|
||||
|
||||
|
@ -338,7 +367,7 @@ local function mk_hiking_pole_coloured(colour)
|
|||
})
|
||||
minetest.register_craft({
|
||||
output = "hiking:"..colour.."_pole_bottom",
|
||||
type = "shapeless",
|
||||
type = "shapeless",
|
||||
recipe = { "hiking:pole_bottom", "hiking:"..colour.."_sign" }
|
||||
})
|
||||
end
|
||||
|
@ -347,17 +376,17 @@ local function mk_hiking_pole_illuminated_coloured(colour)
|
|||
mk_hiking_pole("illuminated_"..colour.."_pole", "Illuminated pole sign "..colour, "hiking_pole_sign_top_"..colour..".png", illuminated_props, "hiking_illuminated_pole_sign_"..colour..".png")
|
||||
minetest.register_craft({
|
||||
output = "hiking:illuminated_"..colour.."_pole_bottom",
|
||||
type = "shapeless",
|
||||
type = "shapeless",
|
||||
recipe = { "default:torch", "hiking:"..colour.."_pole_bottom" }
|
||||
})
|
||||
minetest.register_craft({
|
||||
output = "hiking:illuminated_"..colour.."_pole_bottom",
|
||||
type = "shapeless",
|
||||
type = "shapeless",
|
||||
recipe = { "hiking:pole_bottom", "hiking:illuminated_"..colour.."_sign" }
|
||||
})
|
||||
minetest.register_craft({
|
||||
output = "hiking:illuminated_"..colour.."_pole_bottom",
|
||||
type = "shapeless",
|
||||
type = "shapeless",
|
||||
recipe = { "hiking:illuminated_pole_bottom", "hiking:"..colour.."_sign" }
|
||||
})
|
||||
end
|
||||
|
|
|
@ -1,22 +0,0 @@
|
|||
# Auto detect text files and perform LF normalization
|
||||
* text=auto
|
||||
|
||||
# Custom for Visual Studio
|
||||
*.cs diff=csharp
|
||||
*.sln merge=union
|
||||
*.csproj merge=union
|
||||
*.vbproj merge=union
|
||||
*.fsproj merge=union
|
||||
*.dbproj merge=union
|
||||
|
||||
# Standard to msysgit
|
||||
*.doc diff=astextplain
|
||||
*.DOC diff=astextplain
|
||||
*.docx diff=astextplain
|
||||
*.DOCX diff=astextplain
|
||||
*.dot diff=astextplain
|
||||
*.DOT diff=astextplain
|
||||
*.pdf diff=astextplain
|
||||
*.PDF diff=astextplain
|
||||
*.rtf diff=astextplain
|
||||
*.RTF diff=astextplain
|
|
@ -1,215 +0,0 @@
|
|||
#################
|
||||
## Eclipse
|
||||
#################
|
||||
|
||||
*.pydevproject
|
||||
.project
|
||||
.metadata
|
||||
bin/
|
||||
tmp/
|
||||
*.tmp
|
||||
*.bak
|
||||
*.swp
|
||||
*~.nib
|
||||
local.properties
|
||||
.classpath
|
||||
.settings/
|
||||
.loadpath
|
||||
|
||||
# External tool builders
|
||||
.externalToolBuilders/
|
||||
|
||||
# Locally stored "Eclipse launch configurations"
|
||||
*.launch
|
||||
|
||||
# CDT-specific
|
||||
.cproject
|
||||
|
||||
# PDT-specific
|
||||
.buildpath
|
||||
|
||||
|
||||
#################
|
||||
## Visual Studio
|
||||
#################
|
||||
|
||||
## Ignore Visual Studio temporary files, build results, and
|
||||
## files generated by popular Visual Studio add-ons.
|
||||
|
||||
# User-specific files
|
||||
*.suo
|
||||
*.user
|
||||
*.sln.docstates
|
||||
|
||||
# Build results
|
||||
|
||||
[Dd]ebug/
|
||||
[Rr]elease/
|
||||
x64/
|
||||
build/
|
||||
[Bb]in/
|
||||
[Oo]bj/
|
||||
|
||||
# MSTest test Results
|
||||
[Tt]est[Rr]esult*/
|
||||
[Bb]uild[Ll]og.*
|
||||
|
||||
*_i.c
|
||||
*_p.c
|
||||
*.ilk
|
||||
*.meta
|
||||
*.obj
|
||||
*.pch
|
||||
*.pdb
|
||||
*.pgc
|
||||
*.pgd
|
||||
*.rsp
|
||||
*.sbr
|
||||
*.tlb
|
||||
*.tli
|
||||
*.tlh
|
||||
*.tmp
|
||||
*.tmp_proj
|
||||
*.log
|
||||
*.vspscc
|
||||
*.vssscc
|
||||
.builds
|
||||
*.pidb
|
||||
*.log
|
||||
*.scc
|
||||
|
||||
# Visual C++ cache files
|
||||
ipch/
|
||||
*.aps
|
||||
*.ncb
|
||||
*.opensdf
|
||||
*.sdf
|
||||
*.cachefile
|
||||
|
||||
# Visual Studio profiler
|
||||
*.psess
|
||||
*.vsp
|
||||
*.vspx
|
||||
|
||||
# Guidance Automation Toolkit
|
||||
*.gpState
|
||||
|
||||
# ReSharper is a .NET coding add-in
|
||||
_ReSharper*/
|
||||
*.[Rr]e[Ss]harper
|
||||
|
||||
# TeamCity is a build add-in
|
||||
_TeamCity*
|
||||
|
||||
# DotCover is a Code Coverage Tool
|
||||
*.dotCover
|
||||
|
||||
# NCrunch
|
||||
*.ncrunch*
|
||||
.*crunch*.local.xml
|
||||
|
||||
# Installshield output folder
|
||||
[Ee]xpress/
|
||||
|
||||
# DocProject is a documentation generator add-in
|
||||
DocProject/buildhelp/
|
||||
DocProject/Help/*.HxT
|
||||
DocProject/Help/*.HxC
|
||||
DocProject/Help/*.hhc
|
||||
DocProject/Help/*.hhk
|
||||
DocProject/Help/*.hhp
|
||||
DocProject/Help/Html2
|
||||
DocProject/Help/html
|
||||
|
||||
# Click-Once directory
|
||||
publish/
|
||||
|
||||
# Publish Web Output
|
||||
*.Publish.xml
|
||||
*.pubxml
|
||||
|
||||
# NuGet Packages Directory
|
||||
## TODO: If you have NuGet Package Restore enabled, uncomment the next line
|
||||
#packages/
|
||||
|
||||
# Windows Azure Build Output
|
||||
csx
|
||||
*.build.csdef
|
||||
|
||||
# Windows Store app package directory
|
||||
AppPackages/
|
||||
|
||||
# Others
|
||||
sql/
|
||||
*.Cache
|
||||
ClientBin/
|
||||
[Ss]tyle[Cc]op.*
|
||||
~$*
|
||||
*~
|
||||
*.dbmdl
|
||||
*.[Pp]ublish.xml
|
||||
*.pfx
|
||||
*.publishsettings
|
||||
|
||||
# RIA/Silverlight projects
|
||||
Generated_Code/
|
||||
|
||||
# Backup & report files from converting an old project file to a newer
|
||||
# Visual Studio version. Backup files are not needed, because we have git ;-)
|
||||
_UpgradeReport_Files/
|
||||
Backup*/
|
||||
UpgradeLog*.XML
|
||||
UpgradeLog*.htm
|
||||
|
||||
# SQL Server files
|
||||
App_Data/*.mdf
|
||||
App_Data/*.ldf
|
||||
|
||||
#############
|
||||
## Windows detritus
|
||||
#############
|
||||
|
||||
# Windows image file caches
|
||||
Thumbs.db
|
||||
ehthumbs.db
|
||||
|
||||
# Folder config file
|
||||
Desktop.ini
|
||||
|
||||
# Recycle Bin used on file shares
|
||||
$RECYCLE.BIN/
|
||||
|
||||
# Mac crap
|
||||
.DS_Store
|
||||
|
||||
|
||||
#############
|
||||
## Python
|
||||
#############
|
||||
|
||||
*.py[co]
|
||||
|
||||
# Packages
|
||||
*.egg
|
||||
*.egg-info
|
||||
dist/
|
||||
build/
|
||||
eggs/
|
||||
parts/
|
||||
var/
|
||||
sdist/
|
||||
develop-eggs/
|
||||
.installed.cfg
|
||||
|
||||
# Installer logs
|
||||
pip-log.txt
|
||||
|
||||
# Unit test / coverage reports
|
||||
.coverage
|
||||
.tox
|
||||
|
||||
#Translations
|
||||
*.mo
|
||||
|
||||
#Mr Developer
|
||||
.mr.developer.cfg
|
|
@ -1,13 +1,18 @@
|
|||
function hud.register(name, def)
|
||||
hud.register(name, def)
|
||||
-- name: statbar name (health, air, hunger, armor already used by default)
|
||||
-- def: <HUD item definition> (see below)
|
||||
|
||||
hud.change_item(player, name, def)
|
||||
-- player: player object
|
||||
-- name: statbar name (health, air, hunger, armor already used by default)
|
||||
-- name: statbar name
|
||||
-- def: table containing new values
|
||||
-- currently supported: number, text and offset
|
||||
|
||||
hud.swap_statbar(player, name1, name2) -- swaps position and offset of statbar with name1 with statbar with name2
|
||||
-- player: player object
|
||||
-- name1: statbar name
|
||||
-- name2: statbar name
|
||||
|
||||
hud.remove_item(player, name)
|
||||
|
||||
HUD item definition
|
||||
|
|
|
@ -1,6 +1,6 @@
|
|||
Minetest mod "Better HUD"
|
||||
=========================
|
||||
Version: 2.1.2
|
||||
Version: 2.1.3
|
||||
|
||||
(c) Copyright BlockMen (2013-2015)
|
||||
|
||||
|
|
|
@ -66,6 +66,55 @@ function hud.register(name, def)
|
|||
return true
|
||||
end
|
||||
|
||||
-- swaps stabar positions
|
||||
function hud.swap_statbar(player, item1, item2)
|
||||
if not player or not item1 or not item2 then
|
||||
throw_error("Not enough parameters given to swap statbars")
|
||||
return false
|
||||
end
|
||||
|
||||
local def1 = items[item1] or nil
|
||||
local def2 = items[item2] or nil
|
||||
|
||||
if not def1 or not def2 then
|
||||
throw_error("Can't swap statbars. Given statbars are not correct")
|
||||
return false
|
||||
end
|
||||
|
||||
local pos_swap = false
|
||||
local p_name = player:get_player_name()
|
||||
local elem1 = hud_id[p_name.."_"..item1]
|
||||
local elem2 = hud_id[p_name.."_"..item2]
|
||||
|
||||
player:hud_change(elem2.id, "offset", def1.offset)
|
||||
player:hud_change(elem1.id, "offset", def2.offset)
|
||||
|
||||
if def1.position.x ~= def2.position.x or def1.position.y ~= def2.position.y then
|
||||
player:hud_change(elem2.id, "position", def1.position)
|
||||
player:hud_change(elem1.id, "position", def2.position)
|
||||
pos_swap = true
|
||||
end
|
||||
|
||||
-- do the items have backgrounds? if so, swap them aswell
|
||||
local bg1 = hud_id[p_name.."_"..item1.."_bg"] or nil
|
||||
local bg2 = hud_id[p_name.."_"..item2.."_bg"] or nil
|
||||
if bg1 ~= nil and bg1.id then
|
||||
player:hud_change(bg1.id, "offset", def2.offset)
|
||||
if pos_swap == true then
|
||||
player:hud_change(bg1.id, "position", def2.position)
|
||||
end
|
||||
end
|
||||
if bg2 ~= nil and bg2.id then
|
||||
player:hud_change(bg2.id, "offset", def1.offset)
|
||||
if pos_swap == true then
|
||||
player:hud_change(bg2.id, "position", def1.position)
|
||||
end
|
||||
end
|
||||
|
||||
return true
|
||||
|
||||
end
|
||||
|
||||
function hud.change_item(player, name, def)
|
||||
if not player or not player:is_player() or not name or not def then
|
||||
throw_error("Not enough parameters given to change HUD item")
|
||||
|
@ -106,6 +155,7 @@ function hud.change_item(player, name, def)
|
|||
if bg and bg.max and bg.max < 1 and def.max and def.max > bg.max then
|
||||
player:hud_change(bg.id, "number", def.max)
|
||||
bg.max = def.max
|
||||
bg.number = def.max
|
||||
end
|
||||
end
|
||||
end
|
||||
|
@ -119,27 +169,9 @@ function hud.change_item(player, name, def)
|
|||
|
||||
if def.offset and elem.offset then
|
||||
if def.item_name and def.offset == "item" then
|
||||
local i_name2 = player:get_player_name().."_"..def.item_name
|
||||
local elem2 = hud_id[i_name2]
|
||||
if elem2 then
|
||||
local p2 = elem2.offset
|
||||
local p1 = elem.offset
|
||||
player:hud_change(elem2.id, "offset", p1)
|
||||
player:hud_change(elem.id, "offset", p2)
|
||||
elem2.offset = p1
|
||||
elem.offset = p2
|
||||
if elem.background then
|
||||
local elem3 = hud_id[i_name.."_bg"]
|
||||
if elem3 and elem3.offset then
|
||||
player:hud_change(elem3.id, "offset", p2)
|
||||
elem3.offset = p2
|
||||
local elem4 = hud_id[i_name2.."_bg"]
|
||||
if elem4 and elem4.offset then
|
||||
player:hud_change(elem4.id, "offset", p1)
|
||||
elem4.offset = p1
|
||||
end
|
||||
end
|
||||
end
|
||||
-- for legacy reasons
|
||||
if def.item_name then
|
||||
hud.swap_statbar(player, name, def.item_name)
|
||||
end
|
||||
else
|
||||
player:hud_change(elem.id, "offset", def.offset)
|
||||
|
@ -190,7 +222,7 @@ minetest.register_on_joinplayer(function(player)
|
|||
hud_flags.breathbar = false
|
||||
player:hud_set_flags(hud_flags)
|
||||
|
||||
-- now add the backgrounds (e.g. for statbars)
|
||||
-- now add the backgrounds for statbars
|
||||
for _,item in pairs(sb_bg) do
|
||||
add_hud_item(player, _.."_bg", item)
|
||||
end
|
||||
|
|
|
@ -44,70 +44,70 @@ end
|
|||
|
||||
if damage_enabled then
|
||||
hud.register("health", {
|
||||
hud_elem_type = "statbar",
|
||||
position = HUD_HEALTH_POS,
|
||||
size = HUD_SB_SIZE,
|
||||
text = "hud_heart_fg.png",
|
||||
number = 20,
|
||||
alignment = {x = -1, y = -1},
|
||||
offset = HUD_HEALTH_OFFSET,
|
||||
background = "hud_heart_bg.png",
|
||||
events = {
|
||||
{
|
||||
type = "damage",
|
||||
func = function(player)
|
||||
hud.change_item(player, "health", {number = player:get_hp()})
|
||||
end
|
||||
}
|
||||
},
|
||||
hud_elem_type = "statbar",
|
||||
position = HUD_HEALTH_POS,
|
||||
size = HUD_SB_SIZE,
|
||||
text = "hud_heart_fg.png",
|
||||
number = 20,
|
||||
alignment = {x = -1, y = -1},
|
||||
offset = HUD_HEALTH_OFFSET,
|
||||
background = "hud_heart_bg.png",
|
||||
events = {
|
||||
{
|
||||
type = "damage",
|
||||
func = function(player)
|
||||
hud.change_item(player, "health", {number = player:get_hp()})
|
||||
end
|
||||
}
|
||||
},
|
||||
})
|
||||
|
||||
hud.register("air", {
|
||||
hud_elem_type = "statbar",
|
||||
position = HUD_AIR_POS,
|
||||
size = HUD_SB_SIZE,
|
||||
text = "hud_air_fg.png",
|
||||
number = 0,
|
||||
alignment = {x = -1, y = -1},
|
||||
offset = HUD_AIR_OFFSET,
|
||||
background = nil,
|
||||
events = {
|
||||
{
|
||||
type = "breath",
|
||||
func = function(player)
|
||||
local air = player:get_breath()
|
||||
if air > 10 then
|
||||
air = 0
|
||||
hud_elem_type = "statbar",
|
||||
position = HUD_AIR_POS,
|
||||
size = HUD_SB_SIZE,
|
||||
text = "hud_air_fg.png",
|
||||
number = 0,
|
||||
alignment = {x = -1, y = -1},
|
||||
offset = HUD_AIR_OFFSET,
|
||||
background = nil,
|
||||
events = {
|
||||
{
|
||||
type = "breath",
|
||||
func = function(player)
|
||||
local air = player:get_breath()
|
||||
if air > 10 then
|
||||
air = 0
|
||||
end
|
||||
hud.change_item(player, "air", {number = air * 2})
|
||||
end
|
||||
hud.change_item(player, "air", {number = air * 2})
|
||||
end
|
||||
}
|
||||
},
|
||||
}
|
||||
},
|
||||
})
|
||||
|
||||
hud.register("armor", {
|
||||
hud_elem_type = "statbar",
|
||||
position = HUD_ARMOR_POS,
|
||||
size = HUD_SB_SIZE,
|
||||
text = "hud_armor_fg.png",
|
||||
number = 0,
|
||||
alignment = {x = -1, y = -1},
|
||||
offset = HUD_ARMOR_OFFSET,
|
||||
background = "hud_armor_bg.png",
|
||||
autohide_bg = true,
|
||||
max = 20,
|
||||
hud_elem_type = "statbar",
|
||||
position = HUD_ARMOR_POS,
|
||||
size = HUD_SB_SIZE,
|
||||
text = "hud_armor_fg.png",
|
||||
number = 0,
|
||||
alignment = {x = -1, y = -1},
|
||||
offset = HUD_ARMOR_OFFSET,
|
||||
background = "hud_armor_bg.png",
|
||||
autohide_bg = true,
|
||||
max = 20,
|
||||
})
|
||||
|
||||
hud.register("hunger", {
|
||||
hud_elem_type = "statbar",
|
||||
position = HUD_HUNGER_POS,
|
||||
size = HUD_SB_SIZE,
|
||||
text = "hud_hunger_fg.png",
|
||||
number = 0,
|
||||
alignment = {x = -1, y = -1},
|
||||
offset = HUD_HUNGER_OFFSET,
|
||||
background = "hud_hunger_bg.png",
|
||||
max = 0,
|
||||
hud_elem_type = "statbar",
|
||||
position = HUD_HUNGER_POS,
|
||||
size = HUD_SB_SIZE,
|
||||
text = "hud_hunger_fg.png",
|
||||
number = 0,
|
||||
alignment = {x = -1, y = -1},
|
||||
offset = HUD_HUNGER_OFFSET,
|
||||
background = "hud_hunger_bg.png",
|
||||
max = 0,
|
||||
})
|
||||
else
|
||||
hud.show_armor = false
|
||||
|
|
|
@ -1,3 +1,8 @@
|
|||
2.1.3
|
||||
-----
|
||||
- Added hud.swap_statbar() and fix wrong behavior of previous workaround
|
||||
- Fixed missing background of some statbars in multiplayer
|
||||
|
||||
2.1.2
|
||||
-----
|
||||
- Fixed crash caused by animated nodes (reported by Krock)
|
||||
|
|
|
@ -1,6 +1,6 @@
|
|||
Minetest mod "Hunger"
|
||||
=====================
|
||||
Version: 1.0
|
||||
Version: 1.1
|
||||
|
||||
(c) Copyright BlockMen (2015)
|
||||
|
||||
|
@ -19,6 +19,12 @@ Information:
|
|||
This mod depends on the "Better HUD" mod (https://github.com/BlockMen/hud) to provide information about your current saturation.
|
||||
|
||||
|
||||
For Modders:
|
||||
~~~~~~~~~~~~
|
||||
This mod alters the behavior of minetest.item_eat().
|
||||
All callbacks that are registered via minetest.register_on_item_eat() are called AFTER this mod actions, so the itemstack
|
||||
will have changed already when callbacks are called. You can get the original itemstack as 6th parameter of your function then.
|
||||
|
||||
License:
|
||||
~~~~~~~~
|
||||
(c) Copyright BlockMen (2015)
|
||||
|
|
|
@ -4,3 +4,12 @@
|
|||
- Added API to register food
|
||||
- Added eating sounds
|
||||
- Hungerbar image changes when poisend
|
||||
|
||||
1.1
|
||||
---
|
||||
- Fixed healing after death
|
||||
- Fixed healing while drowning
|
||||
- Fixed crashed caused by Pipeworks mod
|
||||
- Added wrapper for minetest.item_eat(). see Readme.txt for more informations
|
||||
- Updated HUD-API usage
|
||||
- Added beans of Farming Redo
|
||||
|
|
|
@ -253,6 +253,7 @@ if minetest.get_modpath("farming") and farming.mod == "redo" then
|
|||
end
|
||||
register_food("farming:rhubarb", 1)
|
||||
register_food("farming:rhubarb_pie", 6)
|
||||
register_food("farming:beans", 1)
|
||||
end
|
||||
|
||||
if minetest.get_modpath("kpgmobs") ~= nil then
|
||||
|
|
|
@ -65,6 +65,10 @@ function hunger.handle_node_actions(pos, oldnode, player, ext)
|
|||
return
|
||||
end
|
||||
local name = player:get_player_name()
|
||||
if not name or not hunger[name] then
|
||||
return
|
||||
end
|
||||
|
||||
local exhaus = hunger[name].exhaus
|
||||
if not exhaus then
|
||||
hunger[name].exhaus = 0
|
||||
|
@ -96,12 +100,13 @@ function hunger.handle_node_actions(pos, oldnode, player, ext)
|
|||
hunger[name].exhaus = exhaus
|
||||
end
|
||||
|
||||
|
||||
-- Time based hunger functions
|
||||
if minetest.setting_getbool("enable_damage") then
|
||||
local hunger_timer = 0
|
||||
local health_timer = 0
|
||||
local action_timer = 0
|
||||
minetest.register_globalstep(function(dtime)
|
||||
local hunger_timer = 0
|
||||
local health_timer = 0
|
||||
local action_timer = 0
|
||||
|
||||
local function hunger_globaltimer(dtime)
|
||||
hunger_timer = hunger_timer + dtime
|
||||
health_timer = health_timer + dtime
|
||||
action_timer = action_timer + dtime
|
||||
|
@ -141,8 +146,8 @@ if minetest.setting_getbool("enable_damage") then
|
|||
local air = player:get_breath() or 0
|
||||
local hp = player:get_hp()
|
||||
|
||||
-- heal player by 1 hp if not dead and saturation is > 15 (of 30)
|
||||
if tonumber(tab.lvl) > HUNGER_HEAL_LVL and air > 0 then
|
||||
-- heal player by 1 hp if not dead and saturation is > 15 (of 30) player is not drowning
|
||||
if tonumber(tab.lvl) > HUNGER_HEAL_LVL and hp > 0 and air > 0 then
|
||||
player:set_hp(hp + HUNGER_HEAL)
|
||||
end
|
||||
|
||||
|
@ -155,7 +160,10 @@ if minetest.setting_getbool("enable_damage") then
|
|||
|
||||
health_timer = 0
|
||||
end
|
||||
end)
|
||||
end
|
||||
|
||||
if minetest.setting_getbool("enable_damage") then
|
||||
minetest.register_globalstep(hunger_globaltimer)
|
||||
end
|
||||
|
||||
|
||||
|
@ -166,9 +174,9 @@ function hunger.register_food(name, hunger_change, replace_with_item, poisen, he
|
|||
food[name] = {}
|
||||
food[name].saturation = hunger_change -- hunger points added
|
||||
food[name].replace = replace_with_item -- what item is given back after eating
|
||||
food[name].poisen = poisen -- time its poisening
|
||||
food[name].healing = heal -- amount of HP
|
||||
food[name].sound = sound -- special sound that is played when eating
|
||||
food[name].poisen = poisen -- time its poisening
|
||||
food[name].healing = heal -- amount of HP
|
||||
food[name].sound = sound -- special sound that is played when eating
|
||||
end
|
||||
|
||||
-- Poison player
|
||||
|
@ -185,6 +193,20 @@ local function poisenp(tick, time, time_left, player)
|
|||
end
|
||||
end
|
||||
|
||||
-- wrapper for minetest.item_eat (this way we make sure other mods can't break this one)
|
||||
local org_eat = core.do_item_eat
|
||||
core.do_item_eat = function(hp_change, replace_with_item, itemstack, user, pointed_thing)
|
||||
local old_itemstack = itemstack
|
||||
itemstack = hunger.eat(hp_change, replace_with_item, itemstack, user, pointed_thing)
|
||||
for _, callback in pairs(core.registered_on_item_eats) do
|
||||
local result = callback(hp_change, replace_with_item, itemstack, user, pointed_thing, old_itemstack)
|
||||
if result then
|
||||
return result
|
||||
end
|
||||
end
|
||||
return itemstack
|
||||
end
|
||||
|
||||
function hunger.eat(hp_change, replace_with_item, itemstack, user, pointed_thing)
|
||||
local item = itemstack:get_name()
|
||||
local def = food[item]
|
||||
|
@ -228,7 +250,20 @@ function hunger.item_eat(hunger_change, replace_with_item, poisen, heal, sound)
|
|||
end
|
||||
minetest.sound_play(sound, {to_player = name, gain = 0.7})
|
||||
|
||||
itemstack:add_item(replace_with_item)
|
||||
if replace_with_item then
|
||||
if itemstack:is_empty() then
|
||||
itemstack:add_item(replace_with_item)
|
||||
else
|
||||
local inv = user:get_inventory()
|
||||
if inv:room_for_item("main", {name=replace_with_item}) then
|
||||
inv:add_item("main", replace_with_item)
|
||||
else
|
||||
local pos = user:getpos()
|
||||
pos.y = math.floor(pos.y + 0.5)
|
||||
core.add_item(pos, replace_with_item)
|
||||
end
|
||||
end
|
||||
end
|
||||
end
|
||||
|
||||
return itemstack
|
||||
|
|
|
@ -1,7 +1,7 @@
|
|||
hunger = {}
|
||||
hunger.food = {}
|
||||
|
||||
HUNGER_TICK = 800 -- time in seconds after that 1 hunger point is taken
|
||||
HUNGER_TICK = 800 -- time in seconds after that 1 hunger point is taken
|
||||
HUNGER_HEALTH_TICK = 4 -- time in seconds after player gets healed/damaged
|
||||
HUNGER_MOVE_TICK = 0.5 -- time in seconds after the movement is checked
|
||||
|
||||
|
@ -10,12 +10,12 @@ HUNGER_EXHAUST_PLACE = 1 -- exhaustion increased this value after placed
|
|||
HUNGER_EXHAUST_MOVE = 1.5 -- exhaustion increased this value if player movement detected
|
||||
HUNGER_EXHAUST_LVL = 160 -- at what exhaustion player saturation gets lowered
|
||||
|
||||
HUNGER_HEAL = 1 -- number of HP player gets healed after HUNGER_HEALTH_TICK
|
||||
HUNGER_HEAL = 1 -- number of HP player gets healed after HUNGER_HEALTH_TICK
|
||||
HUNGER_HEAL_LVL = 15 -- lower level of saturation needed to get healed
|
||||
HUNGER_STARVE = 1 -- number of HP player gets damaged by hunger after HUNGER_HEALTH_TICK
|
||||
HUNGER_STARVE = 1 -- number of HP player gets damaged by hunger after HUNGER_HEALTH_TICK
|
||||
HUNGER_STARVE_LVL = 3 -- level of staturation that causes starving
|
||||
|
||||
HUNGER_MAX = 30 -- maximum level of saturation
|
||||
HUNGER_MAX = 30 -- maximum level of saturation
|
||||
|
||||
|
||||
local modpath = minetest.get_modpath("hunger")
|
||||
|
@ -39,7 +39,7 @@ if minetest.setting_getbool("enable_damage") then
|
|||
lvl = 20
|
||||
end
|
||||
minetest.after(0.8, function()
|
||||
hud.change_item(player, "hunger", {offset = "item", item_name = "air"})
|
||||
hud.swap_statbar(player, "hunger", "air")
|
||||
hud.change_item(player, "hunger", {number = lvl, max = 20})
|
||||
end)
|
||||
end)
|
||||
|
@ -47,7 +47,6 @@ if minetest.setting_getbool("enable_damage") then
|
|||
-- for exhaustion
|
||||
minetest.register_on_placenode(hunger.handle_node_actions)
|
||||
minetest.register_on_dignode(hunger.handle_node_actions)
|
||||
minetest.register_on_item_eat(hunger.eat)
|
||||
minetest.register_on_respawnplayer(function(player)
|
||||
hunger.update_hunger(player, 20)
|
||||
end)
|
||||
|
|
|
@ -0,0 +1,42 @@
|
|||
# mobs_goblins
|
||||
|
||||
-= MOBS_GOBLINS-MOD for MINETEST =-
|
||||
by FreeLikeGNU
|
||||
https://forum.minetest.net/viewtopic.php?f=9&t=13004
|
||||
https://github.com/FreeLikeGNU/mobs_goblins
|
||||
|
||||
based on MOBS-MOD by PilzAdam, KrupnovPavel, Zeg9, TenPlus1
|
||||
https://forum.minetest.net/viewtopic.php?f=9&t=9917
|
||||
|
||||
This mod adds several Goblins to Minetest that should spawn near ore deposits or lairs underground.
|
||||
|
||||
v0.05 Fix errors in .04, remove texture names from goblin model, and add cobble goblins to build goblin lairs.
|
||||
|
||||
v0.04 Thieving goblins!
|
||||
|
||||
v0.03 This is a test version that adds a goblin king! Thanks to Napiophelios! Some more texture refinement and fixed naming of textures.
|
||||
|
||||
v0.02 This is a test version and some the goblins will not attack unless attacked. Variety varies with ore...
|
||||
|
||||
v0.01 This is a test version and all the goblins act like an NPC and will not attack unless attacked.
|
||||
|
||||
|
||||
License of Media Files:
|
||||
---------------------------------------
|
||||
goblins_goblin.b3d and goblins_goblin.blend
|
||||
by FreeLikeGNU Attribution-ShareAlike 3.0 Unported (CC BY-SA 3.0) by FreeLikeGNU
|
||||
http://creativecommons.org/licenses/by-sa/3.0/
|
||||
|
||||
above meshes based on character from minetest_game
|
||||
by MirceaKitsune (WTFPL)
|
||||
https://github.com/minetest/minetest_game/blob/master/mods/default/README.txt#L71
|
||||
|
||||
goblins_goblins*.png files and goblins_goblin.xcf files
|
||||
by FreeLikeGNU Attribution-ShareAlike 3.0 Unported (CC BY-SA 3.0)
|
||||
http://creativecommons.org/licenses/by-sa/3.0/
|
||||
|
||||
Thanks to Napiophelios for the goblin king skin
|
||||
https://forum.minetest.net/viewtopic.php?f=9&t=13004#p186921
|
||||
goblins_goblin_king.png
|
||||
License: Creative Commons CC-BY-SA-3.0 SummerFeilds TP
|
||||
|
|
@ -0,0 +1,15 @@
|
|||
{
|
||||
"name": "mobs_goblins",
|
||||
"description": "goblins for minetest",
|
||||
"keywords": [
|
||||
"mobs_goblins"
|
||||
],
|
||||
"homepage": "https://github.com/FreeLikeGNU/mobs_goblins",
|
||||
"screenshots": [
|
||||
"https://cloud.githubusercontent.com/assets/51875/9214313/50cbf752-40db-11e5-8661-ce8be773bc92.png"
|
||||
],
|
||||
"authors": [
|
||||
"FreeLikeGNU"
|
||||
],
|
||||
"license": "CC-BY-SA-3.0"
|
||||
}
|
|
@ -0,0 +1,658 @@
|
|||
|
||||
-- Npc by TenPlus1 converted for FLG Goblins :D
|
||||
|
||||
mobs_goblins.goblin_drops = {
|
||||
"default:pick_steel", "default:sword_steel",
|
||||
"default:shovel_steel", "farming:bread", "bucket:bucket_water"
|
||||
}
|
||||
mobs_goblins:register_mob("mobs_goblins:goblin_cobble", {
|
||||
description = "Cobble Goblin",
|
||||
type = "animal",
|
||||
passive = false,
|
||||
damage = 1,
|
||||
attack_type = "dogfight",
|
||||
attacks_monsters = true,
|
||||
hp_min = 5,
|
||||
hp_max = 10,
|
||||
armor = 100,
|
||||
collisionbox = {-0.35,-1.0,-0.35, 0.35,0.0,0.35},
|
||||
visual = "mesh",
|
||||
mesh = "goblins_goblin.b3d",
|
||||
drawtype = "front",
|
||||
textures = {
|
||||
{"goblins_goblin_cobble1.png"},
|
||||
{"goblins_goblin_cobble2.png"},
|
||||
|
||||
},
|
||||
makes_footstep_sound = true,
|
||||
sounds = {
|
||||
random = "mobs_pig",
|
||||
attack = "mobs_pig_angry",
|
||||
},
|
||||
walk_velocity = 2,
|
||||
run_velocity = 3,
|
||||
jump = true,
|
||||
drops = {
|
||||
{name = "default:mossycobble",
|
||||
chance = 1, min = 1, max = 3},
|
||||
{name = "default:apple",
|
||||
chance = 2, min = 1, max = 2},
|
||||
{name = "default:torch",
|
||||
chance = 3, min = 1, max = 10},
|
||||
},
|
||||
water_damage = 0,
|
||||
lava_damage = 2,
|
||||
light_damage = 0,
|
||||
follow = {"default:diamond"},
|
||||
replace_rate = 30,
|
||||
replace_what = {"default:stone","default:desert_stone",},
|
||||
replace_with = "default:mossycobble",
|
||||
replace_offset = 1,
|
||||
view_range = 15,
|
||||
owner = "",
|
||||
order = "follow",
|
||||
animation = {
|
||||
speed_normal = 30,
|
||||
speed_run = 30,
|
||||
stand_start = 0,
|
||||
stand_end = 79,
|
||||
walk_start = 168,
|
||||
walk_end = 187,
|
||||
run_start = 168,
|
||||
run_end = 187,
|
||||
punch_start = 200,
|
||||
punch_end = 219,
|
||||
},
|
||||
on_rightclick = function(self, clicker)
|
||||
local item = clicker:get_wielded_item()
|
||||
local name = clicker:get_player_name()
|
||||
|
||||
-- feed to heal goblin
|
||||
if item:get_name() == "default:apple"
|
||||
or item:get_name() == "farming:bread" then
|
||||
|
||||
local hp = self.object:get_hp()
|
||||
-- return if full health
|
||||
if hp >= self.hp_max then
|
||||
minetest.chat_send_player(name, "goblin at full health.")
|
||||
return
|
||||
end
|
||||
hp = hp + 4
|
||||
if hp > self.hp_max then hp = self.hp_max end
|
||||
self.object:set_hp(hp)
|
||||
-- take item
|
||||
if not minetest.setting_getbool("creative_mode") then
|
||||
item:take_item()
|
||||
clicker:set_wielded_item(item)
|
||||
end
|
||||
|
||||
-- right clicking with gold lump drops random item from mobs_goblins.goblin_drops
|
||||
elseif item:get_name() == "default:gold_lump" then
|
||||
if not minetest.setting_getbool("creative_mode") then
|
||||
item:take_item()
|
||||
clicker:set_wielded_item(item)
|
||||
end
|
||||
local pos = self.object:getpos()
|
||||
pos.y = pos.y + 0.5
|
||||
minetest.add_item(pos, {name = mobs_goblins.goblin_drops[math.random(1, #mobs_goblins.goblin_drops)]})
|
||||
|
||||
else
|
||||
-- if owner switch between follow and stand
|
||||
if self.owner and self.owner == clicker:get_player_name() then
|
||||
if self.order == "follow" then
|
||||
self.order = "stand"
|
||||
else
|
||||
self.order = "follow"
|
||||
end
|
||||
-- else
|
||||
-- self.owner = clicker:get_player_name()
|
||||
end
|
||||
end
|
||||
|
||||
mobs_goblins:capture_mob(self, clicker, 0, 5, 80, false, nil)
|
||||
end,
|
||||
|
||||
})
|
||||
mobs_goblins:register_mob("mobs_goblins:goblin_coal", {
|
||||
description = "Coal Goblin",
|
||||
type = "animal",
|
||||
passive = false,
|
||||
damage = 1,
|
||||
attack_type = "dogfight",
|
||||
attacks_monsters = true,
|
||||
hp_min = 5,
|
||||
hp_max = 10,
|
||||
armor = 100,
|
||||
collisionbox = {-0.35,-1.0,-0.35, 0.35,0.0,0.35},
|
||||
visual = "mesh",
|
||||
mesh = "goblins_goblin.b3d",
|
||||
drawtype = "front",
|
||||
textures = {
|
||||
{"goblins_goblin_coal1.png"},
|
||||
{"goblins_goblin_coal2.png"},
|
||||
},
|
||||
makes_footstep_sound = true,
|
||||
sounds = {
|
||||
random = "mobs_pig",
|
||||
attack = "mobs_pig_angry",
|
||||
},
|
||||
walk_velocity = 2,
|
||||
run_velocity = 3,
|
||||
jump = true,
|
||||
drops = {
|
||||
{name = "default:coal_lump",
|
||||
chance = 1, min = 1, max = 3},
|
||||
{name = "default:apple",
|
||||
chance = 2, min = 1, max = 2},
|
||||
{name = "default:torch",
|
||||
chance = 3, min = 1, max = 10},
|
||||
},
|
||||
water_damage = 0,
|
||||
lava_damage = 2,
|
||||
light_damage = 0,
|
||||
follow = {"default:diamond"},
|
||||
replace_rate = 50,
|
||||
replace_what = {"default:torch",},
|
||||
replace_with = "air",
|
||||
replace_offset = 2,
|
||||
view_range = 15,
|
||||
owner = "",
|
||||
order = "follow",
|
||||
animation = {
|
||||
speed_normal = 30,
|
||||
speed_run = 30,
|
||||
stand_start = 0,
|
||||
stand_end = 79,
|
||||
walk_start = 168,
|
||||
walk_end = 187,
|
||||
run_start = 168,
|
||||
run_end = 187,
|
||||
punch_start = 200,
|
||||
punch_end = 219,
|
||||
},
|
||||
on_rightclick = function(self, clicker)
|
||||
local item = clicker:get_wielded_item()
|
||||
local name = clicker:get_player_name()
|
||||
|
||||
-- feed to heal goblin
|
||||
if item:get_name() == "default:apple"
|
||||
or item:get_name() == "farming:bread" then
|
||||
|
||||
local hp = self.object:get_hp()
|
||||
-- return if full health
|
||||
if hp >= self.hp_max then
|
||||
minetest.chat_send_player(name, "goblin at full health.")
|
||||
return
|
||||
end
|
||||
hp = hp + 4
|
||||
if hp > self.hp_max then hp = self.hp_max end
|
||||
self.object:set_hp(hp)
|
||||
-- take item
|
||||
if not minetest.setting_getbool("creative_mode") then
|
||||
item:take_item()
|
||||
clicker:set_wielded_item(item)
|
||||
end
|
||||
|
||||
-- right clicking with gold lump drops random item from mobs_goblins.goblin_drops
|
||||
elseif item:get_name() == "default:gold_lump" then
|
||||
if not minetest.setting_getbool("creative_mode") then
|
||||
item:take_item()
|
||||
clicker:set_wielded_item(item)
|
||||
end
|
||||
local pos = self.object:getpos()
|
||||
pos.y = pos.y + 0.5
|
||||
minetest.add_item(pos, {name = mobs_goblins.goblin_drops[math.random(1, #mobs_goblins.goblin_drops)]})
|
||||
|
||||
else
|
||||
-- if owner switch between follow and stand
|
||||
if self.owner and self.owner == clicker:get_player_name() then
|
||||
if self.order == "follow" then
|
||||
self.order = "stand"
|
||||
else
|
||||
self.order = "follow"
|
||||
end
|
||||
-- else
|
||||
-- self.owner = clicker:get_player_name()
|
||||
end
|
||||
end
|
||||
|
||||
mobs_goblins:capture_mob(self, clicker, 0, 5, 80, false, nil)
|
||||
end,
|
||||
|
||||
})
|
||||
mobs_goblins:register_mob("mobs_goblins:goblin_iron", {
|
||||
description = "Iron Goblin",
|
||||
type = "animal",
|
||||
passive = false,
|
||||
damage = 2,
|
||||
attack_type = "dogfight",
|
||||
attacks_monsters = true,
|
||||
hp_min = 10,
|
||||
hp_max = 20,
|
||||
armor = 100,
|
||||
collisionbox = {-0.35,-1.0,-0.35, 0.35,0.0,0.35},
|
||||
visual = "mesh",
|
||||
mesh = "goblins_goblin.b3d",
|
||||
drawtype = "front",
|
||||
textures = {
|
||||
{"goblins_goblin_iron1.png"},
|
||||
{"goblins_goblin_iron2.png"},
|
||||
},
|
||||
makes_footstep_sound = true,
|
||||
sounds = {
|
||||
random = "mobs_pig",
|
||||
attack = "mobs_pig_angry",
|
||||
},
|
||||
walk_velocity = 2,
|
||||
run_velocity = 3,
|
||||
jump = true,
|
||||
drops = {
|
||||
{name = "default:iron_lump",
|
||||
chance = 1, min = 1, max = 3},
|
||||
{name = "default:apple",
|
||||
chance = 2, min = 1, max = 2},
|
||||
{name = "default:pick_steel",
|
||||
chance = 5, min = 1, max = 1},
|
||||
},
|
||||
water_damage = 0,
|
||||
lava_damage = 2,
|
||||
light_damage = 0,
|
||||
follow = "default:diamond",
|
||||
replace_rate = 50,
|
||||
replace_what = {"default:torch",},
|
||||
replace_with = "air",
|
||||
replace_offset = 2,
|
||||
view_range = 15,
|
||||
owner = "",
|
||||
order = "follow",
|
||||
animation = {
|
||||
speed_normal = 30,
|
||||
speed_run = 30,
|
||||
stand_start = 0,
|
||||
stand_end = 79,
|
||||
walk_start = 168,
|
||||
walk_end = 187,
|
||||
run_start = 168,
|
||||
run_end = 187,
|
||||
punch_start = 200,
|
||||
punch_end = 219,
|
||||
},
|
||||
on_rightclick = function(self, clicker)
|
||||
local item = clicker:get_wielded_item()
|
||||
local name = clicker:get_player_name()
|
||||
|
||||
-- feed to heal goblin
|
||||
if item:get_name() == "default:apple"
|
||||
or item:get_name() == "farming:bread" then
|
||||
|
||||
local hp = self.object:get_hp()
|
||||
-- return if full health
|
||||
if hp >= self.hp_max then
|
||||
minetest.chat_send_player(name, "goblin at full health.")
|
||||
return
|
||||
end
|
||||
hp = hp + 4
|
||||
if hp > self.hp_max then hp = self.hp_max end
|
||||
self.object:set_hp(hp)
|
||||
-- take item
|
||||
if not minetest.setting_getbool("creative_mode") then
|
||||
item:take_item()
|
||||
clicker:set_wielded_item(item)
|
||||
end
|
||||
|
||||
-- right clicking with gold lump drops random item from mobs_goblins.goblin_drops
|
||||
elseif item:get_name() == "default:gold_lump" then
|
||||
if not minetest.setting_getbool("creative_mode") then
|
||||
item:take_item()
|
||||
clicker:set_wielded_item(item)
|
||||
end
|
||||
local pos = self.object:getpos()
|
||||
pos.y = pos.y + 0.5
|
||||
minetest.add_item(pos, {name = mobs_goblins.goblin_drops[math.random(1, #mobs_goblins.goblin_drops)]})
|
||||
|
||||
else
|
||||
-- if owner switch between follow and stand
|
||||
if self.owner and self.owner == clicker:get_player_name() then
|
||||
if self.order == "follow" then
|
||||
self.order = "stand"
|
||||
else
|
||||
self.order = "follow"
|
||||
end
|
||||
-- else
|
||||
-- self.owner = clicker:get_player_name()
|
||||
end
|
||||
end
|
||||
|
||||
mobs_goblins:capture_mob(self, clicker, 0, 5, 80, false, nil)
|
||||
end,
|
||||
|
||||
})
|
||||
mobs_goblins:register_mob("mobs_goblins:goblin_gold", {
|
||||
description = "Gold Goblin",
|
||||
type = "monster",
|
||||
passive = false,
|
||||
damage = 3,
|
||||
attack_type = "dogfight",
|
||||
attacks_monsters = true,
|
||||
hp_min = 10,
|
||||
hp_max = 30,
|
||||
armor = 100,
|
||||
collisionbox = {-0.35,-1.0,-0.35, 0.35,0.0,0.35},
|
||||
visual = "mesh",
|
||||
mesh = "goblins_goblin.b3d",
|
||||
drawtype = "front",
|
||||
textures = {
|
||||
{"goblins_goblin_gold1.png"},
|
||||
{"goblins_goblin_gold2.png"},
|
||||
},
|
||||
makes_footstep_sound = true,
|
||||
sounds = {
|
||||
random = "mobs_pig",
|
||||
attack = "mobs_pig_angry",
|
||||
},
|
||||
walk_velocity = 2,
|
||||
run_velocity = 3,
|
||||
jump = true,
|
||||
drops = {
|
||||
{name = "default:gold_lump",
|
||||
chance = 1, min = 1, max = 3},
|
||||
{name = "default:apple",
|
||||
chance = 2, min = 1, max = 2},
|
||||
{name = "default:gold_ingot",
|
||||
chance = 5, min = 1, max = 1},
|
||||
},
|
||||
water_damage = 0,
|
||||
lava_damage = 2,
|
||||
light_damage = 0,
|
||||
follow = "default:diamond",
|
||||
replace_rate = 50,
|
||||
replace_what = {"default:torch",},
|
||||
replace_with = "air",
|
||||
replace_offset = 2,
|
||||
view_range = 15,
|
||||
owner = "",
|
||||
order = "follow",
|
||||
animation = {
|
||||
speed_normal = 30,
|
||||
speed_run = 30,
|
||||
stand_start = 0,
|
||||
stand_end = 79,
|
||||
walk_start = 168,
|
||||
walk_end = 187,
|
||||
run_start = 168,
|
||||
run_end = 187,
|
||||
punch_start = 200,
|
||||
punch_end = 219,
|
||||
},
|
||||
on_rightclick = function(self, clicker)
|
||||
local item = clicker:get_wielded_item()
|
||||
local name = clicker:get_player_name()
|
||||
|
||||
-- feed to heal goblin
|
||||
if item:get_name() == "default:apple"
|
||||
or item:get_name() == "farming:bread" then
|
||||
|
||||
local hp = self.object:get_hp()
|
||||
-- return if full health
|
||||
if hp >= self.hp_max then
|
||||
minetest.chat_send_player(name, "goblin at full health.")
|
||||
return
|
||||
end
|
||||
hp = hp + 4
|
||||
if hp > self.hp_max then hp = self.hp_max end
|
||||
self.object:set_hp(hp)
|
||||
-- take item
|
||||
if not minetest.setting_getbool("creative_mode") then
|
||||
item:take_item()
|
||||
clicker:set_wielded_item(item)
|
||||
end
|
||||
|
||||
-- right clicking with gold lump drops random item from mobs_goblins.goblin_drops
|
||||
elseif item:get_name() == "default:gold_lump" then
|
||||
if not minetest.setting_getbool("creative_mode") then
|
||||
item:take_item()
|
||||
clicker:set_wielded_item(item)
|
||||
end
|
||||
local pos = self.object:getpos()
|
||||
pos.y = pos.y + 0.5
|
||||
minetest.add_item(pos, {name = mobs_goblins.goblin_drops[math.random(1, #mobs_goblins.goblin_drops)]})
|
||||
|
||||
else
|
||||
-- if owner switch between follow and stand
|
||||
if self.owner and self.owner == clicker:get_player_name() then
|
||||
if self.order == "follow" then
|
||||
self.order = "stand"
|
||||
else
|
||||
self.order = "follow"
|
||||
end
|
||||
-- else
|
||||
-- self.owner = clicker:get_player_name()
|
||||
end
|
||||
end
|
||||
|
||||
mobs_goblins:capture_mob(self, clicker, 0, 5, 80, false, nil)
|
||||
end,
|
||||
|
||||
})
|
||||
mobs_goblins:register_mob("mobs_goblins:goblin_diamond", {
|
||||
description = "Diamond Goblin",
|
||||
type = "animal",
|
||||
passive = false,
|
||||
damage = 3,
|
||||
attack_type = "dogfight",
|
||||
attacks_monsters = true,
|
||||
hp_min = 20,
|
||||
hp_max = 30,
|
||||
armor = 100,
|
||||
collisionbox = {-0.35,-1.0,-0.35, 0.35,0.0,0.35},
|
||||
visual = "mesh",
|
||||
mesh = "goblins_goblin.b3d",
|
||||
drawtype = "front",
|
||||
textures = {
|
||||
{"goblins_goblin_diamond1.png"},
|
||||
{"goblins_goblin_diamond2.png"},
|
||||
},
|
||||
makes_footstep_sound = true,
|
||||
sounds = {
|
||||
random = "mobs_pig",
|
||||
attack = "mobs_pig_angry",
|
||||
},
|
||||
walk_velocity = 2,
|
||||
run_velocity = 3,
|
||||
jump = true,
|
||||
drops = {
|
||||
{name = "default:pick_diamond",
|
||||
chance = 1, min = 1, max = 1},
|
||||
{name = "default:apple",
|
||||
chance = 2, min = 1, max = 10},
|
||||
{name = "default:diamond",
|
||||
chance = 5, min = 1, max = 1},
|
||||
},
|
||||
water_damage = 0,
|
||||
lava_damage = 2,
|
||||
light_damage = 0,
|
||||
follow = "default:diamond",
|
||||
replace_rate = 50,
|
||||
replace_what = {"default:torch",},
|
||||
replace_with = "air",
|
||||
replace_offset = 2,
|
||||
view_range = 15,
|
||||
owner = "",
|
||||
order = "follow",
|
||||
animation = {
|
||||
speed_normal = 30,
|
||||
speed_run = 30,
|
||||
stand_start = 0,
|
||||
stand_end = 79,
|
||||
walk_start = 168,
|
||||
walk_end = 187,
|
||||
run_start = 168,
|
||||
run_end = 187,
|
||||
punch_start = 200,
|
||||
punch_end = 219,
|
||||
},
|
||||
on_rightclick = function(self, clicker)
|
||||
local item = clicker:get_wielded_item()
|
||||
local name = clicker:get_player_name()
|
||||
|
||||
-- feed to heal goblin
|
||||
if item:get_name() == "default:apple"
|
||||
or item:get_name() == "farming:bread" then
|
||||
|
||||
local hp = self.object:get_hp()
|
||||
-- return if full health
|
||||
if hp >= self.hp_max then
|
||||
minetest.chat_send_player(name, "goblin at full health.")
|
||||
return
|
||||
end
|
||||
hp = hp + 4
|
||||
if hp > self.hp_max then hp = self.hp_max end
|
||||
self.object:set_hp(hp)
|
||||
-- take item
|
||||
if not minetest.setting_getbool("creative_mode") then
|
||||
item:take_item()
|
||||
clicker:set_wielded_item(item)
|
||||
end
|
||||
|
||||
-- right clicking with gold lump drops random item from mobs_goblins.goblin_drops
|
||||
elseif item:get_name() == "default:gold_lump" then
|
||||
if not minetest.setting_getbool("creative_mode") then
|
||||
item:take_item()
|
||||
clicker:set_wielded_item(item)
|
||||
end
|
||||
local pos = self.object:getpos()
|
||||
pos.y = pos.y + 0.5
|
||||
minetest.add_item(pos, {name = mobs_goblins.goblin_drops[math.random(1, #mobs_goblins.goblin_drops)]})
|
||||
|
||||
else
|
||||
-- if owner switch between follow and stand
|
||||
if self.owner and self.owner == clicker:get_player_name() then
|
||||
if self.order == "follow" then
|
||||
self.order = "stand"
|
||||
else
|
||||
self.order = "follow"
|
||||
end
|
||||
-- else
|
||||
-- self.owner = clicker:get_player_name()
|
||||
end
|
||||
end
|
||||
|
||||
mobs_goblins:capture_mob(self, clicker, 0, 5, 80, false, nil)
|
||||
end,
|
||||
|
||||
})
|
||||
mobs_goblins:register_mob("mobs_goblins:goblin_king", {
|
||||
description = "Goblin King",
|
||||
type = "monster",
|
||||
passive = false,
|
||||
damage = 4,
|
||||
attack_type = "dogfight",
|
||||
attacks_monsters = true,
|
||||
hp_min = 20,
|
||||
hp_max = 40,
|
||||
armor = 100,
|
||||
collisionbox = {-0.35,-1.0,-0.35, 0.35,0.0,0.35},
|
||||
visual = "mesh",
|
||||
mesh = "goblins_goblin.b3d",
|
||||
drawtype = "front",
|
||||
textures = {
|
||||
{"goblins_goblin_king.png"},
|
||||
},
|
||||
makes_footstep_sound = true,
|
||||
sounds = {
|
||||
random = "mobs_pig",
|
||||
attack = "mobs_pig_angry",
|
||||
},
|
||||
walk_velocity = 2,
|
||||
run_velocity = 3,
|
||||
jump = true,
|
||||
drops = {
|
||||
{name = "default:pick_mese",
|
||||
chance = 1, min = 1, max = 1},
|
||||
{name = "default:apple",
|
||||
chance = 2, min = 1, max = 10},
|
||||
{name = "default:mese_crystal",
|
||||
chance = 5, min = 1, max = 1},
|
||||
},
|
||||
water_damage = 0,
|
||||
lava_damage = 2,
|
||||
light_damage = 0,
|
||||
follow = "default:diamond",
|
||||
replace_rate = 50,
|
||||
replace_what = {"default:torch",},
|
||||
replace_with = "air",
|
||||
replace_offset = -1,
|
||||
view_range = 15,
|
||||
owner = "",
|
||||
order = "follow",
|
||||
animation = {
|
||||
speed_normal = 30,
|
||||
speed_run = 30,
|
||||
stand_start = 0,
|
||||
stand_end = 79,
|
||||
walk_start = 168,
|
||||
walk_end = 187,
|
||||
run_start = 168,
|
||||
run_end = 187,
|
||||
punch_start = 200,
|
||||
punch_end = 219,
|
||||
},
|
||||
on_rightclick = function(self, clicker)
|
||||
local item = clicker:get_wielded_item()
|
||||
local name = clicker:get_player_name()
|
||||
|
||||
-- feed to heal goblin
|
||||
if item:get_name() == "default:apple"
|
||||
or item:get_name() == "farming:bread" then
|
||||
|
||||
local hp = self.object:get_hp()
|
||||
-- return if full health
|
||||
if hp >= self.hp_max then
|
||||
minetest.chat_send_player(name, "goblin at full health.")
|
||||
return
|
||||
end
|
||||
hp = hp + 4
|
||||
if hp > self.hp_max then hp = self.hp_max end
|
||||
self.object:set_hp(hp)
|
||||
-- take item
|
||||
if not minetest.setting_getbool("creative_mode") then
|
||||
item:take_item()
|
||||
clicker:set_wielded_item(item)
|
||||
end
|
||||
|
||||
-- right clicking with gold lump drops random item from mobs_goblins.goblin_drops
|
||||
elseif item:get_name() == "default:gold_lump" then
|
||||
if not minetest.setting_getbool("creative_mode") then
|
||||
item:take_item()
|
||||
clicker:set_wielded_item(item)
|
||||
end
|
||||
local pos = self.object:getpos()
|
||||
pos.y = pos.y + 0.5
|
||||
minetest.add_item(pos, {name = mobs_goblins.goblin_drops[math.random(1, #mobs_goblins.goblin_drops)]})
|
||||
|
||||
else
|
||||
-- if owner switch between follow and stand
|
||||
if self.owner and self.owner == clicker:get_player_name() then
|
||||
if self.order == "follow" then
|
||||
self.order = "stand"
|
||||
else
|
||||
self.order = "follow"
|
||||
end
|
||||
-- else
|
||||
-- self.owner = clicker:get_player_name()
|
||||
end
|
||||
end
|
||||
|
||||
mobs_goblins:capture_mob(self, clicker, 0, 5, 80, false, nil)
|
||||
end,
|
||||
|
||||
})
|
||||
-- spawn underground near ore and dungeons, except cobble goblins who create goblin lairs.
|
||||
--function mobs_goblins:register_spawn(name, nodes, max_light, min_light, chance, active_object_count, max_height)
|
||||
mobs_goblins:register_spawn("mobs_goblins:goblin_cobble", {"group:stone"}, 1000, 0, 200, 1, 1)
|
||||
mobs_goblins:register_spawn("mobs_goblins:goblin_coal", {"default:torch", "default:coal", "default:mossycobble"}, 1000, 0, 30, 1, 1)
|
||||
mobs_goblins:register_spawn("mobs_goblins:goblin_iron", {"default:stone_with_iron","default:mossycobble",}, 10, 0, 30, 1, 1)
|
||||
mobs_goblins:register_spawn("mobs_goblins:goblin_gold", {"default:stone_with_gold","default:mossycobble", }, 10, 0, 30, 1, 1)
|
||||
mobs_goblins:register_spawn("mobs_goblins:goblin_diamond", {"default:stone_with_diamond","default:mossycobble", }, 30, 0, 100, 1, 1)
|
||||
mobs_goblins:register_spawn("mobs_goblins:goblin_king", {"default:stone_with_mese","default:mossycobble", }, 10, 0, 300, 1, 1)
|
||||
mobs_goblins:register_egg("mobs_goblins:goblin_coal", "goblin egg", "default:stone_with_coal", 1)
|
|
@ -0,0 +1,13 @@
|
|||
local path = minetest.get_modpath("mobs_goblins")
|
||||
|
||||
-- Mob Api
|
||||
|
||||
dofile(path.."/api.lua")
|
||||
|
||||
|
||||
dofile(path.."/goblins.lua") -- TenPlus1 and FreeLikeGNU
|
||||
|
||||
|
||||
--if minetest.setting_get("log_mods") then
|
||||
minetest.log("action", "GOBLINS is lowdids!")
|
||||
--end
|
After Width: | Height: | Size: 259 B |
After Width: | Height: | Size: 2.2 KiB |
After Width: | Height: | Size: 2.2 KiB |
After Width: | Height: | Size: 2.3 KiB |
After Width: | Height: | Size: 2.4 KiB |
After Width: | Height: | Size: 2.1 KiB |
After Width: | Height: | Size: 2.1 KiB |
After Width: | Height: | Size: 2.3 KiB |
After Width: | Height: | Size: 2.4 KiB |
After Width: | Height: | Size: 2.1 KiB |
After Width: | Height: | Size: 2.3 KiB |
After Width: | Height: | Size: 2.0 KiB |
|
@ -3,7 +3,7 @@ Thirsty [thirsty]
|
|||
|
||||
A Minetest mod that adds a "thirst" mechanic.
|
||||
|
||||
Version: 0.9.0
|
||||
Version: 0.10.0
|
||||
|
||||
License:
|
||||
Code: LGPL 2.1 (see included LICENSE file)
|
||||
|
|
|
@ -1,4 +1,4 @@
|
|||
default
|
||||
default?
|
||||
bucket?
|
||||
hud?
|
||||
hudbars?
|
||||
|
|
|
@ -6,13 +6,21 @@ See init.lua for license.
|
|||
|
||||
]]
|
||||
|
||||
local PPA = persistent_player_attributes
|
||||
|
||||
PPA.register({
|
||||
name = 'thirsty_hydro',
|
||||
min = 0,
|
||||
max = 50,
|
||||
default = 20,
|
||||
})
|
||||
|
||||
function thirsty.on_joinplayer(player)
|
||||
local name = player:get_player_name()
|
||||
-- default entry for new players
|
||||
if not thirsty.players[name] then
|
||||
local pos = player:getpos()
|
||||
thirsty.players[name] = {
|
||||
hydro = 20,
|
||||
last_pos = math.floor(pos.x) .. ':' .. math.floor(pos.z),
|
||||
time_in_pos = 0.0,
|
||||
pending_dmg = 0.0,
|
||||
|
@ -26,7 +34,7 @@ function thirsty.on_dieplayer(player)
|
|||
local name = player:get_player_name()
|
||||
local pl = thirsty.players[name]
|
||||
-- reset after death
|
||||
pl.hydro = 20
|
||||
PPA.set_value(player, 'thirsty_hydro', 20)
|
||||
pl.pending_dmg = 0.0
|
||||
pl.thirst_factor = 1.0
|
||||
end
|
||||
|
@ -37,32 +45,25 @@ Getters, setters and such
|
|||
|
||||
]]
|
||||
|
||||
-- internal version, for speed
|
||||
function thirsty._drink(pl, value, max)
|
||||
-- test whether we're not *above* max;
|
||||
-- this function should not remove any overhydration
|
||||
if pl.hydro < max then
|
||||
pl.hydro = math.min(pl.hydro + value, max)
|
||||
--print("Drinking by "..value.." to "..pl.hydro)
|
||||
return true
|
||||
end
|
||||
return false
|
||||
end
|
||||
|
||||
function thirsty.drink(player, value, max)
|
||||
-- if max is not specified, assume 20
|
||||
if not max then
|
||||
max = 20
|
||||
end
|
||||
local name = player:get_player_name()
|
||||
local pl = thirsty.players[name]
|
||||
return thirsty._drink(pl, value, max)
|
||||
local hydro = PPA.get_value(player, 'thirsty_hydro')
|
||||
-- test whether we're not *above* max;
|
||||
-- this function should not remove any overhydration
|
||||
if hydro < max then
|
||||
hydro = math.min(hydro + value, max)
|
||||
--print("Drinking by "..value.." to "..hydro)
|
||||
PPA.set_value(player, 'thirsty_hydro', hydro)
|
||||
return true
|
||||
end
|
||||
return false
|
||||
end
|
||||
|
||||
function thirsty.get_hydro(player)
|
||||
local name = player:get_player_name()
|
||||
local pl = thirsty.players[name]
|
||||
return pl.hydro
|
||||
return PPA.get_value(player, 'thirsty_hydro')
|
||||
end
|
||||
|
||||
function thirsty.set_thirst_factor(player, factor)
|
||||
|
@ -99,6 +100,7 @@ function thirsty.main_loop(dtime)
|
|||
local name = player:get_player_name()
|
||||
local pos = player:getpos()
|
||||
local pl = thirsty.players[name]
|
||||
local hydro = PPA.get_value(player, 'thirsty_hydro')
|
||||
|
||||
-- how long have we been standing "here"?
|
||||
-- (the node coordinates in X and Z should be enough)
|
||||
|
@ -184,40 +186,41 @@ function thirsty.main_loop(dtime)
|
|||
local wear = itemstack:get_wear()
|
||||
if wear == 0 then wear = 65535.0 end
|
||||
local drink = injector_max * thirsty.config.tick_time
|
||||
local drink_missing = 20 - pl.hydro
|
||||
local drink_missing = 20 - hydro
|
||||
drink = math.max(math.min(drink, drink_missing), 0)
|
||||
local drinkwear = drink / capacity * 65535.0
|
||||
wear = wear + drinkwear
|
||||
if wear > 65534 then wear = 65534 end
|
||||
itemstack:set_wear(wear)
|
||||
thirsty._drink(pl, drink, 20)
|
||||
thirsty.drink(player, drink, 20)
|
||||
hydro = PPA.get_value(player, 'thirsty_hydro')
|
||||
player:get_inventory():set_stack("main", i, itemstack)
|
||||
end
|
||||
|
||||
|
||||
if drink_per_second > 0 and pl_standing then
|
||||
-- Drinking from the ground won't give you more than max
|
||||
thirsty._drink(pl, drink_per_second * thirsty.config.tick_time, 20)
|
||||
--print("Raising hydration by "..(drink_per_second*thirsty.config.tick_time).." to "..pl.hydro)
|
||||
thirsty.drink(player, drink_per_second * thirsty.config.tick_time, 20)
|
||||
--print("Raising hydration by "..(drink_per_second*thirsty.config.tick_time).." to "..PPA.get_value(player, 'thirsty_hydro'))
|
||||
else
|
||||
if not pl_afk then
|
||||
-- only get thirsty if not AFK
|
||||
local amount = thirsty.config.thirst_per_second * thirsty.config.tick_time * pl.thirst_factor
|
||||
pl.hydro = pl.hydro - amount
|
||||
if pl.hydro < 0 then pl.hydro = 0 end
|
||||
--print("Lowering hydration by "..amount.." to "..pl.hydro)
|
||||
PPA.set_value(player, 'thirsty_hydro', hydro - amount)
|
||||
hydro = PPA.get_value(player, 'thirsty_hydro')
|
||||
--print("Lowering hydration by "..amount.." to "..hydro)
|
||||
end
|
||||
end
|
||||
|
||||
|
||||
-- should we only update the hud on an actual change?
|
||||
thirsty.hud_update(player, pl.hydro)
|
||||
thirsty.hud_update(player, hydro)
|
||||
|
||||
-- damage, if enabled
|
||||
if minetest.setting_getbool("enable_damage") then
|
||||
-- maybe not the best way to do this, but it does mean
|
||||
-- we can do anything with one tick loop
|
||||
if pl.hydro <= 0.0 and not pl_afk then
|
||||
if hydro <= 0.0 and not pl_afk then
|
||||
pl.pending_dmg = pl.pending_dmg + thirsty.config.damage_per_second * thirsty.config.tick_time
|
||||
--print("Pending damage at " .. pl.pending_dmg)
|
||||
if pl.pending_dmg > 1.0 then
|
||||
|
@ -247,59 +250,6 @@ end
|
|||
|
||||
--[[
|
||||
|
||||
Stash: persist the hydration values in a file in the world directory.
|
||||
|
||||
If this is missing or corrupted, then no worries: nobody's thirsty ;-)
|
||||
|
||||
]]
|
||||
|
||||
function thirsty.read_stash()
|
||||
local filename = minetest.get_worldpath() .. "/" .. thirsty.config.stash_filename
|
||||
local file, err = io.open(filename, "r")
|
||||
if not file then
|
||||
-- no problem, it's just not there
|
||||
-- TODO: or parse err?
|
||||
return
|
||||
end
|
||||
thirsty.players = {}
|
||||
for line in file:lines() do
|
||||
if string.match(line, '^%-%-') then
|
||||
-- comment, ignore
|
||||
elseif string.match(line, '^P [%d.]+ [%d.]+ .+') then
|
||||
-- player line
|
||||
-- is matching again really the best solution?
|
||||
local hydro, dmg, name = string.match(line, '^P ([%d.]+) ([%d.]+) (.+)')
|
||||
thirsty.players[name] = {
|
||||
hydro = tonumber(hydro),
|
||||
last_pos = '0:0', -- not true, but no matter
|
||||
time_in_pos = 0.0,
|
||||
pending_dmg = tonumber(dmg),
|
||||
thirst_factor = 1.0,
|
||||
}
|
||||
end
|
||||
end
|
||||
file:close()
|
||||
end
|
||||
|
||||
function thirsty.write_stash()
|
||||
local filename = minetest.get_worldpath() .. "/" .. thirsty.config.stash_filename
|
||||
local file, err = io.open(filename, "w")
|
||||
if not file then
|
||||
minetest.log("error", "Thirsty: could not write " .. thirsty.config.stash_filename .. ": " ..err)
|
||||
return
|
||||
end
|
||||
file:write('-- Stash file for Minetest mod [thirsty] --\n')
|
||||
-- write players:
|
||||
-- P <hydro> <pending_dmg> <name>
|
||||
file:write('-- Player format: "P <hydro> <pending damage> <name>"\n')
|
||||
for name, data in pairs(thirsty.players) do
|
||||
file:write("P " .. data.hydro .. " " .. data.pending_dmg .. " " .. name .. "\n")
|
||||
end
|
||||
file:close()
|
||||
end
|
||||
|
||||
--[[
|
||||
|
||||
General handler
|
||||
|
||||
Most tools, nodes and craftitems use the same code, so here it is:
|
||||
|
@ -308,7 +258,8 @@ Most tools, nodes and craftitems use the same code, so here it is:
|
|||
|
||||
function thirsty.drink_handler(player, itemstack, node)
|
||||
local pl = thirsty.players[player:get_player_name()]
|
||||
local old_hydro = pl.hydro
|
||||
local hydro = PPA.get_value(player, 'thirsty_hydro')
|
||||
local old_hydro = hydro
|
||||
|
||||
-- selectors, always true, to make the following code easier
|
||||
local item_name = itemstack and itemstack:get_name() or ':'
|
||||
|
@ -321,9 +272,7 @@ function thirsty.drink_handler(player, itemstack, node)
|
|||
-- drink until level
|
||||
local level = math.max(cont_level, node_level)
|
||||
--print("Drinking to level " .. level)
|
||||
if pl.hydro < level then
|
||||
pl.hydro = level
|
||||
end
|
||||
thirsty.drink(player, level, level)
|
||||
|
||||
-- fill container, if applicable
|
||||
if thirsty.config.container_capacity[item_name] then
|
||||
|
@ -335,7 +284,7 @@ function thirsty.drink_handler(player, itemstack, node)
|
|||
-- drinking from a container
|
||||
if itemstack:get_wear() ~= 0 then
|
||||
local capacity = thirsty.config.container_capacity[item_name]
|
||||
local hydro_missing = 20 - pl.hydro;
|
||||
local hydro_missing = 20 - hydro;
|
||||
if hydro_missing > 0 then
|
||||
local wear_missing = hydro_missing / capacity * 65535.0;
|
||||
local wear = itemstack:get_wear()
|
||||
|
@ -346,15 +295,16 @@ function thirsty.drink_handler(player, itemstack, node)
|
|||
end
|
||||
itemstack:set_wear(new_wear)
|
||||
if wear_missing > 0 then -- rounding glitches?
|
||||
thirsty._drink(pl, wear_missing * capacity / 65535.0, 20)
|
||||
thirsty.drink(player, wear_missing * capacity / 65535.0, 20)
|
||||
hydro = PPA.get_value(player, 'thirsty_hydro')
|
||||
end
|
||||
end
|
||||
end
|
||||
end
|
||||
|
||||
-- update HUD if value changed
|
||||
if pl.hydro ~= old_hydro then
|
||||
thirsty.hud_update(player, pl.hydro)
|
||||
if hydro ~= old_hydro then
|
||||
thirsty.hud_update(player, hydro)
|
||||
end
|
||||
end
|
||||
|
||||
|
|
|
@ -17,6 +17,8 @@ Any hud needs to define the following functions:
|
|||
|
||||
]]
|
||||
|
||||
local PPA = persistent_player_attributes
|
||||
|
||||
function thirsty.hud_clamp(value)
|
||||
if value < 0 then
|
||||
return 0
|
||||
|
@ -33,13 +35,11 @@ if minetest.get_modpath("hudbars") then
|
|||
icon = 'thirsty_cup_100_16.png'
|
||||
}, 20, 20, false)
|
||||
function thirsty.hud_init(player)
|
||||
local name = player:get_player_name()
|
||||
hb.init_hudbar(player, 'thirst',
|
||||
thirsty.hud_clamp(thirsty.players[name].hydro),
|
||||
thirsty.hud_clamp(PPA.get_value(player, 'thirsty_hydro')),
|
||||
20, false)
|
||||
end
|
||||
function thirsty.hud_update(player, value)
|
||||
local name = player:get_player_name()
|
||||
hb.change_hudbar(player, 'thirst', thirsty.hud_clamp(value), 20)
|
||||
end
|
||||
elseif minetest.get_modpath("hud") then
|
||||
|
@ -73,7 +73,7 @@ else
|
|||
hud_elem_type = "statbar",
|
||||
position = { x=0.5, y=1 },
|
||||
text = "thirsty_cup_100_24.png",
|
||||
number = thirsty.hud_clamp(thirsty.players[name].hydro),
|
||||
number = thirsty.hud_clamp(PPA.get_value(player, 'thirsty_hydro')),
|
||||
direction = 0,
|
||||
size = { x=24, y=24 },
|
||||
offset = { x=25, y=-(48+24+16+32)},
|
||||
|
|
|
@ -47,7 +47,6 @@ thirsty = {
|
|||
players = {
|
||||
--[[
|
||||
name = {
|
||||
hydro = 20,
|
||||
last_pos = '-10:3',
|
||||
time_in_pos = 0.0,
|
||||
pending_dmg = 0.0,
|
||||
|
@ -72,6 +71,8 @@ thirsty = {
|
|||
time_next_tick = 0.0,
|
||||
}
|
||||
|
||||
dofile(minetest.get_modpath('thirsty')..'/persistent_player_attributes.lua')
|
||||
|
||||
dofile(minetest.get_modpath('thirsty')..'/configuration.lua')
|
||||
|
||||
thirsty.time_next_tick = thirsty.config.tick_time
|
||||
|
@ -86,8 +87,8 @@ minetest.register_globalstep(thirsty.main_loop)
|
|||
dofile(minetest.get_modpath('thirsty')..'/components.lua')
|
||||
|
||||
-- read on startup
|
||||
thirsty.read_stash()
|
||||
--thirsty.read_stash()
|
||||
-- write on shutdown
|
||||
minetest.register_on_shutdown(thirsty.write_stash)
|
||||
--minetest.register_on_shutdown(thirsty.write_stash)
|
||||
|
||||
|
||||
|
|
|
@ -0,0 +1,151 @@
|
|||
--[[
|
||||
|
||||
Persistent player attributes (mixin)
|
||||
====================================
|
||||
|
||||
A mixin to provide persistent player attributes. Simply include and do
|
||||
this file in your mod, it will take care to update itself.
|
||||
|
||||
Copyright (C) 2015 Ben Deutsch <ben@bendeutsch.de>
|
||||
|
||||
License
|
||||
-------
|
||||
|
||||
This library is free software; you can redistribute it and/or
|
||||
modify it under the terms of the GNU Lesser General Public
|
||||
License as published by the Free Software Foundation; either
|
||||
version 2.1 of the License, or (at your option) any later version.
|
||||
|
||||
This library is distributed in the hope that it will be useful,
|
||||
but WITHOUT ANY WARRANTY; without even the implied warranty of
|
||||
MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU
|
||||
Lesser General Public License for more details.
|
||||
|
||||
You should have received a copy of the GNU Lesser General Public
|
||||
License along with this library; if not, write to the Free Software
|
||||
Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301
|
||||
USA
|
||||
|
||||
]]
|
||||
|
||||
local global_exists = minetest.global_exists or function(name) rawget(_G, name) end
|
||||
if not global_exists('persistent_player_attributes') then
|
||||
persistent_player_attributes = {
|
||||
-- trigger "newer version available" below
|
||||
version = 0.000,
|
||||
}
|
||||
end
|
||||
|
||||
--[[
|
||||
|
||||
DO NOT RESET THE GLOBAL VARIABLE!
|
||||
|
||||
The following code *and library users* localize the (overly long)
|
||||
library global variable. If another mod later includes a newer version
|
||||
of this library, and this newer version changes the global variable
|
||||
"persistent_player_attributes", then the mods which previously
|
||||
included this mixin may *or may not* be using the old version.
|
||||
Chaos will certainly ensue.
|
||||
|
||||
]]
|
||||
|
||||
local PPA = persistent_player_attributes
|
||||
|
||||
if PPA.version < 1.000 then
|
||||
|
||||
-- the version, minor and patch are in thousandths,
|
||||
-- e.g. 1.2.3 becomes 1.002003
|
||||
|
||||
PPA.version = 1.000
|
||||
|
||||
-- the stash of registered attributes
|
||||
|
||||
PPA.defs = {--[[
|
||||
name = {
|
||||
name = "mymod_attr1",
|
||||
min = 0,
|
||||
max = 10,
|
||||
default = 5,
|
||||
},
|
||||
]]}
|
||||
|
||||
--[[
|
||||
How to register a new attribute, with named parameters:
|
||||
PPA.register({ name = "mymod_attr1", min = 0, ... })
|
||||
]]
|
||||
|
||||
PPA.register = function(def)
|
||||
PPA.defs[def.name] = {
|
||||
name = name,
|
||||
min = def.min or 0.0,
|
||||
max = def.max or 1.0,
|
||||
default = def.default or def.min or 0.0,
|
||||
}
|
||||
end
|
||||
|
||||
--[[
|
||||
Helper functions that take care of the conversions *and* the
|
||||
clamping for us
|
||||
]]
|
||||
|
||||
local function _count_for_val(value, def)
|
||||
local count = math.floor((value - def.min) / (def.max - def.min) * 65535)
|
||||
if count < 0 then count = 0 end
|
||||
if count > 65535 then count = 65535 end
|
||||
return count
|
||||
end
|
||||
local function _val_for_count(count, def)
|
||||
local value = count / 65535 * (def.max - def.min) + def.min
|
||||
if value < def.min then value = def.min end
|
||||
if value > def.max then value = def.max end
|
||||
return value
|
||||
end
|
||||
|
||||
--[[
|
||||
We cannot override / take back a register_on_joinplayer,
|
||||
so we'll only create and register this one, which calls the
|
||||
(overridable) actual handler
|
||||
]]
|
||||
if not PPA.shim_on_joinplayer then
|
||||
PPA.shim_on_joinplayer = function(player)
|
||||
PPA.on_joinplayer(player)
|
||||
end
|
||||
minetest.register_on_joinplayer(PPA.shim_on_joinplayer)
|
||||
end
|
||||
|
||||
-- The actual on_joinplayer handler
|
||||
|
||||
PPA.on_joinplayer = function(player)
|
||||
local inv = player:get_inventory()
|
||||
for name, def in pairs(PPA.defs) do
|
||||
inv:set_size(name, 1)
|
||||
if inv:is_empty(name) then
|
||||
-- set default value
|
||||
inv:set_stack(name, 1, ItemStack({ name = ":", count = _count_for_val(def.default, def) }))
|
||||
end
|
||||
end
|
||||
end
|
||||
|
||||
--[[ get an attribute, procedural style:
|
||||
local attr1 = PPA.get_value(player, "mymod_attr1")
|
||||
]]
|
||||
|
||||
PPA.get_value = function(player, name)
|
||||
local def = PPA.defs[name]
|
||||
local inv = player:get_inventory()
|
||||
local count = inv:get_stack(name, 1):get_count()
|
||||
return _val_for_count(count, def)
|
||||
end
|
||||
|
||||
--[[ set an attribute, procedural style:
|
||||
PPA.set_value(player, "mymod_attr1", attr1)
|
||||
]]
|
||||
|
||||
PPA.set_value = function(player, name, value)
|
||||
local def = PPA.defs[name]
|
||||
local inv = player:get_inventory()
|
||||
inv:set_stack(name, 1, ItemStack({ name = ":", count = _count_for_val(value, def) }))
|
||||
end
|
||||
|
||||
end
|
||||
|
|
@ -0,0 +1,4 @@
|
|||
GNU GENERAL PUBLIC LICENSE
|
||||
Version 3, 29 June 2007
|
||||
|
||||
See http://www.gnu.org/licenses/gpl-3.0.en.html
|
|
@ -0,0 +1,53 @@
|
|||
# Valleys Mapgen
|
||||
Mapgen mod for Minetest 0.4.12+. Work in progress, not finished.
|
||||
|
||||
![Screenshot](http://i.imgur.com/A6CBuaV.png)
|
||||
|
||||
[Discussion on Minetest Forums](https://forum.minetest.net/viewtopic.php?f=9&t=11430)
|
||||
|
||||
## Changelog
|
||||
### 2.1 ~> Latest
|
||||
* Added flowers (6 species)
|
||||
|
||||
### 2.0 ~> 2.1 (Saturday July 4, 2015)
|
||||
* Modified conditions for desert plants
|
||||
* Added pine tree
|
||||
* Generate special water in rivers
|
||||
* Changed valley shape a bit (no more cliffs on the sides of the rivers)
|
||||
* Changed river shape (smooth floor)
|
||||
|
||||
### 1.3 ~> 2.0 (Sunday May 31, 2015)
|
||||
* Added plants, optionnal, enabled by default
|
||||
* Corrected math.random too large interval (2³² → 2²⁴)
|
||||
* Added snow
|
||||
* When a player dies, it's respawned
|
||||
* Adapted to any `chunksize` (previously the mod was only working for 5)
|
||||
* Added trees (3 species for now), optionnal, enabled by default
|
||||
* Added logs : see vmg.conf.example
|
||||
* Added temperature and humidity noises, used by trees
|
||||
* Changed parameters for lava
|
||||
|
||||
### 1.2 ~> 1.3 (Wednesday April 8, 2015)
|
||||
* Added differents types of dirts (the aim is to make real biomes in the future)
|
||||
* Added beaches
|
||||
* Added setting `water_level` to set water level (default is 1)
|
||||
* Fixed fatal error with number settings
|
||||
|
||||
### 1.1 ~> 1.2 (Tuesday March 17, 2015)
|
||||
* Added lava underground
|
||||
* Settings in minetest.conf : see file vmg.conf.example
|
||||
* Now the player can't spawn in rivers
|
||||
* Player spawn location is randomized : you can set the maximal distance from (0;0) at which the player will appear. (If it's in a big ocean, it may be farther)
|
||||
* Some minor changes about terrain :
|
||||
* Bare stone is rarer
|
||||
* Valleys are slightly larger
|
||||
* Ores are generated properly, according to [Paramat's changes](https://github.com/minetest/minetest/commit/b2b6bbf3e80f0ab06d62c43567122871ae560534) in `minetest.generate_ores`. **I advise you to update your MT version to a recent build (03/11 or later) or the ores overlapping problem will reappear.**
|
||||
|
||||
### 1.0 ~> 1.1 (Sunday March 8, 2015)
|
||||
* Added caves: they are modelised by 4 3D noises.
|
||||
* Corrected ores generation: There was too many ores because it was sometimes generated twice or even more.
|
||||
* Activated versions manager: if you update the mod from 1.0 to this version, the new mapgen will only take effect on new worlds, worlds created with 1.0 will stay in 1.0. If you want to activate mapgen 1.1 in an old world (there could be cleavages), change the file vmg.conf which is in the world directory.
|
||||
* Added… this changelog :-D
|
||||
|
||||
### 1.0 (Saturday March 7, 2015)
|
||||
* Created mapgen (using 7 noises at the moment).
|
|
@ -0,0 +1,2 @@
|
|||
default
|
||||
flowers
|
|
@ -0,0 +1,91 @@
|
|||
vmg = {}
|
||||
vmg.version = "2.2"
|
||||
|
||||
vmg.path = minetest.get_modpath("valleys_mapgen")
|
||||
|
||||
vmg.loglevel = tonumber(minetest.setting_get("vmg_log_level") or 0)
|
||||
|
||||
if vmg.loglevel >= 2 then
|
||||
print("[Valleys Mapgen] Loading basic functions ...")
|
||||
end
|
||||
|
||||
minetest.register_on_mapgen_init(function(mgparams)
|
||||
minetest.set_mapgen_params({mgname="singlenode", flags="nolight"})
|
||||
end)
|
||||
|
||||
if default then
|
||||
if default.register_ores then
|
||||
default.register_ores()
|
||||
end
|
||||
if default.register_blobs then
|
||||
default.register_blobs()
|
||||
end
|
||||
end
|
||||
|
||||
function pos2d(pos)
|
||||
if type(pos) == "number" then
|
||||
return {x = pos, y = pos}
|
||||
elseif pos.z then
|
||||
return {x = pos.x, y = pos.z}
|
||||
else
|
||||
return {x = pos.x, y = pos.y}
|
||||
end
|
||||
end
|
||||
|
||||
function pos3d(pos, alt)
|
||||
alt = alt or 0
|
||||
if type(pos) == "number" then
|
||||
return {x = pos, y = pos, z = pos}
|
||||
elseif pos.z then
|
||||
return {x = pos.x, y = pos.z, z = pos.z}
|
||||
else
|
||||
return {x = pos.x, y = alt, z = pos.y}
|
||||
end
|
||||
end
|
||||
|
||||
function minetest.add_group(node, groups)
|
||||
local def = minetest.registered_items[node]
|
||||
if not def then
|
||||
return false
|
||||
end
|
||||
local def_groups = def.groups or {}
|
||||
for group, value in pairs(groups) do
|
||||
if value ~= 0 then
|
||||
def_groups[group] = value
|
||||
else
|
||||
def_groups[group] = nil
|
||||
end
|
||||
end
|
||||
minetest.override_item(node, {groups = def_groups})
|
||||
return true
|
||||
end
|
||||
|
||||
function displaytime(time)
|
||||
return math.floor(time * 1000000 + 0.5) / 1000 .. " ms"
|
||||
end
|
||||
|
||||
if vmg.loglevel >= 2 then
|
||||
print("[Valleys Mapgen] Loading settings API ...")
|
||||
end
|
||||
|
||||
dofile(vmg.path .. "/settings.lua")
|
||||
|
||||
if vmg.define("spawn", true) then
|
||||
minetest.register_on_newplayer(vmg.spawnplayer)
|
||||
end
|
||||
|
||||
if vmg.define("respawn", true) then
|
||||
minetest.register_on_respawnplayer(vmg.spawnplayer)
|
||||
end
|
||||
|
||||
minetest.register_on_generated(vmg.generate)
|
||||
|
||||
if vmg.loglevel >= 2 then
|
||||
print("[Valleys Mapgen] Loading nodes ...")
|
||||
end
|
||||
|
||||
dofile(vmg.path .. "/nodes.lua")
|
||||
|
||||
if vmg.loglevel >= 1 then
|
||||
print("[Valleys Mapgen] Loaded !")
|
||||
end
|
|
@ -0,0 +1,552 @@
|
|||
-- Mapgen 2.2
|
||||
-- Monday July 6, 2015
|
||||
|
||||
vmg.noises = {
|
||||
|
||||
-- Noise 1 : Base Ground Height 2D
|
||||
{offset = -10, scale = 50, seed = 5202, spread = {x = 1024, y = 1024, z = 1024}, octaves = 6, persist = 0.4, lacunarity = 2},
|
||||
|
||||
-- Noise 2 : Valleys (River where around zero) 2D
|
||||
{offset = 0, scale = 1, seed = -6050, spread = {x = 256, y = 256, z = 256}, octaves = 5, persist = 0.6, lacunarity = 2},
|
||||
|
||||
-- Noise 3 : Valleys Depth 2D
|
||||
{offset = 5, scale = 4, seed = -1914, spread = {x = 512, y = 512, z = 512}, octaves = 1, persist = 1, lacunarity = 2},
|
||||
|
||||
-- Noise 4 : Valleys Profile (Higher values = Larger valleys) 2D
|
||||
{offset = 0.6, scale = 0.5, seed = 777, spread = {x = 512, y = 512, z = 512}, octaves = 1, persist = 1, lacunarity = 2},
|
||||
|
||||
-- Noise 5 : Inter-valleys slopes 2D
|
||||
{offset = 0.5, scale = 0.5, seed = 746, spread = {x = 128, y = 128, z = 128}, octaves = 1, persist = 1, lacunarity = 2},
|
||||
|
||||
-- Noise 6 : Inter-valleys filling 3D
|
||||
{offset = 0, scale = 1, seed = 1993, spread = {x = 256, y = 512, z = 256}, octaves = 6, persist = 0.8, lacunarity = 2},
|
||||
|
||||
-- Noise 7 : Dirt thickness 2D
|
||||
{offset = 3, scale = 1.75, seed = 1605, spread = {x = 256, y = 256, z = 256}, octaves = 3, persist = 0.5, lacunarity = 2},
|
||||
|
||||
-- Noise 8 : Caves I 3D
|
||||
{offset = 0, scale = 1, seed = -4640, spread = {x = 32, y = 32, z = 32}, octaves = 4, persist = 0.5, lacunarity = 2},
|
||||
|
||||
-- Noise 9 : Caves II 3D
|
||||
{offset = 0, scale = 1, seed = 8804, spread = {x = 32, y = 32, z = 32}, octaves = 4, persist = 0.5, lacunarity = 2},
|
||||
|
||||
-- Noise 10 : Caves III 3D
|
||||
{offset = 0, scale = 1, seed = -4780, spread = {x = 32, y = 32, z = 32}, octaves = 4, persist = 0.5, lacunarity = 2},
|
||||
|
||||
-- Noise 11 : Caves IV and Lava I 3D
|
||||
{offset = 0, scale = 1, seed = -9969, spread = {x = 32, y = 32, z = 32}, octaves = 4, persist = 0.5, lacunarity = 2},
|
||||
|
||||
-- Noise 12 : Lava II (Geologic heat) 3D
|
||||
{offset = 0, scale = 1, seed = 3314, spread = {x = 64, y = 64, z = 64}, octaves = 4, persist = 0.5, lacunarity = 2},
|
||||
|
||||
-- Noise 13 : Clayey dirt noise 2D
|
||||
{offset = 0, scale = 1, seed = 2835, spread = {x = 256, y = 256, z = 256}, octaves = 5, persist = 0.5, lacunarity = 4},
|
||||
|
||||
-- Noise 14 : Silty dirt noise 2D
|
||||
{offset = 0, scale = 1, seed = 6674, spread = {x = 256, y = 256, z = 256}, octaves = 5, persist = 0.5, lacunarity = 4},
|
||||
|
||||
-- Noise 15 : Sandy dirt noise 2D
|
||||
{offset = 0, scale = 1, seed = 6940, spread = {x = 256, y = 256, z = 256}, octaves = 5, persist = 0.5, lacunarity = 4},
|
||||
|
||||
-- Noise 16 : Beaches 2D
|
||||
{offset = 2, scale = 8, seed = 2349, spread = {x = 256, y = 256, z = 256}, octaves = 3, persist = 0.5, lacunarity = 2},
|
||||
|
||||
-- Noise 17 : Temperature (not in maps) 3D
|
||||
{offset = 2, scale = 1, seed = -1805, spread = {x = 768, y = 256, z = 768}, octaves = 4, persist = 0.5, lacunarity = 4},
|
||||
|
||||
-- Noise 18 : Humidity 2D
|
||||
{offset = 0, scale = 1, seed = -5787, spread = {x = 243, y = 243, z = 243}, octaves = 4, persist = 0.5, lacunarity = 3},
|
||||
|
||||
}
|
||||
|
||||
function vmg.noisemap(i, minp, chulens)
|
||||
local obj = minetest.get_perlin_map(vmg.noises[i], chulens)
|
||||
if minp.z then
|
||||
return obj:get3dMap_flat(minp)
|
||||
else
|
||||
return obj:get2dMap_flat(minp)
|
||||
end
|
||||
end
|
||||
|
||||
for i, n in ipairs(vmg.noises) do
|
||||
vmg.noises[i] = vmg.define("noise_" .. i, n)
|
||||
end
|
||||
|
||||
vmg.after_mapgen = {}
|
||||
|
||||
function vmg.register_after_mapgen(f, ...)
|
||||
table.insert(vmg.after_mapgen, {f = f, ...})
|
||||
end
|
||||
|
||||
function vmg.execute_after_mapgen()
|
||||
for i, params in ipairs(vmg.after_mapgen) do
|
||||
params.f(unpack(params))
|
||||
end
|
||||
vmg.after_mapgen = {}
|
||||
end
|
||||
|
||||
local river_depth = vmg.define("river_depth", 3) + 1
|
||||
local river_size = vmg.define("river_size", 5) / 100
|
||||
local caves_size = vmg.define("caves_size", 7) / 100
|
||||
local lava_depth = vmg.define("lava_depth", 2000)
|
||||
local lava_max_height = vmg.define("lava_max_height", -1)
|
||||
local altitude_chill = vmg.define("altitude_chill", 90)
|
||||
|
||||
local average_stone_level = vmg.define("average_stone_level", 180)
|
||||
local dirt_thickness = math.sqrt(average_stone_level) / (vmg.noises[7].offset + 0.5)
|
||||
local average_snow_level = vmg.define("average_snow_level", 100)
|
||||
local snow_threshold = vmg.noises[17].offset * 0.5 ^ (average_snow_level / altitude_chill)
|
||||
|
||||
local player_max_distance = vmg.define("player_max_distance", 450)
|
||||
|
||||
local clay_threshold = vmg.define("clay_threshold", 1)
|
||||
local silt_threshold = vmg.define("silt_threshold", 1)
|
||||
local sand_threshold = vmg.define("sand_threshold", 0.75)
|
||||
local dirt_threshold = vmg.define("dirt_threshold", 0.5)
|
||||
|
||||
local tree_density = vmg.define("tree_density", 5) / 100
|
||||
local trees = vmg.define("trees", true)
|
||||
local plant_density = vmg.define("plant_density", 32) / 100
|
||||
local plants = vmg.define("plants", true)
|
||||
|
||||
local water_level = vmg.define("water_level", 1)
|
||||
local river_water = vmg.define("river_water", true)
|
||||
|
||||
function vmg.generate(minp, maxp, seed)
|
||||
local minps, maxps = minetest.pos_to_string(minp), minetest.pos_to_string(maxp)
|
||||
if vmg.loglevel >= 2 then
|
||||
print("[Valleys Mapgen] Preparing to generate map from " .. minps .. " to " .. maxps .. " ...")
|
||||
elseif vmg.loglevel == 1 then
|
||||
print("[Valleys Mapgen] Generating map from " .. minps .. " to " .. maxps .. " ...")
|
||||
end
|
||||
local t0 = os.clock()
|
||||
|
||||
local c_stone = minetest.get_content_id("default:stone")
|
||||
local c_dirt = minetest.get_content_id("default:dirt")
|
||||
local c_lawn = minetest.get_content_id("default:dirt_with_grass")
|
||||
local c_snow = minetest.get_content_id("default:dirt_with_snow")
|
||||
local c_dirt_clay = minetest.get_content_id("valleys_mapgen:dirt_clayey")
|
||||
local c_lawn_clay = minetest.get_content_id("valleys_mapgen:dirt_clayey_with_grass")
|
||||
local c_snow_clay = minetest.get_content_id("valleys_mapgen:dirt_clayey_with_snow")
|
||||
local c_dirt_silt = minetest.get_content_id("valleys_mapgen:dirt_silty")
|
||||
local c_lawn_silt = minetest.get_content_id("valleys_mapgen:dirt_silty_with_grass")
|
||||
local c_snow_silt = minetest.get_content_id("valleys_mapgen:dirt_silty_with_snow")
|
||||
local c_dirt_sand = minetest.get_content_id("valleys_mapgen:dirt_sandy")
|
||||
local c_lawn_sand = minetest.get_content_id("valleys_mapgen:dirt_sandy_with_grass")
|
||||
local c_snow_sand = minetest.get_content_id("valleys_mapgen:dirt_sandy_with_snow")
|
||||
local c_desert_sand = minetest.get_content_id("default:desert_sand")
|
||||
local c_sand = minetest.get_content_id("default:sand")
|
||||
local c_gravel = minetest.get_content_id("default:gravel")
|
||||
local c_silt = minetest.get_content_id("valleys_mapgen:silt")
|
||||
local c_clay = minetest.get_content_id("valleys_mapgen:red_clay")
|
||||
local c_water = minetest.get_content_id("default:water_source")
|
||||
local c_riverwater = minetest.get_content_id("default:river_water_source")
|
||||
local c_lava = minetest.get_content_id("default:lava_source")
|
||||
local c_snow_layer = minetest.get_content_id("default:snow")
|
||||
|
||||
local c_tree = minetest.get_content_id("default:tree")
|
||||
local c_leaves = minetest.get_content_id("default:leaves")
|
||||
local c_apple = minetest.get_content_id("default:apple")
|
||||
local c_jungletree = minetest.get_content_id("default:jungletree")
|
||||
local c_jungleleaves = minetest.get_content_id("default:jungleleaves")
|
||||
local c_pinetree = minetest.get_content_id("default:pinetree")
|
||||
local c_pineleaves = minetest.get_content_id("default:pine_needles")
|
||||
local c_firtree = minetest.get_content_id("valleys_mapgen:fir_tree")
|
||||
local c_firleaves = minetest.get_content_id("valleys_mapgen:fir_needles")
|
||||
|
||||
local c_grass = {
|
||||
minetest.get_content_id("default:grass_1"),
|
||||
minetest.get_content_id("default:grass_2"),
|
||||
minetest.get_content_id("default:grass_3"),
|
||||
minetest.get_content_id("default:grass_4"),
|
||||
minetest.get_content_id("default:grass_5"),
|
||||
}
|
||||
local c_junglegrass = minetest.get_content_id("default:junglegrass")
|
||||
local c_dryshrub = minetest.get_content_id("default:dry_shrub")
|
||||
local c_cactus = minetest.get_content_id("default:cactus")
|
||||
local c_papyrus = minetest.get_content_id("default:papyrus")
|
||||
local c_geranium = minetest.get_content_id("flowers:geranium")
|
||||
local c_rose = minetest.get_content_id("flowers:rose")
|
||||
local c_tulip = minetest.get_content_id("flowers:tulip")
|
||||
local c_viola = minetest.get_content_id("flowers:viola")
|
||||
local c_dandelion_white = minetest.get_content_id("flowers:dandelion_white")
|
||||
local c_dandelion_yellow = minetest.get_content_id("flowers:dandelion_yellow")
|
||||
|
||||
local c_air = minetest.get_content_id("air")
|
||||
local c_ignore = minetest.get_content_id("ignore")
|
||||
|
||||
local vm, emin, emax = minetest.get_mapgen_object("voxelmanip")
|
||||
local data = vm:get_data()
|
||||
local a = VoxelArea:new({MinEdge = emin, MaxEdge = emax})
|
||||
local ystride = a.ystride
|
||||
|
||||
local chulens = vector.add(vector.subtract(maxp, minp), 1)
|
||||
local chulens_sup = {x = chulens.x, y = chulens.y + 6, z = chulens.z}
|
||||
local minp2d = pos2d(minp)
|
||||
|
||||
local t1 = os.clock()
|
||||
if vmg.loglevel >= 2 then
|
||||
print("[Valleys Mapgen] Mapgen preparation finished in " .. displaytime(t1-t0))
|
||||
print("[Valleys Mapgen] Calculating noises ...")
|
||||
end
|
||||
|
||||
local n1 = vmg.noisemap(1, minp2d, chulens)
|
||||
local n2 = vmg.noisemap(2, minp2d, chulens)
|
||||
local n3 = vmg.noisemap(3, minp2d, chulens)
|
||||
local n4 = vmg.noisemap(4, minp2d, chulens)
|
||||
local n5 = vmg.noisemap(5, minp2d, chulens)
|
||||
local n6 = vmg.noisemap(6, minp, chulens_sup)
|
||||
local n7 = vmg.noisemap(7, minp2d, chulens)
|
||||
local n8 = vmg.noisemap(8, minp, chulens)
|
||||
local n9 = vmg.noisemap(9, minp, chulens)
|
||||
local n10 = vmg.noisemap(10, minp, chulens)
|
||||
local n11 = vmg.noisemap(11, minp, chulens)
|
||||
local n12 = vmg.noisemap(12, minp, chulens)
|
||||
local n13 = vmg.noisemap(13, minp2d, chulens)
|
||||
local n14 = vmg.noisemap(14, minp2d, chulens)
|
||||
local n15 = vmg.noisemap(15, minp2d, chulens)
|
||||
local n16 = vmg.noisemap(16, minp2d, chulens)
|
||||
local n18 = vmg.noisemap(18, minp2d, chulens)
|
||||
|
||||
local t2 = os.clock()
|
||||
if vmg.loglevel >= 2 then
|
||||
print("[Valleys Mapgen] Noises calculation finished in " .. displaytime(t2-t1))
|
||||
print("[Valleys Mapgen] Collecting data ...")
|
||||
end
|
||||
|
||||
local i2d = 1 -- index for 2D noises
|
||||
local i3d_sup = 1 -- index for noise 6 which has a special size
|
||||
local i3d = 1 -- index for 3D noises
|
||||
|
||||
-- Calculate increments
|
||||
local i2d_incrZ = chulens.z
|
||||
local i2d_decrX = chulens.x * chulens.z - 1
|
||||
local i3d_incrY = chulens.y
|
||||
local i3d_sup_incrZ = 6 * chulens.y
|
||||
local i3d_decrX = chulens.x * chulens.y * chulens.z - 1
|
||||
local i3d_sup_decrX = chulens.x * (chulens.y + 6) * chulens.z - 1
|
||||
|
||||
for x = minp.x, maxp.x do -- for each YZ plane
|
||||
for z = minp.z, maxp.z do -- for each vertical line in this plane
|
||||
local v1, v2, v3, v4, v5, v7, v13, v14, v15, v16, v18 = n1[i2d], n2[i2d], n3[i2d], n4[i2d], n5[i2d], n7[i2d], n13[i2d], n14[i2d], n15[i2d], n16[i2d], n18[i2d] -- n for noise, v for value
|
||||
v3 = v3 ^ 2 -- v3 must be > 0 and by the square there are high mountains but the median valleys depth is small.
|
||||
local base_ground = v1 + v3 -- v3 is here because terrain is generally higher when valleys are deep (mountains)
|
||||
v2 = math.abs(v2) - river_size
|
||||
local river = v2 < 0
|
||||
local valleys = v3 * (1 - math.exp(- (v2 / v4) ^ 2)) -- use the curve of the function 1−exp(−(x/a)²) to modelise valleys. Making "a" varying 0 < a ≤ 1 will change the shape of the valleys. Try it with a geometry software ! (here x = v2 and a = v4)
|
||||
local mountain_ground = base_ground + valleys
|
||||
local slopes = v5 * valleys
|
||||
|
||||
if river then
|
||||
local depth = river_depth * math.sqrt(1 - (v2 / river_size + 1) ^ 2) -- use the curve of the function −sqrt(1-x²) which modelizes a circle.
|
||||
mountain_ground = math.min(math.max(base_ground - depth, water_level - 6), mountain_ground)
|
||||
slopes = 0
|
||||
end
|
||||
|
||||
-- Choose biome
|
||||
local dirt = c_dirt
|
||||
local lawn = c_lawn
|
||||
local snow = c_snow
|
||||
local max = math.max(v13, v14, v15) -- the biome is the maximal of these 3 values, if bigger than 0.5. Else, make normal dirt.
|
||||
if max > dirt_threshold then
|
||||
if v13 == max then
|
||||
if v13 > clay_threshold then
|
||||
dirt = c_clay
|
||||
lawn = c_clay
|
||||
snow = c_clay
|
||||
else
|
||||
dirt = c_dirt_clay
|
||||
lawn = c_lawn_clay
|
||||
snow = c_snow_clay
|
||||
end
|
||||
elseif v14 == max then
|
||||
if v14 > silt_threshold then
|
||||
dirt = c_silt
|
||||
lawn = c_silt
|
||||
snow = c_silt
|
||||
else
|
||||
dirt = c_dirt_silt
|
||||
lawn = c_lawn_silt
|
||||
snow = c_snow_silt
|
||||
end
|
||||
else
|
||||
if v15 > sand_threshold then
|
||||
dirt = c_desert_sand
|
||||
lawn = c_desert_sand
|
||||
snow = c_desert_sand
|
||||
else
|
||||
dirt = c_dirt_sand
|
||||
lawn = c_lawn_sand
|
||||
snow = c_snow_sand
|
||||
end
|
||||
end
|
||||
end
|
||||
local is_beach = v15 > 0 and v16 > 0
|
||||
local beach = v15 * v16 + water_level -- the y coordinate below which dirt is replaced by beach sand
|
||||
|
||||
-- raw humidity
|
||||
local hraw = 2 ^ (v13 - v15 + v18 * 2)
|
||||
|
||||
for y = minp.y, maxp.y do -- for each node in vertical line
|
||||
local ivm = a:index(x, y, z)
|
||||
local v6, v8, v9, v10, v11, v12 = n6[i3d_sup], n8[i3d], n9[i3d], n10[i3d], n11[i3d], n12[i3d]
|
||||
local is_cave = v8 ^ 2 + v9 ^ 2 + v10 ^ 2 + v11 ^ 2 < caves_size
|
||||
if v6 * slopes > y - mountain_ground then -- if pos is in the ground
|
||||
if not is_cave then
|
||||
local thickness = v7 - math.sqrt(math.abs(y)) / dirt_thickness
|
||||
local above = math.ceil(thickness + math.random()) -- The following code will look for air at this many nodes up. If any, make dirt, else, make stone. So, it's the dirt layer thickness.
|
||||
|
||||
if y >= water_level and n6[i3d_sup+i3d_incrY] * slopes <= y + 1 - mountain_ground and not river then
|
||||
if is_beach and y < beach then
|
||||
data[ivm] = c_sand
|
||||
else -- if node above is not in the ground, place lawn
|
||||
|
||||
-- calculate humidity
|
||||
local sea_water = 0.5 ^ math.max((y - water_level) / 6, 0)
|
||||
local river_water = 0.5 ^ math.max((y - base_ground) / 3, 0)
|
||||
local water = sea_water + (1 - sea_water) * river_water
|
||||
local humidity = hraw + water
|
||||
|
||||
local ivm2 = ivm + ystride
|
||||
y = y + 1
|
||||
local pos = {x = x, y = y, z = z}
|
||||
|
||||
local v17 = vmg.get_noise(pos, 17)
|
||||
local temp -- calculate_temperature for node above
|
||||
if y > 0 then
|
||||
temp = v17 * 0.5 ^ (y / altitude_chill)
|
||||
else
|
||||
temp = v17 * 0.5 ^ (-y / altitude_chill) + 20 * (v12 + 1) * (1 - 2 ^ (y / lava_depth))
|
||||
end
|
||||
|
||||
if temp > snow_threshold then
|
||||
if above > 0 then
|
||||
data[ivm] = lawn
|
||||
else
|
||||
data[ivm] = c_stone
|
||||
end
|
||||
else
|
||||
if above > 0 then
|
||||
data[ivm] = snow
|
||||
else
|
||||
data[ivm] = c_stone
|
||||
end
|
||||
data[ivm2] = c_snow_layer -- set node above to snow
|
||||
end
|
||||
|
||||
if trees and math.random() < tree_density and above > 0 then -- make a tree
|
||||
|
||||
-- choose a tree from climatic and geological conditions
|
||||
if v14 < 0 and temp < 1.5 and temp >= 0.90 and humidity < 1 and v15 < 0.8 and math.abs(v13) < 0.2 and math.random() < 0.3 then -- Pine Tree
|
||||
local rand = math.random()
|
||||
local height = math.floor(9 + 6 * rand)
|
||||
local radius = 4 + 2 * rand
|
||||
vmg.make_pine_tree(pos, data, a, height, radius, c_pinetree, c_pineleaves, c_air, c_ignore)
|
||||
elseif v15 < 0.6 and temp >= 0.85 and temp < 2.3 and humidity < 3 and v16 < 2 and v14 > -0.5 and v13 < 0.8 then -- Apple Tree
|
||||
local rand = math.random()
|
||||
local height = math.floor(4 + 2.5 * rand)
|
||||
local radius = 3 + rand
|
||||
if math.random(1, 4) == 1 then
|
||||
vmg.make_apple_tree(pos, data, a, height, radius, c_tree, c_leaves, c_apple, c_air, c_ignore)
|
||||
else
|
||||
vmg.make_tree(pos, data, a, height, radius, c_tree, c_leaves, c_air, c_ignore)
|
||||
end
|
||||
elseif v15 < 0.7 and temp >= 1.9 and humidity > 2 and v16 > 2 then -- Jungle Tree
|
||||
local rand = math.random()
|
||||
local height = math.floor(8 + 4 * rand)
|
||||
local radius = 5 + 3 * rand
|
||||
vmg.make_jungle_tree(pos, data, a, height, radius, c_jungletree, c_jungleleaves, c_air, c_ignore)
|
||||
elseif temp > 0.38 and temp < 1 and humidity > 0.9 and v15 > 0 and v15 < 0.55 then -- Fir Tree
|
||||
local rand = math.random()
|
||||
local height = math.floor(9 + 6 * rand)
|
||||
local radius = 4 + 2 * rand
|
||||
vmg.make_fir_tree(pos, data, a, height, radius, c_firtree, c_firleaves, c_air, c_ignore)
|
||||
end
|
||||
elseif plants and math.random() < plant_density and above > 0 then -- make a plant
|
||||
if temp > 1 and temp < 1.8 and water > 0.7 and humidity > 3 and v13 > -0.4 and math.random() < 0.04 then -- Papyrus
|
||||
for i = 1, 4 do
|
||||
data[ivm+i*ystride] = c_papyrus
|
||||
end
|
||||
elseif v15 < 0.65 and temp >= 0.65 and temp < 1.5 and humidity < 2.6 and v16 < 1.5 and v13 < 0.8 and math.random() < 0.7 then -- Grass
|
||||
data[ivm2] = c_grass[math.random(1, 5)]
|
||||
elseif v15 > -0.6 and temp >= 1.8 and humidity > 2.2 and v16 > 1.8 then -- Jungle Grass
|
||||
data[ivm2] = c_junglegrass
|
||||
elseif v15 > 0.65 and humidity < 0.5 and math.random() < 0.2 then
|
||||
if v16 > 0 and temp > 1.6 and math.random() < 0.12 then -- Cactus
|
||||
for i = 1, 4 do
|
||||
data[ivm+i*ystride] = c_cactus
|
||||
end
|
||||
elseif temp > 1.2 then -- Dry Shrub
|
||||
data[ivm2] = c_dryshrub
|
||||
end
|
||||
elseif math.random() < 0.04 and temp > 0.98 and temp < 1.8 and humidity < 1.7 and v14 >= -0.1 and v15 < 0.4 and v15 >= -0.6 and v13 < 0.82 then -- Flowers
|
||||
if temp > 1.2 and math.random() < 0.3 then
|
||||
data[ivm2] = c_rose
|
||||
elseif thickness <= 1.3 and math.random() < 0.4 then
|
||||
data[ivm2] = c_geranium
|
||||
elseif v16 < 1.6 and math.random() < 0.7 then
|
||||
data[ivm2] = c_viola
|
||||
elseif temp > 1.3 and humidity < 1.5 and math.random() < 0.2 then
|
||||
data[ivm2] = c_tulip
|
||||
elseif math.random() < 0.5 then
|
||||
data[ivm2] = c_dandelion_white
|
||||
else
|
||||
data[ivm2] = c_dandelion_yellow
|
||||
end
|
||||
end
|
||||
end
|
||||
y = y - 1
|
||||
end
|
||||
elseif above <= 0 then
|
||||
data[ivm] = c_stone
|
||||
elseif n6[i3d_sup+above*i3d_incrY] * slopes <= y + above - mountain_ground then -- if node at "above" nodes up is not in the ground, make dirt
|
||||
if is_beach and y < beach then
|
||||
data[ivm] = c_sand
|
||||
else
|
||||
data[ivm] = dirt
|
||||
end
|
||||
else
|
||||
data[ivm] = c_stone
|
||||
end
|
||||
elseif v11 + v12 > 2 ^ (y / lava_depth) and y <= lava_max_height then
|
||||
data[ivm] = c_lava
|
||||
end
|
||||
elseif y <= water_level then -- if pos is not in the ground, and below water_level, it's an ocean
|
||||
data[ivm] = c_water
|
||||
elseif river and y + 1 < base_ground then
|
||||
if river_water then
|
||||
data[ivm] = c_riverwater
|
||||
else
|
||||
data[ivm] = c_water
|
||||
end
|
||||
end
|
||||
|
||||
i3d = i3d + i3d_incrY -- increment i3d by one line
|
||||
i3d_sup = i3d_sup + i3d_incrY -- idem
|
||||
end
|
||||
i2d = i2d + i2d_incrZ -- increment i2d by one Z
|
||||
-- useless to increment i3d, because increment would be 0 !
|
||||
i3d_sup = i3d_sup + i3d_sup_incrZ -- for i3d_sup, just avoid the 6 supplemental lines
|
||||
end
|
||||
i2d = i2d - i2d_decrX -- decrement the Z line previously incremented and increment by one X (1)
|
||||
i3d = i3d - i3d_decrX -- decrement the YZ plane previously incremented and increment by one X (1)
|
||||
i3d_sup = i3d_sup - i3d_sup_decrX -- idem, including the supplemental lines
|
||||
end
|
||||
vmg.execute_after_mapgen() -- needed for jungletree roots
|
||||
|
||||
local t3 = os.clock()
|
||||
if vmg.loglevel >= 2 then
|
||||
print("[Valleys Mapgen] Data collecting finished in " .. displaytime(t3-t2))
|
||||
print("[Valleys Mapgen] Writing data ...")
|
||||
end
|
||||
|
||||
-- execute voxelmanip boring stuff to write to the map
|
||||
vm:set_data(data)
|
||||
minetest.generate_ores(vm, minp, maxp)
|
||||
vm:set_lighting({day = 0, night = 0})
|
||||
vm:calc_lighting()
|
||||
vm:update_liquids()
|
||||
vm:write_to_map()
|
||||
|
||||
local t4 = os.clock()
|
||||
if vmg.loglevel >= 2 then
|
||||
print("[Valleys Mapgen] Data writing finished in " .. displaytime(t4-t3))
|
||||
end
|
||||
if vmg.loglevel >= 1 then
|
||||
print("[Valleys Mapgen] Mapgen finished in " .. displaytime(t4-t0))
|
||||
end
|
||||
end
|
||||
|
||||
dofile(vmg.path .. "/trees.lua")
|
||||
|
||||
function vmg.get_humidity_raw(pos)
|
||||
local v13 = vmg.get_noise(pos, 13)
|
||||
local v15 = vmg.get_noise(pos, 15)
|
||||
local v18 = vmg.get_noise(pos, 18)
|
||||
return 2 ^ (v13 - v15 + v18 * 2)
|
||||
end
|
||||
|
||||
function vmg.get_humidity(pos)
|
||||
local y = pos.y
|
||||
local flatpos = pos2d(pos)
|
||||
local hraw = vmg.get_humidity_raw(flatpos)
|
||||
|
||||
local v1 = vmg.get_noise(flatpos, 1)
|
||||
local v3 = vmg.get_noise(flatpos, 3) ^ 2
|
||||
local base_ground = v1 + v3
|
||||
local sea_water = 0.5 ^ math.max((y - water_level) / 6, 0)
|
||||
local river_water = 0.5 ^ math.max((y - base_ground) / 3, 0)
|
||||
local water = sea_water + (1 - sea_water) * river_water
|
||||
return hraw + water
|
||||
end
|
||||
|
||||
function vmg.get_temperature(pos)
|
||||
local v12 = vmg.get_noise(pos, 12) + 1
|
||||
local v17 = vmg.get_noise(pos, 17)
|
||||
local y = pos.y
|
||||
if y > 0 then
|
||||
return v17 * 0.5 ^ (y / altitude_chill)
|
||||
else
|
||||
return v17 * 0.5 ^ (-y / altitude_chill) + 20 * v12 * (1 - 2 ^ (y / lava_depth))
|
||||
end
|
||||
end
|
||||
|
||||
function vmg.get_noise(pos, i)
|
||||
local n = vmg.noises[i]
|
||||
local noise = minetest.get_perlin(n.seed, n.octaves, n.persist, 1)
|
||||
if not pos.z then
|
||||
return noise:get2d({x = pos.x / n.spread.x, y = pos.y / n.spread.y}) * n.scale + n.offset
|
||||
else
|
||||
return noise:get3d({x = pos.x / n.spread.x, y = pos.y / n.spread.y, z = pos.z / n.spread.z}) * n.scale + n.offset
|
||||
end
|
||||
end
|
||||
|
||||
local function round(n)
|
||||
return math.floor(n + 0.5)
|
||||
end
|
||||
|
||||
function vmg.get_elevation(pos)
|
||||
local v1 = vmg.get_noise(pos, 1)
|
||||
local v2 = math.abs(vmg.get_noise(pos, 2)) - river_size
|
||||
local v3 = vmg.get_noise(pos, 3) ^ 2
|
||||
local base_ground = v1 + v3
|
||||
if v2 < 0 then
|
||||
return math.ceil(base_ground), true
|
||||
end
|
||||
local v4 = vmg.get_noise(pos, 4)
|
||||
local v5 = vmg.get_noise(pos, 5)
|
||||
local base_ground = v1 + v3
|
||||
local valleys = v3 * (1 - math.exp(- (v2 / v4) ^ 2))
|
||||
local mountain_ground = base_ground + valleys
|
||||
local pos = pos3d(pos, round(mountain_ground))
|
||||
local slopes = v5 * valleys
|
||||
if vmg.get_noise(pos, 6) * slopes > pos.y - mountain_ground then
|
||||
pos.y = pos.y + 1
|
||||
while vmg.get_noise(pos, 6) * slopes > pos.y - mountain_ground do
|
||||
pos.y = pos.y + 1
|
||||
end
|
||||
return pos.y, false
|
||||
else
|
||||
pos.y = pos.y - 1
|
||||
while vmg.get_noise(pos, 6) * slopes <= pos.y - mountain_ground do
|
||||
pos.y = pos.y - 1
|
||||
end
|
||||
return pos.y, false
|
||||
end
|
||||
end
|
||||
|
||||
function vmg.spawnplayer(player)
|
||||
local angle = math.random() * math.pi * 2
|
||||
local distance = math.random() * player_max_distance
|
||||
local p_angle = {x = math.cos(angle), y = math.sin(angle)}
|
||||
local pos = {x = -p_angle.x * distance, y = -p_angle.y * distance}
|
||||
local elevation, river = vmg.get_elevation(pos)
|
||||
while elevation < water_level + 2 or river do
|
||||
pos.x = pos.x + p_angle.x
|
||||
pos.y = pos.y + p_angle.y
|
||||
elevation, river = vmg.get_elevation({x = round(pos.x), y = round(pos.y)})
|
||||
end
|
||||
pos = {x = round(pos.x), y = round(elevation + 1), z = round(pos.y)}
|
||||
player:setpos(pos)
|
||||
return true
|
||||
end
|
|
@ -0,0 +1,192 @@
|
|||
local waterflow = vmg.define("waterflow", 3)
|
||||
|
||||
minetest.override_item("default:river_water_source", {liquid_range = waterflow})
|
||||
minetest.override_item("default:river_water_flowing", {liquid_range = waterflow})
|
||||
|
||||
minetest.register_node("valleys_mapgen:silt", {
|
||||
description = "Silt",
|
||||
tiles = {"vmg_silt.png"},
|
||||
is_ground_content = true,
|
||||
groups = {crumbly=3},
|
||||
sounds = default.node_sound_dirt_defaults(),
|
||||
})
|
||||
|
||||
minetest.register_node("valleys_mapgen:red_clay", {
|
||||
description = "Red Clay",
|
||||
tiles = {"vmg_red_clay.png"},
|
||||
is_ground_content = true,
|
||||
groups = {crumbly=3},
|
||||
sounds = default.node_sound_dirt_defaults(),
|
||||
})
|
||||
|
||||
minetest.override_item("default:clay", {description = "White Clay"})
|
||||
|
||||
local function register_dirts(readname)
|
||||
local name = readname:lower()
|
||||
local itemstr_dirt = "valleys_mapgen:dirt_" .. name
|
||||
local itemstr_lawn = itemstr_dirt .. "_with_grass"
|
||||
local itemstr_snow = itemstr_dirt .. "_with_snow"
|
||||
local tilestr = "vmg_dirt_" .. name .. ".png"
|
||||
|
||||
minetest.register_node(itemstr_dirt, {
|
||||
description = readname .. " Dirt",
|
||||
tiles = {tilestr},
|
||||
is_ground_content = true,
|
||||
groups = {crumbly=3,soil=1},
|
||||
sounds = default.node_sound_dirt_defaults(),
|
||||
})
|
||||
|
||||
minetest.register_node(itemstr_lawn, {
|
||||
description = readname .. " Dirt with Grass",
|
||||
tiles = {"default_grass.png", tilestr, tilestr .. "^default_grass_side.png"},
|
||||
is_ground_content = true,
|
||||
groups = {crumbly=3,soil=1},
|
||||
drop = itemstr_dirt,
|
||||
sounds = default.node_sound_dirt_defaults({
|
||||
footstep = {name="default_grass_footstep", gain=0.25},
|
||||
}),
|
||||
})
|
||||
|
||||
minetest.register_node(itemstr_snow, {
|
||||
description = readname .. " Dirt with Snow",
|
||||
tiles = {"default_snow.png", tilestr, tilestr .. "^default_snow_side.png"},
|
||||
is_ground_content = true,
|
||||
groups = {crumbly=3,soil=1},
|
||||
drop = itemstr_dirt,
|
||||
sounds = default.node_sound_dirt_defaults({
|
||||
footstep = {name="default_snow_footstep", gain=0.25},
|
||||
}),
|
||||
})
|
||||
|
||||
minetest.register_abm({
|
||||
nodenames = {itemstr_dirt},
|
||||
interval = 2,
|
||||
chance = 200,
|
||||
action = function(pos, node)
|
||||
local above = {x=pos.x, y=pos.y+1, z=pos.z}
|
||||
local name = minetest.get_node(above).name
|
||||
local nodedef = minetest.registered_nodes[name]
|
||||
if nodedef and (nodedef.sunlight_propagates or nodedef.paramtype == "light")
|
||||
and nodedef.liquidtype == "none"
|
||||
and (minetest.get_node_light(above) or 0) >= 13 then
|
||||
if name == "default:snow" or name == "default:snowblock" then
|
||||
minetest.set_node(pos, {name = itemstr_snow})
|
||||
else
|
||||
minetest.set_node(pos, {name = itemstr_lawn})
|
||||
end
|
||||
end
|
||||
end
|
||||
})
|
||||
|
||||
minetest.register_abm({
|
||||
nodenames = {itemstr_lawn},
|
||||
interval = 2,
|
||||
chance = 20,
|
||||
action = function(pos, node)
|
||||
local above = {x=pos.x, y=pos.y+1, z=pos.z}
|
||||
local name = minetest.get_node(above).name
|
||||
local nodedef = minetest.registered_nodes[name]
|
||||
if name ~= "ignore" and nodedef
|
||||
and not ((nodedef.sunlight_propagates or nodedef.paramtype == "light")
|
||||
and nodedef.liquidtype == "none") then
|
||||
minetest.set_node(pos, {name = itemstr_dirt})
|
||||
end
|
||||
end
|
||||
})
|
||||
end
|
||||
|
||||
register_dirts("Clayey")
|
||||
register_dirts("Silty")
|
||||
register_dirts("Sandy")
|
||||
|
||||
-----------
|
||||
-- Trees --
|
||||
-----------
|
||||
|
||||
minetest.register_node("valleys_mapgen:fir_tree", {
|
||||
description = "Fir Tree",
|
||||
tiles = {"vmg_fir_tree_top.png", "vmg_fir_tree_top.png", "vmg_fir_tree.png"},
|
||||
paramtype2 = "facedir",
|
||||
is_ground_content = false,
|
||||
groups = {tree=1,choppy=2,oddly_breakable_by_hand=1,flammable=2},
|
||||
sounds = default.node_sound_wood_defaults(),
|
||||
|
||||
on_place = minetest.rotate_node
|
||||
})
|
||||
|
||||
minetest.register_node("valleys_mapgen:fir_tree", {
|
||||
description = "Fir Tree",
|
||||
tiles = {"vmg_fir_tree_top.png", "vmg_fir_tree_top.png", "vmg_fir_tree.png"},
|
||||
paramtype2 = "facedir",
|
||||
is_ground_content = false,
|
||||
groups = {tree=1,choppy=2,oddly_breakable_by_hand=1,flammable=2},
|
||||
sounds = default.node_sound_wood_defaults(),
|
||||
|
||||
on_place = minetest.rotate_node
|
||||
})
|
||||
|
||||
minetest.register_node("valleys_mapgen:fir_sapling", {
|
||||
description = "Fir Sapling",
|
||||
drawtype = "plantlike",
|
||||
visual_scale = 1.0,
|
||||
tiles = {"vmg_fir_sapling.png"},
|
||||
inventory_image = "vmg_fir_sapling.png",
|
||||
wield_image = "vmg_fir_sapling.png",
|
||||
paramtype = "light",
|
||||
sunlight_propagates = true,
|
||||
walkable = false,
|
||||
selection_box = {
|
||||
type = "fixed",
|
||||
fixed = {-0.3, -0.5, -0.3, 0.3, 0.35, 0.3}
|
||||
},
|
||||
groups = {snappy=2,dig_immediate=3,flammable=2,attached_node=1,sapling=1},
|
||||
sounds = default.node_sound_leaves_defaults(),
|
||||
})
|
||||
|
||||
minetest.register_node("valleys_mapgen:fir_needles", {
|
||||
description = "Fir Needles",
|
||||
drawtype = "allfaces_optional",
|
||||
waving = 1,
|
||||
visual_scale = 1.3,
|
||||
tiles = {"vmg_fir_leaves.png"},
|
||||
paramtype = "light",
|
||||
is_ground_content = false,
|
||||
groups = {snappy=3, leafdecay=7, flammable=2, leaves=1},
|
||||
drop = {
|
||||
max_items = 1,
|
||||
items = {
|
||||
{
|
||||
-- player will get sapling with 1/20 chance
|
||||
items = {'valleys_mapgen:fir_sapling'},
|
||||
rarity = 20,
|
||||
},
|
||||
{
|
||||
-- player will get leaves only if he get no saplings,
|
||||
-- this is because max_items is 1
|
||||
items = {'valleys_mapgen:fir_needles'},
|
||||
}
|
||||
}
|
||||
},
|
||||
sounds = default.node_sound_leaves_defaults(),
|
||||
|
||||
after_place_node = default.after_place_leaves,
|
||||
})
|
||||
|
||||
minetest.register_node("valleys_mapgen:fir_wood", {
|
||||
description = "Fir Wood Planks",
|
||||
tiles = {"vmg_fir_wood.png"},
|
||||
is_ground_content = false,
|
||||
groups = {choppy=2,oddly_breakable_by_hand=2,flammable=3,wood=1},
|
||||
sounds = default.node_sound_wood_defaults(),
|
||||
})
|
||||
|
||||
minetest.register_craft({
|
||||
output = "valleys_mapgen:fir_wood 5",
|
||||
recipe = {
|
||||
{"valleys_mapgen:fir_tree"}
|
||||
}
|
||||
})
|
||||
|
||||
minetest.add_group("default:leaves", {leafdecay = 5})
|
||||
minetest.add_group("default:jungleleaves", {leafdecay = 8})
|
||||
minetest.add_group("default:pine_needles", {leafdecay = 7})
|
|
@ -0,0 +1,195 @@
|
|||
-- Mapgen 1.0
|
||||
-- Saturday March 7, 2015
|
||||
|
||||
vmg.noises = {
|
||||
|
||||
-- Noise 1 : Base Ground Height 2D
|
||||
{offset = -10, scale = 50, seed = 5202, spread = {x = 1024, y = 1024, z = 1024}, octaves = 6, persist = 0.4},
|
||||
|
||||
-- Noise 2 : Valleys (River where around zero) 2D
|
||||
{offset = 0, scale = 1, seed = -6050, spread = {x = 256, y = 256, z = 256}, octaves = 5, persist = 0.6},
|
||||
|
||||
-- Noise 3 : Valleys Depth 2D
|
||||
{offset = 5, scale = 4, seed = -1914, spread = {x = 512, y = 512, z = 512}, octaves = 1, persist = 1},
|
||||
|
||||
-- Noise 4 : Valleys Profile (Higher values = Larger valleys) 2D
|
||||
{offset = 0.5, scale = 0.5, seed = 777, spread = {x = 512, y = 512, z = 512}, octaves = 1, persist = 1},
|
||||
|
||||
-- Noise 5 : Inter-valleys slopes 2D
|
||||
{offset = 0.5, scale = 0.5, seed = 746, spread = {x = 128, y = 128, z = 128}, octaves = 1, persist = 1},
|
||||
|
||||
-- Noise 6 : Inter-valleys filling 3D
|
||||
{offset = 0, scale = 1, seed = 1993, spread = {x = 256, y = 512, z = 256}, octaves = 6, persist = 0.8},
|
||||
|
||||
-- Noise 7 : Dirt thickness 2D
|
||||
{offset = 1.75, scale = 3.25, seed = 1605, spread = {x = 256, y = 256, z = 256}, octaves = 1, persist = 1},
|
||||
|
||||
}
|
||||
|
||||
function vmg.generate(minp, maxp, seed)
|
||||
local minps, maxps = minetest.pos_to_string(minp), minetest.pos_to_string(maxp)
|
||||
if vmg.loglevel >= 2 then
|
||||
print("[Valleys Mapgen] Preparing to generate map from " .. minps .. " to " .. maxps .. " ...")
|
||||
elseif vmg.loglevel == 1 then
|
||||
print("[Valleys Mapgen] Generating map from " .. minps .. " to " .. maxps .. " ...")
|
||||
end
|
||||
local t0 = os.clock()
|
||||
|
||||
local c_dirt = minetest.get_content_id("default:dirt")
|
||||
local c_stone = minetest.get_content_id("default:stone")
|
||||
local c_lawn = minetest.get_content_id("default:dirt_with_grass")
|
||||
local c_water = minetest.get_content_id("default:water_source")
|
||||
local c_air = minetest.get_content_id("air")
|
||||
|
||||
local vm, emin, emax = minetest.get_mapgen_object("voxelmanip")
|
||||
local data = vm:get_data()
|
||||
local a = VoxelArea:new({MinEdge = emin, MaxEdge = emax})
|
||||
|
||||
local chulens = vector.add(vector.subtract(maxp, minp), 1)
|
||||
local chulens_sup = {x = chulens.x, y = chulens.y + 6, z = chulens.z}
|
||||
local minp2d = pos2d(minp)
|
||||
|
||||
local t1 = os.clock()
|
||||
if vmg.loglevel >= 2 then
|
||||
print("[Valleys Mapgen] Mapgen preparation finished in " .. displaytime(t1-t0))
|
||||
print("[Valleys Mapgen] Calculating noises ...")
|
||||
end
|
||||
|
||||
local n1 = minetest.get_perlin_map(vmg.noises[1], chulens):get2dMap_flat(minp2d)
|
||||
local n2 = minetest.get_perlin_map(vmg.noises[2], chulens):get2dMap_flat(minp2d)
|
||||
local n3 = minetest.get_perlin_map(vmg.noises[3], chulens):get2dMap_flat(minp2d)
|
||||
local n4 = minetest.get_perlin_map(vmg.noises[4], chulens):get2dMap_flat(minp2d)
|
||||
local n5 = minetest.get_perlin_map(vmg.noises[5], chulens):get2dMap_flat(minp2d)
|
||||
local n6 = minetest.get_perlin_map(vmg.noises[6], chulens_sup):get3dMap_flat(minp)
|
||||
local n7 = minetest.get_perlin_map(vmg.noises[7], chulens):get2dMap_flat(minp2d)
|
||||
|
||||
local t2 = os.clock()
|
||||
if vmg.loglevel >= 2 then
|
||||
print("[Valleys Mapgen] Noises calculation finished in " .. displaytime(t2-t1))
|
||||
print("[Valleys Mapgen] Collecting data ...")
|
||||
end
|
||||
|
||||
local i2d = 1 -- index for 2D noises
|
||||
local i3d = 1 -- index for 3D noises
|
||||
for x = minp.x, maxp.x do -- for each east-west and bottom-top plane
|
||||
for z = minp.z, maxp.z do -- for each vertical row in this plane
|
||||
local v1, v2, v3, v4, v5, v7 = n1[i2d], n2[i2d], n3[i2d], n4[i2d], n5[i2d], n7[i2d] -- n for noise, v for value
|
||||
v3 = v3 ^ 2 -- v3 must be > 0 and by the square there are high mountains but the median valleys depth is small.
|
||||
local base_ground = v1 + v3 -- v3 is here because terrain is generally higher when valleys are deep (mountains)
|
||||
local river = math.abs(v2) < 0.05
|
||||
local valleys = v3 * (1 - math.exp(- (v2 / v4) ^ 2)) -- use the curve of the function 1−exp(−(x/a)²) to modelise valleys. Making "a" varying 0 < a ≤ 1 will change the shape of the valleys. v2 = x and v4 = a.
|
||||
local mountain_ground = base_ground + valleys
|
||||
local slopes = v5 * valleys
|
||||
if river then
|
||||
mountain_ground = math.min(math.max(base_ground - 3, -5), mountain_ground)
|
||||
slopes = 0
|
||||
end
|
||||
for y = minp.y, maxp.y do -- for each node in vertical row
|
||||
local ivm = a:index(x, y, z)
|
||||
local v6 = n6[i3d]
|
||||
if v6 * slopes > y - mountain_ground then -- if pos is in the ground
|
||||
local above = math.ceil(v7 + math.random())
|
||||
if above <= 0 then
|
||||
data[ivm] = c_stone
|
||||
elseif y > 0 and n6[i3d+80] * slopes <= y + 1 - mountain_ground and not river then
|
||||
data[ivm] = c_lawn -- if node above is not in the ground, place lawn
|
||||
elseif n6[i3d+above*80] * slopes <= y + above - mountain_ground then
|
||||
data[ivm] = c_dirt
|
||||
else
|
||||
data[ivm] = c_stone
|
||||
end
|
||||
elseif y <= 1 or river and y - 2 <= mountain_ground then
|
||||
data[ivm] = c_water
|
||||
end
|
||||
|
||||
i3d = i3d + 80 -- increase i3d by one row
|
||||
end
|
||||
i2d = i2d + 80 -- increase i2d by one row
|
||||
i3d = i3d + 480 -- avoid the 6 supplemental lines
|
||||
end
|
||||
i2d = i2d - 6399 -- i2d = 6401 after the first execution of this loop, it must be 2 before the second.
|
||||
i3d = i3d - 550399 -- i3d = 550401 after the first execution of this loop, it must be 2 before the second.
|
||||
end
|
||||
|
||||
local t3 = os.clock()
|
||||
if vmg.loglevel >= 2 then
|
||||
print("[Valleys Mapgen] Data collecting finished in " .. displaytime(t3-t2))
|
||||
print("[Valleys Mapgen] Writing data ...")
|
||||
end
|
||||
|
||||
-- execute voxelmanip boring stuff to write to the map
|
||||
vm:set_data(data)
|
||||
vm:calc_lighting()
|
||||
vm:update_liquids()
|
||||
minetest.generate_ores(vm) -- Thank you kwolekr ! I can generate the ores in 1 line ! And so it's compatible with moreores and other mods which add ores.
|
||||
vm:write_to_map()
|
||||
|
||||
local t4 = os.clock()
|
||||
if vmg.loglevel >= 2 then
|
||||
print("[Valleys Mapgen] Data writing finished in " .. displaytime(t4-t3))
|
||||
end
|
||||
if vmg.loglevel >= 1 then
|
||||
print("[Valleys Mapgen] Mapgen finished in " .. displaytime(t4-t0))
|
||||
end
|
||||
end
|
||||
|
||||
vmg.noises_obj = {}
|
||||
|
||||
for i, n in ipairs(vmg.noises) do
|
||||
vmg.noises_obj[i] = minetest.get_perlin(n.seed, n.octaves, n.persist, 1)
|
||||
end
|
||||
|
||||
function vmg.get_noise(pos, i)
|
||||
local n = vmg.noises[i]
|
||||
local noise = minetest.get_perlin(n.seed, n.octaves, n.persist, 1)
|
||||
if not pos.z then
|
||||
return noise:get2d({x = pos.x / n.spread.x, y = pos.y / n.spread.y}) * n.scale + n.offset
|
||||
else
|
||||
return noise:get3d({x = pos.x / n.spread.x, y = pos.y / n.spread.y, z = pos.z / n.spread.z}) * n.scale + n.offset
|
||||
end
|
||||
end
|
||||
|
||||
local function round(n)
|
||||
return math.floor(n + 0.5)
|
||||
end
|
||||
|
||||
function vmg.get_elevation(pos)
|
||||
local v1 = vmg.get_noise(pos, 1)
|
||||
local v2 = vmg.get_noise(pos, 2)
|
||||
local v3 = vmg.get_noise(pos, 3) ^ 2
|
||||
local v4 = vmg.get_noise(pos, 4)
|
||||
local v5 = vmg.get_noise(pos, 5)
|
||||
local base_ground = v1 + v3
|
||||
local valleys = v3 * (1 - math.exp(- (v2 / v4) ^ 2))
|
||||
local mountain_ground = base_ground + valleys
|
||||
local pos = pos3d(pos, round(mountain_ground))
|
||||
local slopes = v5 * valleys
|
||||
if vmg.get_noise(pos, 6) * slopes > pos.y - mountain_ground then
|
||||
pos.y = pos.y + 1
|
||||
while vmg.get_noise(pos, 6) * slopes > pos.y - mountain_ground do
|
||||
pos.y = pos.y + 1
|
||||
end
|
||||
return pos.y
|
||||
else
|
||||
pos.y = pos.y - 1
|
||||
while vmg.get_noise(pos, 6) * slopes <= pos.y - mountain_ground do
|
||||
pos.y = pos.y - 1
|
||||
end
|
||||
return pos.y
|
||||
end
|
||||
end
|
||||
|
||||
function vmg.spawnplayer(player)
|
||||
local pos = {x = 0, y = 0}
|
||||
local angle = math.random() * math.pi * 2
|
||||
local p_angle = {x = math.cos(angle), y = math.sin(angle)}
|
||||
local elevation = vmg.get_elevation(pos)
|
||||
while elevation < 2 do
|
||||
pos.x = pos.x + p_angle.x
|
||||
pos.y = pos.y + p_angle.y
|
||||
elevation = vmg.get_elevation({x = round(pos.x), y = round(pos.y)})
|
||||
end
|
||||
pos = {x = round(pos.x), y = round(elevation + 1), z = round(pos.y)}
|
||||
player:setpos(pos)
|
||||
return true
|
||||
end
|
|
@ -0,0 +1,222 @@
|
|||
-- Mapgen 1.1
|
||||
-- Sunday March 8, 2015
|
||||
|
||||
vmg.noises = {
|
||||
|
||||
-- Noise 1 : Base Ground Height 2D
|
||||
{offset = -10, scale = 50, seed = 5202, spread = {x = 1024, y = 1024, z = 1024}, octaves = 6, persist = 0.4},
|
||||
|
||||
-- Noise 2 : Valleys (River where around zero) 2D
|
||||
{offset = 0, scale = 1, seed = -6050, spread = {x = 256, y = 256, z = 256}, octaves = 5, persist = 0.6},
|
||||
|
||||
-- Noise 3 : Valleys Depth 2D
|
||||
{offset = 5, scale = 4, seed = -1914, spread = {x = 512, y = 512, z = 512}, octaves = 1, persist = 1},
|
||||
|
||||
-- Noise 4 : Valleys Profile (Higher values = Larger valleys) 2D
|
||||
{offset = 0.5, scale = 0.5, seed = 777, spread = {x = 512, y = 512, z = 512}, octaves = 1, persist = 1},
|
||||
|
||||
-- Noise 5 : Inter-valleys slopes 2D
|
||||
{offset = 0.5, scale = 0.5, seed = 746, spread = {x = 128, y = 128, z = 128}, octaves = 1, persist = 1},
|
||||
|
||||
-- Noise 6 : Inter-valleys filling 3D
|
||||
{offset = 0, scale = 1, seed = 1993, spread = {x = 256, y = 512, z = 256}, octaves = 6, persist = 0.8},
|
||||
|
||||
-- Noise 7 : Dirt thickness 2D
|
||||
{offset = 3, scale = 2, seed = 1605, spread = {x = 256, y = 256, z = 256}, octaves = 3, persist = 0.5},
|
||||
|
||||
-- Noise 8 : Caves I
|
||||
{offset = 0, scale = 1, seed = -4640, spread = {x = 32, y = 32, z = 32}, octaves = 4, persist = 0.5},
|
||||
|
||||
-- Noise 9 : Caves II
|
||||
{offset = 0, scale = 1, seed = 8804, spread = {x = 32, y = 32, z = 32}, octaves = 4, persist = 0.5},
|
||||
|
||||
-- Noise 10 : Caves III
|
||||
{offset = 0, scale = 1, seed = -4780, spread = {x = 32, y = 32, z = 32}, octaves = 4, persist = 0.5},
|
||||
|
||||
-- Noise 11 : Caves IV
|
||||
{offset = 0, scale = 1, seed = -9969, spread = {x = 32, y = 32, z = 32}, octaves = 4, persist = 0.5},
|
||||
|
||||
}
|
||||
|
||||
function vmg.generate(minp, maxp, seed)
|
||||
local minps, maxps = minetest.pos_to_string(minp), minetest.pos_to_string(maxp)
|
||||
if vmg.loglevel >= 2 then
|
||||
print("[Valleys Mapgen] Preparing to generate map from " .. minps .. " to " .. maxps .. " ...")
|
||||
elseif vmg.loglevel == 1 then
|
||||
print("[Valleys Mapgen] Generating map from " .. minps .. " to " .. maxps .. " ...")
|
||||
end
|
||||
local t0 = os.clock()
|
||||
|
||||
local c_dirt = minetest.get_content_id("default:dirt")
|
||||
local c_stone = minetest.get_content_id("default:stone")
|
||||
local c_lawn = minetest.get_content_id("default:dirt_with_grass")
|
||||
local c_water = minetest.get_content_id("default:water_source")
|
||||
local c_air = minetest.get_content_id("air")
|
||||
|
||||
local vm, emin, emax = minetest.get_mapgen_object("voxelmanip")
|
||||
local data = vm:get_data()
|
||||
local a = VoxelArea:new({MinEdge = emin, MaxEdge = emax})
|
||||
|
||||
local chulens = vector.add(vector.subtract(maxp, minp), 1)
|
||||
local chulens_sup = {x = chulens.x, y = chulens.y + 6, z = chulens.z}
|
||||
local minp2d = pos2d(minp)
|
||||
|
||||
local t1 = os.clock()
|
||||
if vmg.loglevel >= 2 then
|
||||
print("[Valleys Mapgen] Mapgen preparation finished in " .. displaytime(t1-t0))
|
||||
print("[Valleys Mapgen] Calculating noises ...")
|
||||
end
|
||||
|
||||
local n1 = minetest.get_perlin_map(vmg.noises[1], chulens):get2dMap_flat(minp2d)
|
||||
local n2 = minetest.get_perlin_map(vmg.noises[2], chulens):get2dMap_flat(minp2d)
|
||||
local n3 = minetest.get_perlin_map(vmg.noises[3], chulens):get2dMap_flat(minp2d)
|
||||
local n4 = minetest.get_perlin_map(vmg.noises[4], chulens):get2dMap_flat(minp2d)
|
||||
local n5 = minetest.get_perlin_map(vmg.noises[5], chulens):get2dMap_flat(minp2d)
|
||||
local n6 = minetest.get_perlin_map(vmg.noises[6], chulens_sup):get3dMap_flat(minp)
|
||||
local n7 = minetest.get_perlin_map(vmg.noises[7], chulens):get2dMap_flat(minp2d)
|
||||
local n8 = minetest.get_perlin_map(vmg.noises[8], chulens):get3dMap_flat(minp)
|
||||
local n9 = minetest.get_perlin_map(vmg.noises[9], chulens):get3dMap_flat(minp)
|
||||
local n10 = minetest.get_perlin_map(vmg.noises[10], chulens):get3dMap_flat(minp)
|
||||
local n11 = minetest.get_perlin_map(vmg.noises[11], chulens):get3dMap_flat(minp)
|
||||
|
||||
local t2 = os.clock()
|
||||
if vmg.loglevel >= 2 then
|
||||
print("[Valleys Mapgen] Noises calculation finished in " .. displaytime(t2-t1))
|
||||
print("[Valleys Mapgen] Collecting data ...")
|
||||
end
|
||||
|
||||
local i2d = 1 -- index for 2D noises
|
||||
local i3d_a = 1 -- index for noise 6 which has a special size
|
||||
local i3d_b = 1 -- index for 3D noises
|
||||
for x = minp.x, maxp.x do -- for each east-west and bottom-top plane
|
||||
for z = minp.z, maxp.z do -- for each vertical row in this plane
|
||||
local v1, v2, v3, v4, v5, v7 = n1[i2d], n2[i2d], n3[i2d], n4[i2d], n5[i2d], n7[i2d] -- n for noise, v for value
|
||||
v3 = v3 ^ 2 -- v3 must be > 0 and by the square there are high mountains but the median valleys depth is small.
|
||||
local base_ground = v1 + v3 -- v3 is here because terrain is generally higher when valleys are deep (mountains)
|
||||
local river = math.abs(v2) < 0.05
|
||||
local valleys = v3 * (1 - math.exp(- (v2 / v4) ^ 2)) -- use the curve of the function 1−exp(−(x/a)²) to modelise valleys. Making "a" varying 0 < a ≤ 1 will change the shape of the valleys. v2 = x and v4 = a.
|
||||
local mountain_ground = base_ground + valleys
|
||||
local slopes = v5 * valleys
|
||||
if river then
|
||||
mountain_ground = math.min(math.max(base_ground - 3, -5), mountain_ground)
|
||||
slopes = 0
|
||||
end
|
||||
for y = minp.y, maxp.y do -- for each node in vertical row
|
||||
local ivm = a:index(x, y, z)
|
||||
local v6, v8, v9, v10, v11 = n6[i3d_a], n8[i3d_b], n9[i3d_b], n10[i3d_b], n11[i3d_b]
|
||||
local is_cave = v8 ^ 2 + v9 ^ 2 + v10 ^ 2 + v11 ^ 2 < 0.07
|
||||
if v6 * slopes > y - mountain_ground then -- if pos is in the ground
|
||||
if not is_cave then
|
||||
local above = math.ceil(v7 + math.random() - math.sqrt(math.abs(y)) / 3.5)
|
||||
if above <= 0 then
|
||||
data[ivm] = c_stone
|
||||
elseif y > 0 and n6[i3d_a+80] * slopes <= y + 1 - mountain_ground and not river then
|
||||
data[ivm] = c_lawn -- if node above is not in the ground, place lawn
|
||||
elseif n6[i3d_a+above*80] * slopes <= y + above - mountain_ground then
|
||||
data[ivm] = c_dirt
|
||||
else
|
||||
data[ivm] = c_stone
|
||||
end
|
||||
end
|
||||
elseif y <= 1 or river and y - 2 <= mountain_ground then
|
||||
data[ivm] = c_water
|
||||
end
|
||||
|
||||
i3d_a = i3d_a + 80 -- increase i3d_a by one row
|
||||
i3d_b = i3d_b + 80 -- increase i3d_b by one row
|
||||
end
|
||||
i2d = i2d + 80 -- increase i2d by one row
|
||||
i3d_a = i3d_a + 480 -- avoid the 6 supplemental lines
|
||||
end
|
||||
i2d = i2d - 6399 -- i2d = 6401 after the first execution of this loop, it must be 2 before the second.
|
||||
i3d_a = i3d_a - 550399 -- i3d_a = 550401 after the first execution of this loop, it must be 2 before the second.
|
||||
i3d_b = i3d_b - 511999 -- i3d_b = 512001 after the first execution of this loop, it must be 2 before the second.
|
||||
end
|
||||
|
||||
local t3 = os.clock()
|
||||
if vmg.loglevel >= 2 then
|
||||
print("[Valleys Mapgen] Data collecting finished in " .. displaytime(t3-t2))
|
||||
print("[Valleys Mapgen] Writing data ...")
|
||||
end
|
||||
|
||||
-- execute voxelmanip boring stuff to write to the map
|
||||
vm:set_data(data)
|
||||
vm:set_lighting({day = 0, night = 0})
|
||||
vm:calc_lighting()
|
||||
vm:update_liquids()
|
||||
vm:write_to_map()
|
||||
|
||||
vm = minetest.get_voxel_manip()
|
||||
vm:read_from_map(minp, maxp)
|
||||
minetest.generate_ores(vm) -- Thank you kwolekr ! I can generate the ores in 1 line ! And so it's compatible with moreores and other mods which add ores.
|
||||
vm:write_to_map()
|
||||
|
||||
local t4 = os.clock()
|
||||
if vmg.loglevel >= 2 then
|
||||
print("[Valleys Mapgen] Data writing finished in " .. displaytime(t4-t3))
|
||||
end
|
||||
if vmg.loglevel >= 1 then
|
||||
print("[Valleys Mapgen] Mapgen finished in " .. displaytime(t4-t0))
|
||||
end
|
||||
end
|
||||
|
||||
vmg.noises_obj = {}
|
||||
|
||||
for i, n in ipairs(vmg.noises) do
|
||||
vmg.noises_obj[i] = minetest.get_perlin(n.seed, n.octaves, n.persist, 1)
|
||||
end
|
||||
|
||||
function vmg.get_noise(pos, i)
|
||||
local n = vmg.noises[i]
|
||||
local noise = minetest.get_perlin(n.seed, n.octaves, n.persist, 1)
|
||||
if not pos.z then
|
||||
return noise:get2d({x = pos.x / n.spread.x, y = pos.y / n.spread.y}) * n.scale + n.offset
|
||||
else
|
||||
return noise:get3d({x = pos.x / n.spread.x, y = pos.y / n.spread.y, z = pos.z / n.spread.z}) * n.scale + n.offset
|
||||
end
|
||||
end
|
||||
|
||||
local function round(n)
|
||||
return math.floor(n + 0.5)
|
||||
end
|
||||
|
||||
function vmg.get_elevation(pos)
|
||||
local v1 = vmg.get_noise(pos, 1)
|
||||
local v2 = vmg.get_noise(pos, 2)
|
||||
local v3 = vmg.get_noise(pos, 3) ^ 2
|
||||
local v4 = vmg.get_noise(pos, 4)
|
||||
local v5 = vmg.get_noise(pos, 5)
|
||||
local base_ground = v1 + v3
|
||||
local valleys = v3 * (1 - math.exp(- (v2 / v4) ^ 2))
|
||||
local mountain_ground = base_ground + valleys
|
||||
local pos = pos3d(pos, round(mountain_ground))
|
||||
local slopes = v5 * valleys
|
||||
if vmg.get_noise(pos, 6) * slopes > pos.y - mountain_ground then
|
||||
pos.y = pos.y + 1
|
||||
while vmg.get_noise(pos, 6) * slopes > pos.y - mountain_ground do
|
||||
pos.y = pos.y + 1
|
||||
end
|
||||
return pos.y
|
||||
else
|
||||
pos.y = pos.y - 1
|
||||
while vmg.get_noise(pos, 6) * slopes <= pos.y - mountain_ground do
|
||||
pos.y = pos.y - 1
|
||||
end
|
||||
return pos.y
|
||||
end
|
||||
end
|
||||
|
||||
function vmg.spawnplayer(player)
|
||||
local pos = {x = 0, y = 0}
|
||||
local angle = math.random() * math.pi * 2
|
||||
local p_angle = {x = math.cos(angle), y = math.sin(angle)}
|
||||
local elevation = vmg.get_elevation(pos)
|
||||
while elevation < 2 do
|
||||
pos.x = pos.x + p_angle.x
|
||||
pos.y = pos.y + p_angle.y
|
||||
elevation = vmg.get_elevation({x = round(pos.x), y = round(pos.y)})
|
||||
end
|
||||
pos = {x = round(pos.x), y = round(elevation + 1), z = round(pos.y)}
|
||||
player:setpos(pos)
|
||||
return true
|
||||
end
|
|
@ -0,0 +1,251 @@
|
|||
-- Mapgen 1.2
|
||||
-- Tuesday March 17, 2015
|
||||
|
||||
vmg.noises = {
|
||||
|
||||
-- Noise 1 : Base Ground Height 2D
|
||||
{offset = -10, scale = 50, seed = 5202, spread = {x = 1024, y = 1024, z = 1024}, octaves = 6, persist = 0.4, lacunarity = 2},
|
||||
|
||||
-- Noise 2 : Valleys (River where around zero) 2D
|
||||
{offset = 0, scale = 1, seed = -6050, spread = {x = 256, y = 256, z = 256}, octaves = 5, persist = 0.6, lacunarity = 2},
|
||||
|
||||
-- Noise 3 : Valleys Depth 2D
|
||||
{offset = 5, scale = 4, seed = -1914, spread = {x = 512, y = 512, z = 512}, octaves = 1, persist = 1, lacunarity = 2},
|
||||
|
||||
-- Noise 4 : Valleys Profile (Higher values = Larger valleys) 2D
|
||||
{offset = 0.6, scale = 0.5, seed = 777, spread = {x = 512, y = 512, z = 512}, octaves = 1, persist = 1, lacunarity = 2},
|
||||
|
||||
-- Noise 5 : Inter-valleys slopes 2D
|
||||
{offset = 0.5, scale = 0.5, seed = 746, spread = {x = 128, y = 128, z = 128}, octaves = 1, persist = 1, lacunarity = 2},
|
||||
|
||||
-- Noise 6 : Inter-valleys filling 3D
|
||||
{offset = 0, scale = 1, seed = 1993, spread = {x = 256, y = 512, z = 256}, octaves = 6, persist = 0.8, lacunarity = 2},
|
||||
|
||||
-- Noise 7 : Dirt thickness 2D
|
||||
{offset = 3, scale = 1.75, seed = 1605, spread = {x = 256, y = 256, z = 256}, octaves = 3, persist = 0.5, lacunarity = 2},
|
||||
|
||||
-- Noise 8 : Caves I 3D
|
||||
{offset = 0, scale = 1, seed = -4640, spread = {x = 32, y = 32, z = 32}, octaves = 4, persist = 0.5, lacunarity = 2},
|
||||
|
||||
-- Noise 9 : Caves II 3D
|
||||
{offset = 0, scale = 1, seed = 8804, spread = {x = 32, y = 32, z = 32}, octaves = 4, persist = 0.5, lacunarity = 2},
|
||||
|
||||
-- Noise 10 : Caves III 3D
|
||||
{offset = 0, scale = 1, seed = -4780, spread = {x = 32, y = 32, z = 32}, octaves = 4, persist = 0.5, lacunarity = 2},
|
||||
|
||||
-- Noise 11 : Caves IV and Lava I 3D
|
||||
{offset = 0, scale = 1, seed = -9969, spread = {x = 32, y = 32, z = 32}, octaves = 4, persist = 0.5, lacunarity = 2},
|
||||
|
||||
-- Noise 12 : Lava II 3D
|
||||
{offset = 0, scale = 1, seed = 3314, spread = {x = 64, y = 64, z = 64}, octaves = 4, persist = 0.5, lacunarity = 2},
|
||||
|
||||
}
|
||||
|
||||
function vmg.noisemap(i, minp, chulens)
|
||||
local obj = minetest.get_perlin_map(vmg.noises[i], chulens)
|
||||
if minp.z then
|
||||
return obj:get3dMap_flat(minp)
|
||||
else
|
||||
return obj:get2dMap_flat(minp)
|
||||
end
|
||||
end
|
||||
|
||||
for i, n in ipairs(vmg.noises) do
|
||||
vmg.noises[i] = vmg.define("noise_" .. i, n)
|
||||
end
|
||||
|
||||
local average_stone_level = vmg.define("average_stone_level", 180)
|
||||
local dirt_thickness = math.sqrt(average_stone_level) / (vmg.noises[7].offset + 0.5)
|
||||
|
||||
local river_size = vmg.define("river_size", 5) / 100
|
||||
local caves_size = vmg.define("caves_size", 7) / 100
|
||||
local lava_depth = vmg.define("lava_depth", 2000)
|
||||
local surface_lava = vmg.define("surface_lava", false)
|
||||
|
||||
local player_max_distance = vmg.define("player_max_distance", 450)
|
||||
|
||||
function vmg.generate(minp, maxp, seed)
|
||||
local minps, maxps = minetest.pos_to_string(minp), minetest.pos_to_string(maxp)
|
||||
if vmg.loglevel >= 2 then
|
||||
print("[Valleys Mapgen] Preparing to generate map from " .. minps .. " to " .. maxps .. " ...")
|
||||
elseif vmg.loglevel == 1 then
|
||||
print("[Valleys Mapgen] Generating map from " .. minps .. " to " .. maxps .. " ...")
|
||||
end
|
||||
local t0 = os.clock()
|
||||
|
||||
local c_dirt = minetest.get_content_id("default:dirt")
|
||||
local c_stone = minetest.get_content_id("default:stone")
|
||||
local c_lawn = minetest.get_content_id("default:dirt_with_grass")
|
||||
local c_water = minetest.get_content_id("default:water_source")
|
||||
local c_lava = minetest.get_content_id("default:lava_source")
|
||||
local c_air = minetest.get_content_id("air")
|
||||
|
||||
local vm, emin, emax = minetest.get_mapgen_object("voxelmanip")
|
||||
local data = vm:get_data()
|
||||
local a = VoxelArea:new({MinEdge = emin, MaxEdge = emax})
|
||||
|
||||
local chulens = vector.add(vector.subtract(maxp, minp), 1)
|
||||
local chulens_sup = {x = chulens.x, y = chulens.y + 6, z = chulens.z}
|
||||
local minp2d = pos2d(minp)
|
||||
|
||||
local t1 = os.clock()
|
||||
if vmg.loglevel >= 2 then
|
||||
print("[Valleys Mapgen] Mapgen preparation finished in " .. displaytime(t1-t0))
|
||||
print("[Valleys Mapgen] Calculating noises ...")
|
||||
end
|
||||
|
||||
local n1 = vmg.noisemap(1, minp2d, chulens)
|
||||
local n2 = vmg.noisemap(2, minp2d, chulens)
|
||||
local n3 = vmg.noisemap(3, minp2d, chulens)
|
||||
local n4 = vmg.noisemap(4, minp2d, chulens)
|
||||
local n5 = vmg.noisemap(5, minp2d, chulens)
|
||||
local n6 = vmg.noisemap(6, minp, chulens_sup)
|
||||
local n7 = vmg.noisemap(7, minp2d, chulens)
|
||||
local n8 = vmg.noisemap(8, minp, chulens)
|
||||
local n9 = vmg.noisemap(9, minp, chulens)
|
||||
local n10 = vmg.noisemap(10, minp, chulens)
|
||||
local n11 = vmg.noisemap(11, minp, chulens)
|
||||
local n12 = vmg.noisemap(12, minp, chulens)
|
||||
|
||||
local t2 = os.clock()
|
||||
if vmg.loglevel >= 2 then
|
||||
print("[Valleys Mapgen] Noises calculation finished in " .. displaytime(t2-t1))
|
||||
print("[Valleys Mapgen] Collecting data ...")
|
||||
end
|
||||
|
||||
local i2d = 1 -- index for 2D noises
|
||||
local i3d_a = 1 -- index for noise 6 which has a special size
|
||||
local i3d_b = 1 -- index for 3D noises
|
||||
for x = minp.x, maxp.x do -- for each east-west and bottom-top plane
|
||||
for z = minp.z, maxp.z do -- for each vertical row in this plane
|
||||
local v1, v2, v3, v4, v5, v7 = n1[i2d], n2[i2d], n3[i2d], n4[i2d], n5[i2d], n7[i2d] -- n for noise, v for value
|
||||
v3 = v3 ^ 2 -- v3 must be > 0 and by the square there are high mountains but the median valleys depth is small.
|
||||
local base_ground = v1 + v3 -- v3 is here because terrain is generally higher when valleys are deep (mountains)
|
||||
local river = math.abs(v2) < river_size
|
||||
local valleys = v3 * (1 - math.exp(- (v2 / v4) ^ 2)) -- use the curve of the function 1−exp(−(x/a)²) to modelise valleys. Making "a" varying 0 < a ≤ 1 will change the shape of the valleys. v2 = x and v4 = a.
|
||||
local mountain_ground = base_ground + valleys
|
||||
local slopes = v5 * valleys
|
||||
if river then
|
||||
mountain_ground = math.min(math.max(base_ground - 3, -5), mountain_ground)
|
||||
slopes = 0
|
||||
end
|
||||
for y = minp.y, maxp.y do -- for each node in vertical row
|
||||
local ivm = a:index(x, y, z)
|
||||
local v6, v8, v9, v10, v11, v12 = n6[i3d_a], n8[i3d_b], n9[i3d_b], n10[i3d_b], n11[i3d_b], n12[i3d_b]
|
||||
local is_cave = v8 ^ 2 + v9 ^ 2 + v10 ^ 2 + v11 ^ 2 < caves_size
|
||||
if v6 * slopes > y - mountain_ground then -- if pos is in the ground
|
||||
if not is_cave then
|
||||
local above = math.ceil(
|
||||
v7 + math.random() - math.sqrt(math.abs(y)) / dirt_thickness
|
||||
)
|
||||
if above <= 0 then
|
||||
data[ivm] = c_stone
|
||||
elseif y > 0 and n6[i3d_a+80] * slopes <= y + 1 - mountain_ground and not river then
|
||||
data[ivm] = c_lawn -- if node above is not in the ground, place lawn
|
||||
elseif n6[i3d_a+above*80] * slopes <= y + above - mountain_ground then
|
||||
data[ivm] = c_dirt
|
||||
else
|
||||
data[ivm] = c_stone
|
||||
end
|
||||
elseif v11 + v12 > 2 ^ (y / lava_depth) and (surface_lava or y < 0) then
|
||||
data[ivm] = c_lava
|
||||
end
|
||||
elseif y <= 1 or river and y - 2 <= mountain_ground then
|
||||
data[ivm] = c_water
|
||||
end
|
||||
|
||||
i3d_a = i3d_a + 80 -- increase i3d_a by one row
|
||||
i3d_b = i3d_b + 80 -- increase i3d_b by one row
|
||||
end
|
||||
i2d = i2d + 80 -- increase i2d by one row
|
||||
i3d_a = i3d_a + 480 -- avoid the 6 supplemental lines
|
||||
end
|
||||
i2d = i2d - 6399 -- i2d = 6401 after the first execution of this loop, it must be 2 before the second.
|
||||
i3d_a = i3d_a - 550399 -- i3d_a = 550401 after the first execution of this loop, it must be 2 before the second.
|
||||
i3d_b = i3d_b - 511999 -- i3d_b = 512001 after the first execution of this loop, it must be 2 before the second.
|
||||
end
|
||||
|
||||
local t3 = os.clock()
|
||||
if vmg.loglevel >= 2 then
|
||||
print("[Valleys Mapgen] Data collecting finished in " .. displaytime(t3-t2))
|
||||
print("[Valleys Mapgen] Writing data ...")
|
||||
end
|
||||
|
||||
-- execute voxelmanip boring stuff to write to the map
|
||||
vm:set_data(data)
|
||||
minetest.generate_ores(vm, minp, maxp)
|
||||
vm:set_lighting({day = 0, night = 0})
|
||||
vm:calc_lighting()
|
||||
vm:update_liquids()
|
||||
vm:write_to_map()
|
||||
|
||||
local t4 = os.clock()
|
||||
if vmg.loglevel >= 2 then
|
||||
print("[Valleys Mapgen] Data writing finished in " .. displaytime(t4-t3))
|
||||
end
|
||||
if vmg.loglevel >= 1 then
|
||||
print("[Valleys Mapgen] Mapgen finished in " .. displaytime(t4-t0))
|
||||
end
|
||||
end
|
||||
|
||||
vmg.noises_obj = {}
|
||||
|
||||
for i, n in ipairs(vmg.noises) do
|
||||
vmg.noises_obj[i] = minetest.get_perlin(n.seed, n.octaves, n.persist, 1)
|
||||
end
|
||||
|
||||
function vmg.get_noise(pos, i)
|
||||
local n = vmg.noises[i]
|
||||
local noise = minetest.get_perlin(n.seed, n.octaves, n.persist, 1)
|
||||
if not pos.z then
|
||||
return noise:get2d({x = pos.x / n.spread.x, y = pos.y / n.spread.y}) * n.scale + n.offset
|
||||
else
|
||||
return noise:get3d({x = pos.x / n.spread.x, y = pos.y / n.spread.y, z = pos.z / n.spread.z}) * n.scale + n.offset
|
||||
end
|
||||
end
|
||||
|
||||
local function round(n)
|
||||
return math.floor(n + 0.5)
|
||||
end
|
||||
|
||||
function vmg.get_elevation(pos)
|
||||
local v1 = vmg.get_noise(pos, 1)
|
||||
local v2 = vmg.get_noise(pos, 2)
|
||||
local v3 = vmg.get_noise(pos, 3) ^ 2
|
||||
local v4 = vmg.get_noise(pos, 4)
|
||||
local v5 = vmg.get_noise(pos, 5)
|
||||
local base_ground = v1 + v3
|
||||
local valleys = v3 * (1 - math.exp(- (v2 / v4) ^ 2))
|
||||
local mountain_ground = base_ground + valleys
|
||||
local pos = pos3d(pos, round(mountain_ground))
|
||||
local slopes = v5 * valleys
|
||||
if vmg.get_noise(pos, 6) * slopes > pos.y - mountain_ground then
|
||||
pos.y = pos.y + 1
|
||||
while vmg.get_noise(pos, 6) * slopes > pos.y - mountain_ground do
|
||||
pos.y = pos.y + 1
|
||||
end
|
||||
return pos.y
|
||||
else
|
||||
pos.y = pos.y - 1
|
||||
while vmg.get_noise(pos, 6) * slopes <= pos.y - mountain_ground do
|
||||
pos.y = pos.y - 1
|
||||
end
|
||||
return pos.y
|
||||
end
|
||||
end
|
||||
|
||||
function vmg.spawnplayer(player)
|
||||
local angle = math.random() * math.pi * 2
|
||||
local distance = math.random() * player_max_distance
|
||||
local p_angle = {x = math.cos(angle), y = math.sin(angle)}
|
||||
local pos = {x = -p_angle.x * distance, y = -p_angle.y * distance}
|
||||
local elevation = vmg.get_elevation(pos)
|
||||
while elevation < 3 or math.abs(vmg.get_noise(pos, 2)) < river_size do
|
||||
pos.x = pos.x + p_angle.x
|
||||
pos.y = pos.y + p_angle.y
|
||||
elevation = vmg.get_elevation({x = round(pos.x), y = round(pos.y)})
|
||||
end
|
||||
pos = {x = round(pos.x), y = round(elevation + 1), z = round(pos.y)}
|
||||
player:setpos(pos)
|
||||
return true
|
||||
end
|
|
@ -0,0 +1,328 @@
|
|||
-- Mapgen 1.3
|
||||
-- Wednesday April 8, 2015
|
||||
|
||||
vmg.noises = {
|
||||
|
||||
-- Noise 1 : Base Ground Height 2D
|
||||
{offset = -10, scale = 50, seed = 5202, spread = {x = 1024, y = 1024, z = 1024}, octaves = 6, persist = 0.4, lacunarity = 2},
|
||||
|
||||
-- Noise 2 : Valleys (River where around zero) 2D
|
||||
{offset = 0, scale = 1, seed = -6050, spread = {x = 256, y = 256, z = 256}, octaves = 5, persist = 0.6, lacunarity = 2},
|
||||
|
||||
-- Noise 3 : Valleys Depth 2D
|
||||
{offset = 5, scale = 4, seed = -1914, spread = {x = 512, y = 512, z = 512}, octaves = 1, persist = 1, lacunarity = 2},
|
||||
|
||||
-- Noise 4 : Valleys Profile (Higher values = Larger valleys) 2D
|
||||
{offset = 0.6, scale = 0.5, seed = 777, spread = {x = 512, y = 512, z = 512}, octaves = 1, persist = 1, lacunarity = 2},
|
||||
|
||||
-- Noise 5 : Inter-valleys slopes 2D
|
||||
{offset = 0.5, scale = 0.5, seed = 746, spread = {x = 128, y = 128, z = 128}, octaves = 1, persist = 1, lacunarity = 2},
|
||||
|
||||
-- Noise 6 : Inter-valleys filling 3D
|
||||
{offset = 0, scale = 1, seed = 1993, spread = {x = 256, y = 512, z = 256}, octaves = 6, persist = 0.8, lacunarity = 2},
|
||||
|
||||
-- Noise 7 : Dirt thickness 2D
|
||||
{offset = 3, scale = 1.75, seed = 1605, spread = {x = 256, y = 256, z = 256}, octaves = 3, persist = 0.5, lacunarity = 2},
|
||||
|
||||
-- Noise 8 : Caves I 3D
|
||||
{offset = 0, scale = 1, seed = -4640, spread = {x = 32, y = 32, z = 32}, octaves = 4, persist = 0.5, lacunarity = 2},
|
||||
|
||||
-- Noise 9 : Caves II 3D
|
||||
{offset = 0, scale = 1, seed = 8804, spread = {x = 32, y = 32, z = 32}, octaves = 4, persist = 0.5, lacunarity = 2},
|
||||
|
||||
-- Noise 10 : Caves III 3D
|
||||
{offset = 0, scale = 1, seed = -4780, spread = {x = 32, y = 32, z = 32}, octaves = 4, persist = 0.5, lacunarity = 2},
|
||||
|
||||
-- Noise 11 : Caves IV and Lava I 3D
|
||||
{offset = 0, scale = 1, seed = -9969, spread = {x = 32, y = 32, z = 32}, octaves = 4, persist = 0.5, lacunarity = 2},
|
||||
|
||||
-- Noise 12 : Lava II 3D
|
||||
{offset = 0, scale = 1, seed = 3314, spread = {x = 64, y = 64, z = 64}, octaves = 4, persist = 0.5, lacunarity = 2},
|
||||
|
||||
-- Noise 13 : Clayey dirt noise 2D
|
||||
{offset = 0, scale = 1, seed = 2835, spread = {x = 256, y = 256, z = 256}, octaves = 5, persist = 0.5, lacunarity = 4},
|
||||
|
||||
-- Noise 14 : Silty dirt noise 2D
|
||||
{offset = 0, scale = 1, seed = 6674, spread = {x = 256, y = 256, z = 256}, octaves = 5, persist = 0.5, lacunarity = 4},
|
||||
|
||||
-- Noise 15 : Sandy dirt noise 2D
|
||||
{offset = 0, scale = 1, seed = 6940, spread = {x = 256, y = 256, z = 256}, octaves = 5, persist = 0.5, lacunarity = 4},
|
||||
|
||||
-- Noise 16 : Beaches 2D
|
||||
{offset = 2, scale = 8, seed = 2349, spread = {x = 256, y = 256, z = 256}, octaves = 3, persist = 0.5, lacunarity = 2},
|
||||
|
||||
}
|
||||
|
||||
function vmg.noisemap(i, minp, chulens)
|
||||
local obj = minetest.get_perlin_map(vmg.noises[i], chulens)
|
||||
if minp.z then
|
||||
return obj:get3dMap_flat(minp)
|
||||
else
|
||||
return obj:get2dMap_flat(minp)
|
||||
end
|
||||
end
|
||||
|
||||
for i, n in ipairs(vmg.noises) do
|
||||
vmg.noises[i] = vmg.define("noise_" .. i, n)
|
||||
end
|
||||
|
||||
local average_stone_level = vmg.define("average_stone_level", 180)
|
||||
local dirt_thickness = math.sqrt(average_stone_level) / (vmg.noises[7].offset + 0.5)
|
||||
|
||||
local river_size = vmg.define("river_size", 5) / 100
|
||||
local caves_size = vmg.define("caves_size", 7) / 100
|
||||
local lava_depth = vmg.define("lava_depth", 2000)
|
||||
local surface_lava = vmg.define("surface_lava", false)
|
||||
|
||||
local player_max_distance = vmg.define("player_max_distance", 450)
|
||||
|
||||
local clay_threshold = vmg.define("clay_threshold", 1)
|
||||
local silt_threshold = vmg.define("silt_threshold", 1)
|
||||
local sand_threshold = vmg.define("sand_threshold", 0.75)
|
||||
local dirt_threshold = vmg.define("dirt_threshold", 0.5)
|
||||
|
||||
local water_level = vmg.define("water_level", 1)
|
||||
|
||||
function vmg.generate(minp, maxp, seed)
|
||||
local minps, maxps = minetest.pos_to_string(minp), minetest.pos_to_string(maxp)
|
||||
if vmg.loglevel >= 2 then
|
||||
print("[Valleys Mapgen] Preparing to generate map from " .. minps .. " to " .. maxps .. " ...")
|
||||
elseif vmg.loglevel == 1 then
|
||||
print("[Valleys Mapgen] Generating map from " .. minps .. " to " .. maxps .. " ...")
|
||||
end
|
||||
local t0 = os.clock()
|
||||
|
||||
local c_stone = minetest.get_content_id("default:stone")
|
||||
local c_dirt = minetest.get_content_id("default:dirt")
|
||||
local c_lawn = minetest.get_content_id("default:dirt_with_grass")
|
||||
local c_dirt_clay = minetest.get_content_id("valleys_mapgen:dirt_clayey")
|
||||
local c_lawn_clay = minetest.get_content_id("valleys_mapgen:dirt_clayey_with_grass")
|
||||
local c_dirt_silt = minetest.get_content_id("valleys_mapgen:dirt_silty")
|
||||
local c_lawn_silt = minetest.get_content_id("valleys_mapgen:dirt_silty_with_grass")
|
||||
local c_dirt_sand = minetest.get_content_id("valleys_mapgen:dirt_sandy")
|
||||
local c_lawn_sand = minetest.get_content_id("valleys_mapgen:dirt_sandy_with_grass")
|
||||
local c_desert_sand = minetest.get_content_id("default:desert_sand")
|
||||
local c_sand = minetest.get_content_id("default:sand")
|
||||
local c_gravel = minetest.get_content_id("default:gravel")
|
||||
local c_silt = minetest.get_content_id("valleys_mapgen:silt")
|
||||
local c_clay = minetest.get_content_id("valleys_mapgen:red_clay")
|
||||
local c_water = minetest.get_content_id("default:water_source")
|
||||
local c_lava = minetest.get_content_id("default:lava_source")
|
||||
local c_air = minetest.get_content_id("air")
|
||||
|
||||
local vm, emin, emax = minetest.get_mapgen_object("voxelmanip")
|
||||
local data = vm:get_data()
|
||||
local a = VoxelArea:new({MinEdge = emin, MaxEdge = emax})
|
||||
|
||||
local chulens = vector.add(vector.subtract(maxp, minp), 1)
|
||||
local chulens_sup = {x = chulens.x, y = chulens.y + 6, z = chulens.z}
|
||||
local minp2d = pos2d(minp)
|
||||
|
||||
local t1 = os.clock()
|
||||
if vmg.loglevel >= 2 then
|
||||
print("[Valleys Mapgen] Mapgen preparation finished in " .. displaytime(t1-t0))
|
||||
print("[Valleys Mapgen] Calculating noises ...")
|
||||
end
|
||||
|
||||
local n1 = vmg.noisemap(1, minp2d, chulens)
|
||||
local n2 = vmg.noisemap(2, minp2d, chulens)
|
||||
local n3 = vmg.noisemap(3, minp2d, chulens)
|
||||
local n4 = vmg.noisemap(4, minp2d, chulens)
|
||||
local n5 = vmg.noisemap(5, minp2d, chulens)
|
||||
local n6 = vmg.noisemap(6, minp, chulens_sup)
|
||||
local n7 = vmg.noisemap(7, minp2d, chulens)
|
||||
local n8 = vmg.noisemap(8, minp, chulens)
|
||||
local n9 = vmg.noisemap(9, minp, chulens)
|
||||
local n10 = vmg.noisemap(10, minp, chulens)
|
||||
local n11 = vmg.noisemap(11, minp, chulens)
|
||||
local n12 = vmg.noisemap(12, minp, chulens)
|
||||
local n13 = vmg.noisemap(13, minp2d, chulens)
|
||||
local n14 = vmg.noisemap(14, minp2d, chulens)
|
||||
local n15 = vmg.noisemap(15, minp2d, chulens)
|
||||
local n16 = vmg.noisemap(16, minp2d, chulens)
|
||||
|
||||
local t2 = os.clock()
|
||||
if vmg.loglevel >= 2 then
|
||||
print("[Valleys Mapgen] Noises calculation finished in " .. displaytime(t2-t1))
|
||||
print("[Valleys Mapgen] Collecting data ...")
|
||||
end
|
||||
|
||||
local i2d = 1 -- index for 2D noises
|
||||
local i3d_a = 1 -- index for noise 6 which has a special size
|
||||
local i3d_b = 1 -- index for 3D noises
|
||||
for x = minp.x, maxp.x do -- for each east-west and bottom-top plane
|
||||
for z = minp.z, maxp.z do -- for each vertical row in this plane
|
||||
local v1, v2, v3, v4, v5, v7, v13, v14, v15, v16 = n1[i2d], n2[i2d], n3[i2d], n4[i2d], n5[i2d], n7[i2d], n13[i2d], n14[i2d], n15[i2d], n16[i2d] -- n for noise, v for value
|
||||
v3 = v3 ^ 2 -- v3 must be > 0 and by the square there are high mountains but the median valleys depth is small.
|
||||
local base_ground = v1 + v3 -- v3 is here because terrain is generally higher when valleys are deep (mountains)
|
||||
local river = math.abs(v2) < river_size
|
||||
local valleys = v3 * (1 - math.exp(- (v2 / v4) ^ 2)) -- use the curve of the function 1−exp(−(x/a)²) to modelise valleys. Making "a" varying 0 < a ≤ 1 will change the shape of the valleys. v2 = x and v4 = a.
|
||||
local mountain_ground = base_ground + valleys
|
||||
local slopes = v5 * valleys
|
||||
|
||||
if river then
|
||||
mountain_ground = math.min(math.max(base_ground - 3, water_level - 6), mountain_ground)
|
||||
slopes = 0
|
||||
end
|
||||
|
||||
local dirt = c_dirt
|
||||
local lawn = c_lawn
|
||||
local max = math.max(v13, v14, v15)
|
||||
if max > dirt_threshold then
|
||||
if v13 == max then
|
||||
if v13 > clay_threshold then
|
||||
dirt = c_clay
|
||||
lawn = c_clay
|
||||
else
|
||||
dirt = c_dirt_clay
|
||||
lawn = c_lawn_clay
|
||||
end
|
||||
elseif v14 == max then
|
||||
if v14 > silt_threshold then
|
||||
dirt = c_silt
|
||||
lawn = c_silt
|
||||
else
|
||||
dirt = c_dirt_silt
|
||||
lawn = c_lawn_silt
|
||||
end
|
||||
else
|
||||
if v15 > sand_threshold then
|
||||
dirt = c_desert_sand
|
||||
lawn = c_desert_sand
|
||||
else
|
||||
dirt = c_dirt_sand
|
||||
lawn = c_lawn_sand
|
||||
end
|
||||
end
|
||||
end
|
||||
local is_beach = v15 > 0 and v16 > 0
|
||||
local beach = v15 * v16 + water_level
|
||||
|
||||
for y = minp.y, maxp.y do -- for each node in vertical row
|
||||
local ivm = a:index(x, y, z)
|
||||
local v6, v8, v9, v10, v11, v12 = n6[i3d_a], n8[i3d_b], n9[i3d_b], n10[i3d_b], n11[i3d_b], n12[i3d_b]
|
||||
local is_cave = v8 ^ 2 + v9 ^ 2 + v10 ^ 2 + v11 ^ 2 < caves_size
|
||||
if v6 * slopes > y - mountain_ground then -- if pos is in the ground
|
||||
if not is_cave then
|
||||
local above = math.ceil(
|
||||
v7 + math.random() - math.sqrt(math.abs(y)) / dirt_thickness
|
||||
)
|
||||
if above <= 0 then
|
||||
data[ivm] = c_stone
|
||||
elseif y >= water_level and n6[i3d_a+80] * slopes <= y + 1 - mountain_ground and not river then
|
||||
if is_beach and y < beach then
|
||||
data[ivm] = c_sand
|
||||
else
|
||||
data[ivm] = lawn -- if node above is not in the ground, place lawn
|
||||
end
|
||||
elseif n6[i3d_a+above*80] * slopes <= y + above - mountain_ground then
|
||||
if is_beach and y < beach then
|
||||
data[ivm] = c_sand
|
||||
else
|
||||
data[ivm] = dirt
|
||||
end
|
||||
else
|
||||
data[ivm] = c_stone
|
||||
end
|
||||
elseif v11 + v12 > 2 ^ (y / lava_depth) and (surface_lava or y < water_level - 1) then
|
||||
data[ivm] = c_lava
|
||||
end
|
||||
elseif y <= water_level or river and y - 2 <= mountain_ground then
|
||||
data[ivm] = c_water
|
||||
end
|
||||
|
||||
i3d_a = i3d_a + 80 -- increase i3d_a by one row
|
||||
i3d_b = i3d_b + 80 -- increase i3d_b by one row
|
||||
end
|
||||
i2d = i2d + 80 -- increase i2d by one row
|
||||
i3d_a = i3d_a + 480 -- avoid the 6 supplemental lines
|
||||
end
|
||||
i2d = i2d - 6399 -- i2d = 6401 after the first execution of this loop, it must be 2 before the second.
|
||||
i3d_a = i3d_a - 550399 -- i3d_a = 550401 after the first execution of this loop, it must be 2 before the second.
|
||||
i3d_b = i3d_b - 511999 -- i3d_b = 512001 after the first execution of this loop, it must be 2 before the second.
|
||||
end
|
||||
|
||||
local t3 = os.clock()
|
||||
if vmg.loglevel >= 2 then
|
||||
print("[Valleys Mapgen] Data collecting finished in " .. displaytime(t3-t2))
|
||||
print("[Valleys Mapgen] Writing data ...")
|
||||
end
|
||||
|
||||
-- execute voxelmanip boring stuff to write to the map
|
||||
vm:set_data(data)
|
||||
minetest.generate_ores(vm, minp, maxp)
|
||||
vm:set_lighting({day = 0, night = 0})
|
||||
vm:calc_lighting()
|
||||
vm:update_liquids()
|
||||
vm:write_to_map()
|
||||
|
||||
local t4 = os.clock()
|
||||
if vmg.loglevel >= 2 then
|
||||
print("[Valleys Mapgen] Data writing finished in " .. displaytime(t4-t3))
|
||||
end
|
||||
if vmg.loglevel >= 1 then
|
||||
print("[Valleys Mapgen] Mapgen finished in " .. displaytime(t4-t0))
|
||||
end
|
||||
end
|
||||
|
||||
vmg.noises_obj = {}
|
||||
|
||||
for i, n in ipairs(vmg.noises) do
|
||||
vmg.noises_obj[i] = minetest.get_perlin(n.seed, n.octaves, n.persist, 1)
|
||||
end
|
||||
|
||||
function vmg.get_noise(pos, i)
|
||||
local n = vmg.noises[i]
|
||||
local noise = minetest.get_perlin(n.seed, n.octaves, n.persist, 1)
|
||||
if not pos.z then
|
||||
return noise:get2d({x = pos.x / n.spread.x, y = pos.y / n.spread.y}) * n.scale + n.offset
|
||||
else
|
||||
return noise:get3d({x = pos.x / n.spread.x, y = pos.y / n.spread.y, z = pos.z / n.spread.z}) * n.scale + n.offset
|
||||
end
|
||||
end
|
||||
|
||||
local function round(n)
|
||||
return math.floor(n + 0.5)
|
||||
end
|
||||
|
||||
function vmg.get_elevation(pos)
|
||||
local v1 = vmg.get_noise(pos, 1)
|
||||
local v2 = vmg.get_noise(pos, 2)
|
||||
local v3 = vmg.get_noise(pos, 3) ^ 2
|
||||
local v4 = vmg.get_noise(pos, 4)
|
||||
local v5 = vmg.get_noise(pos, 5)
|
||||
local base_ground = v1 + v3
|
||||
local valleys = v3 * (1 - math.exp(- (v2 / v4) ^ 2))
|
||||
local mountain_ground = base_ground + valleys
|
||||
local pos = pos3d(pos, round(mountain_ground))
|
||||
local slopes = v5 * valleys
|
||||
if vmg.get_noise(pos, 6) * slopes > pos.y - mountain_ground then
|
||||
pos.y = pos.y + 1
|
||||
while vmg.get_noise(pos, 6) * slopes > pos.y - mountain_ground do
|
||||
pos.y = pos.y + 1
|
||||
end
|
||||
return pos.y
|
||||
else
|
||||
pos.y = pos.y - 1
|
||||
while vmg.get_noise(pos, 6) * slopes <= pos.y - mountain_ground do
|
||||
pos.y = pos.y - 1
|
||||
end
|
||||
return pos.y
|
||||
end
|
||||
end
|
||||
|
||||
function vmg.spawnplayer(player)
|
||||
local angle = math.random() * math.pi * 2
|
||||
local distance = math.random() * player_max_distance
|
||||
local p_angle = {x = math.cos(angle), y = math.sin(angle)}
|
||||
local pos = {x = -p_angle.x * distance, y = -p_angle.y * distance}
|
||||
local elevation = vmg.get_elevation(pos)
|
||||
while elevation < water_level + 2 or math.abs(vmg.get_noise(pos, 2)) < river_size do
|
||||
pos.x = pos.x + p_angle.x
|
||||
pos.y = pos.y + p_angle.y
|
||||
elevation = vmg.get_elevation({x = round(pos.x), y = round(pos.y)})
|
||||
end
|
||||
pos = {x = round(pos.x), y = round(elevation + 1), z = round(pos.y)}
|
||||
player:setpos(pos)
|
||||
return true
|
||||
end
|
|
@ -0,0 +1,203 @@
|
|||
function default.grow_tree(pos, is_apple_tree)
|
||||
local rand = math.random()
|
||||
local height = math.floor(4 + 2.5 * rand)
|
||||
local radius = 3 + rand
|
||||
|
||||
local leaves = minetest.get_content_id("default:leaves")
|
||||
local trunk = minetest.get_content_id("default:tree")
|
||||
local air = minetest.get_content_id("air")
|
||||
local ignore = minetest.get_content_id("ignore")
|
||||
local vm = minetest.get_voxel_manip()
|
||||
local emin, emax = vm:read_from_map({x = pos.x - 4, y = pos.y, z = pos.z - 4}, {x = pos.x + 4, y = pos.y + height + 4, z = pos.z + 4})
|
||||
local area = VoxelArea:new({MinEdge = emin, MaxEdge = emax})
|
||||
local data = vm:get_data()
|
||||
if is_apple_tree then
|
||||
vmg.grow_apple_tree(pos, data, area, height, radius, trunk, leaves, minetest.get_content_id("default:apple"), air, ignore)
|
||||
else
|
||||
vmg.grow_tree(pos, data, area, height, radius, trunk, leaves, air, ignore)
|
||||
end
|
||||
vm:set_data(data)
|
||||
vm:write_to_map()
|
||||
vm:update_map()
|
||||
end
|
||||
|
||||
function default.grow_jungle_tree(pos)
|
||||
local rand = math.random()
|
||||
local height = math.floor(8 + 4 * rand)
|
||||
local radius = 5 + 3 * rand
|
||||
|
||||
local leaves = minetest.get_content_id("default:jungleleaves")
|
||||
local trunk = minetest.get_content_id("default:jungletree")
|
||||
local air = minetest.get_content_id("air")
|
||||
local ignore = minetest.get_content_id("ignore")
|
||||
local vm = minetest.get_voxel_manip()
|
||||
local emin, emax = vm:read_from_map({x = pos.x - 8, y = pos.y - 1, z = pos.z - 8}, {x = pos.x + 8, y = pos.y + height + 5, z = pos.z + 8})
|
||||
local area = VoxelArea:new({MinEdge = emin, MaxEdge = emax})
|
||||
local data = vm:get_data()
|
||||
vmg.grow_jungle_tree(pos, data, area, height, radius, trunk, leaves, air, ignore)
|
||||
vmg.execute_after_mapgen()
|
||||
vm:set_data(data)
|
||||
vm:write_to_map()
|
||||
vm:update_map()
|
||||
end
|
||||
|
||||
function default.grow_pine_tree(pos)
|
||||
local rand = math.random()
|
||||
local height = math.floor(9 + 6 * rand)
|
||||
local radius = 4 + 2 * rand
|
||||
|
||||
local leaves = minetest.get_content_id("default:pine_needles")
|
||||
local trunk = minetest.get_content_id("default:pinetree")
|
||||
local air = minetest.get_content_id("air")
|
||||
local ignore = minetest.get_content_id("ignore")
|
||||
local vm = minetest.get_voxel_manip()
|
||||
local emin, emax = vm:read_from_map({x = pos.x - 6, y = pos.y - 1, z = pos.z - 6}, {x = pos.x + 6, y = pos.y + height + 2, z = pos.z + 6})
|
||||
local area = VoxelArea:new({MinEdge = emin, MaxEdge = emax})
|
||||
local data = vm:get_data()
|
||||
vmg.grow_pine_tree(pos, data, area, height, radius, trunk, leaves, air, ignore)
|
||||
vm:set_data(data)
|
||||
vm:write_to_map()
|
||||
vm:update_map()
|
||||
end
|
||||
|
||||
function vmg.grow_tree(pos, data, area, height, radius, trunk, leaves, air, ignore)
|
||||
if vmg.loglevel >= 3 then
|
||||
print("[Valleys Mapgen] Generating tree at " .. minetest.pos_to_string(pos) .. " ...")
|
||||
end
|
||||
local ystride = area.ystride
|
||||
local iv = area:indexp(pos)
|
||||
for i = 1, height do
|
||||
data[iv] = trunk
|
||||
iv = iv + ystride
|
||||
end
|
||||
local np = {offset = 0.8, scale = 0.4, spread = {x = 8, y = 4, z = 8}, octaves = 3, persist = 0.5}
|
||||
pos.y = pos.y + height - 1
|
||||
vmg.make_leavesblob(pos, data, area, leaves, air, ignore, {x = radius, y = radius, z = radius}, np)
|
||||
end
|
||||
|
||||
function vmg.grow_apple_tree(pos, data, area, height, radius, trunk, leaves, fruit, air, ignore)
|
||||
if vmg.loglevel >= 3 then
|
||||
print("[Valleys Mapgen] Generating apple tree at " .. minetest.pos_to_string(pos) .. " ...")
|
||||
end
|
||||
local ystride = area.ystride
|
||||
local iv = area:indexp(pos)
|
||||
for i = 1, height do
|
||||
data[iv] = trunk
|
||||
iv = iv + ystride
|
||||
end
|
||||
local np = {offset = 0.8, scale = 0.4, spread = {x = 8, y = 4, z = 8}, octaves = 3, persist = 0.5}
|
||||
pos.y = pos.y + height - 1
|
||||
vmg.make_leavesblob(pos, data, area, leaves, air, ignore, {x = radius, y = radius, z = radius}, np, 0.06, fruit)
|
||||
end
|
||||
|
||||
local function make_jungle_root(x0, y0, z0, data, area, tree, air)
|
||||
local ystride = area.ystride
|
||||
local ybot = y0 - 1
|
||||
for x = x0 - 1, x0 + 1 do
|
||||
for z = z0 - 1, z0 + 1 do
|
||||
local iv = area:index(x, ybot, z)
|
||||
for i = 0, 5 do
|
||||
if data[iv] == air then
|
||||
if math.random() < 0.6 then
|
||||
data[iv-ystride] = tree -- make jungle tree below
|
||||
if math.random() < 0.6 then
|
||||
data[iv] = tree -- make jungle tree at this air node
|
||||
end
|
||||
end
|
||||
break
|
||||
end
|
||||
iv = iv + ystride
|
||||
end
|
||||
end
|
||||
end
|
||||
end
|
||||
|
||||
function vmg.grow_jungle_tree(pos, data, area, height, radius, trunk, leaves, air, ignore)
|
||||
if vmg.loglevel >= 3 then
|
||||
print("[Valleys Mapgen] Generating jungle tree at " .. minetest.pos_to_string(pos) .. " ...")
|
||||
end
|
||||
local ystride = area.ystride
|
||||
local iv = area:indexp(pos)
|
||||
for i = 1, height do
|
||||
data[iv] = trunk
|
||||
iv = iv + ystride
|
||||
end
|
||||
vmg.register_after_mapgen(make_jungle_root, pos.x, pos.y, pos.z, data, area, trunk, air)
|
||||
local np = {offset = 0.8, scale = 0.4, spread = {x = 8, y = 4, z = 8}, octaves = 3, persist = 0.8}
|
||||
pos.y = pos.y + height
|
||||
vmg.make_leavesblob(pos, data, area, leaves, air, ignore, {x = radius, y = radius * 0.5, z = radius}, np)
|
||||
end
|
||||
|
||||
function vmg.grow_pine_tree(pos, data, area, height, radius, trunk, leaves, air, ignore)
|
||||
if vmg.loglevel >= 3 then
|
||||
print("[Valleys Mapgen] Generating pine tree at " .. minetest.pos_to_string(pos) .. " ...")
|
||||
end
|
||||
local ystride = area.ystride
|
||||
local iv = area:indexp(pos)
|
||||
for i = 1, height do
|
||||
data[iv] = trunk
|
||||
iv = iv + ystride
|
||||
end
|
||||
|
||||
-- add leaves on the top (4% 0 ; 36% 1 ; 60% 2)
|
||||
local rand = math.random()
|
||||
if rand < 0.96 then
|
||||
data[iv] = leaves
|
||||
if rand < 0.60 then
|
||||
iv = iv + ystride
|
||||
data[iv] = leaves
|
||||
end
|
||||
end
|
||||
|
||||
-- make several leaves rings
|
||||
local max_height = pos.y + height
|
||||
local min_height = pos.y + math.floor((0.2 + 0.3 * math.random()) * height)
|
||||
local radius_increment = (radius - 1.2) / (max_height - min_height)
|
||||
local np = {offset = 0.8, scale = 0.4, spread = {x = 12, y = 4, z = 12}, octaves = 3, persist = 0.8}
|
||||
|
||||
pos.y = max_height - 1
|
||||
while pos.y >= min_height do
|
||||
local ring_radius = (max_height - pos.y) * radius_increment + 1.2
|
||||
vmg.make_leavesblob(pos, data, area, leaves, air, ignore, {x = ring_radius, y = 2, z = ring_radius}, np)
|
||||
pos.y = pos.y - math.random(2, 3)
|
||||
end
|
||||
end
|
||||
|
||||
function vmg.make_leavesblob(pos, data, area, leaves, air, ignore, radius, np, fruit_chance, fruit)
|
||||
local count = 0
|
||||
fruit_chance = fruit_chance or 0
|
||||
|
||||
np.seed = math.random(0, 16777215)
|
||||
local round_radius = {x = math.ceil(radius.x), y = math.ceil(radius.y), z = math.ceil(radius.z)}
|
||||
|
||||
local length = vector.multiply(round_radius, 2)
|
||||
local chulens = vector.add(length, 1)
|
||||
local minp = vector.subtract(pos, round_radius)
|
||||
local maxp = vector.add(minp, length)
|
||||
local obj = minetest.get_perlin_map(np, chulens)
|
||||
local pmap = obj:get3dMap_flat(minp)
|
||||
local i = 1
|
||||
for x = minp.x, maxp.x do
|
||||
local xval = ((x - pos.x) / radius.x) ^ 2
|
||||
for y = minp.y, maxp.y do
|
||||
local yval = ((y - pos.y) / radius.y) ^ 2
|
||||
for z = minp.z, maxp.z do
|
||||
local zval = ((z - pos.z) / radius.z) ^ 2
|
||||
local dist = math.sqrt(xval + yval + zval)
|
||||
local nval = pmap[i]
|
||||
if nval > dist then
|
||||
local iv = area:index(x, y, z)
|
||||
if data[iv] == air or data[iv] == ignore then
|
||||
count = count + 1
|
||||
if math.random() < fruit_chance then
|
||||
data[iv] = fruit
|
||||
else
|
||||
data[iv] = leaves
|
||||
end
|
||||
end
|
||||
end
|
||||
i = i + 1
|
||||
end
|
||||
end
|
||||
end
|
||||
end
|
|
@ -0,0 +1,510 @@
|
|||
-- Mapgen 2.0
|
||||
-- Sunday May 31, 2015
|
||||
|
||||
vmg.noises = {
|
||||
|
||||
-- Noise 1 : Base Ground Height 2D
|
||||
{offset = -10, scale = 50, seed = 5202, spread = {x = 1024, y = 1024, z = 1024}, octaves = 6, persist = 0.4, lacunarity = 2},
|
||||
|
||||
-- Noise 2 : Valleys (River where around zero) 2D
|
||||
{offset = 0, scale = 1, seed = -6050, spread = {x = 256, y = 256, z = 256}, octaves = 5, persist = 0.6, lacunarity = 2},
|
||||
|
||||
-- Noise 3 : Valleys Depth 2D
|
||||
{offset = 5, scale = 4, seed = -1914, spread = {x = 512, y = 512, z = 512}, octaves = 1, persist = 1, lacunarity = 2},
|
||||
|
||||
-- Noise 4 : Valleys Profile (Higher values = Larger valleys) 2D
|
||||
{offset = 0.6, scale = 0.5, seed = 777, spread = {x = 512, y = 512, z = 512}, octaves = 1, persist = 1, lacunarity = 2},
|
||||
|
||||
-- Noise 5 : Inter-valleys slopes 2D
|
||||
{offset = 0.5, scale = 0.5, seed = 746, spread = {x = 128, y = 128, z = 128}, octaves = 1, persist = 1, lacunarity = 2},
|
||||
|
||||
-- Noise 6 : Inter-valleys filling 3D
|
||||
{offset = 0, scale = 1, seed = 1993, spread = {x = 256, y = 512, z = 256}, octaves = 6, persist = 0.8, lacunarity = 2},
|
||||
|
||||
-- Noise 7 : Dirt thickness 2D
|
||||
{offset = 3, scale = 1.75, seed = 1605, spread = {x = 256, y = 256, z = 256}, octaves = 3, persist = 0.5, lacunarity = 2},
|
||||
|
||||
-- Noise 8 : Caves I 3D
|
||||
{offset = 0, scale = 1, seed = -4640, spread = {x = 32, y = 32, z = 32}, octaves = 4, persist = 0.5, lacunarity = 2},
|
||||
|
||||
-- Noise 9 : Caves II 3D
|
||||
{offset = 0, scale = 1, seed = 8804, spread = {x = 32, y = 32, z = 32}, octaves = 4, persist = 0.5, lacunarity = 2},
|
||||
|
||||
-- Noise 10 : Caves III 3D
|
||||
{offset = 0, scale = 1, seed = -4780, spread = {x = 32, y = 32, z = 32}, octaves = 4, persist = 0.5, lacunarity = 2},
|
||||
|
||||
-- Noise 11 : Caves IV and Lava I 3D
|
||||
{offset = 0, scale = 1, seed = -9969, spread = {x = 32, y = 32, z = 32}, octaves = 4, persist = 0.5, lacunarity = 2},
|
||||
|
||||
-- Noise 12 : Lava II (Geologic heat) 3D
|
||||
{offset = 0, scale = 1, seed = 3314, spread = {x = 64, y = 64, z = 64}, octaves = 4, persist = 0.5, lacunarity = 2},
|
||||
|
||||
-- Noise 13 : Clayey dirt noise 2D
|
||||
{offset = 0, scale = 1, seed = 2835, spread = {x = 256, y = 256, z = 256}, octaves = 5, persist = 0.5, lacunarity = 4},
|
||||
|
||||
-- Noise 14 : Silty dirt noise 2D
|
||||
{offset = 0, scale = 1, seed = 6674, spread = {x = 256, y = 256, z = 256}, octaves = 5, persist = 0.5, lacunarity = 4},
|
||||
|
||||
-- Noise 15 : Sandy dirt noise 2D
|
||||
{offset = 0, scale = 1, seed = 6940, spread = {x = 256, y = 256, z = 256}, octaves = 5, persist = 0.5, lacunarity = 4},
|
||||
|
||||
-- Noise 16 : Beaches 2D
|
||||
{offset = 2, scale = 8, seed = 2349, spread = {x = 256, y = 256, z = 256}, octaves = 3, persist = 0.5, lacunarity = 2},
|
||||
|
||||
-- Noise 17 : Temperature (not in maps) 3D
|
||||
{offset = 2, scale = 1, seed = -1805, spread = {x = 768, y = 256, z = 768}, octaves = 4, persist = 0.5, lacunarity = 4},
|
||||
|
||||
-- Noise 18 : Humidity 2D
|
||||
{offset = 0, scale = 1, seed = -5787, spread = {x = 243, y = 243, z = 243}, octaves = 4, persist = 0.5, lacunarity = 3},
|
||||
|
||||
}
|
||||
|
||||
function vmg.noisemap(i, minp, chulens)
|
||||
local obj = minetest.get_perlin_map(vmg.noises[i], chulens)
|
||||
if minp.z then
|
||||
return obj:get3dMap_flat(minp)
|
||||
else
|
||||
return obj:get2dMap_flat(minp)
|
||||
end
|
||||
end
|
||||
|
||||
for i, n in ipairs(vmg.noises) do
|
||||
vmg.noises[i] = vmg.define("noise_" .. i, n)
|
||||
end
|
||||
|
||||
vmg.after_mapgen = {}
|
||||
|
||||
function vmg.register_after_mapgen(f, ...)
|
||||
table.insert(vmg.after_mapgen, {f = f, ...})
|
||||
end
|
||||
|
||||
function vmg.execute_after_mapgen()
|
||||
for i, params in ipairs(vmg.after_mapgen) do
|
||||
params.f(unpack(params))
|
||||
end
|
||||
vmg.after_mapgen = {}
|
||||
end
|
||||
|
||||
local river_size = vmg.define("river_size", 5) / 100
|
||||
local caves_size = vmg.define("caves_size", 7) / 100
|
||||
local lava_depth = vmg.define("lava_depth", 2000)
|
||||
local lava_max_height = vmg.define("lava_max_height", -1)
|
||||
local altitude_chill = vmg.define("altitude_chill", 90)
|
||||
|
||||
local average_stone_level = vmg.define("average_stone_level", 180)
|
||||
local dirt_thickness = math.sqrt(average_stone_level) / (vmg.noises[7].offset + 0.5)
|
||||
local average_snow_level = vmg.define("average_snow_level", 100)
|
||||
local snow_threshold = vmg.noises[17].offset * 0.5 ^ (average_snow_level / altitude_chill)
|
||||
|
||||
local player_max_distance = vmg.define("player_max_distance", 450)
|
||||
|
||||
local clay_threshold = vmg.define("clay_threshold", 1)
|
||||
local silt_threshold = vmg.define("silt_threshold", 1)
|
||||
local sand_threshold = vmg.define("sand_threshold", 0.75)
|
||||
local dirt_threshold = vmg.define("dirt_threshold", 0.5)
|
||||
|
||||
local tree_density = vmg.define("tree_density", 5) / 100
|
||||
local trees = vmg.define("trees", true)
|
||||
local plant_density = vmg.define("plant_density", 32) / 100
|
||||
local plants = vmg.define("plants", true)
|
||||
|
||||
local water_level = vmg.define("water_level", 1)
|
||||
|
||||
function vmg.generate(minp, maxp, seed)
|
||||
local minps, maxps = minetest.pos_to_string(minp), minetest.pos_to_string(maxp)
|
||||
if vmg.loglevel >= 2 then
|
||||
print("[Valleys Mapgen] Preparing to generate map from " .. minps .. " to " .. maxps .. " ...")
|
||||
elseif vmg.loglevel == 1 then
|
||||
print("[Valleys Mapgen] Generating map from " .. minps .. " to " .. maxps .. " ...")
|
||||
end
|
||||
local t0 = os.clock()
|
||||
|
||||
local c_stone = minetest.get_content_id("default:stone")
|
||||
local c_dirt = minetest.get_content_id("default:dirt")
|
||||
local c_lawn = minetest.get_content_id("default:dirt_with_grass")
|
||||
local c_snow = minetest.get_content_id("default:dirt_with_snow")
|
||||
local c_dirt_clay = minetest.get_content_id("valleys_mapgen:dirt_clayey")
|
||||
local c_lawn_clay = minetest.get_content_id("valleys_mapgen:dirt_clayey_with_grass")
|
||||
local c_snow_clay = minetest.get_content_id("valleys_mapgen:dirt_clayey_with_snow")
|
||||
local c_dirt_silt = minetest.get_content_id("valleys_mapgen:dirt_silty")
|
||||
local c_lawn_silt = minetest.get_content_id("valleys_mapgen:dirt_silty_with_grass")
|
||||
local c_snow_silt = minetest.get_content_id("valleys_mapgen:dirt_silty_with_snow")
|
||||
local c_dirt_sand = minetest.get_content_id("valleys_mapgen:dirt_sandy")
|
||||
local c_lawn_sand = minetest.get_content_id("valleys_mapgen:dirt_sandy_with_grass")
|
||||
local c_snow_sand = minetest.get_content_id("valleys_mapgen:dirt_sandy_with_snow")
|
||||
local c_desert_sand = minetest.get_content_id("default:desert_sand")
|
||||
local c_sand = minetest.get_content_id("default:sand")
|
||||
local c_gravel = minetest.get_content_id("default:gravel")
|
||||
local c_silt = minetest.get_content_id("valleys_mapgen:silt")
|
||||
local c_clay = minetest.get_content_id("valleys_mapgen:red_clay")
|
||||
local c_water = minetest.get_content_id("default:water_source")
|
||||
local c_lava = minetest.get_content_id("default:lava_source")
|
||||
local c_snow_layer = minetest.get_content_id("default:snow")
|
||||
|
||||
local c_tree = minetest.get_content_id("default:tree")
|
||||
local c_leaves = minetest.get_content_id("default:leaves")
|
||||
local c_apple = minetest.get_content_id("default:apple")
|
||||
local c_jungletree = minetest.get_content_id("default:jungletree")
|
||||
local c_jungleleaves = minetest.get_content_id("default:jungleleaves")
|
||||
local c_pinetree = minetest.get_content_id("default:pinetree")
|
||||
local c_pineleaves = minetest.get_content_id("default:pine_needles")
|
||||
|
||||
local c_grass = {
|
||||
minetest.get_content_id("default:grass_1"),
|
||||
minetest.get_content_id("default:grass_2"),
|
||||
minetest.get_content_id("default:grass_3"),
|
||||
minetest.get_content_id("default:grass_4"),
|
||||
minetest.get_content_id("default:grass_5"),
|
||||
}
|
||||
local c_junglegrass = minetest.get_content_id("default:junglegrass")
|
||||
local c_dryshrub = minetest.get_content_id("default:dry_shrub")
|
||||
local c_cactus = minetest.get_content_id("default:cactus")
|
||||
local c_papyrus = minetest.get_content_id("default:papyrus")
|
||||
|
||||
local c_air = minetest.get_content_id("air")
|
||||
local c_ignore = minetest.get_content_id("ignore")
|
||||
|
||||
local vm, emin, emax = minetest.get_mapgen_object("voxelmanip")
|
||||
local data = vm:get_data()
|
||||
local a = VoxelArea:new({MinEdge = emin, MaxEdge = emax})
|
||||
local ystride = a.ystride
|
||||
|
||||
local chulens = vector.add(vector.subtract(maxp, minp), 1)
|
||||
local chulens_sup = {x = chulens.x, y = chulens.y + 6, z = chulens.z}
|
||||
local minp2d = pos2d(minp)
|
||||
|
||||
local t1 = os.clock()
|
||||
if vmg.loglevel >= 2 then
|
||||
print("[Valleys Mapgen] Mapgen preparation finished in " .. displaytime(t1-t0))
|
||||
print("[Valleys Mapgen] Calculating noises ...")
|
||||
end
|
||||
|
||||
local n1 = vmg.noisemap(1, minp2d, chulens)
|
||||
local n2 = vmg.noisemap(2, minp2d, chulens)
|
||||
local n3 = vmg.noisemap(3, minp2d, chulens)
|
||||
local n4 = vmg.noisemap(4, minp2d, chulens)
|
||||
local n5 = vmg.noisemap(5, minp2d, chulens)
|
||||
local n6 = vmg.noisemap(6, minp, chulens_sup)
|
||||
local n7 = vmg.noisemap(7, minp2d, chulens)
|
||||
local n8 = vmg.noisemap(8, minp, chulens)
|
||||
local n9 = vmg.noisemap(9, minp, chulens)
|
||||
local n10 = vmg.noisemap(10, minp, chulens)
|
||||
local n11 = vmg.noisemap(11, minp, chulens)
|
||||
local n12 = vmg.noisemap(12, minp, chulens)
|
||||
local n13 = vmg.noisemap(13, minp2d, chulens)
|
||||
local n14 = vmg.noisemap(14, minp2d, chulens)
|
||||
local n15 = vmg.noisemap(15, minp2d, chulens)
|
||||
local n16 = vmg.noisemap(16, minp2d, chulens)
|
||||
local n18 = vmg.noisemap(18, minp2d, chulens)
|
||||
|
||||
local t2 = os.clock()
|
||||
if vmg.loglevel >= 2 then
|
||||
print("[Valleys Mapgen] Noises calculation finished in " .. displaytime(t2-t1))
|
||||
print("[Valleys Mapgen] Collecting data ...")
|
||||
end
|
||||
|
||||
local i2d = 1 -- index for 2D noises
|
||||
local i3d_sup = 1 -- index for noise 6 which has a special size
|
||||
local i3d = 1 -- index for 3D noises
|
||||
|
||||
-- Calculate increments
|
||||
local i2d_incrZ = chulens.z
|
||||
local i2d_decrX = chulens.x * chulens.z - 1
|
||||
local i3d_incrY = chulens.y
|
||||
local i3d_sup_incrZ = 6 * chulens.y
|
||||
local i3d_decrX = chulens.x * chulens.y * chulens.z - 1
|
||||
local i3d_sup_decrX = chulens.x * (chulens.y + 6) * chulens.z - 1
|
||||
|
||||
for x = minp.x, maxp.x do -- for each YZ plane
|
||||
for z = minp.z, maxp.z do -- for each vertical line in this plane
|
||||
local v1, v2, v3, v4, v5, v7, v13, v14, v15, v16, v18 = n1[i2d], n2[i2d], n3[i2d], n4[i2d], n5[i2d], n7[i2d], n13[i2d], n14[i2d], n15[i2d], n16[i2d], n18[i2d] -- n for noise, v for value
|
||||
v3 = v3 ^ 2 -- v3 must be > 0 and by the square there are high mountains but the median valleys depth is small.
|
||||
local base_ground = v1 + v3 -- v3 is here because terrain is generally higher when valleys are deep (mountains)
|
||||
local river = math.abs(v2) < river_size
|
||||
local valleys = v3 * (1 - math.exp(- (v2 / v4) ^ 2)) -- use the curve of the function 1−exp(−(x/a)²) to modelise valleys. Making "a" varying 0 < a ≤ 1 will change the shape of the valleys. Try it with a geometry software ! (here x = v2 and a = v4)
|
||||
local mountain_ground = base_ground + valleys
|
||||
local slopes = v5 * valleys
|
||||
|
||||
if river then
|
||||
mountain_ground = math.min(math.max(base_ground - 3, water_level - 6), mountain_ground)
|
||||
slopes = 0
|
||||
end
|
||||
|
||||
-- Choose biome
|
||||
local dirt = c_dirt
|
||||
local lawn = c_lawn
|
||||
local snow = c_snow
|
||||
local max = math.max(v13, v14, v15) -- the biome is the maximal of these 3 values, if bigger than 0.5. Else, make normal dirt.
|
||||
if max > dirt_threshold then
|
||||
if v13 == max then
|
||||
if v13 > clay_threshold then
|
||||
dirt = c_clay
|
||||
lawn = c_clay
|
||||
snow = c_clay
|
||||
else
|
||||
dirt = c_dirt_clay
|
||||
lawn = c_lawn_clay
|
||||
snow = c_snow_clay
|
||||
end
|
||||
elseif v14 == max then
|
||||
if v14 > silt_threshold then
|
||||
dirt = c_silt
|
||||
lawn = c_silt
|
||||
snow = c_silt
|
||||
else
|
||||
dirt = c_dirt_silt
|
||||
lawn = c_lawn_silt
|
||||
snow = c_snow_silt
|
||||
end
|
||||
else
|
||||
if v15 > sand_threshold then
|
||||
dirt = c_desert_sand
|
||||
lawn = c_desert_sand
|
||||
snow = c_desert_sand
|
||||
else
|
||||
dirt = c_dirt_sand
|
||||
lawn = c_lawn_sand
|
||||
snow = c_snow_sand
|
||||
end
|
||||
end
|
||||
end
|
||||
local is_beach = v15 > 0 and v16 > 0
|
||||
local beach = v15 * v16 + water_level -- the y coordinate below which dirt is replaced by beach sand
|
||||
|
||||
-- raw humidity
|
||||
local hraw = 2 ^ (v13 - v15 + v18 * 2)
|
||||
|
||||
for y = minp.y, maxp.y do -- for each node in vertical line
|
||||
local ivm = a:index(x, y, z)
|
||||
local v6, v8, v9, v10, v11, v12 = n6[i3d_sup], n8[i3d], n9[i3d], n10[i3d], n11[i3d], n12[i3d]
|
||||
local is_cave = v8 ^ 2 + v9 ^ 2 + v10 ^ 2 + v11 ^ 2 < caves_size
|
||||
if v6 * slopes > y - mountain_ground then -- if pos is in the ground
|
||||
if not is_cave then
|
||||
local above = math.ceil(
|
||||
v7 + math.random() - math.sqrt(math.abs(y)) / dirt_thickness -- The following code will look for air at this many nodes up. If any, make dirt, else, make stone. So, it's the dirt layer thickness.
|
||||
)
|
||||
if y >= water_level and n6[i3d_sup+i3d_incrY] * slopes <= y + 1 - mountain_ground and not river then
|
||||
if is_beach and y < beach then
|
||||
data[ivm] = c_sand
|
||||
else -- if node above is not in the ground, place lawn
|
||||
|
||||
-- calculate humidity
|
||||
local sea_water = 0.5 ^ math.max((y - water_level) / 6, 0)
|
||||
local river_water = 0.5 ^ math.max((y - base_ground) / 3, 0)
|
||||
local water = sea_water + (1 - sea_water) * river_water
|
||||
local humidity = hraw + water
|
||||
|
||||
local ivm2 = ivm + ystride
|
||||
y = y + 1
|
||||
local pos = {x = x, y = y, z = z}
|
||||
|
||||
local v17 = vmg.get_noise(pos, 17)
|
||||
local temp -- calculate_temperature for node above
|
||||
if y > 0 then
|
||||
temp = v17 * 0.5 ^ (y / altitude_chill)
|
||||
else
|
||||
temp = v17 * 0.5 ^ (-y / altitude_chill) + 20 * (v12 + 1) * (1 - 2 ^ (y / lava_depth))
|
||||
end
|
||||
|
||||
if temp > snow_threshold then
|
||||
if above > 0 then
|
||||
data[ivm] = lawn
|
||||
else
|
||||
data[ivm] = c_stone
|
||||
end
|
||||
else
|
||||
if above > 0 then
|
||||
data[ivm] = snow
|
||||
else
|
||||
data[ivm] = c_stone
|
||||
end
|
||||
data[ivm2] = c_snow_layer -- set node above to snow
|
||||
end
|
||||
|
||||
if trees and math.random() < tree_density and above > 0 then -- make a tree
|
||||
|
||||
-- choose a tree from climatic and geological conditions
|
||||
if v15 < 0.6 and temp >= 0.85 and temp < 2.3 and humidity < 3 and v16 < 2 and v14 > -0.5 and v13 < 0.8 then -- Apple Tree
|
||||
local rand = math.random()
|
||||
local height = math.floor(4 + 2.5 * rand)
|
||||
local radius = 3 + rand
|
||||
if math.random(1, 4) == 1 then
|
||||
vmg.grow_apple_tree(pos, data, a, height, radius, c_tree, c_leaves, c_apple, c_air, c_ignore)
|
||||
else
|
||||
vmg.grow_tree(pos, data, a, height, radius, c_tree, c_leaves, c_air, c_ignore)
|
||||
end
|
||||
elseif v15 < 0.7 and temp >= 1.9 and humidity > 2 and v16 > 2 then -- Jungle Tree
|
||||
local rand = math.random()
|
||||
local height = math.floor(8 + 4 * rand)
|
||||
local radius = 5 + 3 * rand
|
||||
vmg.grow_jungle_tree(pos, data, a, height, radius, c_jungletree, c_jungleleaves, c_air, c_ignore)
|
||||
elseif temp > 0.38 and temp < 1 and humidity > 0.9 and v15 > 0 and v15 < 0.55 then -- Pine Tree (or Fir Tree)
|
||||
local rand = math.random()
|
||||
local height = math.floor(9 + 6 * rand)
|
||||
local radius = 4 + 2 * rand
|
||||
vmg.grow_pine_tree(pos, data, a, height, radius, c_pinetree, c_pineleaves, c_air, c_ignore)
|
||||
end
|
||||
elseif plants and math.random() < plant_density and above > 0 then -- make a plant
|
||||
if temp > 1 and temp < 1.8 and water > 0.7 and humidity > 3 and v13 > -0.4 and math.random() < 0.04 then -- Papyrus
|
||||
for i = 1, 4 do
|
||||
data[ivm+i*ystride] = c_papyrus
|
||||
end
|
||||
elseif v15 < 0.65 and temp >= 0.65 and temp < 1.5 and humidity < 2.6 and v16 < 1.5 and v13 < 0.8 and math.random() < 0.7 then -- Grass
|
||||
data[ivm2] = c_grass[math.random(1, 5)]
|
||||
elseif v15 > -0.6 and temp >= 1.8 and humidity > 2.2 and v16 > 1.8 then -- Jungle Grass
|
||||
data[ivm2] = c_junglegrass
|
||||
elseif v15 > 0.6 and v15 < 0.9 and humidity < 0.5 and temp > 1.8 and math.random() < 0.2 then
|
||||
if v16 < 0 and math.random() < 0.12 then -- Cactus
|
||||
for i = 1, 4 do
|
||||
data[ivm+i*ystride] = c_cactus
|
||||
end
|
||||
else -- Dry Shrub
|
||||
data[ivm2] = c_dryshrub
|
||||
end
|
||||
end
|
||||
end
|
||||
y = y - 1
|
||||
end
|
||||
elseif above <= 0 then
|
||||
data[ivm] = c_stone
|
||||
elseif n6[i3d_sup+above*i3d_incrY] * slopes <= y + above - mountain_ground then -- if node at "above" nodes up is not in the ground, make dirt
|
||||
if is_beach and y < beach then
|
||||
data[ivm] = c_sand
|
||||
else
|
||||
data[ivm] = dirt
|
||||
end
|
||||
else
|
||||
data[ivm] = c_stone
|
||||
end
|
||||
elseif v11 + v12 > 2 ^ (y / lava_depth) and y <= lava_max_height then
|
||||
data[ivm] = c_lava
|
||||
end
|
||||
elseif y <= water_level or river and y - 2 <= mountain_ground then -- if pos is not in the ground, and below water_level, it's an ocean
|
||||
data[ivm] = c_water
|
||||
end
|
||||
|
||||
i3d = i3d + i3d_incrY -- increment i3d by one line
|
||||
i3d_sup = i3d_sup + i3d_incrY -- idem
|
||||
end
|
||||
i2d = i2d + i2d_incrZ -- increment i2d by one Z
|
||||
-- useless to increment i3d, because increment would be 0 !
|
||||
i3d_sup = i3d_sup + i3d_sup_incrZ -- for i3d_sup, just avoid the 6 supplemental lines
|
||||
end
|
||||
i2d = i2d - i2d_decrX -- decrement the Z line previously incremented and increment by one X (1)
|
||||
i3d = i3d - i3d_decrX -- decrement the YZ plane previously incremented and increment by one X (1)
|
||||
i3d_sup = i3d_sup - i3d_sup_decrX -- idem, including the supplemental lines
|
||||
end
|
||||
vmg.execute_after_mapgen() -- needed for jungletree roots
|
||||
|
||||
local t3 = os.clock()
|
||||
if vmg.loglevel >= 2 then
|
||||
print("[Valleys Mapgen] Data collecting finished in " .. displaytime(t3-t2))
|
||||
print("[Valleys Mapgen] Writing data ...")
|
||||
end
|
||||
|
||||
-- execute voxelmanip boring stuff to write to the map
|
||||
vm:set_data(data)
|
||||
minetest.generate_ores(vm, minp, maxp)
|
||||
vm:set_lighting({day = 0, night = 0})
|
||||
vm:calc_lighting()
|
||||
vm:update_liquids()
|
||||
vm:write_to_map()
|
||||
|
||||
local t4 = os.clock()
|
||||
if vmg.loglevel >= 2 then
|
||||
print("[Valleys Mapgen] Data writing finished in " .. displaytime(t4-t3))
|
||||
end
|
||||
if vmg.loglevel >= 1 then
|
||||
print("[Valleys Mapgen] Mapgen finished in " .. displaytime(t4-t0))
|
||||
end
|
||||
end
|
||||
|
||||
dofile(vmg.path .. "/old_mapgens/2.0-trees.lua")
|
||||
|
||||
function vmg.get_humidity_raw(pos)
|
||||
local v13 = vmg.get_noise(pos, 13)
|
||||
local v15 = vmg.get_noise(pos, 15)
|
||||
local v18 = vmg.get_noise(pos, 18)
|
||||
return 2 ^ (v13 - v15 + v18 * 2)
|
||||
end
|
||||
|
||||
function vmg.get_humidity(pos)
|
||||
local y = pos.y
|
||||
local flatpos = pos2d(pos)
|
||||
local hraw = vmg.get_humidity_raw(flatpos)
|
||||
|
||||
local v1 = vmg.get_noise(flatpos, 1)
|
||||
local v3 = vmg.get_noise(flatpos, 3) ^ 2
|
||||
local base_ground = v1 + v3
|
||||
local sea_water = 0.5 ^ math.max((y - water_level) / 6, 0)
|
||||
local river_water = 0.5 ^ math.max((y - base_ground) / 3, 0)
|
||||
local water = sea_water + (1 - sea_water) * river_water
|
||||
return hraw + water
|
||||
end
|
||||
|
||||
function vmg.get_temperature(pos)
|
||||
local v12 = vmg.get_noise(pos, 12) + 1
|
||||
local v17 = vmg.get_noise(pos, 17)
|
||||
local y = pos.y
|
||||
if y > 0 then
|
||||
return v17 * 0.5 ^ (y / altitude_chill)
|
||||
else
|
||||
return v17 * 0.5 ^ (-y / altitude_chill) + 20 * v12 * (1 - 2 ^ (y / lava_depth))
|
||||
end
|
||||
end
|
||||
|
||||
function vmg.get_noise(pos, i)
|
||||
local n = vmg.noises[i]
|
||||
local noise = minetest.get_perlin(n.seed, n.octaves, n.persist, 1)
|
||||
if not pos.z then
|
||||
return noise:get2d({x = pos.x / n.spread.x, y = pos.y / n.spread.y}) * n.scale + n.offset
|
||||
else
|
||||
return noise:get3d({x = pos.x / n.spread.x, y = pos.y / n.spread.y, z = pos.z / n.spread.z}) * n.scale + n.offset
|
||||
end
|
||||
end
|
||||
|
||||
local function round(n)
|
||||
return math.floor(n + 0.5)
|
||||
end
|
||||
|
||||
function vmg.get_elevation(pos)
|
||||
local v1 = vmg.get_noise(pos, 1)
|
||||
local v2 = vmg.get_noise(pos, 2)
|
||||
local v3 = vmg.get_noise(pos, 3) ^ 2
|
||||
local v4 = vmg.get_noise(pos, 4)
|
||||
local v5 = vmg.get_noise(pos, 5)
|
||||
local base_ground = v1 + v3
|
||||
local valleys = v3 * (1 - math.exp(- (v2 / v4) ^ 2))
|
||||
local mountain_ground = base_ground + valleys
|
||||
local pos = pos3d(pos, round(mountain_ground))
|
||||
local slopes = v5 * valleys
|
||||
if vmg.get_noise(pos, 6) * slopes > pos.y - mountain_ground then
|
||||
pos.y = pos.y + 1
|
||||
while vmg.get_noise(pos, 6) * slopes > pos.y - mountain_ground do
|
||||
pos.y = pos.y + 1
|
||||
end
|
||||
return pos.y
|
||||
else
|
||||
pos.y = pos.y - 1
|
||||
while vmg.get_noise(pos, 6) * slopes <= pos.y - mountain_ground do
|
||||
pos.y = pos.y - 1
|
||||
end
|
||||
return pos.y
|
||||
end
|
||||
end
|
||||
|
||||
function vmg.spawnplayer(player)
|
||||
local angle = math.random() * math.pi * 2
|
||||
local distance = math.random() * player_max_distance
|
||||
local p_angle = {x = math.cos(angle), y = math.sin(angle)}
|
||||
local pos = {x = -p_angle.x * distance, y = -p_angle.y * distance}
|
||||
local elevation = vmg.get_elevation(pos)
|
||||
while elevation < water_level + 2 or math.abs(vmg.get_noise(pos, 2)) < river_size do
|
||||
pos.x = pos.x + p_angle.x
|
||||
pos.y = pos.y + p_angle.y
|
||||
elevation = vmg.get_elevation({x = round(pos.x), y = round(pos.y)})
|
||||
end
|
||||
pos = {x = round(pos.x), y = round(elevation + 1), z = round(pos.y)}
|
||||
player:setpos(pos)
|
||||
return true
|
||||
end
|
|
@ -0,0 +1,287 @@
|
|||
local function can_grow(pos) -- from default mod
|
||||
local node_under = minetest.get_node_or_nil({x = pos.x, y = pos.y - 1, z = pos.z})
|
||||
if not node_under then
|
||||
return false
|
||||
end
|
||||
local name_under = node_under.name
|
||||
local is_soil = minetest.get_item_group(name_under, "soil")
|
||||
if is_soil == 0 then
|
||||
return false
|
||||
end
|
||||
return true
|
||||
end
|
||||
|
||||
minetest.register_abm({
|
||||
nodenames = {"valleys_mapgen:fir_sapling"},
|
||||
interval = 14,
|
||||
chance = 50,
|
||||
action = function(pos, node)
|
||||
if not can_grow(pos) then
|
||||
return
|
||||
end
|
||||
|
||||
minetest.log("action", "A fir sapling grows into a tree at "..
|
||||
minetest.pos_to_string(pos))
|
||||
vmg.grow_fir_tree(pos)
|
||||
end
|
||||
})
|
||||
|
||||
function default.grow_tree(pos, is_apple_tree)
|
||||
local rand = math.random()
|
||||
local height = math.floor(4 + 2.5 * rand)
|
||||
local radius = 3 + rand
|
||||
|
||||
local leaves = minetest.get_content_id("default:leaves")
|
||||
local trunk = minetest.get_content_id("default:tree")
|
||||
local air = minetest.get_content_id("air")
|
||||
local ignore = minetest.get_content_id("ignore")
|
||||
local vm = minetest.get_voxel_manip()
|
||||
local emin, emax = vm:read_from_map({x = pos.x - 4, y = pos.y, z = pos.z - 4}, {x = pos.x + 4, y = pos.y + height + 4, z = pos.z + 4})
|
||||
local area = VoxelArea:new({MinEdge = emin, MaxEdge = emax})
|
||||
local data = vm:get_data()
|
||||
if is_apple_tree then
|
||||
vmg.make_apple_tree(pos, data, area, height, radius, trunk, leaves, minetest.get_content_id("default:apple"), air, ignore)
|
||||
else
|
||||
vmg.make_tree(pos, data, area, height, radius, trunk, leaves, air, ignore)
|
||||
end
|
||||
vm:set_data(data)
|
||||
vm:write_to_map()
|
||||
vm:update_map()
|
||||
end
|
||||
|
||||
function default.grow_jungle_tree(pos)
|
||||
local rand = math.random()
|
||||
local height = math.floor(8 + 4 * rand)
|
||||
local radius = 5 + 3 * rand
|
||||
|
||||
local leaves = minetest.get_content_id("default:jungleleaves")
|
||||
local trunk = minetest.get_content_id("default:jungletree")
|
||||
local air = minetest.get_content_id("air")
|
||||
local ignore = minetest.get_content_id("ignore")
|
||||
local vm = minetest.get_voxel_manip()
|
||||
local emin, emax = vm:read_from_map({x = pos.x - 8, y = pos.y - 1, z = pos.z - 8}, {x = pos.x + 8, y = pos.y + height + 5, z = pos.z + 8})
|
||||
local area = VoxelArea:new({MinEdge = emin, MaxEdge = emax})
|
||||
local data = vm:get_data()
|
||||
vmg.make_jungle_tree(pos, data, area, height, radius, trunk, leaves, air, ignore)
|
||||
vmg.execute_after_mapgen()
|
||||
vm:set_data(data)
|
||||
vm:write_to_map()
|
||||
vm:update_map()
|
||||
end
|
||||
|
||||
function default.grow_pine_tree(pos)
|
||||
local rand = math.random()
|
||||
local height = math.floor(9 + 6 * rand)
|
||||
local radius = 4 + 2 * rand
|
||||
|
||||
local leaves = minetest.get_content_id("default:pine_needles")
|
||||
local trunk = minetest.get_content_id("default:pinetree")
|
||||
local air = minetest.get_content_id("air")
|
||||
local ignore = minetest.get_content_id("ignore")
|
||||
local vm = minetest.get_voxel_manip()
|
||||
local emin, emax = vm:read_from_map({x = pos.x - 6, y = pos.y - 1, z = pos.z - 6}, {x = pos.x + 6, y = pos.y + height + 2, z = pos.z + 6})
|
||||
local area = VoxelArea:new({MinEdge = emin, MaxEdge = emax})
|
||||
local data = vm:get_data()
|
||||
vmg.make_pine_tree(pos, data, area, height, radius, trunk, leaves, air, ignore)
|
||||
vm:set_data(data)
|
||||
vm:write_to_map()
|
||||
vm:update_map()
|
||||
end
|
||||
|
||||
function vmg.grow_fir_tree(pos)
|
||||
local rand = math.random()
|
||||
local height = math.floor(9 + 6 * rand)
|
||||
local radius = 4 + 2 * rand
|
||||
|
||||
local leaves = minetest.get_content_id("valleys_mapgen:fir_needles")
|
||||
local trunk = minetest.get_content_id("valleys_mapgen:fir_tree")
|
||||
local air = minetest.get_content_id("air")
|
||||
local ignore = minetest.get_content_id("ignore")
|
||||
local vm = minetest.get_voxel_manip()
|
||||
local emin, emax = vm:read_from_map({x = pos.x - 6, y = pos.y - 1, z = pos.z - 6}, {x = pos.x + 6, y = pos.y + height + 2, z = pos.z + 6})
|
||||
local area = VoxelArea:new({MinEdge = emin, MaxEdge = emax})
|
||||
local data = vm:get_data()
|
||||
vmg.make_fir_tree(pos, data, area, height, radius, trunk, leaves, air, ignore)
|
||||
vm:set_data(data)
|
||||
vm:write_to_map()
|
||||
vm:update_map()
|
||||
end
|
||||
|
||||
function vmg.make_tree(pos, data, area, height, radius, trunk, leaves, air, ignore)
|
||||
if vmg.loglevel >= 3 then
|
||||
print("[Valleys Mapgen] Generating tree at " .. minetest.pos_to_string(pos) .. " ...")
|
||||
end
|
||||
local ystride = area.ystride
|
||||
local iv = area:indexp(pos)
|
||||
for i = 1, height do
|
||||
data[iv] = trunk
|
||||
iv = iv + ystride
|
||||
end
|
||||
local np = {offset = 0.8, scale = 0.4, spread = {x = 8, y = 4, z = 8}, octaves = 3, persist = 0.5}
|
||||
pos.y = pos.y + height - 1
|
||||
vmg.make_leavesblob(pos, data, area, leaves, air, ignore, {x = radius, y = radius, z = radius}, np)
|
||||
end
|
||||
|
||||
function vmg.make_apple_tree(pos, data, area, height, radius, trunk, leaves, fruit, air, ignore)
|
||||
if vmg.loglevel >= 3 then
|
||||
print("[Valleys Mapgen] Generating apple tree at " .. minetest.pos_to_string(pos) .. " ...")
|
||||
end
|
||||
local ystride = area.ystride
|
||||
local iv = area:indexp(pos)
|
||||
for i = 1, height do
|
||||
data[iv] = trunk
|
||||
iv = iv + ystride
|
||||
end
|
||||
local np = {offset = 0.8, scale = 0.4, spread = {x = 8, y = 4, z = 8}, octaves = 3, persist = 0.5}
|
||||
pos.y = pos.y + height - 1
|
||||
vmg.make_leavesblob(pos, data, area, leaves, air, ignore, {x = radius, y = radius, z = radius}, np, 0.06, fruit)
|
||||
end
|
||||
|
||||
local function make_jungle_root(x0, y0, z0, data, area, tree, air)
|
||||
local ystride = area.ystride
|
||||
local ybot = y0 - 1
|
||||
for x = x0 - 1, x0 + 1 do
|
||||
for z = z0 - 1, z0 + 1 do
|
||||
local iv = area:index(x, ybot, z)
|
||||
for i = 0, 5 do
|
||||
if data[iv] == air then
|
||||
if math.random() < 0.6 then
|
||||
data[iv-ystride] = tree -- make jungle tree below
|
||||
if math.random() < 0.6 then
|
||||
data[iv] = tree -- make jungle tree at this air node
|
||||
end
|
||||
end
|
||||
break
|
||||
end
|
||||
iv = iv + ystride
|
||||
end
|
||||
end
|
||||
end
|
||||
end
|
||||
|
||||
function vmg.make_jungle_tree(pos, data, area, height, radius, trunk, leaves, air, ignore)
|
||||
if vmg.loglevel >= 3 then
|
||||
print("[Valleys Mapgen] Generating jungle tree at " .. minetest.pos_to_string(pos) .. " ...")
|
||||
end
|
||||
local ystride = area.ystride
|
||||
local iv = area:indexp(pos)
|
||||
for i = 1, height do
|
||||
data[iv] = trunk
|
||||
iv = iv + ystride
|
||||
end
|
||||
vmg.register_after_mapgen(make_jungle_root, pos.x, pos.y, pos.z, data, area, trunk, air)
|
||||
local np = {offset = 0.8, scale = 0.4, spread = {x = 8, y = 4, z = 8}, octaves = 3, persist = 0.8}
|
||||
pos.y = pos.y + height
|
||||
vmg.make_leavesblob(pos, data, area, leaves, air, ignore, {x = radius, y = radius * 0.5, z = radius}, np)
|
||||
end
|
||||
|
||||
function vmg.make_fir_tree(pos, data, area, height, radius, trunk, leaves, air, ignore)
|
||||
if vmg.loglevel >= 3 then
|
||||
print("[Valleys Mapgen] Generating fir tree at " .. minetest.pos_to_string(pos) .. " ...")
|
||||
end
|
||||
local ystride = area.ystride
|
||||
local iv = area:indexp(pos)
|
||||
for i = 1, height do
|
||||
data[iv] = trunk
|
||||
iv = iv + ystride
|
||||
end
|
||||
|
||||
-- add leaves on the top (4% 0 ; 36% 1 ; 60% 2)
|
||||
local rand = math.random()
|
||||
if rand < 0.96 then
|
||||
data[iv] = leaves
|
||||
if rand < 0.60 then
|
||||
iv = iv + ystride
|
||||
data[iv] = leaves
|
||||
end
|
||||
end
|
||||
|
||||
-- make several leaves rings
|
||||
local max_height = pos.y + height
|
||||
local min_height = pos.y + math.floor((0.2 + 0.3 * math.random()) * height)
|
||||
local radius_increment = (radius - 1.2) / (max_height - min_height)
|
||||
local np = {offset = 0.8, scale = 0.4, spread = {x = 12, y = 4, z = 12}, octaves = 3, persist = 0.8}
|
||||
|
||||
pos.y = max_height - 1
|
||||
while pos.y >= min_height do
|
||||
local ring_radius = (max_height - pos.y) * radius_increment + 1.2
|
||||
vmg.make_leavesblob(pos, data, area, leaves, air, ignore, {x = ring_radius, y = 2, z = ring_radius}, np)
|
||||
pos.y = pos.y - math.random(2, 3)
|
||||
end
|
||||
end
|
||||
|
||||
function vmg.make_pine_tree(pos, data, area, height, radius, trunk, leaves, air, ignore)
|
||||
if vmg.loglevel >= 3 then
|
||||
print("[Valleys Mapgen] Generating pine tree at " .. minetest.pos_to_string(pos) .. " ...")
|
||||
end
|
||||
local ystride = area.ystride
|
||||
local iv = area:indexp(pos)
|
||||
for i = 1, height do
|
||||
data[iv] = trunk
|
||||
iv = iv + ystride
|
||||
end
|
||||
|
||||
-- add leaves on the top (4% 0 ; 36% 1 ; 60% 2)
|
||||
local rand = math.random()
|
||||
if rand < 0.96 then
|
||||
data[iv] = leaves
|
||||
if rand < 0.60 then
|
||||
iv = iv + ystride
|
||||
data[iv] = leaves
|
||||
end
|
||||
end
|
||||
|
||||
local np = {offset = 0.8, scale = 0.3, spread = {x = 8, y = 4, z = 8}, octaves = 3, persist = 1}
|
||||
local min_height = pos.y + math.floor((0.4 + 0.2 * math.random()) * height)
|
||||
local midradius = radius / 2
|
||||
|
||||
pos.y = pos.y + height - 1
|
||||
vmg.make_leavesblob(pos, data, area, leaves, air, ignore, {x = radius, y = 1.5, z = radius}, np)
|
||||
while pos.y >= min_height do
|
||||
local angle, distance = math.random() * 2 * math.pi, math.random() * midradius
|
||||
local cos, sin = math.cos(angle) * distance, math.sin(angle) * distance
|
||||
local bpos = {x = pos.x + cos, y = pos.y, z = pos.z + sin}
|
||||
vmg.make_leavesblob(bpos, data, area, leaves, air, ignore, {x = midradius, y = 1.5, z = midradius}, np)
|
||||
pos.y = pos.y - math.random(1, 2)
|
||||
end
|
||||
end
|
||||
|
||||
function vmg.make_leavesblob(pos, data, area, leaves, air, ignore, radius, np, fruit_chance, fruit)
|
||||
local count = 0
|
||||
fruit_chance = fruit_chance or 0
|
||||
|
||||
np.seed = math.random(0, 16777215)
|
||||
local minp = vector.subtract(pos, radius)
|
||||
local maxp = vector.add(pos, radius)
|
||||
local int_minp = {x = math.floor(minp.x), y = math.floor(minp.y), z = math.floor(minp.z)}
|
||||
local int_maxp = {x = math.ceil(maxp.x), y = math.ceil(maxp.y), z = math.ceil(maxp.z)}
|
||||
|
||||
local length = vector.subtract(int_maxp, int_minp)
|
||||
local chulens = vector.add(length, 1)
|
||||
local obj = minetest.get_perlin_map(np, chulens)
|
||||
local pmap = obj:get3dMap_flat(minp)
|
||||
local i = 1
|
||||
for x = int_minp.x, int_maxp.x do
|
||||
local xval = ((x - pos.x) / radius.x) ^ 2
|
||||
for y = int_minp.y, int_maxp.y do
|
||||
local yval = ((y - pos.y) / radius.y) ^ 2
|
||||
for z = int_minp.z, int_maxp.z do
|
||||
local zval = ((z - pos.z) / radius.z) ^ 2
|
||||
local dist = math.sqrt(xval + yval + zval)
|
||||
local nval = pmap[i]
|
||||
if nval > dist then
|
||||
local iv = area:index(x, y, z)
|
||||
if data[iv] == air or data[iv] == ignore then
|
||||
count = count + 1
|
||||
if math.random() < fruit_chance then
|
||||
data[iv] = fruit
|
||||
else
|
||||
data[iv] = leaves
|
||||
end
|
||||
end
|
||||
end
|
||||
i = i + 1
|
||||
end
|
||||
end
|
||||
end
|
||||
end
|
|
@ -0,0 +1,532 @@
|
|||
-- Mapgen 2.1
|
||||
-- Saturday July 4, 2015
|
||||
|
||||
vmg.noises = {
|
||||
|
||||
-- Noise 1 : Base Ground Height 2D
|
||||
{offset = -10, scale = 50, seed = 5202, spread = {x = 1024, y = 1024, z = 1024}, octaves = 6, persist = 0.4, lacunarity = 2},
|
||||
|
||||
-- Noise 2 : Valleys (River where around zero) 2D
|
||||
{offset = 0, scale = 1, seed = -6050, spread = {x = 256, y = 256, z = 256}, octaves = 5, persist = 0.6, lacunarity = 2},
|
||||
|
||||
-- Noise 3 : Valleys Depth 2D
|
||||
{offset = 5, scale = 4, seed = -1914, spread = {x = 512, y = 512, z = 512}, octaves = 1, persist = 1, lacunarity = 2},
|
||||
|
||||
-- Noise 4 : Valleys Profile (Higher values = Larger valleys) 2D
|
||||
{offset = 0.6, scale = 0.5, seed = 777, spread = {x = 512, y = 512, z = 512}, octaves = 1, persist = 1, lacunarity = 2},
|
||||
|
||||
-- Noise 5 : Inter-valleys slopes 2D
|
||||
{offset = 0.5, scale = 0.5, seed = 746, spread = {x = 128, y = 128, z = 128}, octaves = 1, persist = 1, lacunarity = 2},
|
||||
|
||||
-- Noise 6 : Inter-valleys filling 3D
|
||||
{offset = 0, scale = 1, seed = 1993, spread = {x = 256, y = 512, z = 256}, octaves = 6, persist = 0.8, lacunarity = 2},
|
||||
|
||||
-- Noise 7 : Dirt thickness 2D
|
||||
{offset = 3, scale = 1.75, seed = 1605, spread = {x = 256, y = 256, z = 256}, octaves = 3, persist = 0.5, lacunarity = 2},
|
||||
|
||||
-- Noise 8 : Caves I 3D
|
||||
{offset = 0, scale = 1, seed = -4640, spread = {x = 32, y = 32, z = 32}, octaves = 4, persist = 0.5, lacunarity = 2},
|
||||
|
||||
-- Noise 9 : Caves II 3D
|
||||
{offset = 0, scale = 1, seed = 8804, spread = {x = 32, y = 32, z = 32}, octaves = 4, persist = 0.5, lacunarity = 2},
|
||||
|
||||
-- Noise 10 : Caves III 3D
|
||||
{offset = 0, scale = 1, seed = -4780, spread = {x = 32, y = 32, z = 32}, octaves = 4, persist = 0.5, lacunarity = 2},
|
||||
|
||||
-- Noise 11 : Caves IV and Lava I 3D
|
||||
{offset = 0, scale = 1, seed = -9969, spread = {x = 32, y = 32, z = 32}, octaves = 4, persist = 0.5, lacunarity = 2},
|
||||
|
||||
-- Noise 12 : Lava II (Geologic heat) 3D
|
||||
{offset = 0, scale = 1, seed = 3314, spread = {x = 64, y = 64, z = 64}, octaves = 4, persist = 0.5, lacunarity = 2},
|
||||
|
||||
-- Noise 13 : Clayey dirt noise 2D
|
||||
{offset = 0, scale = 1, seed = 2835, spread = {x = 256, y = 256, z = 256}, octaves = 5, persist = 0.5, lacunarity = 4},
|
||||
|
||||
-- Noise 14 : Silty dirt noise 2D
|
||||
{offset = 0, scale = 1, seed = 6674, spread = {x = 256, y = 256, z = 256}, octaves = 5, persist = 0.5, lacunarity = 4},
|
||||
|
||||
-- Noise 15 : Sandy dirt noise 2D
|
||||
{offset = 0, scale = 1, seed = 6940, spread = {x = 256, y = 256, z = 256}, octaves = 5, persist = 0.5, lacunarity = 4},
|
||||
|
||||
-- Noise 16 : Beaches 2D
|
||||
{offset = 2, scale = 8, seed = 2349, spread = {x = 256, y = 256, z = 256}, octaves = 3, persist = 0.5, lacunarity = 2},
|
||||
|
||||
-- Noise 17 : Temperature (not in maps) 3D
|
||||
{offset = 2, scale = 1, seed = -1805, spread = {x = 768, y = 256, z = 768}, octaves = 4, persist = 0.5, lacunarity = 4},
|
||||
|
||||
-- Noise 18 : Humidity 2D
|
||||
{offset = 0, scale = 1, seed = -5787, spread = {x = 243, y = 243, z = 243}, octaves = 4, persist = 0.5, lacunarity = 3},
|
||||
|
||||
}
|
||||
|
||||
function vmg.noisemap(i, minp, chulens)
|
||||
local obj = minetest.get_perlin_map(vmg.noises[i], chulens)
|
||||
if minp.z then
|
||||
return obj:get3dMap_flat(minp)
|
||||
else
|
||||
return obj:get2dMap_flat(minp)
|
||||
end
|
||||
end
|
||||
|
||||
for i, n in ipairs(vmg.noises) do
|
||||
vmg.noises[i] = vmg.define("noise_" .. i, n)
|
||||
end
|
||||
|
||||
vmg.after_mapgen = {}
|
||||
|
||||
function vmg.register_after_mapgen(f, ...)
|
||||
table.insert(vmg.after_mapgen, {f = f, ...})
|
||||
end
|
||||
|
||||
function vmg.execute_after_mapgen()
|
||||
for i, params in ipairs(vmg.after_mapgen) do
|
||||
params.f(unpack(params))
|
||||
end
|
||||
vmg.after_mapgen = {}
|
||||
end
|
||||
|
||||
local river_depth = vmg.define("river_depth", 3) + 1
|
||||
local river_size = vmg.define("river_size", 5) / 100
|
||||
local caves_size = vmg.define("caves_size", 7) / 100
|
||||
local lava_depth = vmg.define("lava_depth", 2000)
|
||||
local lava_max_height = vmg.define("lava_max_height", -1)
|
||||
local altitude_chill = vmg.define("altitude_chill", 90)
|
||||
|
||||
local average_stone_level = vmg.define("average_stone_level", 180)
|
||||
local dirt_thickness = math.sqrt(average_stone_level) / (vmg.noises[7].offset + 0.5)
|
||||
local average_snow_level = vmg.define("average_snow_level", 100)
|
||||
local snow_threshold = vmg.noises[17].offset * 0.5 ^ (average_snow_level / altitude_chill)
|
||||
|
||||
local player_max_distance = vmg.define("player_max_distance", 450)
|
||||
|
||||
local clay_threshold = vmg.define("clay_threshold", 1)
|
||||
local silt_threshold = vmg.define("silt_threshold", 1)
|
||||
local sand_threshold = vmg.define("sand_threshold", 0.75)
|
||||
local dirt_threshold = vmg.define("dirt_threshold", 0.5)
|
||||
|
||||
local tree_density = vmg.define("tree_density", 5) / 100
|
||||
local trees = vmg.define("trees", true)
|
||||
local plant_density = vmg.define("plant_density", 32) / 100
|
||||
local plants = vmg.define("plants", true)
|
||||
|
||||
local water_level = vmg.define("water_level", 1)
|
||||
local river_water = vmg.define("river_water", true)
|
||||
|
||||
function vmg.generate(minp, maxp, seed)
|
||||
local minps, maxps = minetest.pos_to_string(minp), minetest.pos_to_string(maxp)
|
||||
if vmg.loglevel >= 2 then
|
||||
print("[Valleys Mapgen] Preparing to generate map from " .. minps .. " to " .. maxps .. " ...")
|
||||
elseif vmg.loglevel == 1 then
|
||||
print("[Valleys Mapgen] Generating map from " .. minps .. " to " .. maxps .. " ...")
|
||||
end
|
||||
local t0 = os.clock()
|
||||
|
||||
local c_stone = minetest.get_content_id("default:stone")
|
||||
local c_dirt = minetest.get_content_id("default:dirt")
|
||||
local c_lawn = minetest.get_content_id("default:dirt_with_grass")
|
||||
local c_snow = minetest.get_content_id("default:dirt_with_snow")
|
||||
local c_dirt_clay = minetest.get_content_id("valleys_mapgen:dirt_clayey")
|
||||
local c_lawn_clay = minetest.get_content_id("valleys_mapgen:dirt_clayey_with_grass")
|
||||
local c_snow_clay = minetest.get_content_id("valleys_mapgen:dirt_clayey_with_snow")
|
||||
local c_dirt_silt = minetest.get_content_id("valleys_mapgen:dirt_silty")
|
||||
local c_lawn_silt = minetest.get_content_id("valleys_mapgen:dirt_silty_with_grass")
|
||||
local c_snow_silt = minetest.get_content_id("valleys_mapgen:dirt_silty_with_snow")
|
||||
local c_dirt_sand = minetest.get_content_id("valleys_mapgen:dirt_sandy")
|
||||
local c_lawn_sand = minetest.get_content_id("valleys_mapgen:dirt_sandy_with_grass")
|
||||
local c_snow_sand = minetest.get_content_id("valleys_mapgen:dirt_sandy_with_snow")
|
||||
local c_desert_sand = minetest.get_content_id("default:desert_sand")
|
||||
local c_sand = minetest.get_content_id("default:sand")
|
||||
local c_gravel = minetest.get_content_id("default:gravel")
|
||||
local c_silt = minetest.get_content_id("valleys_mapgen:silt")
|
||||
local c_clay = minetest.get_content_id("valleys_mapgen:red_clay")
|
||||
local c_water = minetest.get_content_id("default:water_source")
|
||||
local c_riverwater = minetest.get_content_id("default:river_water_source")
|
||||
local c_lava = minetest.get_content_id("default:lava_source")
|
||||
local c_snow_layer = minetest.get_content_id("default:snow")
|
||||
|
||||
local c_tree = minetest.get_content_id("default:tree")
|
||||
local c_leaves = minetest.get_content_id("default:leaves")
|
||||
local c_apple = minetest.get_content_id("default:apple")
|
||||
local c_jungletree = minetest.get_content_id("default:jungletree")
|
||||
local c_jungleleaves = minetest.get_content_id("default:jungleleaves")
|
||||
local c_pinetree = minetest.get_content_id("default:pinetree")
|
||||
local c_pineleaves = minetest.get_content_id("default:pine_needles")
|
||||
local c_firtree = minetest.get_content_id("valleys_mapgen:fir_tree")
|
||||
local c_firleaves = minetest.get_content_id("valleys_mapgen:fir_needles")
|
||||
|
||||
local c_grass = {
|
||||
minetest.get_content_id("default:grass_1"),
|
||||
minetest.get_content_id("default:grass_2"),
|
||||
minetest.get_content_id("default:grass_3"),
|
||||
minetest.get_content_id("default:grass_4"),
|
||||
minetest.get_content_id("default:grass_5"),
|
||||
}
|
||||
local c_junglegrass = minetest.get_content_id("default:junglegrass")
|
||||
local c_dryshrub = minetest.get_content_id("default:dry_shrub")
|
||||
local c_cactus = minetest.get_content_id("default:cactus")
|
||||
local c_papyrus = minetest.get_content_id("default:papyrus")
|
||||
|
||||
local c_air = minetest.get_content_id("air")
|
||||
local c_ignore = minetest.get_content_id("ignore")
|
||||
|
||||
local vm, emin, emax = minetest.get_mapgen_object("voxelmanip")
|
||||
local data = vm:get_data()
|
||||
local a = VoxelArea:new({MinEdge = emin, MaxEdge = emax})
|
||||
local ystride = a.ystride
|
||||
|
||||
local chulens = vector.add(vector.subtract(maxp, minp), 1)
|
||||
local chulens_sup = {x = chulens.x, y = chulens.y + 6, z = chulens.z}
|
||||
local minp2d = pos2d(minp)
|
||||
|
||||
local t1 = os.clock()
|
||||
if vmg.loglevel >= 2 then
|
||||
print("[Valleys Mapgen] Mapgen preparation finished in " .. displaytime(t1-t0))
|
||||
print("[Valleys Mapgen] Calculating noises ...")
|
||||
end
|
||||
|
||||
local n1 = vmg.noisemap(1, minp2d, chulens)
|
||||
local n2 = vmg.noisemap(2, minp2d, chulens)
|
||||
local n3 = vmg.noisemap(3, minp2d, chulens)
|
||||
local n4 = vmg.noisemap(4, minp2d, chulens)
|
||||
local n5 = vmg.noisemap(5, minp2d, chulens)
|
||||
local n6 = vmg.noisemap(6, minp, chulens_sup)
|
||||
local n7 = vmg.noisemap(7, minp2d, chulens)
|
||||
local n8 = vmg.noisemap(8, minp, chulens)
|
||||
local n9 = vmg.noisemap(9, minp, chulens)
|
||||
local n10 = vmg.noisemap(10, minp, chulens)
|
||||
local n11 = vmg.noisemap(11, minp, chulens)
|
||||
local n12 = vmg.noisemap(12, minp, chulens)
|
||||
local n13 = vmg.noisemap(13, minp2d, chulens)
|
||||
local n14 = vmg.noisemap(14, minp2d, chulens)
|
||||
local n15 = vmg.noisemap(15, minp2d, chulens)
|
||||
local n16 = vmg.noisemap(16, minp2d, chulens)
|
||||
local n18 = vmg.noisemap(18, minp2d, chulens)
|
||||
|
||||
local t2 = os.clock()
|
||||
if vmg.loglevel >= 2 then
|
||||
print("[Valleys Mapgen] Noises calculation finished in " .. displaytime(t2-t1))
|
||||
print("[Valleys Mapgen] Collecting data ...")
|
||||
end
|
||||
|
||||
local i2d = 1 -- index for 2D noises
|
||||
local i3d_sup = 1 -- index for noise 6 which has a special size
|
||||
local i3d = 1 -- index for 3D noises
|
||||
|
||||
-- Calculate increments
|
||||
local i2d_incrZ = chulens.z
|
||||
local i2d_decrX = chulens.x * chulens.z - 1
|
||||
local i3d_incrY = chulens.y
|
||||
local i3d_sup_incrZ = 6 * chulens.y
|
||||
local i3d_decrX = chulens.x * chulens.y * chulens.z - 1
|
||||
local i3d_sup_decrX = chulens.x * (chulens.y + 6) * chulens.z - 1
|
||||
|
||||
for x = minp.x, maxp.x do -- for each YZ plane
|
||||
for z = minp.z, maxp.z do -- for each vertical line in this plane
|
||||
local v1, v2, v3, v4, v5, v7, v13, v14, v15, v16, v18 = n1[i2d], n2[i2d], n3[i2d], n4[i2d], n5[i2d], n7[i2d], n13[i2d], n14[i2d], n15[i2d], n16[i2d], n18[i2d] -- n for noise, v for value
|
||||
v3 = v3 ^ 2 -- v3 must be > 0 and by the square there are high mountains but the median valleys depth is small.
|
||||
local base_ground = v1 + v3 -- v3 is here because terrain is generally higher when valleys are deep (mountains)
|
||||
v2 = math.abs(v2) - river_size
|
||||
local river = v2 < 0
|
||||
local valleys = v3 * (1 - math.exp(- (v2 / v4) ^ 2)) -- use the curve of the function 1−exp(−(x/a)²) to modelise valleys. Making "a" varying 0 < a ≤ 1 will change the shape of the valleys. Try it with a geometry software ! (here x = v2 and a = v4)
|
||||
local mountain_ground = base_ground + valleys
|
||||
local slopes = v5 * valleys
|
||||
|
||||
if river then
|
||||
local depth = river_depth * math.sqrt(1 - (v2 / river_size + 1) ^ 2) -- use the curve of the function −sqrt(1-x²) which modelizes a circle.
|
||||
mountain_ground = math.min(math.max(base_ground - depth, water_level - 6), mountain_ground)
|
||||
slopes = 0
|
||||
end
|
||||
|
||||
-- Choose biome
|
||||
local dirt = c_dirt
|
||||
local lawn = c_lawn
|
||||
local snow = c_snow
|
||||
local max = math.max(v13, v14, v15) -- the biome is the maximal of these 3 values, if bigger than 0.5. Else, make normal dirt.
|
||||
if max > dirt_threshold then
|
||||
if v13 == max then
|
||||
if v13 > clay_threshold then
|
||||
dirt = c_clay
|
||||
lawn = c_clay
|
||||
snow = c_clay
|
||||
else
|
||||
dirt = c_dirt_clay
|
||||
lawn = c_lawn_clay
|
||||
snow = c_snow_clay
|
||||
end
|
||||
elseif v14 == max then
|
||||
if v14 > silt_threshold then
|
||||
dirt = c_silt
|
||||
lawn = c_silt
|
||||
snow = c_silt
|
||||
else
|
||||
dirt = c_dirt_silt
|
||||
lawn = c_lawn_silt
|
||||
snow = c_snow_silt
|
||||
end
|
||||
else
|
||||
if v15 > sand_threshold then
|
||||
dirt = c_desert_sand
|
||||
lawn = c_desert_sand
|
||||
snow = c_desert_sand
|
||||
else
|
||||
dirt = c_dirt_sand
|
||||
lawn = c_lawn_sand
|
||||
snow = c_snow_sand
|
||||
end
|
||||
end
|
||||
end
|
||||
local is_beach = v15 > 0 and v16 > 0
|
||||
local beach = v15 * v16 + water_level -- the y coordinate below which dirt is replaced by beach sand
|
||||
|
||||
-- raw humidity
|
||||
local hraw = 2 ^ (v13 - v15 + v18 * 2)
|
||||
|
||||
for y = minp.y, maxp.y do -- for each node in vertical line
|
||||
local ivm = a:index(x, y, z)
|
||||
local v6, v8, v9, v10, v11, v12 = n6[i3d_sup], n8[i3d], n9[i3d], n10[i3d], n11[i3d], n12[i3d]
|
||||
local is_cave = v8 ^ 2 + v9 ^ 2 + v10 ^ 2 + v11 ^ 2 < caves_size
|
||||
if v6 * slopes > y - mountain_ground then -- if pos is in the ground
|
||||
if not is_cave then
|
||||
local above = math.ceil(
|
||||
v7 + math.random() - math.sqrt(math.abs(y)) / dirt_thickness -- The following code will look for air at this many nodes up. If any, make dirt, else, make stone. So, it's the dirt layer thickness.
|
||||
)
|
||||
if y >= water_level and n6[i3d_sup+i3d_incrY] * slopes <= y + 1 - mountain_ground and not river then
|
||||
if is_beach and y < beach then
|
||||
data[ivm] = c_sand
|
||||
else -- if node above is not in the ground, place lawn
|
||||
|
||||
-- calculate humidity
|
||||
local sea_water = 0.5 ^ math.max((y - water_level) / 6, 0)
|
||||
local river_water = 0.5 ^ math.max((y - base_ground) / 3, 0)
|
||||
local water = sea_water + (1 - sea_water) * river_water
|
||||
local humidity = hraw + water
|
||||
|
||||
local ivm2 = ivm + ystride
|
||||
y = y + 1
|
||||
local pos = {x = x, y = y, z = z}
|
||||
|
||||
local v17 = vmg.get_noise(pos, 17)
|
||||
local temp -- calculate_temperature for node above
|
||||
if y > 0 then
|
||||
temp = v17 * 0.5 ^ (y / altitude_chill)
|
||||
else
|
||||
temp = v17 * 0.5 ^ (-y / altitude_chill) + 20 * (v12 + 1) * (1 - 2 ^ (y / lava_depth))
|
||||
end
|
||||
|
||||
if temp > snow_threshold then
|
||||
if above > 0 then
|
||||
data[ivm] = lawn
|
||||
else
|
||||
data[ivm] = c_stone
|
||||
end
|
||||
else
|
||||
if above > 0 then
|
||||
data[ivm] = snow
|
||||
else
|
||||
data[ivm] = c_stone
|
||||
end
|
||||
data[ivm2] = c_snow_layer -- set node above to snow
|
||||
end
|
||||
|
||||
if trees and math.random() < tree_density and above > 0 then -- make a tree
|
||||
|
||||
-- choose a tree from climatic and geological conditions
|
||||
if v14 < 0 and temp < 1.5 and temp >= 0.90 and humidity < 1 and v15 < 0.8 and math.abs(v13) < 0.2 and math.random() < 0.3 then -- Pine Tree
|
||||
local rand = math.random()
|
||||
local height = math.floor(9 + 6 * rand)
|
||||
local radius = 4 + 2 * rand
|
||||
vmg.make_pine_tree(pos, data, a, height, radius, c_pinetree, c_pineleaves, c_air, c_ignore)
|
||||
elseif v15 < 0.6 and temp >= 0.85 and temp < 2.3 and humidity < 3 and v16 < 2 and v14 > -0.5 and v13 < 0.8 then -- Apple Tree
|
||||
local rand = math.random()
|
||||
local height = math.floor(4 + 2.5 * rand)
|
||||
local radius = 3 + rand
|
||||
if math.random(1, 4) == 1 then
|
||||
vmg.make_apple_tree(pos, data, a, height, radius, c_tree, c_leaves, c_apple, c_air, c_ignore)
|
||||
else
|
||||
vmg.make_tree(pos, data, a, height, radius, c_tree, c_leaves, c_air, c_ignore)
|
||||
end
|
||||
elseif v15 < 0.7 and temp >= 1.9 and humidity > 2 and v16 > 2 then -- Jungle Tree
|
||||
local rand = math.random()
|
||||
local height = math.floor(8 + 4 * rand)
|
||||
local radius = 5 + 3 * rand
|
||||
vmg.make_jungle_tree(pos, data, a, height, radius, c_jungletree, c_jungleleaves, c_air, c_ignore)
|
||||
elseif temp > 0.38 and temp < 1 and humidity > 0.9 and v15 > 0 and v15 < 0.55 then -- Fir Tree
|
||||
local rand = math.random()
|
||||
local height = math.floor(9 + 6 * rand)
|
||||
local radius = 4 + 2 * rand
|
||||
vmg.make_fir_tree(pos, data, a, height, radius, c_firtree, c_firleaves, c_air, c_ignore)
|
||||
end
|
||||
elseif plants and math.random() < plant_density and above > 0 then -- make a plant
|
||||
if temp > 1 and temp < 1.8 and water > 0.7 and humidity > 3 and v13 > -0.4 and math.random() < 0.04 then -- Papyrus
|
||||
for i = 1, 4 do
|
||||
data[ivm+i*ystride] = c_papyrus
|
||||
end
|
||||
elseif v15 < 0.65 and temp >= 0.65 and temp < 1.5 and humidity < 2.6 and v16 < 1.5 and v13 < 0.8 and math.random() < 0.7 then -- Grass
|
||||
data[ivm2] = c_grass[math.random(1, 5)]
|
||||
elseif v15 > -0.6 and temp >= 1.8 and humidity > 2.2 and v16 > 1.8 then -- Jungle Grass
|
||||
data[ivm2] = c_junglegrass
|
||||
elseif v15 > 0.65 and humidity < 0.5 and math.random() < 0.2 then
|
||||
if v16 > 0 and temp > 1.6 and math.random() < 0.12 then -- Cactus
|
||||
for i = 1, 4 do
|
||||
data[ivm+i*ystride] = c_cactus
|
||||
end
|
||||
elseif temp > 1.2 then -- Dry Shrub
|
||||
data[ivm2] = c_dryshrub
|
||||
end
|
||||
end
|
||||
end
|
||||
y = y - 1
|
||||
end
|
||||
elseif above <= 0 then
|
||||
data[ivm] = c_stone
|
||||
elseif n6[i3d_sup+above*i3d_incrY] * slopes <= y + above - mountain_ground then -- if node at "above" nodes up is not in the ground, make dirt
|
||||
if is_beach and y < beach then
|
||||
data[ivm] = c_sand
|
||||
else
|
||||
data[ivm] = dirt
|
||||
end
|
||||
else
|
||||
data[ivm] = c_stone
|
||||
end
|
||||
elseif v11 + v12 > 2 ^ (y / lava_depth) and y <= lava_max_height then
|
||||
data[ivm] = c_lava
|
||||
end
|
||||
elseif y <= water_level then -- if pos is not in the ground, and below water_level, it's an ocean
|
||||
data[ivm] = c_water
|
||||
elseif river and y + 1 < base_ground then
|
||||
if river_water then
|
||||
data[ivm] = c_riverwater
|
||||
else
|
||||
data[ivm] = c_water
|
||||
end
|
||||
end
|
||||
|
||||
i3d = i3d + i3d_incrY -- increment i3d by one line
|
||||
i3d_sup = i3d_sup + i3d_incrY -- idem
|
||||
end
|
||||
i2d = i2d + i2d_incrZ -- increment i2d by one Z
|
||||
-- useless to increment i3d, because increment would be 0 !
|
||||
i3d_sup = i3d_sup + i3d_sup_incrZ -- for i3d_sup, just avoid the 6 supplemental lines
|
||||
end
|
||||
i2d = i2d - i2d_decrX -- decrement the Z line previously incremented and increment by one X (1)
|
||||
i3d = i3d - i3d_decrX -- decrement the YZ plane previously incremented and increment by one X (1)
|
||||
i3d_sup = i3d_sup - i3d_sup_decrX -- idem, including the supplemental lines
|
||||
end
|
||||
vmg.execute_after_mapgen() -- needed for jungletree roots
|
||||
|
||||
local t3 = os.clock()
|
||||
if vmg.loglevel >= 2 then
|
||||
print("[Valleys Mapgen] Data collecting finished in " .. displaytime(t3-t2))
|
||||
print("[Valleys Mapgen] Writing data ...")
|
||||
end
|
||||
|
||||
-- execute voxelmanip boring stuff to write to the map
|
||||
vm:set_data(data)
|
||||
minetest.generate_ores(vm, minp, maxp)
|
||||
vm:set_lighting({day = 0, night = 0})
|
||||
vm:calc_lighting()
|
||||
vm:update_liquids()
|
||||
vm:write_to_map()
|
||||
|
||||
local t4 = os.clock()
|
||||
if vmg.loglevel >= 2 then
|
||||
print("[Valleys Mapgen] Data writing finished in " .. displaytime(t4-t3))
|
||||
end
|
||||
if vmg.loglevel >= 1 then
|
||||
print("[Valleys Mapgen] Mapgen finished in " .. displaytime(t4-t0))
|
||||
end
|
||||
end
|
||||
|
||||
dofile(vmg.path .. "/old_mapgens/2.1-trees.lua")
|
||||
|
||||
function vmg.get_humidity_raw(pos)
|
||||
local v13 = vmg.get_noise(pos, 13)
|
||||
local v15 = vmg.get_noise(pos, 15)
|
||||
local v18 = vmg.get_noise(pos, 18)
|
||||
return 2 ^ (v13 - v15 + v18 * 2)
|
||||
end
|
||||
|
||||
function vmg.get_humidity(pos)
|
||||
local y = pos.y
|
||||
local flatpos = pos2d(pos)
|
||||
local hraw = vmg.get_humidity_raw(flatpos)
|
||||
|
||||
local v1 = vmg.get_noise(flatpos, 1)
|
||||
local v3 = vmg.get_noise(flatpos, 3) ^ 2
|
||||
local base_ground = v1 + v3
|
||||
local sea_water = 0.5 ^ math.max((y - water_level) / 6, 0)
|
||||
local river_water = 0.5 ^ math.max((y - base_ground) / 3, 0)
|
||||
local water = sea_water + (1 - sea_water) * river_water
|
||||
return hraw + water
|
||||
end
|
||||
|
||||
function vmg.get_temperature(pos)
|
||||
local v12 = vmg.get_noise(pos, 12) + 1
|
||||
local v17 = vmg.get_noise(pos, 17)
|
||||
local y = pos.y
|
||||
if y > 0 then
|
||||
return v17 * 0.5 ^ (y / altitude_chill)
|
||||
else
|
||||
return v17 * 0.5 ^ (-y / altitude_chill) + 20 * v12 * (1 - 2 ^ (y / lava_depth))
|
||||
end
|
||||
end
|
||||
|
||||
function vmg.get_noise(pos, i)
|
||||
local n = vmg.noises[i]
|
||||
local noise = minetest.get_perlin(n.seed, n.octaves, n.persist, 1)
|
||||
if not pos.z then
|
||||
return noise:get2d({x = pos.x / n.spread.x, y = pos.y / n.spread.y}) * n.scale + n.offset
|
||||
else
|
||||
return noise:get3d({x = pos.x / n.spread.x, y = pos.y / n.spread.y, z = pos.z / n.spread.z}) * n.scale + n.offset
|
||||
end
|
||||
end
|
||||
|
||||
local function round(n)
|
||||
return math.floor(n + 0.5)
|
||||
end
|
||||
|
||||
function vmg.get_elevation(pos)
|
||||
local v1 = vmg.get_noise(pos, 1)
|
||||
local v2 = math.abs(vmg.get_noise(pos, 2)) - river_size
|
||||
local v3 = vmg.get_noise(pos, 3) ^ 2
|
||||
local base_ground = v1 + v3
|
||||
if v2 < 0 then
|
||||
return math.ceil(base_ground), true
|
||||
end
|
||||
local v4 = vmg.get_noise(pos, 4)
|
||||
local v5 = vmg.get_noise(pos, 5)
|
||||
local base_ground = v1 + v3
|
||||
local valleys = v3 * (1 - math.exp(- (v2 / v4) ^ 2))
|
||||
local mountain_ground = base_ground + valleys
|
||||
local pos = pos3d(pos, round(mountain_ground))
|
||||
local slopes = v5 * valleys
|
||||
if vmg.get_noise(pos, 6) * slopes > pos.y - mountain_ground then
|
||||
pos.y = pos.y + 1
|
||||
while vmg.get_noise(pos, 6) * slopes > pos.y - mountain_ground do
|
||||
pos.y = pos.y + 1
|
||||
end
|
||||
return pos.y, false
|
||||
else
|
||||
pos.y = pos.y - 1
|
||||
while vmg.get_noise(pos, 6) * slopes <= pos.y - mountain_ground do
|
||||
pos.y = pos.y - 1
|
||||
end
|
||||
return pos.y, false
|
||||
end
|
||||
end
|
||||
|
||||
function vmg.spawnplayer(player)
|
||||
local angle = math.random() * math.pi * 2
|
||||
local distance = math.random() * player_max_distance
|
||||
local p_angle = {x = math.cos(angle), y = math.sin(angle)}
|
||||
local pos = {x = -p_angle.x * distance, y = -p_angle.y * distance}
|
||||
local elevation, river = vmg.get_elevation(pos)
|
||||
while elevation < water_level + 2 or river do
|
||||
pos.x = pos.x + p_angle.x
|
||||
pos.y = pos.y + p_angle.y
|
||||
elevation, river = vmg.get_elevation({x = round(pos.x), y = round(pos.y)})
|
||||
end
|
||||
pos = {x = round(pos.x), y = round(elevation + 1), z = round(pos.y)}
|
||||
player:setpos(pos)
|
||||
return true
|
||||
end
|
|
@ -0,0 +1,132 @@
|
|||
vmg.settings = Settings(minetest.get_worldpath() .. "/vmg.conf")
|
||||
|
||||
local function define_str(flag, default, write_to_config)
|
||||
local value = vmg.settings:get(flag)
|
||||
if value then
|
||||
return value, true
|
||||
else
|
||||
local on_config = minetest.setting_get("vmg_" .. flag)
|
||||
if on_config then
|
||||
vmg.settings:set(flag, on_config)
|
||||
return on_config, false
|
||||
else
|
||||
if write_to_config then
|
||||
minetest.setting_set("vmg_" .. flag, default)
|
||||
end
|
||||
vmg.settings:set(flag, default)
|
||||
return default, false
|
||||
end
|
||||
end
|
||||
end
|
||||
|
||||
local function define_num(flag, default, write_to_config)
|
||||
local value = vmg.settings:get(flag)
|
||||
if value then
|
||||
return tonumber(value), true
|
||||
else
|
||||
local on_config = minetest.setting_get("vmg_" .. flag)
|
||||
if on_config then
|
||||
vmg.settings:set(flag, on_config)
|
||||
return tonumber(on_config), false
|
||||
else
|
||||
if write_to_config then
|
||||
minetest.setting_set("vmg_" .. flag, default)
|
||||
end
|
||||
vmg.settings:set(flag, default)
|
||||
return default, false
|
||||
end
|
||||
end
|
||||
end
|
||||
|
||||
local function define_bool(flag, default, write_to_config)
|
||||
local value = vmg.settings:get_bool(flag)
|
||||
if value ~= nil then
|
||||
return value, true
|
||||
else
|
||||
local on_config = minetest.setting_getbool("vmg_" .. flag)
|
||||
if on_config ~= nil then
|
||||
vmg.settings:set(flag, tostring(on_config))
|
||||
return on_config, false
|
||||
else
|
||||
if write_to_config then
|
||||
minetest.setting_setbool("vmg_" .. flag, default)
|
||||
end
|
||||
vmg.settings:set(flag, tostring(default))
|
||||
return default, false
|
||||
end
|
||||
end
|
||||
end
|
||||
|
||||
local function define_noise(flag, default, write_to_config)
|
||||
local value = vmg.settings:get(flag)
|
||||
if value then
|
||||
return vmg.string_to_noise(value), true
|
||||
else
|
||||
local on_config = minetest.setting_get("vmg_" .. flag)
|
||||
if on_config then
|
||||
vmg.settings:set(flag, on_config)
|
||||
return vmg.string_to_noise(on_config), false
|
||||
else
|
||||
local str_default = vmg.noise_to_string(default)
|
||||
if write_to_config then
|
||||
minetest.setting_set("vmg_" .. flag, str_default)
|
||||
end
|
||||
vmg.settings:set(flag, str_default)
|
||||
return default, false
|
||||
end
|
||||
end
|
||||
end
|
||||
|
||||
function vmg.define(flag, default, write_to_config)
|
||||
local typeval = type(default)
|
||||
if typeval == "string" then
|
||||
return define_str(flag, default, write_to_config)
|
||||
elseif typeval == "number" then
|
||||
return define_num(flag, default, write_to_config)
|
||||
elseif typeval == "boolean" then
|
||||
return define_bool(flag, default, write_to_config)
|
||||
elseif typeval == "table" then
|
||||
return define_noise(flag, default, write_to_config)
|
||||
end
|
||||
end
|
||||
|
||||
function vmg.noise_to_string(n)
|
||||
return n.offset ..
|
||||
", " .. n.scale ..
|
||||
", " .. minetest.pos_to_string(n.spread) ..
|
||||
", " .. n.seed ..
|
||||
", " .. n.octaves ..
|
||||
", " .. n.persist ..
|
||||
", " .. n.lacunarity
|
||||
end
|
||||
|
||||
function vmg.string_to_noise(str)
|
||||
local t = {}
|
||||
for line in str:gmatch("[%d%.%-e]+") do
|
||||
table.insert(t, tonumber(line))
|
||||
end
|
||||
return {
|
||||
offset = t[1],
|
||||
scale = t[2],
|
||||
spread = {x=t[3], y=t[4], z=t[5]},
|
||||
seed = t[6],
|
||||
octaves = t[7],
|
||||
persist = t[8],
|
||||
lacunarity = t[9],
|
||||
}
|
||||
end
|
||||
|
||||
if vmg.loglevel >= 2 then
|
||||
print("[Valleys Mapgen] Loading mapgen ...")
|
||||
end
|
||||
|
||||
-- Choose the appropriate mapgen version
|
||||
|
||||
local version = vmg.define("version", vmg.version)
|
||||
if version == vmg.version then
|
||||
dofile(vmg.path .. "/mapgen.lua")
|
||||
else
|
||||
dofile(vmg.path .. "/old_mapgens/" .. version .. ".lua")
|
||||
end
|
||||
|
||||
vmg.settings:write()
|
|
@ -0,0 +1,40 @@
|
|||
with GIMP :
|
||||
Color ~> Hue-Saturation
|
||||
|
||||
vmg_dirt_clayey.png
|
||||
from default_dirt.png
|
||||
Hue −6
|
||||
Brightness +5
|
||||
Saturation +40
|
||||
|
||||
vmg_dirt_sandy.png
|
||||
from default_dirt.png
|
||||
Hue +5
|
||||
Brightness +40
|
||||
Saturation −10
|
||||
|
||||
vmg_dirt_silty.png
|
||||
from default_dirt.png
|
||||
Hue +8
|
||||
Brightness −10
|
||||
Saturation −30
|
||||
|
||||
vmg_red_clay.png
|
||||
from default_dirt.png
|
||||
Hue −5
|
||||
Brightness +10
|
||||
Saturation +100
|
||||
|
||||
vmg_silt.png
|
||||
from default_dirt.png
|
||||
Hue +6
|
||||
Brightness +10
|
||||
Saturation −78
|
||||
|
||||
vmg_fir_tree.png :
|
||||
from default_wood.png
|
||||
Hue +6
|
||||
Brightness +50
|
||||
Saturation −24
|
||||
|
||||
And convert to indexed color.
|
After Width: | Height: | Size: 324 B |
After Width: | Height: | Size: 323 B |
After Width: | Height: | Size: 323 B |
After Width: | Height: | Size: 379 B |
After Width: | Height: | Size: 289 B |
After Width: | Height: | Size: 443 B |
After Width: | Height: | Size: 362 B |
After Width: | Height: | Size: 268 B |
After Width: | Height: | Size: 323 B |
After Width: | Height: | Size: 323 B |
|
@ -0,0 +1,295 @@
|
|||
local function can_grow(pos) -- from default mod
|
||||
local node_under = minetest.get_node_or_nil({x = pos.x, y = pos.y - 1, z = pos.z})
|
||||
if not node_under then
|
||||
return false
|
||||
end
|
||||
local name_under = node_under.name
|
||||
local is_soil = minetest.get_item_group(name_under, "soil")
|
||||
if is_soil == 0 then
|
||||
return false
|
||||
end
|
||||
return true
|
||||
end
|
||||
|
||||
minetest.register_abm({
|
||||
nodenames = {"valleys_mapgen:fir_sapling"},
|
||||
interval = 14,
|
||||
chance = 50,
|
||||
action = function(pos, node)
|
||||
if not can_grow(pos) then
|
||||
return
|
||||
end
|
||||
|
||||
minetest.log("action", "A fir sapling grows into a tree at "..
|
||||
minetest.pos_to_string(pos))
|
||||
vmg.grow_fir_tree(pos)
|
||||
end
|
||||
})
|
||||
|
||||
function default.grow_tree(pos, is_apple_tree)
|
||||
local rand = math.random()
|
||||
local height = math.floor(4 + 2.5 * rand)
|
||||
local radius = 3 + rand
|
||||
|
||||
local leaves = minetest.get_content_id("default:leaves")
|
||||
local trunk = minetest.get_content_id("default:tree")
|
||||
local air = minetest.get_content_id("air")
|
||||
local ignore = minetest.get_content_id("ignore")
|
||||
local vm = minetest.get_voxel_manip()
|
||||
local emin, emax = vm:read_from_map({x = pos.x - 4, y = pos.y, z = pos.z - 4}, {x = pos.x + 4, y = pos.y + height + 4, z = pos.z + 4})
|
||||
local area = VoxelArea:new({MinEdge = emin, MaxEdge = emax})
|
||||
local data = vm:get_data()
|
||||
if is_apple_tree then
|
||||
vmg.make_apple_tree(pos, data, area, height, radius, trunk, leaves, minetest.get_content_id("default:apple"), air, ignore)
|
||||
else
|
||||
vmg.make_tree(pos, data, area, height, radius, trunk, leaves, air, ignore)
|
||||
end
|
||||
vm:set_data(data)
|
||||
vm:write_to_map()
|
||||
vm:update_map()
|
||||
end
|
||||
|
||||
function default.grow_jungle_tree(pos)
|
||||
local rand = math.random()
|
||||
local height = math.floor(8 + 4 * rand)
|
||||
local radius = 5 + 3 * rand
|
||||
|
||||
local leaves = minetest.get_content_id("default:jungleleaves")
|
||||
local trunk = minetest.get_content_id("default:jungletree")
|
||||
local air = minetest.get_content_id("air")
|
||||
local ignore = minetest.get_content_id("ignore")
|
||||
local vm = minetest.get_voxel_manip()
|
||||
local emin, emax = vm:read_from_map({x = pos.x - 8, y = pos.y - 1, z = pos.z - 8}, {x = pos.x + 8, y = pos.y + height + 5, z = pos.z + 8})
|
||||
local area = VoxelArea:new({MinEdge = emin, MaxEdge = emax})
|
||||
local data = vm:get_data()
|
||||
vmg.make_jungle_tree(pos, data, area, height, radius, trunk, leaves, air, ignore)
|
||||
vmg.execute_after_mapgen()
|
||||
vm:set_data(data)
|
||||
vm:write_to_map()
|
||||
vm:update_map()
|
||||
end
|
||||
|
||||
function default.grow_pine_tree(pos)
|
||||
local rand = math.random()
|
||||
local height = math.floor(9 + 6 * rand)
|
||||
local radius = 4 + 2 * rand
|
||||
|
||||
local leaves = minetest.get_content_id("default:pine_needles")
|
||||
local trunk = minetest.get_content_id("default:pinetree")
|
||||
local air = minetest.get_content_id("air")
|
||||
local ignore = minetest.get_content_id("ignore")
|
||||
local vm = minetest.get_voxel_manip()
|
||||
local emin, emax = vm:read_from_map({x = pos.x - 6, y = pos.y - 1, z = pos.z - 6}, {x = pos.x + 6, y = pos.y + height + 2, z = pos.z + 6})
|
||||
local area = VoxelArea:new({MinEdge = emin, MaxEdge = emax})
|
||||
local data = vm:get_data()
|
||||
vmg.make_pine_tree(pos, data, area, height, radius, trunk, leaves, air, ignore)
|
||||
vm:set_data(data)
|
||||
vm:write_to_map()
|
||||
vm:update_map()
|
||||
end
|
||||
|
||||
function vmg.grow_fir_tree(pos)
|
||||
local rand = math.random()
|
||||
local height = math.floor(9 + 6 * rand)
|
||||
local radius = 4 + 2 * rand
|
||||
|
||||
local leaves = minetest.get_content_id("valleys_mapgen:fir_needles")
|
||||
local trunk = minetest.get_content_id("valleys_mapgen:fir_tree")
|
||||
local air = minetest.get_content_id("air")
|
||||
local ignore = minetest.get_content_id("ignore")
|
||||
local vm = minetest.get_voxel_manip()
|
||||
local emin, emax = vm:read_from_map({x = pos.x - 6, y = pos.y - 1, z = pos.z - 6}, {x = pos.x + 6, y = pos.y + height + 2, z = pos.z + 6})
|
||||
local area = VoxelArea:new({MinEdge = emin, MaxEdge = emax})
|
||||
local data = vm:get_data()
|
||||
vmg.make_fir_tree(pos, data, area, height, radius, trunk, leaves, air, ignore)
|
||||
vm:set_data(data)
|
||||
vm:write_to_map()
|
||||
vm:update_map()
|
||||
end
|
||||
|
||||
function vmg.make_tree(pos, data, area, height, radius, trunk, leaves, air, ignore)
|
||||
if vmg.loglevel >= 3 then
|
||||
print("[Valleys Mapgen] Generating tree at " .. minetest.pos_to_string(pos) .. " ...")
|
||||
end
|
||||
local ystride = area.ystride
|
||||
local iv = area:indexp(pos)
|
||||
for i = 1, height do
|
||||
data[iv] = trunk
|
||||
iv = iv + ystride
|
||||
end
|
||||
local np = {offset = 0.8, scale = 0.4, spread = {x = 8, y = 4, z = 8}, octaves = 3, persist = 0.5}
|
||||
pos.y = pos.y + height - 1
|
||||
vmg.make_leavesblob(pos, data, area, leaves, air, ignore, {x = radius, y = radius, z = radius}, np)
|
||||
end
|
||||
|
||||
function vmg.make_apple_tree(pos, data, area, height, radius, trunk, leaves, fruit, air, ignore)
|
||||
if vmg.loglevel >= 3 then
|
||||
print("[Valleys Mapgen] Generating apple tree at " .. minetest.pos_to_string(pos) .. " ...")
|
||||
end
|
||||
local ystride = area.ystride
|
||||
local iv = area:indexp(pos)
|
||||
for i = 1, height do
|
||||
data[iv] = trunk
|
||||
iv = iv + ystride
|
||||
end
|
||||
local np = {offset = 0.8, scale = 0.4, spread = {x = 8, y = 4, z = 8}, octaves = 3, persist = 0.5}
|
||||
pos.y = pos.y + height - 1
|
||||
vmg.make_leavesblob(pos, data, area, leaves, air, ignore, {x = radius, y = radius, z = radius}, np, 0.06, fruit)
|
||||
end
|
||||
|
||||
local function make_jungle_root(x0, y0, z0, data, area, tree, air)
|
||||
local ystride = area.ystride
|
||||
local ybot = y0 - 1
|
||||
for x = x0 - 1, x0 + 1 do
|
||||
for z = z0 - 1, z0 + 1 do
|
||||
local iv = area:index(x, ybot, z)
|
||||
for i = 0, 5 do
|
||||
if data[iv] == air then
|
||||
if math.random() < 0.6 then
|
||||
data[iv-ystride] = tree -- make jungle tree below
|
||||
if math.random() < 0.6 then
|
||||
data[iv] = tree -- make jungle tree at this air node
|
||||
end
|
||||
end
|
||||
break
|
||||
end
|
||||
iv = iv + ystride
|
||||
end
|
||||
end
|
||||
end
|
||||
end
|
||||
|
||||
function vmg.make_jungle_tree(pos, data, area, height, radius, trunk, leaves, air, ignore)
|
||||
if vmg.loglevel >= 3 then
|
||||
print("[Valleys Mapgen] Generating jungle tree at " .. minetest.pos_to_string(pos) .. " ...")
|
||||
end
|
||||
local ystride = area.ystride
|
||||
local iv = area:indexp(pos)
|
||||
for i = 1, height do
|
||||
data[iv] = trunk
|
||||
iv = iv + ystride
|
||||
end
|
||||
vmg.register_after_mapgen(make_jungle_root, pos.x, pos.y, pos.z, data, area, trunk, air)
|
||||
local np = {offset = 0.8, scale = 0.4, spread = {x = 8, y = 4, z = 8}, octaves = 3, persist = 0.8}
|
||||
pos.y = pos.y + height
|
||||
vmg.make_leavesblob(pos, data, area, leaves, air, ignore, {x = radius, y = radius * 0.5, z = radius}, np)
|
||||
end
|
||||
|
||||
function vmg.make_fir_tree(pos, data, area, height, radius, trunk, leaves, air, ignore)
|
||||
if vmg.loglevel >= 3 then
|
||||
print("[Valleys Mapgen] Generating fir tree at " .. minetest.pos_to_string(pos) .. " ...")
|
||||
end
|
||||
local ystride = area.ystride
|
||||
local iv = area:indexp(pos)
|
||||
for i = 1, height do
|
||||
data[iv] = trunk
|
||||
iv = iv + ystride
|
||||
end
|
||||
|
||||
-- add leaves on the top (4% 0 ; 36% 1 ; 60% 2)
|
||||
local rand = math.random()
|
||||
if rand < 0.96 then
|
||||
data[iv] = leaves
|
||||
if rand < 0.60 then
|
||||
iv = iv + ystride
|
||||
data[iv] = leaves
|
||||
end
|
||||
end
|
||||
|
||||
-- make several leaves rings
|
||||
local max_height = pos.y + height
|
||||
local min_height = pos.y + math.floor((0.2 + 0.3 * math.random()) * height)
|
||||
local radius_increment = (radius - 1.2) / (max_height - min_height)
|
||||
local np = {offset = 0.8, scale = 0.4, spread = {x = 12, y = 4, z = 12}, octaves = 3, persist = 0.8}
|
||||
|
||||
pos.y = max_height - 1
|
||||
while pos.y >= min_height do
|
||||
local ring_radius = (max_height - pos.y) * radius_increment + 1.2
|
||||
vmg.make_leavesblob(pos, data, area, leaves, air, ignore, {x = ring_radius, y = 2, z = ring_radius}, np)
|
||||
pos.y = pos.y - math.random(2, 3)
|
||||
end
|
||||
end
|
||||
|
||||
function vmg.make_pine_tree(pos, data, area, height, radius, trunk, leaves, air, ignore)
|
||||
if vmg.loglevel >= 3 then
|
||||
print("[Valleys Mapgen] Generating pine tree at " .. minetest.pos_to_string(pos) .. " ...")
|
||||
end
|
||||
local ystride = area.ystride
|
||||
local iv = area:indexp(pos)
|
||||
for i = 1, height do
|
||||
data[iv] = trunk
|
||||
iv = iv + ystride
|
||||
end
|
||||
|
||||
-- add leaves on the top (4% 0 ; 36% 1 ; 60% 2)
|
||||
local rand = math.random()
|
||||
if rand < 0.96 then
|
||||
data[iv] = leaves
|
||||
if rand < 0.60 then
|
||||
iv = iv + ystride
|
||||
data[iv] = leaves
|
||||
end
|
||||
end
|
||||
|
||||
local np = {offset = 0.8, scale = 0.3, spread = {x = 8, y = 4, z = 8}, octaves = 3, persist = 1}
|
||||
local min_height = pos.y + math.floor((0.4 + 0.2 * math.random()) * height)
|
||||
local midradius = radius / 2
|
||||
|
||||
pos.y = pos.y + height - 1
|
||||
vmg.make_leavesblob(pos, data, area, leaves, air, ignore, {x = radius, y = 1.5, z = radius}, np)
|
||||
while pos.y >= min_height do
|
||||
local angle, distance = math.random() * 2 * math.pi, math.random() * midradius
|
||||
local cos, sin = math.cos(angle) * distance, math.sin(angle) * distance
|
||||
local bpos = {x = pos.x + cos, y = pos.y, z = pos.z + sin}
|
||||
vmg.make_leavesblob(bpos, data, area, leaves, air, ignore, {x = midradius, y = 1.5, z = midradius}, np)
|
||||
pos.y = pos.y - math.random(1, 2)
|
||||
end
|
||||
end
|
||||
|
||||
function vmg.make_leavesblob(pos, data, area, leaves, air, ignore, radius, np, fruit_chance, fruit)
|
||||
local count = 0
|
||||
fruit_chance = fruit_chance or 0
|
||||
|
||||
np.seed = math.random(0, 16777215)
|
||||
local minp = vector.subtract(pos, radius)
|
||||
local maxp = vector.add(pos, radius)
|
||||
local int_minp = {x = math.floor(minp.x), y = math.floor(minp.y), z = math.floor(minp.z)}
|
||||
local int_maxp = {x = math.ceil(maxp.x), y = math.ceil(maxp.y), z = math.ceil(maxp.z)}
|
||||
|
||||
local length = vector.subtract(int_maxp, int_minp)
|
||||
local chulens = vector.add(length, 1)
|
||||
local obj = minetest.get_perlin_map(np, chulens)
|
||||
local pmap = obj:get3dMap_flat(minp)
|
||||
local i = 1
|
||||
for x = int_minp.x, int_maxp.x do
|
||||
local xval = ((x - pos.x) / radius.x) ^ 2
|
||||
for y = int_minp.y, int_maxp.y do
|
||||
local yval = ((y - pos.y) / radius.y) ^ 2
|
||||
for z = int_minp.z, int_maxp.z do
|
||||
local zval = ((z - pos.z) / radius.z) ^ 2
|
||||
local dist = math.sqrt(xval + yval + zval)
|
||||
local nval = pmap[i]
|
||||
if nval > dist then
|
||||
local iv = area:index(x, y, z)
|
||||
if data[iv] == air or data[iv] == ignore then
|
||||
count = count + 1
|
||||
if math.random() < fruit_chance then
|
||||
data[iv] = fruit
|
||||
else
|
||||
data[iv] = leaves
|
||||
end
|
||||
end
|
||||
end
|
||||
i = i + 1
|
||||
end
|
||||
end
|
||||
end
|
||||
end
|
||||
|
||||
-- Adapt the code to the latest minetest_game that use these functions
|
||||
function default.grow_new_apple_tree(pos)
|
||||
local is_apple_tree = math.random(4) == 1
|
||||
default.grow_tree(pos, is_apple_tree)
|
||||
end
|
||||
default.grow_new_jungle_tree = default.grow_jungle_tree
|
||||
default.grow_new_pine_tree = default.grow_pine_tree
|
|
@ -0,0 +1,88 @@
|
|||
# format : FLAG = VALUE
|
||||
|
||||
# Settings are presents twice :
|
||||
# - In every world :
|
||||
# world_directory/vmg.conf
|
||||
|
||||
# - In the main directory :
|
||||
# usually main_directory/minetest.conf
|
||||
|
||||
# /!\ IMPORTANT : In minetest.conf, flags have to be preceded by "vmg_" like "vmg_average_stone_level".
|
||||
|
||||
|
||||
|
||||
#version = 2.2
|
||||
# mapgen version used.
|
||||
|
||||
#player_max_distance = 450
|
||||
# maximal distance from (0;0) at which the player will appear. (If it's in a big ocean, it may be farther)
|
||||
#spawn = true
|
||||
# New players are randomely spawned by the mod. Disable it to spawn the player another way.
|
||||
#respawn = true
|
||||
# After death, players are respawned by the mod. Disable it to respawn the player another way.
|
||||
|
||||
#water_level = 1
|
||||
#river_water = true
|
||||
# use river water instead of normal water in rivers.
|
||||
#waterflow = 3
|
||||
# maximal length of a river water flowing.
|
||||
|
||||
#average_stone_level = 180
|
||||
# height at which the half of the surface is made solely of stone.
|
||||
#average_snow_level = 100
|
||||
# height at which the half of the surface is covered by snow.
|
||||
#clay_threshold = 1
|
||||
# if noise 13 is above this value, make pure clay instead of clayey dirt.
|
||||
#silt_threshold = 1
|
||||
# if noise 14 is above this value, make pure silt instead of silty dirt.
|
||||
#sand_threshold = 0.75
|
||||
# if noise 15 is above this value, make desert sand instead of sandy dirt.
|
||||
#dirt_threshold = 0.5
|
||||
# if not any of noises 13, 14 and 15 is above this value, make normal dirt. Else make special dirt.
|
||||
#river_depth = 3
|
||||
#river_size = 5
|
||||
#caves_size = 7
|
||||
#lava_depth = 2000
|
||||
# to manage lava amount increasing by going deep underground : lower values = bigger increasing.
|
||||
#surface_lava = false
|
||||
# DEPRECATED. No longer supported since mapgen version 2.0. Use lava_max_height instead.
|
||||
#lava_max_height = -1
|
||||
# Lava can't be generated above this height. Use 31000 to disable this restriction, or -31000 to fully disable lava.
|
||||
#altitude_chill = 90
|
||||
|
||||
#trees = true
|
||||
# If false, no trees, of course !
|
||||
#plants = true
|
||||
#tree_density = 5
|
||||
# Percent of the lawn nodes that are covered by trees.
|
||||
#plant_density = 32
|
||||
|
||||
# NOISES : offset, scale, (spread), seed, octaves, persist, lacunarity
|
||||
# (see mapgen.lua to see what is the role of each noise)
|
||||
|
||||
#noise_1 = -10, 50, (1024,1024,1024), 5202, 6, 0.4, 2
|
||||
#noise_2 = 0, 1, (256,256,256), -6050, 5, 0.6, 2
|
||||
#noise_3 = 5, 4, (512,512,512), -1914, 1, 1, 2
|
||||
#noise_4 = 0.6, 0.5, (512,512,512), 777, 1, 1, 2
|
||||
#noise_5 = 0.5, 0.5, (128,128,128), 746, 1, 1, 2
|
||||
#noise_6 = 0, 1, (256,512,256), 1993, 6, 0.8, 2
|
||||
#noise_7 = 3, 1.75, (256,256,256), 1605, 3, 0.5, 2
|
||||
#noise_8 = 0, 1, (32,32,32), -4640, 4, 0.5, 2
|
||||
#noise_9 = 0, 1, (32,32,32), 8804, 4, 0.5, 2
|
||||
#noise_10 = 0, 1, (32,32,32), -4780, 4, 0.5, 2
|
||||
#noise_11 = 0, 1, (32,32,32), -9969, 4, 0.5, 2
|
||||
#noise_12 = 0, 1, (64,64,64), 3314, 4, 0.5, 2
|
||||
#noise_13 = 0, 1, (256,256,256), 2835, 5, 0.5, 4
|
||||
#noise_14 = 0, 1, (256,256,256), 6674, 5, 0.5, 4
|
||||
#noise_15 = 0, 1, (256,256,256), 6940, 5, 0.5, 4
|
||||
#noise_16 = 2, 8, (256,256,256), 2349, 3, 0.5, 2
|
||||
#noise_17 = 0, 1, (768,256,768), -1805, 4, 0.5, 4
|
||||
#noise_18 = 0, 1, (243,243,243), -5787, 4, 0.5, 3
|
||||
|
||||
# Flags that are ONLY available in minetest.conf :
|
||||
|
||||
#vmg_log_level = 0
|
||||
# 0 = Not any log from Valleys Mapgen
|
||||
# 1 = Total mapgen time
|
||||
# 2 = Detailed mapgen time (step by step)
|
||||
# 3 = Detailed mapgen time + trees
|
|
@ -285,3 +285,11 @@ function vmg.make_leavesblob(pos, data, area, leaves, air, ignore, radius, np, f
|
|||
end
|
||||
end
|
||||
end
|
||||
|
||||
-- Adapt the code to the latest minetest_game that use these functions
|
||||
function default.grow_new_apple_tree(pos)
|
||||
local is_apple_tree = math.random(4) == 1
|
||||
default.grow_tree(pos, is_apple_tree)
|
||||
end
|
||||
default.grow_new_jungle_tree = default.grow_jungle_tree
|
||||
default.grow_new_pine_tree = default.grow_pine_tree
|
||||
|
|