diff --git a/bubblesponge/LICENSE.txt b/bubblesponge/LICENSE.txt new file mode 100644 index 0000000..b7347c0 --- /dev/null +++ b/bubblesponge/LICENSE.txt @@ -0,0 +1,24 @@ +Sounds are under various licenses, see the license.txt file in the /sounds directory for details. + +License for Code and Textures +----------------------------- + +Copyright 2023 by 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. \ No newline at end of file diff --git a/bubblesponge/init.lua b/bubblesponge/init.lua new file mode 100644 index 0000000..1a6fb7a --- /dev/null +++ b/bubblesponge/init.lua @@ -0,0 +1,188 @@ +local S = minetest.get_translator(minetest.get_current_modname()) + +local print_settingtypes = false +local CONFIG_FILE_PREFIX = "bubblesponge_" +local config = {} + +bubblesponge = {} +bubblesponge.config = config + +local function setting(stype, name, default, description) + local value + if stype == "bool" then + value = minetest.settings:get_bool(CONFIG_FILE_PREFIX..name) + elseif stype == "string" then + value = minetest.settings:get(CONFIG_FILE_PREFIX..name) + elseif stype == "int" or stype == "float" then + value = tonumber(minetest.settings:get(CONFIG_FILE_PREFIX..name)) + end + if value == nil then + value = default + end + config[name] = value + + if print_settingtypes then + minetest.debug(CONFIG_FILE_PREFIX..name.." ("..description..") "..stype.." "..tostring(default)) + end +end + +setting("int", "uses", 30, "Number of uses for a bubblesponge") +setting("int", "growth_seconds", 1000, "Number of seconds between each growth check for bubblesponge stems") +setting("int", "y_max", -300, "Maximum altitude at which bubblesponge will grow") + +local function use_airtank(itemstack, user) + local breath = user:get_breath() + if breath > 9 then return itemstack end + breath = math.min(10, breath+5) + user:set_breath(breath) + minetest.sound_play("bubblesponge_bubbles", {pos = user:get_pos(), gain = 0.5}) + + --if not minetest.settings:get_bool("creative_mode") then + local wdef = itemstack:get_definition() + itemstack:add_wear(65535/(wdef._airtanks_uses-1)) + if itemstack:get_count() == 0 then + if wdef.sound and wdef.sound.breaks then + minetest.sound_play(wdef.sound.breaks, + {pos = user:get_pos(), gain = 0.5}) + end + end + --end + return itemstack +end + +minetest.register_tool("bubblesponge:tank", { + description = S("Bubblesponge Frond"), + _doc_items_longdesc = S("A frond harvested from a bubblesponge."), + _doc_items_usagehelp = S("If you're underwater and you're running out of breath, wield this item and use it to replenish 5 bubbles on your breath bar. When fully charged this frond has @1 uses before it becomes empty.", config.uses), + _airtanks_uses = config.uses, + inventory_image = "bubblesponge_frond.png", + wield_image = "bubblesponge_frond.png", + stack_max = 1, + groups = {bubblesponge_tank = 1}, + + on_place = function(itemstack, user, pointed_thing) + return use_airtank(itemstack, user) + end, + + on_use = function(itemstack, user, pointed_thing) + return use_airtank(itemstack, user) + end, +}) + +minetest.register_tool("bubblesponge:bundle", { + description = S("Bubblesponge Bundle"), + _doc_items_longdesc = S("A bundle of fronds harvested from a bubblesponge."), + _doc_items_usagehelp = S("If you're underwater and you're running out of breath, wield this item and use it to replenish 5 bubbles on your breath bar. When fully charged this frond has @1 uses before it becomes empty.", config.uses * 9), + _airtanks_uses = config.uses * 9, + inventory_image = "bubblesponge_bundle.png", + wield_image = "bubblesponge_bundle.png", + stack_max = 1, + groups = {bubblesponge_tank = 1}, + + on_place = function(itemstack, user, pointed_thing) + return use_airtank(itemstack, user) + end, + + on_use = function(itemstack, user, pointed_thing) + return use_airtank(itemstack, user) + end, +}) + +minetest.register_craft({ + recipe = { + {"bubblesponge:tank", "bubblesponge:tank", "bubblesponge:tank"}, + {"bubblesponge:tank", "bubblesponge:tank", "bubblesponge:tank"}, + {"bubblesponge:tank", "bubblesponge:tank", "bubblesponge:tank"}, + }, + output = "bubblesponge:bundle", +}) + +local water_node = df_dependencies.node_name_water_source + +minetest.register_node("bubblesponge:stem", { + description = S("Bubblesponge Trunk"), + _doc_items_longdesc = S("The trunk of a massive sponge. Bubblesponges grow deep underwater in caverns and their fronds have uniquely helpful properties for divers."), + _doc_items_usagehelp = S("If you're underwater and you're running out of breath you can squeeze a lungful of air from a wielded Bubblesponge frond"), + groups = {oddly_breakable_by_hand = 1, handy = 1}, + sounds = df_trees.node_sound_tree_soft_fungus_defaults(), + tiles = {"bubblesponge_bubblesponge.png"}, + use_texture_alpha = "clip", + drawtype = "normal", + paramtype = "light", + is_ground_content = false, + light_source = 6, + + on_timer = function(pos, elapsed) + local timer = minetest.get_node_timer(pos) + elapsed = elapsed - config.growth_seconds + timer:set(config.growth_seconds, elapsed) + + if pos.y > config.y_max then + return + end + + pos.y = pos.y + 1 + + if minetest.find_node_near(pos, 4, "air", true) then + return + end + + local tries = 0 + while tries < 3 do + local this_node = minetest.get_node(pos).name + if minetest.get_node(pos).name == water_node then + minetest.set_node(pos, {name = "bubblesponge:frond"}) + return + else + pos = {x = pos.x + math.random(-1, 1), y = pos.y + math.random(0, 1), z = pos.z + math.random(-1, 1)} + tries = tries + 1 + end + end + end, + + on_construct = function(pos) + minetest.get_node_timer(pos):start(config.growth_seconds + math.random(-0.1, 0.1)*config.growth_seconds) + --minetest.get_node_timer(pos):set(1, config.growth_seconds * 6) -- immediate growth + end, + on_destruct = function(pos) + minetest.get_node_timer(pos):stop() + end, +}) + +minetest.register_node("bubblesponge:frond", { + description = S("Bubblesponge Frond"), + drawtype = "plantlike", + visual_scale = 1.2, + tiles = {"bubblesponge_growth.png"}, + paramtype = "light", + sunlight_propagates = true, + walkable = false, + buildable_to = true, + groups = {snappy=3, oddly_breakable_by_hand = 1, handy = 1, not_in_creatove_inventory=1}, + sounds = default.node_sound_leaves_defaults(), + drop = "bubblesponge:tank", +}) + +local function use_any_airtank_in_hotbar(player) + local inv = player:get_inventory() + local hotbar = player:hud_get_hotbar_itemcount() + for i=1, hotbar do + local itemstack = inv:get_stack("main", i) + if minetest.get_item_group(itemstack:get_name(), "bubblesponge_tank") >= 1 then + itemstack = use_airtank(itemstack, player) + inv:set_stack("main", i, itemstack) + return true + end + end + return false +end + +local function player_event_handler(player, eventname) + if player:is_player() and eventname == "breath_changed" and player:get_breath() < 2 then + use_any_airtank_in_hotbar(player) + end + + return false +end + +minetest.register_playerevent(player_event_handler) diff --git a/bubblesponge/mod.conf b/bubblesponge/mod.conf new file mode 100644 index 0000000..b62d4a6 --- /dev/null +++ b/bubblesponge/mod.conf @@ -0,0 +1,4 @@ +name = bubblesponge +description = A species of sponge that, when harvested, provides a limited air supply for underwater travel +depends = df_dependencies, df_trees +optional_depends = doc \ No newline at end of file diff --git a/bubblesponge/settingtypes.txt b/bubblesponge/settingtypes.txt new file mode 100644 index 0000000..bb0bb17 --- /dev/null +++ b/bubblesponge/settingtypes.txt @@ -0,0 +1,3 @@ +bubblesponge_uses (Number of uses provided by a bubblesponge) int 30 2 1000 +bubblesponge_growth_seconds (Number of seconds between each bubblesponge stem growing a new frond) int 1000 1 100000 +bubblesponge_y_max (Maximum altitude at which bubblesponge will grow) int -300 \ No newline at end of file diff --git a/bubblesponge/sounds/bubblesponge_bubbles.ogg b/bubblesponge/sounds/bubblesponge_bubbles.ogg new file mode 100644 index 0000000..f35c85f Binary files /dev/null and b/bubblesponge/sounds/bubblesponge_bubbles.ogg differ diff --git a/bubblesponge/sounds/license.txt b/bubblesponge/sounds/license.txt new file mode 100644 index 0000000..e089e06 --- /dev/null +++ b/bubblesponge/sounds/license.txt @@ -0,0 +1 @@ +bubblesponge_bubbles is from https://freesound.org/people/murraysortz/sounds/192501/ by Murraysortz under the CC-BY-3.0 license \ No newline at end of file diff --git a/bubblesponge/textures/bubblesponge_bubblesponge.png b/bubblesponge/textures/bubblesponge_bubblesponge.png new file mode 100644 index 0000000..164c845 Binary files /dev/null and b/bubblesponge/textures/bubblesponge_bubblesponge.png differ diff --git a/bubblesponge/textures/bubblesponge_bundle.png b/bubblesponge/textures/bubblesponge_bundle.png new file mode 100644 index 0000000..de2680a Binary files /dev/null and b/bubblesponge/textures/bubblesponge_bundle.png differ diff --git a/bubblesponge/textures/bubblesponge_frond.png b/bubblesponge/textures/bubblesponge_frond.png new file mode 100644 index 0000000..f9f6994 Binary files /dev/null and b/bubblesponge/textures/bubblesponge_frond.png differ diff --git a/bubblesponge/textures/bubblesponge_growth.png b/bubblesponge/textures/bubblesponge_growth.png new file mode 100644 index 0000000..37ef3f7 Binary files /dev/null and b/bubblesponge/textures/bubblesponge_growth.png differ diff --git a/df_caverns/mod.conf b/df_caverns/mod.conf index e2e9db8..4a9ab59 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 = 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 \ 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, mcl_flowers, mine_gas, bubblesponge \ No newline at end of file diff --git a/df_caverns/node_ids.lua b/df_caverns/node_ids.lua index 0b003cd..a04b234 100644 --- a/df_caverns/node_ids.lua +++ b/df_caverns/node_ids.lua @@ -35,6 +35,10 @@ 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("bubblesponge") then + df_caverns.node_id.bubblesponge = minetest.get_content_id("bubblesponge:stem") +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") diff --git a/df_caverns/shared.lua b/df_caverns/shared.lua index ffdf1e1..7cefaad 100644 --- a/df_caverns/shared.lua +++ b/df_caverns/shared.lua @@ -20,9 +20,15 @@ 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 +local c_bubblesponge = df_caverns.node_id.bubblesponge df_caverns.data_param2 = {} -- shared among all mapgens to reduce memory clutter +local log_location +if mapgen_helper.log_location_enabled then + log_location = mapgen_helper.log_first_location +end + 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) @@ -114,7 +120,17 @@ df_caverns.flooded_cavern_floor = function(abs_cracks, vert_rand, vi, area, data if abs_cracks < 0.25 then data[vi] = c_mossycobble elseif data[vi-ystride] ~= c_water then - data[vi] = c_sand_scum + + if c_bubblesponge and abs_cracks > 0.5 and math.random() < 0.01 then + local vi_above = vi + ystride + if data[vi_above] == c_water then + data[vi] = c_bubblesponge + minetest.get_node_timer(area:position(vi)):set(1, bubblesponge.config.growth_seconds * 6) -- immediate growth + if log_location then log_location("flooded_bubblesponge", area:position(vi_above)) end + end + else + data[vi] = c_sand_scum + end end -- put in only the large stalagmites that won't get in the way of the water @@ -123,6 +139,7 @@ df_caverns.flooded_cavern_floor = function(abs_cracks, vert_rand, vi, area, data 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) diff --git a/df_mapitems/doc.lua b/df_mapitems/doc.lua index 359e090..d184543 100644 --- a/df_mapitems/doc.lua +++ b/df_mapitems/doc.lua @@ -36,7 +36,7 @@ df_mapitems.doc.glow_worms_usage = S("Glow worms can be harvested and used as a df_mapitems.doc.snareweed_desc = S("A nasty kelp-like plant that grows in patches on the floor of the Sunless Sea. Its reflective patches draw in the unwary and then its prickly barbs catch and hold small creatures.") df_mapitems.doc.snareweed_usage = S("Snareweed has no practical use, its fibers disintegrate when they dry.") -df_mapitems.doc.cave_coral_desc = S("A rare form of coral found only deep underground in the Sunless Sea, cave coral grows hanging from the ceilings of flooded caverns.") +df_mapitems.doc.cave_coral_desc = S("A rare form of coral found only deep underground in the Sunless Sea, cave coral grows where dripstone dips into the water to deliver the minerals needed for its skeletal structure.") df_mapitems.doc.cave_coral_usage = S("Aside from their aesthetic beauty, cave corals can be harvested for simple building materials.") df_mapitems.doc.flowstone_desc = S("Flowstone is a carbonate-rich rock formation deposited by flowing water. It consists of minerals that the water dissolved earlier as it widens cracks and fissures into caves.") diff --git a/guide.md b/guide.md index 2ad4036..4addf74 100644 --- a/guide.md +++ b/guide.md @@ -188,7 +188,7 @@ The distinguishing feature of the Sunless Sea is the vast expanse of water to be Below the surface of the water Snareweed can be found, a dangerous kelp-like growth that uses bioluminescence and reflective patches to lure cave fish close enough to snag with their barbs. Swimming through Snareweed is a painful experience. Deeper down are craggy towers of softly glowing Cave Coral. -This is the last stop for the living world. Caverns continue to stretch below but nothing grows below. +This is the last stop for the living world. Caverns continue to stretch downward but nothing grows below. # Lakes of Oil