A simple pit cave mod, based off of code from the volcano pipes in my magma_conduits mod

This commit is contained in:
FaceDeer 2021-05-06 17:01:00 -06:00
parent 79fd356477
commit c71766aaea
6 changed files with 239 additions and 1 deletions

View File

@ -5,7 +5,7 @@ Sounds and textures are under various licenses, see the license.txt file in the
License for Code
----------------
Copyright (C) 2018 FaceDeer
Copyright (C) 2021 FaceDeer
Permission is hereby granted, free of charge, to any person obtaining a copy
of this software and associated documentation files (the "Software"), to deal

22
pit_caves/LICENSE.txt Normal file
View File

@ -0,0 +1,22 @@
License for Code
----------------
Copyright (C) 2021 FaceDeer
Permission is hereby granted, free of charge, to any person obtaining a copy
of this software and associated documentation files (the "Software"), to deal
in the Software without restriction, including without limitation the rights
to use, copy, modify, merge, publish, distribute, sublicense, and/or sell
copies of the Software, and to permit persons to whom the Software is
furnished to do so, subject to the following conditions:
The above copyright notice and this permission notice shall be included in all
copies or substantial portions of the Software.
THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR
IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY,
FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE
AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER
LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM,
OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE
SOFTWARE.

196
pit_caves/init.lua Normal file
View File

