firefly/mods/firefly_base/init.lua
2026-02-14 12:37:11 -05:00

236 lines
5.9 KiB
Lua

-- Enable Minetest forever.
minetest = core
firefly = {
-- Set to `true` to enable testing admin things without having to open a server.
singleplayer_admin = true
}
local ns = firefly
function include(file)
return dofile(minetest.get_modpath(minetest.get_current_modname()).."/"..file)
end
function enum(cases)
local out = {}
local i = 0
for _, x in ipairs(cases) do
out[x] = i
i = i +1
end
return out
end
say = minetest.chat_send_all
function extend(dst, src)
for k, v in pairs(src) do
dst[k] = v
end
return dst
end
Promise = {
resolve = function(e, ...)
if e.resolved then return end
e.resolved = true
if e._after then e._after(...) end
end,
after = function(e, fn)
e._after = fn
end
}
Promise.__index = Promise
setmetatable(Promise, {
__call = function(_, fn)
local e = {resolved = false}
setmetatable(e, Promise)
fn(function(...) e:resolve(...) end)
return e
end
})
EventTarget = {
init = function()
local e = {
listeners = {}
}
return setmetatable(e, EventTarget)
end,
listen = function(e, channel, fn)
if not e.listeners[channel] then e.listeners[channel] = {} end
local l = e.listeners[channel]
l[#l +1] = fn
end,
unlisten = function(e, channel, fn)
if not e.listeners[channel] then return end
local l = e.listeners[channel]
local idx = table.indexof(l, fn)
if idx < 0 then return end
table.remove(l, idx)
end,
dispatch = function(e, channel, ...)
local l = e.listeners[channel]
if not l then return end
for i = 1, #l do
l[i](...)
end
end
}
EventTarget.__index = EventTarget
setmetatable(EventTarget, {
__call = function(_, ...) return EventTarget.init(...) end
})
-- HACK: Lookup table for getting a rotation from a
-- facedir (because Minetest doesn't have any way
-- to get this information normally).
local facedir_rotations = {
-- +Y
[0] = vector.new(0, 0, 0),
[1] = vector.new(0, math.pi * 1.5, 0),
[2] = vector.new(0, math.pi * 1.0, 0),
[3] = vector.new(0, math.pi * 0.5, 0),
-- +Z
[4] = vector.new(math.pi * 1.5, 0, 0),
[5] = vector.new(0, math.pi * 1.5, math.pi * 1.5),
[6] = vector.new(math.pi * 0.5, math.pi * 1.0, 0),
[7] = vector.new(0, math.pi * 0.5, math.pi * 0.5),
-- -Z
[8] = vector.new(math.pi * 0.5, 0, 0),
[9] = vector.new(0, math.pi * 1.5, math.pi * 0.5),
[10] = vector.new(math.pi * 1.5, math.pi * 1.0, 0),
[11] = vector.new(0, math.pi * 0.5, math.pi * 1.5),
-- +X
[12] = vector.new(0, 0, math.pi * 0.5),
[13] = vector.new(math.pi * 1.5, math.pi * 1.5, 0),
[14] = vector.new(0, math.pi * 1.0, math.pi * 1.5),
[15] = vector.new(math.pi * 0.5, math.pi * 0.5, 0),
-- -X
[16] = vector.new(0, 0, math.pi * 1.5),
[17] = vector.new(math.pi * 0.5, math.pi * 1.5, 0),
[18] = vector.new(0, math.pi * 1.0, math.pi * 0.5),
[19] = vector.new(math.pi * 1.5, math.pi * 0.5, 0),
-- -Y
[20] = vector.new(0, 0, math.pi * 1.0),
[21] = vector.new(0, math.pi * 0.5, math.pi * 1.0),
[22] = vector.new(0, math.pi * 1.0, math.pi * 1.0),
[23] = vector.new(0, math.pi * 1.5, math.pi * 1.0),
}
function ns.facedir_to_rotation(facedir)
return facedir_rotations[facedir] or minetest.facedir_to_dir(facedir):dir_to_rotation()
end
function ns.rotate_selectionbox(box, rot)
local a = vector.new(box[1], box[2], box[3]):rotate(rot)
local b = vector.new(box[4], box[5], box[6]):rotate(rot)
return {
a.x, a.y, a.z,
b.x, b.y, b.z
}
end
function ns.register_item(name, def)
local needs_alias
if not name:find ":" then
def._name = name
name = "firefly:"..name
needs_alias = true
end
minetest.register_craftitem(":"..name, def)
if needs_alias then
minetest.register_alias(def._name, name)
end
end
function ns.solid_color_frames(frames)
local out = "[fill:1x"..#frames..":0,0:#000"
for i, x in ipairs(frames) do
out = out.."^[fill:1x3:0,"..(i -1)..":"..x
end
return out
end
local digit_widths = {
[0] = 7,
6,
7,
7,
7,
7,
7,
7,
7,
7,
}
function ns.texture_from_number(num)
local w = 0
local digits = {}
repeat
w = w +1
digits[w] = num %10
num = math.floor(num /10)
until num <= 0
local width = 0
local out = ""
for i = w, 1, -1 do
out = out..":"..width..",1=firefly_number_"..digits[i]..".png"
width = width +digit_widths[digits[i]] +(i > 1 and 2 or 0)
end
return "[combine:"..width.."x16"..out, width
end
function ns.read_file(path)
local f = io.open(path)
if not f then return false end
local out = f:read("a")
f:close()
return out
end
function ns.manhattan_distance(a, b)
return math.abs(b.x -a.x) +math.abs(b.y -a.y) +math.abs(b.z -a.z)
end
minetest.register_lbm {
name = ":firefly:on_load",
nodenames = {"group:call_on_load"},
action = function(pos, node)
minetest.registered_nodes[node.name].on_load(pos)
end
}
ns.timer = EventTarget()
local last_time = minetest.get_us_time()
minetest.register_globalstep(function()
local time = minetest.get_us_time()
if time -last_time > 1000000 then
ns.timer:dispatch("every_second")
last_time = time
end
end)
minetest.register_entity(":display", {
initial_properties = {
visual = "sprite",
textures = {"blank.png"},
pointable = false,
static_save = false
},
on_activate = function(e)
e.object:set_armor_groups{immortal = 1}
end
})
if minetest.get_modpath("testtools") then
minetest.override_item("testtools:param2tool", {
pointabilities = {
nodes = {["group:everything"] = true},
objects = {["group:immortal"] = false}
}
})
end