2018-12-29 12:56:30 -07:00
|
|
|
local sidelen = mapgen_helper.block_size
|
|
|
|
|
|
|
|
local snap_to_minp = function(ydepth)
|
|
|
|
return ydepth - (ydepth+32) % sidelen -- put ydepth at the minp.y of mapblocks
|
|
|
|
end
|
2017-03-22 00:03:26 -06:00
|
|
|
|
2018-12-29 12:56:30 -07:00
|
|
|
local outside_region = 0
|
|
|
|
local inside_ground = 1
|
|
|
|
local inside_cavern = 2
|
|
|
|
|
|
|
|
-- Spawn player underground in a giant cavern
|
2023-09-29 20:15:23 -06:00
|
|
|
local function spawnplayer(cave_layer_def, player, ydepth)
|
2018-12-29 12:56:30 -07:00
|
|
|
subterrane.set_defaults(cave_layer_def)
|
2017-03-22 00:03:26 -06:00
|
|
|
|
2018-12-29 12:56:30 -07:00
|
|
|
local YMIN = cave_layer_def.y_min
|
|
|
|
local YMAX = cave_layer_def.y_max
|
|
|
|
local BLEND = math.min(cave_layer_def.boundary_blend_range, (YMAX-YMIN)/2)
|
2017-03-22 00:03:26 -06:00
|
|
|
|
2018-12-29 12:56:30 -07:00
|
|
|
local TCAVE = cave_layer_def.cave_threshold
|
2023-09-29 20:15:23 -06:00
|
|
|
|
2018-12-29 12:56:30 -07:00
|
|
|
local np_cave = cave_layer_def.perlin_cave
|
|
|
|
local np_wave = cave_layer_def.perlin_wave
|
2023-09-29 20:15:23 -06:00
|
|
|
|
2018-12-29 12:56:30 -07:00
|
|
|
local y_blend_min = YMIN + BLEND * 1.5
|
2023-09-29 20:15:23 -06:00
|
|
|
local y_blend_max = YMAX - BLEND * 1.5
|
|
|
|
|
2018-12-29 12:56:30 -07:00
|
|
|
local column_def = cave_layer_def.columns
|
|
|
|
local double_frequency = cave_layer_def.double_frequency
|
|
|
|
|
|
|
|
local options = {}
|
|
|
|
|
2017-03-22 00:03:26 -06:00
|
|
|
for chunk = 1, 64 do
|
2018-12-29 12:56:30 -07:00
|
|
|
minetest.log("info", "[subterrane] searching for spawn "..chunk)
|
2023-09-29 20:15:23 -06:00
|
|
|
|
2018-12-29 12:56:30 -07:00
|
|
|
local minp = {x = sidelen * math.random(-32, 32) - 32, z = sidelen * math.random(-32, 32) - 32, y = ydepth}
|
|
|
|
local maxp = {x = minp.x + sidelen - 1, z = minp.z + sidelen - 1, y = ydepth + sidelen - 1}
|
2017-03-22 00:03:26 -06:00
|
|
|
|
2018-12-29 12:56:30 -07:00
|
|
|
local nvals_cave, cave_area = mapgen_helper.perlin3d("subterrane:cave", minp, maxp, np_cave) --cave noise for structure
|
|
|
|
local nvals_wave = mapgen_helper.perlin3d("subterrane:wave", minp, maxp, np_wave) --wavy structure of cavern ceilings and floors
|
2017-03-22 00:03:26 -06:00
|
|
|
|
2018-12-29 12:56:30 -07:00
|
|
|
-- pre-average everything
|
|
|
|
for vi, value in ipairs(nvals_cave) do
|
|
|
|
nvals_cave[vi] = (value + nvals_wave[vi])/2
|
|
|
|
end
|
|
|
|
local column_points = nil
|
2023-09-29 20:15:23 -06:00
|
|
|
local column_weight = nil
|
|
|
|
|
2018-12-29 12:56:30 -07:00
|
|
|
local previous_y = minp.y
|
|
|
|
local previous_node_state = outside_region
|
2023-09-29 20:15:23 -06:00
|
|
|
|
2018-12-29 12:56:30 -07:00
|
|
|
for vi, x, y, z in cave_area:iterp_yxz(vector.add(minp, 2), vector.subtract(maxp, 2)) do
|
2023-09-29 20:15:23 -06:00
|
|
|
|
2018-12-29 12:56:30 -07:00
|
|
|
if y < previous_y then
|
|
|
|
previous_node_state = outside_region
|
|
|
|
end
|
|
|
|
previous_y = y
|
2023-09-29 20:15:23 -06:00
|
|
|
|
2018-12-29 12:56:30 -07:00
|
|
|
local cave_local_threshold
|
|
|
|
if y < y_blend_min then
|
|
|
|
cave_local_threshold = TCAVE + ((y_blend_min - y) / BLEND) ^ 2
|
|
|
|
elseif y > y_blend_max then
|
|
|
|
cave_local_threshold = TCAVE + ((y - y_blend_max) / BLEND) ^ 2
|
|
|
|
else
|
|
|
|
cave_local_threshold = TCAVE
|
|
|
|
end
|
2017-03-22 00:03:26 -06:00
|
|
|
|
2018-12-29 12:56:30 -07:00
|
|
|
local cave_value = nvals_cave[vi]
|
|
|
|
if double_frequency then
|
|
|
|
cave_value = math.abs(cave_value)
|
2023-09-29 20:15:23 -06:00
|
|
|
end
|
|
|
|
|
2018-12-29 12:56:30 -07:00
|
|
|
-- inside a giant cavern
|
|
|
|
if cave_value > cave_local_threshold then
|
|
|
|
local column_value = 0
|
2023-09-29 20:15:23 -06:00
|
|
|
local inside_column
|
2018-12-29 12:56:30 -07:00
|
|
|
if column_def then
|
|
|
|
if column_points == nil then
|
|
|
|
column_points = subterrane.get_column_points(minp, maxp, column_def)
|
|
|
|
column_weight = column_def.weight
|
|
|
|
end
|
|
|
|
column_value = subterrane.get_column_value({x=x, y=y, z=z}, column_points)
|
|
|
|
end
|
2023-09-29 20:15:23 -06:00
|
|
|
inside_column = column_value > 0 and cave_value - column_value * column_weight < cave_local_threshold
|
2018-12-29 12:56:30 -07:00
|
|
|
if previous_node_state == inside_ground and not inside_column then
|
|
|
|
-- we just entered the cavern from below. Do a quick check for head space.
|
|
|
|
local val_above = nvals_cave[vi+cave_area.ystride]
|
|
|
|
if double_frequency then
|
|
|
|
val_above = math.abs(val_above)
|
2017-03-22 00:03:26 -06:00
|
|
|
end
|
2018-12-29 12:56:30 -07:00
|
|
|
if val_above > cave_local_threshold then
|
|
|
|
table.insert(options, {x=x, y=y+1, z=z})
|
2017-03-22 00:03:26 -06:00
|
|
|
end
|
|
|
|
end
|
2018-12-29 12:56:30 -07:00
|
|
|
if not inside_column then
|
|
|
|
previous_node_state = inside_cavern
|
|
|
|
else
|
|
|
|
previous_node_state = inside_ground
|
2017-03-22 00:03:26 -06:00
|
|
|
end
|
2018-12-29 12:56:30 -07:00
|
|
|
|
|
|
|
else
|
|
|
|
previous_node_state = inside_ground
|
2017-03-22 00:03:26 -06:00
|
|
|
end
|
|
|
|
end
|
2018-12-29 12:56:30 -07:00
|
|
|
|
|
|
|
if table.getn(options) > 20 then -- minimum 20 to ensure the player is put in a place with a modicum of size
|
|
|
|
local choice = math.random(1, table.getn(options))
|
|
|
|
local spawnpoint = options[ choice ]
|
|
|
|
minetest.log("action", "[subterrane] spawning player " .. minetest.pos_to_string(spawnpoint))
|
|
|
|
player:setpos(spawnpoint)
|
|
|
|
return true
|
2017-03-22 00:03:26 -06:00
|
|
|
end
|
|
|
|
end
|
2018-12-29 12:56:30 -07:00
|
|
|
return false
|
2017-03-22 00:03:26 -06:00
|
|
|
end
|
2023-09-29 20:15:23 -06:00
|
|
|
|
|
|
|
function subterrane:register_cave_spawn(cave_layer_def, start_depth)
|
|
|
|
minetest.register_on_newplayer(function(player)
|
|
|
|
local ydepth = snap_to_minp(start_depth or cave_layer_def.y_max)
|
|
|
|
local spawned = false
|
|
|
|
while spawned ~= true do
|
|
|
|
spawned = spawnplayer(cave_layer_def, player, ydepth)
|
|
|
|
ydepth = ydepth - sidelen
|
|
|
|
if ydepth < cave_layer_def.y_min then
|
|
|
|
ydepth = snap_to_minp(cave_layer_def.y_max)
|
|
|
|
end
|
|
|
|
end
|
|
|
|
end)
|
|
|
|
|
|
|
|
minetest.register_on_respawnplayer(function(player)
|
|
|
|
local ydepth = snap_to_minp(start_depth or cave_layer_def.y_max)
|
|
|
|
local spawned = false
|
|
|
|
while spawned ~= true do
|
|
|
|
spawned = spawnplayer(cave_layer_def, player, ydepth)
|
|
|
|
ydepth = ydepth - sidelen
|
|
|
|
if ydepth < cave_layer_def.y_min then
|
|
|
|
ydepth = snap_to_minp(cave_layer_def.y_max)
|
|
|
|
end
|
|
|
|
end
|
|
|
|
return true
|
|
|
|
end)
|
|
|
|
end
|