1
0
Fork 0

Reformat global & local functions

main
Bram van den Heuvel 2024-09-04 17:30:58 +02:00
parent ba500af72e
commit 2b33d45a60
3 changed files with 135 additions and 176 deletions

12
API.md
View File

@ -108,7 +108,7 @@ dripstone.register_droplet("mercury")
dripstone.register_droplet("mineral_water") dripstone.register_droplet("mineral_water")
``` ```
### dripstone.add_droplet_source(droplet, nodename) ### dripstone.register_source(droplet, nodename)
In order to let droplets stream down dripstone nodes, you need to define which In order to let droplets stream down dripstone nodes, you need to define which
nodes a full dripstone block can absorb liquid from. Absorbing liquid does not nodes a full dripstone block can absorb liquid from. Absorbing liquid does not
@ -120,10 +120,10 @@ However, you don't need to do this! You could use any node, as long as it has a
name. name.
```lua ```lua
dripstone.add_droplet_source("water", "mymod:swamp_water_source") dripstone.register_source("water", "mymod:swamp_water_source")
``` ```
### dripstone.add_droplet_catcher(droplet, oldnodename, newnodename) ### dripstone.register_catcher(droplet, oldnodename, newnodename)
Similarly, on the other side of the dripstone, you can create a catcher that Similarly, on the other side of the dripstone, you can create a catcher that
can catch any of the liquid drops dripping down. You can use this to create can catch any of the liquid drops dripping down. You can use this to create
@ -131,9 +131,9 @@ orchids, or to create other interactions with nodes that might change from a
tiny bit of liquid. tiny bit of liquid.
```lua ```lua
dripstone.add_droplet_catcher("water", "mymod:cauldron_empty", "mymod:water_cauldron") dripstone.register_catcher("water", "mymod:cauldron_empty", "mymod:water_cauldron")
dripstone.add_droplet_catcher("water", "mymod:dirt", "mymod:farmland") dripstone.register_catcher("water", "mymod:dirt", "mymod:farmland")
dripstone.add_droplet_catcher("lava", "mymod:precious_orchid", "mymod:dead_bush") dripstone.register_catcher("lava", "mymod:precious_orchid", "mymod:dead_bush")
``` ```
### dripstone.register_dripstone(flavor, def) ### dripstone.register_dripstone(flavor, def)

259
api.lua
View File

