A complete guide to Lua controllers can be found at: http://mesecons.net/luacontroller
Some of the crafting recipes are different.
Tutorial na
https://h2mm.gitlab.io/web/tutorials/digilines.html
ukázku kódu z Minetestu
CACTUS FARM by PeterisU1
code 1 z prvniho luacontrolleru:
local channel = "button1"
-- Define temp globally to ensure it exists prior to any event handling
local temp = {}
local function minfy(sec)
return math.floor(sec / 60)
end
mem.names = mem.names or {} -- Ensure persistence of names across events
if event.type == "program" then
digiline_send(channel, "stop")
digiline_send("lcd", "Hello, want some cactus?")
digiline_send("debug", "Hello! \n TABLE <-- --> last digiline msg \n\n down - clean table")
end
local function padString(str, length)
local paddedStr = str
while #paddedStr < length do
paddedStr = paddedStr .. " "
end
return paddedStr
end
--- clean table on DOWN
if event.type == "digiline" and event.msg == "down" then
mem.names = {}
digiline_send("debug","--TABLE cleaned--")
end
-- Check for Digiline event and "left" message
if event.type == "digiline" and event.msg == "left" then
local message = ""
if type(mem.names) == "table" then
for player, details in pairs(mem.names) do
local playerName = padString(player, 20)
local lastTime = padString(tostring(details.lt), 10)
local cactusCount = padString(tostring(details.q), 6)
message = message .. playerName .. ": Last Time - " .. lastTime .. " - Cactus: " .. cactusCount .. "\n"
end
else
message = "Error: mem.names is not a table or does not exist."
end
digiline_send("debug", message)
end
if event.type == "digiline" and event.channel == channel then
if event.msg.action == "player" and event.msg.name then
local playerName = event.msg.name
local lcdstr = ""
temp.names = mem.names or {}
temp.ct = minfy(os.time())
local dt = temp.names[playerName] or {q=0, lt=0}
if dt.q == 0 then -- Only serve if they have never received cactus before
local cactus_amount = 10
dt.q = cactus_amount
dt.lt = temp.ct
lcdstr = playerName .. ": Welcome! You get " .. cactus_amount .. " initial cactus."
digiline_send("storage", "output default:cactus " .. cactus_amount)
temp.names[playerName] = dt
else
lcdstr = playerName .. ": Sorry, no more cactus available."
end
mem.names = temp.names
digiline_send("lcd", lcdstr)
-- Optional: Reset message after a delay
interrupt(10, "reset_message")
end
elseif event.type == "interrupt" and event.iid == "reset_message" then
digiline_send("lcd", "Hello, want some cactus?")
end
code 2 z druheho luacontrolleru:
-- Define global variables
local interval1_duration = 60 -- will harvest once a 5 minutes
local interval2_duration = 2 -- Duration of interval2 s
local max_count = 6 -- Maximum count for the loop
if event.type == "program" then
mem.counter = 0 -- Initialize a counter in memory to keep track of the loop iterations
interrupt(interval1_duration, "interval1") -- Start the first interval
elseif event.type == "interrupt" and event.iid == "interval1" then
mem.counter = mem.counter + 1 -- Increment the counter
if mem.counter <= max_count then -- Check if the counter is within the desired range
digiline_send("br", "break " .. mem.counter) -- Send the message
interrupt(interval2_duration, "interval2") -- Set the next interrupt for the pause
else
mem.counter = 0 -- Reset the counter after reaching the max count
interrupt(interval1_duration, "interval1") -- Set the next interrupt for the main interval
end
elseif event.type == "interrupt" and event.iid == "interval2" then
-- After the pause, continue or restart the process
if mem.counter < max_count then
interrupt(interval2_duration, "interval1") -- Immediately set the next main interval if more messages need to be sent
else
interrupt(interval1_duration, "interval1") -- Restart the main interval after the last message
end
end
STEAK HOUSE
code luacontroller:
local channel = "button1" --
local function minfy(sec)
return math.floor(sec / 60)
end
local function gms(min)
return math.floor(minfy(os.time()) - min)
end
local temp = {}
mem.names = mem.names or {} -- Ensure persistence of names across events
if event.type == "program" then
digiline_send(channel, "stop") -- Adjusted to use the new channel
digiline_send("lcd", "Hello, want some steak?")
digiline_send("debug", "Hello! \n TABLE <-- --> last digiline msg \n\n down - clean table")
end
local function padString(str, length)
local paddedStr = str
while #paddedStr < length do
paddedStr = paddedStr .. " " -- Using spaces for padding for better readability
end
return paddedStr
end
--- clean table on DOWN
if event.type == "digiline" and event.msg == "down" then
mem.names = {}
digiline_send("debug","--TABLE cleaned--")
end
-- Check for Digiline event and "left" message
if event.type == "digiline" and event.msg == "left" then
local message = ""
if type(mem.names) == "table" then
for player, details in pairs(mem.names) do
local playerName = padString(player, 20)
local lastTime = padString(tostring(details.lt), 10)
local steaks = padString(tostring(details.q), 6)
message = message .. playerName .. ": Last Time - " .. lastTime .. " - Steaks: " .. steaks .. "\n"
end
else
message = "Error: mem.names is not a table or does not exist."
end
digiline_send("debug", message)
end
if event.type == "digiline" and event.channel == channel then
if event.msg.action == "player" and event.msg.name then
local playerName = event.msg.name
local lcdstr = ""
temp.names = mem.names or {}
temp.ct = minfy(os.time())
local dt = temp.names[playerName] or {q=0, lt=0} -- Adjusted to not subtract from current time initially
local timepassed = temp.ct - (dt.lt or 0)
local isNew = dt.q == 0
if isNew then
local initial_steaks = 5
dt.q = initial_steaks
dt.lt = temp.ct -- Update time here as steaks are given
lcdstr = playerName .. ": Welcome! You get " .. initial_steaks .. " initial steak(s). And some wood to craft your first armor and things."
digiline_send("storage", "output animalia:beef_cooked " .. initial_steaks)
digiline_send("storage", "output df_trees:blood_thorn " .. 10)
temp.names[playerName] = dt -- Update table here
elseif timepassed > 119 then
local new_steaks = math.min(math.floor(timepassed / 120), 30)
dt.q = dt.q + new_steaks
dt.lt = temp.ct -- Update time here as steaks are given
lcdstr = playerName .. ": You get " .. new_steaks .. " steak(s) for your patience."
digiline_send("storage", "output animalia:beef_cooked " .. new_steaks)
temp.names[playerName] = dt -- Update table here
else
lcdstr = playerName .. ": Hey! You got steaks " .. timepassed .. " minutes ago. You can have more steaks in " .. (120 - timepassed) .. " minutes."
-- Note: We do NOT update the table here since no steaks are given
end
mem.names = temp.names
digiline_send("lcd", lcdstr)
-- Optional: Reset message after a delay
interrupt(10, "reset_message")
end
elseif event.type == "interrupt" and event.iid == "reset_message" then
-- Reset the message on the LCD to a general welcome or status message
digiline_send("lcd", "Hello, want some steak?")
end
BOARD DIGILINE
digiline_send("board","/1NazevKteryChciAbyBezelNaLEDCe")
/1 az /9 cisla urcuji barvu pisma
MOVE MACHINE CODE:
-- [digimovestone="a"/"b"/"c"/"d"] to match labeling of luacontroller
-- [digimovestone="fence"][luacontroller][digimovestone="fence"]
-- [digimovestone="a"/"b"/"c"/"d"] to match labeling of luacontroller
-- Can extend length by adding digimese or digiline between luacontroller and any "fence"
-- Clear channelname of any "fence" to pause, requires two "fence" to be running.
if event.type=="program" then
mem = {offset={a={x=-1,z=0},b={x=0,z=1},c={x=1,z=0},d={x=0,z=-1}}}
end
if event.type=="digiline" then
if (event.channel=="fence") and event.msg.pos then
if not mem.fence then
mem.fence = {}
elseif #mem.fence < 2 then
table.insert(mem.fence, event.msg.pos)
end
if #mem.fence == 2 and (mem.fence[1].y - mem.fence[2].y == 0) then
dx = mem.fence[1].x - mem.fence[2].x
dz = mem.fence[1].z - mem.fence[2].z
if (dx == 0) and not (dz == 0) then
digiline_send("a", {command = "getstate"})
digiline_send("c", {command = "getstate"})
elseif (dz == 0) and not (dx == 0) then
digiline_send("b", {command = "getstate"})
digiline_send("d", {command = "getstate"})
end
end
end
if (mem.offset[event.channel] ~= nil) and (#mem.fence == 2) and event.msg.pos then
idx = 1
if (mem.offset[event.channel].z == 0 and
(math.abs(event.msg.pos.z - mem.fence[1].z) <
math.abs(event.msg.pos.z - mem.fence[2].z))) or
(mem.offset[event.channel].x == 0 and
(math.abs(event.msg.pos.x - mem.fence[1].x) <
math.abs(event.msg.pos.x - mem.fence[2].x))) then
idx = 2
end
digiline_send(event.channel,{command="absmove",
x=mem.fence[idx].x + mem.offset[event.channel].x,
y=mem.fence[idx].y,
z=mem.fence[idx].z + mem.offset[event.channel].z})
end
end
if event.type == "interrupt" then
mem.fence={}
digiline_send("fence", {command = "getstate"})
end
interrupt(5,"-")
LAVA MACHINE (meni lavu na obsidian)
if event.type == "program" then
mem=true
end
if event.type == "interrupt" then
if mem==true then
mem=false
digiline_send("up", "retract")
digiline_send("over", "extend")
else
mem=true
digiline_send("up", "extend")
digiline_send("over", "retract")
end
end
interrupt(6)
BLOODSTEM COLLECTOR (nastaveni lua controleru)
-- Define global variables
local interval1_duration = 120 -- Duration of interval1 s
local interval2_duration = 2 -- Duration of interval2 s
local max_count = 5 -- Maximum count for the loop
if event.type == "program" then
mem.counter = 0 -- Initialize a counter in memory to keep track of the loop iterations
interrupt(interval1_duration, "interval1") -- Start the first interval
elseif event.type == "interrupt" and event.iid == "interval1" then
mem.counter = mem.counter + 1 -- Increment the counter
if mem.counter <= max_count then -- Check if the counter is within the desired range
digiline_send("br", "break " .. mem.counter) -- Send the message
interrupt(interval2_duration, "interval2") -- Set the next interrupt for the pause
else
mem.counter = 0 -- Reset the counter after reaching the max count
interrupt(interval1_duration, "interval1") -- Set the next interrupt for the main interval
end
elseif event.type == "interrupt" and event.iid == "interval2" then
-- After the pause, continue or restart the process
if mem.counter < max_count then
interrupt(interval2_duration, "interval1") -- Immediately set the next main interval if more messages need to be sent
else
interrupt(interval1_duration, "interval1") -- Restart the main interval after the last message
end
end
-- ======================================================================================
-- We will be using the Queue data structure three times, so it is worth getting it right
-- ======================================================================================
local Queue = {}
Queue.PREV = {}
Queue.NEXT = {}
Queue.FIRST = {}
Queue.LAST = {}
function Queue.new()
local tab = {}
tab[Queue.FIRST] = {}
tab[Queue.FIRST][Queue.NEXT] = nil
tab[Queue.LAST] = {}
tab[Queue.LAST][Queue.PREV] = nil
return tab
end
function Queue.is_empty(q)
if q[Queue.FIRST] == nil then
return true
else
return q[Queue.FIRST][Queue.NEXT] == nil
end
end
function Queue.contains(q, el)
return el ~= nil and (q[el] ~= nil or q[Queue.LAST][Queue.PREV] == el)
end
function Queue.get_first(q)
if q[Queue.FIRST] ~= nil then
return q[Queue.FIRST][Queue.NEXT]
else
return nil
end
end
function Queue.set_first(q, el)
q[Queue.FIRST][Queue.NEXT] = el
return true
end
function Queue.get_last(q)
return q[Queue.LAST][Queue.PREV]
end
function Queue.set_last(q, el)
q[Queue.LAST][Queue.PREV] = el
return true
end
function Queue.insert(q, el)
if el ~= nil and not Queue.contains(q, el) then
if Queue.is_empty(q) then
Queue.set_first(q, el)
q[el] = {}
Queue.set_last(q, el)
else
local tail = Queue.get_last(q)
q[tail][Queue.NEXT] = el
q[el] = {}
q[el][Queue.PREV] = tail
Queue.set_last(q, el)
end
return true
end
return false
end
function Queue.remove(q)
if Queue.is_empty(q) then
return
end
if Queue.get_first(q) then
local head = Queue.get_first(q)
local new_head = q[head][Queue.NEXT]
q[head] = nil
if q[new_head] and q[new_head][Queue.PREV] then
q[new_head][Queue.PREV] = nil
end
Queue.set_first(q, new_head)
return head
else
return nil
end
end
function Queue.loop(q, func)
local next = q[Queue.FIRST][Queue.NEXT]
local output_table = {}
while next ~= nil do
local curr = next
if func then
func(curr)
else
table.insert(output_table, curr)
end
next = q[curr][Queue.NEXT]
end
if not func then
return output_table
else
return true
end
end
-- ======================================================================================
local function tableLength(T)
local L = 0
for i, _ in pairs(T) do
L = L + 1
end
return L
end
local function tableLengths(listOfTables)
local totalLength = 0
for i, t in pairs(listOfTables) do
totalLength = totalLength + tableLength(t)
end
return totalLength
end
local function processAction(action, tbl)
local unitID = Queue.remove(tbl[1])
digiline_send(unitID .. "_" .. action, tbl[3])
if tbl[2] then
Queue.insert(tbl[2], unitID)
end
sendMessage("display", unitID)
return true
end
local function process(action)
local queues = {}
queues["break"] = {mem.break_queue, mem.plant_queue, "break 1"}
queues["plant"] = {mem.plant_queue, mem.input_queue, "deploy " .. mem.crop.item}
queues["input"] = {mem.input_queue, false, "output " .. mem.crop.item .. " 1"}
for _, action in ipairs({"input", "plant", "break"}) do
processAction(action, queues[action])
end
end
local function isFindUnit(event)
if string.find(event.channel, "_find", 1, true) then
return true
else
return false
end
end
local function splitString(inputstr, sep)
if sep == nil then
sep = "%s"
end
local t = {}
for str in string.gmatch(inputstr, "([^"..sep.."]+)") do
table.insert(t, str)
end
return t
end
local function obtainUnitID(event)
local s, e = string.find(event.channel, "_find", 1, true)
return string.sub(event.channel, 1, s-1)
end
local function sendMessage(channel, C)
digiline_send(channel, "*** Farm monitor ***\nLast dug: " .. mem.crop.name .. "\nChannel: " .. C .. "\nNum dug: " .. mem.dugs .. "\nLength of queue: " .. tableLength(mem.queue))
end
local function reset()
mem.dugs = 0
mem.break_queue = Queue.new()
mem.plant_queue = Queue.new()
mem.input_queue = Queue.new()
end
local function controlPanel(event)
if event.msg == "back" then reset() end
end
local function findUnit(event)
local M = event.msg.detected[1]
local C = obtainUnitID(event)
if M.label ~= mem.crop.item .. "_" .. mem.crop.harvest then
return
end
Queue.insert(mem.break_queue, C)
mem.dugs = mem.dugs + 1
sendMessage("display", C)
end
if event.type == "program" then
mem.crop = {
item = "farming:potato",
harvest = "4",
name = "Potato"
}
reset()
digiline_send("display", "Initialised!\nLength of break queue is " .. tableLength(mem.break_queue)-2)
mem.initialised = true
end
if event.type == "digiline" and mem.initialised then
if isFindUnit(event) then
findUnit(event)
end
end
if event.type == "on" then
for _, i in pairs({"input", "plant", "break"}) do
process(i)
end
end
TREE BREAKER ASPEN by niceride
code luacontroller:
Id = "cb"
List = {}
function List.new ()
return {first = 0, last = -1}
end
function List.pushl (l, v)
l.first = l.first - 1
l[l.first] = v
end
function List.popr (l)
local v = nil
if l.first <= l.last then
v = l[l.last]
l[l.last] = nil
l.last = l.last - 1
end
return v
end
function harvest ()
List.pushl(mem.q, {ch="dig " .. Id, cmd="break 1"})
List.pushl(mem.q, {ch="dig " .. Id, cmd="break 2"})
List.pushl(mem.q, {ch="dig " .. Id, cmd="break 3"})
List.pushl(mem.q, {ch="dig " .. Id, cmd="break 4"})
List.pushl(mem.q, {ch="dig " .. Id, cmd="break 5"})
interrupt(0.2)
end
if event.type == "program" then
mem = { q = List.new() }
harvest()
end
if event.type == "digiline" and event.channel == "det " .. Id and event.msg.action == "detect" then
for ak, av in pairs (event.msg.detected) do
for dk, dv in pairs (event.msg.detected[ak]) do
if dk == "name" and dv == "default:aspen_tree" and mem.q.last < mem.q.first then
harvest()
end
end
end
end
if event.type == "on" and event.pin.name == string.upper(string.sub(Id, -1, -1)) then
if mem.q.last < mem.q.first then harvest() end
end
if event.type == "interrupt" then
if mem.q.last >= mem.q.first then
local r = List.popr(mem.q)
digiline_send(r.ch, r.cmd)
interrupt(heat+0.2)
end
end