2021-09-24 21:49:05 -04:00
|
|
|
local UPDATE_INTERVAL =
|
|
|
|
tonumber(minetest.settings:get("large_slugs_update_interval")) or 5
|
|
|
|
local UPDATE_CHANCE =
|
|
|
|
tonumber(minetest.settings:get("large_slugs_update_chance")) or 5
|
2021-09-24 10:30:37 -04:00
|
|
|
local BIRTH_CHANCE =
|
2021-09-24 21:49:05 -04:00
|
|
|
tonumber(minetest.settings:get("large_slugs_birth_chance")) or 5
|
2021-09-24 10:30:37 -04:00
|
|
|
local BIRTH_SPACE =
|
|
|
|
tonumber(minetest.settings:get("large_slugs_birth_space")) or 11
|
|
|
|
|
2021-09-24 21:49:05 -04:00
|
|
|
-- With the given vectors, computes a = b + c.
|
|
|
|
local function set_add(a, b, c)
|
|
|
|
a.x = b.x + c.x
|
|
|
|
a.y = b.y + c.y
|
|
|
|
a.z = b.z + c.z
|
|
|
|
end
|
|
|
|
|
|
|
|
-- A map of wallmounted directions to their perpendicular directions.
|
2021-09-24 10:30:37 -04:00
|
|
|
local WALLMOUNT_TO_PERP_WALLMOUNTS = {}
|
|
|
|
WALLMOUNT_TO_PERP_WALLMOUNTS[0] = {4, 2, 5, 3}
|
|
|
|
WALLMOUNT_TO_PERP_WALLMOUNTS[2] = {4, 0, 5, 1}
|
|
|
|
WALLMOUNT_TO_PERP_WALLMOUNTS[4] = {2, 0, 3, 1}
|
|
|
|
WALLMOUNT_TO_PERP_WALLMOUNTS[1] = WALLMOUNT_TO_PERP_WALLMOUNTS[0]
|
|
|
|
WALLMOUNT_TO_PERP_WALLMOUNTS[3] = WALLMOUNT_TO_PERP_WALLMOUNTS[2]
|
|
|
|
WALLMOUNT_TO_PERP_WALLMOUNTS[5] = WALLMOUNT_TO_PERP_WALLMOUNTS[4]
|
|
|
|
|
2021-09-24 21:49:05 -04:00
|
|
|
-- A map of wallmounted directions to their opposites.
|
2021-09-24 10:30:37 -04:00
|
|
|
local WALLMOUNT_TO_OPP_WALLMOUNT = {
|
|
|
|
[0] = 1, [1] = 0, [2] = 3, [3] = 2, [4] = 5, [5] = 4,
|
|
|
|
}
|
|
|
|
|
2021-09-24 21:49:05 -04:00
|
|
|
-- The numbers added to movement added wallmounted values to identify the type
|
|
|
|
-- of movement:
|
|
|
|
-- 1. Shifting to an adjacent node without rotation.
|
|
|
|
-- 2. Rotating to attach to a different node around the same position.
|
|
|
|
-- 3. Rotating around the node to which the slug is attached.
|
|
|
|
local SHIFT = 32
|
|
|
|
local ROTATE = 64
|
|
|
|
local SHIFT_ROTATE = 96
|
2021-09-24 10:30:37 -04:00
|
|
|
|
2021-09-24 21:49:05 -04:00
|
|
|
-- These are kept around to save a few allocations, probably negligible.
|
|
|
|
local opts = {}
|
|
|
|
local check_pos = {}
|
2021-09-24 10:30:37 -04:00
|
|
|
|
2021-09-24 21:49:05 -04:00
|
|
|
-- Update a slug, randomly trying to either move it or have it give birth.
|
|
|
|
local function update_slug(pos, node)
|
|
|
|
local def = large_slugs.registered_slugs[node.name]
|
|
|
|
if not def then return end
|
2021-09-24 10:30:37 -04:00
|
|
|
|
2021-09-24 21:49:05 -04:00
|
|
|
local old_wallmount = node.param2
|
|
|
|
local old_dir = minetest.wallmounted_to_dir(old_wallmount)
|
|
|
|
if not old_dir then return end
|
2021-09-24 10:30:37 -04:00
|
|
|
|
2021-09-24 21:49:05 -04:00
|
|
|
-- Determine whether this is a move or a birth (births require an empty
|
|
|
|
-- area around the parent):
|
|
|
|
local move = math.random(BIRTH_CHANCE) < BIRTH_CHANCE or
|
|
|
|
minetest.find_node_near(pos, BIRTH_SPACE, node.name) ~= nil
|
|
|
|
|
|
|
|
-- Scan for options, looking in directions perpendicular to the current
|
|
|
|
-- wallmounted direction of the node.
|
|
|
|
local n_opts = 0
|
|
|
|
local perp_wallmounts = WALLMOUNT_TO_PERP_WALLMOUNTS[old_wallmount]
|
|
|
|
for _, perp_wallmount in ipairs(perp_wallmounts) do
|
|
|
|
set_add(check_pos,
|
|
|
|
pos, minetest.wallmounted_to_dir(perp_wallmount))
|
2021-09-24 10:30:37 -04:00
|
|
|
local check_node = minetest.get_node(check_pos)
|
2021-09-24 21:49:05 -04:00
|
|
|
if move and def.ground[check_node.name] then
|
|
|
|
n_opts = n_opts + 1
|
|
|
|
opts[n_opts] = perp_wallmount + ROTATE
|
2021-09-24 10:30:37 -04:00
|
|
|
elseif check_node.name == "air" then
|
2021-09-24 21:49:05 -04:00
|
|
|
set_add(check_pos, check_pos, old_dir)
|
2021-09-24 10:30:37 -04:00
|
|
|
check_node = minetest.get_node(check_pos)
|
2021-09-24 21:49:05 -04:00
|
|
|
if def.ground[check_node.name] then
|
|
|
|
n_opts = n_opts + 1
|
|
|
|
opts[n_opts] = perp_wallmount + SHIFT
|
2021-09-24 10:30:37 -04:00
|
|
|
elseif check_node.name == "air" then
|
2021-09-24 21:49:05 -04:00
|
|
|
n_opts = n_opts + 1
|
|
|
|
opts[n_opts] = perp_wallmount + SHIFT_ROTATE
|
2021-09-24 10:30:37 -04:00
|
|
|
end
|
|
|
|
end
|
|
|
|
end
|
|
|
|
|
|
|
|
if n_opts < 1 then return end
|
|
|
|
|
2021-09-24 21:49:05 -04:00
|
|
|
-- Choose one of the options and move in the way it specifies.
|
|
|
|
local chosen = opts[math.random(n_opts)]
|
|
|
|
local new_wallmount = chosen % 8
|
|
|
|
local chosen_type = chosen - new_wallmount
|
|
|
|
if chosen_type == SHIFT then
|
|
|
|
if move then minetest.remove_node(pos) end
|
|
|
|
set_add(pos, pos, minetest.wallmounted_to_dir(new_wallmount))
|
|
|
|
minetest.set_node(pos, node)
|
|
|
|
elseif chosen_type == ROTATE then
|
|
|
|
node.param2 = new_wallmount
|
|
|
|
minetest.swap_node(pos, node)
|
|
|
|
else -- SHIFT_ROTATE
|
|
|
|
if move then minetest.remove_node(pos) end
|
|
|
|
set_add(pos, pos, minetest.wallmounted_to_dir(new_wallmount))
|
|
|
|
set_add(pos, pos, old_dir)
|
|
|
|
node.param2 = WALLMOUNT_TO_OPP_WALLMOUNT[new_wallmount]
|
|
|
|
minetest.set_node(pos, node)
|
2021-09-24 10:30:37 -04:00
|
|
|
end
|
|
|
|
end
|
|
|
|
|
|
|
|
minetest.register_abm({
|
2021-09-24 21:49:05 -04:00
|
|
|
label = "Slugs updating",
|
2021-09-24 10:30:37 -04:00
|
|
|
nodenames = "group:large_slug",
|
2021-09-24 21:49:05 -04:00
|
|
|
interval = UPDATE_INTERVAL,
|
|
|
|
chance = UPDATE_CHANCE,
|
2021-09-24 10:30:37 -04:00
|
|
|
catch_up = false,
|
2021-09-24 21:49:05 -04:00
|
|
|
action = update_slug,
|
2021-09-24 10:30:37 -04:00
|
|
|
})
|