@ -1,150 +1,80 @@
dripstone = {} -- Nodes that function as cauldrons
local CAULDRONS = {}
-- 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 -- How many nodes downwards a droplet is able to drop from a stalactite
-- before the droplet evaporates. -- before the droplet evaporates.
drop_down_reach = 50, local DROP_DOWN_REACH = 50
-- The number of seconds it takes for a dripstone node to grow 1 unit -- The number of seconds it takes for a dripstone node to grow 1 unit
-- (NOTE: Not one node size! One unit, which quadratically increases -- (NOTE: Not one node size! One unit, which quadratically increases
-- per node size.) -- per node size.)
growth_factor = 3, local GROWTH_FACTOR = 3
-- This mod's name. -- This mod's name.
modname = minetest.get_current_modname(), local MODNAME = minetest.get_current_modname()
-- The number of samples that each ABM should execute. -- The number of samples that each ABM should execute.
-- Make sure this is a whole number and less than speed_factor. -- Make sure this is a whole number and less than speed_factor.
samples_per_interval = 30, local SAMPLES_PER_INTERVAL = 30
-- Nodes that provide droplets
local SOURCES = {}
-- Factor deciding this mod's relative speed. -- Factor deciding this mod's relative speed.
-- Set this value to 1 if you wish to debug and let the dripstone -- Set this value to 1 if you wish to debug and let the dripstone
-- change rapidly. -- change rapidly.
-- Rule of thumb: with a setting of 60, it takes a lava farm about 30 -- Rule of thumb: with a setting of 60, it takes a lava farm about 30
-- minutes to fill a cauldron with lava. -- minutes to fill a cauldron with lava.
speed_factor = 60, local 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 -- Nodes that allow a droplet to trickle down if it is directly below a
-- node that passes down that droplet. -- node that passes down that droplet.
tricklers = {}, local TRICKLERS = {}
-- Names of the various dripstone widths
local WIDTH_NAMES = {
"spike", "tiny", "small", "medium", "great", "large", "huge", "block",
} }
------------------------------------------------------------------------------- -------------------------------------------------------------------------------
------------------------------------------------------------------------------- -------------------------------------------------------------------------------
--------------------------- PUBLIC API -------------------------------- -------------------------------------------------------------------------------
------------------------------------------------------------------------------- -------------------------------------------------------------------------------
------------------------------------------------------------------------------- -------------------------------------------------------------------------------
-- Register a node that can catch a droplet from a dripstone stalactite. -- Internal table that lets us define functions without directly exposing them.
function dripstone.add_droplet_catcher(droplet, oldnodename, newnodename) local internal = {}
return internal.add_droplet_catcher(droplet, oldnodename, newnodename)
end
-- Register a new source node that can provide droplets to dripstone blocks.
function 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 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 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 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 -- Add a droplet catcher, which is a node that allows a stalactite spike to
-- change the name using a droplet. -- change the name using a droplet.
function internal.add_droplet_catcher(droplet, oldnodename, newnodename) function internal.register_droplet_catcher(droplet, oldnodename, newnodename)
return internal.register_cauldron(droplet, oldnodename, newnodename) if CAULDRONS[droplet] == nil then
end
function internal.add_droplet_source(droplet, nodename)
if internal.sources[droplet] == nil then
internal.uninitialized_droplet_error(droplet) internal.uninitialized_droplet_error(droplet)
end end
table.insert(internal.sources[droplet], nodename)
CAULDRONS[droplet][oldnodename] = newnodename
end
function internal.register_droplet_source(droplet, nodename)
if SOURCES[droplet] == nil then
internal.uninitialized_droplet_error(droplet)
end
table.insert(SOURCES[droplet], nodename)
-- If the node can emit an infinite number of droplets,
-- it can also absorb an infinite number of droplets.
internal.register_droplet_catcher(droplet, oldnodename, newnodename)
end end
-- Add a droplet trickler, which is a dripstone node that allows a droplet to -- Add a droplet trickler, which is a dripstone node that allows a droplet to
-- be trickled down from the node directly above it. -- be trickled down from the node directly above it.
-- Running this function overrides previous values. -- Running this function overrides previous values.
function internal.add_droplet_trickler(droplet, oldnodename, newnodename) function internal.add_droplet_trickler(droplet, oldnodename, newnodename)
if internal.tricklers[droplet] == nil then if TRICKLERS[droplet] == nil then
internal.uninitialized_droplet_error(droplet) internal.uninitialized_droplet_error(droplet)
end end
internal.tricklers[droplet][oldnodename] = newnodename TRICKLERS[droplet][oldnodename] = newnodename
end end
-- Capitalize a string -- Capitalize a string
@ -161,7 +91,7 @@ function internal.drawtype_of_size(size)
end end
function internal.hit_with_droplet(pos, node, droplet, spikename) function internal.hit_with_droplet(pos, node, droplet, spikename)
local m = internal.cauldrons[droplet] or {} local m = CAULDRONS[droplet] or {}
if m[node.name] == nil then if m[node.name] == nil then
-- Not a cauldron! Therefore we place a spike on top. -- Not a cauldron! Therefore we place a spike on top.
@ -202,14 +132,14 @@ end
function internal.register_absorb_abm(droplet, oldnodename, newnodename) function internal.register_absorb_abm(droplet, oldnodename, newnodename)
minetest.register_abm({ minetest.register_abm({
nodenames = { oldnodename }, nodenames = { oldnodename },
interval = internal.constant.speed_factor / internal.constant.samples_per_interval, interval = SPEED_FACTOR / SAMPLES_PER_INTERVAL,
chance = internal.constant.samples_per_interval, chance = SAMPLES_PER_INTERVAL,
catch_up = true, catch_up = true,
action = function (pos, node, aoc, aocw) action = function(pos, node)
local pos_above = vector.offset(pos, 0, 1, 0) local pos_above = vector.offset(pos, 0, 1, 0)
local node_above = minetest.get_node(pos_above) local node_above = minetest.get_node(pos_above)
for _, source in pairs(internal.sources[droplet] or {}) do for _, source in pairs(SOURCES[droplet] or {}) do
if node_above.name == source then if node_above.name == source then
node.name = newnodename node.name = newnodename
minetest.set_node(pos, node) minetest.set_node(pos, node)
@ -220,14 +150,6 @@ function internal.register_absorb_abm(droplet, oldnodename, newnodename)
}) })
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) function internal.register_dripstone_craft(newnodename, oldnodename, spikename)
minetest.register_craft({ minetest.register_craft({
output = newnodename, output = newnodename,
@ -276,9 +198,26 @@ function internal.register_dripstone_flavor(flavor, def)
end end
end end
-- Allow spike stalagmites to catch droplets -- 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.register_droplet_catcher(
trickl,
internal.size_to_name(flavor, 1),
internal.size_to_name(flavor, 1)
)
-- Allow spike stalagmites to catch droplets.
-- This feature can override the former safeguard.
for droplet, new_flavor in pairs(on_droplet_receive) do for droplet, new_flavor in pairs(on_droplet_receive) do
internal.register_cauldron( internal.register_droplet_catcher(
droplet, droplet,
internal.size_to_name(flavor, 1), internal.size_to_name(flavor, 1),
internal.size_to_name(new_flavor, 1) internal.size_to_name(new_flavor, 1)
@ -327,22 +266,6 @@ function internal.register_dripstone_flavor(flavor, def)
internal.size_to_name(dry_up, 1), internal.size_to_name(dry_up, 1),
trickle_speed 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
end end
@ -387,10 +310,10 @@ end
function internal.register_drop_down_abm(droplet, spikename, dryspikename, trickle_speed) function internal.register_drop_down_abm(droplet, spikename, dryspikename, trickle_speed)
minetest.register_abm({ minetest.register_abm({
nodenames = { spikename }, nodenames = { spikename },
interval = trickle_speed * internal.constant.speed_factor / internal.constant.samples_per_interval, interval = trickle_speed * SPEED_FACTOR / SAMPLES_PER_INTERVAL,
chance = internal.constant.samples_per_interval, chance = SAMPLES_PER_INTERVAL,
catch_up = true, catch_up = true,
action = function (pos, node, aoc, aocw) action = function(pos, node)
local pos_below = vector.offset(pos, 0, -1, 0) local pos_below = vector.offset(pos, 0, -1, 0)
local node_below = minetest.get_node(pos_below) local node_below = minetest.get_node(pos_below)
@ -399,7 +322,7 @@ function internal.register_drop_down_abm(droplet, spikename, dryspikename, trick
return return
end end
for dy = 2, internal.constant.drop_down_reach, 1 do for dy = 2, DROP_DOWN_REACH, 1 do
pos_below = vector.offset(pos, 0, -dy, 0) pos_below = vector.offset(pos, 0, -dy, 0)
node_below = minetest.get_node(pos_below) node_below = minetest.get_node(pos_below)
@ -421,14 +344,27 @@ function internal.register_drop_down_abm(droplet, spikename, dryspikename, trick
}) })
end end
-- Register a new droplet type that can be absorbed and passed on by dripstone.
function internal.register_droplet(droplet)
if CAULDRONS[droplet] == nil then
CAULDRONS[droplet] = {}
end
if SOURCES[droplet] == nil then
SOURCES[droplet] = {}
end
if TRICKLERS[droplet] == nil then
TRICKLERS[droplet] = {}
end
end
function internal.register_grow_abm(oldnodename, newnodename, width) function internal.register_grow_abm(oldnodename, newnodename, width)
minetest.register_abm({ minetest.register_abm({
nodenames = { oldnodename }, nodenames = { oldnodename },
-- 2(w + 1) * 2(w + 1) - 2w * 2w = 8w + 4 -- 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, interval = (8 * width + 4) * SPEED_FACTOR * GROWTH_FACTOR / SAMPLES_PER_INTERVAL,
chance = internal.constant.samples_per_interval, chance = SAMPLES_PER_INTERVAL,
catch_up = true, catch_up = true,
action = function (pos, node, aoc, aocw) action = function(pos, node)
node.name = newnodename node.name = newnodename
minetest.set_node(pos, node) minetest.set_node(pos, node)
end end
@ -438,14 +374,14 @@ end
function internal.register_trickle_down_abm(droplet, width, old_source, new_source, dry_up, trickle_speed) function internal.register_trickle_down_abm(droplet, width, old_source, new_source, dry_up, trickle_speed)
minetest.register_abm({ minetest.register_abm({
nodenames = { old_source }, nodenames = { old_source },
interval = trickle_speed * internal.constant.speed_factor / internal.constant.samples_per_interval, interval = trickle_speed * SPEED_FACTOR / SAMPLES_PER_INTERVAL,
chance = internal.constant.samples_per_interval, chance = SAMPLES_PER_INTERVAL,
catch_up = true, catch_up = true,
action = function (pos, node, aoc, aocw) action = function(pos, node)
local pos_below = vector.offset(pos, 0, -1, 0) local pos_below = vector.offset(pos, 0, -1, 0)
local node_below = minetest.get_node(pos_below) local node_below = minetest.get_node(pos_below)
local m = internal.tricklers[droplet] or {} local m = TRICKLERS[droplet] or {}
if m[node_below.name] ~= nil then if m[node_below.name] ~= nil then
-- Trickler found below! -- Trickler found below!
@ -465,7 +401,7 @@ function internal.register_trickle_down_abm(droplet, width, old_source, new_sour
end end
function internal.size_to_description(flavor, size) function internal.size_to_description(flavor, size)
local width_name = internal.constant.width_names[size] local width_name = WIDTH_NAMES[size]
if size == 1 or size == 8 then if size == 1 or size == 8 then
return internal.capitalize(flavor) .. " dripstone " .. width_name return internal.capitalize(flavor) .. " dripstone " .. width_name
@ -475,8 +411,8 @@ function internal.size_to_description(flavor, size)
end end
function internal.size_to_name(flavor, size) function internal.size_to_name(flavor, size)
local namespace = internal.constant.modname .. ":" local namespace = MODNAME .. ":"
local width_name = internal.constant.width_names[size] local width_name = WIDTH_NAMES[size]
if size == 1 or size == 8 then if size == 1 or size == 8 then
return namespace .. flavor .. "_dripstone_" .. width_name return namespace .. flavor .. "_dripstone_" .. width_name
@ -490,3 +426,26 @@ function internal.uninitialized_droplet_error(droplet)
"Droplet " .. droplet .. " has not been initialized yet!" "Droplet " .. droplet .. " has not been initialized yet!"
) )
end end
-------------------------------------------------------------------------------
-------------------------------------------------------------------------------
--------------------------- PUBLIC API --------------------------------
-------------------------------------------------------------------------------
-------------------------------------------------------------------------------
dripstone = {
-- Register a node that can catch a droplet from a dripstone stalactite.
register_catcher = internal.register_droplet_catcher,
-- Register a new dripstone type.
register_dripstone = internal.register_dripstone_flavor,
-- Register a new droplet type that can be absorbed and passed on by dripstone.
register_droplet = internal.register_droplet,
-- Register a source node that can provide droplets to dripstone blocks.
register_source = internal.register_droplet_source,
-- Get a dripstone's node name based on its flavor and size.
size_to_name = internal.size_to_name,
}

View File

@ -72,16 +72,16 @@ dripstone.register_dripstone("hardened", {
-- Register droplet sources above dripstone blocks -- Register droplet sources above dripstone blocks
if minetest.get_modpath("default") then if minetest.get_modpath("default") then
dripstone.add_droplet_source("water", "default:river_water_source") dripstone.register_source("water", "default:river_water_source")
dripstone.add_droplet_source("water", "default:water_source") dripstone.register_source("water", "default:water_source")
dripstone.add_droplet_source("lava", "default:lava_source") dripstone.register_source("lava", "default:lava_source")
end end
if minetest.get_modpath("mcl_core") then if minetest.get_modpath("mcl_core") then
dripstone.add_droplet_source("water", "mcl_core:water_source") dripstone.register_source("water", "mcl_core:water_source")
dripstone.add_droplet_source("lava", "mcl_core:lava_source") dripstone.register_source("lava", "mcl_core:lava_source")
end end
if minetest.get_modpath("mclx_core") then if minetest.get_modpath("mclx_core") then
dripstone.add_droplet_source("water", "mclx_core:river_water_source") dripstone.register_source("water", "mclx_core:river_water_source")
end end