1
0
Fork 0

Refactor: make dripstone less repetitive

main
Bram van den Heuvel 2024-09-03 23:03:25 +02:00
parent 4746e121e6
commit b7af84645a
2 changed files with 562 additions and 743 deletions

492
api.lua Normal file
View File

@ -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 = <standard sound definition for a node>
--
-- -- Node tiles for layout
-- tiles = <node tile layout>
--
-- -- 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

811
init.lua
View File

@ -1,760 +1,87 @@
noordstar_dripstone = {} -- Load dripstone API
-- Constants local modpath = minetest.get_modpath(minetest.get_current_modname())
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
-- Namespaced node names local function load(name)
local dry_dripstone_block = "noordstar_dripstone:dripstone_block" dofile(modpath.."/"..name..".lua")
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)
end end
function noordstar_dripstone.add_lava_catcher(nodename, newnodename) load("api")
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
-- Choose dripstone sounds
-- 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
local dripstone_sounds local dripstone_sounds
if minetest.get_modpath("mcl_sounds") then if minetest.get_modpath("mcl_sounds") then
dripstone_sounds = mcl_sounds.node_sound_stone_defaults() dripstone_sounds = mcl_sounds.node_sound_stone_defaults()
end end
-- Trickle down config -- Register droplet types
noordstar_dripstone.register_droplet("water")
noordstar_dripstone.register_droplet("lava")
local lava_trickle_down = { -- Register dripstone types
{ from = dry_dripstone_block, to = molten_dripstone_block }, noordstar_dripstone.register_dripstone("dry", {
{ from = dry_dripstone_huge, to = molten_dripstone_huge }, sounds = dripstone_sounds,
{ from = dry_dripstone_large, to = molten_dripstone_large }, tiles = {
{ from = dry_dripstone_great, to = molten_dripstone_great }, "noordstar_dripstone_dripstone_top.png",
{ from = dry_dripstone_medium, to = molten_dripstone_medium }, "noordstar_dripstone_dripstone_top.png",
{ from = dry_dripstone_small, to = molten_dripstone_small }, "noordstar_dripstone_dripstone_side.png",
{ from = dry_dripstone_tiny, to = molten_dripstone_tiny }, },
{ from = dry_dripstone_spike, to = molten_dripstone_spike }, on_droplet_receive = {
{ from = watered_dripstone_block, to = hardened_dripstone_block }, water = "watered",
{ from = watered_dripstone_huge, to = hardened_dripstone_huge }, lava = "molten",
{ from = watered_dripstone_large, to = hardened_dripstone_large }, },
{ from = watered_dripstone_great, to = hardened_dripstone_great }, })
{ from = watered_dripstone_medium, to = hardened_dripstone_medium }, noordstar_dripstone.register_dripstone("watered", {
{ from = watered_dripstone_small, to = hardened_dripstone_small }, drop = noordstar_dripstone.size_to_name("dry", 1),
{ from = watered_dripstone_tiny, to = hardened_dripstone_tiny }, grow_to = "dry",
{ from = watered_dripstone_spike, to = hardened_dripstone_spike }, on_droplet_receive = {
{ from = "air", to = dry_dripstone_spike }, lava = "hardened",
} },
local water_trickle_down = { sounds = dripstone_sounds,
{ from = dry_dripstone_block, to = watered_dripstone_block }, tiles = {
{ from = dry_dripstone_huge, to = watered_dripstone_huge }, "noordstar_dripstone_watered_dripstone_top.png",
{ from = dry_dripstone_large, to = watered_dripstone_large }, "noordstar_dripstone_watered_dripstone_top.png",
{ from = dry_dripstone_great, to = watered_dripstone_great }, "noordstar_dripstone_watered_dripstone_side.png",
{ from = dry_dripstone_medium, to = watered_dripstone_medium }, },
{ from = dry_dripstone_small, to = watered_dripstone_small }, trickle_down = "water",
{ from = dry_dripstone_tiny, to = watered_dripstone_tiny }, })
{ from = dry_dripstone_spike, to = watered_dripstone_spike }, noordstar_dripstone.register_dripstone("molten", {
{ from = molten_dripstone_block, to = hardened_dripstone_block }, drop = noordstar_dripstone.size_to_name("dry", 1),
{ from = molten_dripstone_huge, to = hardened_dripstone_huge }, grow_to = "dry",
{ from = molten_dripstone_large, to = hardened_dripstone_large }, on_droplet_receive = {
{ from = molten_dripstone_great, to = hardened_dripstone_great }, water = "hardened",
{ from = molten_dripstone_medium, to = hardened_dripstone_medium }, },
{ from = molten_dripstone_small, to = hardened_dripstone_small }, sounds = dripstone_sounds,
{ from = molten_dripstone_tiny, to = hardened_dripstone_tiny }, tiles = {
{ from = molten_dripstone_spike, to = hardened_dripstone_spike }, "noordstar_dripstone_molten_dripstone_top.png",
{ from = "air", to = dry_dripstone_spike }, "noordstar_dripstone_molten_dripstone_top.png",
} "noordstar_dripstone_molten_dripstone_side.png",
},
local lava_trickle_down_spike = { trickle_down = "lava",
{ from = dry_dripstone_block, to = molten_dripstone_block }, trickle_speed = 6,
{ from = dry_dripstone_huge, to = molten_dripstone_huge }, })
{ from = dry_dripstone_large, to = molten_dripstone_large }, noordstar_dripstone.register_dripstone("hardened", {
{ from = dry_dripstone_great, to = molten_dripstone_great }, sounds = dripstone_sounds,
{ from = dry_dripstone_medium, to = molten_dripstone_medium }, tiles = {
{ from = dry_dripstone_small, to = molten_dripstone_small }, "noordstar_dripstone_hardened_dripstone_top.png",
{ from = dry_dripstone_tiny, to = molten_dripstone_tiny }, "noordstar_dripstone_hardened_dripstone_top.png",
{ from = dry_dripstone_spike, to = molten_dripstone_spike }, "noordstar_dripstone_hardened_dripstone_side.png",
{ 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 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 end
-- ABSORB LIQUIDS if minetest.get_modpath("mcl_core") then
noordstar_dripstone.add_droplet_source("water", "mcl_core:water_source")
make_abm(dry_dripstone_block, seconds_per_water_trickle, absorb_liquid) noordstar_dripstone.add_droplet_source("lava", "mcl_core:lava_source")
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 },
}
})
end 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 if minetest.get_modpath("mclx_core") then
noordstar_dripstone.add_water_catcher("mcl_cauldrons:cauldron", "mcl_cauldrons:cauldron_1r") noordstar_dripstone.add_droplet_source("water", "mclx_core:river_water_source")
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 end