mirror of
https://github.com/mt-mods/led_marquee.git
synced 2024-11-24 08:13:52 +01:00
4bb68ec009
Stack up a wall of LED panels, any horizontal and vertical amount Set a channel on the upper left panel, leave the others un-set, and connect a LuaC to it via digilines. Long strings sent to that channel will be displayed using all panels, starting at the upper-left and working from left to right, top to bottom, wrapping from line to line as appropriate (similar to printing to a shell terminal). string.char(28) can be inserted anywhere to force a linefeed. As usual, printing continues from node to node until the program either finds a panel with a different non-empty channel than the first one, or it finds a panel that's facing the wrong way. If the program finds something other than a panel, it wraps to the next line. If it finds something other than a panel twice in a row, that signals that text has wrapped off of the last row, and printing is cut off. Lines of panels don't need to be the same length, the program will wrap as needed. This commit also gets rid of the end-of-line padding, uses proper string.rep() to create the all-off and all-on fills (each of which is 1kB), and fixes one or two other minor issues. Strings are trimmed to 1 kB. Panels are not erased between prints.
223 lines
6.7 KiB
Lua
223 lines
6.7 KiB
Lua
-- simple LED marquee mod
|
|
-- by Vanessa Dannenberg
|
|
|
|
local S
|
|
if minetest.get_modpath("intllib") then
|
|
S = intllib.make_gettext_pair()
|
|
else
|
|
S = function(s) return s end
|
|
end
|
|
|
|
-- the following functions based on the so-named ones in Jeija's digilines mod
|
|
|
|
local reset_meta = function(pos)
|
|
minetest.get_meta(pos):set_string("formspec", "field[channel;Channel;${channel}]")
|
|
end
|
|
|
|
local on_digiline_receive_std = function(pos, node, channel, msg)
|
|
local meta = minetest.get_meta(pos)
|
|
local setchan = meta:get_string("channel")
|
|
if setchan ~= channel then return end
|
|
local num = tonumber(msg)
|
|
if msg == "colon" or msg == "period" or msg == "off" or (num and (num >= 0 and num <= 9)) then
|
|
minetest.swap_node(pos, { name = "led_marquee:marquee_"..msg, param2 = node.param2})
|
|
end
|
|
end
|
|
|
|
-- the nodes:
|
|
|
|
local fdir_to_right = {
|
|
{ 0, -1 },
|
|
{ 0, -1 },
|
|
{ 0, -1 },
|
|
{ 0, 1 },
|
|
{ 1, 0 },
|
|
{ -1, 0 },
|
|
}
|
|
|
|
local cbox = {
|
|
type = "wallmounted",
|
|
wall_top = { -8/16, 7/16, -8/16, 8/16, 8/16, 8/16 },
|
|
wall_bottom = { -8/16, -8/16, -8/16, 8/16, -7/16, 8/16 },
|
|
wall_side = { -8/16, -8/16, -8/16, -7/16, 8/16, 8/16 }
|
|
}
|
|
|
|
local display_string = function(pos, channel, string)
|
|
if string == "off_multi" then
|
|
string = string.rep(" ", 1024)
|
|
elseif string == "allon_multi" then
|
|
string = string.rep(string.char(144), 1024)
|
|
end
|
|
string = string.sub(string, 1, 1024)
|
|
local master_fdir = minetest.get_node(pos).param2 % 8
|
|
local master_meta = minetest.get_meta(pos)
|
|
local last_color = master_meta:get_int("last_color")
|
|
local pos2 = table.copy(pos)
|
|
if not last_color or last_color < 0 or last_color > 27 then
|
|
last_color = 0
|
|
master_meta:set_int("last_color", 0)
|
|
end
|
|
local i = 1
|
|
local len = string.len(string)
|
|
local wrapped = nil
|
|
while i <= len do
|
|
local node = minetest.get_node(pos2)
|
|
local fdir = node.param2 % 8
|
|
local meta = minetest.get_meta(pos2)
|
|
local setchan = nil
|
|
if meta then setchan = meta:get_string("channel") end
|
|
local asc = string.byte(string, i, i)
|
|
if not string.match(node.name, "led_marquee:char_") then
|
|
if not wrapped then
|
|
pos2.x = pos.x
|
|
pos2.y = pos2.y-1
|
|
pos2.z = pos.z
|
|
wrapped = true
|
|
else
|
|
break
|
|
end
|
|
elseif string.match(node.name, "led_marquee:char_")
|
|
and fdir ~= master_fdir or (setchan ~= nil and setchan ~= "" and setchan ~= channel) then
|
|
break
|
|
elseif asc == 28 then
|
|
pos2.x = pos.x
|
|
pos2.y = pos2.y-1
|
|
pos2.z = pos.z
|
|
i = i + 1
|
|
wrapped = nil
|
|
elseif asc > 30 and asc < 256 then
|
|
minetest.swap_node(pos2, { name = "led_marquee:char_"..asc, param2 = master_fdir + (last_color*8)})
|
|
pos2.x = pos2.x + fdir_to_right[fdir+1][1]
|
|
pos2.z = pos2.z + fdir_to_right[fdir+1][2]
|
|
i = i + 1
|
|
wrapped = nil
|
|
elseif asc < 28 then
|
|
last_color = asc
|
|
master_meta:set_int("last_color", asc)
|
|
i = i + 1
|
|
wrapped = nil
|
|
end
|
|
end
|
|
end
|
|
|
|
local on_digiline_receive_string = function(pos, node, channel, msg)
|
|
local meta = minetest.get_meta(pos)
|
|
local setchan = meta:get_string("channel")
|
|
local last_color = meta:get_int("last_color")
|
|
if not last_color or last_color < 0 or last_color > 27 then
|
|
last_color = 0
|
|
meta:set_int("last_color", 0)
|
|
end
|
|
local fdir = node.param2 % 8
|
|
|
|
if setchan ~= channel then return end
|
|
if msg and msg ~= "" and type(msg) == "string" then
|
|
if string.len(msg) > 1 then
|
|
if msg == "off" then
|
|
minetest.swap_node(pos, { name = "led_marquee:char_32", param2 = fdir + (last_color*8)})
|
|
elseif msg == "colon" then
|
|
minetest.swap_node(pos, { name = "led_marquee:char_58", param2 = fdir + (last_color*8)})
|
|
elseif msg == "period" then
|
|
minetest.swap_node(pos, { name = "led_marquee:char_46", param2 = fdir + (last_color*8)})
|
|
elseif msg == "del" then
|
|
minetest.swap_node(pos, { name = "led_marquee:char_127", param2 = fdir + (last_color*8)})
|
|
elseif msg == "allon" then
|
|
minetest.swap_node(pos, { name = "led_marquee:char_144", param2 = fdir + (last_color*8)})
|
|
elseif msg == "cursor" then
|
|
minetest.swap_node(pos, { name = "led_marquee:char_31", param2 = fdir + (last_color*8)})
|
|
else
|
|
display_string(pos, channel, msg)
|
|
end
|
|
else
|
|
local asc = string.byte(msg)
|
|
if asc > 30 and asc < 256 then
|
|
minetest.swap_node(pos, { name = "led_marquee:char_"..asc, param2 = fdir + (last_color*8)})
|
|
elseif asc < 28 then
|
|
last_color = asc
|
|
meta:set_int("last_color", asc)
|
|
elseif msg == "get" then -- get value as ASCII numerical value
|
|
digiline:receptor_send(pos, digiline.rules.default, channel, tonumber(string.match(minetest.get_node(pos).name,"led_marquee:char_(.+)"))) -- wonderfully horrible string manipulaiton
|
|
elseif msg == "getstr" then -- get actual char
|
|
digiline:receptor_send(pos, digiline.rules.default, channel, string.char(tonumber(string.match(minetest.get_node(pos).name,"led_marquee:char_(.+)"))))
|
|
end
|
|
end
|
|
elseif msg and type(msg) == "number" then
|
|
if msg == 0 then
|
|
minetest.swap_node(pos, { name = "led_marquee:char_32", param2 = fdir + (last_color*8)})
|
|
elseif msg > 30 then
|
|
minetest.swap_node(pos, { name = "led_marquee:char_"..tostring(msg), param2 = fdir + (last_color*8)})
|
|
end
|
|
end
|
|
end
|
|
|
|
for i = 31, 255 do
|
|
local groups = { cracky = 2, not_in_creative_inventory = 1}
|
|
local light = LIGHT_MAX-2
|
|
local description = S("Alphanumeric LED marquee panel ("..i..")")
|
|
local tiles = {
|
|
{ name="led_marquee_base.png", color="white"},
|
|
{ name="led_marquee_leds_off.png", color="white"},
|
|
"led_marquee_char_"..i..".png",
|
|
}
|
|
|
|
if i == 31 then
|
|
tiles = {
|
|
{ name="led_marquee_base.png", color="white"},
|
|
{ name="led_marquee_leds_off.png", color="white"},
|
|
{
|
|
name = "led_marquee_char_31.png",
|
|
animation = {type = "vertical_frames", aspect_w = 32, aspect_h = 32, length = 0.75}
|
|
}
|
|
}
|
|
end
|
|
|
|
if i == 32 then
|
|
groups = {cracky = 2}
|
|
light = nil
|
|
description = S("Alphanumeric LED marquee panel")
|
|
end
|
|
|
|
minetest.register_node("led_marquee:char_"..i, {
|
|
description = description,
|
|
drawtype = "mesh",
|
|
mesh = "led_marquee.obj",
|
|
tiles = tiles,
|
|
palette="led_marquee_palette.png",
|
|
use_texture_alpha = true,
|
|
groups = groups,
|
|
paramtype = "light",
|
|
paramtype2 = "colorwallmounted",
|
|
light_source = light,
|
|
selection_box = cbox,
|
|
node_box = cbox,
|
|
on_construct = function(pos)
|
|
reset_meta(pos)
|
|
end,
|
|
on_receive_fields = function(pos, formname, fields, sender)
|
|
if (fields.channel) then
|
|
minetest.get_meta(pos):set_string("channel", fields.channel)
|
|
end
|
|
end,
|
|
digiline = {
|
|
receptor = {},
|
|
effector = {
|
|
action = on_digiline_receive_string,
|
|
},
|
|
},
|
|
drop = "led_marquee:char_32"
|
|
})
|
|
end
|
|
|
|
-- crafts
|
|
|
|
|
|
minetest.register_craft({
|
|
output = "led_marquee:char_32 6",
|
|
recipe = {
|
|
{ "default:glass", "default:glass", "default:glass" },
|
|
{ "mesecons_lamp:lamp_off", "mesecons_lamp:lamp_off", "mesecons_lamp:lamp_off" },
|
|
{ "group:wood", "mesecons_microcontroller:microcontroller0000", "group:wood" }
|
|
},
|
|
})
|
|
|