diff --git a/big_webs/init.lua b/big_webs/init.lua index 365ad11..0a8e709 100644 --- a/big_webs/init.lua +++ b/big_webs/init.lua @@ -31,11 +31,20 @@ local cardinal_directions = { {x=1,y=0,z=0}, {x=-1,y=0,z=0}, {x=0,y=1,z=0}, - {x=0,y=1,z=0}, + {x=0,y=-1,z=0}, {x=0,y=0,z=1}, {x=0,y=0,z=-1} } +local cardinal_planes = { + {3,5}, + {3,5}, + {1,5}, + {1,5}, + {1,3}, + {1,3}, +} + local insert_if_not_in_hashtable = function(pos, insert_into, if_not_in) local hash = minetest.hash_node_position(pos) if if_not_in[hash] then @@ -67,10 +76,51 @@ if default_path then sound = default.node_sound_leaves_defaults() end + +local web_line = function(pos, dir, distance) + local web_spine = {} + for i = 0, distance do + local web_pos = vector.add(pos, vector.multiply(dir,i)) + local node = minetest.get_node(web_pos).name + if node.name == "air" or node.name == "big_webs:webbing" then + table.insert(web_spine, web_pos) + elseif in_anchor_group(node.name) then + anchored=true + break + else + anchored=false + break + end + end + + if anchored then + for _, web_pos in web_spine do + minetest.set_node(web_pos, {name="big_webs:webbing"}) + minetest.get_node_timer(web_pos):stop() -- no need to test, we know it's anchored + end + return web_spine + end + return nil +end + +local generate_web = function(pos) + local dir_choice = math.random(1, 6) + local dir = cardinal_directions[dir_choice] + local web_spine = web_line(pos, dir, 30) + if web_spine then + local dir2 = cardinal_planes[dir_choice][math.random(1, 4)] + local dir2_opposite = vector.multiply(dir2, -1) + for _, web_pos in pairs(web_spine) do + web_line(web_pos, dir2, 15) + web_line(web_pos, dir2_opposite, 15) + end + end +end + minetest.register_node("big_webs:webbing", { - description = S("Big Spiderweb"), - _doc_items_longdesc = S("Thick ropes of sticky silk, strung between cavern walls in hopes of catching bats and larger beasts."), - _doc_items_usagehelp = S("Webbing can be collected and re-strung elsewhere to aid in climbing."), + description = S("Giant Cave Spider Webbing"), + _doc_items_longdesc = S("Thick ropes of sticky, springy silk, strung between cavern walls in hopes of catching bats and even larger beasts."), + _doc_items_usagehelp = S("Webbing can be collected and re-strung elsewhere to aid in climbing. It absorbs all falling damage when you land on it."), tiles = { {name="big_webs.png"}, }, @@ -81,13 +131,23 @@ minetest.register_node("big_webs:webbing", { node_box = get_node_box(0.0625), collision_box = get_node_box(0.0625), paramtype = "light", - --light_source = 2, is_ground_content = false, climbable = true, - walkable = false, floodable = true, - groups = {choppy = 2, webbing = 1, flammable=1}, + groups = {choppy = 2, webbing = 1, flammable=1, fall_damage_add_percent=-100, bouncy=20}, sounds = sound, + on_construct = function(pos) + minetest.get_node_timer(pos):start(30) + end, + on_destruct = function(pos) + for _, dir in pairs(cardinal_directions) do + local neighbor_pos = vector.add(pos, dir) + if minetest.get_item_group(minetest.get_node(neighbor_pos).name, "webbing") > 0 then + minetest.get_node_timer(neighbor_pos):start(30) + end + end + minetest.get_node_timer(pos):stop() + end, on_timer = function(pos, elapsed) local webs = {} local anchors = {} @@ -103,8 +163,35 @@ minetest.register_node("big_webs:webbing", { if first_anchor == nil then -- unsupported web minetest.set_node(web_pos, {name="air"}) + minetest.item_drop(ItemStack("big_webs:webbing"), nil, web_pos) end minetest.get_node_timer(web_pos):stop() -- no need to recheck end end, +}) + +minetest.register_node("big_webs:web_egg", { + description = S("Giant Cave Spider Web Generator"), + tiles = { + {name="big_webs.png"}, + }, + use_texture_alpha = "blend", + connects_to = {"group:soil", "group:stone", "group:tree", "group:leaves", "group:sand", "group:wood", "group:webbing"}, + connect_sides = { "top", "bottom", "front", "left", "back", "right" }, + drawtype = "nodebox", + node_box = get_node_box(0.0625), + collision_box = get_node_box(0.0625), + paramtype = "light", + is_ground_content = false, + climbable = true, + floodable = true, + groups = {choppy = 2, webbing = 1, flammable=1, fall_damage_add_percent=-100, bouncy=20}, + sounds = sound, + on_construct = function(pos) + minetest.get_node_timer(pos):start(1) + end, + on_timer = function(pos, elapsed) + minetest.set_node(pos, {name="air"}) + generate_web(pos) + end, }) \ No newline at end of file diff --git a/big_webs/locale/template.txt b/big_webs/locale/template.txt index 28fd613..dd1f111 100644 --- a/big_webs/locale/template.txt +++ b/big_webs/locale/template.txt @@ -7,5 +7,5 @@ Big Spiderweb= Thick ropes of sticky silk, strung between cavern walls in hopes of catching bats and larger beasts.= -Webbing can be collected and re-strung elsewhere to aid in climbing.= +Webbing can be collected and re-strung elsewhere to aid in climbing. It absorbs all falling damage when you land on it.= diff --git a/chasms/init.lua b/chasms/init.lua index fd4fdc0..75ef8a4 100644 --- a/chasms/init.lua +++ b/chasms/init.lua @@ -1,5 +1,7 @@ local data = {} +chasms = {} + local maxy = tonumber(minetest.settings:get("chasms_maxy")) or -50 local miny = tonumber(minetest.settings:get("chasms_miny")) or -2500 local falloff = tonumber(minetest.settings:get("chasms_falloff")) or 100 @@ -72,31 +74,41 @@ end local z_displace = 10000 + +local calculate_web_array = function(minp, maxp) + local seed = math.random()*10000000 + math.randomseed(minp.y + z_displace*minp.z) -- use consistent seeds across the x axis + local webs = {} + for count = 1, math.random(10,30) do + local width = math.random(5, 20) + local direction_vertical = math.random() > 0.5 + local web_y = math.random(minp.y+8, maxp.y-8) + local web_z = math.random(minp.z+8, maxp.z-8) + for i = -math.floor(width/2), math.ceil(width/2) do + if direction_vertical then + webs[(web_y+i) + web_z*z_displace] = true + else + webs[web_y + (web_z+i)*z_displace] = true + end + end + end + math.randomseed(seed) + return webs +end + minetest.register_on_generated(function(minp, maxp, seed) if minp.y >= maxy or maxp.y <= miny then return end - -- build a set of web patterns + -- check if webs are present local webs + local webs_present = false if big_webs_path then local seed = math.random()*10000000 math.randomseed(minp.y + z_displace*minp.z) -- use consistent seeds across the x axis if math.random() < web_probability then - webs = {} - for count = 1, math.random(10,30) do - local width = math.random(5, 20) - local direction_vertical = math.random() > 0.5 - local web_y = math.random(minp.y+8, maxp.y-8) - local web_z = math.random(minp.z+8, maxp.z-8) - for i = -math.floor(width/2), math.ceil(width/2) do - if direction_vertical then - webs[(web_y+i) + web_z*z_displace] = true - else - webs[web_y + (web_z+i)*z_displace] = true - end - end - end + webs_present = true end math.randomseed(seed) end @@ -117,7 +129,8 @@ minetest.register_on_generated(function(minp, maxp, seed) local waver = math.min(math.max(math.floor(waver_data[i]+0.5), -waver_strength), waver_strength) local intensity = get_intensity(y) if chasm_data[chasm_area:index(x+waver, y, z)]*intensity > chasms_threshold then - if webs then + if webs_present then + webs = webs or calculate_web_array(minp, maxp) -- only calculate webs when we know we're in a chasm if webs[y + z*z_displace] and math.random() < 0.85 then -- random holes in the web data[i] = c_web minetest.get_node_timer({x=x,y=y,z=z}):start(1) -- this timer will check for unsupported webs @@ -134,3 +147,23 @@ minetest.register_on_generated(function(minp, maxp, seed) vm:calc_lighting() vm:write_to_map() end) + +local nobj_local_chasm = minetest.get_perlin(np_chasms) +local nobj_local_waver = minetest.get_perlin(np_waver) + +chasms.is_in_chasm = function(pos) + nobj_local_chasm = nobj_local_chasm or minetest.get_perlin(np_chasms) + nobj_local_waver = nobj_local_waver or minetest.get_perlin(np_waver) + local waver = math.min(math.max(math.floor(nobj_local_waver:get_3d(pos)+0.5), -waver_strength), waver_strength) + local chasm_value = nobj_local_chasm:get_3d({x=pos.x+waver, y=pos.y, z=pos.z}) + return chasm_value*get_intensity(pos.y) > chasms_threshold +end + +-- A little cheaper to run, for mapgens that know they don't have to worry about the tops and bottoms of chasms +chasms.is_in_chasm_without_taper = function(pos) + nobj_local_chasm = nobj_local_chasm or minetest.get_perlin(np_chasms) + nobj_local_waver = nobj_local_waver or minetest.get_perlin(np_waver) + local waver = math.min(math.max(math.floor(nobj_local_waver:get_3d(pos)+0.5), -waver_strength), waver_strength) + local chasm_value = nobj_local_chasm:get_3d({x=pos.x+waver, y=pos.y, z=pos.z}) + return chasm_value > chasms_threshold +end \ No newline at end of file diff --git a/chasms/mod.conf b/chasms/mod.conf index 16929f7..f0464dc 100644 --- a/chasms/mod.conf +++ b/chasms/mod.conf @@ -1,3 +1,3 @@ name=chasms depends=mapgen_helper -optional_depends=df_caverns, big_webs \ No newline at end of file +optional_depends=big_webs \ No newline at end of file diff --git a/df_caverns/level1.lua b/df_caverns/level1.lua index 801501c..774079f 100644 --- a/df_caverns/level1.lua +++ b/df_caverns/level1.lua @@ -10,6 +10,8 @@ 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, @@ -273,6 +275,18 @@ local decorate_level_1 = function(minp, maxp, seed, vm, node_arrays, area, data) 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) diff --git a/df_caverns/level2.lua b/df_caverns/level2.lua index c503e72..732a214 100644 --- a/df_caverns/level2.lua +++ b/df_caverns/level2.lua @@ -14,6 +14,9 @@ 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 wall_vein_perlin_params = { offset = 0, scale = 1, @@ -354,6 +357,19 @@ local decorate_level_2 = function(minp, maxp, seed, vm, node_arrays, area, data) 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) diff --git a/df_caverns/level3.lua b/df_caverns/level3.lua index 5997a21..14a1753 100644 --- a/df_caverns/level3.lua +++ b/df_caverns/level3.lua @@ -18,6 +18,8 @@ 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 chasms_path = minetest.get_modpath("chasms") + 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) @@ -459,7 +461,7 @@ local decorate_level_3 = function(minp, maxp, seed, vm, node_arrays, area, data) end ---------------------------------------------- - -- Column material override for dry biome + -- 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]) @@ -476,7 +478,7 @@ local decorate_level_3 = function(minp, maxp, seed, vm, node_arrays, area, data) -- 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 and hoar_moss_generator:get_3d({x=pos.z, y=pos.y, z=pos.x}) > 0.5 then -- TODO: version 0.4.16 gets no hoar moss + 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 @@ -491,6 +493,19 @@ local decorate_level_3 = function(minp, maxp, seed, vm, node_arrays, area, data) 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) diff --git a/df_caverns/mod.conf b/df_caverns/mod.conf index 6ff8691..0c3b855 100644 --- a/df_caverns/mod.conf +++ b/df_caverns/mod.conf @@ -1,4 +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 = default, subterrane, df_trees, df_mapitems -optional_depends = df_farming, ice_sprites, oil, df_underworld_items, magma_conduits, bones_loot, named_waypoints, name_generator, fireflies \ No newline at end of file +optional_depends = df_farming, ice_sprites, oil, df_underworld_items, magma_conduits, bones_loot, named_waypoints, name_generator, fireflies, chasms, big_webs \ No newline at end of file diff --git a/df_caverns/node_ids.lua b/df_caverns/node_ids.lua index 1cd8de6..f71d708 100644 --- a/df_caverns/node_ids.lua +++ b/df_caverns/node_ids.lua @@ -14,6 +14,11 @@ if minetest.get_modpath("df_farming") then df_caverns.node_id.dead_fungus = minetest.get_content_id("df_farming:dead_fungus") end +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 + df_caverns.node_id.air = minetest.get_content_id("air") df_caverns.node_id.cobble = minetest.get_content_id("default:cobble") diff --git a/df_caverns/shared.lua b/df_caverns/shared.lua index cb93210..640ce17 100644 --- a/df_caverns/shared.lua +++ b/df_caverns/shared.lua @@ -21,9 +21,25 @@ local c_wet_flowstone = df_caverns.node_id.wet_flowstone df_caverns.data_param2 = {} +-- 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[df_caverns.node_id.big_webs] = true + dont_build_speleothems_on[df_caverns.node_id.big_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 @@ -118,13 +134,6 @@ df_caverns.glow_worm_cavern_ceiling = function(abs_cracks, vert_rand, vi, area, end end -local content_in_list=function(content, list) - for i, v in ipairs(list) do - if content == v then return true end - end - return false -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 @@ -135,7 +144,7 @@ df_caverns.tunnel_floor = function(minp, maxp, area, vi, nvals_cracks, data, dat local abs_cracks = math.abs(cracks) if wet then - if abs_cracks < 0.05 and data[vi+ystride] == c_air and not content_in_list(data[vi], df_mapitems.wet_stalagmite_ids) then -- make sure data[vi] is not already flowstone. Stalagmites from lower levels are acting as base for further stalagmites + 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) @@ -144,7 +153,7 @@ df_caverns.tunnel_floor = function(minp, maxp, area, vi, nvals_cracks, data, dat data[vi] = dirt_node end else - if abs_cracks < 0.025 and data[vi+ystride] == c_air and not content_in_list(data[vi], df_mapitems.dry_stalagmite_ids) then -- make sure data[vi] is not already flowstone. Stalagmites from lower levels are acting as base for further stalagmites + 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) @@ -165,14 +174,14 @@ df_caverns.tunnel_ceiling = function(minp, maxp, area, vi, nvals_cracks, data, d local abs_cracks = math.abs(cracks) if wet then - if abs_cracks < 0.05 and data[vi-ystride] == c_air and not content_in_list(data[vi], df_mapitems.wet_stalagmite_ids) then -- make sure data[vi] is not already flowstone. Stalagmites from lower levels are acting as base for further stalagmites + 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 content_in_list(data[vi], df_mapitems.dry_stalagmite_ids) then -- make sure data[vi] is not already flowstone. Stalagmites from lower levels are acting as base for further stalagmites + 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)