nixie_tubes/init.lua
Vanessa Dannenberg 83dced745d rudimentary multi-tube string support
digiline_send(channel, "some string") will now echo "some string"
to all alphanumeric tubes in a lineup, so long as they all face
the same way, starting from the nixie the LuaC is connected to,
going left to right.  The other tubes in the line do not need to
be connected to anything - think of them as being connected
toghether internally.

The string will spread until either a tube is found that faces the
wrong way, or it has a channel that's not empty/nil and is set to
something other than what the first is set to, or if a node is
encountered that is not an alpha-numeric tube at all.

Tubes to the left of the connected one are ignored; you can put
multiple lines of tubes side by side, so long as each tube that
starts each line has a unique channel.

The string is padded with spaces and trimmed to 64 chars.

Special messages:

"off_multi" turns all tubes in the lineup off
"allon_multi" turns on all anode segments of all tubes in the lineup.

Note that the existing messages "get" and "getstr" will only read
the one character from the first, connected tube, not the others
in the lineup.
2018-08-14 19:38:18 -04:00

518 lines
16 KiB
Lua

-- simple nixie tubes mod
-- by Vanessa Ezekowitz
nixie_tubes = {}
local S
if minetest.get_modpath("intllib") then
S = intllib.Getter()
else
S = function(s) return s end
end
local nixie_types = {
"1",
"2",
"3",
"4",
"5",
"6",
"7",
"8",
"9",
"0",
"colon",
"period",
"off"
}
local tube_cbox = {
type = "fixed",
fixed = { -11/32, -8/16, -11/32, 11/32, 8/16, 11/32 }
}
-- 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
if string.sub(node.name,1,21) == "nixie_tubes:numitron_" then
minetest.swap_node(pos, { name = "nixie_tubes:numitron_"..msg, param2 = node.param2})
else
minetest.swap_node(pos, { name = "nixie_tubes:tube_"..msg, param2 = node.param2})
end
end
end
local on_digiline_receive_deca = function(pos, node, channel, msg)
local meta = minetest.get_meta(pos)
local setchan = meta:get_string("channel")
if setchan ~= channel then return end
local tubenum = string.gsub(node.name, "nixie_tubes:decatron_", "")
local num = tonumber(msg)
if msg == "off" or (num and (num >= 0 and num <= 9)) then
minetest.swap_node(pos, { name = "nixie_tubes:decatron_"..msg, param2 = node.param2})
elseif msg == "inc" then
num = (tonumber(tubenum) or 0) + 1
if num > 9 then
num = 0
digiline:receptor_send(pos, digiline.rules.default, channel, "carry")
end
minetest.swap_node(pos, { name = "nixie_tubes:decatron_"..num, param2 = node.param2})
elseif msg == "dec" then
num = (tonumber(tubenum) or 0) - 1
if num < 0 then
num = 9
digiline:receptor_send(pos, digiline.rules.default, channel, "borrow")
end
minetest.swap_node(pos, { name = "nixie_tubes:decatron_"..num, param2 = node.param2})
elseif msg == "get" then
digiline:receptor_send(pos, digiline.rules.default, channel, tubenum)
end
end
-- the nodes:
for _,tube in ipairs(nixie_types) do
local groups = { cracky = 2, not_in_creative_inventory = 1}
local light = LIGHT_MAX-4
local light2 = LIGHT_MAX-5
local description = S("Nixie Tube ("..tube..")")
local description2 = S("Decatron ("..tube..")")
local cathode = "nixie_tube_cathode_off.png^nixie_tube_cathode_"..tube..".png"
local cathode2 = "decatron_cathode_"..tube..".png"
local cathode3 = "numitron_filaments.png^numitron_"..tube..".png"
if tube == "off" then
groups = {cracky = 2}
light = nil
light2 = nil
description = S("Nixie Tube")
description2 = S("Decatron")
description3 = S("Numitron Tube")
cathode = "nixie_tube_cathode_off.png"
cathode2 = "nixie_tube_blank.png"
cathode3 = "numitron_filaments.png"
end
minetest.register_node("nixie_tubes:tube_"..tube, {
description = description,
drawtype = "mesh",
mesh = "nixie_tube.obj",
tiles = {
"nixie_tube_base.png",
"nixie_tube_backing.png",
cathode,
"nixie_tube_anode.png",
"nixie_tube_glass.png",
},
use_texture_alpha = true,
groups = groups,
paramtype = "light",
paramtype2 = "facedir",
light_source = light,
selection_box = tube_cbox,
collision_box = tube_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_std
},
},
drop = "nixie_tubes:tube_off"
})
minetest.register_node("nixie_tubes:numitron_"..tube, {
description = description3,
drawtype = "mesh",
mesh = "nixie_tube.obj",
tiles = {
"nixie_tube_base.png",
"nixie_tube_backing.png",
cathode3,
"nixie_tube_anode.png",
"nixie_tube_glass.png",
},
use_texture_alpha = true,
groups = groups,
paramtype = "light",
paramtype2 = "facedir",
light_source = light,
selection_box = tube_cbox,
collision_box = tube_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_std
},
},
drop = "nixie_tubes:numitron_off"
})
if tube ~= "colon" and tube ~= "period" then
minetest.register_node("nixie_tubes:decatron_"..tube, {
description = description2,
drawtype = "mesh",
mesh = "decatron.obj",
tiles = {
"nixie_tube_base.png",
"decatron_internals.png",
"decatron_anode.png",
"decatron_cathode_pins.png",
cathode2,
"nixie_tube_glass.png",
},
use_texture_alpha = true,
groups = groups,
paramtype = "light",
paramtype2 = "facedir",
light_source = light2,
selection_box = tube_cbox,
collision_box = tube_cbox,
after_place_node = function(pos, placer, itemstack, pointed_thing)
minetest.set_node(pos, { name = "air"})
minetest.rotate_node(itemstack, placer, pointed_thing)
if minetest.get_node(pos).param2 == 12 then
minetest.set_node(pos, { name = "nixie_tubes:decatron_off", param2 = 15 })
end
end,
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_deca
},
},
drop = "nixie_tubes:decatron_off"
})
end
end
-- Alpha-numeric tubes (Burroughs B-7971 or similar)
--[[
Map of display wires:
--1------
|\ |8 /|
6| \ | / |2
| 7\ | /9 |
| \|/ |
14--> ---- ---- <--10
| /|\ |
|13/ | \11|
5| / | \ |3
|/ 12| \|
------4--
_
--¯¯ ¯¯-- <--15
-- Wire positions in table:
-- char = { 1, 2, 3, 4, .... , 13, 14, 15 }
]]--
local alnum_chars = {
{ " ", { 0,0,0,0,0,0,0,0,0,0,0,0,0,0,0 } }, -- 32
{ "!", { 0,0,0,0,1,1,0,0,0,0,0,0,0,0,0 } },
{ '"', { 0,0,0,0,0,1,0,1,0,0,0,0,0,0,0 } },
{ "#", { 0,1,1,1,0,0,0,1,0,1,0,1,0,1,0 } },
{ "$", { 1,0,1,1,0,1,0,1,0,1,0,1,0,1,0 } },
{ "%", { 0,0,1,0,0,1,0,0,1,0,0,0,1,0,0 } },
{ "&", { 1,0,0,1,1,0,1,0,1,0,1,0,0,1,0 } },
{ "'", { 0,0,0,0,0,0,0,1,0,0,0,0,0,0,0 } },
{ "(", { 0,0,0,0,0,0,0,0,1,0,1,0,0,0,0 } },
{ ")", { 0,0,0,0,0,0,1,0,0,0,0,0,1,0,0 } },
{ "*", { 0,0,0,0,0,0,1,1,1,1,1,1,1,1,0 } },
{ "+", { 0,0,0,0,0,0,0,1,0,1,0,1,0,1,0 } },
{ ",", { 0,0,0,0,0,0,0,0,0,0,0,0,1,0,0 } },
{ "-", { 0,0,0,0,0,0,0,0,0,0,0,0,0,1,0 } },
{ ".", { 0,0,0,0,1,0,0,0,0,0,0,0,0,0,0 } },
{ "/", { 0,0,0,0,0,0,0,0,1,0,0,0,1,0,0 } },
{ "0", { 1,1,1,1,1,1,0,0,1,0,0,0,1,0,0 } }, -- 48
{ "1", { 0,1,1,0,0,0,0,0,1,0,0,0,0,0,0 } },
{ "2", { 1,1,0,1,0,0,0,0,0,1,0,0,1,0,0 } },
{ "3", { 1,1,1,1,0,0,0,0,0,1,0,0,0,0,0 } },
{ "4", { 0,1,1,0,0,1,0,0,0,1,0,0,0,1,0 } },
{ "5", { 1,0,1,1,0,1,0,0,0,1,0,0,0,1,0 } },
{ "6", { 1,0,1,1,1,1,0,0,0,1,0,0,0,1,0 } },
{ "7", { 1,0,0,0,0,0,0,0,1,0,0,1,0,0,0 } },
{ "8", { 1,1,1,1,1,1,0,0,0,1,0,0,0,1,0 } },
{ "9", { 1,1,1,0,0,1,0,0,0,1,0,0,0,1,0 } },
{ ":", { 0,0,0,0,0,0,0,1,0,0,0,1,0,0,0 } }, -- 58
{ ";", { 0,0,0,0,0,0,0,1,0,0,0,0,1,0,0 } },
{ "<", { 0,0,0,0,0,0,0,0,1,0,1,0,0,1,0 } },
{ "=", { 0,0,0,1,0,0,0,0,0,1,0,0,0,1,0 } },
{ ">", { 0,0,0,0,0,0,1,0,0,1,0,0,1,0,0 } },
{ "?", { 1,1,0,0,0,0,0,0,0,1,0,1,0,0,0 } },
{ "@", { 1,1,0,1,1,1,0,1,0,1,0,0,0,0,0 } }, -- 64
{ "A", { 1,1,1,0,1,1,0,0,0,1,0,0,0,1,0 } },
{ "B", { 1,1,1,1,0,0,0,1,0,1,0,1,0,0,0 } },
{ "C", { 1,0,0,1,1,1,0,0,0,0,0,0,0,0,0 } },
{ "D", { 1,1,1,1,0,0,0,1,0,0,0,1,0,0,0 } },
{ "E", { 1,0,0,1,1,1,0,0,0,0,0,0,0,1,0 } },
{ "F", { 1,0,0,0,1,1,0,0,0,0,0,0,0,1,0 } },
{ "G", { 1,0,1,1,1,1,0,0,0,1,0,0,0,0,0 } },
{ "H", { 0,1,1,0,1,1,0,0,0,1,0,0,0,1,0 } },
{ "I", { 1,0,0,1,0,0,0,1,0,0,0,1,0,0,0 } },
{ "J", { 0,1,1,1,1,0,0,0,0,0,0,0,0,0,0 } },
{ "K", { 0,0,0,0,1,1,0,0,1,0,1,0,0,1,0 } },
{ "L", { 0,0,0,1,1,1,0,0,0,0,0,0,0,0,0 } },
{ "M", { 0,1,1,0,1,1,1,0,1,0,0,0,0,0,0 } },
{ "N", { 0,1,1,0,1,1,1,0,0,0,1,0,0,0,0 } },
{ "O", { 1,1,1,1,1,1,0,0,0,0,0,0,0,0,0 } },
{ "P", { 1,1,0,0,1,1,0,0,0,1,0,0,0,1,0 } },
{ "Q", { 1,1,1,1,1,1,0,0,0,0,1,0,0,0,0 } },
{ "R", { 1,1,0,0,1,1,0,0,0,1,1,0,0,1,0 } },
{ "S", { 1,0,1,1,0,1,0,0,0,1,0,0,0,1,0 } },
{ "T", { 1,0,0,0,0,0,0,1,0,0,0,1,0,0,0 } },
{ "U", { 0,1,1,1,1,1,0,0,0,0,0,0,0,0,0 } },
{ "V", { 0,0,0,0,1,1,0,0,1,0,0,0,1,0,0 } },
{ "W", { 0,1,1,0,1,1,0,0,0,0,1,0,1,0,0 } },
{ "X", { 0,0,0,0,0,0,1,0,1,0,1,0,1,0,0 } },
{ "Y", { 0,0,0,0,0,0,1,0,1,0,0,1,0,0,0 } },
{ "Z", { 1,0,0,1,0,0,0,0,1,0,0,0,1,0,0 } },
{ "[", { 1,0,0,1,1,1,0,0,0,0,0,0,0,0,0 } }, -- 91
{ "\\", { 0,0,0,0,0,0,1,0,0,0,1,0,0,0,0 } },
{ "]", { 1,1,1,1,0,0,0,0,0,0,0,0,0,0,0 } },
{ "^", { 0,0,0,0,0,0,0,0,0,0,1,0,1,0,0 } },
{ "_", { 0,0,0,1,0,0,0,0,0,0,0,0,0,0,0 } },
{ "`", { 0,0,0,0,0,0,1,0,0,0,0,0,0,0,0 } },
{ "a", { 1,1,1,1,0,0,0,0,0,1,0,0,1,0,0 } }, -- 97
{ "b", { 0,0,0,1,1,1,0,0,0,0,1,0,0,1,0 } },
{ "c", { 0,0,0,1,1,0,0,0,0,1,0,0,0,1,0 } },
{ "d", { 0,1,1,1,0,0,0,0,0,1,0,0,1,0,0 } },
{ "e", { 0,0,0,1,1,0,0,0,0,0,0,0,1,1,0 } },
{ "f", { 1,0,0,0,1,1,0,0,0,0,0,0,0,1,0 } },
{ "g", { 1,1,1,1,0,0,1,0,0,1,0,0,0,0,0 } },
{ "h", { 0,0,0,0,1,1,0,0,0,0,1,0,0,1,0 } },
{ "i", { 0,0,0,0,0,0,0,0,0,0,0,1,0,0,0 } },
{ "j", { 0,1,1,1,0,0,0,0,0,0,0,0,0,0,0 } },
{ "k", { 0,0,0,0,0,0,0,1,1,0,1,1,0,0,0 } },
{ "l", { 0,0,0,0,0,0,0,1,0,0,0,1,0,0,0 } },
{ "m", { 0,0,1,0,1,0,0,0,0,1,0,1,0,1,0 } },
{ "n", { 0,0,0,0,1,0,0,0,0,0,1,0,0,1,0 } },
{ "o", { 0,0,1,1,1,0,0,0,0,1,0,0,0,1,0 } },
{ "p", { 1,0,0,0,1,1,0,0,1,0,0,0,0,1,0 } },
{ "q", { 1,1,1,0,0,0,1,0,0,1,0,0,0,0,0 } },
{ "r", { 0,0,0,0,1,0,0,0,0,0,0,0,0,1,0 } },
{ "s", { 0,0,0,1,0,0,0,0,0,1,1,0,0,0,0 } },
{ "t", { 0,0,0,1,1,1,0,0,0,0,0,0,0,1,0 } },
{ "u", { 0,0,1,1,1,0,0,0,0,0,0,0,0,0,0 } },
{ "v", { 0,0,0,0,1,0,0,0,0,0,0,0,1,0,0 } },
{ "w", { 0,0,1,0,1,0,0,0,0,0,1,0,1,0,0 } },
{ "x", { 0,0,0,0,0,0,1,0,1,0,1,0,1,0,0 } },
{ "y", { 0,0,0,0,0,0,1,0,1,0,0,0,1,0,0 } },
{ "z", { 0,0,0,4,0,0,0,0,0,0,0,0,1,1,0 } },
{ "{", { 1,0,0,1,0,0,1,0,0,0,0,0,1,1,0 } },
{ "|", { 0,0,0,0,0,0,0,1,0,0,0,1,0,0,0 } },
{ "}", { 1,0,0,1,0,0,0,0,1,1,1,0,0,0,0 } },
{ "~", { 0,1,0,0,0,1,1,0,0,1,0,0,0,0,0 } },
{ string.char(127), { 1,1,1,1,1,1,1,1,1,1,1,1,1,1,0 } }, -- "DEL"
{ string.char(128), { 1,1,1,1,1,1,1,1,1,1,1,1,1,1,1 } }, -- all-on
{ string.char(129), { 0,0,0,0,0,0,0,0,0,0,0,0,0,0,1 } }, -- "cursor" segment
}
local fdir_to_right = {
{ 1, 0 },
{ 0, -1 },
{ -1, 0 },
{ 0, 1 },
}
local padding = " "
local allon = string.char(128)
for i = 1, 64 do
padding = padding.." "
allon = allon..string.char(128)
end
local display_string = function(pos, channel, string)
if string == "off_multi" then
string = ""
elseif string == "allon_multi" then
string = allon
end
local padded_string = string.sub(string..padding, 1, 64)
local fdir = minetest.get_node(pos).param2 % 4
local pos2 = pos
for i = 1, 64 do
local node = minetest.get_node(pos2)
local meta = minetest.get_meta(pos2)
local setchan = meta:get_string("channel")
if not string.match(node.name, "nixie_tubes:alnum_") or (setchan ~= nil and setchan ~= "" and setchan ~= channel) then break end
local asc = string.byte(padded_string, i, i)
if node.param2 == fdir and asc > 31 and alnum_chars[asc - 31] then
minetest.swap_node(pos2, { name = "nixie_tubes:alnum_"..asc, param2 = node.param2})
end
pos2.x = pos2.x + fdir_to_right[fdir+1][1]
pos2.z = pos2.z + fdir_to_right[fdir+1][2]
end
end
local on_digiline_receive_alnum = function(pos, node, channel, msg)
local meta = minetest.get_meta(pos)
local setchan = meta:get_string("channel")
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 = "nixie_tubes:alnum_32", param2 = node.param2})
elseif msg == "colon" then
minetest.swap_node(pos, { name = "nixie_tubes:alnum_58", param2 = node.param2})
elseif msg == "period" then
minetest.swap_node(pos, { name = "nixie_tubes:alnum_46", param2 = node.param2})
elseif msg == "del" then
minetest.swap_node(pos, { name = "nixie_tubes:alnum_127", param2 = node.param2})
elseif msg == "allon" then
minetest.swap_node(pos, { name = "nixie_tubes:alnum_128", param2 = node.param2})
elseif msg == "cursor" then
minetest.swap_node(pos, { name = "nixie_tubes:alnum_129", param2 = node.param2})
else
display_string(pos, channel, msg)
end
else
local asc = string.byte(msg)
if asc > 31 and alnum_chars[asc - 31] then
minetest.swap_node(pos, { name = "nixie_tubes:alnum_"..asc, param2 = node.param2})
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,"nixie_tubes:alnum_(.+)"))) -- 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,"nixie_tubes:alnum_(.+)"))))
end
end
elseif msg and type(msg) == "number" then
if msg == 0 then
minetest.swap_node(pos, { name = "nixie_tubes:alnum_32", param2 = node.param2})
elseif msg > 31 and alnum_chars[msg - 31] ~= nil then
minetest.swap_node(pos, { name = "nixie_tubes:alnum_"..tostring(msg), param2 = node.param2})
end
end
end
for i in ipairs(alnum_chars) do
local char = alnum_chars[i][1]
local bits = alnum_chars[i][2]
local groups = { cracky = 2, not_in_creative_inventory = 1}
local light = LIGHT_MAX-4
local description = S("Alphanumeric Nixie Tube ("..char..")")
local wires = "nixie_tube_alnum_wires.png"
for j = 1, 15 do
if bits[j] == 1 then
wires = wires.."^nixie_tube_alnum_seg_"..j..".png"
end
end
if char == " " then
groups = {cracky = 2}
light = nil
description = S("Alphanumeric Nixie Tube")
wires = "nixie_tube_alnum_wires.png"
end
minetest.register_node("nixie_tubes:alnum_"..string.byte(char), {
description = description,
drawtype = "mesh",
mesh = "nixie_tube.obj",
tiles = {
"nixie_tube_base.png",
"nixie_tube_backing.png",
wires,
"nixie_tube_anode.png",
"nixie_tube_glass.png",
},
use_texture_alpha = true,
groups = groups,
paramtype = "light",
paramtype2 = "facedir",
light_source = light,
selection_box = tube_cbox,
collision_box = tube_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_alnum
},
},
drop = "nixie_tubes:alnum_32"
})
end
-- crafts
minetest.register_craft({
output = "nixie_tubes:tube_off 4",
recipe = {
{ "", "default:glass", "" },
{ "default:glass", "default:sign_wall", "default:glass" },
{ "default:glass", "default:mese_crystal_fragment", "default:glass" }
},
})
minetest.register_craft({
output = "nixie_tubes:numitron_off 4",
recipe = {
{ "", "default:glass", "" },
{ "default:glass", "default:copper_ingot", "default:glass" },
{ "default:glass", "default:mese_crystal_fragment", "default:glass" }
},
})
minetest.register_craft({
output = "nixie_tubes:alnum_32 4",
recipe = {
{ "", "default:glass", "" },
{ "default:glass", "default:sign_wall", "default:glass" },
{ "default:glass", "default:mese_crystal", "default:glass" }
},
})