dfcaverns/chasms/init.lua
FaceDeer 9b7e71c675
Chasms (#19)
* initial chasms mod

* tweak default chasm settings

* prevent chasms from breaching oil and magma seas, make veinstone actually do something

* overgenerate caverns to eliminate floating stalactites

* make veinstone punchable instead of right-clickable

* ensure dfcaverns get carved before chasms

this has an unfortunate tradeoff. Chasms will no longer have floating giant columns in them, but will also no longer have smaller stalactites and stalagmites. Also will carve chasms through lake water. Not sure if this is ideal.

* add rare big webs to the chasms, to give them a unique feature

* reverse the dependencies for df_caverns and chasms, let chasms go first.

* fix web generator

* add webs to level 3 tunnels, fix sunless sea chasms

* fix up tunnel webs

* make webs snappy

* make webs slightly more prevalent

* add chasms to the guide

* final touch-ups before merging

* allow anchoring against unloaded blocks
2021-03-28 15:20:52 -06:00

169 lines
5.5 KiB
Lua

local data = {}
chasms = {}
local maxy = tonumber(minetest.settings:get("chasms_maxy")) or -50
local miny = tonumber(minetest.settings:get("chasms_miny")) or -2500
local falloff = tonumber(minetest.settings:get("chasms_falloff")) or 100
local web_probability = 0.15 -- the chance that a given mapblock will have webbing criss-crossing the chasm
local chasms_threshold = tonumber(minetest.settings:get("chasms_threshold")) or 0.9
local np_chasms_default = {
offset = 0,
scale = 1,
spread = {x = 50, y = 1000, z = 3000},
seed = 94586,
octaves = 2,
persist = 0.63,
lacunarity = 2.0,
}
local np_chasms = minetest.settings:get_np_group("chasms_params") or np_chasms_default
-- For some reason, these numbers are returned as strings by get_np_group.
local tonumberize_params = function(params)
params.scale = tonumber(params.scale)
params.lacunarity = tonumber(params.lacunarity)
params.spread.x = tonumber(params.spread.x)
params.spread.y = tonumber(params.spread.y)
params.spread.z = tonumber(params.spread.z)
params.offset = tonumber(params.offset)
params.persistence = tonumber(params.persistence)
end
tonumberize_params(np_chasms)
local nobj_chasm
local chasm_data = {}
local waver_strength = 8
local waver_vector = {x=waver_strength, y=0, z=0}
local np_waver = {
offset = 0,
scale = waver_strength,
spread = {x = 50, y = 50, z = 50},
seed = 49585,
octaves = 2,
persist = 0.63,
lacunarity = 2.0,
}
local nobj_waver
local waver_data = {}
local minfalloff = miny + falloff
local maxfalloff = maxy - falloff
local get_intensity = function(y)
if y < miny or y > maxy then
return 0
end
if y <= maxfalloff and y >= minfalloff then
return 1
end
if y < minfalloff then
return (y-miny)/falloff
end
-- if y > maxfalloff then
return (maxy-y)/falloff
-- end
end
local c_air = minetest.get_content_id("air")
local c_web
local big_webs_path = minetest.get_modpath("big_webs")
if big_webs_path then
c_web = minetest.get_content_id("big_webs:webbing")
end
local z_displace = 10000
local calculate_web_array = function(minp, maxp)
local seed = math.random()*10000000
math.randomseed(minp.y + z_displace*minp.z) -- use consistent seeds across the x axis
local webs = {}
for count = 1, math.random(5,20) do
local width = math.random(5, 25)
local direction_vertical = math.random() > 0.5
local web_y = math.random(minp.y+8, maxp.y-8)
local web_z = math.random(minp.z+8, maxp.z-8)
for i = -math.floor(width/2), math.ceil(width/2) do
if direction_vertical then
webs[(web_y+i) + web_z*z_displace] = true
else
webs[web_y + (web_z+i)*z_displace] = true
end
end
end
math.randomseed(seed)
return webs
end
minetest.register_on_generated(function(minp, maxp, seed)
if minp.y >= maxy or maxp.y <= miny then
return
end
-- check if webs are present
local webs
local webs_present = false
if big_webs_path then
local seed = math.random()*10000000
math.randomseed(minp.y + z_displace*minp.z) -- use consistent seeds across the x axis
if math.random() < web_probability then
webs_present = true
end
math.randomseed(seed)
end
local vm, emin, emax = minetest.get_mapgen_object("voxelmanip")
vm:get_data(data)
nobj_chasm = nobj_chasm or minetest.get_perlin_map(np_chasms, {x = emax.x - emin.x + 1 + waver_strength*2, y = emax.y - emin.y + 1, z = emax.z - emin.z + 1})
nobj_chasm:get_3d_map_flat(vector.subtract(emin, waver_vector), chasm_data)
nobj_waver = nobj_waver or minetest.get_perlin_map(np_waver, {x = emax.x - emin.x + 1, y = emax.y - emin.y + 1, z = emax.z - emin.z + 1})
nobj_waver:get_3d_map_flat(emin, waver_data)
local chasm_area = VoxelArea:new{MinEdge = vector.subtract(emin, waver_vector), MaxEdge = vector.add(emax, waver_vector)}
local data_area = VoxelArea:new{MinEdge = emin, MaxEdge = emax}
for i, x, y, z in data_area:iterp_xyz(emin, emax) do
local waver = math.min(math.max(math.floor(waver_data[i]+0.5), -waver_strength), waver_strength)
local intensity = get_intensity(y)
if chasm_data[chasm_area:index(x+waver, y, z)]*intensity > chasms_threshold then
if webs_present then
webs = webs or calculate_web_array(minp, maxp) -- only calculate webs when we know we're in a chasm
if webs[y + z*z_displace] and math.random() < 0.85 then -- random holes in the web
data[i] = c_web
minetest.get_node_timer({x=x,y=y,z=z}):start(1) -- this timer will check for unsupported webs
else
data[i] = c_air
end
else
data[i] = c_air
end
end
end
vm:set_data(data)
vm:calc_lighting()
vm:write_to_map()
end)
local nobj_local_chasm = minetest.get_perlin(np_chasms)
local nobj_local_waver = minetest.get_perlin(np_waver)
chasms.is_in_chasm = function(pos)
nobj_local_chasm = nobj_local_chasm or minetest.get_perlin(np_chasms)
nobj_local_waver = nobj_local_waver or minetest.get_perlin(np_waver)
local waver = math.min(math.max(math.floor(nobj_local_waver:get_3d(pos)+0.5), -waver_strength), waver_strength)
local chasm_value = nobj_local_chasm:get_3d({x=pos.x+waver, y=pos.y, z=pos.z})
return chasm_value*get_intensity(pos.y) > chasms_threshold
end
-- A little cheaper to run, for mapgens that know they don't have to worry about the tops and bottoms of chasms
chasms.is_in_chasm_without_taper = function(pos)
nobj_local_chasm = nobj_local_chasm or minetest.get_perlin(np_chasms)
nobj_local_waver = nobj_local_waver or minetest.get_perlin(np_waver)
local waver = math.min(math.max(math.floor(nobj_local_waver:get_3d(pos)+0.5), -waver_strength), waver_strength)
local chasm_value = nobj_local_chasm:get_3d({x=pos.x+waver, y=pos.y, z=pos.z})
return chasm_value > chasms_threshold
end