diff --git a/api.lua b/api.lua new file mode 100644 index 0000000..9367ae1 --- /dev/null +++ b/api.lua @@ -0,0 +1,492 @@ +noordstar_dripstone = {} + +-- Internal values that cannot be changed by other mods (directly). +local internal = { + -- These values are not meant to be changed during runtime. + constant = { + -- How many nodes downwards a droplet is able to drop from a stalactite + -- before the droplet evaporates. + drop_down_reach = 50, + + -- The number of seconds it takes for a dripstone node to grow 1 unit + -- (NOTE: Not one node size! One unit, which quadratically increases + -- per node size.) + growth_factor = 3, + + -- This mod's name. + modname = minetest.get_current_modname(), + + -- The number of samples that each ABM should execute. + -- Make sure this is a whole number and less than speed_factor. + samples_per_interval = 30, + + -- Factor deciding this mod's relative speed. + -- Set this value to 1 if you wish to debug and let the dripstone + -- change rapidly. + -- Rule of thumb: with a setting of 60, it takes a lava farm about 30 + -- minutes to fill a cauldron with lava. + speed_factor = 60, + + -- Names of the various dripstone widths + width_names = { + "spike", "tiny", "small", "medium", + "great", "large", "huge", "block", + }, + }, + + -- Nodes that function as cauldrons + cauldrons = {}, + + -- Nodes that provide droplets + sources = {}, + + -- Nodes that allow a droplet to trickle down if it is directly below a + -- node that passes down that droplet. + tricklers = {}, +} + + +------------------------------------------------------------------------------- +------------------------------------------------------------------------------- +--------------------------- PUBLIC API -------------------------------- +------------------------------------------------------------------------------- +------------------------------------------------------------------------------- + +-- Register a node that can catch a droplet from a dripstone stalactite. +function noordstar_dripstone.add_droplet_catcher(droplet, oldnodename, newnodename) + return internal.add_droplet_catcher(droplet, oldnodename, newnodename) +end + +-- Register a new source node that can provide droplets to dripstone blocks. +function noordstar_dripstone.add_droplet_source(droplet, nodename) + return internal.add_droplet_source(droplet, nodename) +end + +-- Register a new dripstone type. +-- +-- { +-- -- What item is dropped when the dripstone is broken. +-- -- When left nil, the spike of the dripstone type is dropped. +-- drop = "dry" +-- +-- -- What flavor to become when using liquid to grow. +-- -- Leave to nil when unable to grow. +-- grow_to = "dry" +-- +-- -- When receiving a droplet of a given type, transform into a different +-- -- dripstone type. When a droplet is unspecified, the block cannot +-- -- receive the droplet. +-- on_droplet_receive = { +-- water = "watered", +-- lava = "molten", +-- } +-- +-- -- Sounds that the dripstone makes +-- sounds = +-- +-- -- Node tiles for layout +-- tiles = +-- +-- -- Droplet type that the dripstone flavor can pass down. +-- -- When the droplet is passed down, the dripstone converts to the +-- -- "grow_to" type +-- trickle_down = "water" +-- +-- -- Speed of how often a droplet trickles down. +-- trickle_speed = 5 +-- } +function noordstar_dripstone.register_dripstone(flavor, def) + return internal.register_dripstone_flavor(flavor, def) +end + +-- Register a new droplet type that can be absorbed and passed on by dripstone. +function noordstar_dripstone.register_droplet(droplet) + if internal.cauldrons[droplet] == nil then + internal.cauldrons[droplet] = {} + end + if internal.sources[droplet] == nil then + internal.sources[droplet] = {} + end + if internal.tricklers[droplet] == nil then + internal.tricklers[droplet] = {} + end +end + +-- Get a dripstone's node name based on its flavor and size. +function noordstar_dripstone.size_to_name(flavor, size) + return internal.size_to_name(flavor, size) +end + +------------------------------------------------------------------------------- +------------------------------------------------------------------------------- +------------------------------------------------------------------------------- +------------------------------------------------------------------------------- +------------------------------------------------------------------------------- + +-- Add a droplet catcher, which is a node that allows a stalactite spike to +-- change the name using a droplet. +function internal.add_droplet_catcher(droplet, oldnodename, newnodename) + return internal.register_cauldron(droplet, oldnodename, newnodename) +end + +function internal.add_droplet_source(droplet, nodename) + if internal.sources[droplet] == nil then + internal.uninitialized_droplet_error(droplet) + end + table.insert(internal.sources[droplet], nodename) +end + +-- Add a droplet trickler, which is a dripstone node that allows a droplet to +-- be trickled down from the node directly above it. +-- Running this function overrides previous values. +function internal.add_droplet_trickler(droplet, oldnodename, newnodename) + if internal.tricklers[droplet] == nil then + internal.uninitialized_droplet_error(droplet) + end + + internal.tricklers[droplet][oldnodename] = newnodename +end + +-- Capitalize a string +function internal.capitalize(str) + return (str:gsub("^%l", string.upper)) +end + +function internal.drawtype_of_size(size) + if size >= 8 then + return "normal" + else + return "nodebox" + end +end + +function internal.hit_with_droplet(pos, node, droplet, spikename) + local m = internal.cauldrons[droplet] or {} + + if m[node.name] == nil then + -- Not a cauldron! Therefore we place a spike on top. + pos = vector.offset(pos, 0, 1, 0) + node = minetest.get_node(pos) + node.name = spikename + minetest.set_node(pos, node) + else + node.name = m[node.name] + minetest.set_node(pos, node) + end +end + +-- Determine whether this mod considers a node an air node. +function internal.is_air(nodename) + if nodename == "air" then + return true + else + return minetest.get_item_group(nodename, "air") ~= 0 + end +end + +-- Create a node box for any given dripstone size. +-- Size 8 is a normal block size +function internal.nodebox_of_size(size) + if size >= 8 then + return nil + else + return { + type = "fixed", + fixed = { + { - size / 16, -0.5, - size / 16, size / 16, 0.5, size / 16 }, + }, + } + end +end + +function internal.register_absorb_abm(droplet, oldnodename, newnodename) + minetest.register_abm({ + nodenames = { oldnodename }, + interval = internal.constant.speed_factor / internal.constant.samples_per_interval, + chance = internal.constant.samples_per_interval, + catch_up = true, + action = function (pos, node, aoc, aocw) + local pos_above = vector.offset(pos, 0, 1, 0) + local node_above = minetest.get_node(pos_above) + + for _, source in pairs(internal.sources[droplet] or {}) do + if node_above.name == source then + node.name = newnodename + minetest.set_node(pos, node) + return + end + end + end + }) +end + +function internal.register_cauldron(droplet, oldnodename, newnodename) + if internal.cauldrons[droplet] == nil then + internal.uninitialized_droplet_error(droplet) + end + + internal.cauldrons[droplet][oldnodename] = newnodename +end + +function internal.register_dripstone_craft(newnodename, oldnodename, spikename) + minetest.register_craft({ + output = newnodename, + recipe = { + { spikename, spikename , spikename }, + { spikename, oldnodename, spikename }, + { spikename, spikename , spikename }, + } + }) +end + +function internal.register_dripstone_flavor(flavor, def) + -- Guaranteed values + local drop = def.drop or internal.size_to_name(flavor, 1) + local on_droplet_receive = def.on_droplet_receive or {} + local trickle_speed = def.trickle_speed or 1 + + -- Potentially nil, might need to be checked before assumed safe + local dry_up = def.grow_to + local sounds = def.sounds + local tiles = def.tiles + local trickl = def.trickle_down + + -- Register nodes + for width = 1, 8, 1 do + internal.register_dripstone_node(flavor, width, tiles, sounds, drop) + end + + -- Register upgrade crafting recipes + for width = 1, 6, 1 do + internal.register_dripstone_craft( + internal.size_to_name(flavor, width + 1), + internal.size_to_name(flavor, width), + internal.size_to_description(flavor, 1) + ) + end + + -- Allow dripstone nodes to trickle down droplets + for droplet, new_flavor in pairs(on_droplet_receive) do + for width = 1, 8, 1 do + internal.add_droplet_trickler( + droplet, + internal.size_to_name(flavor, width), + internal.size_to_name(new_flavor, width) + ) + end + end + + -- Allow spike stalagmites to catch droplets + for droplet, new_flavor in pairs(on_droplet_receive) do + internal.register_cauldron( + droplet, + internal.size_to_name(flavor, 1), + internal.size_to_name(new_flavor, 1) + ) + end + + -- Register ABM to grow when possible. + if dry_up then + for width = 1, 6, 1 do + internal.register_grow_abm( + internal.size_to_name(flavor, width), + internal.size_to_name(dry_up, width + 1), + width + ) + end + end + + -- Register ABM to grow when possible + if trickl and dry_up then + for width = 1, 8, 1 do + internal.register_trickle_down_abm( + trickl, + width, + internal.size_to_name(flavor, width), + internal.size_to_name(dry_up, width), + dry_up, + trickle_speed + ) + end + end + + -- Register ABM to absorb liquids from above + for droplet, new_flavor in pairs(on_droplet_receive) do + internal.register_absorb_abm( + droplet, + internal.size_to_name(flavor, 8), + internal.size_to_name(new_flavor, 8) + ) + end + + -- Register ABM to drop down droplets from a stalactite spike + if dry_up and trickl then + internal.register_drop_down_abm( + trickl, + internal.size_to_name(flavor, 1), + internal.size_to_name(dry_up, 1), + trickle_speed + ) + + -- Makes dripstone stalagmite spikes delete droplets. + -- Without this, stalactites remain very thick and short while + -- stalagmites become absurdly long and thin. + -- A watered stalagmite can't accept a water droplet and the stalagmite + -- therefore grows one per droplet. To mitigate this, a watered spike + -- can still act as a water droplet cauldron without changing. + -- This way, no new droplets are passed on if the stalagmite is already + -- full, and the structure simply waits for a dripstone node to grow. + -- This behaviour is designed to be easy to override. (For example: if + -- you want a HEAVY watered dripstone type that holds 2 droplets.) + internal.add_droplet_catcher( + trickl, + internal.size_to_name(flavor, 1), + internal.size_to_name(flavor, 1) + ) + end +end + +function internal.register_dripstone_node(flavor, size, tiles, sounds, drop) + minetest.register_node(internal.size_to_name(flavor, size), { + description = internal.size_to_description(flavor, size), + tiles = tiles, + groups = { + pickaxey=2, + material_stone=1, + fall_damage_add_percent = math.max(4 - size, 0) / 4 * 100 + }, + is_ground_content = true, + drop = { + max_items = math.floor((size + 1) / 2), + items = { + { rarity = 1 + , items = { drop } + }, + { rarity = 2 + , items = { drop } + }, + { rarity = 4 + , items = { drop } + }, + { rarity = 4 + , items = { drop } + }, + } + }, + sounds = sounds, + drawtype = internal.drawtype_of_size(size), + paramtype = "light", + sunlight_propagates = size < 8, + node_box = internal.nodebox_of_size(size), + _mcl_hardness = 1.0 + size / 8, + _mcl_blast_resistance = 1 + size / 2, + _mcl_silk_touch_drop = true, + }) +end + +function internal.register_drop_down_abm(droplet, spikename, dryspikename, trickle_speed) + minetest.register_abm({ + nodenames = { spikename }, + interval = trickle_speed * internal.constant.speed_factor / internal.constant.samples_per_interval, + chance = internal.constant.samples_per_interval, + catch_up = true, + action = function (pos, node, aoc, aocw) + local pos_below = vector.offset(pos, 0, -1, 0) + local node_below = minetest.get_node(pos_below) + + if not internal.is_air(node_below.name) then + -- Node below is not air! Unable to drop a droplet down. + return + end + + for dy = 2, internal.constant.drop_down_reach, 1 do + pos_below = vector.offset(pos, 0, -dy, 0) + node_below = minetest.get_node(pos_below) + + if not internal.is_air(node_below.name) then + -- Node is not air! If it is a cauldron, update the node. + internal.hit_with_droplet( + pos_below, + node_below, + droplet, + dryspikename + ) + break + end + end + + node.name = dryspikename + minetest.set_node(pos, node) + end + }) +end + +function internal.register_grow_abm(oldnodename, newnodename, width) + minetest.register_abm({ + nodenames = { oldnodename }, + -- 2(w + 1) * 2(w + 1) - 2w * 2w = 8w + 4 + interval = (8 * width + 4) * internal.constant.speed_factor * internal.constant.growth_factor / internal.constant.samples_per_interval, + chance = internal.constant.samples_per_interval, + catch_up = true, + action = function (pos, node, aoc, aocw) + node.name = newnodename + minetest.set_node(pos, node) + end + }) +end + +function internal.register_trickle_down_abm(droplet, width, old_source, new_source, dry_up, trickle_speed) + minetest.register_abm({ + nodenames = { old_source }, + interval = trickle_speed * internal.constant.speed_factor / internal.constant.samples_per_interval, + chance = internal.constant.samples_per_interval, + catch_up = true, + action = function (pos, node, aoc, aocw) + local pos_below = vector.offset(pos, 0, -1, 0) + local node_below = minetest.get_node(pos_below) + + local m = internal.tricklers[droplet] or {} + + if m[node_below.name] ~= nil then + -- Trickler found below! + node_below.name = m[node_below.name] + elseif width > 1 and internal.is_air(node_below.name) then + -- Air node found below a non-spike, turn it into a spike. + node_below.name = internal.size_to_name(dry_up, 1) + else + return -- Prevent droplet from leaking away + end + + node.name = new_source + minetest.set_node(pos_below, node_below) + minetest.set_node(pos, node) + end + }) +end + +function internal.size_to_description(flavor, size) + local width_name = internal.constant.width_names[size] + + if size == 1 or size == 8 then + return internal.capitalize(flavor) .. " dripstone " .. width_name + else + return internal.capitalize(width_name) .. " " .. flavor .. " dripstone" + end +end + +function internal.size_to_name(flavor, size) + local namespace = internal.constant.modname .. ":" + local width_name = internal.constant.width_names[size] + + if size == 1 or size == 8 then + return namespace .. flavor .. "_dripstone_" .. width_name + else + return namespace .. width_name .. "_" .. flavor .. "_dripstone" + end +end + +function internal.uninitialized_droplet_error(droplet) + error( + "Droplet " .. droplet .. " has not been initialized yet!" + ) +end diff --git a/init.lua b/init.lua index 801e05c..660c4c6 100644 --- a/init.lua +++ b/init.lua @@ -1,760 +1,87 @@ -noordstar_dripstone = {} +-- Load dripstone API --- Constants -local speed_factor = 60 -local seconds_per_growth = 10 * speed_factor -local seconds_per_water_trickle = 1 * speed_factor -local seconds_per_lava_trickle = 6 * speed_factor -local samples_per_interval = 30 +local modpath = minetest.get_modpath(minetest.get_current_modname()) --- Namespaced node names -local dry_dripstone_block = "noordstar_dripstone:dripstone_block" -local dry_dripstone_huge = "noordstar_dripstone:huge_dripstone" -local dry_dripstone_large = "noordstar_dripstone:large_dripstone" -local dry_dripstone_great = "noordstar_dripstone:great_dripstone" -local dry_dripstone_medium = "noordstar_dripstone:medium_dripstone" -local dry_dripstone_small = "noordstar_dripstone:small_dripstone" -local dry_dripstone_tiny = "noordstar_dripstone:tiny_dripstone" -local dry_dripstone_spike = "noordstar_dripstone:dripstone_spike" -local hardened_dripstone_block = "noordstar_dripstone:hardened_dripstone_block" -local hardened_dripstone_huge = "noordstar_dripstone:huge_hardened_dripstone" -local hardened_dripstone_large = "noordstar_dripstone:large_hardened_dripstone" -local hardened_dripstone_great = "noordstar_dripstone:great_hardened_dripstone" -local hardened_dripstone_medium = "noordstar_dripstone:medium_hardened_dripstone" -local hardened_dripstone_small = "noordstar_dripstone:small_hardened_dripstone" -local hardened_dripstone_tiny = "noordstar_dripstone:tiny_hardened_dripstone" -local hardened_dripstone_spike = "noordstar_dripstone:hardened_dripstone_spike" -local molten_dripstone_block = "noordstar_dripstone:molten_dripstone_block" -local molten_dripstone_huge = "noordstar_dripstone:huge_molten_dripstone" -local molten_dripstone_large = "noordstar_dripstone:large_molten_dripstone" -local molten_dripstone_great = "noordstar_dripstone:great_molten_dripstone" -local molten_dripstone_medium = "noordstar_dripstone:medium_molten_dripstone" -local molten_dripstone_small = "noordstar_dripstone:small_molten_dripstone" -local molten_dripstone_tiny = "noordstar_dripstone:tiny_molten_dripstone" -local molten_dripstone_spike = "noordstar_dripstone:molten_dripstone_spike" -local watered_dripstone_block = "noordstar_dripstone:watered_dripstone_block" -local watered_dripstone_huge = "noordstar_dripstone:huge_watered_dripstone" -local watered_dripstone_large = "noordstar_dripstone:large_watered_dripstone" -local watered_dripstone_great = "noordstar_dripstone:great_watered_dripstone" -local watered_dripstone_medium = "noordstar_dripstone:medium_watered_dripstone" -local watered_dripstone_small = "noordstar_dripstone:small_watered_dripstone" -local watered_dripstone_tiny = "noordstar_dripstone:tiny_watered_dripstone" -local watered_dripstone_spike = "noordstar_dripstone:watered_dripstone_spike" - -local internal = { - -- Nodes that the mod should consider as sources to extract water from - water_nodes = { - "default:river_water_source", - "default:water_source", - "mcl_core:water_source", - "mclx_core:river_water_source", - }, - - -- Nodes that the mod should consider as sources to extract lava from - lava_nodes = { - "default:lava_source", - "mcl_core:lava_source", - }, - - -- Nodes that can catch a lava droplet instead of letting a spike grow on top - lava_cauldrons = { - { from = dry_dripstone_spike, to = molten_dripstone_spike }, - }, - - -- Nodes that can catch a water droplet instead of letting a spike grow on top - water_cauldrons = { - { from = dry_dripstone_spike, to = watered_dripstone_spike }, - } -} - -function noordstar_dripstone.add_lava_source(nodename) - table.insert(internal.lava_nodes) -end -function noordstar_dripstone.add_water_source(nodename) - table.insert(internal.water_nodes, nodename) +local function load(name) + dofile(modpath.."/"..name..".lua") end -function noordstar_dripstone.add_lava_catcher(nodename, newnodename) - table.insert(internal.lava_cauldrons, { from = nodename, to = newnodename }) -end -function noordstar_dripstone.add_water_catcher(nodename, newnodename) - table.insert(internal.water_cauldrons, { from = nodename, to = newnodename }) -end +load("api") - --- Create a node box for any given dripstone size. --- Size 8 is a normal block size -local function nodebox_of_size(size) - if size >= 8 then - return nil - else - return { - type = "fixed", - fixed = { - { - size / 16, -0.5, - size / 16, size / 16, 0.5, size / 16 }, - }, - } - end -end - -local function drawtype_of_size(size) - if size >= 8 then - return "normal" - else - return "nodebox" - end -end - --- Sounds +-- Choose dripstone sounds local dripstone_sounds if minetest.get_modpath("mcl_sounds") then dripstone_sounds = mcl_sounds.node_sound_stone_defaults() end --- Trickle down config +-- Register droplet types +noordstar_dripstone.register_droplet("water") +noordstar_dripstone.register_droplet("lava") -local lava_trickle_down = { - { from = dry_dripstone_block, to = molten_dripstone_block }, - { from = dry_dripstone_huge, to = molten_dripstone_huge }, - { from = dry_dripstone_large, to = molten_dripstone_large }, - { from = dry_dripstone_great, to = molten_dripstone_great }, - { from = dry_dripstone_medium, to = molten_dripstone_medium }, - { from = dry_dripstone_small, to = molten_dripstone_small }, - { from = dry_dripstone_tiny, to = molten_dripstone_tiny }, - { from = dry_dripstone_spike, to = molten_dripstone_spike }, - { from = watered_dripstone_block, to = hardened_dripstone_block }, - { from = watered_dripstone_huge, to = hardened_dripstone_huge }, - { from = watered_dripstone_large, to = hardened_dripstone_large }, - { from = watered_dripstone_great, to = hardened_dripstone_great }, - { from = watered_dripstone_medium, to = hardened_dripstone_medium }, - { from = watered_dripstone_small, to = hardened_dripstone_small }, - { from = watered_dripstone_tiny, to = hardened_dripstone_tiny }, - { from = watered_dripstone_spike, to = hardened_dripstone_spike }, - { from = "air", to = dry_dripstone_spike }, -} -local water_trickle_down = { - { from = dry_dripstone_block, to = watered_dripstone_block }, - { from = dry_dripstone_huge, to = watered_dripstone_huge }, - { from = dry_dripstone_large, to = watered_dripstone_large }, - { from = dry_dripstone_great, to = watered_dripstone_great }, - { from = dry_dripstone_medium, to = watered_dripstone_medium }, - { from = dry_dripstone_small, to = watered_dripstone_small }, - { from = dry_dripstone_tiny, to = watered_dripstone_tiny }, - { from = dry_dripstone_spike, to = watered_dripstone_spike }, - { from = molten_dripstone_block, to = hardened_dripstone_block }, - { from = molten_dripstone_huge, to = hardened_dripstone_huge }, - { from = molten_dripstone_large, to = hardened_dripstone_large }, - { from = molten_dripstone_great, to = hardened_dripstone_great }, - { from = molten_dripstone_medium, to = hardened_dripstone_medium }, - { from = molten_dripstone_small, to = hardened_dripstone_small }, - { from = molten_dripstone_tiny, to = hardened_dripstone_tiny }, - { from = molten_dripstone_spike, to = hardened_dripstone_spike }, - { from = "air", to = dry_dripstone_spike }, -} - -local lava_trickle_down_spike = { - { from = dry_dripstone_block, to = molten_dripstone_block }, - { from = dry_dripstone_huge, to = molten_dripstone_huge }, - { from = dry_dripstone_large, to = molten_dripstone_large }, - { from = dry_dripstone_great, to = molten_dripstone_great }, - { from = dry_dripstone_medium, to = molten_dripstone_medium }, - { from = dry_dripstone_small, to = molten_dripstone_small }, - { from = dry_dripstone_tiny, to = molten_dripstone_tiny }, - { from = dry_dripstone_spike, to = molten_dripstone_spike }, - { from = watered_dripstone_block, to = hardened_dripstone_block }, - { from = watered_dripstone_huge, to = hardened_dripstone_huge }, - { from = watered_dripstone_large, to = hardened_dripstone_large }, - { from = watered_dripstone_great, to = hardened_dripstone_great }, - { from = watered_dripstone_medium, to = hardened_dripstone_medium }, - { from = watered_dripstone_small, to = hardened_dripstone_small }, - { from = watered_dripstone_tiny, to = hardened_dripstone_tiny }, - { from = watered_dripstone_spike, to = hardened_dripstone_spike }, -} -local water_trickle_down_spike = { - { from = dry_dripstone_block, to = watered_dripstone_block }, - { from = dry_dripstone_huge, to = watered_dripstone_huge }, - { from = dry_dripstone_large, to = watered_dripstone_large }, - { from = dry_dripstone_great, to = watered_dripstone_great }, - { from = dry_dripstone_medium, to = watered_dripstone_medium }, - { from = dry_dripstone_small, to = watered_dripstone_small }, - { from = dry_dripstone_tiny, to = watered_dripstone_tiny }, - { from = dry_dripstone_spike, to = watered_dripstone_spike }, - { from = molten_dripstone_block, to = hardened_dripstone_block }, - { from = molten_dripstone_huge, to = hardened_dripstone_huge }, - { from = molten_dripstone_large, to = hardened_dripstone_large }, - { from = molten_dripstone_great, to = hardened_dripstone_great }, - { from = molten_dripstone_medium, to = hardened_dripstone_medium }, - { from = molten_dripstone_small, to = hardened_dripstone_small }, - { from = molten_dripstone_tiny, to = hardened_dripstone_tiny }, - { from = molten_dripstone_spike, to = hardened_dripstone_spike }, -} - --- Tiles for dripstone - -local dry_dripstone_tiles = { - "noordstar_dripstone_dripstone_top.png", - "noordstar_dripstone_dripstone_top.png", - "noordstar_dripstone_dripstone_side.png", -} -local hardened_dripstone_tiles = { - "noordstar_dripstone_hardened_dripstone_top.png", - "noordstar_dripstone_hardened_dripstone_top.png", - "noordstar_dripstone_hardened_dripstone_side.png", -} -local molten_dripstone_tiles = { - "noordstar_dripstone_molten_dripstone_top.png", - "noordstar_dripstone_molten_dripstone_top.png", - "noordstar_dripstone_molten_dripstone_side.png", -} -local watered_dripstone_tiles = { - "noordstar_dripstone_watered_dripstone_top.png", - "noordstar_dripstone_watered_dripstone_top.png", - "noordstar_dripstone_watered_dripstone_side.png", -} - --- Register dripstone nodes - -local function make_dripstone(name, desc, longdesc, tiles, drop, size) - local sunlight_propagates = nil - if size < 8 then - sunlight_propagates = true - end - - minetest.register_node(name, { - description = desc, - _doc_items_longdesc = longdesc, - tiles = tiles, - groups = { - pickaxey=2, - material_stone=1, - fall_damage_add_percent = math.max(4 - size, 0) / 4 * 100 - }, - is_ground_content = true, - drop = { - max_items = math.floor((size + 1) / 2), - items = { - { rarity = 1 - , items = { drop } - }, - { rarity = 2 - , items = { drop } - }, - { rarity = 4 - , items = { drop } - }, - { rarity = 4 - , items = { drop } - }, - } - }, - sounds = dripstone_sounds, - drawtype = drawtype_of_size(size), - paramtype = "light", - sunlight_propagates = sunlight_propagates, - node_box = nodebox_of_size(size), - _mcl_hardness = 1.0 + size / 8, - _mcl_blast_resistance = 1 + size / 2, - _mcl_silk_touch_drop = true, - }) -end - --- BASE BLOCKS --- These blocks are able to absorb water or lava from above them. - -make_dripstone( - dry_dripstone_block, - "Dripstone block", - "Dripstone block that can suck up liquids above it and creates stalactites below it.", - dry_dripstone_tiles, - dry_dripstone_spike, - 8 -) -make_dripstone( - hardened_dripstone_block, - "Hardened dripstone block", - "Dripstone block that is no longer able to absorb liquids above it.", - hardened_dripstone_tiles, - dry_dripstone_spike, - 8 -) -make_dripstone( - molten_dripstone_block, - "Molten dripstone block", - "A dripstone block that has absorbed some lava, allowing it to form a stalactite.", - molten_dripstone_tiles, - dry_dripstone_spike, - 8 -) -make_dripstone( - watered_dripstone_block, - "Watered dripstone block", - "A dripstone block that has absorbed some water, allowing it to form a stalactite.", - watered_dripstone_tiles, - dry_dripstone_spike, - 8 -) - --- HUGE DRIPSTONE --- This is the largest form a non-block can get. - -make_dripstone( - dry_dripstone_huge, - "Huge dripstone", - "Dripstone in the largest shape it can reach.", - dry_dripstone_tiles, - dry_dripstone_spike, - 7 -) -make_dripstone( - hardened_dripstone_huge, - "Huge hardened dripstone", - "Dripstone in the largest shape it can reach. It is no longer able to grow or absorb liquids.", - hardened_dripstone_tiles, - hardened_dripstone_spike, - 7 -) -make_dripstone( - molten_dripstone_huge, - "Huge molten dripstone", - "Dripstone in the largest shape it can reach. It has absorbed some lava, but it can no longer grow in thickness.", - molten_dripstone_tiles, - dry_dripstone_spike, - 7 -) -make_dripstone( - watered_dripstone_huge, - "Huge watered dripstone", - "Dripstone in the largest shape it can reach. It has absorbed some water, but it can no longer grow in thickness.", - watered_dripstone_tiles, - dry_dripstone_spike, - 7 -) - --- LARGE DRIPSTONE - -make_dripstone( - dry_dripstone_large, - "Large dripstone", - "A thick layer of dripstone.", - dry_dripstone_tiles, - dry_dripstone_spike, - 6 -) -make_dripstone( - hardened_dripstone_large, - "Large hardened dripstone", - "A thick layer of dripstone. It is no longer able to grow or absorb liquids.", - hardened_dripstone_tiles, - hardened_dripstone_spike, - 6 -) -make_dripstone( - molten_dripstone_large, - "Large molten dripstone", - "A thick layer of dripstone. It has absorbed some lava, so it is able to grow in thickness.", - molten_dripstone_tiles, - dry_dripstone_spike, - 6 -) -make_dripstone( - watered_dripstone_large, - "Large watered dripstone", - "A thick layer of dripstone. It has absorbed some water, so it is able to grow in thickness.", - watered_dripstone_tiles, - dry_dripstone_spike, - 6 -) - --- GREAT DRIPSTONE - -make_dripstone( - dry_dripstone_great, - "Great dripstone", - "A thick layer of dripstone.", - dry_dripstone_tiles, - dry_dripstone_spike, - 5 -) -make_dripstone( - hardened_dripstone_great, - "Great hardened dripstone", - "A thick layer of dripstone. It is no longer able to grow or absorb liquids.", - hardened_dripstone_tiles, - hardened_dripstone_spike, - 5 -) -make_dripstone( - molten_dripstone_great, - "Great molten dripstone", - "A thick layer of dripstone. It has absorbed some lava, so it is able to grow in thickness.", - molten_dripstone_tiles, - dry_dripstone_spike, - 5 -) -make_dripstone( - watered_dripstone_great, - "Great watered dripstone", - "A thick layer of dripstone. It has absorbed some water, so it is able to grow in thickness.", - watered_dripstone_tiles, - dry_dripstone_spike, - 5 -) - --- MEDIUM DRIPSTONE - -make_dripstone( - dry_dripstone_medium, - "Medium dripstone", - "A thick layer of dripstone.", - dry_dripstone_tiles, - dry_dripstone_spike, - 4 -) -make_dripstone( - hardened_dripstone_medium, - "Medium hardened dripstone", - "A thick layer of dripstone. It is no longer able to grow or absorb liquids.", - hardened_dripstone_tiles, - hardened_dripstone_spike, - 4 -) -make_dripstone( - molten_dripstone_medium, - "Medium molten dripstone", - "A thick layer of dripstone. It has absorbed some lava, so it is able to grow in thickness.", - molten_dripstone_tiles, - dry_dripstone_spike, - 4 -) -make_dripstone( - watered_dripstone_medium, - "Medium watered dripstone", - "A thick layer of dripstone. It has absorbed some water, so it is able to grow in thickness.", - watered_dripstone_tiles, - dry_dripstone_spike, - 4 -) - --- SMALL DRIPSTONE - -make_dripstone( - dry_dripstone_small, - "Small dripstone", - "A thick layer of dripstone.", - dry_dripstone_tiles, - dry_dripstone_spike, - 3 -) -make_dripstone( - hardened_dripstone_small, - "Small hardened dripstone", - "A thick layer of dripstone. It is no longer able to grow or absorb liquids.", - hardened_dripstone_tiles, - hardened_dripstone_spike, - 3 -) -make_dripstone( - molten_dripstone_small, - "Small molten dripstone", - "A thick layer of dripstone. It has absorbed some lava, so it is able to grow in thickness.", - molten_dripstone_tiles, - dry_dripstone_spike, - 3 -) -make_dripstone( - watered_dripstone_small, - "Small watered dripstone", - "A thick layer of dripstone. It has absorbed some water, so it is able to grow in thickness.", - watered_dripstone_tiles, - dry_dripstone_spike, - 3 -) - --- TINY DRIPSTONE - -make_dripstone( - dry_dripstone_tiny, - "Tiny dripstone", - "A thick layer of dripstone.", - dry_dripstone_tiles, - dry_dripstone_spike, - 2 -) -make_dripstone( - hardened_dripstone_tiny, - "Tiny hardened dripstone", - "A thick layer of dripstone. It is no longer able to grow or absorb liquids.", - hardened_dripstone_tiles, - hardened_dripstone_spike, - 2 -) -make_dripstone( - molten_dripstone_tiny, - "Tiny molten dripstone", - "A thick layer of dripstone. It has absorbed some lava, so it is able to grow in thickness.", - molten_dripstone_tiles, - dry_dripstone_spike, - 2 -) -make_dripstone( - watered_dripstone_tiny, - "Tiny watered dripstone", - "A thick layer of dripstone. It has absorbed some water, so it is able to grow in thickness.", - watered_dripstone_tiles, - dry_dripstone_spike, - 2 -) - --- DRIPSTONE SPIKE - -make_dripstone( - dry_dripstone_spike, - "Dripstone spike", - "A thick layer of dripstone.", - dry_dripstone_tiles, - dry_dripstone_spike, - 1 -) -make_dripstone( - hardened_dripstone_spike, - "Hardened dripstone spike", - "A thick layer of dripstone. It is no longer able to grow or absorb liquids.", - hardened_dripstone_tiles, - hardened_dripstone_spike, - 1 -) -make_dripstone( - molten_dripstone_spike, - "Molten dripstone spike", - "A thick layer of dripstone. It has absorbed some lava, so it is able to grow in thickness.", - molten_dripstone_tiles, - dry_dripstone_spike, - 1 -) -make_dripstone( - watered_dripstone_spike, - "Watered dripstone spike", - "A thick layer of dripstone. It has absorbed some water, so it is able to grow in thickness.", - watered_dripstone_tiles, - dry_dripstone_spike, - 1 -) - --- ACTIONS - -local function absorb_liquid(pos, node, aoc, aocw) - local node_above = minetest.get_node(vector.offset(pos, 0, 1, 0)) or {} - local na_name = node_above.name - - for _, water in pairs(internal.water_nodes) do - if water == na_name then - -- Make block watery - node.name = watered_dripstone_block - minetest.set_node(pos, node) - return - end - end - - for _, lava in pairs(internal.lava_nodes) do - if lava == na_name then - -- Make block molten - node.name = molten_dripstone_block - minetest.set_node(pos, node) - return - end - end -end - -local function drop_down_to(options, dry_up_node_name) - return function(pos, node, aoc, aocw) - for i = 1, 25 do - local pos_rel = vector.offset(pos, 0, -i, 0) - local node_rel = minetest.get_node(pos_rel) or {} - local node_name = node_rel.name or "" - - if minetest.get_item_group(node_name, "air") ~= 0 then - -- Non-air node has been found! - -- Check if it reacts to the dripstone and if it can be - -- activated. - for _, option in pairs(options) do - if node_name == option.from then - node_rel.name = option.to - node.name = dry_up_node_name - - minetest.set_node(pos, node) - minetest.set_node(pos_rel, node_rel) - return - end - end - - -- The node cannot be changed and hence a new spike starts on top - -- of it. - if i > 1 then - pos_rel = vector.offset(pos, 0, 1-i, 0) - minetest.set_node(pos_rel, { name = dry_dripstone_spike }) - - node.name = dry_up_node_name - minetest.set_node(pos, node) - end - return - end - end - end -end - -local function grow_to(dry_grown_node_name) - return function(pos, node, aoc, aocw) - node.name = dry_grown_node_name - minetest.set_node(pos, node) - end -end - -local function harden(harden_nodes_func) - return function(pos, node, aoc, aocw) - local node_above = minetest.get_node(vector.offset(pos, 0, 1, 0)) or {} - local na_name = node_above.name - - for _, hardener in pairs(harden_nodes_func()) do - if hardener == na_name then - -- Harden dripstone block - node.name = hardened_dripstone_block - minetest.set_node(pos, node) - return - end - end - end -end - -local function trickle_down(options, dry_up_node_name) - return function(pos, node, aoc, aocw) - local pos_below = vector.offset(pos, 0, -1, 0) - local node_below = minetest.get_node(pos_below) or {} - local nb_name = node_below.name or "" - - for _, option in pairs(options) do - local expected_node_name = option.from or nil - local resulted_node_name = option.to - - if nb_name == expected_node_name then - node.name = dry_up_node_name - node_below.name = resulted_node_name - - minetest.set_node(pos, node) - minetest.set_node(pos_below, node_below) - return - end - end - end -end - -local function make_abm(nodename, expected_duration, action) - minetest.register_abm( - { nodenames = { nodename } - , interval = expected_duration / samples_per_interval - , chance = samples_per_interval - , catch_up = true - , action = action +-- Register dripstone types +noordstar_dripstone.register_dripstone("dry", { + sounds = dripstone_sounds, + tiles = { + "noordstar_dripstone_dripstone_top.png", + "noordstar_dripstone_dripstone_top.png", + "noordstar_dripstone_dripstone_side.png", + }, + on_droplet_receive = { + water = "watered", + lava = "molten", + }, +}) +noordstar_dripstone.register_dripstone("watered", { + drop = noordstar_dripstone.size_to_name("dry", 1), + grow_to = "dry", + on_droplet_receive = { + lava = "hardened", + }, + sounds = dripstone_sounds, + tiles = { + "noordstar_dripstone_watered_dripstone_top.png", + "noordstar_dripstone_watered_dripstone_top.png", + "noordstar_dripstone_watered_dripstone_side.png", + }, + trickle_down = "water", +}) +noordstar_dripstone.register_dripstone("molten", { + drop = noordstar_dripstone.size_to_name("dry", 1), + grow_to = "dry", + on_droplet_receive = { + water = "hardened", + }, + sounds = dripstone_sounds, + tiles = { + "noordstar_dripstone_molten_dripstone_top.png", + "noordstar_dripstone_molten_dripstone_top.png", + "noordstar_dripstone_molten_dripstone_side.png", + }, + trickle_down = "lava", + trickle_speed = 6, +}) +noordstar_dripstone.register_dripstone("hardened", { + sounds = dripstone_sounds, + tiles = { + "noordstar_dripstone_hardened_dripstone_top.png", + "noordstar_dripstone_hardened_dripstone_top.png", + "noordstar_dripstone_hardened_dripstone_side.png", } -) +}) + +-- Register droplet sources above dripstone blocks + +if minetest.get_modpath("default") then + noordstar_dripstone.add_droplet_source("water", "default:river_water_source") + noordstar_dripstone.add_droplet_source("water", "default:water_source") + noordstar_dripstone.add_droplet_source("lava", "default:lava_source") end --- ABSORB LIQUIDS - -make_abm(dry_dripstone_block, seconds_per_water_trickle, absorb_liquid) -make_abm(molten_dripstone_block, seconds_per_lava_trickle, harden(function () - return internal.water_nodes -end)) -make_abm(watered_dripstone_block, seconds_per_water_trickle, harden(function () - return internal.lava_nodes -end)) - --- TRICKLE DOWN - -make_abm(molten_dripstone_block, seconds_per_lava_trickle, trickle_down(lava_trickle_down, dry_dripstone_block)) -make_abm(watered_dripstone_block, seconds_per_water_trickle, trickle_down(water_trickle_down, dry_dripstone_block)) -make_abm(molten_dripstone_huge, seconds_per_lava_trickle, trickle_down(lava_trickle_down, dry_dripstone_huge)) -make_abm(watered_dripstone_huge, seconds_per_water_trickle, trickle_down(water_trickle_down, dry_dripstone_huge)) -make_abm(molten_dripstone_large, seconds_per_lava_trickle, trickle_down(lava_trickle_down, dry_dripstone_large)) -make_abm(watered_dripstone_large, seconds_per_water_trickle, trickle_down(water_trickle_down, dry_dripstone_large)) -make_abm(molten_dripstone_great, seconds_per_lava_trickle, trickle_down(lava_trickle_down, dry_dripstone_great)) -make_abm(watered_dripstone_great, seconds_per_water_trickle, trickle_down(water_trickle_down, dry_dripstone_great)) -make_abm(molten_dripstone_medium, seconds_per_lava_trickle, trickle_down(lava_trickle_down, dry_dripstone_medium)) -make_abm(watered_dripstone_medium, seconds_per_water_trickle, trickle_down(water_trickle_down, dry_dripstone_medium)) -make_abm(molten_dripstone_small, seconds_per_lava_trickle, trickle_down(lava_trickle_down, dry_dripstone_small)) -make_abm(watered_dripstone_small, seconds_per_water_trickle, trickle_down(water_trickle_down, dry_dripstone_small)) -make_abm(molten_dripstone_tiny, seconds_per_lava_trickle, trickle_down(lava_trickle_down, dry_dripstone_tiny)) -make_abm(watered_dripstone_tiny, seconds_per_water_trickle, trickle_down(water_trickle_down, dry_dripstone_tiny)) -make_abm(molten_dripstone_spike, seconds_per_lava_trickle, trickle_down(lava_trickle_down_spike, dry_dripstone_spike)) -make_abm(watered_dripstone_spike, seconds_per_water_trickle, trickle_down(water_trickle_down_spike, dry_dripstone_spike)) - --- GROW - -make_abm(molten_dripstone_large, seconds_per_growth*(14*14 - 12*12), grow_to(dry_dripstone_huge)) -make_abm(watered_dripstone_large, seconds_per_growth*(14*14 - 12*12), grow_to(dry_dripstone_huge)) -make_abm(molten_dripstone_great, seconds_per_growth*(12*12 - 10*10), grow_to(dry_dripstone_large)) -make_abm(watered_dripstone_great, seconds_per_growth*(12*12 - 10*10), grow_to(dry_dripstone_large)) -make_abm(molten_dripstone_medium, seconds_per_growth*(10*10 - 8*8), grow_to(dry_dripstone_great)) -make_abm(watered_dripstone_medium, seconds_per_growth*(10*10 - 8*8), grow_to(dry_dripstone_great)) -make_abm(molten_dripstone_small, seconds_per_growth*(8*8 - 6*6), grow_to(dry_dripstone_medium)) -make_abm(watered_dripstone_small, seconds_per_growth*(8*8 - 6*6), grow_to(dry_dripstone_medium)) -make_abm(molten_dripstone_tiny, seconds_per_growth*(6*6 - 4*4), grow_to(dry_dripstone_small)) -make_abm(watered_dripstone_tiny, seconds_per_growth*(6*6 - 4*4), grow_to(dry_dripstone_small)) -make_abm(molten_dripstone_spike, seconds_per_growth*(4*4 - 2*2), grow_to(dry_dripstone_tiny)) -make_abm(watered_dripstone_spike, seconds_per_growth*(4*4 - 2*2), grow_to(dry_dripstone_tiny)) - --- DROP DOWN - -make_abm(molten_dripstone_spike, seconds_per_lava_trickle, drop_down_to(internal.lava_cauldrons, dry_dripstone_spike)) -make_abm(watered_dripstone_spike, seconds_per_water_trickle, drop_down_to(internal.water_cauldrons, dry_dripstone_spike)) - --- CRATING RECIPES - -local function make_recipe(border, middle, output) - minetest.register_craft({ - output = output, - recipe = { - { border, border, border }, - { border, middle, border }, - { border, border, border }, - } - }) +if minetest.get_modpath("mcl_core") then + noordstar_dripstone.add_droplet_source("water", "mcl_core:water_source") + noordstar_dripstone.add_droplet_source("lava", "mcl_core:lava_source") end -make_recipe(dry_dripstone_spike, dry_dripstone_spike, dry_dripstone_tiny) -make_recipe(dry_dripstone_spike, dry_dripstone_tiny, dry_dripstone_small) -make_recipe(dry_dripstone_spike, dry_dripstone_small, dry_dripstone_medium) -make_recipe(dry_dripstone_spike, dry_dripstone_medium, dry_dripstone_great) -make_recipe(dry_dripstone_spike, dry_dripstone_great, dry_dripstone_large) -make_recipe(dry_dripstone_spike, dry_dripstone_large, dry_dripstone_huge) -make_recipe(hardened_dripstone_spike, hardened_dripstone_spike, hardened_dripstone_tiny) -make_recipe(hardened_dripstone_spike, hardened_dripstone_tiny, hardened_dripstone_small) -make_recipe(hardened_dripstone_spike, hardened_dripstone_small, hardened_dripstone_medium) -make_recipe(hardened_dripstone_spike, hardened_dripstone_medium, hardened_dripstone_great) -make_recipe(hardened_dripstone_spike, hardened_dripstone_great, hardened_dripstone_large) -make_recipe(hardened_dripstone_spike, hardened_dripstone_large, hardened_dripstone_huge) -make_recipe(molten_dripstone_spike, molten_dripstone_spike, molten_dripstone_tiny) -make_recipe(molten_dripstone_spike, molten_dripstone_tiny, molten_dripstone_small) -make_recipe(molten_dripstone_spike, molten_dripstone_small, molten_dripstone_medium) -make_recipe(molten_dripstone_spike, molten_dripstone_medium, molten_dripstone_great) -make_recipe(molten_dripstone_spike, molten_dripstone_great, molten_dripstone_large) -make_recipe(molten_dripstone_spike, molten_dripstone_large, molten_dripstone_huge) -make_recipe(watered_dripstone_spike, watered_dripstone_spike, watered_dripstone_tiny) -make_recipe(watered_dripstone_spike, watered_dripstone_tiny, watered_dripstone_small) -make_recipe(watered_dripstone_spike, watered_dripstone_small, watered_dripstone_medium) -make_recipe(watered_dripstone_spike, watered_dripstone_medium, watered_dripstone_great) -make_recipe(watered_dripstone_spike, watered_dripstone_great, watered_dripstone_large) -make_recipe(watered_dripstone_spike, watered_dripstone_large, watered_dripstone_huge) - -noordstar_dripstone.add_lava_catcher("mcl_cauldrons:cauldron", "mcl_cauldrons:cauldron_1_lava") -noordstar_dripstone.add_lava_catcher("mcl_cauldrons:cauldron_1_lava", "mcl_cauldrons:cauldron_2_lava") -noordstar_dripstone.add_lava_catcher("mcl_cauldrons:cauldron_2_lava", "mcl_cauldrons:cauldron_3_lava") - -noordstar_dripstone.add_water_catcher("mcl_cauldrons:cauldron", "mcl_cauldrons:cauldron_1") -noordstar_dripstone.add_water_catcher("mcl_cauldrons:cauldron_1", "mcl_cauldrons:cauldron_2") -noordstar_dripstone.add_water_catcher("mcl_cauldrons:cauldron_2", "mcl_cauldrons:cauldron_3") - if minetest.get_modpath("mclx_core") then - noordstar_dripstone.add_water_catcher("mcl_cauldrons:cauldron", "mcl_cauldrons:cauldron_1r") - noordstar_dripstone.add_water_catcher("mcl_cauldrons:cauldron_1r", "mcl_cauldrons:cauldron_2r") - noordstar_dripstone.add_water_catcher("mcl_cauldrons:cauldron_2r", "mcl_cauldrons:cauldron_3r") -end \ No newline at end of file + noordstar_dripstone.add_droplet_source("water", "mclx_core:river_water_source") +end