parent
87f0ea7a51
commit
b30272d2dd
@ -0,0 +1,238 @@ |
||||
--[[ |
||||
|
||||
Nether mod for minetest |
||||
|
||||
Helper functions for excavating and decorating dungeons, in a |
||||
separate file to keep the size of mapgen.lua manageable. |
||||
|
||||
|
||||
Copyright (C) 2021 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. |
||||
|
||||
]]-- |
||||
|
||||
|
||||
-- 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}) |
||||
|
||||
|
||||
-- Content ids |
||||
|
||||
local c_air = minetest.get_content_id("air") |
||||
local c_netherrack = minetest.get_content_id("nether:rack") |
||||
local c_netherrack_deep = minetest.get_content_id("nether:rack_deep") |
||||
local c_dungeonbrick = minetest.get_content_id("nether:brick") |
||||
local c_dungeonbrick_alt = minetest.get_content_id("nether:brick_cracked") |
||||
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") |
||||
|
||||
-- Misc math functions |
||||
|
||||
-- avoid needing table lookups each time a common math function is invoked |
||||
local math_max, math_min = math.max, math.min |
||||
|
||||
|
||||
-- Dungeon excavation functions |
||||
|
||||
function is_dungeon_brick(node_id) |
||||
return node_id == c_dungeonbrick or node_id == c_dungeonbrick_alt |
||||
end |
||||
|
||||
|
||||
nether.mapgen.build_dungeon_room_list = function(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) |
||||
nether.mapgen.excavate_dungeons = function(data, area, rooms) |
||||
|
||||
local vi, node_id |
||||
|
||||
-- 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 |
||||
vi = area:index(room_min.x, y, z) |
||||
for x = room_min.x, room_max.x do |
||||
node_id = data[vi] |
||||
if node_id == c_netherrack or node_id == c_netherrack_deep 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. |
||||
nether.mapgen.decorate_dungeons = function(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 (feel free to replace with a fancy schematic) |
||||
local vi = area:index(roomInfo.x, room_max.y + 1, roomInfo.z) |
||||
if is_dungeon_brick(data[vi]) 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 is_dungeon_brick(data[vi - yStride]) then |
||||
data[vi - yStride] = c_lava_source |
||||
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 |
||||
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 is_dungeon_brick(data[vi_min + offset]) then data[vi_min + offset] = window_node end |
||||
if is_dungeon_brick(data[vi_max + offset]) 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 is_dungeon_brick(data[vi_min + offset]) then data[vi_min + offset] = window_node end |
||||
if is_dungeon_brick(data[vi_max + offset]) then data[vi_max + offset] = window_node end |
||||
end |
||||
end |
||||
|
||||
-- Weeds on the floor once Nether weeds are added |
||||
end |
||||
end |
||||
end |
Loading…
Reference in new issue