@ -0,0 +1,196 @@
local modpath = minetest.get_modpath(minetest.get_current_modname())
local S = minetest.get_translator(minetest.get_current_modname())
local min_depth = tonumber(minetest.settings:get("pit_caves_min_bottom") or -2500)
local max_depth = tonumber(minetest.settings:get("pit_caves_max_bottom") or -500)
local min_top = tonumber(minetest.settings:get("pit_caves_min_top") or -100)
local max_top = tonumber(minetest.settings:get("pit_caves_max_top") or 100)
assert(min_depth < max_depth, "pit_caves_min_bottom is above pit_caves_max_bottom")
assert(min_top < max_top, "pit_caves_min_top is above pit_caves_max_top")
assert(max_depth < min_top, "pit_caves_max_bottom is above pit_caves_min_top")
local pit_radius = 3 -- approximate minimum radius of pit - noise adds a lot to this
local region_mapblocks = tonumber(minetest.settings:get("pit_caves_mapblock_spacing") or 16)
local mapgen_chunksize = tonumber(minetest.get_mapgen_setting("chunksize"))
local pit_region_size = region_mapblocks * mapgen_chunksize * 16
local c_air = minetest.get_content_id("air")
local c_gravel = c_air
if minetest.get_modpath("default") then
c_gravel = minetest.get_content_id("default:gravel")
end
local water_level = tonumber(minetest.get_mapgen_setting("water_level"))
local mapgen_seed = tonumber(minetest.get_mapgen_setting("seed")) % 2^16
local scatter_2d = function(min_xz, gridscale, border_width)
local bordered_scale = gridscale - 2 * border_width
local point = {}
point.x = math.floor(math.random() * bordered_scale + min_xz.x + border_width)
point.y = 0
point.z = math.floor(math.random() * bordered_scale + min_xz.z + border_width)
return point
end
-- For some reason, map chunks generate with -32, -32, -32 as the "origin" minp. To make the large-scale grid align with map chunks it needs to be offset like this.
local get_corner = function(pos)
return {x = math.floor((pos.x+32) / pit_region_size) * pit_region_size - 32, z = math.floor((pos.z+32) / pit_region_size) * pit_region_size - 32}
end
local get_pit = function(pos)
local corner_xz = get_corner(pos)
local next_seed = math.random(1, 1000000000)
math.randomseed(corner_xz.x + corner_xz.z * 2 ^ 8 + mapgen_seed + 1)
local location = scatter_2d(corner_xz, pit_region_size, 0)
local depth = math.floor(math.random() * (max_depth - min_depth) + min_depth)
local top = math.floor(math.random() * (max_top - min_top) + min_top)
math.randomseed(next_seed)
return {location = location, depth = depth, top = top}
end
local perlin_params = {
offset = 0,
scale = 1,
spread = {x=30, y=30, z=30},
seed = 45011,
octaves = 3,
persist = 0.67
}
local data = {}
minetest.register_on_generated(function(minp, maxp, seed)
if minp.y > max_top or maxp.y < min_depth then
return
end
local pit = get_pit(minp)
if pit == nil then
return -- no pit in this map region
end
local location_x = pit.location.x
local location_z = pit.location.z
-- early out if the pit is too far away to matter
-- The plus 20 is because the noise being added will generally be in the 0-20 range, see the "distance" calculation below
if location_x - 20 > maxp.x or
location_x + 20 < minp.x or
location_z - 20 > maxp.z or
location_z + 20 < minp.z
then
return
end
local top = pit.top
local depth = pit.depth
local vm, emin, emax = minetest.get_mapgen_object("voxelmanip")
local area = VoxelArea:new{MinEdge=emin, MaxEdge=emax}
vm:get_data(data)
local nvals_perlin = mapgen_helper.perlin3d("pit_caves:pit", emin, emax, perlin_params)
for vi, x, y, z in area:iterp_xyz(emin, emax) do
local distance_perturbation = (nvals_perlin[vi]+1)*10
local distance = vector.distance({x=x, y=y, z=z}, {x=location_x, y=y, z=location_z}) - distance_perturbation
local taper_min = top - 40
if y < top and y > depth then
-- taper the top end
if y > top - 40 then
distance = distance - ((taper_min - y)/2)
end
if distance < pit_radius then
if y < depth + 20 and data[vi] ~= c_air then
data[vi] = c_gravel
else
data[vi] = c_air
end
end
end
end
--send data back to voxelmanip
vm:set_data(data)
--calc lighting
vm:set_lighting({day = 0, night = 0})
vm:calc_lighting()
vm:update_liquids()
--write it to world
vm:write_to_map()
end)
----------------------------------------------------------------------------------------------
-- Debugging and sightseeing commands
function round(val, decimal)
if (decimal) then
return math.floor( (val * 10^decimal) + 0.5) / (10^decimal)
else
return math.floor(val+0.5)
end
end
local send_pit_state = function(pos, name)
local pit = get_pit(pos)
if pit == nil then
return false
end
local location = {x=math.floor(pit.location.x), y=pit.top, z=math.floor(pit.location.z)}
minetest.chat_send_player(name, S("Pit at @1, bottom @2", minetest.pos_to_string(location), pit.depth))
return true
end
local send_nearby_states = function(pos, name)
local retval = false
retval = send_pit_state({x=pos.x-pit_region_size, y=0, z=pos.z+pit_region_size}, name) or retval
retval = send_pit_state({x=pos.x, y=0, z=pos.z+pit_region_size}, name) or retval
retval = send_pit_state({x=pos.x+pit_region_size, y=0, z=pos.z+pit_region_size}, name) or retval
retval = send_pit_state({x=pos.x-pit_region_size, y=0, z=pos.z}, name) or retval
retval = send_pit_state(pos, name) or retval
retval = send_pit_state({x=pos.x+pit_region_size, y=0, z=pos.z}, name) or retval
retval = send_pit_state({x=pos.x-pit_region_size, y=0, z=pos.z-pit_region_size}, name) or retval
retval = send_pit_state({x=pos.x, y=0, z=pos.z-pit_region_size}, name) or retval
retval = send_pit_state({x=pos.x+pit_region_size, y=0, z=pos.z-pit_region_size}, name) or retval
return retval
end
minetest.register_chatcommand("findpit", {
params = "pos", -- Short parameter description
description = S("find the pits near the player's map region, or in the map region containing pos if provided"),
func = function(name, param)
if minetest.check_player_privs(name, {server = true}) then
local pos = {}
pos.x, pos.y, pos.z = string.match(param, "^([%d.-]+)[, ] *([%d.-]+)[, ] *([%d.-]+)$")
pos.x = tonumber(pos.x)
pos.y = tonumber(pos.y)
pos.z = tonumber(pos.z)
if pos.x and pos.y and pos.z then
if not send_nearby_states(pos, name) then
minetest.chat_send_player(name, S("No pits near @1", minetest.pos_to_string(pos)))
end
return true
else
local playerobj = minetest.get_player_by_name(name)
pos = playerobj:get_pos()
if not send_nearby_states(pos, name) then
pos.x = math.floor(pos.x)
pos.y = math.floor(pos.y)
pos.z = math.floor(pos.z)
minetest.chat_send_player(name, S("No pits near @1", minetest.pos_to_string(pos)))
end
return true
end
else
return false, S("You need the server privilege to use this command.")
end
end,
})

View File

@ -0,0 +1,11 @@
# textdomain: pit_caves
### init.lua ###
No pits near @1=
Pit at @1, bottom @2=
You need the server privilege to use this command.=
find the pits near the player's map region, or in the map region containing pos if provided=

4
pit_caves/mod.conf Normal file
View File

@ -0,0 +1,4 @@
name = pit_caves
description = Inserts very tall "pit" caves underground
depends =
optional_depends = mapgen_helper, default

View File

@ -0,0 +1,5 @@
pit_caves_min_bottom (Lower limit of bottoms of pits) int -2500
pit_caves_max_bottom (Upper limit of bottoms of pits) int -500
pit_caves_min_top (Lower limit of tops of pits) int -100
pit_caves_max_top (Upper limit of tops of pits) int 100
pit_caves_mapblock_spacing (Average number of map blocks between pits) int 16