mirror of
https://gitlab.com/gaelysam/mapgen_rivers.git
synced 2024-12-28 20:00:41 +01:00
121 lines
3.0 KiB
Lua
121 lines
3.0 KiB
Lua
local np_distort_x = mapgen_rivers.noise_params.distort_x
|
|
local np_distort_z = mapgen_rivers.noise_params.distort_z
|
|
local np_distort_amplitude = mapgen_rivers.noise_params.distort_amplitude
|
|
|
|
local nobj_distort_x, nobj_distort_z, nobj_distort_amplitude
|
|
|
|
local sea_level = mapgen_rivers.settings.sea_level
|
|
local distort = mapgen_rivers.settings.distort
|
|
|
|
-- Linear interpolation
|
|
local function interp(v00, v01, v11, v10, xf, zf)
|
|
local v0 = v01*xf + v00*(1-xf)
|
|
local v1 = v11*xf + v10*(1-xf)
|
|
return v1*zf + v0*(1-zf)
|
|
end
|
|
|
|
local function estimate_spawn_level(pos, use_distort)
|
|
local x, z = pos.x, pos.z
|
|
if distort and use_distort then
|
|
nobj_distort_x = nobj_distort_x or minetest.get_perlin(np_distort_x)
|
|
nobj_distort_z = nobj_distort_z or minetest.get_perlin(np_distort_z)
|
|
nobj_distort_amplitude = nobj_distort_amplitude or minetest.get_perlin(np_distort_amplitude)
|
|
|
|
local amplitude = nobj_distort_amplitude:get_2d({x=pos.x, y=pos.z})
|
|
x = x + nobj_distort_x:get_3d(pos)*amplitude
|
|
z = z + nobj_distort_z:get_3d(pos)*amplitude
|
|
end
|
|
|
|
local terrain, lakes = mapgen_rivers.make_heightmaps(
|
|
{x=math.floor(x), z=math.floor(z) },
|
|
{x=math.floor(x)+1, z=math.floor(z)+1}
|
|
)
|
|
|
|
local ex, ez = x % 1, z % 1
|
|
--local h = terrain[1]*(1-ex)*(1-ez) + terrain[2]*ex*(1-ez) + terrain[3]*(1-ex)*ez + terrain[4]*ex*ez
|
|
local h = interp(terrain[1], terrain[2], terrain[4], terrain[3], ex, ez)
|
|
local lake = math.min(lakes[1], lakes[2], lakes[3], lakes[4])
|
|
|
|
if h < lake or h <= sea_level then
|
|
return false, h
|
|
end
|
|
|
|
return true, h
|
|
end
|
|
|
|
local function get_spawn_level(x, z)
|
|
print(x, z)
|
|
local pos = {x=x, z=z}
|
|
local suitable, y = estimate_spawn_level(pos, false)
|
|
if not suitable then
|
|
return
|
|
end
|
|
|
|
if not distort then
|
|
return math.floor(y) + 1
|
|
end
|
|
|
|
local low_bound = -math.huge
|
|
local high_bound = math.huge
|
|
local suitable_high = false
|
|
|
|
repeat
|
|
pos.y = math.max(math.min(math.floor(y+0.5), high_bound-1), low_bound+1)
|
|
suitable, y = estimate_spawn_level(pos, true)
|
|
if y > pos.y then
|
|
low_bound = pos.y
|
|
else
|
|
high_bound = pos.y
|
|
suitable_high = suitable
|
|
end
|
|
until high_bound - low_bound <= 1
|
|
|
|
if not suitable_high then
|
|
return
|
|
end
|
|
|
|
return high_bound + 1
|
|
end
|
|
minetest.get_spawn_level = get_spawn_level
|
|
|
|
local rmax = 2000
|
|
local function find_spawn_point(seed)
|
|
local level = get_spawn_level(0, 0)
|
|
if level then
|
|
return {x=0, y=level, z=0}
|
|
end
|
|
|
|
local pr = PcgRandom(seed or os.time())
|
|
local incr = 16
|
|
local r0 = 0
|
|
|
|
while r0 < rmax do
|
|
local r1 = r0 + incr
|
|
local r = pr:next(r0*r0+1, r1*r1) ^ 0.5
|
|
local a = pr:next() / 2147483648 * math.pi
|
|
|
|
local x = math.floor(math.cos(a) * r + 0.5)
|
|
local z = math.floor(math.sin(a) * r + 0.5)
|
|
|
|
level = get_spawn_level(x, z)
|
|
if level then
|
|
return {x=x, y=level, z=z}
|
|
end
|
|
r0 = r1
|
|
end
|
|
end
|
|
|
|
local function spawn_player(player)
|
|
if minetest.settings:get("static_spawnpoint") then
|
|
return
|
|
end
|
|
|
|
local spawn_point = find_spawn_point()
|
|
if spawn_point then
|
|
player:set_pos(spawn_point)
|
|
end
|
|
end
|
|
|
|
minetest.register_on_newplayer(spawn_player)
|
|
minetest.register_on_respawnplayer(spawn_player)
|