mirror of
https://github.com/minetest-mods/nether.git
synced 2024-11-11 13:00:22 +01:00
Merge pull request #13 from Treer/feature/biome_mapgen
Switch mapgen to using biomes (still with backwards compatibility)
This commit is contained in:
commit
aac3ea6719
23
init.lua
23
init.lua
|
@ -38,9 +38,14 @@ nether = {}
|
||||||
nether.modname = minetest.get_current_modname()
|
nether.modname = minetest.get_current_modname()
|
||||||
nether.path = minetest.get_modpath(nether.modname)
|
nether.path = minetest.get_modpath(nether.modname)
|
||||||
nether.get_translator = S
|
nether.get_translator = S
|
||||||
|
-- nether.useBiomes allows other mods to know whether they can register ores etc. in the Nether.
|
||||||
|
-- See mapgen.lua for an explanation of why minetest.read_schematic is being checked
|
||||||
|
nether.useBiomes = minetest.get_mapgen_setting("mg_name") ~= "v6" and minetest.read_schematic ~= nil
|
||||||
|
|
||||||
|
|
||||||
-- Settings
|
-- Settings
|
||||||
nether.DEPTH = -5000 -- The y location of the Nether
|
nether.DEPTH_CEILING = -5000 -- The y location of the Nether's celing
|
||||||
|
nether.DEPTH_FLOOR = -11000 -- The y location of the Nether's floor
|
||||||
nether.FASTTRAVEL_FACTOR = 8 -- 10 could be better value for Minetest, since there's no sprint, but ex-Minecraft players will be mathing for 8
|
nether.FASTTRAVEL_FACTOR = 8 -- 10 could be better value for Minetest, since there's no sprint, but ex-Minecraft players will be mathing for 8
|
||||||
nether.PORTAL_BOOK_LOOT_WEIGHTING = 0.9 -- Likelyhood of finding the Book of Portals (guide) in dungeon chests. Set to 0 to disable.
|
nether.PORTAL_BOOK_LOOT_WEIGHTING = 0.9 -- Likelyhood of finding the Book of Portals (guide) in dungeon chests. Set to 0 to disable.
|
||||||
nether.NETHER_REALM_ENABLED = true -- Setting to false disables the Nether and Nether portal
|
nether.NETHER_REALM_ENABLED = true -- Setting to false disables the Nether and Nether portal
|
||||||
|
@ -50,13 +55,23 @@ nether.NETHER_REALM_ENABLED = true -- Setting to false disables the Nethe
|
||||||
nether.FASTTRAVEL_FACTOR = tonumber(minetest.settings:get("nether_fasttravel_factor") or nether.FASTTRAVEL_FACTOR)
|
nether.FASTTRAVEL_FACTOR = tonumber(minetest.settings:get("nether_fasttravel_factor") or nether.FASTTRAVEL_FACTOR)
|
||||||
nether.PORTAL_BOOK_LOOT_WEIGHTING = tonumber(minetest.settings:get("nether_portalBook_loot_weighting") or nether.PORTAL_BOOK_LOOT_WEIGHTING)
|
nether.PORTAL_BOOK_LOOT_WEIGHTING = tonumber(minetest.settings:get("nether_portalBook_loot_weighting") or nether.PORTAL_BOOK_LOOT_WEIGHTING)
|
||||||
nether.NETHER_REALM_ENABLED = minetest.settings:get_bool("nether_realm_enabled", nether.NETHER_REALM_ENABLED)
|
nether.NETHER_REALM_ENABLED = minetest.settings:get_bool("nether_realm_enabled", nether.NETHER_REALM_ENABLED)
|
||||||
|
nether.DEPTH_CEILING = tonumber(minetest.settings:get("nether_depth_ymax") or nether.DEPTH_CEILING)
|
||||||
|
nether.DEPTH_FLOOR = tonumber(minetest.settings:get("nether_depth_ymin") or nether.DEPTH_FLOOR)
|
||||||
|
|
||||||
|
if nether.DEPTH_FLOOR + 1000 > nether.DEPTH_CEILING then
|
||||||
|
error("The lower limit of the Nether must be set at least 1000 lower than the upper limit, and more than 3000 is recommended. Set settingtypes.txt, or 'All Settings' -> 'Mods' -> 'nether' -> 'Nether depth'", 0)
|
||||||
|
end
|
||||||
|
nether.DEPTH = nether.DEPTH_CEILING -- Deprecated, use nether.DEPTH_CEILING instead.
|
||||||
|
|
||||||
-- Load files
|
-- Load files
|
||||||
dofile(nether.path .. "/portal_api.lua")
|
dofile(nether.path .. "/portal_api.lua")
|
||||||
dofile(nether.path .. "/nodes.lua")
|
dofile(nether.path .. "/nodes.lua")
|
||||||
if nether.NETHER_REALM_ENABLED then
|
if nether.NETHER_REALM_ENABLED then
|
||||||
|
if nether.useBiomes then
|
||||||
dofile(nether.path .. "/mapgen.lua")
|
dofile(nether.path .. "/mapgen.lua")
|
||||||
|
else
|
||||||
|
dofile(nether.path .. "/mapgen_nobiomes.lua")
|
||||||
|
end
|
||||||
end
|
end
|
||||||
dofile(nether.path .. "/portal_examples.lua")
|
dofile(nether.path .. "/portal_examples.lua")
|
||||||
|
|
||||||
|
@ -83,7 +98,7 @@ This opens to a truly hellish place, though for small mercies the air there is s
|
||||||
The expedition parties have found no diamonds or gold, and after an experienced search party failed to return from the trail of a missing expedition party, I must conclude this is a dangerous place.]], 10 * nether.FASTTRAVEL_FACTOR),
|
The expedition parties have found no diamonds or gold, and after an experienced search party failed to return from the trail of a missing expedition party, I must conclude this is a dangerous place.]], 10 * nether.FASTTRAVEL_FACTOR),
|
||||||
|
|
||||||
is_within_realm = function(pos) -- return true if pos is inside the Nether
|
is_within_realm = function(pos) -- return true if pos is inside the Nether
|
||||||
return pos.y < nether.DEPTH
|
return pos.y < nether.DEPTH_CEILING
|
||||||
end,
|
end,
|
||||||
|
|
||||||
find_realm_anchorPos = function(surface_anchorPos)
|
find_realm_anchorPos = function(surface_anchorPos)
|
||||||
|
@ -91,7 +106,7 @@ The expedition parties have found no diamonds or gold, and after an experienced
|
||||||
local destination_pos = vector.divide(surface_anchorPos, nether.FASTTRAVEL_FACTOR)
|
local destination_pos = vector.divide(surface_anchorPos, nether.FASTTRAVEL_FACTOR)
|
||||||
destination_pos.x = math.floor(0.5 + destination_pos.x) -- round to int
|
destination_pos.x = math.floor(0.5 + destination_pos.x) -- round to int
|
||||||
destination_pos.z = math.floor(0.5 + destination_pos.z) -- round to int
|
destination_pos.z = math.floor(0.5 + destination_pos.z) -- round to int
|
||||||
destination_pos.y = nether.DEPTH - 1000 -- temp value so find_nearest_working_portal() returns nether portals
|
destination_pos.y = nether.DEPTH_CEILING - 1000 -- temp value so find_nearest_working_portal() returns nether portals
|
||||||
|
|
||||||
-- a y_factor of 0 makes the search ignore the altitude of the portals (as long as they are in the Nether)
|
-- a y_factor of 0 makes the search ignore the altitude of the portals (as long as they are in the Nether)
|
||||||
local existing_portal_location, existing_portal_orientation =
|
local existing_portal_location, existing_portal_orientation =
|
||||||
|
@ -100,7 +115,7 @@ The expedition parties have found no diamonds or gold, and after an experienced
|
||||||
if existing_portal_location ~= nil then
|
if existing_portal_location ~= nil then
|
||||||
return existing_portal_location, existing_portal_orientation
|
return existing_portal_location, existing_portal_orientation
|
||||||
else
|
else
|
||||||
local start_y = nether.DEPTH - math.random(500, 1500) -- Search starting altitude
|
local start_y = nether.DEPTH_CEILING - math.random(500, 1500) -- Search starting altitude
|
||||||
destination_pos.y = nether.find_nether_ground_y(destination_pos.x, destination_pos.z, start_y)
|
destination_pos.y = nether.find_nether_ground_y(destination_pos.x, destination_pos.z, start_y)
|
||||||
return destination_pos
|
return destination_pos
|
||||||
end
|
end
|
||||||
|
|
509
mapgen.lua
509
mapgen.lua
|
@ -22,11 +22,164 @@
|
||||||
|
|
||||||
-- Parameters
|
-- Parameters
|
||||||
|
|
||||||
local NETHER_DEPTH = nether.DEPTH
|
local NETHER_CEILING = nether.DEPTH_CEILING
|
||||||
|
local NETHER_FLOOR = nether.DEPTH_FLOOR
|
||||||
local TCAVE = 0.6
|
local TCAVE = 0.6
|
||||||
local BLEND = 128
|
local BLEND = 128
|
||||||
|
|
||||||
|
|
||||||
|
-- Stuff
|
||||||
|
|
||||||
|
local math_max, math_min = math.max, math.min -- avoid needing table lookups each time a common math function is invoked
|
||||||
|
|
||||||
|
if minetest.read_schematic == nil then
|
||||||
|
-- Using biomes to create the Nether requires the ability for biomes to set "node_cave_liquid = air".
|
||||||
|
-- This feature was introduced by paramat in b1b40fef1 on 2019-05-19, but we can't test for
|
||||||
|
-- it directly. However b2065756c was merged a few months later (in 2019-08-14) and it is easy
|
||||||
|
-- to directly test for - it adds minetest.read_schematic() - so we use this as a proxy-test
|
||||||
|
-- for whether the Minetest engine is recent enough to have implemented node_cave_liquid=air
|
||||||
|
error("This " .. nether.modname .. " mapgen requires Minetest v5.1 or greater, use mapgen_nobiomes.lua instead.", 0)
|
||||||
|
end
|
||||||
|
|
||||||
|
local function override_underground_biomes()
|
||||||
|
-- https://forum.minetest.net/viewtopic.php?p=257522#p257522
|
||||||
|
-- Q: Is there a way to override an already-registered biome so I can get it out of the
|
||||||
|
-- way of my own underground biomes without disturbing the other biomes registered by
|
||||||
|
-- default?
|
||||||
|
-- A: No, all you can do is use a mod to clear all biomes then re-register the complete
|
||||||
|
-- set but with your changes. It has been described as hacky but this is actually the
|
||||||
|
-- official way to alter biomes, most mods and subgames would want to completely change
|
||||||
|
-- all biomes anyway.
|
||||||
|
-- To avoid the engine side of mapgen becoming overcomplex the approach is to require mods
|
||||||
|
-- to do slightly more complex stuff in Lua.
|
||||||
|
|
||||||
|
-- take a copy of all biomes, decorations, and ores. Regregistering a biome changes its ID, so
|
||||||
|
-- any decorations or ores using the 'biomes' field must afterwards be cleared and re-registered.
|
||||||
|
-- https://github.com/minetest/minetest/issues/9288
|
||||||
|
local registered_biomes_copy = {}
|
||||||
|
local registered_decorations_copy = {}
|
||||||
|
local registered_ores_copy = {}
|
||||||
|
|
||||||
|
for old_biome_key, old_biome_def in pairs(minetest.registered_biomes) do
|
||||||
|
registered_biomes_copy[old_biome_key] = old_biome_def
|
||||||
|
end
|
||||||
|
for old_decoration_key, old_decoration_def in pairs(minetest.registered_decorations) do
|
||||||
|
registered_decorations_copy[old_decoration_key] = old_decoration_def
|
||||||
|
end
|
||||||
|
for old_ore_key, old_ore_def in pairs(minetest.registered_ores) do
|
||||||
|
registered_ores_copy[old_ore_key] = old_ore_def
|
||||||
|
end
|
||||||
|
|
||||||
|
-- clear biomes, decorations, and ores
|
||||||
|
minetest.clear_registered_decorations()
|
||||||
|
minetest.clear_registered_ores()
|
||||||
|
minetest.clear_registered_biomes()
|
||||||
|
|
||||||
|
-- Restore biomes, adjusted to not overlap the Nether
|
||||||
|
for biome_key, new_biome_def in pairs(registered_biomes_copy) do
|
||||||
|
local biome_y_max, biome_y_min = tonumber(new_biome_def.y_max), tonumber(new_biome_def.y_min)
|
||||||
|
|
||||||
|
if biome_y_max > NETHER_FLOOR and biome_y_min < NETHER_CEILING then
|
||||||
|
-- This biome occupies some or all of the depth of the Nether, shift/crop it.
|
||||||
|
local spaceOccupiedAbove = biome_y_max - NETHER_CEILING
|
||||||
|
local spaceOccupiedBelow = NETHER_FLOOR - biome_y_min
|
||||||
|
if spaceOccupiedAbove >= spaceOccupiedBelow or biome_y_min <= -30000 then
|
||||||
|
-- place the biome above the Nether
|
||||||
|
-- We also shift biomes which extend to the bottom of the map above the Nether, since they
|
||||||
|
-- likely only extend that deep as a catch-all, and probably have a role nearer the surface.
|
||||||
|
new_biome_def.y_min = NETHER_CEILING + 1
|
||||||
|
new_biome_def.y_max = math_max(biome_y_max, NETHER_CEILING + 2)
|
||||||
|
else
|
||||||
|
-- shift the biome to below the Nether
|
||||||
|
new_biome_def.y_max = NETHER_FLOOR - 1
|
||||||
|
new_biome_def.y_min = math_min(biome_y_min, NETHER_CEILING - 2)
|
||||||
|
end
|
||||||
|
end
|
||||||
|
minetest.register_biome(new_biome_def)
|
||||||
|
end
|
||||||
|
|
||||||
|
-- Restore biome decorations
|
||||||
|
for decoration_key, new_decoration_def in pairs(registered_decorations_copy) do
|
||||||
|
minetest.register_decoration(new_decoration_def)
|
||||||
|
end
|
||||||
|
-- Restore biome ores
|
||||||
|
for ore_key, new_ore_def in pairs(registered_ores_copy) do
|
||||||
|
minetest.register_ore(new_ore_def)
|
||||||
|
end
|
||||||
|
end
|
||||||
|
|
||||||
|
-- Shift any overlapping biomes out of the way before we create the Nether biomes
|
||||||
|
override_underground_biomes()
|
||||||
|
|
||||||
|
-- nether:native_mapgen is used to prevent ores and decorations being generated according
|
||||||
|
-- to landforms created by the native mapgen.
|
||||||
|
-- Ores and decorations are registered against "nether:rack" instead, and the lua
|
||||||
|
-- on_generate() callback will carve the Nether with nether:rack before invoking
|
||||||
|
-- generate_decorations and generate_ores.
|
||||||
|
minetest.register_node("nether:native_mapgen", {})
|
||||||
|
|
||||||
|
minetest.register_biome({
|
||||||
|
name = "nether_caverns",
|
||||||
|
node_stone = "nether:native_mapgen", -- nether:native_mapgen is used here to prevent the native mapgen from placing ores and decorations.
|
||||||
|
node_filler = "nether:native_mapgen", -- The lua on_generate will transform nether:rack_native into nether:rack then decorate and add ores.
|
||||||
|
node_dungeon = "nether:brick",
|
||||||
|
--node_dungeon_alt = "default:mossycobble",
|
||||||
|
node_dungeon_stair = "stairs:stair_nether_brick",
|
||||||
|
-- Setting node_cave_liquid to "air" avoids the need to filter lava and water out of the mapchunk and
|
||||||
|
-- surrounding shell (overdraw nodes beyond the mapchunk).
|
||||||
|
-- This feature was introduced by paramat in b1b40fef1 on 2019-05-19, and this mapgen.lua file should only
|
||||||
|
-- be run if the Minetest version includes it. The earliest tag made after 2019-05-19 is 5.1.0 on 2019-10-13,
|
||||||
|
-- however we shouldn't test version numbers. minetest.read_schematic() was added by b2065756c and merged in
|
||||||
|
-- 2019-08-14 and is easy to test for, we don't use it but it should make a good proxy-test for whether the
|
||||||
|
-- Minetest version is recent enough to have implemented node_cave_liquid=air
|
||||||
|
node_cave_liquid = "air",
|
||||||
|
y_max = NETHER_CEILING,
|
||||||
|
y_min = NETHER_FLOOR,
|
||||||
|
vertical_blend = 0,
|
||||||
|
heat_point = 50,
|
||||||
|
humidity_point = 50,
|
||||||
|
})
|
||||||
|
|
||||||
|
|
||||||
|
-- Ores and decorations
|
||||||
|
|
||||||
|
dofile(nether.path .. "/mapgen_decorations.lua")
|
||||||
|
|
||||||
|
minetest.register_ore({
|
||||||
|
ore_type = "scatter",
|
||||||
|
ore = "nether:glowstone",
|
||||||
|
wherein = "nether:rack",
|
||||||
|
clust_scarcity = 11 * 11 * 11,
|
||||||
|
clust_num_ores = 3,
|
||||||
|
clust_size = 2,
|
||||||
|
y_max = NETHER_CEILING,
|
||||||
|
y_min = NETHER_FLOOR,
|
||||||
|
})
|
||||||
|
|
||||||
|
minetest.register_ore({
|
||||||
|
ore_type = "scatter",
|
||||||
|
ore = "default:lava_source",
|
||||||
|
wherein = "nether:rack",
|
||||||
|
clust_scarcity = 32 * 32 * 32,
|
||||||
|
clust_num_ores = 4,
|
||||||
|
clust_size = 2,
|
||||||
|
y_max = NETHER_CEILING,
|
||||||
|
y_min = NETHER_FLOOR,
|
||||||
|
})
|
||||||
|
|
||||||
|
minetest.register_ore({
|
||||||
|
ore_type = "blob",
|
||||||
|
ore = "nether:sand",
|
||||||
|
wherein = "nether:rack",
|
||||||
|
clust_scarcity = 14 * 14 * 14,
|
||||||
|
clust_size = 8,
|
||||||
|
y_max = NETHER_CEILING,
|
||||||
|
y_min = NETHER_FLOOR
|
||||||
|
})
|
||||||
|
|
||||||
|
|
||||||
|
-- Mapgen
|
||||||
|
|
||||||
-- 3D noise
|
-- 3D noise
|
||||||
|
|
||||||
local np_cave = {
|
local np_cave = {
|
||||||
|
@ -40,159 +193,275 @@ local np_cave = {
|
||||||
--flags = ""
|
--flags = ""
|
||||||
}
|
}
|
||||||
|
|
||||||
|
-- Buffers and objects we shouldn't recreate every on_generate
|
||||||
-- Stuff
|
|
||||||
|
|
||||||
local yblmax = NETHER_DEPTH - BLEND * 2
|
|
||||||
|
|
||||||
|
|
||||||
|
|
||||||
|
|
||||||
-- Mapgen
|
|
||||||
|
|
||||||
-- Initialize noise object, localise noise and data buffers
|
|
||||||
|
|
||||||
local nobj_cave = nil
|
local nobj_cave = nil
|
||||||
local nbuf_cave = nil
|
local nbuf_cave = nil
|
||||||
local dbuf = nil
|
local dbuf = nil
|
||||||
|
|
||||||
|
local yblmin = NETHER_FLOOR + BLEND * 2
|
||||||
|
local yblmax = NETHER_CEILING - BLEND * 2
|
||||||
|
|
||||||
-- Content ids
|
-- Content ids
|
||||||
|
|
||||||
local c_air = minetest.get_content_id("air")
|
local c_air = minetest.get_content_id("air")
|
||||||
|
|
||||||
--local c_stone_with_coal = minetest.get_content_id("default:stone_with_coal")
|
|
||||||
--local c_stone_with_iron = minetest.get_content_id("default:stone_with_iron")
|
|
||||||
local c_stone_with_mese = minetest.get_content_id("default:stone_with_mese")
|
|
||||||
local c_stone_with_diamond = minetest.get_content_id("default:stone_with_diamond")
|
|
||||||
local c_stone_with_gold = minetest.get_content_id("default:stone_with_gold")
|
|
||||||
--local c_stone_with_copper = minetest.get_content_id("default:stone_with_copper")
|
|
||||||
local c_mese = minetest.get_content_id("default:mese")
|
|
||||||
|
|
||||||
local c_gravel = minetest.get_content_id("default:gravel")
|
|
||||||
local c_dirt = minetest.get_content_id("default:dirt")
|
|
||||||
local c_sand = minetest.get_content_id("default:sand")
|
|
||||||
|
|
||||||
local c_cobble = minetest.get_content_id("default:cobble")
|
|
||||||
local c_mossycobble = minetest.get_content_id("default:mossycobble")
|
|
||||||
local c_stair_cobble = minetest.get_content_id("stairs:stair_cobble")
|
|
||||||
|
|
||||||
local c_lava_source = minetest.get_content_id("default:lava_source")
|
|
||||||
local c_lava_flowing = minetest.get_content_id("default:lava_flowing")
|
|
||||||
local c_water_source = minetest.get_content_id("default:water_source")
|
|
||||||
local c_water_flowing = minetest.get_content_id("default:water_flowing")
|
|
||||||
|
|
||||||
local c_glowstone = minetest.get_content_id("nether:glowstone")
|
|
||||||
local c_nethersand = minetest.get_content_id("nether:sand")
|
|
||||||
local c_netherbrick = minetest.get_content_id("nether:brick")
|
|
||||||
local c_netherrack = minetest.get_content_id("nether:rack")
|
local c_netherrack = minetest.get_content_id("nether:rack")
|
||||||
|
local c_netherbrick = minetest.get_content_id("nether:brick")
|
||||||
|
local c_netherbrick_slab = minetest.get_content_id("stairs:slab_nether_brick")
|
||||||
|
local c_netherfence = minetest.get_content_id("nether:fence_nether_brick")
|
||||||
|
local c_glowstone = minetest.get_content_id("nether:glowstone")
|
||||||
|
local c_lava_source = minetest.get_content_id("default:lava_source")
|
||||||
|
local c_native_mapgen = minetest.get_content_id("nether:native_mapgen")
|
||||||
|
|
||||||
|
|
||||||
|
-- Dungeon excavation functions
|
||||||
|
|
||||||
|
function build_dungeon_room_list(data, area)
|
||||||
|
|
||||||
|
local result = {}
|
||||||
|
|
||||||
|
-- Unfortunately gennotify only returns dungeon rooms, not corridors.
|
||||||
|
-- We don't need to check for temples because only dungeons are generated in biomes
|
||||||
|
-- that define their own dungeon nodes.
|
||||||
|
local gennotify = minetest.get_mapgen_object("gennotify")
|
||||||
|
local roomLocations = gennotify["dungeon"] or {}
|
||||||
|
|
||||||
|
-- Excavation should still know to stop if a cave or corridor has removed the dungeon wall.
|
||||||
|
-- See MapgenBasic::generateDungeons in mapgen.cpp for max room sizes.
|
||||||
|
local maxRoomSize = 18
|
||||||
|
local maxRoomRadius = math.ceil(maxRoomSize / 2)
|
||||||
|
|
||||||
|
local xStride, yStride, zStride = 1, area.ystride, area.zstride
|
||||||
|
local minEdge, maxEdge = area.MinEdge, area.MaxEdge
|
||||||
|
|
||||||
|
for _, roomPos in ipairs(roomLocations) do
|
||||||
|
|
||||||
|
if area:containsp(roomPos) then -- this safety check does not appear to be necessary, but lets make it explicit
|
||||||
|
|
||||||
|
local room_vi = area:indexp(roomPos)
|
||||||
|
--data[room_vi] = minetest.get_content_id("default:torch") -- debug
|
||||||
|
|
||||||
|
local startPos = vector.new(roomPos)
|
||||||
|
if roomPos.y + 1 <= maxEdge.y and data[room_vi + yStride] == c_air then
|
||||||
|
-- The roomPos coords given by gennotify are at floor level, but whenever possible we
|
||||||
|
-- want to be performing searches a node higher than floor level to avoids dungeon chests.
|
||||||
|
startPos.y = startPos.y + 1
|
||||||
|
room_vi = area:indexp(startPos)
|
||||||
|
end
|
||||||
|
|
||||||
|
local bound_min_x = math_max(minEdge.x, roomPos.x - maxRoomRadius)
|
||||||
|
local bound_min_y = math_max(minEdge.y, roomPos.y - 1) -- room coords given by gennotify are on the floor
|
||||||
|
local bound_min_z = math_max(minEdge.z, roomPos.z - maxRoomRadius)
|
||||||
|
|
||||||
|
local bound_max_x = math_min(maxEdge.x, roomPos.x + maxRoomRadius)
|
||||||
|
local bound_max_y = math_min(maxEdge.y, roomPos.y + maxRoomSize) -- room coords given by gennotify are on the floor
|
||||||
|
local bound_max_z = math_min(maxEdge.z, roomPos.z + maxRoomRadius)
|
||||||
|
|
||||||
|
local room_min = vector.new(startPos)
|
||||||
|
local room_max = vector.new(startPos)
|
||||||
|
|
||||||
|
local vi = room_vi
|
||||||
|
while room_max.y < bound_max_y and data[vi + yStride] == c_air do
|
||||||
|
room_max.y = room_max.y + 1
|
||||||
|
vi = vi + yStride
|
||||||
|
end
|
||||||
|
|
||||||
|
vi = room_vi
|
||||||
|
while room_min.y > bound_min_y and data[vi - yStride] == c_air do
|
||||||
|
room_min.y = room_min.y - 1
|
||||||
|
vi = vi - yStride
|
||||||
|
end
|
||||||
|
|
||||||
|
vi = room_vi
|
||||||
|
while room_max.z < bound_max_z and data[vi + zStride] == c_air do
|
||||||
|
room_max.z = room_max.z + 1
|
||||||
|
vi = vi + zStride
|
||||||
|
end
|
||||||
|
|
||||||
|
vi = room_vi
|
||||||
|
while room_min.z > bound_min_z and data[vi - zStride] == c_air do
|
||||||
|
room_min.z = room_min.z - 1
|
||||||
|
vi = vi - zStride
|
||||||
|
end
|
||||||
|
|
||||||
|
vi = room_vi
|
||||||
|
while room_max.x < bound_max_x and data[vi + xStride] == c_air do
|
||||||
|
room_max.x = room_max.x + 1
|
||||||
|
vi = vi + xStride
|
||||||
|
end
|
||||||
|
|
||||||
|
vi = room_vi
|
||||||
|
while room_min.x > bound_min_x and data[vi - xStride] == c_air do
|
||||||
|
room_min.x = room_min.x - 1
|
||||||
|
vi = vi - xStride
|
||||||
|
end
|
||||||
|
|
||||||
|
local roomInfo = vector.new(roomPos)
|
||||||
|
roomInfo.minp = room_min
|
||||||
|
roomInfo.maxp = room_max
|
||||||
|
result[#result + 1] = roomInfo
|
||||||
|
end
|
||||||
|
end
|
||||||
|
|
||||||
|
return result;
|
||||||
|
end
|
||||||
|
|
||||||
|
-- Only partially excavates dungeons, the rest is left as an exercise for the player ;)
|
||||||
|
-- (Corridors and the parts of rooms which extend beyond the emerge boundary will remain filled)
|
||||||
|
function excavate_dungeons(data, area, rooms)
|
||||||
|
|
||||||
|
-- any air from the native mapgen has been replaced by netherrack, but
|
||||||
|
-- we don't want this inside dungeons, so fill dungeon rooms with air
|
||||||
|
for _, roomInfo in ipairs(rooms) do
|
||||||
|
|
||||||
|
local room_min = roomInfo.minp
|
||||||
|
local room_max = roomInfo.maxp
|
||||||
|
|
||||||
|
for z = room_min.z, room_max.z do
|
||||||
|
for y = room_min.y, room_max.y do
|
||||||
|
local vi = area:index(room_min.x, y, z)
|
||||||
|
for x = room_min.x, room_max.x do
|
||||||
|
if data[vi] == c_netherrack then data[vi] = c_air end
|
||||||
|
vi = vi + 1
|
||||||
|
end
|
||||||
|
end
|
||||||
|
end
|
||||||
|
end
|
||||||
|
end
|
||||||
|
|
||||||
|
-- Since we already know where all the rooms and their walls are, and have all the nodes stored
|
||||||
|
-- in a voxelmanip already, we may as well add a little Nether flair to the dungeons found here.
|
||||||
|
function decorate_dungeons(data, area, rooms)
|
||||||
|
|
||||||
|
local xStride, yStride, zStride = 1, area.ystride, area.zstride
|
||||||
|
local minEdge, maxEdge = area.MinEdge, area.MaxEdge
|
||||||
|
|
||||||
|
for _, roomInfo in ipairs(rooms) do
|
||||||
|
|
||||||
|
local room_min, room_max = roomInfo.minp, roomInfo.maxp
|
||||||
|
local room_size = vector.distance(room_min, room_max)
|
||||||
|
|
||||||
|
if room_size > 10 then
|
||||||
|
local room_seed = roomInfo.x + 3 * roomInfo.z + 13 * roomInfo.y
|
||||||
|
local window_y = roomInfo.y + math_min(2, room_max.y - roomInfo.y - 1)
|
||||||
|
|
||||||
|
if room_seed % 3 == 0 and room_max.y < maxEdge.y then
|
||||||
|
-- Glowstone chandelier
|
||||||
|
local vi = area:index(roomInfo.x, room_max.y + 1, roomInfo.z)
|
||||||
|
if data[vi] == c_netherbrick then data[vi] = c_glowstone end
|
||||||
|
|
||||||
|
elseif room_seed % 4 == 0 and room_min.y > minEdge.y
|
||||||
|
and room_min.x > minEdge.x and room_max.x < maxEdge.x
|
||||||
|
and room_min.z > minEdge.z and room_max.z < maxEdge.z then
|
||||||
|
-- lava well (feel free to replace with a fancy schematic)
|
||||||
|
local vi = area:index(roomInfo.x, room_min.y, roomInfo.z)
|
||||||
|
if data[vi - yStride] == c_netherbrick then data[vi - yStride] = c_lava_source end
|
||||||
|
if data[vi - zStride] == c_air then data[vi - zStride] = c_netherbrick_slab end
|
||||||
|
if data[vi + zStride] == c_air then data[vi + zStride] = c_netherbrick_slab end
|
||||||
|
if data[vi - xStride] == c_air then data[vi - xStride] = c_netherbrick_slab end
|
||||||
|
if data[vi + xStride] == c_air then data[vi + xStride] = c_netherbrick_slab end
|
||||||
|
end
|
||||||
|
|
||||||
|
-- Barred windows
|
||||||
|
if room_seed % 7 < 5 and room_max.x - room_min.x >= 4 and room_max.z - room_min.z >= 4
|
||||||
|
and window_y >= minEdge.y and window_y + 1 <= maxEdge.y
|
||||||
|
and room_min.x > minEdge.x and room_max.x < maxEdge.x
|
||||||
|
and room_min.z > minEdge.z and room_max.z < maxEdge.z then
|
||||||
|
--data[area:indexp(roomInfo)] = minetest.get_content_id("default:mese_post_light") -- debug
|
||||||
|
|
||||||
|
-- Until whisper glass is added, every window will be made of netherbrick fence (rather
|
||||||
|
-- than material depending on room_seed)
|
||||||
|
local window_node = c_netherfence
|
||||||
|
|
||||||
|
local vi_min = area:index(room_min.x - 1, window_y, roomInfo.z)
|
||||||
|
local vi_max = area:index(room_max.x + 1, window_y, roomInfo.z)
|
||||||
|
local locations = {-zStride, zStride, -zStride + yStride, zStride + yStride}
|
||||||
|
for _, offset in ipairs(locations) do
|
||||||
|
if data[vi_min + offset] == c_netherbrick then data[vi_min + offset] = window_node end
|
||||||
|
if data[vi_max + offset] == c_netherbrick then data[vi_max + offset] = window_node end
|
||||||
|
end
|
||||||
|
vi_min = area:index(roomInfo.x, window_y, room_min.z - 1)
|
||||||
|
vi_max = area:index(roomInfo.x, window_y, room_max.z + 1)
|
||||||
|
locations = {-xStride, xStride, -xStride + yStride, xStride + yStride}
|
||||||
|
for _, offset in ipairs(locations) do
|
||||||
|
if data[vi_min + offset] == c_netherbrick then data[vi_min + offset] = window_node end
|
||||||
|
if data[vi_max + offset] == c_netherbrick then data[vi_max + offset] = window_node end
|
||||||
|
end
|
||||||
|
end
|
||||||
|
|
||||||
|
-- Weeds on the floor once Nether weeds are added
|
||||||
|
end
|
||||||
|
end
|
||||||
|
end
|
||||||
|
|
||||||
|
|
||||||
-- On-generated function
|
-- On-generated function
|
||||||
|
|
||||||
minetest.register_on_generated(function(minp, maxp, seed)
|
local function on_generated(minp, maxp, seed)
|
||||||
if minp.y > NETHER_DEPTH then
|
|
||||||
|
if minp.y > NETHER_CEILING or maxp.y < NETHER_FLOOR then
|
||||||
return
|
return
|
||||||
end
|
end
|
||||||
|
|
||||||
local x1 = maxp.x
|
local vm, emerge_min, emerge_max = minetest.get_mapgen_object("voxelmanip")
|
||||||
local y1 = maxp.y
|
local area = VoxelArea:new{MinEdge=emerge_min, MaxEdge=emerge_max}
|
||||||
local z1 = maxp.z
|
|
||||||
local x0 = minp.x
|
|
||||||
local y0 = minp.y
|
|
||||||
local z0 = minp.z
|
|
||||||
|
|
||||||
local vm, emin, emax = minetest.get_mapgen_object("voxelmanip")
|
|
||||||
local area = VoxelArea:new{MinEdge = emin, MaxEdge = emax}
|
|
||||||
local data = vm:get_data(dbuf)
|
local data = vm:get_data(dbuf)
|
||||||
|
|
||||||
local x11 = emax.x -- Limits of mapchunk plus mapblock shell
|
local x0, y0, z0 = minp.x, math_max(minp.y, NETHER_FLOOR), minp.z
|
||||||
local y11 = emax.y
|
local x1, y1, z1 = maxp.x, math_min(maxp.y, NETHER_CEILING), maxp.z
|
||||||
local z11 = emax.z
|
|
||||||
local x00 = emin.x
|
|
||||||
local y00 = emin.y
|
|
||||||
local z00 = emin.z
|
|
||||||
|
|
||||||
local ystride = x1 - x0 + 1
|
local yCaveStride = x1 - x0 + 1
|
||||||
local zstride = ystride * ystride
|
local zCaveStride = yCaveStride * yCaveStride
|
||||||
local chulens = {x = ystride, y = ystride, z = ystride}
|
local chulens = {x = yCaveStride, y = yCaveStride, z = yCaveStride}
|
||||||
local minposxyz = {x = x0, y = y0, z = z0}
|
|
||||||
|
|
||||||
nobj_cave = nobj_cave or minetest.get_perlin_map(np_cave, chulens)
|
nobj_cave = nobj_cave or minetest.get_perlin_map(np_cave, chulens)
|
||||||
local nvals_cave = nobj_cave:get3dMap_flat(minposxyz, nbuf_cave)
|
local nvals_cave = nobj_cave:get3dMap_flat(minp, nbuf_cave)
|
||||||
|
|
||||||
for y = y00, y11 do -- Y loop first to minimise tcave calculations
|
|
||||||
local tcave
|
|
||||||
local in_chunk_y = false
|
|
||||||
if y >= y0 and y <= y1 then
|
|
||||||
if y > yblmax then
|
|
||||||
tcave = TCAVE + ((y - yblmax) / BLEND) ^ 2
|
|
||||||
else
|
|
||||||
tcave = TCAVE
|
|
||||||
end
|
|
||||||
in_chunk_y = true
|
|
||||||
end
|
|
||||||
|
|
||||||
for z = z00, z11 do
|
local dungeonRooms = build_dungeon_room_list(data, area)
|
||||||
local vi = area:index(x00, y, z) -- Initial voxelmanip index
|
|
||||||
local ni
|
|
||||||
local in_chunk_yz = in_chunk_y and z >= z0 and z <= z1
|
|
||||||
|
|
||||||
for x = x00, x11 do
|
for y = y0, y1 do -- Y loop first to minimise tcave calculations
|
||||||
if in_chunk_yz and x == x0 then
|
|
||||||
-- Initial noisemap index
|
local tcave = TCAVE
|
||||||
ni = (z - z0) * zstride + (y - y0) * ystride + 1
|
if y > yblmax then tcave = TCAVE + ((y - yblmax) / BLEND) ^ 2 end
|
||||||
end
|
if y < yblmin then tcave = TCAVE + ((yblmin - y) / BLEND) ^ 2 end
|
||||||
local in_chunk_yzx = in_chunk_yz and x >= x0 and x <= x1 -- In mapchunk
|
|
||||||
|
for z = z0, z1 do
|
||||||
|
local vi = area:index(x0, y, z) -- Initial voxelmanip index
|
||||||
|
local ni = (z - z0) * zCaveStride + (y - y0) * yCaveStride + 1
|
||||||
|
|
||||||
|
for x = x0, x1 do
|
||||||
|
|
||||||
local id = data[vi] -- Existing node
|
local id = data[vi] -- Existing node
|
||||||
-- Cave air, cave liquids and dungeons are overgenerated,
|
|
||||||
-- convert these throughout mapchunk plus shell
|
if nvals_cave[ni] > tcave then
|
||||||
if id == c_air or -- Air and liquids to air
|
|
||||||
id == c_lava_source or
|
|
||||||
id == c_lava_flowing or
|
|
||||||
id == c_water_source or
|
|
||||||
id == c_water_flowing then
|
|
||||||
data[vi] = c_air
|
data[vi] = c_air
|
||||||
-- Dungeons are preserved so we don't need
|
elseif id == c_air or id == c_native_mapgen then
|
||||||
-- to check for cavern in the shell
|
data[vi] = c_netherrack -- excavate_dungeons() will mostly reverse this inside dungeons
|
||||||
elseif id == c_cobble or -- Dungeons (preserved) to netherbrick
|
|
||||||
id == c_mossycobble or
|
|
||||||
id == c_stair_cobble then
|
|
||||||
data[vi] = c_netherbrick
|
|
||||||
end
|
|
||||||
|
|
||||||
if in_chunk_yzx then -- In mapchunk
|
|
||||||
if nvals_cave[ni] > tcave then -- Only excavate cavern in mapchunk
|
|
||||||
data[vi] = c_air
|
|
||||||
elseif id == c_mese then -- Mese block to lava
|
|
||||||
data[vi] = c_lava_source
|
|
||||||
elseif id == c_stone_with_gold or -- Precious ores to glowstone
|
|
||||||
id == c_stone_with_mese or
|
|
||||||
id == c_stone_with_diamond then
|
|
||||||
data[vi] = c_glowstone
|
|
||||||
elseif id == c_gravel or -- Blob ore to nethersand
|
|
||||||
id == c_dirt or
|
|
||||||
id == c_sand then
|
|
||||||
data[vi] = c_nethersand
|
|
||||||
else -- All else to netherstone
|
|
||||||
data[vi] = c_netherrack
|
|
||||||
end
|
|
||||||
|
|
||||||
ni = ni + 1 -- Only increment noise index in mapchunk
|
|
||||||
end
|
end
|
||||||
|
|
||||||
|
ni = ni + 1
|
||||||
vi = vi + 1
|
vi = vi + 1
|
||||||
end
|
end
|
||||||
end
|
end
|
||||||
end
|
end
|
||||||
|
|
||||||
|
-- any air from the native mapgen has been replaced by netherrack, but we
|
||||||
|
-- don't want netherrack inside dungeons, so fill known dungeon rooms with air.
|
||||||
|
excavate_dungeons(data, area, dungeonRooms)
|
||||||
|
decorate_dungeons(data, area, dungeonRooms)
|
||||||
|
|
||||||
vm:set_data(data)
|
vm:set_data(data)
|
||||||
vm:set_lighting({day = 0, night = 0})
|
|
||||||
|
-- avoid generating decorations on the underside of the bottom of the nether
|
||||||
|
if minp.y > NETHER_FLOOR and maxp.y < NETHER_CEILING then minetest.generate_decorations(vm) end
|
||||||
|
|
||||||
|
minetest.generate_ores(vm)
|
||||||
|
vm:set_lighting({day = 0, night = 0}, minp, maxp)
|
||||||
vm:calc_lighting()
|
vm:calc_lighting()
|
||||||
vm:update_liquids()
|
vm:update_liquids()
|
||||||
vm:write_to_map()
|
vm:write_to_map()
|
||||||
end)
|
end
|
||||||
|
|
||||||
|
|
||||||
-- use knowledge of the nether mapgen algorithm to return a suitable ground level for placing a portal.
|
-- use knowledge of the nether mapgen algorithm to return a suitable ground level for placing a portal.
|
||||||
|
@ -200,7 +469,7 @@ function nether.find_nether_ground_y(target_x, target_z, start_y)
|
||||||
local nobj_cave_point = minetest.get_perlin(np_cave)
|
local nobj_cave_point = minetest.get_perlin(np_cave)
|
||||||
local air = 0 -- Consecutive air nodes found
|
local air = 0 -- Consecutive air nodes found
|
||||||
|
|
||||||
for y = start_y, start_y - 4096, -1 do
|
for y = start_y, math_max(NETHER_FLOOR + BLEND, start_y - 4096), -1 do
|
||||||
local nval_cave = nobj_cave_point:get3d({x = target_x, y = y, z = target_z})
|
local nval_cave = nobj_cave_point:get3d({x = target_x, y = y, z = target_z})
|
||||||
|
|
||||||
if nval_cave > TCAVE then -- Cavern
|
if nval_cave > TCAVE then -- Cavern
|
||||||
|
@ -221,5 +490,11 @@ function nether.find_nether_ground_y(target_x, target_z, start_y)
|
||||||
end
|
end
|
||||||
end
|
end
|
||||||
|
|
||||||
return start_y -- Fallback
|
return math_max(start_y, NETHER_FLOOR + BLEND) -- Fallback
|
||||||
end
|
end
|
||||||
|
|
||||||
|
-- We don't need to be gen-notified of temples because only dungeons will be generated
|
||||||
|
-- if a biome defines the dungeon nodes
|
||||||
|
minetest.set_gen_notify({dungeon = true})
|
||||||
|
|
||||||
|
minetest.register_on_generated(on_generated)
|
138
mapgen_decorations.lua
Normal file
138
mapgen_decorations.lua
Normal file
|
@ -0,0 +1,138 @@
|
||||||
|
--[[
|
||||||
|
|
||||||
|
Register decorations for Nether mapgen
|
||||||
|
|
||||||
|
Copyright (C) 2020 Treer
|
||||||
|
|
||||||
|
Permission to use, copy, modify, and/or distribute this software for
|
||||||
|
any purpose with or without fee is hereby granted, provided that the
|
||||||
|
above copyright notice and this permission notice appear in all copies.
|
||||||
|
|
||||||
|
THE SOFTWARE IS PROVIDED "AS IS" AND THE AUTHOR DISCLAIMS ALL
|
||||||
|
WARRANTIES WITH REGARD TO THIS SOFTWARE INCLUDING ALL IMPLIED
|
||||||
|
WARRANTIES OF MERCHANTABILITY AND FITNESS. IN NO EVENT SHALL THE AUTHOR
|
||||||
|
BE LIABLE FOR ANY SPECIAL, DIRECT, INDIRECT, OR CONSEQUENTIAL DAMAGES
|
||||||
|
OR ANY DAMAGES WHATSOEVER RESULTING FROM LOSS OF USE, DATA OR PROFITS,
|
||||||
|
WHETHER IN AN ACTION OF CONTRACT, NEGLIGENCE OR OTHER TORTIOUS ACTION,
|
||||||
|
ARISING OUT OF OR IN CONNECTION WITH THE USE OR PERFORMANCE OF THIS
|
||||||
|
SOFTWARE.
|
||||||
|
|
||||||
|
]]--
|
||||||
|
|
||||||
|
-- Lava is unreliable in the old Nether mapgen because it removes lava
|
||||||
|
-- from the overdraw areas, so any decorations involving lava will often
|
||||||
|
-- have the lava missing depending on whether nearby chunks were already
|
||||||
|
-- emerged or not before the decoration was placed.
|
||||||
|
local allow_lava_decorations = nether.useBiomes
|
||||||
|
|
||||||
|
local _ = {name = "air", prob = 0}
|
||||||
|
local A = {name = "air", prob = 255, force_place = true}
|
||||||
|
local G = {name = "nether:glowstone", prob = 255, force_place = true}
|
||||||
|
local N = {name = "nether:rack", prob = 255}
|
||||||
|
local S = {name = "nether:sand", prob = 255, force_place = true}
|
||||||
|
local L = {name = "default:lava_source", prob = 255, force_place = true}
|
||||||
|
|
||||||
|
|
||||||
|
-- =================
|
||||||
|
-- Stalactites
|
||||||
|
-- =================
|
||||||
|
|
||||||
|
local schematic_GlowstoneStalactite = {
|
||||||
|
size = {x = 5, y = 10, z = 5},
|
||||||
|
data = {
|
||||||
|
_, _, _, _, _,
|
||||||
|
_, _, _, _, _,
|
||||||
|
_, _, _, _, _,
|
||||||
|
_, _, _, _, _,
|
||||||
|
_, _, _, _, _,
|
||||||
|
_, _, _, _, _,
|
||||||
|
_, _, _, _, _,
|
||||||
|
_, _, _, _, _,
|
||||||
|
_, N, G, N, _,
|
||||||
|
_, N, N, N, _,
|
||||||
|
|
||||||
|
_, _, _, _, _,
|
||||||
|
_, _, _, _, _,
|
||||||
|
_, _, _, _, _,
|
||||||
|
_, _, _, _, _,
|
||||||
|
_, _, _, _, _,
|
||||||
|
_, _, G, _, _,
|
||||||
|
_, _, G, _, _,
|
||||||
|
_, G, G, G, _,
|
||||||
|
N, G, G, G, N,
|
||||||
|
N, N, G, N, N,
|
||||||
|
|
||||||
|
_, _, N, _, _, -- ypos 0, prob 25% (64/256)
|
||||||
|
_, _, G, _, _, -- ypos 1, prob 37% (96/256)
|
||||||
|
_, _, G, _, _, -- ypos 2, prob 100%
|
||||||
|
_, _, G, _, _, -- ypos 3, prob 100%
|
||||||
|
_, _, G, G, _, -- ypos 4, prob 50% (128/256) to make half of stalactites asymmetric
|
||||||
|
_, G, G, G, _, -- ypos 5, prob 75% (192/256)
|
||||||
|
_, G, G, G, _, -- ypos 6, prob 75% (192/256)
|
||||||
|
_, G, G, G, _, -- ypos 7, prob 100%
|
||||||
|
G, G, G, G, G, -- ypos 8, prob 100%
|
||||||
|
N, G, G, G, N, -- ypos 9, prob 75% (192/256)
|
||||||
|
|
||||||
|
_, _, _, _, _,
|
||||||
|
_, _, _, _, _,
|
||||||
|
_, _, _, _, _,
|
||||||
|
_, _, _, _, _,
|
||||||
|
_, _, G, _, _,
|
||||||
|
_, _, G, _, _,
|
||||||
|
_, _, G, _, _,
|
||||||
|
_, G, G, G, _,
|
||||||
|
N, G, G, G, N,
|
||||||
|
N, N, G, N, N,
|
||||||
|
|
||||||
|
_, _, _, _, _,
|
||||||
|
_, _, _, _, _,
|
||||||
|
_, _, _, _, _,
|
||||||
|
_, _, _, _, _,
|
||||||
|
_, _, _, _, _,
|
||||||
|
_, _, _, _, _,
|
||||||
|
_, _, _, _, _,
|
||||||
|
_, _, _, _, _,
|
||||||
|
_, N, G, N, _,
|
||||||
|
_, N, N, N, _
|
||||||
|
},
|
||||||
|
-- Y-slice probabilities do not function correctly for ceiling schematic
|
||||||
|
-- decorations because they are inverted, so ypos numbers have been inverted
|
||||||
|
-- to match, and a larger offset in place_offset_y should be used (e.g. -3).
|
||||||
|
yslice_prob = {
|
||||||
|
{ypos = 9, prob = 192},
|
||||||
|
{ypos = 6, prob = 192},
|
||||||
|
{ypos = 5, prob = 192},
|
||||||
|
{ypos = 4, prob = 128},
|
||||||
|
{ypos = 1, prob = 96},
|
||||||
|
{ypos = 0, prob = 64}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
minetest.register_decoration({
|
||||||
|
name = "Glowstone stalactite",
|
||||||
|
deco_type = "schematic",
|
||||||
|
place_on = "nether:rack",
|
||||||
|
sidelen = 80,
|
||||||
|
fill_ratio = 0.0004,
|
||||||
|
biomes = {"nether_caverns"},
|
||||||
|
y_max = nether.DEPTH_CEILING, -- keep compatibility with mapgen_nobiomes.lua
|
||||||
|
y_min = nether.DEPTH_FLOOR,
|
||||||
|
schematic = schematic_GlowstoneStalactite,
|
||||||
|
flags = "place_center_x,place_center_z,force_placement,all_ceilings",
|
||||||
|
place_offset_y=-3
|
||||||
|
})
|
||||||
|
|
||||||
|
minetest.register_decoration({
|
||||||
|
name = "Netherrack stalactite",
|
||||||
|
deco_type = "schematic",
|
||||||
|
place_on = "nether:rack",
|
||||||
|
sidelen = 80,
|
||||||
|
fill_ratio = 0.0007,
|
||||||
|
biomes = {"nether_caverns"},
|
||||||
|
y_max = nether.DEPTH_CEILING, -- keep compatibility with mapgen_nobiomes.lua
|
||||||
|
y_min = nether.DEPTH_FLOOR,
|
||||||
|
schematic = schematic_GlowstoneStalactite,
|
||||||
|
replacements = {["nether:glowstone"] = "nether:rack"},
|
||||||
|
flags = "place_center_x,place_center_z,all_ceilings",
|
||||||
|
place_offset_y=-3
|
||||||
|
})
|
230
mapgen_nobiomes.lua
Normal file
230
mapgen_nobiomes.lua
Normal file
|
@ -0,0 +1,230 @@
|
||||||
|
--[[
|
||||||
|
|
||||||
|
Nether mod for minetest
|
||||||
|
|
||||||
|
Copyright (C) 2013 PilzAdam
|
||||||
|
|
||||||
|
Permission to use, copy, modify, and/or distribute this software for
|
||||||
|
any purpose with or without fee is hereby granted, provided that the
|
||||||
|
above copyright notice and this permission notice appear in all copies.
|
||||||
|
|
||||||
|
THE SOFTWARE IS PROVIDED "AS IS" AND THE AUTHOR DISCLAIMS ALL
|
||||||
|
WARRANTIES WITH REGARD TO THIS SOFTWARE INCLUDING ALL IMPLIED
|
||||||
|
WARRANTIES OF MERCHANTABILITY AND FITNESS. IN NO EVENT SHALL THE AUTHOR
|
||||||
|
BE LIABLE FOR ANY SPECIAL, DIRECT, INDIRECT, OR CONSEQUENTIAL DAMAGES
|
||||||
|
OR ANY DAMAGES WHATSOEVER RESULTING FROM LOSS OF USE, DATA OR PROFITS,
|
||||||
|
WHETHER IN AN ACTION OF CONTRACT, NEGLIGENCE OR OTHER TORTIOUS ACTION,
|
||||||
|
ARISING OUT OF OR IN CONNECTION WITH THE USE OR PERFORMANCE OF THIS
|
||||||
|
SOFTWARE.
|
||||||
|
|
||||||
|
]]--
|
||||||
|
|
||||||
|
|
||||||
|
-- Parameters
|
||||||
|
|
||||||
|
local NETHER_CEILING = nether.DEPTH_CEILING
|
||||||
|
local NETHER_FLOOR = nether.DEPTH_FLOOR
|
||||||
|
local TCAVE = 0.6
|
||||||
|
local BLEND = 128
|
||||||
|
|
||||||
|
|
||||||
|
-- 3D noise
|
||||||
|
|
||||||
|
local np_cave = {
|
||||||
|
offset = 0,
|
||||||
|
scale = 1,
|
||||||
|
spread = {x = 384, y = 128, z = 384}, -- squashed 3:1
|
||||||
|
seed = 59033,
|
||||||
|
octaves = 5,
|
||||||
|
persist = 0.7,
|
||||||
|
lacunarity = 2.0,
|
||||||
|
--flags = ""
|
||||||
|
}
|
||||||
|
|
||||||
|
|
||||||
|
-- Stuff
|
||||||
|
|
||||||
|
local yblmin = NETHER_FLOOR + BLEND * 2
|
||||||
|
local yblmax = NETHER_CEILING - BLEND * 2
|
||||||
|
|
||||||
|
|
||||||
|
|
||||||
|
-- Mapgen
|
||||||
|
|
||||||
|
dofile(nether.path .. "/mapgen_decorations.lua")
|
||||||
|
|
||||||
|
-- Initialize noise object, localise noise and data buffers
|
||||||
|
|
||||||
|
local nobj_cave = nil
|
||||||
|
local nbuf_cave = nil
|
||||||
|
local dbuf = nil
|
||||||
|
|
||||||
|
|
||||||
|
-- Content ids
|
||||||
|
|
||||||
|
local c_air = minetest.get_content_id("air")
|
||||||
|
|
||||||
|
--local c_stone_with_coal = minetest.get_content_id("default:stone_with_coal")
|
||||||
|
--local c_stone_with_iron = minetest.get_content_id("default:stone_with_iron")
|
||||||
|
local c_stone_with_mese = minetest.get_content_id("default:stone_with_mese")
|
||||||
|
local c_stone_with_diamond = minetest.get_content_id("default:stone_with_diamond")
|
||||||
|
local c_stone_with_gold = minetest.get_content_id("default:stone_with_gold")
|
||||||
|
--local c_stone_with_copper = minetest.get_content_id("default:stone_with_copper")
|
||||||
|
local c_mese = minetest.get_content_id("default:mese")
|
||||||
|
|
||||||
|
local c_gravel = minetest.get_content_id("default:gravel")
|
||||||
|
local c_dirt = minetest.get_content_id("default:dirt")
|
||||||
|
local c_sand = minetest.get_content_id("default:sand")
|
||||||
|
|
||||||
|
local c_cobble = minetest.get_content_id("default:cobble")
|
||||||
|
local c_mossycobble = minetest.get_content_id("default:mossycobble")
|
||||||
|
local c_stair_cobble = minetest.get_content_id("stairs:stair_cobble")
|
||||||
|
|
||||||
|
local c_lava_source = minetest.get_content_id("default:lava_source")
|
||||||
|
local c_lava_flowing = minetest.get_content_id("default:lava_flowing")
|
||||||
|
local c_water_source = minetest.get_content_id("default:water_source")
|
||||||
|
local c_water_flowing = minetest.get_content_id("default:water_flowing")
|
||||||
|
|
||||||
|
local c_glowstone = minetest.get_content_id("nether:glowstone")
|
||||||
|
local c_nethersand = minetest.get_content_id("nether:sand")
|
||||||
|
local c_netherbrick = minetest.get_content_id("nether:brick")
|
||||||
|
local c_netherrack = minetest.get_content_id("nether:rack")
|
||||||
|
|
||||||
|
|
||||||
|
-- On-generated function
|
||||||
|
|
||||||
|
minetest.register_on_generated(function(minp, maxp, seed)
|
||||||
|
if minp.y > NETHER_CEILING or maxp.y < NETHER_FLOOR then
|
||||||
|
return
|
||||||
|
end
|
||||||
|
|
||||||
|
local x1 = maxp.x
|
||||||
|
local y1 = math.min(maxp.y, NETHER_CEILING)
|
||||||
|
local z1 = maxp.z
|
||||||
|
local x0 = minp.x
|
||||||
|
local y0 = math.max(minp.y, NETHER_FLOOR)
|
||||||
|
local z0 = minp.z
|
||||||
|
|
||||||
|
local vm, emin, emax = minetest.get_mapgen_object("voxelmanip")
|
||||||
|
local area = VoxelArea:new{MinEdge = emin, MaxEdge = emax}
|
||||||
|
local data = vm:get_data(dbuf)
|
||||||
|
|
||||||
|
local x11 = emax.x -- Limits of mapchunk plus mapblock shell
|
||||||
|
local y11 = emax.y
|
||||||
|
local z11 = emax.z
|
||||||
|
local x00 = emin.x
|
||||||
|
local y00 = emin.y
|
||||||
|
local z00 = emin.z
|
||||||
|
|
||||||
|
local ystride = x1 - x0 + 1
|
||||||
|
local zstride = ystride * ystride
|
||||||
|
local chulens = {x = ystride, y = ystride, z = ystride}
|
||||||
|
local minposxyz = {x = x0, y = y0, z = z0}
|
||||||
|
|
||||||
|
nobj_cave = nobj_cave or minetest.get_perlin_map(np_cave, chulens)
|
||||||
|
local nvals_cave = nobj_cave:get3dMap_flat(minposxyz, nbuf_cave)
|
||||||
|
|
||||||
|
for y = y00, y11 do -- Y loop first to minimise tcave calculations
|
||||||
|
local tcave
|
||||||
|
local in_chunk_y = false
|
||||||
|
if y >= y0 and y <= y1 then
|
||||||
|
tcave = TCAVE
|
||||||
|
if y > yblmax then tcave = TCAVE + ((y - yblmax) / BLEND) ^ 2 end
|
||||||
|
if y < yblmin then tcave = TCAVE + ((yblmin - y) / BLEND) ^ 2 end
|
||||||
|
in_chunk_y = true
|
||||||
|
end
|
||||||
|
|
||||||
|
for z = z00, z11 do
|
||||||
|
local vi = area:index(x00, y, z) -- Initial voxelmanip index
|
||||||
|
local ni
|
||||||
|
local in_chunk_yz = in_chunk_y and z >= z0 and z <= z1
|
||||||
|
|
||||||
|
for x = x00, x11 do
|
||||||
|
if in_chunk_yz and x == x0 then
|
||||||
|
-- Initial noisemap index
|
||||||
|
ni = (z - z0) * zstride + (y - y0) * ystride + 1
|
||||||
|
end
|
||||||
|
local in_chunk_yzx = in_chunk_yz and x >= x0 and x <= x1 -- In mapchunk
|
||||||
|
|
||||||
|
local id = data[vi] -- Existing node
|
||||||
|
-- Cave air, cave liquids and dungeons are overgenerated,
|
||||||
|
-- convert these throughout mapchunk plus shell
|
||||||
|
if id == c_air or -- Air and liquids to air
|
||||||
|
id == c_lava_source or
|
||||||
|
id == c_lava_flowing or
|
||||||
|
id == c_water_source or
|
||||||
|
id == c_water_flowing then
|
||||||
|
data[vi] = c_air
|
||||||
|
-- Dungeons are preserved so we don't need
|
||||||
|
-- to check for cavern in the shell
|
||||||
|
elseif id == c_cobble or -- Dungeons (preserved) to netherbrick
|
||||||
|
id == c_mossycobble or
|
||||||
|
id == c_stair_cobble then
|
||||||
|
data[vi] = c_netherbrick
|
||||||
|
end
|
||||||
|
|
||||||
|
if in_chunk_yzx then -- In mapchunk
|
||||||
|
if nvals_cave[ni] > tcave then -- Only excavate cavern in mapchunk
|
||||||
|
data[vi] = c_air
|
||||||
|
elseif id == c_mese then -- Mese block to lava
|
||||||
|
data[vi] = c_lava_source
|
||||||
|
elseif id == c_stone_with_gold or -- Precious ores to glowstone
|
||||||
|
id == c_stone_with_mese or
|
||||||
|
id == c_stone_with_diamond then
|
||||||
|
data[vi] = c_glowstone
|
||||||
|
elseif id == c_gravel or -- Blob ore to nethersand
|
||||||
|
id == c_dirt or
|
||||||
|
id == c_sand then
|
||||||
|
data[vi] = c_nethersand
|
||||||
|
else -- All else to netherstone
|
||||||
|
data[vi] = c_netherrack
|
||||||
|
end
|
||||||
|
|
||||||
|
ni = ni + 1 -- Only increment noise index in mapchunk
|
||||||
|
end
|
||||||
|
|
||||||
|
vi = vi + 1
|
||||||
|
end
|
||||||
|
end
|
||||||
|
end
|
||||||
|
|
||||||
|
vm:set_data(data)
|
||||||
|
|
||||||
|
-- avoid generating decorations on the underside of the bottom of the nether
|
||||||
|
if minp.y > NETHER_FLOOR and maxp.y < NETHER_CEILING then minetest.generate_decorations(vm) end
|
||||||
|
|
||||||
|
vm:set_lighting({day = 0, night = 0}, minp, maxp)
|
||||||
|
vm:calc_lighting()
|
||||||
|
vm:update_liquids()
|
||||||
|
vm:write_to_map()
|
||||||
|
end)
|
||||||
|
|
||||||
|
|
||||||
|
-- use knowledge of the nether mapgen algorithm to return a suitable ground level for placing a portal.
|
||||||
|
function nether.find_nether_ground_y(target_x, target_z, start_y)
|
||||||
|
local nobj_cave_point = minetest.get_perlin(np_cave)
|
||||||
|
local air = 0 -- Consecutive air nodes found
|
||||||
|
|
||||||
|
for y = start_y, start_y - 4096, -1 do
|
||||||
|
local nval_cave = nobj_cave_point:get3d({x = target_x, y = y, z = target_z})
|
||||||
|
|
||||||
|
if nval_cave > TCAVE then -- Cavern
|
||||||
|
air = air + 1
|
||||||
|
else -- Not cavern, check if 4 nodes of space above
|
||||||
|
if air >= 4 then
|
||||||
|
-- Check volume for non-natural nodes
|
||||||
|
local minp = {x = target_x - 1, y = y , z = target_z - 2}
|
||||||
|
local maxp = {x = target_x + 2, y = y + 4, z = target_z + 2}
|
||||||
|
if nether.volume_is_natural(minp, maxp) then
|
||||||
|
return y + 1
|
||||||
|
else -- Restart search a little lower
|
||||||
|
nether.find_nether_ground_y(target_x, target_z, y - 16)
|
||||||
|
end
|
||||||
|
else -- Not enough space, reset air to zero
|
||||||
|
air = 0
|
||||||
|
end
|
||||||
|
end
|
||||||
|
end
|
||||||
|
|
||||||
|
return start_y -- Fallback
|
||||||
|
end
|
|
@ -17,3 +17,9 @@ nether_enable_portal_example_floatlands (Enable example portal: Floatlands) bool
|
||||||
|
|
||||||
# Enables the Surface-travel portal api code example
|
# Enables the Surface-travel portal api code example
|
||||||
nether_enable_portal_example_surfacetravel (Enable example portal: Surface-travel) bool false
|
nether_enable_portal_example_surfacetravel (Enable example portal: Surface-travel) bool false
|
||||||
|
|
||||||
|
[Nether depth]
|
||||||
|
#The depth where the Nether begins / the Nether ceiling
|
||||||
|
nether_depth_ymax (Upper limit of Nether) int -5000 -30000 32767
|
||||||
|
#The lower limit of the Nether must be at least 1000 lower than the upper limit, and more than 3000 lower is recommended.
|
||||||
|
nether_depth_ymin (Lower limit of Nether) int -11000 -32768 30000
|
Loading…
Reference in New Issue
Block a user