many worldgen mods and gonna try technic now

This commit is contained in:
2026-09-13 03:30:48 -06:00
parent bac6ac94a3
commit 548749cb1a
4811 changed files with 163271 additions and 1 deletions
+22
View File
@@ -0,0 +1,22 @@
License for Code
----------------
Copyright (C) 2018 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.
+159
View File
@@ -0,0 +1,159 @@
if minetest.get_modpath("dungeon_loot") then
if df_caverns.config.enable_underworld then
dungeon_loot.register({
{name = "df_underworld_items:glow_amethyst", chance = 0.3, count = {1, 12}, y = {-32768, df_caverns.config.lava_sea_level}},
})
end
if df_caverns.config.enable_oil_sea and minetest.get_modpath("bucket") then
dungeon_loot.register({
{name = "oil:oil_bucket", chance = 0.5, count = {1, 3}, y = {-32768, df_caverns.config.ymax}},
})
end
if df_caverns.config.enable_lava_sea then
dungeon_loot.register({
{name = "df_mapitems:mese_crystal", chance = 0.25, count = {1, 5}, y = {-32768, df_caverns.config.sunless_sea_min}},
{name = "df_mapitems:glow_mese", chance = 0.1, count = {1, 3}, y = {-32768, df_caverns.config.sunless_sea_min}},
})
end
dungeon_loot.register({
{name = "df_farming:cave_wheat_seed", chance = 0.5, count = {1, 10}, y = {-32768, df_caverns.config.ymax}},
{name = "df_farming:cave_bread", chance = 0.8, count = {1, 10}, y = {-32768, df_caverns.config.ymax}},
{name = "df_farming:pig_tail_thread", chance = 0.7, count = {1, 10}, y = {-32768, df_caverns.config.ymax}},
{name = "df_farming:plump_helmet_spawn", chance = 0.4, count = {1, 8}, y = {-32768, df_caverns.config.ymax}},
{name = "df_farming:plump_helmet_4_picked", chance = 0.8, count = {1, 15}, y = {-32768, df_caverns.config.ymax}},
{name = "df_trees:glowing_bottle_red", chance = 0.6, count = {1, 20}, y = {-32768, df_caverns.config.ymax}},
{name = "df_trees:glowing_bottle_green", chance = 0.5, count = {1, 20}, y = {-32768, df_caverns.config.ymax}},
{name = "df_trees:glowing_bottle_cyan", chance = 0.4, count = {1, 15}, y = {-32768, df_caverns.config.ymax}},
{name = "df_trees:glowing_bottle_golden", chance = 0.3, count = {1, 5}, y = {-32768, df_caverns.config.ymax}},
{name = "df_farming:pig_tail_seed", chance = 0.5, count = {1, 10}, y = {-32768, df_caverns.config.level1_min}},
{name = "df_mapitems:med_crystal", chance = 0.2, count = {1, 2}, y = {-32768, df_caverns.config.level1_min}},
{name = "df_farming:dimple_cup_seed", chance = 0.3, count = {1, 10}, y = {-32768, df_caverns.config.level2_min}},
{name = "df_farming:quarry_bush_seed", chance = 0.3, count = {1, 5}, y = {-32768, df_caverns.config.level2_min}},
{name = "df_farming:sweet_pod_seed", chance = 0.3, count = {1, 5}, y = {-32768, df_caverns.config.level2_min}},
{name = "df_mapitems:big_crystal", chance = 0.1, count = {1, 1}, y = {-32768, df_caverns.config.level2_min}},
{name = "df_trees:torchspine_ember", chance = 0.3, count = {1, 3}, y = {-32768, df_caverns.config.level2_min}},
{name = "ice_sprites:ice_sprite_bottle", chance = 0.1, count = {1, 1}, y = {-32768, df_caverns.config.level2_min}},
})
end
if minetest.get_modpath("bones_loot") and df_caverns.config.enable_underworld then
if minetest.get_modpath("default") then
bones_loot.register_loot({
{name = "binoculars:binoculars", chance = 0.05, count = {1,1}, types = {"underworld_warrior"}},
{name = "boats:boat", chance = 0.05, count = {1,1}, types = {"underworld_warrior"}},
{name = "bucket:bucket_empty", chance = 0.3, count = {1,1}, types = {"underworld_warrior"}},
{name = "fire:flint_and_steel", chance = 0.3, count = {1,1}, types = {"underworld_warrior"}},
{name = "flowers:tulip_black", chance = 0.1, count = {1,1}, types = {"underworld_warrior"}},
{name = "flowers:dandelion_white", chance = 0.1, count = {1,1}, types = {"underworld_warrior"}},
{name = "flowers:dandelion_yellow", chance = 0.1, count = {1,1}, types = {"underworld_warrior"}},
{name = "flowers:rose", chance = 0.1, count = {1,1}, types = {"underworld_warrior"}},
{name = "flowers:tulip", chance = 0.1, count = {1,1}, types = {"underworld_warrior"}},
{name = "flowers:chrysanthemum_green", chance = 0.1, count = {1,1}, types = {"underworld_warrior"}},
{name = "flowers:geranium", chance = 0.1, count = {1,1}, types = {"underworld_warrior"}},
{name = "map:mapping_kit", chance = 0.1, count = {1,1}, types = {"underworld_warrior"}},
{name = "screwdriver:screwdriver", chance = 0.05, count = {1,1}, types = {"underworld_warrior"}},
-- don't give the player tnt:tnt, they can craft that from this if tnt is enabled for them
{name = "tnt:gunpowder", chance = 0.4, count = {1,10}, types = {"underworld_warrior"}},
{name = "tnt:tnt_stick", chance = 0.3, count = {1,6}, types = {"underworld_warrior"}},
{name = "vessels:steel_bottle", chance = 0.4, count = {1,3}, types = {"underworld_warrior"}},
{name = "vessels:glass_bottle", chance = 0.2, count = {1,2}, types = {"underworld_warrior"}},
{name = "vessels:glass_fragments", chance = 0.1, count = {1,4}, types = {"underworld_warrior"}},
{name = "default:book", chance = 0.05, count = {1,1}, types = {"underworld_warrior"}},
{name = "default:paper", chance = 0.1, count = {1,6}, types = {"underworld_warrior"}},
{name = "default:skeleton_key", chance = 0.05, count = {1,1}, types = {"underworld_warrior"}},
{name = "default:torch", chance = 0.75, count = {1,10}, types = {"underworld_warrior"}},
{name = "default:pick_bronze", chance = 0.15, count = {1,1}, types = {"underworld_warrior"}},
{name = "default:pick_steel", chance = 0.1, count = {1,1}, types = {"underworld_warrior"}},
{name = "default:pick_mese", chance = 0.05, count = {1,1}, types = {"underworld_warrior"}},
{name = "default:pick_diamond", chance = 0.05, count = {1,1}, types = {"underworld_warrior"}},
{name = "default:shovel_bronze", chance = 0.1, count = {1,1}, types = {"underworld_warrior"}},
{name = "default:shovel_steel", chance = 0.05, count = {1,1}, types = {"underworld_warrior"}},
{name = "default:shovel_mese", chance = 0.025, count = {1,1}, types = {"underworld_warrior"}},
{name = "default:shovel_diamond", chance = 0.025, count = {1,1}, types = {"underworld_warrior"}},
{name = "default:axe_bronze", chance = 0.3, count = {1,1}, types = {"underworld_warrior"}},
{name = "default:axe_steel", chance = 0.5, count = {1,1}, types = {"underworld_warrior"}},
{name = "default:axe_mese", chance = 0.15, count = {1,1}, types = {"underworld_warrior"}},
{name = "default:axe_diamond", chance = 0.15, count = {1,1}, types = {"underworld_warrior"}},
{name = "default:sword_bronze", chance = 0.5, count = {1,1}, types = {"underworld_warrior"}},
{name = "default:sword_steel", chance = 0.75, count = {1,1}, types = {"underworld_warrior"}},
{name = "default:sword_mese", chance = 0.35, count = {1,1}, types = {"underworld_warrior"}},
{name = "default:sword_diamond", chance = 0.35, count = {1,1}, types = {"underworld_warrior"}},
{name = "default:coal_lump", chance = 0.5, count = {1,5}, types = {"underworld_warrior"}},
{name = "default:mese_crystal", chance = 0.1, count = {1,1}, types = {"underworld_warrior"}},
{name = "default:diamond", chance = 0.1, count = {1,1}, types = {"underworld_warrior"}},
{name = "default:steel_ingot", chance = 0.2, count = {1,3}, types = {"underworld_warrior"}},
{name = "default:copper_ingot", chance = 0.1, count = {1,2}, types = {"underworld_warrior"}},
{name = "default:bronze_ingot", chance = 0.2, count = {1,5}, types = {"underworld_warrior"}},
{name = "default:gold_ingot", chance = 0.3, count = {1,3}, types = {"underworld_warrior"}},
{name = "default:mese_crystal_fragment", chance = 0.4, count = {1,5}, types = {"underworld_warrior"}},
{name = "default:obsidian_shard", chance = 0.4, count = {1,3}, types = {"underworld_warrior"}},
{name = "default:flint", chance = 0.3, count = {1,1}, types = {"underworld_warrior"}},
{name = "default:sign_wall_wood", chance = 0.1, count = {1,4}, types = {"underworld_warrior"}},
{name = "default:sign_wall_steel", chance = 0.1, count = {1,2}, types = {"underworld_warrior"}},
{name = "default:ladder_wood", chance = 0.5, count = {1,10}, types = {"underworld_warrior"}},
{name = "default:ladder_steel", chance = 0.2, count = {1,5}, types = {"underworld_warrior"}},
{name = "default:meselamp", chance = 0.1, count = {1,2}, types = {"underworld_warrior"}},
{name = "default:mese_post_light", chance = 0.25, count = {1,5}, types = {"underworld_warrior"}},
})
end
if minetest.get_modpath("mcl_core") then
bones_loot.register_loot({
-- Taken from the ruined portal loot table in mcl
{name = "mcl_core:iron_nugget", types = {"underworld_warrior"}, chance = 40/50, count ={9, 18}},
{name = "mcl_core:flint", types = {"underworld_warrior"}, chance = 40/50, count ={9, 18}},
{name = "mcl_core:obsidian", types = {"underworld_warrior"}, chance = 40/50, count ={1, 2}},
{name = "mcl_fire:fire_charge", types = {"underworld_warrior"}, chance = 40/50, count ={1, 1}},
{name = "mcl_fire:flint_and_steel", types = {"underworld_warrior"}, chance = 40/50, count ={1, 1}},
{name = "mcl_core:gold_nugget", types = {"underworld_warrior"}, chance = 15/50, count ={4, 24}},
{name = "mcl_core:apple_gold", types = {"underworld_warrior"}, chance = 15/50, count ={1, 1}},
{name = "mcl_tools:axe_gold", types = {"underworld_warrior"}, chance = 15/50, count ={1, 1}},
{name = "mcl_farming:hoe_gold", types = {"underworld_warrior"}, chance = 15/50, count ={1, 1}},
{name = "mcl_tools:pick_gold", types = {"underworld_warrior"}, chance = 15/50, count ={1, 1}},
{name = "mcl_tools:shovel_gold", types = {"underworld_warrior"}, chance = 15/50, count ={1, 1}},
{name = "mcl_tools:sword_gold", types = {"underworld_warrior"}, chance = 15/50, count ={1, 1}},
{name = "mcl_armor:helmet_gold", types = {"underworld_warrior"}, chance = 15/50, count ={1, 1}},
{name = "mcl_armor:chestplate_gold", types = {"underworld_warrior"}, chance = 15/50, count ={1, 1}},
{name = "mcl_armor:leggings_gold", types = {"underworld_warrior"}, chance = 15/50, count ={1, 1}},
{name = "mcl_armor:boots_gold", types = {"underworld_warrior"}, chance = 15/50, count ={1, 1}},
{name = "mcl_potions:speckled_melon", types = {"underworld_warrior"}, chance = 5/50, count ={4, 12}},
{name = "mcl_farming:carrot_item_gold", types = {"underworld_warrior"}, chance = 5/50, count ={4, 12}},
{name = "mcl_core:gold_ingot", types = {"underworld_warrior"}, chance = 5/50, count ={2, 8}},
{name = "mcl_clock:clock", types = {"underworld_warrior"}, chance = 5/50, count ={1,1}},
{name = "mesecons_pressureplates:pressure_plate_gold_off", types = {"underworld_warrior"}, chance = 5/50, count ={1,1}},
{name = "mobs_mc:gold_horse_armor", types = {"underworld_warrior"}, chance = 5/50, count ={1,1}},
{name = "mcl_bells:bell", types = {"underworld_warrior"}, chance = 1/50, count ={1,1}},
{name = "mcl_core:apple_gold_enchanted", types = {"underworld_warrior"}, chance = 1/50, count ={1,1}},
})
for flower_name, _ in pairs(mcl_flowers.registered_simple_flowers) do
bones_loot.register_loot({
{name = flower_name, chance = 0.1, count = {1,1}, types = {"underworld_warrior"}},
})
end
end
bones_loot.register_loot({
{name = "ice_sprites:ice_sprite_bottle", chance = 0.025, count = {1, 1}, types = {"underworld_warrior"}},
{name = "df_underworld_items:glow_amethyst", chance = 0.25, count = {1, 2}, types = {"underworld_warrior"}},
})
if df_caverns.config.enable_lava_sea then
bones_loot.register_loot({name = "df_mapitems:mese_crystal", chance = 0.25, count = {1, 2}, types = {"underworld_warrior"}})
end
end
@@ -0,0 +1,48 @@
local add_biome_restrictions = function(root_table, function_name, biome_set)
local old_function = root_table[function_name]
root_table[function_name] = function(pos)
local biome = df_caverns.get_biome(pos)
return old_function(pos) and biome_set[biome]
end
end
if df_caverns.config.restrict_trees_to_biomes then
if minetest.get_modpath("df_trees") then
add_biome_restrictions(df_trees, "black_cap_growth_permitted", {blackcap = true})
add_biome_restrictions(df_trees, "blood_thorn_growth_permitted", {bloodthorn = true})
add_biome_restrictions(df_trees, "fungiwood_growth_permitted", {fungiwood = true, fungispore = true})
add_biome_restrictions(df_trees, "goblin_cap_growth_permitted", {goblincap = true, towergoblin = true})
add_biome_restrictions(df_trees, "nether_cap_growth_permitted", {nethercap = true})
add_biome_restrictions(df_trees, "spore_tree_growth_permitted", {sporetree = true, fungispore = true})
add_biome_restrictions(df_trees, "tower_cap_growth_permitted", {towercap = true, towergoblin = true})
add_biome_restrictions(df_trees, "tunnel_tube_growth_permitted", {tunneltube = true})
-- Deliberately not biome-restricted
--add_biome_restrictions(df_trees, "torchspine_growth_permitted", {})
--add_biome_restrictions(df_trees, "spindlestem_growth_permitted", {})
end
if minetest.get_modpath("df_primordial_items") then
add_biome_restrictions(df_primordial_items, "primordial_mushroom_growth_permitted", {["primordial fungus"] = true})
add_biome_restrictions(df_primordial_items, "giant_mycelium_growth_permitted", {["primordial fungus"] = true})
add_biome_restrictions(df_primordial_items, "giant_fern_growth_permitted", {["primordial jungle"] = true})
add_biome_restrictions(df_primordial_items, "jungle_mushroom_growth_permitted", {["primordial jungle"] = true})
add_biome_restrictions(df_primordial_items, "jungletree_growth_permitted", {["primordial jungle"] = true})
end
end
if df_caverns.config.restrict_farmables_to_biomes and minetest.get_modpath("df_farming") then
add_biome_restrictions(df_farming.growth_permitted, "df_farming:cave_wheat_seed",
{fungiwood = true, tunneltube = true, sporetree = true, fungispore = true})
add_biome_restrictions(df_farming.growth_permitted, "df_farming:dimple_cup_seed",
{towergoblin = true})
add_biome_restrictions(df_farming.growth_permitted, "df_farming:pig_tail_seed",
{sporetree = true, fungispore = true})
add_biome_restrictions(df_farming.growth_permitted, "df_farming:quarry_bush_seed",
{bloodthorn = true})
add_biome_restrictions(df_farming.growth_permitted, "df_farming:sweet_pod_seed",
{tunneltube = true, fungispore = true})
add_biome_restrictions(df_farming.growth_permitted, "df_farming:plump_helmet_spawn",
{fungiwood = true, towercap = true, goblincap = true, towergoblin = true})
end
+21
View File
@@ -0,0 +1,21 @@
df_caverns = {}
df_caverns.config = df_dependencies.config
--grab a shorthand for the filepath of the mod
local modpath = minetest.get_modpath(minetest.get_current_modname())
--load companion lua files
dofile(modpath.."/node_ids.lua")
dofile(modpath.."/shared.lua")
dofile(modpath.."/surface_tunnels.lua")
dofile(modpath.."/level1.lua")
dofile(modpath.."/level2.lua")
dofile(modpath.."/level3.lua")
dofile(modpath.."/sunless_sea.lua")
dofile(modpath.."/oil_sea.lua")
dofile(modpath.."/lava_sea.lua")
dofile(modpath.."/underworld.lua")
dofile(modpath.."/primordial.lua")
dofile(modpath.."/dungeon_loot.lua")
dofile(modpath.."/growth_restrictions.lua")
+157
View File
@@ -0,0 +1,157 @@
if not df_caverns.config.enable_lava_sea then
return
end
local c_air = df_caverns.node_id.air
local c_lava = df_caverns.node_id.lava
local c_meseore = df_caverns.node_id.meseore
local c_mese_crystal = df_caverns.node_id.mese_crystal
local c_mese_crystal_block = df_caverns.node_id.mese_crystal_block
local c_obsidian = df_caverns.node_id.obsidian
local log_location
if mapgen_helper.log_location_enabled then
log_location = mapgen_helper.log_first_location
end
-------------------------------------------------------------------------------------------
local perlin_cave = {
offset = 0,
scale = 1,
spread = {x=100, y=100, z=100},
seed = -787324,
octaves = 3,
persist = 0.67
}
-- large-scale rise and fall
local perlin_wave = {
offset = 0,
scale = 1,
spread = {x=1000, y=1000, z=1000},
seed = 256664,
octaves = 3,
persist = 0.67
}
local perlin_mese = {
offset = 0,
scale = 1,
spread = {x=500, y=500, z=500},
seed = -50001,
octaves = 3,
persist = 0.67
}
local median = df_caverns.config.lava_sea_level
local floor_mult = 60
local floor_displace = -25
local ceiling_mult = -40
local ceiling_displace = 15
local wave_mult = 10
local y_max = median + 2*wave_mult + -2*ceiling_mult + ceiling_displace
local y_min = median - 2*wave_mult - 2*floor_mult + floor_displace
df_caverns.register_biome_check(function(pos, heat, humidity)
if pos.y > y_max or pos.y < y_min then
return
end
return "lava_sea"
end)
minetest.register_on_generated(function(minp, maxp, seed)
--if out of range of cave definition limits, abort
if minp.y > y_max or maxp.y < y_min then
return
end
local t_start = os.clock()
math.randomseed(minp.x + minp.y*2^8 + minp.z*2^16 + seed) -- make decorations consistent between runs
local vm, data, data_param2, area = mapgen_helper.mapgen_vm_data_param2()
local nvals_cave = mapgen_helper.perlin2d("df_caverns:lava_cave", minp, maxp, perlin_cave)
local nvals_wave = mapgen_helper.perlin2d("df_caverns:lava_wave", minp, maxp, perlin_wave)
local nvals_mese = mapgen_helper.perlin2d("df_caverns:lava_mese", minp, maxp, perlin_mese)
local nvals_lavasurface = mapgen_helper.perlin2d("df_cavern:cracks", minp, maxp, df_caverns.np_cracks)
for vi, x, y, z in area:iterp_yxz(minp, maxp) do
local index2d = mapgen_helper.index2d(minp, maxp, x, z)
local abs_cave = math.abs(nvals_cave[index2d]) -- range is from 0 to approximately 2, with 0 being connected and 2s being islands
local wave = nvals_wave[index2d] * wave_mult
local lava = nvals_lavasurface[index2d]
local floor_height = math.floor(abs_cave * floor_mult + floor_displace + median + wave)
local ceiling_height = math.floor(abs_cave * ceiling_mult + median + ceiling_displace + wave)
local lava_height = math.floor(median + lava * 2)
if y >= floor_height - 2 and y >= ceiling_height and y < ceiling_height + 2 and y <= lava_height + 2 and not mapgen_helper.buildable_to(data[vi]) then
data[vi] = c_obsidian -- obsidian ceiling
elseif y > floor_height and y < ceiling_height then
if y > lava_height then
data[vi] = c_air
else
data[vi] = c_lava
if log_location then log_location("magma_sea", area:position(vi)) end
end
elseif y > floor_height - 5 and y < ceiling_height and y <= lava_height + 2 and not mapgen_helper.buildable_to(data[vi]) then
data[vi] = c_obsidian -- thick obsidian floor
elseif y < lava_height and data[vi] == c_air then
data[vi] = c_lava
end
end
-- decoration loop.
for x = minp.x + 1, maxp.x-1 do
for z = minp.z + 1, maxp.z -1 do
local index2d = mapgen_helper.index2d(minp, maxp, x, z)
local mese_intensity = math.abs(nvals_mese[index2d])
local abs_cave = math.abs(nvals_cave[index2d]) -- range is from 0 to approximately 2, with 0 being connected and 2s being islands
local wave = nvals_wave[index2d] * wave_mult
local floor_height = math.floor(abs_cave * floor_mult + floor_displace + median + wave)
local ceiling_height = math.floor(abs_cave * ceiling_mult + median + ceiling_displace + wave)
local lava = nvals_lavasurface[index2d]
local lava_height = math.floor(median + lava * 2)
if mese_intensity > 0.65 and ceiling_height > lava_height + 1 and ceiling_height > floor_height + 1 and ceiling_height <= maxp.y and ceiling_height >= minp.y then
local vi = area:index(x, ceiling_height, z)
if not mapgen_helper.buildable_to(data[vi]) then
-- decorate ceiling
if math.random() < 0.25 then
data[vi] = c_meseore
if log_location then log_location("magma_sea_meseore", area:position(vi)) end
elseif mese_intensity > 0.75 and math.random() < 0.1 then
data[vi] = c_meseore
local bi = vi-area.ystride
data[bi] = c_mese_crystal
data_param2[bi] = math.random(1,4) + 19
if log_location then log_location("magma_sea_mesecrystal", area:position(vi)) end
elseif mese_intensity > 0.85 and math.random() < 0.025 then
subterrane.big_stalactite(vi-area.ystride, area, data, 6, 13, c_meseore, c_meseore, c_mese_crystal_block)
if log_location then log_location("magma_sea_mesebig", area:position(vi)) end
end
end
end
end
end
--send data back to voxelmanip
vm:set_data(data)
vm:set_param2_data(data_param2)
--calc lighting
vm:set_lighting({day = 0, night = 0})
vm:calc_lighting()
vm:update_liquids()
--write it to world
vm:write_to_map()
local time_taken = os.clock() - t_start -- how long this chunk took, in seconds
mapgen_helper.record_time("df_caverns lava sea", time_taken)
end)
+341
View File
@@ -0,0 +1,341 @@
local c_water = df_caverns.node_id.water
local c_air = df_caverns.node_id.air
local c_dirt = df_caverns.node_id.dirt
local c_dirt_moss = df_caverns.node_id.dirt_moss
local c_gravel = df_caverns.node_id.gravel
local c_wet_flowstone = df_caverns.node_id.wet_flowstone
local c_dry_flowstone = df_caverns.node_id.dry_flowstone
local c_spindlestem_white = df_caverns.node_id.spindlestem_white
local tower_cap_shrublist
local fungiwood_shrublist
local chasms_path = minetest.get_modpath("chasms")
if minetest.get_modpath("df_farming") then
tower_cap_shrublist = {
df_farming.spawn_plump_helmet_vm,
df_farming.spawn_plump_helmet_vm,
df_farming.spawn_dead_fungus_vm,
df_farming.spawn_cavern_fungi_vm,
}
fungiwood_shrublist = {
df_farming.spawn_plump_helmet_vm,
df_farming.spawn_cave_wheat_vm,
df_farming.spawn_cave_wheat_vm,
df_farming.spawn_dead_fungus_vm,
df_farming.spawn_cavern_fungi_vm,
}
end
local log_location
if mapgen_helper.log_location_enabled then
log_location = mapgen_helper.log_first_location
end
local subsea_level = df_caverns.config.level1_min - (df_caverns.config.level1_min - df_caverns.config.ymax) * 0.33
local flooding_threshold = math.min(df_caverns.config.tunnel_flooding_threshold, df_caverns.config.cavern_threshold)
local get_biome = function(heat, humidity)
if humidity < 23 then -- about 20% of locations fall below this threshold
return "barren"
elseif heat < 50 then
return "towercap"
else
return "fungiwood"
end
end
df_caverns.register_biome_check(function(pos, heat, humidity)
if pos.y < df_caverns.config.level1_min or pos.y > df_caverns.config.ymax then
return nil
end
return get_biome(heat, humidity)
end)
local tower_cap_cavern_floor = function(abs_cracks, vert_rand, vi, area, data, data_param2)
local ystride = area.ystride
if abs_cracks < 0.1 then
df_caverns.stalagmites(abs_cracks, vert_rand, vi, area, data, data_param2, true)
elseif data[vi-ystride] ~= c_air and data[vi-ystride] ~= c_water then -- leave the ground as rock if it's only one node thick
if math.random() < 0.25 then
data[vi] = c_dirt
else
data[vi] = c_dirt_moss
end
if math.random() < 0.1 then
df_caverns.place_shrub(vi+ystride, area, data, data_param2, tower_cap_shrublist)
elseif abs_cracks > 0.25 then
if math.random() < 0.01 then
df_trees.spawn_tower_cap_vm(vi+ystride, area, data)
elseif math.random() < 0.04 then
df_trees.spawn_spindlestem_vm(vi+ystride, area, data, data_param2, c_spindlestem_white)
end
end
end
end
local fungiwood_cavern_floor = function(abs_cracks, vert_rand, vi, area, data, data_param2)
local ystride = area.ystride
if abs_cracks < 0.1 then
df_caverns.stalagmites(abs_cracks, vert_rand, vi, area, data, data_param2, true)
elseif data[vi-ystride] ~= c_air and data[vi-ystride] ~= c_water then -- leave the ground as rock if it's only one node thick
if math.random() < 0.25 then
data[vi] = c_dirt
else
data[vi] = c_dirt_moss
end
if math.random() < 0.1 then
df_caverns.place_shrub(vi+ystride, area, data, data_param2, fungiwood_shrublist)
elseif math.random() < 0.03 and abs_cracks > 0.35 then
df_trees.spawn_fungiwood_vm(vi+ystride, area, data)
elseif math.random() < 0.04 then
df_trees.spawn_spindlestem_vm(vi+ystride, area, data, data_param2)
end
end
end
local decorate_level_1 = function(minp, maxp, seed, vm, node_arrays, area, data)
math.randomseed(minp.x + minp.y*2^8 + minp.z*2^16 + seed) -- make decorations consistent between runs
local heatmap = minetest.get_mapgen_object("heatmap")
local humiditymap = minetest.get_mapgen_object("humiditymap")
local data_param2 = df_caverns.data_param2
vm:get_param2_data(data_param2)
local nvals_cracks = mapgen_helper.perlin2d("df_cavern:cracks", minp, maxp, df_caverns.np_cracks)
local nvals_cave = node_arrays.nvals_cave
local cave_area = node_arrays.cave_area
-- Partly fill flooded caverns and warrens
if minp.y <= subsea_level then
for vi, x, y, z in area:iterp_yxz(area.MinEdge, area.MaxEdge) do
-- convert all air below sea level into water
if y <= subsea_level and data[vi] == c_air and nvals_cave[vi] < -flooding_threshold then
data[vi] = c_water
end
end
end
---------------------------------------------------------
-- Cavern floors
for _, vi in ipairs(node_arrays.cavern_floor_nodes) do
local vert_rand = mapgen_helper.xz_consistent_randomi(area, vi)
local index2d = mapgen_helper.index2di(minp, maxp, area, vi)
local biome_name = get_biome(heatmap[index2d], humiditymap[index2d])
local abs_cracks = math.abs(nvals_cracks[index2d])
local flooded_caverns = nvals_cave[vi] < 0 -- this indicates if we're in the "flooded" set of caves or not.
if minp.y < subsea_level and area:get_y(vi) < subsea_level and flooded_caverns then
-- underwater floor
df_caverns.flooded_cavern_floor(abs_cracks, vert_rand, vi, area, data)
if log_location then log_location("level1_flooded_"..biome_name, area:position(vi)) end
elseif biome_name == "towercap" then
tower_cap_cavern_floor(abs_cracks, vert_rand, vi, area, data, data_param2)
if log_location then log_location("level1_towercap", area:position(vi)) end
elseif biome_name == "fungiwood" then
fungiwood_cavern_floor(abs_cracks, vert_rand, vi, area, data, data_param2)
if log_location then log_location("level1_fungiwood", area:position(vi)) end
elseif biome_name == "barren" then
if flooded_caverns then
df_caverns.wet_cavern_floor(abs_cracks, vert_rand, vi, area, data, data_param2)
if log_location then log_location("level1_barren_wet", area:position(vi)) end
else
df_caverns.dry_cavern_floor(abs_cracks, vert_rand, vi, area, data, data_param2)
if log_location then log_location("level1_barren_dry", area:position(vi)) end
end
end
end
--------------------------------------
-- Cavern ceilings
for _, vi in ipairs(node_arrays.cavern_ceiling_nodes) do
local vert_rand = mapgen_helper.xz_consistent_randomi(area, vi)
local index2d = mapgen_helper.index2di(minp, maxp, area, vi)
local biome_name = get_biome(heatmap[index2d], humiditymap[index2d])
local abs_cracks = math.abs(nvals_cracks[index2d])
local flooded_caverns = nvals_cave[vi] < 0 -- this indicates if we're in the "flooded" set of caves or not.
if flooded_caverns and minp.y < subsea_level and area:get_y(vi) < subsea_level then
-- underwater ceiling, do nothing
elseif biome_name == "barren" then
if flooded_caverns then
-- wet barren
if abs_cracks < 0.1 then
df_caverns.stalactites(abs_cracks, vert_rand, vi, area, data, data_param2, true)
end
else
-- dry barren
if abs_cracks < 0.075 then
df_caverns.stalactites(abs_cracks, vert_rand, vi, area, data, data_param2, false)
end
end
else -- all the other biomes
df_caverns.glow_worm_cavern_ceiling(abs_cracks, vert_rand, vi, area, data, data_param2)
end
end
----------------------------------------------
-- Tunnel floors
for _, vi in ipairs(node_arrays.tunnel_floor_nodes) do
local index2d = mapgen_helper.index2di(minp, maxp, area, vi)
local biome_name = get_biome(heatmap[index2d], humiditymap[index2d])
local flooded_caverns = nvals_cave[vi] < 0 -- this indicates if we're in the "flooded" set of caves or not.
if not (flooded_caverns and minp.y < subsea_level and area:get_y(vi) < subsea_level) then
if flooded_caverns or biome_name ~= "barren" then
-- we're in flooded areas or are not barren
df_caverns.tunnel_floor(minp, maxp, area, vi, nvals_cracks, data, data_param2, true)
else
df_caverns.tunnel_floor(minp, maxp, area, vi, nvals_cracks, data, data_param2, false, c_gravel)
end
end
end
------------------------------------------------------
-- Tunnel ceiling
for _, vi in ipairs(node_arrays.tunnel_ceiling_nodes) do
local index2d = mapgen_helper.index2di(minp, maxp, area, vi)
local biome_name = get_biome(heatmap[index2d], humiditymap[index2d])
local flooded_caverns = nvals_cave[vi] < 0 -- this indicates if we're in the "flooded" set of caves or not.
if not (flooded_caverns and minp.y < subsea_level and area:get_y(vi) < subsea_level) then
if flooded_caverns or biome_name ~= "barren" then
-- we're in flooded areas or are not barren
df_caverns.tunnel_ceiling(minp, maxp, area, vi, nvals_cracks, data, data_param2, true)
else
df_caverns.tunnel_ceiling(minp, maxp, area, vi, nvals_cracks, data, data_param2, false)
end
else
-- air pockets
local ystride = area.ystride
local cracks = nvals_cracks[index2d]
if cracks > 0.5 and data[vi-ystride] == c_water then
data[vi-ystride] = c_air
if cracks > 0.7 and data[vi-ystride*2] == c_water then
data[vi-ystride*2] = c_air
end
end
end
end
----------------------------------------------
-- Warren floors
for _, vi in ipairs(node_arrays.warren_floor_nodes) do
local index2d = mapgen_helper.index2di(minp, maxp, area, vi)
local biome_name = get_biome(heatmap[index2d], humiditymap[index2d])
local flooded_caverns = nvals_cave[vi] < 0 -- this indicates if we're in the "flooded" set of caves or not.
local ystride = area.ystride
if log_location then
local flood_name = ""
if flooded_caverns then flood_name = "_flooded" end
log_location("level1_warren_"..biome_name..flood_name, area:position(vi))
end
if not (flooded_caverns and minp.y < subsea_level and area:get_y(vi) < subsea_level) then
if flooded_caverns or biome_name ~= "barren" then
-- we're in flooded areas or are not barren
df_caverns.tunnel_floor(minp, maxp, area, vi, nvals_cracks, data, data_param2, true)
else
df_caverns.tunnel_floor(minp, maxp, area, vi, nvals_cracks, data, data_param2, false, c_gravel)
end
if biome_name ~= "barren" then
local cracks = nvals_cracks[index2d]
if cracks > 0.25 then
local rand = math.random()
if rand > cracks then
if math.random() < 0.25 then
data[vi] = c_dirt_moss
else
data[vi] = c_dirt
end
if data[vi+ystride] == c_air and math.random() < 0.25 then
df_caverns.place_shrub(vi+ystride, area, data, data_param2, tower_cap_shrublist)
end
end
if rand > cracks*2 then
df_trees.spawn_spindlestem_vm(vi+ystride, area, data, data_param2)
end
end
end
end
end
------------------------------------------------------
-- Warren ceiling
for _, vi in ipairs(node_arrays.warren_ceiling_nodes) do
local index2d = mapgen_helper.index2di(minp, maxp, area, vi)
local biome_name = get_biome(heatmap[index2d], humiditymap[index2d])
local flooded_caverns = nvals_cave[vi] < 0 -- this indicates if we're in the "flooded" set of caves or not.
if not (flooded_caverns and minp.y < subsea_level and area:get_y(vi) < subsea_level) then
if flooded_caverns or biome_name ~= "barren" then
-- we're in flooded areas or are not barren
df_caverns.tunnel_ceiling(minp, maxp, area, vi, nvals_cracks, data, data_param2, true)
else
df_caverns.tunnel_ceiling(minp, maxp, area, vi, nvals_cracks, data, data_param2, false)
end
end
-- else air pockets?
end
----------------------------------------------
-- Column material override for dry biome
for _, vi in ipairs(node_arrays.column_nodes) do
local index2d = mapgen_helper.index2di(minp, maxp, area, vi)
local biome_name = get_biome(heatmap[index2d], humiditymap[index2d])
local dry = (biome_name == "barren") and (nvals_cave[vi] > 0)
if dry and data[vi] == c_wet_flowstone then
data[vi] = c_dry_flowstone
end
if chasms_path then
local pos = area:position(vi)
if chasms.is_in_chasm_without_taper(pos) then
local flooded_caverns = nvals_cave[vi] < 0 -- this indicates if we're in the "flooded" set of caves or not.
if flooded_caverns and pos.y < subsea_level then
data[vi] = c_water
else
data[vi] = c_air
end
end
end
end
vm:set_param2_data(data_param2)
end
-------------------------------------------------------------------------------------------
subterrane.register_layer({
name = "cavern layer 1",
y_max = df_caverns.config.ymax,
y_min = df_caverns.config.level1_min,
cave_threshold = df_caverns.config.cavern_threshold,
boundary_blend_range = 64, -- range near ymin and ymax over which caves diminish to nothing
perlin_cave = df_caverns.perlin_cave,
perlin_wave = df_caverns.perlin_wave,
solidify_lava = true,
columns = {
maximum_radius = 10,
minimum_radius = 4,
node = "df_mapitems:wet_flowstone",
weight = 0.25,
maximum_count = 50,
minimum_count = 0,
},
decorate = decorate_level_1,
warren_region_variability_threshold = 0.33,
double_frequency = true,
is_ground_content = df_caverns.is_ground_content,
})
+424
View File
@@ -0,0 +1,424 @@
local c_water = df_caverns.node_id.water
local c_air = df_caverns.node_id.air
local c_dirt = df_caverns.node_id.dirt
local c_dirt_moss = df_caverns.node_id.dirt_moss
local c_gravel = df_caverns.node_id.gravel
local c_stillworm = df_caverns.node_id.stillworm
local c_pebble_fungus = df_caverns.node_id.pebble_fungus
local c_red = df_caverns.node_id.spindlestem_red
local c_wet_flowstone = df_caverns.node_id.wet_flowstone
local c_dry_flowstone = df_caverns.node_id.dry_flowstone
local c_veinstone = df_caverns.node_id.veinstone
local c_pearls = df_caverns.node_id.pearls
local chasms_path = minetest.get_modpath("chasms")
local log_location
if mapgen_helper.log_location_enabled then
log_location = mapgen_helper.log_first_location
end
local wall_vein_perlin_params = {
offset = 0,
scale = 1,
spread = {x = 50, y = 50, z = 50},
seed = 2199,
octaves = 3,
persist = 0.63,
lacunarity = 2.0,
flags = "eased",
}
local subsea_level = df_caverns.config.level2_min - (df_caverns.config.level2_min - df_caverns.config.level1_min) * 0.33 -- "sea level" for the flooded caverns.
local flooding_threshold = math.min(df_caverns.config.tunnel_flooding_threshold, df_caverns.config.cavern_threshold) -- cavern value out to which we're flooding tunnels and warrens
local get_biome = function(heat, humidity)
if humidity < 23 then -- about 20% of locations fall below this threshold
return "barren"
elseif heat < 40 then
return "goblincap" -- about 33% are below this threshold
elseif heat < 60 then
return "sporetree" -- another 33%
else
return "tunneltube"
end
end
df_caverns.register_biome_check(function(pos, heat, humidity)
if pos.y < df_caverns.config.level2_min or pos.y >= df_caverns.config.level1_min then
return nil
end
return get_biome(heat, humidity)
end)
local goblin_cap_shrublist
local tunnel_tube_shrublist
local spore_tree_shrublist
if minetest.get_modpath("df_farming") then
goblin_cap_shrublist = {
df_farming.spawn_plump_helmet_vm,
df_farming.spawn_plump_helmet_vm,
df_farming.spawn_dead_fungus_vm,
df_farming.spawn_cavern_fungi_vm,
}
tunnel_tube_shrublist = {
df_farming.spawn_sweet_pod_vm,
df_farming.spawn_cave_wheat_vm,
df_farming.spawn_cave_wheat_vm,
df_farming.spawn_dead_fungus_vm,
df_farming.spawn_cavern_fungi_vm,
}
spore_tree_shrublist = {
df_farming.spawn_pig_tail_vm,
df_farming.spawn_pig_tail_vm,
df_farming.spawn_cave_wheat_vm,
df_farming.spawn_dead_fungus_vm,
df_farming.spawn_cavern_fungi_vm,
}
end
local goblin_cap_cavern_floor = function(abs_cracks, vert_rand, vi, area, data, data_param2)
local ystride = area.ystride
if abs_cracks < 0.1 then
df_caverns.stalagmites(abs_cracks, vert_rand, vi, area, data, data_param2, true)
elseif data[vi-ystride] ~= c_air then -- leave the ground as rock if it's only one node thick
if math.random() < 0.25 then
data[vi] = c_dirt
else
data[vi] = c_dirt_moss
end
if math.random() < 0.1 then
df_caverns.place_shrub(vi+ystride, area, data, data_param2, goblin_cap_shrublist)
elseif math.random() < 0.02 then
df_trees.spawn_spindlestem_vm(vi+ystride, area, data, data_param2, c_red)
elseif math.random() < 0.015 then
df_trees.spawn_goblin_cap_vm(vi+ystride, area, data, data_param2)
end
end
end
local spore_tree_cavern_floor = function(abs_cracks, vert_rand, vi, area, data, data_param2)
local ystride = area.ystride
if abs_cracks < 0.1 then
df_caverns.stalagmites(abs_cracks, vert_rand, vi, area, data, data_param2, true)
elseif data[vi-ystride] ~= c_air then -- leave the ground as rock if it's only one node thick
if math.random() < 0.25 then
data[vi] = c_dirt
else
data[vi] = c_pebble_fungus
end
if math.random() < 0.1 then
df_caverns.place_shrub(vi+ystride, area, data, data_param2, spore_tree_shrublist)
elseif math.random() < 0.05 then
df_trees.spawn_spore_tree_vm(vi+ystride, area, data, data_param2)
end
end
end
local tunnel_tube_cavern_floor = function(abs_cracks, vert_rand, vi, area, data, data_param2)
local ystride = area.ystride
if abs_cracks < 0.1 then
df_caverns.stalagmites(abs_cracks, vert_rand, vi, area, data, data_param2, true)
elseif data[vi-ystride] ~= c_air then -- leave the ground as rock if it's only one node thick
if math.random() < 0.25 then
data[vi] = c_dirt
else
data[vi] = c_stillworm
end
if math.random() < 0.1 then
df_caverns.place_shrub(vi+ystride, area, data, data_param2, tunnel_tube_shrublist)
elseif math.random() < 0.05 then
df_trees.spawn_tunnel_tube_vm(vi+ystride, area, data, data_param2)
end
end
end
local decorate_level_2 = function(minp, maxp, seed, vm, node_arrays, area, data)
math.randomseed(minp.x + minp.y*2^8 + minp.z*2^16 + seed) -- make decorations consistent between runs
local heatmap = minetest.get_mapgen_object("heatmap")
local humiditymap = minetest.get_mapgen_object("humiditymap")
local data_param2 = df_caverns.data_param2
vm:get_param2_data(data_param2)
local nvals_cracks = mapgen_helper.perlin2d("df_cavern:cracks", minp, maxp, df_caverns.np_cracks)
local nvals_cave = node_arrays.nvals_cave
local cave_area = node_arrays.cave_area
local cavern_def = node_arrays.cavern_def
local vein_noise
local vein_area
-- Partly fill flooded caverns and warrens
for vi, x, y, z in area:iterp_yxz(area.MinEdge, area.MaxEdge) do
local cave_val = nvals_cave[vi]
if cave_val < -flooding_threshold then
if mapgen_helper.is_pos_within_box({x=x, y=y, z=z}, minp, maxp) then
local index2d = mapgen_helper.index2di(minp, maxp, area, vi)
local biome_name = get_biome(heatmap[index2d], humiditymap[index2d])
local cave_threshold = cavern_def.cave_threshold
--check if we're just inside the boundary of the (negazone) cavern threshold
if biome_name == "barren" and cave_val < -cave_threshold and cave_val > -cave_threshold - 0.01 then
-- add giant rooty structures to the flooded barren caverns
if vein_noise == nil then
vein_noise, vein_area = mapgen_helper.perlin3d("df_caverns:wall_veins", minp, maxp, wall_vein_perlin_params)
end
if data[vi] == c_air and math.abs(vein_noise[vein_area:transform(area, vi)]) < 0.02 then
data[vi] = c_veinstone
end
if log_location then log_location("level2_veinstone", area:position(vi)) end
end
end
if data[vi] == c_air and y <= subsea_level then
data[vi] = c_water -- otherwise, fill air with water when below sea level
end
end
end
---------------------------------------------------------
-- Cavern floors
for _, vi in ipairs(node_arrays.cavern_floor_nodes) do
local vert_rand = mapgen_helper.xz_consistent_randomi(area, vi)
local index2d = mapgen_helper.index2di(minp, maxp, area, vi)
local biome_name = get_biome(heatmap[index2d], humiditymap[index2d])
local abs_cracks = math.abs(nvals_cracks[index2d])
local flooded_caverns = nvals_cave[vi] < 0 -- this indicates if we're in the "flooded" set of caves or not.
if minp.y < subsea_level and area:get_y(vi) < subsea_level and flooded_caverns then
-- underwater floor
df_caverns.flooded_cavern_floor(abs_cracks, vert_rand, vi, area, data)
if log_location then log_location("level2_flooded_"..biome_name, area:position(vi)) end
elseif biome_name == "barren" then
if flooded_caverns then
df_caverns.wet_cavern_floor(abs_cracks, vert_rand, vi, area, data, data_param2)
if log_location then log_location("level2_barren_wet", area:position(vi)) end
else
df_caverns.dry_cavern_floor(abs_cracks, vert_rand, vi, area, data, data_param2)
if log_location then log_location("level2_barren_dry", area:position(vi)) end
end
elseif biome_name == "goblincap" then
goblin_cap_cavern_floor(abs_cracks, vert_rand, vi, area, data, data_param2)
if log_location then log_location("level2_goblincap", area:position(vi)) end
elseif biome_name == "sporetree" then
spore_tree_cavern_floor(abs_cracks, vert_rand, vi, area, data, data_param2)
if log_location then log_location("level2_sporetree", area:position(vi)) end
elseif biome_name == "tunneltube" then
tunnel_tube_cavern_floor(abs_cracks, vert_rand, vi, area, data, data_param2)
if log_location then log_location("level2_tunneltube", area:position(vi)) end
end
end
--------------------------------------
-- Cavern ceilings
for _, vi in ipairs(node_arrays.cavern_ceiling_nodes) do
local vert_rand = mapgen_helper.xz_consistent_randomi(area, vi)
local index2d = mapgen_helper.index2di(minp, maxp, area, vi)
local biome_name = get_biome(heatmap[index2d], humiditymap[index2d])
local abs_cracks = math.abs(nvals_cracks[index2d])
local flooded_caverns = nvals_cave[vi] < 0 -- this indicates if we're in the "flooded" set of caves or not.
if flooded_caverns and minp.y < subsea_level and area:get_y(vi) < subsea_level then
-- underwater ceiling, do nothing
elseif biome_name == "barren" then
if flooded_caverns then
-- wet barren
if abs_cracks < 0.1 then
df_caverns.stalactites(abs_cracks, vert_rand, vi, area, data, data_param2, true)
end
else
-- dry barren
if abs_cracks < 0.075 then
df_caverns.stalactites(abs_cracks, vert_rand, vi, area, data, data_param2, false)
end
local y = area:get_y(vi)
local y_proportional = (y - df_caverns.config.level1_min) / (df_caverns.config.level2_min - df_caverns.config.level1_min)
if abs_cracks * y_proportional > 0.3 and math.random() < 0.005 * y_proportional then
df_mapitems.place_big_crystal_cluster(area, data, data_param2, vi, math.random(0,1), true)
end
end
else -- all the other biomes
df_caverns.glow_worm_cavern_ceiling(abs_cracks, vert_rand, vi, area, data, data_param2)
end
end
----------------------------------------------
-- Tunnel floors
for _, vi in ipairs(node_arrays.tunnel_floor_nodes) do
local index2d = mapgen_helper.index2di(minp, maxp, area, vi)
local biome_name = get_biome(heatmap[index2d], humiditymap[index2d])
local flooded_caverns = nvals_cave[vi] < 0 -- this indicates if we're in the "flooded" set of caves or not.
if not (flooded_caverns and minp.y < subsea_level and area:get_y(vi) < subsea_level) then
if flooded_caverns or biome_name ~= "barren" then
-- we're in flooded areas or are not barren
df_caverns.tunnel_floor(minp, maxp, area, vi, nvals_cracks, data, data_param2, true)
else
df_caverns.tunnel_floor(minp, maxp, area, vi, nvals_cracks, data, data_param2, false, c_gravel)
end
end
end
------------------------------------------------------
-- Tunnel ceiling
for _, vi in ipairs(node_arrays.tunnel_ceiling_nodes) do
local index2d = mapgen_helper.index2di(minp, maxp, area, vi)
local biome_name = get_biome(heatmap[index2d], humiditymap[index2d])
local flooded_caverns = nvals_cave[vi] < 0 -- this indicates if we're in the "flooded" set of caves or not.
local ystride = area.ystride
if not (flooded_caverns and minp.y < subsea_level and area:get_y(vi) < subsea_level) then
if flooded_caverns or biome_name ~= "barren" then
-- we're in flooded areas or are not barren
df_caverns.tunnel_ceiling(minp, maxp, area, vi, nvals_cracks, data, data_param2, true)
else
df_caverns.tunnel_ceiling(minp, maxp, area, vi, nvals_cracks, data, data_param2, false)
end
if not flooded_caverns and (biome_name == "barren" or biome_name == "sporetree") and nvals_cracks[index2d] > 0.5 then
for i= 1, 4 do
if math.random() > 0.5 then
local index = vi-i*ystride
if data[index] == c_air then
df_mapitems.place_against_surface_vm(c_pearls, index, area, data, data_param2)
end
end
end
end
else
-- air pockets
local ystride = area.ystride
local cracks = nvals_cracks[index2d]
if cracks > 0.4 and data[vi-ystride] == c_water then
data[vi-ystride] = c_air
if cracks > 0.6 and data[vi-ystride*2] == c_water then
data[vi-ystride*2] = c_air
end
end
end
end
----------------------------------------------
-- Warren floors
for _, vi in ipairs(node_arrays.warren_floor_nodes) do
local index2d = mapgen_helper.index2di(minp, maxp, area, vi)
local biome_name = get_biome(heatmap[index2d], humiditymap[index2d])
local flooded_caverns = nvals_cave[vi] < 0 -- this indicates if we're in the "flooded" set of caves or not.
if log_location then
local flood_name = ""
if flooded_caverns then flood_name = "_flooded" end
log_location("level2_warren_"..biome_name..flood_name, area:position(vi))
end
if not (flooded_caverns and minp.y < subsea_level and area:get_y(vi) < subsea_level) then
if flooded_caverns or biome_name ~= "barren" then
-- we're in flooded areas or are not barren
df_caverns.tunnel_floor(minp, maxp, area, vi, nvals_cracks, data, data_param2, true)
else
df_caverns.tunnel_floor(minp, maxp, area, vi, nvals_cracks, data, data_param2, false, c_gravel)
end
end
end
------------------------------------------------------
-- Warren ceiling
for _, vi in ipairs(node_arrays.warren_ceiling_nodes) do
local index2d = mapgen_helper.index2di(minp, maxp, area, vi)
local biome_name = get_biome(heatmap[index2d], humiditymap[index2d])
local flooded_caverns = nvals_cave[vi] < 0 -- this indicates if we're in the "flooded" set of caves or not.
local ystride = area.ystride
if not (flooded_caverns and minp.y < subsea_level and area:get_y(vi) < subsea_level) then
if flooded_caverns or biome_name ~= "barren" then
-- we're in flooded areas or are not barren
df_caverns.tunnel_ceiling(minp, maxp, area, vi, nvals_cracks, data, data_param2, true)
else
df_caverns.tunnel_ceiling(minp, maxp, area, vi, nvals_cracks, data, data_param2, false)
end
if not flooded_caverns and (biome_name == "barren" or biome_name == "sporetree") and nvals_cracks[index2d] > 0.5 then
for i= 1, 4 do
if math.random() > 0.5 then
local index = vi-i*ystride
if data[index] == c_air then
df_mapitems.place_against_surface_vm(c_pearls, index, area, data, data_param2)
end
end
end
end
else
-- air pockets
local cracks = nvals_cracks[index2d]
if cracks > 0.4 and data[vi-ystride] == c_water then
data[vi-ystride] = c_air
if cracks > 0.6 and data[vi-ystride*2] == c_water then
data[vi-ystride*2] = c_air
end
end
end
end
----------------------------------------------
-- Column material override for dry biome
for _, vi in ipairs(node_arrays.column_nodes) do
local index2d = mapgen_helper.index2di(minp, maxp, area, vi)
local biome_name = get_biome(heatmap[index2d], humiditymap[index2d])
local dry = (biome_name == "barren") and (nvals_cave[vi] > 0)
if dry and data[vi] == c_wet_flowstone then
data[vi] = c_dry_flowstone
end
if chasms_path then
local pos = area:position(vi)
if chasms.is_in_chasm_without_taper(pos) then
local flooded_caverns = nvals_cave[vi] < 0 -- this indicates if we're in the "flooded" set of caves or not.
if flooded_caverns and pos.y < subsea_level then
data[vi] = c_water
else
data[vi] = c_air
end
end
end
end
vm:set_param2_data(data_param2)
end
subterrane.register_layer({
name = "cavern layer 2",
y_max = df_caverns.config.level1_min-1,
y_min = df_caverns.config.level2_min,
cave_threshold = df_caverns.config.cavern_threshold,
boundary_blend_range = 64, -- range near ymin and ymax over which caves diminish to nothing
perlin_cave = df_caverns.perlin_cave,
perlin_wave = df_caverns.perlin_wave,
solidify_lava = true,
columns = {
maximum_radius = 15,
minimum_radius = 4,
node = "df_mapitems:wet_flowstone",
weight = 0.25,
maximum_count = 50,
minimum_count = 5,
},
decorate = decorate_level_2,
warren_region_variability_threshold = 0.33,
double_frequency = true,
is_ground_content = df_caverns.is_ground_content,
})
+583
View File
@@ -0,0 +1,583 @@
local c_water = df_caverns.node_id.water
local c_air = df_caverns.node_id.air
local c_desert_sand = df_caverns.node_id.desert_sand
local c_stone_with_coal = df_caverns.node_id.stone_with_coal
local c_silver_sand = df_caverns.node_id.silver_sand
local c_snow = df_caverns.node_id.snow
local c_ice = df_caverns.node_id.ice
local c_hoar_moss = df_caverns.node_id.hoar_moss
local c_gravel = df_caverns.node_id.gravel
local c_oil = df_caverns.node_id.oil
local c_cobble_fungus_fine = df_caverns.node_id.cobble_fungus_fine
local c_cobble_fungus = df_caverns.node_id.cobble_fungus
local c_cobble = df_caverns.node_id.cobble
local c_wet_flowstone = df_caverns.node_id.wet_flowstone
local c_dry_flowstone = df_caverns.node_id.dry_flowstone
local c_glow_ore = df_caverns.node_id.glow_ore
local c_salty_cobble = df_caverns.node_id.salty_cobble
local c_salt_crystal = df_caverns.node_id.salt_crystal
local c_sprite = df_caverns.node_id.sprite
local c_webs_egg = df_caverns.node_id.big_webs_egg
local chasms_path = minetest.get_modpath("chasms")
local log_location
if mapgen_helper.log_location_enabled then
log_location = mapgen_helper.log_first_location
end
local subsea_level = math.floor(df_caverns.config.level3_min - (df_caverns.config.level3_min - df_caverns.config.level2_min) * 0.33)
local flooding_threshold = math.min(df_caverns.config.tunnel_flooding_threshold, df_caverns.config.cavern_threshold)
local ice_thickness = 3
local get_biome = function(heat, humidity)
if humidity < 23 then -- about 20% of locations fall below this threshold
return "barren"
elseif heat < 50 then
return "blackcap"
else
return "bloodnether"
end
end
df_caverns.register_biome_check(function(pos, heat, humidity)
if pos.y < df_caverns.config.level3_min or pos.y >= df_caverns.config.level2_min then
return nil
end
local biome = get_biome(heat, humidity)
if biome == "bloodnether" then
local cavern_value = subterrane.get_cavern_value("cavern layer 3", pos)
if cavern_value == nil then
-- this shouldn't happen, the pos.y check above should prevent it.
return nil
end
if cavern_value < 0 then
return "nethercap"
end
return "bloodthorn"
end
return biome
end)
local black_cap_shrublist
local nether_cap_shrublist
local blood_thorn_shrublist
if minetest.get_modpath("df_farming") then
black_cap_shrublist = {
df_farming.spawn_dead_fungus_vm,
}
nether_cap_shrublist = {
df_farming.spawn_dead_fungus_vm,
df_farming.spawn_dead_fungus_vm,
df_farming.spawn_dead_fungus_vm,
df_farming.spawn_cavern_fungi_vm,
}
blood_thorn_shrublist = {
df_farming.spawn_quarry_bush_vm,
df_farming.spawn_dead_fungus_vm,
df_farming.spawn_dead_fungus_vm,
}
end
local hoar_moss_perlin_params = {
offset = 0,
scale = 1,
spread = {x = 3, y = 30, z = 3},
seed = 345421,
octaves = 3,
persist = 0.63,
lacunarity = 2.0,
flags = "eased",
}
local black_cap_cavern_floor = function(abs_cracks, vert_rand, vi, area, data, data_param2)
if math.random() < 0.25 then
data[vi] = c_stone_with_coal
else
data[vi] = c_cobble_fungus
end
if abs_cracks < 0.1 then
df_caverns.stalagmites(abs_cracks, vert_rand, vi, area, data, data_param2, false)
elseif abs_cracks < 0.15 and math.random() < 0.3 then
df_trees.spawn_torchspine_vm(vi+area.ystride, area, data, data_param2)
else
if math.random() < 0.05 then
df_caverns.place_shrub(vi+area.ystride, area, data, data_param2, black_cap_shrublist)
elseif math.random() < 0.01 and abs_cracks > 0.25 then
df_trees.spawn_black_cap_vm(vi+area.ystride, area, data)
end
end
end
local nether_cap_cavern_floor = function(cracks, abs_cracks, vert_rand, vi, area, data, data_param2)
local ystride = area.ystride
if abs_cracks < 0.1 then
if vert_rand < 0.004 then
subterrane.big_stalagmite(vi+ystride, area, data, 6, 15, c_ice, c_ice, c_ice)
else
local param2 = abs_cracks*1000000 - math.floor(abs_cracks*1000000/4)*4
local height = abs_cracks * 50
if vert_rand > 0.5 then
subterrane.stalagmite(vi+ystride, area, data, data_param2, param2, math.floor(height), df_mapitems.icicle_ids)
else
subterrane.stalagmite(vi+ystride, area, data, data_param2, param2, math.floor(height*0.5), df_mapitems.dry_stalagmite_ids)
end
end
end
if cracks < -0.3 then
data[vi] = c_silver_sand
if math.random() < 0.025 then
df_trees.spawn_nether_cap_vm(vi+ystride, area, data)
elseif math.random() < 0.05 then
df_caverns.place_shrub(vi+ystride, area, data, data_param2, nether_cap_shrublist)
elseif cracks < -0.4 and cracks > -0.6 then
data[vi + ystride] = c_snow
end
elseif cracks > 0.1 then
if math.random() < 0.002 then
df_trees.spawn_nether_cap_vm(vi+ystride, area, data)
else
data[vi] = c_ice
end
if cracks > 0.4 then
data[vi + ystride] = c_ice
if cracks > 0.6 then
data[vi + 2*ystride] = c_ice
end
end
end
end
local nether_cap_cavern_ceiling = function(abs_cracks, vert_rand, vi, area, data, data_param2)
local ystride = area.ystride
if abs_cracks < 0.1 then
if vert_rand < 0.01 then
subterrane.big_stalactite(vi-ystride, area, data, 6, 15, c_ice, c_ice, c_ice)
else
local param2 = abs_cracks*1000000 - math.floor(abs_cracks*1000000/4)*4
local height = abs_cracks * 50
if vert_rand > 0.5 then
subterrane.stalactite(vi-ystride, area, data, data_param2, param2, math.floor(height), df_mapitems.icicle_ids)
else
subterrane.stalactite(vi-ystride, area, data, data_param2, param2, math.floor(height*0.5), df_mapitems.dry_stalagmite_ids)
end
end
end
if c_sprite and abs_cracks < 0.5 and math.random() < 0.02 then
local sprite_vi = vi-ystride*math.random(1,5)
if data[sprite_vi] == c_air and area:containsi(sprite_vi) then
data[sprite_vi] = c_sprite
minetest.get_node_timer(area:position(sprite_vi)):start(1)
end
end
end
local blood_thorn_cavern_floor = function(abs_cracks, vert_rand, vi, area, data, data_param2)
local ai = vi+area.ystride
if abs_cracks < 0.075 then
if vert_rand < 0.004 then
subterrane.big_stalagmite(ai, area, data, 6, 15, c_dry_flowstone, c_dry_flowstone, c_dry_flowstone)
elseif data[vi] ~= c_air and math.random() < 0.5 then
data[vi] = c_salty_cobble
if data[ai] == c_air and math.random() < 0.25 then
data[ai] = c_salt_crystal
data_param2[ai] = math.random(1,4)-1
end
else
local param2 = abs_cracks*1000000 - math.floor(abs_cracks*1000000/4)*4
local height = math.floor(abs_cracks * 66)
subterrane.stalagmite(ai, area, data, data_param2, param2, height, df_mapitems.dry_stalagmite_ids)
end
elseif math.random() > abs_cracks + 0.66 then
df_trees.spawn_blood_thorn_vm(ai, area, data, data_param2)
data[vi] = c_desert_sand
else
if math.random() < 0.1 then
df_caverns.place_shrub(ai, area, data, data_param2, blood_thorn_shrublist)
data[vi] = c_desert_sand
elseif math.random() > 0.25 then
data[vi] = c_desert_sand
else
data[vi] = c_cobble
end
end
end
local hoar_moss_generator
local decorate_level_3 = function(minp, maxp, seed, vm, node_arrays, area, data)
math.randomseed(minp.x + minp.y*2^8 + minp.z*2^16 + seed) -- make decorations consistent between runs
local heatmap = minetest.get_mapgen_object("heatmap")
local humiditymap = minetest.get_mapgen_object("humiditymap")
local data_param2 = df_caverns.data_param2
vm:get_param2_data(data_param2)
local nvals_cracks = mapgen_helper.perlin2d("df_cavern:cracks", minp, maxp, df_caverns.np_cracks)
local nvals_cave = node_arrays.nvals_cave
local cave_area = node_arrays.cave_area
local cavern_def = node_arrays.cavern_def
-- Partly fill flooded caverns and warrens
if minp.y <= subsea_level then
for vi, x, y, z in area:iterp_yxz(area.MinEdge, area.MaxEdge) do
local cave = nvals_cave[vi]
if y <= subsea_level and cave < -flooding_threshold then
if data[vi] == c_air and y <= subsea_level then
data[vi] = c_water
end
if (mapgen_helper.is_pos_within_box({x=x, y=y, z=z}, minp, maxp)) then
local index2d = mapgen_helper.index2di(minp, maxp, area, vi)
local biome_name = get_biome(heatmap[index2d], humiditymap[index2d])
if biome_name == "blackcap" then
-- oil slick
if y == subsea_level and data[vi] == c_water and math.abs(cave) + nvals_cracks[index2d]*0.025 < cavern_def.cave_threshold + 0.1 then
data[vi] = c_oil
if log_location then log_location("level3_blackcap_oil", vector.new(x,y,z)) end
end
elseif biome_name == "bloodnether" and y <= subsea_level and y > subsea_level - ice_thickness and data[vi] == c_water then
-- floating ice
data[vi] = c_ice
if log_location then log_location("level3_nethercap_floating_ice", vector.new(x,y,z)) end
end
end
end
end
end
---------------------------------------------------------
-- Cavern floors
for _, vi in ipairs(node_arrays.cavern_floor_nodes) do
local vert_rand = mapgen_helper.xz_consistent_randomi(area, vi)
local index2d = mapgen_helper.index2di(minp, maxp, area, vi)
local biome_name = get_biome(heatmap[index2d], humiditymap[index2d])
local cracks = nvals_cracks[index2d]
local abs_cracks = math.abs(cracks)
local flooded_caverns = nvals_cave[vi] < 0 -- this indicates if we're in the "flooded" set of caves or not.
if flooded_caverns and minp.y < subsea_level and area:get_y(vi) < subsea_level then
-- underwater floor. Not using df_caverns.flooded_cavern_floor to make level 3 water darker
local ystride = area.ystride
if abs_cracks > 0.25 and data[vi-ystride] ~= c_water then
data[vi] = c_gravel
end
-- put in only the large stalagmites that won't get in the way of the water
if abs_cracks < 0.1 then
if vert_rand < 0.004 then
subterrane.big_stalagmite(vi+ystride, area, data, 6, 15, c_wet_flowstone, c_wet_flowstone, c_wet_flowstone)
end
end
if log_location then log_location("level3_flooded_"..biome_name, area:position(vi)) end
elseif biome_name == "barren" then
if flooded_caverns then
-- wet zone floor
df_caverns.dry_cavern_floor(abs_cracks, vert_rand, vi, area, data, data_param2)
if log_location then log_location("level3_barren_dry", area:position(vi)) end
else
-- dry zone floor, add crystals
if abs_cracks < 0.075 then
df_caverns.stalagmites(abs_cracks, vert_rand, vi, area, data, data_param2, false)
elseif abs_cracks > 0.3 and math.random() < 0.005 then
df_mapitems.place_big_crystal_cluster(area, data, data_param2, vi+area.ystride, math.random(0,2), false)
end
if log_location then log_location("level3_barren_wet", area:position(vi)) end
end
elseif biome_name == "blackcap" then
black_cap_cavern_floor(abs_cracks, vert_rand, vi, area, data, data_param2)
if log_location then log_location("level3_blackcap", area:position(vi)) end
elseif biome_name == "bloodnether" then
if flooded_caverns then
nether_cap_cavern_floor(cracks, abs_cracks, vert_rand, vi, area, data, data_param2)
if log_location then log_location("level3_nethercap", area:position(vi)) end
else
blood_thorn_cavern_floor(abs_cracks, vert_rand, vi, area, data, data_param2)
if log_location then log_location("level3_bloodthorn", area:position(vi)) end
end
end
end
--------------------------------------
-- Cavern ceilings
for _, vi in ipairs(node_arrays.cavern_ceiling_nodes) do
local vert_rand = mapgen_helper.xz_consistent_randomi(area, vi)
local index2d = mapgen_helper.index2di(minp, maxp, area, vi)
local biome_name = get_biome(heatmap[index2d], humiditymap[index2d])
local abs_cracks = math.abs(nvals_cracks[index2d])
local flooded_caverns = nvals_cave[vi] < 0 -- this indicates if we're in the "flooded" set of caves or not.
if flooded_caverns and minp.y < subsea_level and area:get_y(vi) < subsea_level then
-- underwater ceiling, do nothing
elseif biome_name == "blackcap" then
if abs_cracks < 0.1 then
df_caverns.stalactites(abs_cracks, vert_rand, vi, area, data, data_param2, false)
end
if math.random() < 0.25 then
data[vi] = c_stone_with_coal
end
elseif biome_name == "barren" then
if flooded_caverns then
-- wet zone ceiling
if abs_cracks < 0.1 then
df_caverns.stalactites(abs_cracks, vert_rand, vi, area, data, data_param2, true)
end
else
-- dry zone ceiling, add crystals
if abs_cracks < 0.1 then
df_caverns.stalactites(abs_cracks, vert_rand, vi, area, data, data_param2, false)
end
if abs_cracks > 0.3 and math.random() < 0.005 then
df_mapitems.place_big_crystal_cluster(area, data, data_param2, vi, math.random(0,3), true)
end
end
elseif biome_name == "bloodnether" then
if flooded_caverns then
--Nethercap ceiling
nether_cap_cavern_ceiling(abs_cracks, vert_rand, vi, area, data, data_param2)
else
-- bloodthorn ceiling
if abs_cracks < 0.075 then
if data[vi] ~= c_air and math.random() < 0.5 then
data[vi] = c_salty_cobble
local bi = vi - area.ystride
if data[bi] == c_air and math.random() < 0.25 then
data[bi] = c_salt_crystal
data_param2[bi] = 19 + math.random(1,4)
end
else
df_caverns.stalactites(abs_cracks, vert_rand, vi, area, data, data_param2, false)
end
elseif abs_cracks > 0.75 and math.random() < 0.05 then
data[vi] = c_glow_ore
df_mapitems.place_big_crystal(data, data_param2, vi-area.ystride, true)
end
end
end
end
----------------------------------------------
-- Tunnel floors
for _, vi in ipairs(node_arrays.tunnel_floor_nodes) do
local index2d = mapgen_helper.index2di(minp, maxp, area, vi)
local biome_name = get_biome(heatmap[index2d], humiditymap[index2d])
local flooded_caverns = nvals_cave[vi] < 0 -- this indicates if we're in the "flooded" set of caves or not.
if not (flooded_caverns and minp.y < subsea_level and area:get_y(vi) < subsea_level) then
if flooded_caverns or biome_name == "blackcap" then
-- we're in flooded areas or are not barren
df_caverns.tunnel_floor(minp, maxp, area, vi, nvals_cracks, data, data_param2, true)
else
df_caverns.tunnel_floor(minp, maxp, area, vi, nvals_cracks, data, data_param2, false, c_gravel)
end
end
end
------------------------------------------------------
-- Tunnel ceiling
for _, vi in ipairs(node_arrays.tunnel_ceiling_nodes) do
local index2d = mapgen_helper.index2di(minp, maxp, area, vi)
local humidity = humiditymap[index2d]
local biome_name = get_biome(heatmap[index2d], humidity)
local flooded_caverns = nvals_cave[vi] < 0 -- this indicates if we're in the "flooded" set of caves or not.
local ystride = area.ystride
if not (flooded_caverns and minp.y < subsea_level and area:get_y(vi) < subsea_level) then
if flooded_caverns or biome_name == "blackcap" then
-- we're in flooded areas or are not barren
df_caverns.tunnel_ceiling(minp, maxp, area, vi, nvals_cracks, data, data_param2, true)
else
df_caverns.tunnel_ceiling(minp, maxp, area, vi, nvals_cracks, data, data_param2, false)
end
if c_webs_egg and humidity < 40 and nvals_cracks[index2d] > 0.5 and math.random() < 0.1 then
local index = vi-ystride
if data[index] == c_air then
data[index] = c_webs_egg
minetest.get_node_timer(area:position(index)):start(1)
end
end
else
-- air pockets
local cracks = nvals_cracks[index2d]
if cracks > 0.5 and data[vi-ystride] == c_water then
data[vi-ystride] = c_air
if cracks > 0.7 and data[vi-ystride*2] == c_water then
data[vi-ystride*2] = c_air
end
end
end
end
------------------------------------------------------
-- Warren ceiling
for _, vi in ipairs(node_arrays.warren_ceiling_nodes) do
local index2d = mapgen_helper.index2di(minp, maxp, area, vi)
local biome_name = get_biome(heatmap[index2d], humiditymap[index2d])
local flooded_caverns = nvals_cave[vi] < 0 -- this indicates if we're in the "flooded" set of caves or not.
if log_location then
local flood_name = ""
if flooded_caverns then flood_name = "_flooded" end
log_location("level3_warren_"..biome_name..flood_name, area:position(vi))
end
if flooded_caverns and minp.y < subsea_level and area:get_y(vi) < subsea_level then
-- underwater ceiling, do nothing
elseif biome_name == "bloodnether" and flooded_caverns then
-- Nethercap warrens
local cracks = nvals_cracks[index2d]
local abs_cracks = math.abs(cracks)
local vert_rand = mapgen_helper.xz_consistent_randomi(area, vi)
local ystride = area.ystride
if abs_cracks < 0.15 then
if vert_rand < 0.004 then
subterrane.big_stalactite(vi-ystride, area, data, 6, 15, c_ice, c_ice, c_ice)
else
local param2 = abs_cracks*1000000 - math.floor(abs_cracks*1000000/4)*4
local height = abs_cracks * 50
if vert_rand > 0.5 then
subterrane.stalactite(vi-ystride, area, data, data_param2, param2, math.floor(height), df_mapitems.icicle_ids)
else
subterrane.stalactite(vi-ystride, area, data, data_param2, param2, math.floor(height*0.5), df_mapitems.dry_stalagmite_ids)
end
end
end
else
if flooded_caverns or biome_name == "blackcap" then
df_caverns.tunnel_ceiling(minp, maxp, area, vi, nvals_cracks, data, data_param2, true)
else
df_caverns.tunnel_ceiling(minp, maxp, area, vi, nvals_cracks, data, data_param2, false)
end
end
end
----------------------------------------------
-- Warren floors
for _, vi in ipairs(node_arrays.warren_floor_nodes) do
local index2d = mapgen_helper.index2di(minp, maxp, area, vi)
local biome_name = get_biome(heatmap[index2d], humiditymap[index2d])
local flooded_caverns = nvals_cave[vi] < 0 -- this indicates if we're in the "flooded" set of caves or not.
if minp.y < subsea_level and area:get_y(vi) < subsea_level and flooded_caverns then
-- underwater floor, do nothing
elseif biome_name == "bloodnether" and flooded_caverns then
-- nethercap warren
local cracks = nvals_cracks[index2d]
local abs_cracks = math.abs(cracks)
local vert_rand = mapgen_helper.xz_consistent_randomi(area, vi)
local ystride = area.ystride
if abs_cracks < 0.15 then
if vert_rand < 0.004 then
subterrane.big_stalagmite(vi+ystride, area, data, 6, 15, c_ice, c_ice, c_ice)
else
local param2 = abs_cracks*1000000 - math.floor(abs_cracks*1000000/4)*4
local height =abs_cracks * 50
if vert_rand > 0.5 then
subterrane.stalagmite(vi+ystride, area, data, data_param2, param2, math.floor(height), df_mapitems.icicle_ids)
else
subterrane.stalagmite(vi+ystride, area, data, data_param2, param2, math.floor(height*0.5), df_mapitems.dry_stalagmite_ids)
end
end
elseif cracks > 0.4 then
data[vi + ystride] = c_ice
if cracks > 0.6 then
data[vi + 2*ystride] = c_ice
end
end
else
if flooded_caverns or biome_name == "blackcap" then
df_caverns.tunnel_floor(minp, maxp, area, vi, nvals_cracks, data, data_param2, true)
else
df_caverns.tunnel_floor(minp, maxp, area, vi, nvals_cracks, data, data_param2, false, c_gravel)
end
end
end
----------------------------------------------
-- Column material override for dry and icy biomes
for _, vi in ipairs(node_arrays.column_nodes) do
local index2d = mapgen_helper.index2di(minp, maxp, area, vi)
local biome_name = get_biome(heatmap[index2d], humiditymap[index2d])
local flooded_caverns = nvals_cave[vi] < 0
if biome_name == "bloodnether" and data[vi] == c_wet_flowstone then
if not flooded_caverns then
data[vi] = c_dry_flowstone -- bloodthorn
else
if area:get_y(vi) > subsea_level - ice_thickness then
if data[vi + 1] == c_air or data[vi - 1] == c_air or data[vi + area.zstride] == c_air or data[vi - area.zstride] == c_air then
--surface node, potential hoar moss streak
-- This particular Perlin noise is only called in small amounts on rare occasions, so don't bother
-- with the full blown generated array rigamarole.
hoar_moss_generator = hoar_moss_generator or minetest.get_perlin(hoar_moss_perlin_params)
local pos = area:position(vi)
if hoar_moss_generator:get_3d({x=pos.z, y=pos.y, z=pos.x}) > 0.5 then
data[vi] = c_hoar_moss
else
data[vi] = c_ice
end
else
data[vi] = c_ice
end
else
data[vi] = c_water -- ice columns shouldn't extend below the surface of the water. There should probably be a bulge below, though. Not sure best way to implement that.
end
end
elseif biome_name == "barren" and not flooded_caverns and data[vi] == c_wet_flowstone then
data[vi] = c_dry_flowstone
end
if chasms_path then
local pos = area:position(vi)
if chasms.is_in_chasm_without_taper(pos) then
if flooded_caverns and pos.y < subsea_level then
data[vi] = c_water -- this puts a crack in the ice of icy biomes, but why not? A crack in the ice is interesting.
else
data[vi] = c_air
end
end
end
end
vm:set_param2_data(data_param2)
end
-- Layer 3
subterrane.register_layer({
name = "cavern layer 3",
y_max = df_caverns.config.level2_min-1,
y_min = df_caverns.config.level3_min,
cave_threshold = df_caverns.config.cavern_threshold,
boundary_blend_range = 64, -- range near ymin and ymax over which caves diminish to nothing
perlin_cave = df_caverns.perlin_cave,
perlin_wave = df_caverns.perlin_wave,
solidify_lava = true,
columns = {
maximum_radius = 20,
minimum_radius = 5,
node = "df_mapitems:wet_flowstone",
weight = 0.25,
maximum_count = 50,
minimum_count = 10,
},
decorate = decorate_level_3,
warren_region_variability_threshold = 0.33,
double_frequency = true,
is_ground_content = df_caverns.is_ground_content,
})
@@ -0,0 +1,11 @@
# textdomain: df_caverns
### underworld.lua ###
#WARNING: AUTOTRANSLATED BY GOOGLE TRANSLATE
A glowing pit=Eine leuchtende Grube
#WARNING: AUTOTRANSLATED BY GOOGLE TRANSLATE
Ancient ruin=Alte Ruine
#WARNING: AUTOTRANSLATED BY GOOGLE TRANSLATE
Mysterious seal=Geheimnisvolles Siegel
@@ -0,0 +1,11 @@
# textdomain: df_caverns
### underworld.lua ###
#WARNING: AUTOTRANSLATED BY GOOGLE TRANSLATE
A glowing pit=Un pozzo luminoso
#WARNING: AUTOTRANSLATED BY GOOGLE TRANSLATE
Ancient ruin=Antica rovina
#WARNING: AUTOTRANSLATED BY GOOGLE TRANSLATE
Mysterious seal=Sigillo misterioso
@@ -0,0 +1,8 @@
# textdomain: df_caverns
### underworld.lua ###
A glowing pit=
Ancient ruin=
Mysterious seal=
+4
View File
@@ -0,0 +1,4 @@
name = df_caverns
description = Adds vast underground caverns in the style of Dwarf Fortress, complete with underground flora in diverse biomes. Also adds stalactite/stalagmite decorations in the smaller tunnels.
depends = df_dependencies, subterrane, df_trees, df_mapitems,
optional_depends = df_farming, ice_sprites, oil, df_underworld_items, magma_conduits, bones_loot, named_waypoints, name_generator, fireflies, chasms, big_webs, mcl_flowers, mine_gas
+81
View File
@@ -0,0 +1,81 @@
df_caverns.node_id = {}
minetest.after(0, function() df_caverns.node_id = nil end) -- should only be used during initialization.
if df_dependencies.node_name_fireflies then
df_caverns.node_id.fireflies = minetest.get_content_id(df_dependencies.node_name_fireflies)
end
df_caverns.node_id.cobble = minetest.get_content_id(df_dependencies.node_name_cobble)
df_caverns.node_id.desert_sand = minetest.get_content_id(df_dependencies.node_name_desert_sand)
df_caverns.node_id.dirt = minetest.get_content_id(df_dependencies.node_name_dirt)
df_caverns.node_id.gravel = minetest.get_content_id(df_dependencies.node_name_gravel)
df_caverns.node_id.ice = minetest.get_content_id(df_dependencies.node_name_ice)
df_caverns.node_id.lava = minetest.get_content_id(df_dependencies.node_name_lava_source)
df_caverns.node_id.meseore = minetest.get_content_id(df_dependencies.node_name_stone_with_mese)
df_caverns.node_id.mossycobble = minetest.get_content_id(df_dependencies.node_name_mossycobble)
df_caverns.node_id.obsidian = minetest.get_content_id(df_dependencies.node_name_obsidian)
df_caverns.node_id.sand = minetest.get_content_id(df_dependencies.node_name_sand)
df_caverns.node_id.silver_sand = minetest.get_content_id(df_dependencies.node_name_silver_sand)
df_caverns.node_id.snow = minetest.get_content_id(df_dependencies.node_name_snow)
df_caverns.node_id.stone = minetest.get_content_id(df_dependencies.node_name_stone)
df_caverns.node_id.stone_with_coal = minetest.get_content_id(df_dependencies.node_name_stone_with_coal)
df_caverns.node_id.water = minetest.get_content_id(df_dependencies.node_name_water_source)
if minetest.get_modpath("big_webs") then
df_caverns.node_id.big_webs = minetest.get_content_id("big_webs:webbing")
df_caverns.node_id.big_webs_egg = minetest.get_content_id("big_webs:web_egg")
end
if minetest.get_modpath("ice_sprites") then
df_caverns.node_id.sprite = minetest.get_content_id("ice_sprites:ice_sprite")
end
if minetest.get_modpath("df_farming") then
df_caverns.node_id.dead_fungus = minetest.get_content_id("df_farming:dead_fungus")
end
df_caverns.node_id.air = minetest.get_content_id("air")
df_caverns.node_id.cobble_fungus = minetest.get_content_id("df_mapitems:cobble_with_floor_fungus")
df_caverns.node_id.cobble_fungus_fine = minetest.get_content_id("df_mapitems:cobble_with_floor_fungus_fine")
df_caverns.node_id.dirt_moss = minetest.get_content_id("df_mapitems:dirt_with_cave_moss")
df_caverns.node_id.dry_flowstone = minetest.get_content_id("df_mapitems:dry_flowstone")
df_caverns.node_id.glow_ore = minetest.get_content_id("df_mapitems:glow_ruby_ore")
df_caverns.node_id.hoar_moss = minetest.get_content_id("df_mapitems:ice_with_hoar_moss")
df_caverns.node_id.mese_crystal = minetest.get_content_id("df_mapitems:mese_crystal")
df_caverns.node_id.mese_crystal_block = minetest.get_content_id("df_mapitems:glow_mese")
df_caverns.node_id.pearls = minetest.get_content_id("df_mapitems:cave_pearls")
df_caverns.node_id.pebble_fungus = minetest.get_content_id("df_mapitems:dirt_with_pebble_fungus")
df_caverns.node_id.rock_rot = minetest.get_content_id("df_mapitems:rock_rot")
df_caverns.node_id.spongestone = minetest.get_content_id("df_mapitems:spongestone")
df_caverns.node_id.salt_crystal = minetest.get_content_id("df_mapitems:salt_crystal")
df_caverns.node_id.salty_cobble = minetest.get_content_id("df_mapitems:salty_cobble")
df_caverns.node_id.sand_scum = minetest.get_content_id("df_mapitems:sand_scum")
df_caverns.node_id.stillworm = minetest.get_content_id("df_mapitems:dirt_with_stillworm")
df_caverns.node_id.veinstone = minetest.get_content_id("df_mapitems:veinstone")
df_caverns.node_id.wet_flowstone = minetest.get_content_id("df_mapitems:wet_flowstone")
df_caverns.node_id.spindlestem_red = minetest.get_content_id("df_trees:spindlestem_cap_red")
df_caverns.node_id.spindlestem_white = minetest.get_content_id("df_trees:spindlestem_cap_white")
df_caverns.node_id.amethyst = minetest.get_content_id("df_underworld_items:glow_amethyst")
df_caverns.node_id.glowstone = minetest.get_content_id("df_underworld_items:glowstone")
df_caverns.node_id.pit_plasma = minetest.get_content_id("df_underworld_items:pit_plasma")
df_caverns.node_id.slade = minetest.get_content_id("df_underworld_items:slade")
df_caverns.node_id.slade_block = minetest.get_content_id("df_underworld_items:slade_block")
df_caverns.node_id.oil = minetest.get_content_id("oil:oil_source")
df_caverns.node_id.gas = minetest.get_content_id("mine_gas:gas")
df_caverns.node_id.gas_wisp = minetest.get_content_id("mine_gas:gas_wisp")
df_caverns.node_id.giant_mycelium = minetest.get_content_id("df_primordial_items:giant_hypha_apical_mapgen")
df_caverns.node_id.ivy = minetest.get_content_id("df_primordial_items:jungle_ivy")
df_caverns.node_id.jungle_dirt = minetest.get_content_id("df_primordial_items:dirt_with_jungle_grass")
df_caverns.node_id.mycelial_dirt = minetest.get_content_id("df_primordial_items:dirt_with_mycelium")
df_caverns.node_id.orb = minetest.get_content_id("df_primordial_items:glow_orb_hanging")
df_caverns.node_id.packed_roots = minetest.get_content_id("df_primordial_items:packed_roots")
df_caverns.node_id.plant_matter = minetest.get_content_id("df_primordial_items:plant_matter")
df_caverns.node_id.root_1 = minetest.get_content_id("df_primordial_items:jungle_roots_1")
df_caverns.node_id.root_2 = minetest.get_content_id("df_primordial_items:jungle_roots_2")
+131
View File
@@ -0,0 +1,131 @@
if not df_caverns.config.enable_oil_sea then
return
end
local c_oil = df_caverns.node_id.oil
local c_gas = df_caverns.node_id.gas
local c_gas_wisp = df_caverns.node_id.gas_wisp
local c_lava = df_caverns.node_id.lava
local c_obsidian = df_caverns.node_id.obsidian
local log_location
if mapgen_helper.log_location_enabled then
log_location = mapgen_helper.log_first_location
end
-------------------------------------------------------------------------------------------
local perlin_cave = {
offset = 0,
scale = 1,
spread = {x=300, y=300, z=300},
seed = 6000089,
octaves = 3,
persist = 0.67
}
-- large-scale rise and fall
local perlin_wave = {
offset = 0,
scale = 1,
spread = {x=1000, y=1000, z=1000},
seed = 10089,
octaves = 3,
persist = 0.67
}
local median = df_caverns.config.oil_sea_level
local floor_mult = -80
local floor_displace = 60
local ceiling_mult = 40
local ceiling_displace = -30
local wave_mult = 10
local c_lava_set
local y_max = median + 2*wave_mult + 2*ceiling_mult + ceiling_displace
local y_min = median - 2*wave_mult + 2*floor_mult + floor_displace
df_caverns.register_biome_check(function(pos, heat, humidity)
if pos.y > y_max or pos.y < y_min then
return
end
return "oil_sea"
end)
minetest.register_on_generated(function(minp, maxp, seed)
--if out of range of cave definition limits, abort
if minp.y > y_max or maxp.y < y_min then
return
end
local t_start = os.clock()
local vm, data, area = mapgen_helper.mapgen_vm_data()
local nvals_cave = mapgen_helper.perlin2d("df_caverns:oil_cave", minp, maxp, perlin_cave)
local nvals_wave = mapgen_helper.perlin2d("df_caverns:oil_wave", minp, maxp, perlin_wave)
if c_lava_set == nil then
c_lava_set = {}
for name, def in pairs(minetest.registered_nodes) do
if def.groups ~= nil and def.groups.lava ~= nil then
c_lava_set[minetest.get_content_id(name)] = true
end
end
end
for vi, x, y, z in area:iterp_yxz(minp, maxp) do
local index2d = mapgen_helper.index2d(minp, maxp, x, z)
local abs_cave = math.abs(nvals_cave[index2d]) -- range is from 0 to approximately 2, with 0 being connected and 2s being islands
local wave = nvals_wave[index2d] * wave_mult
local floor_height = math.floor(abs_cave * floor_mult + floor_displace + median + wave)
local ceiling_height = math.floor(abs_cave * ceiling_mult + median + ceiling_displace + wave)
if y > floor_height - 5 and y < ceiling_height + 5 then
if c_lava_set[data[vi]] then
data[vi] = c_obsidian
end
end
if y > floor_height and y < ceiling_height then
if y > median then
if math.random() < 0.00025 and ((y < median + 3) or (y > ceiling_height - 3)) then
data[vi] = c_gas_wisp
else
data[vi] = c_gas
end
else
data[vi] = c_oil
if log_location then log_location("oil_sea", area:position(vi)) 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()
local time_taken = os.clock() - t_start -- how long this chunk took, in seconds
mapgen_helper.record_time("df_caverns oil sea", time_taken)
end)
minetest.register_ore({
ore_type = "scatter",
ore = "mine_gas:gas_seep",
wherein = df_dependencies.node_name_stone,
clust_scarcity = 32 * 32 * 32,
clust_num_ores = 27,
clust_size = 6,
y_max = df_caverns.config.sunless_sea_min,
y_min = y_min,
})
+508
View File
@@ -0,0 +1,508 @@
if not df_caverns.config.enable_primordial or not minetest.get_modpath("df_primordial_items") then
return
end
local c_air = df_caverns.node_id.air
local log_location
if mapgen_helper.log_location_enabled then
log_location = mapgen_helper.log_first_location
end
local perlin_cave_primordial = {
offset = 0,
scale = 1,
spread = {x=df_caverns.config.horizontal_cavern_scale, y=df_caverns.config.vertical_cavern_scale*0.5, z=df_caverns.config.horizontal_cavern_scale},
seed = 14055553,
octaves = 3,
persist = 0.67
}
local perlin_wave_primordial = {
offset = 0,
scale = 1,
spread = {x=df_caverns.config.horizontal_cavern_scale, y=df_caverns.config.vertical_cavern_scale*0.5, z=df_caverns.config.horizontal_cavern_scale},
seed = 923444,
octaves = 6,
persist = 0.63
}
local giant_mycelium_timer_spread = tonumber(minetest.settings:get("dcaverns_giant_mycelium_timer_spread")) or 10
df_caverns.register_biome_check(function(pos, heat, humidity)
if pos.y < df_caverns.config.primordial_min or pos.y > df_caverns.config.primordial_max then
return nil
end
if subterrane.get_cavern_value("primordial", pos) < 0 then
return "primordial jungle"
end
return "primordial fungus"
end)
-----------------------------------------------------------------------------------------
-- Fungal biome
local c_orb = df_caverns.node_id.orb
local c_mycelial_dirt = df_caverns.node_id.mycelial_dirt
local c_dirt = df_caverns.node_id.dirt
local c_giant_mycelium = df_caverns.node_id.giant_mycelium
local fungal_plant_names = {}
local fungal_plants = {}
for node_name, node_def in pairs(minetest.registered_nodes) do
if minetest.get_item_group(node_name, "primordial_fungal_plant") > 0 then
table.insert(fungal_plant_names, node_name)
table.insert(fungal_plants, minetest.get_content_id(node_name))
end
end
local mushroom_cavern_floor = function(abs_cracks, humidity, vi, area, data, data_param2)
local ystride = area.ystride
local humidityfactor = humidity/200 + 0.5
abs_cracks = abs_cracks * humidityfactor
if abs_cracks < 0.7 then
data[vi] = c_mycelial_dirt
elseif abs_cracks < 1 then
data[vi] = c_dirt
end
local rand = math.random() * math.min(abs_cracks, 1) * humidityfactor
if rand < 0.0005 then
local mycelium_index = vi+ystride
data[mycelium_index] = c_giant_mycelium
minetest.get_node_timer(area:position(mycelium_index)):start(math.random(1,giant_mycelium_timer_spread))
elseif rand < 0.003 then
local schematic = df_primordial_items.get_primordial_mushroom()
local rotation = (math.random(1,4)-1)*90
mapgen_helper.place_schematic_on_data_if_it_fits(data, data_param2, area, area:position(vi+ystride), schematic, rotation)
elseif rand < 0.05 then
data[vi+ystride] = fungal_plants[math.random(1,5)]
end
end
local mushroom_cavern_ceiling = function(abs_cracks, humidity, vi, area, data, data_param2)
local ystride = area.ystride
local humidityfactor = humidity/200 + 0.5
abs_cracks = abs_cracks * humidityfactor
if abs_cracks < 0.5 then
data[vi] = c_mycelial_dirt
if abs_cracks < 0.3 then
local rand = math.random() * humidityfactor
if rand < 0.002 then
local mycelium_index = vi-ystride
data[mycelium_index] = c_giant_mycelium
minetest.get_node_timer(area:position(mycelium_index)):start(math.random(1,giant_mycelium_timer_spread))
elseif rand < 0.03 then
df_primordial_items.spawn_ceiling_spire_vm(vi, area, data)
elseif rand < 0.2 then
data[vi-ystride] = c_orb
data_param2[vi-ystride] = math.random(0,179)
end
end
end
end
local mushroom_warren_ceiling = function(abs_cracks, vi, area, data, data_param2)
local ystride = area.ystride
if abs_cracks < 0.3 then
data[vi] = c_mycelial_dirt
if abs_cracks < 0.2 then
local rand = math.random()
if rand < 0.001 then
local mycelium_index = vi-ystride
data[mycelium_index] = c_giant_mycelium
minetest.get_node_timer(area:position(mycelium_index)):start(math.random(1,giant_mycelium_timer_spread))
elseif rand < 0.2 then
data[vi-ystride] = c_orb
data_param2[vi-ystride] = math.random(0,179)
end
end
end
end
local mushroom_warren_floor = function(abs_cracks, vi, area, data, data_param2)
local ystride = area.ystride
if abs_cracks < 0.7 then
data[vi] = c_mycelial_dirt
elseif abs_cracks < 1 then
data[vi] = c_dirt
end
local rand = math.random() * math.min(abs_cracks, 1)
if rand < 0.001 then
local mycelium_index = vi+ystride
data[mycelium_index] = c_giant_mycelium
minetest.get_node_timer(area:position(mycelium_index)):start(math.random(1,giant_mycelium_timer_spread))
elseif rand < 0.03 then
data[vi+ystride] = fungal_plants[math.random(1,5)]
end
end
--------------------------------------------------------------------------------------------------
-- Jungle biome
local jungle_plant_names = {}
local jungle_plants = {}
for node_name, node_def in pairs(minetest.registered_nodes) do
if minetest.get_item_group(node_name, "primordial_jungle_plant") > 0 then
table.insert(jungle_plant_names, node_name)
table.insert(jungle_plants, minetest.get_content_id(node_name))
end
end
local c_jungle_dirt = df_caverns.node_id.jungle_dirt
local c_plant_matter = df_caverns.node_id.plant_matter
local c_packed_roots = df_caverns.node_id.packed_roots
local c_glowstone = df_caverns.node_id.glowstone
local c_ivy = df_caverns.node_id.ivy
local c_root_2 = df_caverns.node_id.root_2
local c_root_1 = df_caverns.node_id.root_1
local c_fireflies = df_caverns.node_id.fireflies
local jungle_cavern_floor = function(abs_cracks, humidity, vi, area, data, data_param2)
local ystride = area.ystride
local humidityfactor = humidity/100
if log_location then
local pos = area:position(vi)
log_location("primordial_jungle", pos)
if humidityfactor < 0.25 then
log_location("primordial_jungle_low_humidity", pos)
elseif humidityfactor > 0.75 then
log_location("primordial_jungle_high_humidity", pos)
end
end
data[vi] = c_jungle_dirt
local rand = math.random()
if rand < 0.025 * humidityfactor then
local fern_schematic = df_primordial_items.get_fern_schematic()
local rotation = (math.random(1,4)-1)*90
mapgen_helper.place_schematic_on_data_if_it_fits(data, data_param2, area, area:position(vi+ystride), fern_schematic, rotation)
elseif rand < 0.025 * (1-humidityfactor) then
df_primordial_items.spawn_jungle_mushroom_vm(vi+ystride, area, data)
elseif rand < 0.05 * (1-humidityfactor) then
df_primordial_items.spawn_jungle_tree_vm(math.random(8,14), vi+ystride, area, data)
elseif rand < 0.3 then
data[vi+ystride] = jungle_plants[math.random(1,#jungle_plants)]
end
if c_fireflies and math.random() < 0.01 then
local firefly_vi = vi + ystride * math.random(1, 5)
if data[firefly_vi] == c_air then
data[firefly_vi] = c_fireflies
minetest.get_node_timer(area:position(firefly_vi)):start(1)
end
end
end
local jungle_cavern_ceiling = function(abs_cracks, vi, area, data, data_param2)
if abs_cracks < 0.25 then
data[vi] = c_glowstone
elseif abs_cracks > 0.75 and math.random() < 0.1 then
local ystride = area.ystride
data[vi] = c_dirt
local index = vi - ystride
local hanging_node
if math.random() < 0.5 then
hanging_node = c_ivy
else
hanging_node = c_root_2
end
for i = 1, math.random(16) do
if data[index] == c_air then
data[index] = hanging_node
index = index - ystride
else
break
end
end
end
end
local jungle_warren_ceiling = function(abs_cracks, vi, area, data, data_param2)
if abs_cracks < 0.1 then
data[vi] = c_glowstone
elseif abs_cracks > 0.75 and math.random() < 0.1 then
local ystride = area.ystride
data[vi] = c_dirt
local index = vi - ystride
local hanging_node
if math.random() < 0.5 then
hanging_node = c_root_1
else
hanging_node = c_root_2
end
for i = 1, math.random(8) do
if data[index] == c_air then
data[index] = hanging_node
index = index - ystride
else
break
end
end
end
end
local jungle_warren_floor = function(abs_cracks, vi, area, data, data_param2)
local ystride = area.ystride
if abs_cracks < 0.7 then
data[vi] = c_jungle_dirt
local rand = math.random() * abs_cracks
if rand < 0.1 then
data[vi+ystride] = jungle_plants[math.random(1,#jungle_plants)]
end
elseif abs_cracks < 1 then
data[vi] = c_dirt
end
if c_fireflies and math.random() < 0.005 then
local firefly_vi = vi + ystride * math.random(1, 5)
if data[firefly_vi] == c_air then
data[firefly_vi] = c_fireflies
minetest.get_node_timer(area:position(firefly_vi)):start(1)
end
end
end
---------------------------------------------------------------------------------------------------------
local decorate_primordial = function(minp, maxp, seed, vm, node_arrays, area, data)
math.randomseed(minp.x + minp.y*2^8 + minp.z*2^16 + seed) -- make decorations consistent between runs
local data_param2 = df_caverns.data_param2
vm:get_param2_data(data_param2)
local nvals_cracks = mapgen_helper.perlin2d("df_cavern:cracks", minp, maxp, df_caverns.np_cracks)
local cave_area = node_arrays.cave_area
local nvals_cave = node_arrays.nvals_cave
local humiditymap = minetest.get_mapgen_object("humiditymap")
---------------------------------------------------------
-- Cavern floors
for _, vi in ipairs(node_arrays.cavern_floor_nodes) do
local index2d = mapgen_helper.index2di(minp, maxp, area, vi)
local cracks = nvals_cracks[index2d]
local abs_cracks = math.abs(cracks)
local humidity = humiditymap[index2d]
local jungle = nvals_cave[vi] < 0
if jungle then
jungle_cavern_floor(abs_cracks, humidity, vi, area, data, data_param2)
else
mushroom_cavern_floor(abs_cracks, humidity, vi, area, data, data_param2)
if log_location then log_location("primordial_mushrooms", area:position(vi)) end
end
end
--------------------------------------
-- Cavern ceilings
for _, vi in ipairs(node_arrays.cavern_ceiling_nodes) do
local index2d = mapgen_helper.index2di(minp, maxp, area, vi)
local cracks = nvals_cracks[index2d]
local abs_cracks = math.abs(cracks)
local jungle = nvals_cave[vi] < 0
local humidity = humiditymap[index2d]
if jungle then
jungle_cavern_ceiling(abs_cracks, vi, area, data, data_param2)
else
mushroom_cavern_ceiling(abs_cracks, humidity, vi, area, data, data_param2)
end
end
----------------------------------------------
-- Tunnel floors
-- for _, vi in ipairs(node_arrays.tunnel_floor_nodes) do
-- end
------------------------------------------------------
-- Tunnel ceiling
-- for _, vi in ipairs(node_arrays.tunnel_ceiling_nodes) do
-- end
------------------------------------------------------
-- Warren ceiling
for _, vi in ipairs(node_arrays.warren_ceiling_nodes) do
local index2d = mapgen_helper.index2di(minp, maxp, area, vi)
local cracks = nvals_cracks[index2d]
local abs_cracks = math.abs(cracks)
local jungle = nvals_cave[vi] < 0
if jungle then
jungle_warren_ceiling(abs_cracks, vi, area, data, data_param2)
else
mushroom_warren_ceiling(abs_cracks, vi, area, data, data_param2)
end
end
----------------------------------------------
-- Warren floors
for _, vi in ipairs(node_arrays.warren_floor_nodes) do
local index2d = mapgen_helper.index2di(minp, maxp, area, vi)
local cracks = nvals_cracks[index2d]
local abs_cracks = math.abs(cracks)
local jungle = nvals_cave[vi] < 0
if jungle then
jungle_warren_floor(abs_cracks, vi, area, data, data_param2)
if log_location then log_location("primordial_jungle_warren", area:position(vi)) end
else
mushroom_warren_floor(abs_cracks, vi, area, data, data_param2)
if log_location then log_location("primordial_mushroom_warren", area:position(vi)) end
end
end
-- columns
-- no flowstone below the Sunless Sea, replace with something else
local random_dir = {1, -1, area.zstride, -area.zstride}
for _, vi in ipairs(node_arrays.column_nodes) do
local jungle = nvals_cave[vi] < 0
if jungle then
data[vi] = c_plant_matter
minetest.get_node_timer(area:position(vi)):start(math.random(30, 120))
else
data[vi] = c_mycelial_dirt
if math.random() < 0.05 then
local rand_vi = vi + random_dir[math.random(1,4)]
if data[rand_vi] == c_air then
data[rand_vi] = c_giant_mycelium
minetest.get_node_timer(area:position(rand_vi)):start(math.random(1,giant_mycelium_timer_spread))
end
end
end
end
vm:set_param2_data(data_param2)
end
--Primordial Caverns
subterrane.register_layer({
name = "primordial",
y_max = df_caverns.config.primordial_max,
y_min = df_caverns.config.primordial_min,
cave_threshold = df_caverns.config.sunless_sea_threshold, -- Make the caves a bit bigger than above
perlin_cave = perlin_cave_primordial,
perlin_wave = perlin_wave_primordial,
solidify_lava = true,
columns = {
maximum_radius = 20,
minimum_radius = 5,
node = df_dependencies.node_name_stone, -- no flowstone below the Sunless Sea, replace with something else
weight = 0.5,
maximum_count = 60,
minimum_count = 10,
},
decorate = decorate_primordial,
double_frequency = true,
is_ground_content = df_caverns.is_ground_content,
})
minetest.register_ore({
ore_type = "vein",
ore = "df_underworld_items:glowstone",
wherein = {
"default:stone",
"default:stone_with_coal",
"default:stone_with_iron",
"default:stone_with_copper",
"default:stone_with_tin",
"default:stone_with_gold",
"default:stone_with_diamond",
"default:dirt",
"default:sand",
"default:desert_sand",
"default:silver_sand",
"default:gravel",
},
column_height_min = 2,
column_height_max = 6,
y_min = df_caverns.config.primordial_min,
y_max = df_caverns.config.primordial_max,
noise_threshold = 0.9,
noise_params = {
offset = 0,
scale = 3,
spread = {x=400, y=400, z=400},
seed = 25111,
octaves = 4,
persist = 0.5,
flags = "eased",
},
random_factor = 0,
})
-- Rather than make plants farmable, have them randomly respawn in jungle soil. You can only get them down there by foraging, not farming.
minetest.register_abm({
label = "Primordial plant growth",
nodenames = {"df_primordial_items:dirt_with_jungle_grass"},
neighbors = {"air"},
interval = 60.0,
chance = 50,
action = function(pos, node, active_object_count, active_object_count_wider)
if minetest.find_node_near(pos, 2, {"group:primordial_jungle_plant"}) == nil then
local pos_above = {x=pos.x, y=pos.y+1, z=pos.z}
local node_above = minetest.get_node(pos_above)
if node_above.name == "air" then
minetest.set_node(pos_above, {name = jungle_plant_names[math.random(1,#jungle_plant_names)]})
end
end
end,
})
minetest.register_abm({
label = "Primordial fungus growth",
nodenames = {"df_primordial_items:dirt_with_mycelium"},
neighbors = {"air"},
interval = 60.0,
chance = 50,
action = function(pos, node, active_object_count, active_object_count_wider)
if minetest.find_node_near(pos, 3, {"group:primordial_fungal_plant"}) == nil then
local pos_above = {x=pos.x, y=pos.y+1, z=pos.z}
local node_above = minetest.get_node(pos_above)
if node_above.name == "air" then
minetest.set_node(pos_above, {name = fungal_plant_names[math.random(1,#fungal_plant_names)]})
end
end
end,
})
-- an ABM to extinguish fires on the primordial layer. Glowstone next to plant life equals too much fire.
local fire_enabled = minetest.settings:get_bool("enable_fire")
if fire_enabled == nil then
-- enable_fire setting not specified, check for disable_fire
local fire_disabled = minetest.settings:get_bool("disable_fire")
if fire_disabled == nil then
-- Neither setting specified, check whether singleplayer
fire_enabled = minetest.is_singleplayer()
else
fire_enabled = not fire_disabled
end
end
if fire_enabled and minetest.get_modpath("fire") then
local primordial_min = df_caverns.config.primordial_min
local primordial_max = df_caverns.config.primordial_max
minetest.register_abm({
label = "Remove fire in the primordial layer",
nodenames = {"fire:basic_flame"},
--neighbors = {"fire:basic_flame"},
interval = 3,
chance = 3,
catch_up = false,
action = function(pos)
local pos_y = pos.y
if pos_y > primordial_min and pos_y < primordial_max then
minetest.remove_node(pos)
end
end
})
end
@@ -0,0 +1,49 @@
local n1 = { name = "df_underworld_items:slade_block", force_place=true }
local n2 = { name = df_dependencies.node_name_stair_outer_slade_brick, param2 = 1, force_place=true }
local n3 = { name = df_dependencies.node_name_stair_slade_brick, force_place=true }
local n4 = { name = df_dependencies.node_name_stair_outer_slade_brick, force_place=true }
local n5 = { name = "air", force_place=true }
local n6 = { name = "df_underworld_items:slade_seal", force_place=true }
local n7 = { name = df_dependencies.node_name_stair_slade_brick, param2 = 1, force_place=true }
local n8 = { name = "df_underworld_items:slade_brick", force_place=true }
local n9 = { name = df_dependencies.node_name_stair_slade_brick, param2 = 3, force_place=true }
local n10 = { name = "df_underworld_items:slade_wall", force_place=true }
local n11 = { name = "df_underworld_items:ancient_lantern_slade_worn", prob=192 } -- 50% chance of being force-placed
local n12 = { name = df_dependencies.node_name_stair_outer_slade_brick, param2 = 2, force_place=true }
local n13 = { name = df_dependencies.node_name_stair_slade_brick, param2 = 2, force_place=true }
local n14 = { name = df_dependencies.node_name_stair_outer_slade_brick, param2 = 3, force_place=true }
return {
name = "df_caverns:lamppost",
size = {x = 3, y = 15, z = 3},
center_pos = {x = 1, y = 7, z = 1},
data = {
n1, n1, n1, n1, n1, n1, n1, n1, n1,
n1, n1, n1, n1, n1, n1, n1, n1, n1,
n1, n1, n1, n1, n1, n1, n2, n3, n4,
n5, n5, n5,
n5, n5, n5,
n5, n5, n5,
n5, n5, n5,
n5, n11, n5,
n5, n5, n5,
n1, n1, n1, n1, n5, n1, n1, n5, n1,
n1, n5, n1, n1, n5, n1, n1, n5, n1,
n1, n5, n1, n1, n6, n1, n7, n8, n9,
n5, n8, n5,
n5, n8, n5,
n5, n10, n5,
n5, n10, n5,
n11, n10, n11,
n5, n5, n5,
n1, n1, n1, n1, n1, n1, n1, n1, n1,
n1, n1, n1, n1, n1, n1, n1, n1, n1,
n1, n1, n1, n1, n1, n1, n12, n13, n14,
n5, n5, n5,
n5, n5, n5,
n5, n5, n5,
n5, n5, n5,
n5, n11, n5,
n5, n5, n5,
}
}
@@ -0,0 +1,115 @@
local n1 = { name = "ignore"}
local n8 = { name = "air", force_place=true }
local n3 = { name = "df_underworld_items:slade_brick", force_place=true }
local n4 = { name = "df_underworld_items:slade_wall", force_place=true }
local n5 = { name = df_dependencies.node_name_stair_outer_slade_brick, param2 = 1, force_place=true }
local n6 = { name = df_dependencies.node_name_stair_slade_brick, force_place=true }
local n7 = { name = df_dependencies.node_name_stair_outer_slade_brick, force_place=true }
local n9 = { name = df_dependencies.node_name_slab_slade_brick, param2 = 23, force_place=true }
local n10 = { name = df_dependencies.node_name_stair_slade_brick, param2 = 1, force_place=true }
local n11 = { name = df_dependencies.node_name_stair_slade_brick, param2 = 3, force_place=true }
local n14 = { name = df_dependencies.node_name_stair_slade_brick, param2 = 23, force_place=true }
local n15 = { name = df_dependencies.node_name_stair_outer_slade_brick, param2 = 2, force_place=true }
local n16 = { name = df_dependencies.node_name_stair_slade_brick, param2 = 2, force_place=true }
local n17 = { name = df_dependencies.node_name_stair_outer_slade_brick, param2 = 3, force_place=true }
-- foundation nodes
local n2 = { name = "df_underworld_items:slade_brick", force_place=false, place_on_condition=mapgen_helper.buildable_to }
local n12 = { name = "df_underworld_items:slade_wall", force_place=false, place_on_condition=mapgen_helper.buildable_to }
local n13 = { name = df_dependencies.node_name_stair_slade_brick, param2 = 1, force_place=false, place_on_condition=mapgen_helper.buildable_to }
return {
name = "df_caverns:medium_building",
size = {x = 15, y = 12, z = 8},
center_pos = {x = 10, y = 6, z = 3},
data = {
n1, n1, n1, n1, n1, n1, n1, n2, n2, n2, n2, n2, n2, n2, n2, n1, n1,
n1, n1, n1, n1, n1, n2, n2, n2, n2, n2, n2, n2, n2, n1, n1, n1, n1,
n1, n1, n1, n2, n2, n2, n2, n2, n2, n2, n2, n1, n1, n1, n1, n1, n1,
n1, n2, n2, n2, n2, n2, n2, n2, n2, n1, n1, n1, n1, n1, n1, n1, n2,
n2, n2, n2, n2, n2, n2, n2, n1, n1, n1, n1, n1, n1, n1, n3, n3, n3,
n3, n3, n3, n3, n3, n1, n1, n1, n1, n1, n1, n1, n3, n4, n4, n4, n4,
n4, n4, n3, n1, n1, n1, n1, n1, n1, n1, n3, n4, n4, n4, n4, n4, n4,
n3, n1, n1, n1, n1, n1, n1, n1, n3, n3, n3, n3, n3, n3, n3, n3, n1,
n1, n1, n1, n1, n1, n1, n3, n4, n4, n4, n4, n4, n4, n3, n1, n1, n1,
n1, n1, n1, n1, n3, n4, n4, n4, n4, n4, n4, n3, n1, n1, n1, n1, n1,
n1, n1, n5, n6, n6, n6, n6, n6, n6, n7, n1, n1, n1, n1, n1, n1, n1,
n2, n2, n2, n2, n2, n2, n2, n2, n1, n1, n1, n1, n1, n1, n1, n2, n2,
n2, n2, n2, n2, n2, n2, n1, n1, n1, n1, n1, n1, n1, n2, n2, n2, n2,
n2, n2, n2, n2, n1, n1, n1, n1, n1, n1, n1, n2, n2, n2, n2, n2, n2,
n2, n2, n1, n1, n1, n1, n1, n1, n1, n2, n2, n2, n2, n2, n2, n2, n2,
n1, n1, n1, n1, n1, n1, n1, n3, n3, n3, n3, n3, n3, n3, n3, n1, n1,
n1, n1, n1, n1, n8, n4, n8, n8, n8, n8, n8, n8, n4, n1, n1, n1, n1,
n1, n1, n8, n4, n8, n8, n8, n8, n8, n8, n4, n1, n1, n1, n1, n1, n1,
n1, n3, n9, n9, n9, n9, n9, n9, n3, n1, n1, n1, n1, n1, n1, n1, n4,
n8, n8, n8, n8, n8, n8, n4, n1, n1, n1, n1, n1, n1, n1, n4, n8, n8,
n8, n8, n8, n8, n4, n1, n1, n1, n1, n1, n1, n1, n10, n9, n9, n9, n9,
n9, n9, n11, n12, n12, n2, n2, n2, n2, n2, n2, n2, n2, n2, n2, n2,
n2, n2, n1, n12, n12, n2, n2, n2, n2, n2, n2, n2, n2, n2, n2, n2, n2,
n1, n1, n12, n12, n2, n2, n2, n2, n2, n2, n2, n2, n2, n2, n2, n1, n1,
n1, n12, n12, n2, n2, n2, n2, n2, n2, n2, n2, n2, n2, n1, n1, n1, n1,
n12, n12, n2, n2, n2, n2, n2, n2, n2, n2, n2, n1, n1, n1, n1, n1,
n12, n12, n3, n3, n3, n3, n3, n3, n3, n3, n1, n1, n1, n1, n1, n1,
n12, n3, n8, n8, n8, n8, n8, n8, n4, n1, n1, n1, n1, n1, n1, n8, n3,
n8, n8, n8, n8, n8, n8, n4, n1, n1, n1, n1, n1, n1, n1, n3, n9, n9,
n9, n9, n9, n9, n3, n1, n1, n1, n1, n1, n1, n1, n4, n8, n8, n8, n8,
n8, n8, n4, n1, n1, n1, n1, n1, n1, n1, n4, n8, n8, n8, n8, n8, n8,
n4, n1, n1, n1, n1, n1, n1, n1, n10, n9, n9, n9, n9, n9, n9, n11, n1,
n13, n2, n2, n2, n2, n2, n2, n2, n2, n2, n2, n2, n2, n2, n1, n1, n13,
n2, n2, n2, n2, n2, n2, n2, n2, n2, n2, n2, n2, n1, n1, n1, n13, n2,
n2, n2, n2, n2, n2, n2, n2, n2, n2, n2, n1, n1, n1, n1, n13, n2, n2,
n2, n2, n2, n2, n2, n2, n2, n2, n1, n1, n1, n1, n1, n13, n2, n2, n2,
n2, n2, n2, n2, n2, n2, n1, n1, n1, n1, n1, n1, n13, n3, n3, n3, n3,
n3, n3, n3, n3, n1, n1, n1, n1, n1, n1, n8, n8, n8, n8, n8, n8, n8,
n8, n4, n1, n1, n1, n1, n1, n1, n8, n8, n8, n8, n8, n8, n8, n8, n4,
n1, n1, n1, n1, n1, n1, n1, n3, n9, n9, n9, n9, n9, n9, n3, n1, n1,
n1, n1, n1, n1, n1, n4, n8, n8, n8, n8, n8, n8, n4, n1, n1, n1, n1,
n1, n1, n1, n4, n8, n8, n8, n8, n8, n8, n4, n1, n1, n1, n1, n1, n1,
n1, n10, n9, n9, n9, n9, n9, n9, n11, n1, n13, n2, n2, n2, n2, n2,
n2, n2, n2, n2, n2, n2, n2, n2, n1, n1, n13, n2, n2, n2, n2, n2, n2,
n2, n2, n2, n2, n2, n2, n1, n1, n1, n13, n2, n2, n2, n2, n2, n2, n2,
n2, n2, n2, n2, n1, n1, n1, n1, n13, n2, n2, n2, n2, n2, n2, n2, n2,
n2, n2, n1, n1, n1, n1, n1, n13, n2, n2, n2, n2, n2, n2, n2, n2, n2,
n1, n1, n1, n1, n1, n1, n13, n3, n3, n3, n3, n3, n3, n3, n3, n1, n1,
n1, n1, n1, n1, n8, n8, n8, n8, n8, n8, n8, n8, n4, n1, n1, n1, n1,
n1, n1, n8, n8, n8, n8, n8, n8, n8, n8, n4, n1, n1, n1, n1, n1, n1,
n1, n3, n9, n9, n9, n9, n9, n9, n3, n1, n1, n1, n1, n1, n1, n1, n4,
n8, n8, n8, n8, n8, n8, n4, n1, n1, n1, n1, n1, n1, n1, n4, n8, n8,
n8, n8, n8, n8, n4, n1, n1, n1, n1, n1, n1, n1, n10, n9, n9, n9, n9,
n9, n9, n11, n12, n12, n2, n2, n2, n2, n2, n2, n2, n2, n2, n2, n2,
n2, n2, n1, n12, n12, n2, n2, n2, n2, n2, n2, n2, n2, n2, n2, n2, n2,
n1, n1, n12, n12, n2, n2, n2, n2, n2, n2, n2, n2, n2, n2, n2, n1, n1,
n1, n12, n12, n2, n2, n2, n2, n2, n2, n2, n2, n2, n2, n1, n1, n1, n1,
n12, n12, n12, n2, n2, n2, n2, n2, n2, n2, n2, n1, n1, n1, n1, n1,
n12, n12, n3, n3, n3, n3, n3, n3, n3, n3, n1, n1, n1, n1, n1, n1,
n12, n3, n8, n8, n8, n8, n8, n8, n4, n1, n1, n1, n1, n1, n1, n8, n3,
n8, n8, n8, n8, n8, n8, n4, n1, n1, n1, n1, n1, n1, n1, n3, n9, n9,
n9, n9, n9, n9, n3, n1, n1, n1, n1, n1, n1, n1, n4, n8, n8, n8, n8,
n8, n8, n4, n1, n1, n1, n1, n1, n1, n1, n4, n8, n8, n8, n8, n8, n8,
n4, n1, n1, n1, n1, n1, n1, n1, n10, n9, n9, n9, n9, n9, n9, n11, n1,
n1, n1, n1, n1, n1, n1, n2, n2, n2, n2, n2, n2, n2, n2, n1, n1, n1,
n1, n1, n1, n1, n2, n2, n2, n2, n2, n2, n2, n2, n1, n1, n1, n1, n1,
n1, n1, n2, n2, n2, n2, n2, n2, n2, n2, n1, n1, n1, n1, n1, n1, n1,
n2, n2, n2, n2, n2, n2, n2, n2, n1, n1, n1, n1, n1, n1, n1, n2, n2,
n2, n2, n2, n2, n2, n2, n1, n1, n1, n1, n1, n1, n1, n3, n3, n3, n3,
n3, n3, n3, n3, n1, n1, n1, n1, n1, n1, n8, n4, n8, n8, n14, n11, n8,
n8, n4, n1, n1, n1, n1, n1, n1, n8, n4, n8, n14, n11, n8, n8, n8, n4,
n1, n1, n1, n1, n1, n1, n1, n3, n14, n11, n8, n8, n8, n9, n3, n1, n1,
n1, n1, n1, n1, n1, n4, n8, n8, n8, n8, n8, n8, n4, n1, n1, n1, n1,
n1, n1, n1, n4, n8, n8, n8, n8, n8, n8, n4, n1, n1, n1, n1, n1, n1,
n1, n10, n9, n9, n9, n9, n9, n9, n11, n1, n1, n1, n1, n1, n1, n1, n2,
n2, n2, n2, n2, n2, n2, n2, n1, n1, n1, n1, n1, n1, n1, n2, n2, n2,
n2, n2, n2, n2, n2, n1, n1, n1, n1, n1, n1, n1, n2, n2, n2, n2, n2,
n2, n2, n2, n1, n1, n1, n1, n1, n1, n1, n2, n2, n2, n2, n2, n2, n2,
n2, n1, n1, n1, n1, n1, n1, n1, n2, n2, n2, n2, n2, n2, n2, n2, n1,
n1, n1, n1, n1, n1, n1, n3, n3, n3, n3, n3, n3, n3, n3, n1, n1, n1,
n1, n1, n1, n1, n3, n4, n4, n4, n4, n4, n4, n3, n1, n1, n1, n1, n1,
n1, n1, n3, n4, n4, n4, n4, n4, n4, n3, n1, n1, n1, n1, n1, n1, n1,
n3, n3, n3, n3, n3, n3, n3, n3, n1, n1, n1, n1, n1, n1, n1, n3, n4,
n4, n4, n4, n4, n4, n3, n1, n1, n1, n1, n1, n1, n1, n3, n4, n4, n4,
n4, n4, n4, n3, n1, n1, n1, n1, n1, n1, n1, n15, n16, n16, n16, n16,
n16, n16, n17,
}
}
@@ -0,0 +1,24 @@
local n1 = { name = "df_underworld_items:slade_block", force_place=true }
local n2 = { name = df_dependencies.node_name_stair_outer_slade_brick, param2 = 1, force_place=true }
local n3 = { name = df_dependencies.node_name_stair_slade_brick, force_place=true }
local n4 = { name = df_dependencies.node_name_stair_outer_slade_brick, force_place=true }
local n5 = { name = "air", force_place=true }
local n6 = { name = "df_underworld_items:slade_seal", force_place=true }
local n7 = { name = df_dependencies.node_name_stair_slade_brick, param2 = 1, force_place=true }
local n8 = { name = df_dependencies.node_name_stair_slade_brick, param2 = 3, force_place=true }
local n9 = { name = df_dependencies.node_name_stair_outer_slade_brick, param2 = 2, force_place=true }
local n10 = { name = df_dependencies.node_name_stair_slade_brick, param2 = 2, force_place=true }
local n11 = { name = df_dependencies.node_name_stair_outer_slade_brick, param2 = 3, force_place=true }
return {
name="df_caverns:oubliette",
size = {x = 3, y = 9, z = 3},
center_pos = {x = 1, y = 7, z = 1},
data = {
n1, n1, n1, n1, n1, n1, n1, n1, n1, n1, n1, n1, n1, n1, n1, n1, n1,
n1, n1, n1, n1, n1, n1, n1, n2, n3, n4, n1, n1, n1, n1, n5, n1, n1,
n5, n1, n1, n5, n1, n1, n5, n1, n1, n5, n1, n1, n5, n1, n1, n6, n1,
n7, n5, n8, n1, n1, n1, n1, n1, n1, n1, n1, n1, n1, n1, n1, n1, n1,
n1, n1, n1, n1, n1, n1, n1, n1, n1, n1, n9, n10, n11,
},
}
@@ -0,0 +1,74 @@
local n1 = { name = "ignore" }
local n10 = { name = "air", force_place=true }
local n3 = { name = "df_underworld_items:slade_brick", force_place=true }
local n4 = { name = "df_underworld_items:slade_wall", force_place=true }
local n5 = { name = df_dependencies.node_name_stair_outer_slade_brick, param2 = 1, force_place=true }
local n6 = { name = df_dependencies.node_name_stair_slade_brick, force_place=true }
local n7 = { name = df_dependencies.node_name_stair_outer_slade_brick, force_place=true }
local n11 = { name = df_dependencies.node_name_stair_slade_brick, param2 = 1, force_place=true }
local n12 = { name = df_dependencies.node_name_slab_slade_brick, param2 = 22, force_place=true}
local n13 = { name = df_dependencies.node_name_stair_slade_brick, param2 = 3, force_place=true }
local n15 = { name = df_dependencies.node_name_stair_outer_slade_brick, param2 = 2, force_place=true }
local n16 = { name = df_dependencies.node_name_stair_slade_brick, param2 = 2, force_place=true }
local n17 = { name = df_dependencies.node_name_stair_outer_slade_brick, param2 = 3, force_place=true }
-- foundation nodes
local n2 = { name = "df_underworld_items:slade_brick", force_place=false, place_on_condition=mapgen_helper.buildable_to }
local n8 = { name = df_dependencies.node_name_stair_slade_brick, param2 = 2, force_place=false, place_on_condition=mapgen_helper.buildable_to }
local n9 = { name = df_dependencies.node_name_stair_slade_brick, force_place=false, place_on_condition=mapgen_helper.buildable_to }
local n14 = { name = df_dependencies.node_name_stair_slade_brick, param2 = 1, force_place=false, place_on_condition=mapgen_helper.buildable_to }
local n18 = { name = "df_underworld_items:puzzle_chest_closed", param2 = 1, prob=192 } -- 50% chance of being force-placed.
return {
name = "df_caverns:small_building",
size = {x = 11, y = 9, z = 7},
center_pos = {x = 7, y = 5, z = 3},
data = {
n1, n1, n2, n2, n2, n2, n2, n2, n2, n2, n2, n1, n1, n2, n2, n2, n2,
n2, n2, n2, n2, n2, n1, n1, n2, n2, n2, n2, n2, n2, n2, n2, n2, n1,
n1, n2, n2, n2, n2, n2, n2, n2, n2, n2, n1, n1, n1, n1, n2, n2, n2,
n2, n2, n2, n2, n1, n1, n1, n1, n3, n3, n3, n3, n3, n3, n3, n1, n1,
n1, n1, n3, n4, n4, n4, n4, n4, n3, n1, n1, n1, n1, n3, n4, n4, n4,
n4, n4, n3, n1, n1, n1, n1, n5, n6, n6, n6, n6, n6, n7, n1, n1, n2,
n2, n2, n2, n2, n2, n2, n2, n2, n1, n1, n2, n2, n2, n2, n2, n2, n2,
n2, n2, n1, n1, n2, n2, n2, n2, n2, n2, n2, n2, n2, n1, n1, n8, n2,
n2, n2, n2, n2, n2, n2, n2, n1, n1, n1, n9, n2, n2, n2, n2, n2, n2,
n2, n1, n1, n1, n1, n3, n3, n3, n3, n3, n3, n3, n1, n1, n1, n10, n4,
n10, n10, n10, n10, n10, n4, n1, n1, n1, n10, n4, n10, n10, n10, n10,
n10, n4, n1, n1, n1, n1, n11, n12, n12, n12, n12, n12, n13, n1, n1,
n2, n2, n2, n2, n2, n2, n2, n2, n2, n1, n1, n2, n2, n2, n2, n2, n2,
n2, n2, n2, n1, n1, n8, n2, n2, n2, n2, n2, n2, n2, n2, n1, n1, n1,
n2, n2, n2, n2, n2, n2, n2, n2, n1, n1, n1, n2, n2, n2, n2, n2, n2,
n2, n2, n1, n1, n1, n9, n3, n3, n3, n3, n3, n3, n3, n1, n1, n1, n10,
n3, n10, n10, n10, n10, n10, n4, n1, n1, n1, n10, n3, n10, n10, n10,
n10, n10, n4, n1, n1, n1, n1, n11, n12, n12, n12, n12, n12, n13, n14,
n2, n2, n2, n2, n2, n2, n2, n2, n2, n2, n1, n14, n2, n2, n2, n2, n2,
n2, n2, n2, n2, n1, n1, n1, n2, n2, n2, n2, n2, n2, n2, n2, n1, n1,
n1, n2, n2, n2, n2, n2, n2, n2, n2, n1, n1, n1, n2, n2, n2, n2, n2,
n2, n2, n2, n1, n1, n1, n2, n3, n3, n3, n3, n3, n3, n3, n1, n1, n1,
n10, n10, n10, n10, n10, n10, n18, n4, n1, n1, n1, n10, n10, n10,
n10, n10, n10, n10, n4, n1, n1, n1, n1, n11, n12, n12, n12, n12, n12,
n13, n1, n1, n2, n2, n2, n2, n2, n2, n2, n2, n2, n1, n1, n2, n2, n2,
n2, n2, n2, n2, n2, n2, n1, n1, n9, n2, n2, n2, n2, n2, n2, n2, n2,
n1, n1, n1, n2, n2, n2, n2, n2, n2, n2, n2, n1, n1, n1, n2, n2, n2,
n2, n2, n2, n2, n2, n1, n1, n1, n8, n3, n3, n3, n3, n3, n3, n3, n1,
n1, n1, n10, n3, n10, n10, n10, n10, n10, n4, n1, n1, n1, n10, n3,
n10, n10, n10, n10, n10, n4, n1, n1, n1, n1, n11, n12, n12, n12, n12,
n12, n13, n1, n1, n2, n2, n2, n2, n2, n2, n2, n2, n2, n1, n1, n2, n2,
n2, n2, n2, n2, n2, n2, n2, n1, n1, n2, n2, n2, n2, n2, n2, n2, n2,
n2, n1, n1, n9, n2, n2, n2, n2, n2, n2, n2, n2, n1, n1, n1, n8, n2,
n2, n2, n2, n2, n2, n2, n1, n1, n1, n1, n3, n3, n3, n3, n3, n3, n3,
n1, n1, n1, n10, n4, n10, n10, n10, n10, n10, n4, n1, n1, n1, n10,
n4, n10, n10, n10, n10, n10, n4, n1, n1, n1, n1, n11, n12, n12, n12,
n12, n12, n13, n1, n1, n2, n2, n2, n2, n2, n2, n2, n2, n2, n1, n1,
n2, n2, n2, n2, n2, n2, n2, n2, n2, n1, n1, n2, n2, n2, n2, n2, n2,
n2, n2, n2, n1, n1, n2, n2, n2, n2, n2, n2, n2, n2, n2, n1, n1, n1,
n1, n2, n2, n2, n2, n2, n2, n2, n1, n1, n1, n1, n3, n3, n3, n3, n3,
n3, n3, n1, n1, n1, n1, n3, n4, n4, n4, n4, n4, n3, n1, n1, n1, n1,
n3, n4, n4, n4, n4, n4, n3, n1, n1, n1, n1, n15, n16, n16, n16, n16,
n16, n17,
}
}
@@ -0,0 +1,16 @@
local n1 = { name = "df_underworld_items:slade_brick", force_place=false, place_on_condition=mapgen_helper.buildable_to }
local n2 = { name = df_dependencies.node_name_stair_inner_slade_brick, param2 = 1, force_place=true }
local n3 = { name = df_dependencies.node_name_stair_inner_slade_brick, force_place=true }
local n4 = { name = "df_underworld_items:slade_brick", force_place=true }
local n5 = { name = df_dependencies.node_name_stair_inner_slade_brick, param2 = 2, force_place=true }
local n6 = { name = df_dependencies.node_name_stair_inner_slade_brick, param2 = 3, force_place=true }
return {
name = "df_caverns:small_slab",
size = {y = 2, x = 2, z = 3},
center_pos = {x = 1, y = 1, z = 1},
data = {
n1, n1, n2, n3, n1, n1, n4, n4, n1, n1, n5, n6,
}
}
Binary file not shown.

After

Width:  |  Height:  |  Size: 27 KiB

Binary file not shown.

After

Width:  |  Height:  |  Size: 37 KiB

Binary file not shown.

After

Width:  |  Height:  |  Size: 20 KiB

Binary file not shown.

After

Width:  |  Height:  |  Size: 22 KiB

Binary file not shown.

After

Width:  |  Height:  |  Size: 54 KiB

Binary file not shown.

After

Width:  |  Height:  |  Size: 47 KiB

Binary file not shown.

After

Width:  |  Height:  |  Size: 27 KiB

Binary file not shown.

After

Width:  |  Height:  |  Size: 33 KiB

Binary file not shown.

After

Width:  |  Height:  |  Size: 47 KiB

Binary file not shown.

After

Width:  |  Height:  |  Size: 54 KiB

Binary file not shown.

After

Width:  |  Height:  |  Size: 146 KiB

Binary file not shown.

After

Width:  |  Height:  |  Size: 20 KiB

Binary file not shown.

After

Width:  |  Height:  |  Size: 21 KiB

Binary file not shown.

After

Width:  |  Height:  |  Size: 15 KiB

Binary file not shown.

After

Width:  |  Height:  |  Size: 45 KiB

Binary file not shown.

After

Width:  |  Height:  |  Size: 76 KiB

Binary file not shown.

After

Width:  |  Height:  |  Size: 56 KiB

Binary file not shown.

After

Width:  |  Height:  |  Size: 26 KiB

Binary file not shown.

After

Width:  |  Height:  |  Size: 46 KiB

Binary file not shown.

After

Width:  |  Height:  |  Size: 35 KiB

Binary file not shown.

After

Width:  |  Height:  |  Size: 30 KiB

Binary file not shown.

After

Width:  |  Height:  |  Size: 50 KiB

Binary file not shown.

After

Width:  |  Height:  |  Size: 40 KiB

+296
View File
@@ -0,0 +1,296 @@
-- This file contains code that is used by multiple different cavern layers.
local c_air = df_caverns.node_id.air
local c_cobble = df_caverns.node_id.cobble
local c_cobble_fungus = df_caverns.node_id.cobble_fungus
local c_cobble_fungus_fine = df_caverns.node_id.cobble_fungus_fine
local c_dead_fungus = df_caverns.node_id.dead_fungus
local c_dirt = df_caverns.node_id.dirt
local c_dirt_moss = df_caverns.node_id.dirt_moss
local c_dry_flowstone = df_caverns.node_id.dry_flowstone
local c_fireflies = df_caverns.node_id.fireflies
local c_glowstone = df_caverns.node_id.glowstone
local c_ice = df_caverns.node_id.ice
local c_mossycobble = df_caverns.node_id.mossycobble
local c_oil = df_caverns.node_id.oil
local c_sand_scum = df_caverns.node_id.sand_scum
local c_spongestone = df_caverns.node_id.spongestone
local c_rock_rot = df_caverns.node_id.rock_rot
local c_water = df_caverns.node_id.water
local c_wet_flowstone = df_caverns.node_id.wet_flowstone
local c_webs = df_caverns.node_id.big_webs
local c_webs_egg = df_caverns.node_id.big_webs_egg
df_caverns.data_param2 = {} -- shared among all mapgens to reduce memory clutter
local get_biome_at_pos_list = {} -- a list of methods of the form function(pos, heat, humidity) to allow modpack-wide queries about what should grow where
df_caverns.register_biome_check = function(func)
table.insert(get_biome_at_pos_list, func)
end
df_caverns.get_biome = function(pos)
pos = vector.round(pos)
local heat = minetest.get_heat(pos)
local humidity = minetest.get_humidity(pos)
for _, val in pairs(get_biome_at_pos_list) do
local biome = val(pos, heat, humidity)
if biome ~= nil then
return biome
end
end
end
-- for testing
--local debug_timer = 0
--minetest.register_globalstep(function(dtime)
-- debug_timer = debug_timer + dtime
-- if debug_timer > 5 then
-- local singleplayer = minetest.get_player_by_name("singleplayer")
-- if singleplayer then
-- minetest.debug(df_caverns.get_biome(singleplayer:get_pos()))
-- end
-- debug_timer = debug_timer - 5
-- end
--end)
-- prevent mapgen from using these nodes as a base for stalactites or stalagmites
local dont_build_speleothems_on = {}
for _, content_id in pairs(df_mapitems.wet_stalagmite_ids) do
dont_build_speleothems_on[content_id] = true
end
for _, content_id in pairs(df_mapitems.dry_stalagmite_ids) do
dont_build_speleothems_on[content_id] = true
end
if minetest.get_modpath("big_webs") then
dont_build_speleothems_on[c_webs] = true
dont_build_speleothems_on[c_webs_egg] = true
end
--------------------------------------------------
df_caverns.stalagmites = function(abs_cracks, vert_rand, vi, area, data, data_param2, wet, reverse_sign)
if dont_build_speleothems_on[data[vi]] then
return
end
local flowstone
local stalagmite_ids
if wet then
flowstone = c_wet_flowstone
stalagmite_ids = df_mapitems.wet_stalagmite_ids
else
flowstone = c_dry_flowstone
stalagmite_ids = df_mapitems.dry_stalagmite_ids
end
local height_mult = 1
local ystride = area.ystride
if reverse_sign then
ystride = - ystride
height_mult = -1
end
if vert_rand < 0.004 then
if reverse_sign then
subterrane.big_stalactite(vi+ystride, area, data, 6, 15, flowstone, flowstone, flowstone)
else
subterrane.big_stalagmite(vi+ystride, area, data, 6, 15, flowstone, flowstone, flowstone)
end
else
local param2 = abs_cracks*1000000 - math.floor(abs_cracks*1000000/4)*4
local height = math.floor(abs_cracks * 50)
subterrane.stalagmite(vi+ystride, area, data, data_param2, param2, height*height_mult, stalagmite_ids)
end
data[vi] = flowstone
end
df_caverns.stalactites = function(abs_cracks, vert_rand, vi, area, data, data_param2, wet)
df_caverns.stalagmites(abs_cracks, vert_rand, vi, area, data, data_param2, wet, true)
end
--------------------------------------------------
df_caverns.flooded_cavern_floor = function(abs_cracks, vert_rand, vi, area, data)
local ystride = area.ystride
if abs_cracks < 0.25 then
data[vi] = c_mossycobble
elseif data[vi-ystride] ~= c_water then
data[vi] = c_sand_scum
end
-- put in only the large stalagmites that won't get in the way of the water
if abs_cracks < 0.1 then
if vert_rand < 0.004 then
subterrane.big_stalagmite(vi+ystride, area, data, 6, 15, c_wet_flowstone, c_wet_flowstone, c_wet_flowstone)
end
end
end
df_caverns.dry_cavern_floor = function(abs_cracks, vert_rand, vi, area, data, data_param2)
if abs_cracks < 0.075 then
df_caverns.stalagmites(abs_cracks, vert_rand, vi, area, data, data_param2, false)
elseif abs_cracks < 0.4 then
data[vi] = c_cobble
elseif abs_cracks < 0.6 then
data[vi] = c_cobble_fungus_fine
else
data[vi] = c_cobble_fungus
if c_dead_fungus and math.random() < 0.05 then
data[vi+area.ystride] = c_dead_fungus
end
end
end
df_caverns.wet_cavern_floor = function(abs_cracks, vert_rand, vi, area, data, data_param2)
if abs_cracks < 0.1 then
df_caverns.stalagmites(abs_cracks, vert_rand, vi, area, data, data_param2, true)
elseif abs_cracks < 0.6 then
data[vi] = c_cobble
elseif abs_cracks < 0.8 then
data[vi] = c_rock_rot
else
data[vi] = c_spongestone
if c_dead_fungus and math.random() < 0.05 then
data[vi+area.ystride] = c_dead_fungus
end
end
end
--------------------------------------
df_caverns.glow_worm_cavern_ceiling = function(abs_cracks, vert_rand, vi, area, data, data_param2)
if abs_cracks < 0.1 then
df_caverns.stalactites(abs_cracks, vert_rand, vi, area, data, data_param2, true)
elseif abs_cracks < 0.5 and abs_cracks > 0.3 and math.random() < 0.3 then
df_mapitems.glow_worm_ceiling(area, data, vi-area.ystride)
end
end
df_caverns.tunnel_floor = function(minp, maxp, area, vi, nvals_cracks, data, data_param2, wet, dirt_node)
if maxp.y > -30 then
wet = false
end
local ystride = area.ystride
local index2d = mapgen_helper.index2di(minp, maxp, area, vi)
local cracks = nvals_cracks[index2d]
local abs_cracks = math.abs(cracks)
if wet then
if abs_cracks < 0.05 and data[vi+ystride] == c_air and not dont_build_speleothems_on[data[vi]] then -- make sure data[vi] is not already flowstone. Stalagmites from lower levels are acting as base for further stalagmites
local param2 = abs_cracks*1000000 - math.floor(abs_cracks*1000000/4)*4
local height = math.floor(abs_cracks * 100)
subterrane.stalagmite(vi+ystride, area, data, data_param2, param2, height, df_mapitems.wet_stalagmite_ids)
data[vi] = c_wet_flowstone
elseif dirt_node and abs_cracks > 0.5 and data[vi-ystride] ~= c_air then
data[vi] = dirt_node
end
else
if abs_cracks < 0.025 and data[vi+ystride] == c_air and not dont_build_speleothems_on[data[vi]] then -- make sure data[vi] is not already flowstone. Stalagmites from lower levels are acting as base for further stalagmites
local param2 = abs_cracks*1000000 - math.floor(abs_cracks*1000000/4)*4
local height = math.floor(abs_cracks * 100)
subterrane.stalagmite(vi+ystride, area, data, data_param2, param2, height, df_mapitems.dry_stalagmite_ids)
elseif dirt_node and cracks > 0.5 and data[vi-ystride] ~= c_air then
data[vi] = dirt_node
end
end
end
df_caverns.tunnel_ceiling = function(minp, maxp, area, vi, nvals_cracks, data, data_param2, wet)
if maxp.y > -30 then
wet = false
end
local ystride = area.ystride
local index2d = mapgen_helper.index2di(minp, maxp, area, vi)
local cracks = nvals_cracks[index2d]
local abs_cracks = math.abs(cracks)
if wet then
if abs_cracks < 0.05 and data[vi-ystride] == c_air and not dont_build_speleothems_on[data[vi]] then -- make sure data[vi] is not already flowstone. Stalagmites from lower levels are acting as base for further stalagmites
local param2 = abs_cracks*1000000 - math.floor(abs_cracks*1000000/4)*4
local height = math.floor(abs_cracks * 100)
subterrane.stalactite(vi-ystride, area, data, data_param2, param2, height, df_mapitems.wet_stalagmite_ids)
data[vi] = c_wet_flowstone
end
else
if abs_cracks < 0.025 and data[vi-ystride] == c_air and not dont_build_speleothems_on[data[vi]] then -- make sure data[vi] is not already flowstone. Stalagmites from lower levels are acting as base for further stalagmites
local param2 = abs_cracks*1000000 - math.floor(abs_cracks*1000000/4)*4
local height = math.floor(abs_cracks * 100)
subterrane.stalactite(vi-ystride, area, data, data_param2, param2, height, df_mapitems.dry_stalagmite_ids)
end
end
end
df_caverns.perlin_cave = {
offset = 0,
scale = 1,
spread = {x=df_caverns.config.horizontal_cavern_scale, y=df_caverns.config.vertical_cavern_scale, z=df_caverns.config.horizontal_cavern_scale},
seed = -400000000089,
octaves = 3,
persist = 0.67
}
df_caverns.perlin_wave = {
offset = 0,
scale = 1,
spread = {x=df_caverns.config.horizontal_cavern_scale * 2, y=df_caverns.config.vertical_cavern_scale, z=df_caverns.config.horizontal_cavern_scale * 2}, -- squashed 2:1
seed = 59033,
octaves = 6,
persist = 0.63
}
-- Used for making lines of dripstone, and in various other places where small-scale patterns are needed
df_caverns.np_cracks = {
offset = 0,
scale = 1,
spread = {x = 20, y = 20, z = 20},
seed = 5717,
octaves = 3,
persist = 0.63,
lacunarity = 2.0,
}
---------------------------------------------------------------------------------
df_caverns.place_shrub = function(vi, area, data, param2_data, shrub_list)
if shrub_list == nil then
return
end
local shrub = shrub_list[math.random(#shrub_list)]
shrub(vi, area, data, param2_data)
end
---------------------------------------------------------------------------------
-- This method allows subterrane to overgenerate caves without destroying any of the decorations
local dfcaverns_nodes = nil
local dfcaverns_mods = {
"df_farming:",
"df_mapitems:",
"df_primordial_items:",
"df_trees:",
"df_underworld_items:",
"ice_sprites:",
"mine_gas:",
}
df_caverns.is_ground_content = function(c_node)
if dfcaverns_nodes then
return not dfcaverns_nodes[c_node]
end
dfcaverns_nodes = {}
for k, v in pairs(minetest.registered_nodes) do
for _, prefix in ipairs(dfcaverns_mods) do
if k:sub(1, #prefix) == prefix then
dfcaverns_nodes[minetest.get_content_id(k)] = true
end
end
end
dfcaverns_nodes[c_ice] = true -- needed for nethercap cavern water covering
dfcaverns_nodes[c_oil] = true -- needed for blackcap oil slicks
if c_fireflies then
dfcaverns_nodes[c_fireflies] = true -- used in the primordial caverns
end
dfcaverns_nodes[c_glowstone] = nil
dfcaverns_mods = nil
return not dfcaverns_nodes[c_node]
end
+454
View File
@@ -0,0 +1,454 @@
local c_water = df_caverns.node_id.water
local c_air = df_caverns.node_id.air
local c_dirt = df_caverns.node_id.dirt
local c_dirt_moss = df_caverns.node_id.dirt_moss
local c_sand = df_caverns.node_id.sand
local c_gravel = df_caverns.node_id.gravel
local c_wet_flowstone = df_caverns.node_id.wet_flowstone
local c_dry_flowstone = df_caverns.node_id.dry_flowstone
local c_lava = df_caverns.node_id.lava
local c_obsidian = df_caverns.node_id.obsidian
local chasms_path = minetest.get_modpath("chasms")
local log_location
if mapgen_helper.log_location_enabled then
log_location = mapgen_helper.log_first_location
end
local c_coral_table = {}
for node_name, node_def in pairs(minetest.registered_nodes) do
if minetest.get_item_group(node_name, "dfcaverns_cave_coral") > 0 then
table.insert(c_coral_table, minetest.get_content_id(node_name))
end
end
local towergoblin_shrublist
local fungispore_shrublist
if minetest.get_modpath("df_farming") then
towergoblin_shrublist = {
df_farming.spawn_plump_helmet_vm,
df_farming.spawn_plump_helmet_vm,
df_farming.spawn_dimple_cup_vm,
df_farming.spawn_dead_fungus_vm,
df_farming.spawn_cavern_fungi_vm,
}
fungispore_shrublist = {
df_farming.spawn_pig_tail_vm,
df_farming.spawn_sweet_pod_vm,
df_farming.spawn_cave_wheat_vm,
df_farming.spawn_cave_wheat_vm,
df_farming.spawn_dead_fungus_vm,
df_farming.spawn_cavern_fungi_vm,
}
end
------------------------------------------------------------------------------------------
local perlin_cave_sunless_sea = {
offset = 0,
scale = 1,
spread = {x=df_caverns.config.horizontal_cavern_scale * 2, y=df_caverns.config.vertical_cavern_scale * 0.5, z=df_caverns.config.horizontal_cavern_scale * 2},
seed = -400000000089,
octaves = 3,
persist = 0.67
}
local perlin_wave_sunless_sea = {
offset = 0,
scale = 1,
spread = {x=df_caverns.config.horizontal_cavern_scale * 4, y=df_caverns.config.vertical_cavern_scale * 0.5, z=df_caverns.config.horizontal_cavern_scale * 4}, -- squashed 2:1
seed = 59033,
octaves = 6,
persist = 0.63
}
local perlin_cave_rivers = {
offset = 0,
scale = 1,
spread = {x=400, y=400, z=400},
seed = -400000000089,
octaves = 3,
persist = 0.67,
flags = "", -- remove "eased" flag, makes the paths of rivers a bit jaggedier and more interesting that curvy smooth paths
}
-- large-scale rise and fall to make the seam between roof and floor less razor-flat and make the rivers shallower and deeper in various places
local perlin_wave_rivers = {
offset = 0,
scale = 1,
spread = {x=800, y=800, z=800},
seed = -4000089,
octaves = 3,
persist = 0.67,
}
local sea_level = df_caverns.config.level3_min - (df_caverns.config.level3_min - df_caverns.config.sunless_sea_min) * 0.5
local floor_mult = 100
local floor_displace = -10
local ceiling_mult = -200
local ceiling_displace = 20
local wave_mult = 7
local ripple_mult = 15
local y_max_river = sea_level + 2*wave_mult + ceiling_displace + ripple_mult
local y_min_river = sea_level - 2*wave_mult + floor_displace
local hot_zone_boundary = 70
local middle_zone_boundary = 50
local cool_zone_boundary = 30
df_caverns.register_biome_check(function(pos, heat, humidity)
if pos.y < df_caverns.config.sunless_sea_min or pos.y >= df_caverns.config.level3_min then
return nil
end
if pos.y < sea_level then
return "sunless undersea"
elseif heat > hot_zone_boundary then
return "barren" -- hot zone
elseif heat > middle_zone_boundary then
return "fungispore"
elseif heat > cool_zone_boundary then
return "towergoblin"
else
return "barren" -- cool zone
end
end)
local towergoblin_cavern_floor = function(abs_cracks, vert_rand, vi, area, data, data_param2)
local ystride = area.ystride
if abs_cracks < 0.1 then
df_caverns.stalagmites(abs_cracks, vert_rand, vi, area, data, data_param2, true)
elseif data[vi-ystride] ~= c_air and data[vi-ystride] ~= c_water then -- leave the ground as rock if it's only one node thick
if math.random() < 0.25 then
data[vi] = c_dirt
else
data[vi] = c_dirt_moss
end
if math.random() < 0.1 then
df_caverns.place_shrub(vi+ystride, area, data, data_param2, towergoblin_shrublist)
elseif abs_cracks > 0.25 then
if math.random() < 0.01 then
df_trees.spawn_tower_cap_vm(vi+ystride, area, data)
elseif math.random() < 0.01 then
df_trees.spawn_goblin_cap_vm(vi+ystride, area, data, data_param2)
elseif math.random() < 0.02 then
df_trees.spawn_spindlestem_vm(vi+ystride, area, data, data_param2)
end
end
end
end
local fungispore_cavern_floor = function(abs_cracks, vert_rand, vi, area, data, data_param2)
local ystride = area.ystride
if abs_cracks < 0.1 then
df_caverns.stalagmites(abs_cracks, vert_rand, vi, area, data, data_param2, true)
elseif data[vi-ystride] ~= c_air and data[vi-ystride] ~= c_water then -- leave the ground as rock if it's only one node thick
if math.random() < 0.25 then
data[vi] = c_dirt
else
data[vi] = c_dirt_moss
end
if math.random() < 0.1 then
df_caverns.place_shrub(vi+ystride, area, data, data_param2, fungispore_shrublist)
elseif abs_cracks > 0.35 then
if math.random() < 0.025 then
df_trees.spawn_fungiwood_vm(vi+ystride, area, data)
elseif math.random() < 0.025 then
df_trees.spawn_spore_tree_vm(vi+ystride, area, data, data_param2)
end
end
end
end
local cool_zone_ceiling = function(abs_cracks, vert_rand, vi, area, data, data_param2)
if abs_cracks < 0.1 then
df_caverns.stalactites(abs_cracks, vert_rand, vi, area, data, data_param2, false)
end
end
local hot_zone_ceiling = function(abs_cracks, vert_rand, vi, area, data, data_param2)
-- dry zone ceiling, add crystals
if abs_cracks < 0.1 then
df_caverns.stalactites(abs_cracks, vert_rand, vi, area, data, data_param2, false)
end
if abs_cracks > 0.3 and math.random() < 0.005 then
df_mapitems.place_big_crystal_cluster(area, data, data_param2, vi, math.random(0,3), true)
end
end
local cool_zone_floor = df_caverns.dry_cavern_floor
local hot_zone_floor = function(abs_cracks, vert_rand, vi, area, data, data_param2)
if abs_cracks < 0.075 then
df_caverns.stalagmites(abs_cracks, vert_rand, vi, area, data, data_param2, false)
elseif abs_cracks > 0.3 and math.random() < 0.005 then
df_mapitems.place_big_crystal_cluster(area, data, data_param2, vi+area.ystride, math.random(0,2), false)
end
end
local decorate_sunless_sea = function(minp, maxp, seed, vm, node_arrays, area, data)
math.randomseed(minp.x + minp.y*2^8 + minp.z*2^16 + seed) -- make decorations consistent between runs
local heatmap = minetest.get_mapgen_object("heatmap")
local data_param2 = df_caverns.data_param2
vm:get_param2_data(data_param2)
local nvals_cracks = mapgen_helper.perlin2d("df_cavern:cracks", minp, maxp, df_caverns.np_cracks)
local minp_below = minp.y <= sea_level
local maxp_above = maxp.y > sea_level
local nvals_cave = mapgen_helper.perlin2d("df_caverns:sunless_sea", minp, maxp, perlin_cave_rivers) --cave noise for structure
local nvals_wave = mapgen_helper.perlin2d("df_caverns:sunless_sea_wave", minp, maxp, perlin_wave_rivers) --cave noise for structure
local skip_next = false -- mapgen is proceeding upward on the y axis,
--if this is true it skips a step to allow for things to be placed above the floor
-- creates "river" caverns
for vi, x, y, z in area:iterp_yxz(minp, maxp) do
if not skip_next then
if y < y_max_river and y > y_min_river then
local index2d = mapgen_helper.index2d(minp, maxp, x, z)
local abs_cave = math.abs(nvals_cave[index2d])
local wave = nvals_wave[index2d] * wave_mult
local cracks = nvals_cracks[index2d]
local ripple = cracks * ((y - y_min_river) / (y_max_river - y_min_river)) * ripple_mult
-- above floor and below ceiling
local floor_height = math.floor(abs_cave * floor_mult + sea_level + floor_displace + wave)
local ceiling_height = math.floor(abs_cave * ceiling_mult + sea_level + ceiling_displace + wave + ripple)
-- deal with lava
if y <= floor_height and y > floor_height - 3 and y < sea_level + 5 and data[vi] == c_lava then
data[vi] = c_obsidian
end
if y == floor_height and y < sea_level and not mapgen_helper.buildable_to(data[vi]) then
if cracks > 0.2 then
data[vi] = c_sand
if cracks > 0.5 then
data[vi+area.ystride] = c_sand
skip_next = true
end
else
data[vi] = c_gravel
end
elseif y > floor_height and y < ceiling_height and data[vi] ~= c_wet_flowstone then
data[vi] = c_air
if log_location then log_location("sunless_sea_river", vector.new(x,y,z)) end
elseif y == ceiling_height and not mapgen_helper.buildable_to(data[vi]) then
df_caverns.glow_worm_cavern_ceiling(math.abs(cracks),
mapgen_helper.xz_consistent_randomi(area, vi), vi, area, data, data_param2)
end
-- Deal with lava
if y >= ceiling_height and y < ceiling_height + 5 and y > sea_level - 5 and data[vi] == c_lava then
data[vi] = c_obsidian
end
end
else
skip_next = false
end
end
if minp.y <= sea_level then
for vi, x, y, z in area:iterp_yxz(area.MinEdge, area.MaxEdge) do
-- convert all air below sea level into water
if y <= sea_level and data[vi] == c_air then
data[vi] = c_water
end
end
end
---------------------------------------------------------
-- Cavern floors
for _, vi in ipairs(node_arrays.cavern_floor_nodes) do
local index2d = mapgen_helper.index2di(minp, maxp, area, vi)
local heat = heatmap[index2d]
local cracks = nvals_cracks[index2d]
local abs_cracks = math.abs(cracks)
local vert_rand = mapgen_helper.xz_consistent_randomi(area, vi)
local y = area:get_y(vi)
-- The vertically squished aspect of these caverns produces too many very thin shelves, this blunts them
if mapgen_helper.buildable_to(data[vi-area.ystride]) then
if y <= sea_level then
data[vi] = c_water
else
data[vi] = c_air
end
end
-- extra test is needed because the rivers can remove nodes that Subterrane marked as floor.
if not mapgen_helper.buildable_to(data[vi]) then
if y >= sea_level then
if heat > hot_zone_boundary then
hot_zone_floor(abs_cracks, vert_rand, vi, area, data, data_param2)
if log_location then log_location("sunless_sea_hot", area:position(vi)) end
elseif heat > middle_zone_boundary then
fungispore_cavern_floor(abs_cracks, vert_rand, vi, area, data, data_param2)
if log_location then log_location("sunless_sea_fungispore", area:position(vi)) end
elseif heat > cool_zone_boundary then
towergoblin_cavern_floor(abs_cracks, vert_rand, vi, area, data, data_param2)
if log_location then log_location("sunless_sea_towergoblin", area:position(vi)) end
else
cool_zone_floor(abs_cracks, vert_rand, vi, area, data, data_param2)
if log_location then log_location("sunless_sea_cool", area:position(vi)) end
end
elseif y >= sea_level - 30 then
if math.random() < 0.005 then
df_mapitems.place_snareweed_patch(area, data, vi, data_param2, 6)
else
data[vi] = c_dirt
end
else
data[vi] = c_sand
if math.random() < 0.001 then
local iterations = math.random(1, 6)
df_mapitems.spawn_coral_pile(area, data, vi, iterations)
df_mapitems.spawn_castle_coral(area, data, vi+area.ystride, iterations)
if log_location then log_location("sunless_sea_castle_coral", area:position(vi)) end
end
end
end
end
--------------------------------------
-- Cavern ceilings
for _, vi in ipairs(node_arrays.cavern_ceiling_nodes) do
local index2d = mapgen_helper.index2di(minp, maxp, area, vi)
local heat = heatmap[index2d]
local cracks = nvals_cracks[index2d]
local abs_cracks = math.abs(cracks)
local vert_rand = mapgen_helper.xz_consistent_randomi(area, vi)
local y = area:get_y(vi)
if y > sea_level and not mapgen_helper.buildable_to(data[vi]) then
if heat > hot_zone_boundary then
hot_zone_ceiling(abs_cracks, vert_rand, vi, area, data, data_param2)
elseif heat > cool_zone_boundary then
df_caverns.glow_worm_cavern_ceiling(abs_cracks, vert_rand, vi, area, data, data_param2)
else
cool_zone_ceiling(abs_cracks, vert_rand, vi, area, data, data_param2)
end
end
end
----------------------------------------------
-- Tunnel floors
for _, vi in ipairs(node_arrays.tunnel_floor_nodes) do
if area:get_y(vi) >= sea_level and not mapgen_helper.buildable_to(data[vi]) then
df_caverns.tunnel_floor(minp, maxp, area, vi, nvals_cracks, data, data_param2, true)
end
end
------------------------------------------------------
-- Tunnel ceiling
for _, vi in ipairs(node_arrays.tunnel_ceiling_nodes) do
if area:get_y(vi) > sea_level and not mapgen_helper.buildable_to(data[vi]) then
df_caverns.tunnel_ceiling(minp, maxp, area, vi, nvals_cracks, data, data_param2, true)
else
-- air pockets
local index2d = mapgen_helper.index2di(minp, maxp, area, vi)
local cracks = nvals_cracks[index2d]
local ystride = area.ystride
if cracks > 0.6 and data[vi-ystride] == c_water then
data[vi-ystride] = c_air
if cracks > 0.8 and data[vi-ystride*2] == c_water then
data[vi-ystride*2] = c_air
end
end
end
end
------------------------------------------------------
-- Warren ceiling
for _, vi in ipairs(node_arrays.warren_ceiling_nodes) do
if area:get_y(vi) > sea_level and not mapgen_helper.buildable_to(data[vi]) then
df_caverns.tunnel_ceiling(minp, maxp, area, vi, nvals_cracks, data, data_param2, true)
else
-- air pockets
local index2d = mapgen_helper.index2di(minp, maxp, area, vi)
local cracks = nvals_cracks[index2d]
local ystride = area.ystride
if cracks > 0.6 and data[vi-ystride] == c_water then
data[vi-ystride] = c_air
if cracks > 0.8 and data[vi-ystride*2] == c_water then
data[vi-ystride*2] = c_air
end
end
end
end
----------------------------------------------
-- Warren floors
for _, vi in ipairs(node_arrays.warren_floor_nodes) do
if area:get_y(vi) >= sea_level and not mapgen_helper.buildable_to(data[vi]) then
df_caverns.tunnel_floor(minp, maxp, area, vi, nvals_cracks, data, data_param2, true)
if log_location then log_location("sunless_sea_warren", area:position(vi)) end
end
end
-- columns
for _, vi in ipairs(node_arrays.column_nodes) do
if data[vi] == c_wet_flowstone then
if area:get_y(vi) > sea_level then
local index2d = mapgen_helper.index2di(minp, maxp, area, vi)
local heat = heatmap[index2d]
if heat > hot_zone_boundary then
data[vi] = c_dry_flowstone
end
else
data[vi] = c_coral_table[math.random(1,3)]
data_param2[vi] = math.random(1,4)-1
minetest.get_node_timer(area:position(vi)):start(math.random(10, 60))
end
if chasms_path then
local pos = area:position(vi)
if chasms.is_in_chasm(pos) then
if pos.y <= sea_level then
data[vi] = c_water
else
data[vi] = c_air
end
end
end
end
end
vm:set_param2_data(data_param2)
end
--Sunless Sea
subterrane.register_layer({
name = "sunless sea",
y_max = df_caverns.config.level3_min-1,
y_min = df_caverns.config.sunless_sea_min,
cave_threshold = df_caverns.config.sunless_sea_threshold,
perlin_cave = perlin_cave_sunless_sea,
perlin_wave = perlin_wave_sunless_sea,
solidify_lava = true,
columns = {
maximum_radius = 20,
minimum_radius = 5,
node = "df_mapitems:wet_flowstone",
weight = 0.5,
maximum_count = 60,
minimum_count = 10,
},
decorate = decorate_sunless_sea,
double_frequency = false,
is_ground_content = df_caverns.is_ground_content,
})
@@ -0,0 +1,87 @@
-- surface tunnels
local y_max = 200
local y_min = df_caverns.config.ymax
local c_stone = df_caverns.node_id.stone
local c_air = df_caverns.node_id.air
minetest.register_on_generated(function(minp, maxp, seed)
--if out of range of cave definition limits, abort
if minp.y > y_max or maxp.y < y_min then
return
end
local t_start = os.clock()
local vm, data, data_param2, area = mapgen_helper.mapgen_vm_data_param2()
local data_changed = false
local eminp = {x=minp.x, y=area.MinEdge.y, z=minp.z}
local emaxp = {x=maxp.x, y=area.MaxEdge.y, z=maxp.z}
local minp_y = minp.y
local maxp_y = maxp.y
local humiditymap = minetest.get_mapgen_object("humiditymap")
local nvals_cracks = mapgen_helper.perlin2d("df_cavern:cracks", minp, maxp, df_caverns.np_cracks)
local previous_y = eminp.y-1
local previous_potential_floor_vi
local previous_potential_floor_y
local previous_node
for vi, x, y, z in area:iterp_yxz(eminp, emaxp) do
if y < previous_y then
-- we've started a new column, initialize everything
previous_potential_floor_vi = nil
previous_potential_floor_y = nil
previous_node = nil
end
previous_y = y
local current_node = data[vi]
if previous_node and y < y_max then
if current_node == c_air and previous_node == c_stone then
-- this may be a floor, but only if we eventually hit a ceiling in this column
previous_potential_floor_vi = vi-area.ystride
previous_potential_floor_y = y-1
elseif current_node == c_stone and previous_node == c_air and previous_potential_floor_vi then
-- we hit a ceiling after passing through a floor
local index2d = mapgen_helper.index2d(minp, maxp, x, z)
local humidity = humiditymap[index2d]
if previous_potential_floor_y <= maxp_y and previous_potential_floor_y >= minp_y then
data_changed = true
df_caverns.tunnel_floor(minp, maxp, area, previous_potential_floor_vi, nvals_cracks, data, data_param2, humidity > 30)
end
if y <= maxp_y and y >= minp_y then
data_changed = true
df_caverns.tunnel_ceiling(minp, maxp, area, vi, nvals_cracks, data, data_param2, humidity > 30)
end
previous_potential_floor_vi = nil
elseif not mapgen_helper.buildable_to(current_node) then
-- we've entered a non-stone ceiling of some kind. Abort potential floor-ceiling pair detection.
previous_potential_floor_vi = nil
end
end
previous_node = current_node
end
if data_changed then
--send data back to voxelmanip
vm:set_data(data)
vm:set_param2_data(data_param2)
--calc lighting
vm:set_lighting({day = 0, night = 0})
vm:calc_lighting()
vm:update_liquids()
--write it to world
vm:write_to_map()
end
local time_taken = os.clock() - t_start -- how long this chunk took, in seconds
mapgen_helper.record_time("df_caverns surface tunnels", time_taken)
end)
+628
View File
@@ -0,0 +1,628 @@
if not df_caverns.config.enable_underworld or not minetest.get_modpath("df_underworld_items") then
return
end
local modname = minetest.get_current_modname()
local modpath = minetest.get_modpath(modname)
local S = minetest.get_translator(modname)
local bones_loot_path = minetest.get_modpath("bones_loot")
local bones_node = df_dependencies.node_name_bones
local named_waypoints_path = minetest.get_modpath("named_waypoints")
local name_generator_path = minetest.get_modpath("name_generator")
local hunters_enabled = minetest.get_modpath("hunter_statue") and df_underworld_items.config.underworld_hunter_statues
local log_location
if mapgen_helper.log_location_enabled then
log_location = mapgen_helper.log_first_location
end
-- Exposed as a global so that other mods can override it.
df_caverns.populate_puzzle_chest = function(pos)
local meta = minetest.get_meta(pos)
local inv = meta:get_inventory()
for i = 1, math.random(1,8) do
local item = ItemStack(df_underworld_items.colour_items[math.random(1,#df_underworld_items.colour_items)])
--item:set_count(math.random(1,4))
inv:add_item("main", item)
end
end
local name_pit = function() end
local name_ruin = function() end
if named_waypoints_path then
local item_required = nil
if minetest.settings:get_bool("dfcaverns_underworld_hud_requires_item", true) then
local setting_item_required = minetest.settings:get("dfcaverns_underworld_hud_item_required")
if setting_item_required == nil or setting_item_required == "" then
setting_item_required = "map:mapping_kit"
end
item_required = setting_item_required
end
local pit_waypoint_def = {
default_name = S("A glowing pit"),
default_color = 0xFF88FF,
discovery_volume_radius = tonumber(minetest.settings:get("dfcaverns_pit_discovery_range")) or 60,
visibility_requires_item = item_required,
}
if minetest.settings:get_bool("dfcaverns_show_pits_in_hud", true) then
pit_waypoint_def.visibility_volume_radius = tonumber(minetest.settings:get("dfcaverns_pit_visibility_range")) or 500
pit_waypoint_def.on_discovery = named_waypoints.default_discovery_popup
end
named_waypoints.register_named_waypoints("glowing_pits", pit_waypoint_def)
local seal_waypoint_def = {
default_name = S("Mysterious seal"),
default_color = 0x9C2233,
discovery_volume_radius = tonumber(minetest.settings:get("dfcaverns_seal_discovery_range")) or 10,
visibility_requires_item = item_required,
}
if minetest.settings:get_bool("dfcaverns_show_seals_in_hud", true) then
seal_waypoint_def.visibility_volume_radius = tonumber(minetest.settings:get("dfcaverns_seal_visibility_range")) or 200
seal_waypoint_def.on_discovery = named_waypoints.default_discovery_popup
end
named_waypoints.register_named_waypoints("puzzle_seals", seal_waypoint_def)
if name_generator_path then
name_generator.parse_lines(io.lines(modpath.."/underworld_names.cfg"))
name_pit = function()
return name_generator.generate("glowing_pits")
end
name_ruin = function()
return name_generator.generate("underworld_ruins")
end
local underworld_ruin_def = {
default_name = S("Ancient ruin"),
discovery_volume_radius = tonumber(minetest.settings:get("dfcaverns_ruin_discovery_range")) or 40,
visibility_requires_item = item_required,
}
if minetest.settings:get_bool("dfcaverns_show_ruins_in_hud", true) then
underworld_ruin_def.visibility_volume_radius = tonumber(minetest.settings:get("dfcaverns_ruin_visibility_range")) or 250
underworld_ruin_def.on_discovery = named_waypoints.default_discovery_popup
end
named_waypoints.register_named_waypoints("underworld_ruins", underworld_ruin_def)
end
end
local c_slade = df_caverns.node_id.slade
local c_slade_block = df_caverns.node_id.slade_block
local c_air = df_caverns.node_id.air
local c_water = df_caverns.node_id.water
local c_glowstone = df_caverns.node_id.glowstone
local c_amethyst = df_caverns.node_id.amethyst
local c_pit_plasma = df_caverns.node_id.pit_plasma
local MP = minetest.get_modpath(minetest.get_current_modname())
local oubliette_schematic = dofile(MP.."/schematics/oubliette.lua")
local lamppost_schematic = dofile(MP.."/schematics/lamppost.lua")
local small_slab_schematic = dofile(MP.."/schematics/small_slab.lua")
local small_building_schematic = dofile(MP.."/schematics/small_building.lua")
local medium_building_schematic = dofile(MP.."/schematics/medium_building.lua")
local perlin_cave = {
offset = 0,
scale = 1,
spread = {x=200, y=200, z=200},
seed = 88233498,
octaves = 6,
persist = 0.67
}
-- large-scale rise and fall to make the seam between stone and slade less razor-flat
local perlin_wave = {
offset = 0,
scale = 1,
spread = {x=1000, y=1000, z=1000},
seed = 993455,
octaves = 3,
persist = 0.67
}
-- building zones
local perlin_zone = {
offset = 0,
scale = 1,
spread = {x=500, y=500, z=500},
seed = 199422,
octaves = 3,
persist = 0.67
}
local median = df_caverns.config.underworld_level
local floor_mult = 20
local floor_displace = -10
local ceiling_mult = -40
local ceiling_displace = 20
local wave_mult = 50
local y_max = median + 2*wave_mult + ceiling_displace + -2*ceiling_mult
local y_min = median - 2*wave_mult + floor_displace - 2*floor_mult
--df_caverns.config.underworld_min = y_min
--local poisson = mapgen_helper.get_poisson_points({x=-32000, z=-32000}, {x=32000, z=32000}, 1000)
--minetest.debug(dump(poisson.objects))
---------------------------------------------------------
-- Buildings
local oubliette_threshold = 0.8
local town_threshold = 1.1
local local_random = function(x, z)
local next_seed = math.floor(math.random()*2^21)
math.randomseed(x + z*2^16)
local ret = math.random()
math.randomseed(next_seed)
return ret
end
-- create a deterministic list of buildings
local get_buildings = function(emin, emax, nvals_zone)
local buildings = {}
for x = emin.x, emax.x do
for z = emin.z, emax.z do
local index2d = mapgen_helper.index2d(emin, emax, x, z)
local zone = math.abs(nvals_zone[index2d])
if zone > oubliette_threshold and zone < town_threshold then
-- oubliette zone
--zone = (zone - oubliette_threshold)/(town_threshold-oubliette_threshold) -- turn this into a 0-1 spread
local building_val = local_random(x, z)
if building_val > 0.98 then
building_val = (building_val - 0.98)/0.02
local building_type
if building_val < 0.8 then
building_type = "oubliette"
elseif building_val < 0.9 then
building_type = "open oubliette"
else
building_type = "lamppost"
end
table.insert(buildings,
{
pos = {x=x, y=0, z=z}, -- y to be determined later
building_type = building_type,
bounding_box = {minpos={x=x-2, z=z-2}, maxpos={x=x+2, z=z+2}},
priority = math.floor(building_val * 10000000) % 1000, -- indended to allow for deterministic removal of overlapping buildings
}
)
end
elseif zone > town_threshold then
-- town zone
local building_val = local_random(x, z)
if building_val > 0.9925 then
building_val = (building_val - 0.9925)/0.0075
local building_type
local bounding_box
local priority = math.floor(building_val * 10000000) % 1000
local rotation = (priority % 4) * 90
if building_val < 0.75 then
building_type = "small building"
local boundmin, boundmax = mapgen_helper.get_schematic_bounding_box({x=x, y=0, z=z}, small_building_schematic, rotation)
bounding_box = {minpos=boundmin, maxpos=boundmax}
elseif building_val < 0.85 then
building_type = "medium building"
local boundmin, boundmax = mapgen_helper.get_schematic_bounding_box({x=x, y=0, z=z}, medium_building_schematic, rotation)
bounding_box = {minpos=boundmin, maxpos=boundmax}
else
building_type = "small slab"
local boundmin, boundmax = mapgen_helper.get_schematic_bounding_box({x=x, y=0, z=z}, small_slab_schematic, rotation)
bounding_box = {minpos=boundmin, maxpos=boundmax}
end
table.insert(buildings,
{
pos = {x=x, y=0, z=z}, -- y to be determined later
building_type = building_type,
bounding_box = bounding_box,
rotation = rotation,
priority = priority, -- indended to allow for deterministic removal of overlapping buildings
}
)
end
end
end
end
-- eliminate overlapping buildings
local building_count = table.getn(buildings)
local overlap_count = 0
for i = 1, building_count-1 do
local curr_building = buildings[i]
for j = i+1, building_count do
local test_building = buildings[j]
if test_building ~= nil and curr_building ~= nil and mapgen_helper.intersect_exists_xz(
curr_building.bounding_box.minpos,
curr_building.bounding_box.maxpos,
test_building.bounding_box.minpos,
test_building.bounding_box.maxpos) then
if curr_building.priority < test_building.priority then -- this makes elimination of overlapping buildings deterministic
buildings[i] = nil
j=building_count+1
else
buildings[j] = nil
end
overlap_count = overlap_count + 1
end
end
end
if building_count > 50 and overlap_count > building_count * 2/3 then
minetest.log("warning", "[df_caverns] underworld mapgen generated " ..
tostring(building_count) .. " buildings and " .. tostring(overlap_count) ..
" were eliminated as overlapping, if this happens a lot consider reducing building" ..
" generation probability to improve efficiency.")
end
local compacted_buildings = {}
for _, building in pairs(buildings) do
compacted_buildings[minetest.hash_node_position(building.pos)] = building
end
return compacted_buildings
end
-----------------------------------------------------------
-- Pits
local radius_pit_max = 40 -- won't actually be this wide, there'll be crystal spires around it
local radius_pit_variance = 10
local plasma_depth_min = 5
local plasma_depth_max = 75
local region_mapblocks = df_caverns.config.underworld_glowing_pit_mapblocks -- One glowing pit in each region this size
local mapgen_chunksize = tonumber(minetest.get_mapgen_setting("chunksize"))
local pit_region_size = region_mapblocks * mapgen_chunksize * 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 mapgen_seed = tonumber(minetest.get_mapgen_setting("seed")) % 2^21
local get_pit = function(pos)
if region_mapblocks < 1 then return nil end
local corner_xz = get_corner(pos)
local next_seed = math.floor(math.random() * 2^21)
math.randomseed(corner_xz.x + corner_xz.z * 2 ^ 8 + mapgen_seed)
local location = scatter_2d(corner_xz, pit_region_size, radius_pit_max + radius_pit_variance)
local variance_multiplier = math.random()
local radius = variance_multiplier * (radius_pit_max - 15) + 15
local variance = radius_pit_variance/2 + radius_pit_variance*variance_multiplier/2
local depth = math.random(plasma_depth_min, plasma_depth_max)
math.randomseed(next_seed)
return {location = location, radius = radius, variance = variance, depth = depth}
end
df_caverns.get_nearest_glowing_pit = get_pit
local perlin_pit = {
offset = 0,
scale = 1,
spread = {x=30, y=30, z=30},
seed = 901,
octaves = 3,
persist = 0.67
}
-------------------------------------
minetest.register_chatcommand("find_pit", {
params = "",
privs = {server=true},
decription = "find a nearby glowing pit",
func = function(name, param)
local player = minetest.get_player_by_name(name)
local pit = get_pit(player:get_pos())
if pit then
minetest.chat_send_player(name, "Pit location: x=" .. math.floor(pit.location.x) .. " z=" .. math.floor(pit.location.z))
end
end,
})
df_caverns.register_biome_check(function(pos, heat, humidity)
if pos.y > y_max or pos.y < y_min then
return
end
return "underworld"
end)
minetest.register_on_generated(function(minp, maxp, seed)
--if out of range of cave definition limits, abort
if minp.y > y_max or maxp.y < y_min then
return
end
local t_start = os.clock()
local vm, data, data_param2, area = mapgen_helper.mapgen_vm_data_param2()
local emin = area.MinEdge
local emax = area.MaxEdge
local nvals_cave = mapgen_helper.perlin2d("df_caverns:underworld_cave", emin, emax, perlin_cave) --cave noise for structure
local nvals_wave = mapgen_helper.perlin2d("df_caverns:underworld_wave", emin, emax, perlin_wave) --cave noise for structure
local nvals_zone = mapgen_helper.perlin2d("df_caverns:underworld_zone", emin, emax, perlin_zone) --building zones
local pit = get_pit(minp)
--minetest.chat_send_all(minetest.pos_to_string(pit.location))
local buildings = get_buildings(emin, emax, nvals_zone)
local pit_uninitialized = true
local nvals_pit, area_pit
for vi, x, y, z in area:iterp_yxz(minp, maxp) do
if y > y_min then
local index2d = mapgen_helper.index2d(emin, emax, x, z)
local abs_cave = math.abs(nvals_cave[index2d]) -- range is from 0 to approximately 2, with 0 being connected and 2s being islands
local wave = nvals_wave[index2d] * wave_mult
local floor_height = math.floor(abs_cave * floor_mult + median + floor_displace + wave)
if named_waypoints_path and floor_height == y and pit and pit.location.x == x and pit.location.z == z then
named_waypoints.add_waypoint("glowing_pits", {x=x, y=y, z=z}, {name=name_pit()})
end
local underside_height = math.floor(y_min + math.abs(wave) / 5)+2 -- divide wave by five to smooth out the underside of the slade, we only want the interface to ripple a little down here
local ceiling_height = math.floor(abs_cave * ceiling_mult + median + ceiling_displace + wave)
if (y == underside_height or y == underside_height - 1) and (x % 8 == 0 or z % 8 == 0) then
data[vi] = c_air
elseif y < floor_height and y > underside_height then
data[vi] = c_slade
if pit and
pit.location.x - radius_pit_max - radius_pit_variance < maxp.x and
pit.location.x + radius_pit_max + radius_pit_variance > minp.x and
pit.location.z - radius_pit_max - radius_pit_variance < maxp.z and
pit.location.z + radius_pit_max + radius_pit_variance > minp.z
then
-- there's a pit nearby
if pit_uninitialized then
nvals_pit, area_pit = mapgen_helper.perlin3d("df_cavern:perlin_cave", minp, maxp, perlin_pit)
pit_uninitialized = false
end
local pit_value = nvals_pit[area_pit:index(x,y,z)] * pit.variance
local distance = vector.distance({x=x, y=y, z=z}, {x=pit.location.x, y=y, z=pit.location.z}) + pit_value
if distance < pit.radius -2.5 then
if y < median + floor_displace + wave - pit.depth or y < underside_height + plasma_depth_min then
data[vi] = c_pit_plasma
if log_location then log_location("underworld_pit", vector.new(x,y,z)) end
else
data[vi] = c_air
end
elseif distance < pit.radius then
data[vi] = c_amethyst
elseif distance < radius_pit_max and y == floor_height - 4 then
if math.random() > 0.95 then
df_underworld_items.underworld_shard(data, area, vi)
end
end
end
elseif y >= floor_height and y < ceiling_height and data[vi] ~= c_amethyst then
data[vi] = c_air
elseif data[vi] == c_water then
data[vi] = c_air -- no water down here
end
end
end
-- Ceiling decoration
for x = minp.x + 1, maxp.x-1 do
for z = minp.z + 1, maxp.z -1 do
local index2d = mapgen_helper.index2d(emin, emax, x, z)
local abs_cave = math.abs(nvals_cave[index2d]) -- range is from 0 to approximately 2, with 0 being connected and 2s being islands
local wave = nvals_wave[index2d] * wave_mult
local floor_height = math.floor(abs_cave * floor_mult + median + floor_displace + wave)
local ceiling_height = math.floor(abs_cave * ceiling_mult + median + ceiling_displace + wave)
if ceiling_height > floor_height + 5 and ceiling_height < maxp.y and ceiling_height > minp.y then
local vi = area:index(x, ceiling_height, z)
if (
--test if we're nestled in a crevice
(not mapgen_helper.buildable_to(data[vi-area.ystride + 1]) and not mapgen_helper.buildable_to(data[vi-area.ystride - 1])) or
(not mapgen_helper.buildable_to(data[vi-area.ystride + area.zstride]) and not mapgen_helper.buildable_to(data[vi-area.ystride - area.zstride]))
)
then
data[vi] = c_glowstone
end
end
end
end
-- buildings
for x = emin.x + 5, emax.x - 5 do
for z = emin.z + 5, emax.z - 5 do
local skip = false
if pit and
pit.location.x - radius_pit_max - radius_pit_variance < x and
pit.location.x + radius_pit_max + radius_pit_variance > x and
pit.location.z - radius_pit_max - radius_pit_variance < z and
pit.location.z + radius_pit_max + radius_pit_variance > z
then
if vector.distance(pit.location, {x=x, y=0, z=z}) < radius_pit_max + radius_pit_variance then
-- there's a pit nearby
skip = true
end
end
if not skip then
local index2d = mapgen_helper.index2d(emin, emax, x, z)
local abs_cave = math.abs(nvals_cave[index2d]) -- range is from 0 to approximately 2, with 0 being connected and 2s being islands
local wave = nvals_wave[index2d] * wave_mult
local floor_height = math.floor(abs_cave * floor_mult + median + floor_displace + wave)
local ceiling_height = math.floor(abs_cave * ceiling_mult + median + ceiling_displace + wave)
if ceiling_height > floor_height and floor_height <= maxp.y and floor_height >= minp.y then
local building = buildings[minetest.hash_node_position({x=x,y=0,z=z})]
if building ~= nil then
building.pos.y = floor_height
--minetest.chat_send_all("placing " .. building.building_type .. " at " .. minetest.pos_to_string(building.pos))
if building.building_type == "oubliette" then
mapgen_helper.place_schematic_on_data(data, data_param2, area, building.pos, oubliette_schematic)
elseif building.building_type == "open oubliette" then
mapgen_helper.place_schematic_on_data(data, data_param2, area, building.pos, oubliette_schematic, 0, {["df_underworld_items:slade_seal"] = "air"})
elseif building.building_type == "lamppost" then
mapgen_helper.place_schematic_on_data(data, data_param2, area, building.pos, lamppost_schematic)
local lamp_pos = vector.new(building.pos.x, building.pos.y+6, building.pos.z)
minetest.after(math.random()*10, function()
-- not all of these locations will get a lamp, but it's easier to just set four
-- timers than to worry about testing first.
minetest.get_node_timer({x=lamp_pos.x+1, y=lamp_pos.y, z=lamp_pos.z}):start(math.random()*30)
minetest.get_node_timer({x=lamp_pos.x-1, y=lamp_pos.y, z=lamp_pos.z}):start(math.random()*30)
minetest.get_node_timer({x=lamp_pos.x, y=lamp_pos.y, z=lamp_pos.z+1}):start(math.random()*30)
minetest.get_node_timer({x=lamp_pos.x, y=lamp_pos.y, z=lamp_pos.z-1}):start(math.random()*30)
end)
elseif building.building_type == "small building" then
mapgen_helper.place_schematic_on_data(data, data_param2, area, building.pos, small_building_schematic, building.rotation)
local pos = building.pos
minetest.after(1, function()
local puzzle_chest = minetest.find_node_near(pos, 4, {"df_underworld_items:puzzle_chest_closed"}, true)
if puzzle_chest then
local def = minetest.registered_nodes["df_underworld_items:puzzle_chest_closed"]
def.can_dig(puzzle_chest) -- initializes the inventory
df_caverns.populate_puzzle_chest(puzzle_chest)
end
end)
elseif building.building_type == "medium building" then
mapgen_helper.place_schematic_on_data(data, data_param2, area, building.pos, medium_building_schematic, building.rotation)
if name_generator_path then
if not next(named_waypoints.get_waypoints_in_area("underworld_ruins", vector.subtract(building.pos, 250), vector.add(building.pos, 250))) then
named_waypoints.add_waypoint("underworld_ruins", {x=building.pos.x, y=floor_height+1, z=building.pos.z}, {name=name_ruin()})
end
end
if log_location then log_location("underworld_building", building.pos) end
elseif building.building_type == "small slab" then
mapgen_helper.place_schematic_on_data(data, data_param2, area, building.pos, small_slab_schematic, building.rotation)
else
minetest.log("error", "unrecognized underworld building type: " .. tostring(building.building_type))
end
end
end
end
end
end
-- puzzle seal
local puzzle_seal = nil
if pit_uninitialized and math.random() < 0.05 then
local index2d = mapgen_helper.index2d(emin, emax, minp.x + 3, minp.z + 3)
local abs_cave = math.abs(nvals_cave[index2d]) -- range is from 0 to approximately 2, with 0 being connected and 2s being islands
local wave = nvals_wave[index2d] * wave_mult
local floor_height = math.floor(abs_cave * floor_mult + median + floor_displace + wave)
local underside_height = math.floor(y_min + math.abs(wave) / 5)
if floor_height < maxp.y and floor_height > minp.y then
for plat_vi in area:iter(minp.x, floor_height-6, minp.z, minp.x+6, floor_height, minp.z+6) do
data[plat_vi] = c_slade_block
end
puzzle_seal = {x=minp.x+3, y=floor_height+1, z=minp.z+3}
minetest.log("info", "Puzzle seal generated at " .. minetest.pos_to_string(puzzle_seal))
if log_location then log_location("underworld_puzzle_seal", puzzle_seal) end
end
end
--send data back to voxelmanip
vm:set_data(data)
vm:set_param2_data(data_param2)
--calc lighting
vm:set_lighting({day = 0, night = 0})
vm:calc_lighting()
vm:update_liquids()
--write it to world
vm:write_to_map()
if puzzle_seal ~= nil then
if named_waypoints_path then
named_waypoints.add_waypoint("puzzle_seals", puzzle_seal)
end
minetest.place_schematic({x=puzzle_seal.x-3, y=puzzle_seal.y, z=puzzle_seal.z-3}, df_underworld_items.seal_temple_schem, 0, {}, true)
local node_name = minetest.get_node(puzzle_seal).name
local node_def = minetest.registered_nodes[node_name]
node_def.on_construct(puzzle_seal)
end
if bones_loot_path then
for i = 1, 30 do
local x = math.random(minp.x, maxp.x)
local z = math.random(minp.z, maxp.z)
local index2d = mapgen_helper.index2d(emin, emax, x, z)
local abs_cave = math.abs(nvals_cave[index2d]) -- range is from 0 to approximately 2, with 0 being connected and 2s being islands
local wave = nvals_wave[index2d] * wave_mult
local floor_height = math.floor(abs_cave * floor_mult + median + floor_displace + wave)-1
local ceiling_height = math.floor(abs_cave * ceiling_mult + median + ceiling_displace + wave)
if floor_height < ceiling_height then
local zone = math.abs(nvals_zone[index2d])
if math.random() < zone/2 then -- bones are more common in the built-up areas
local floor_node = minetest.get_node({x=x, y=floor_height, z=z})
local floor_node_def = minetest.registered_nodes[floor_node.name]
if floor_node_def and not floor_node_def.buildable_to then
local y = floor_height + 1
while y < ceiling_height do
local target_pos = {x=x, y=y, z=z}
local target_node = minetest.get_node(target_pos)
if target_node.name == "air" then
bones_loot.place_bones(target_pos, "underworld_warrior", math.random(3, 10), nil, true)
break
elseif target_node.name == bones_node then
-- don't stack bones on bones, it looks silly
break
end
y = y + 1
end
end
end
end
end
end
if hunters_enabled then
local x = math.random(minp.x, maxp.x)
local z = math.random(minp.z, maxp.z)
local index2d = mapgen_helper.index2d(emin, emax, x, z)
local abs_cave = math.abs(nvals_cave[index2d]) -- range is from 0 to approximately 2, with 0 being connected and 2s being islands
local wave = nvals_wave[index2d] * wave_mult
local floor_height = math.floor(abs_cave * floor_mult + median + floor_displace + wave)-1
local zone = math.abs(nvals_zone[index2d])
if math.random() < zone / 4 then -- hunters are more common in the built-up areas. zone/4 gives ~ 400 hunters per square kilometer.
for y = floor_height, floor_height+20 do
local target_pos = {x=x, y=y, z=z}
local target_node = minetest.get_node(target_pos)
if minetest.get_item_group(target_node.name, "slade") == 0 then
minetest.set_node(target_pos, {name="df_underworld_items:hunter_statue"})
break
end
end
end
end
local time_taken = os.clock() - t_start -- how long this chunk took, in seconds
mapgen_helper.record_time("df_caverns underworld", time_taken)
end)
@@ -0,0 +1,18 @@
name "glowing_pits" {
customGroupA = "Actinic, Amethyst, Angry, Atrocious, Bad, Blighted, Baneful, Baleful, Beastly, Calamitous, Corrupt, Crazed, Damnable, Demoniacal, Demonic, Depraved, Destructive, Devilish, Diabolical, Disastrous, Execrable, Fiendish, Foul, Frenzied, Glaring, Harmful, Hateful, Heinous, Hellish, Hideous, Infernal, Iniquitous, Injurious, Loathsome, Lost, Maleficent, Malevolent, Malicious, Malignant, Manic, Nefarious, Nightmare, Obscene, Offensive, Pernicious, Poison, Possessed, Rancorous, Repugnant, Repulsive, Revolting, Spiteful, Unhallowed, Unpleasant, Vicious, Vile, Villainous, Violent, Wicked, Wrathful"
customGroupB = "Abyss, Aperture, Breach, Cavity, Chasm, Crevasse, Depth, Deep, Fissure, Funnel, Gate, Gulf, Hell, Hole, Hollow, Inferno, Maw, Mouth, Opening, Pit, Portal, Puncture, Ravager, Rent, Rift, Rim, Schism, Shaft, Split, Throat, Void, Well"
customGroupC = "Adversity, Affliction, Annihilation, Bale, Bane, Blight, Calamity, Cataclysm, Catastrophe, Collapse, Conclusion, Condemnation, Death, Defeat, Destiny, Destruction, Disaster, Doom, Downfall, Failure, Grief, Harm, Hazard, Judgment, Karma, Misadventure, Mischance, Misfortune, Mishap, Ruin, Ruination, Tragedy, Undoing, Verdict, Woe"
rules = "%50The_$A_$B, The_$B_of_$C, %10The_$A_$B_of_$C"
}
name "underworld_ruins" {
customGroupA = "Abandoned, Absent, Adrift, Alien, Anonymous, Bare, Barren, Blank, Buried, Clandestine, Cloaked, Concealed, Covered, Cryptic, Dark, Dead, Depleted, Deserted, Desolate, Despoiled, Destitute, Devoid, Disappeared, Distant, Exhausted, Empty, Forfeit, Forfeited, Forsaken, Hidden, Incognito, Indiscernible, Invisible, Irretrievable, Irrevocable, Masked, Mislaid, Misplaced, Mystic, Mystical, Nameless, Obscured, Secluded, Secret, Sequestered, Shadowy, Shrouded, Stark, Strange, Uncelebrated, Uncharted, Undiscovered, Unexplained, Unexplored, Unfamiliar, Unfilled, Unidentified, Unknown, Unnamed, Unredeemed, Unsung, Untold, Vacant, Vacated, Vanished, Veiled, Wayward, Warrior's, King's, Knave's, Coward's, Cardinal's, Priest's, Soldier's, Noble, Steadfast, Children's, Howling, Silent, Grinding, Dusty"
customGroupB = "Temple, Chapel, House, Sanctuary, Shrine, Fortress, Tomb, Crypt, Graves, Citadel, Garrison, Rampart, Redoubt, Refuge, Asylum, Haven, Hideout, Retreat, Shelter, Stronghold, Covert, Den, Settlement, Preserve, Seat, Watch, Bulwark, Necropolis, Catacomb, Ruin, Hulk, Wreck"
rules = "The_$A_$B"
}