Advertisement
Not a member of Pastebin yet?
Sign Up,
it unlocks many cool features!
- -- This is the CC modem channel
- -- used to receive status messages
- local statusChannelID = 5
- -- Set this to false to prevent displaying the
- -- interface on a monitor even if one is attached.
- local useMonitor = true
- -- Set this to true to enable debug messages on the terminal
- local debug = false
- -- None of these variables should need to be changed
- local craftMaintainFileName = "craftMaintain.json"
- local craftInteractive = false
- local craftEditItem = nil
- local crafting = false
- local craftingItemKey = nil
- local craftCheckCount = 0
- local craftFiltering = false
- local myID = os.getComputerID()
- -- Global tables used for states
- local status = {}
- local inventory = {}
- local crafts = {}
- local autos = {}
- local craftList = {}
- local craftMaintain = {}
- -- Find Wireless Modem
- local modem = peripheral.find("modem", function(n, o) return o.isWireless() end)
- if modem ~= nil then
- modem.open(statusChannelID)
- end
- -- Find the ME Bridge from peripherals++
- local bridge = peripheral.find("meBridge")
- -- Find Speaker (from Peripherals++) if one is attached
- local speaker = peripheral.find("speaker")
- -- Find Monitor if one is attached
- local monitor = peripheral.find("monitor", function(name, object) return object.isColour() end)
- local monWidth, monHeight
- local display
- local clickEvent
- if monitor == nil or useMonitor == false then
- display = term.current()
- clickEvent = "mouse_click"
- else
- display = monitor
- display.setTextScale(1.0)
- clickEvent = "monitor_touch"
- end
- monWidth, monHeight = display.getSize()
- if monWidth < 30 and monitor ~= nil then
- display.setTextScale(0.5)
- monWidth, monHeight = display.getSize()
- end
- display.setBackgroundColor(colors.black)
- display.setTextColor(colors.white)
- -- Trim whitespace from the lead/trailing
- local function trim(s)
- return s:match'^%s*(.*.%S)' or ''
- end
- -- Returns the "pairs" of a table iteratively sorted by key
- function spairs(t)
- -- collect the keys
- local keys = {}
- for k in pairs(t) do keys[#keys+1] = k end
- table.sort(keys)
- -- return the iterator function
- local i = 0
- return function()
- i = i + 1
- if keys[i] then
- return keys[i], t[keys[i]]
- end
- end
- end
- -- Set up windows
- local windowHeight = monHeight - 2
- local winHeader = window.create(display, 1, 1, monWidth, 2, true)
- local tabs = {}
- local tabTitles = {}
- local tabDims = {}
- tabsByLabel = {general = 1, craft = 2}
- tabs[1] = window.create(display, 1, 3, monWidth, windowHeight, true)
- tabs[2] = window.create(display, 1, 3, monWidth, windowHeight, false)
- local tW, tH = tabs[1].getSize()
- local oX, oY = tabs[1].getPosition()
- tabDims[1] = {width = tW, height = tH, offsetX = (oX - 1), offsetY = (oY - 1)}
- local tW, tH = tabs[2].getSize()
- local oX, oY = tabs[2].getPosition()
- tabDims[2] = {width = tW, height = tH, offsetX = (oX - 1), offsetY = (oY - 1)}
- -- Use spaces to make all the titles the same width... because I'm lazy
- tabTitles[1] = {label = "Base Status Monitor", phon = "Base Status Monitor"}
- tabTitles[2] = {label = " ME Auto Craft ", phon = "Ehmee Auto Craft"}
- local curTab = 1
- local craftPage = 1
- local craftLineCount = tabDims[tabsByLabel.craft].height - 2
- local buttons = {}
- colors.Au = colors.yellow
- colors.VA = colors.lime
- colors.Cu = colors.orange
- colors.Ag = colors.white
- colors.Sh = colors.lightBlue
- colors.Bz = colors.orange
- colors.EA = colors.orange
- colors.Ye = colors.yellow
- colors.En = colors.green
- colors.Fe = colors.lightGray
- colors.Sn = colors.white
- colors.Al = colors.lightGray
- colors.Sg = colors.orange
- colors.El = colors.yellow
- colors.Pb = colors.cyan
- colors.St = colors.gray
- colors.RI = colors.gray
- colors.Os = colors.cyan
- local function getMag(num)
- return string.len(tostring(num))
- end
- local function centerWrite(disp, msg, y)
- local x = math.floor(monWidth/2) - math.floor(string.len(msg)/2) + 1
- disp.setCursorPos(x, y)
- disp.write(msg)
- return x
- end
- local function showButton(win, button)
- win.setCursorPos(button.startX, button.startY)
- win.setTextColor(button.fg)
- win.setBackgroundColor(button.bg)
- win.write(button.text)
- end
- local function updateHeader()
- winHeader.setTextColor(colors.pink)
- winHeader.setBackgroundColor(colors.black)
- centerWrite(winHeader, tabTitles[curTab].label, 1)
- showButton(winHeader, buttons.resetStatus)
- showButton(winHeader, buttons.filterCrafts)
- showButton(winHeader, buttons.leftMain)
- showButton(winHeader, buttons.rightMain)
- end
- -- This updates the contents of the main status tab
- local function updateGeneral()
- local label, value
- local y = 1
- for label, value in spairs(status) do
- tabs[tabsByLabel.general].setCursorPos(1, y)
- tabs[tabsByLabel.general].clearLine()
- tabs[tabsByLabel.general].setTextColor(colors.yellow)
- tabs[tabsByLabel.general].write(label .. ": ")
- tabs[tabsByLabel.general].setTextColor(colors.cyan)
- tabs[tabsByLabel.general].write(value .. " ")
- y = y + 1
- end
- local row = 1
- for symbol, quantity in spairs(inventory) do
- tabs[tabsByLabel.general].setCursorPos(monWidth - 8, row)
- tabs[tabsByLabel.general].write(" ")
- if colors[symbol] ~= nil then tabs[tabsByLabel.general].setTextColor(colors[symbol]) else tabs[tabsByLabel.general].setTextColor(colors.white) end
- tabs[tabsByLabel.general].setCursorPos(monWidth - 2 - getMag(quantity), row)
- tabs[tabsByLabel.general].write(math.floor(quantity))
- tabs[tabsByLabel.general].setCursorPos(monWidth - 1, row)
- tabs[tabsByLabel.general].write(symbol)
- row = row + 1
- end
- end
- -- This repopulates the crafts table with the current craftable items in the ME network
- local function pollCrafts()
- local rawCrafts = bridge.listCraft()
- crafts = {}
- for i, item in ipairs(rawCrafts) do
- local key = item.name .. ":" .. item.meta
- if craftFiltering == true and craftMaintain[key] ~= nil and craftMaintain[key].maintain ~= 0 then
- crafts[item.displayName] = item
- elseif craftFiltering == false then
- crafts[item.displayName] = item
- end
- end
- end
- -- This updates the Craftables tab with either a paginated list of craftable items in the ME network
- -- or the interactive "pop up" for setting the maintain amount for a craftable item
- local function updateCraft()
- -- If we are in a craft dialog then we should process that and return
- if craftInteractive == true then
- -- If the maintain dialog buttons don't exist, make them
- local tabCenter = math.ceil(tabDims[tabsByLabel.craft].width/2)
- if buttons.maintCancel == nil then
- buttons.maintSubTen = { startX = (tabCenter - 14), startY = 8, endX = (tabCenter - 10), endY = 8, fg = colors.black, bg = colors.orange, text = " -10 ", tab = tabsByLabel.craft, callBack = "maintSubTen" }
- buttons.maintSubOne = { startX = (tabCenter - 8), startY = 8, endX = (tabCenter - 5), endY = 8, fg = colors.black, bg = colors.pink, text = " -1 ", tab = tabsByLabel.craft, callBack = "maintSubOne" }
- buttons.maintSetZero = { startX = (tabCenter - 3), startY = 8, endX = (tabCenter + 2), endY = 8, fg = colors.black, bg = colors.lightBlue, text = " Zero ", tab = tabsByLabel.craft, callBack = "maintSetZero" }
- buttons.maintAddOne = { startX = (tabCenter + 4), startY = 8, endX = (tabCenter + 7), endY = 8, fg = colors.black, bg = colors.pink, text = " +1 ", tab = tabsByLabel.craft, callBack = "maintAddOne" }
- buttons.maintAddTen = { startX = (tabCenter + 9), startY = 8, endX = (tabCenter + 12), endY = 8, fg = colors.black, bg = colors.orange, text = " +10 ", tab = tabsByLabel.craft, callBack = "maintAddTen" }
- buttons.maintCancel = { startX = (tabCenter - 9), startY = 10, endX = (tabCenter - 2), endY = 10, fg = colors.black, bg = colors.red, text = " Cancel ", tab = tabsByLabel.craft, callBack = "maintCancel" }
- buttons.maintSubmit = { startX = (tabCenter + 1), startY = 10, endX = (tabCenter + 7), endY = 10, fg = colors.black, bg = colors.green, text = " Submit ", tab = tabsByLabel.craft, callBack = "maintSubmit" }
- tabs[tabsByLabel.craft].setBackgroundColor(colors.black)
- tabs[tabsByLabel.craft].clear()
- tabs[tabsByLabel.craft].setTextColor(colors.orange)
- tabs[tabsByLabel.craft].setBackgroundColor(colors.black)
- centerWrite(tabs[tabsByLabel.craft], craftEditItem.displayName, 4)
- showButton(tabs[buttons.maintSubTen.tab], buttons.maintSubTen)
- showButton(tabs[buttons.maintSubOne.tab], buttons.maintSubOne)
- showButton(tabs[buttons.maintSetZero.tab], buttons.maintSetZero)
- showButton(tabs[buttons.maintAddOne.tab], buttons.maintAddOne)
- showButton(tabs[buttons.maintAddTen.tab], buttons.maintAddTen)
- showButton(tabs[buttons.maintCancel.tab], buttons.maintCancel)
- showButton(tabs[buttons.maintSubmit.tab], buttons.maintSubmit)
- end
- tabs[tabsByLabel.craft].setCursorPos(1, 6)
- tabs[tabsByLabel.craft].setTextColor(colors.white)
- tabs[tabsByLabel.craft].setBackgroundColor(colors.black)
- tabs[tabsByLabel.craft].clearLine()
- centerWrite(tabs[tabsByLabel.craft], ("Maintain: " .. craftEditItem.maintain), 6)
- return
- end
- -- Normal craftable list display here
- pollCrafts()
- local cY = 1
- local startIndex = ((craftPage - 1) * craftLineCount) + 1
- local lineColors = {colors.orange, colors.lightBlue}
- tabs[tabsByLabel.craft].setBackgroundColor(colors.black)
- local index = 0
- craftList = {}
- for name, item in spairs(crafts) do
- index = index + 1
- if index >= startIndex and cY <= craftLineCount then
- craftList[cY] = item
- lc = (cY % 2) + 1
- tabs[tabsByLabel.craft].setTextColor(lineColors[lc])
- tabs[tabsByLabel.craft].setCursorPos(1, cY)
- tabs[tabsByLabel.craft].clearLine()
- tabs[tabsByLabel.craft].write(string.sub(item.displayName, 1, tabDims[tabsByLabel.craft].width - 11))
- tabs[tabsByLabel.craft].setCursorPos(tabDims[tabsByLabel.craft].width - 10, cY)
- tabs[tabsByLabel.craft].write(item.amount)
- local key = item.name .. ":" .. item.meta
- if craftMaintain[key] ~= nil and craftMaintain[key].maintain ~= 0 then
- tabs[tabsByLabel.craft].write("/" .. craftMaintain[key].maintain)
- end
- cY = cY + 1
- end
- end
- showButton(tabs[buttons.leftCraft.tab], buttons.leftCraft)
- showButton(tabs[buttons.rightCraft.tab], buttons.rightCraft)
- showButton(tabs[buttons.filterCrafts.tab], buttons.filterCrafts)
- tabs[tabsByLabel.craft].setTextColor(colors.cyan)
- tabs[tabsByLabel.craft].setBackgroundColor(colors.black)
- local lastPage = math.ceil(index/craftLineCount)
- centerWrite(tabs[tabsByLabel.craft], craftPage .. "/" .. lastPage, tabDims[tabsByLabel.craft].height)
- end
- -- Return nil or a button based on a click on the monitor/terminal
- local function identifyButton(x, y)
- local but
- local oX, oY
- for label, button in pairs(buttons) do
- if button.tab ~= 0 then
- oX = tabDims[button.tab].offsetX
- oY = tabDims[button.tab].offsetY
- else
- oX = 0
- oY = 0
- end
- local startX = button.startX + oX
- local startY = button.startY + oY
- local endX = button.endX + oX
- local endY = button.endY + oY
- --print("Checking " .. x .. "," .. y .. " against " .. startX .. "," .. startY .. " to " .. endX .. "," .. endY .. " on tab=" .. button.tab)
- if x >= startX and x <= endX and y >= startY and y <= endY and (curTab == button.tab or button.tab == 0) then
- return button
- end
- end
- end
- -- Checks to see if anything needs to be crafted. If any item has been crafting for 30 seconds
- -- then restart crafting for that item (in case something was jammed up). Only crafts one
- -- unique item at a time (may craft multiples of that item at once)
- local function checkAutoCraft()
- if status["ME Crafting CPUs"] == nil or status["ME Crafting CPUs"] == 0 then return end
- pollCrafts()
- -- If we are currently crafting, see if we're done, or requeue if stuck
- if crafting == true then
- local item = crafts[craftMaintain[craftingItemKey].displayName]
- local stored = item.amount
- local target = craftMaintain[craftingItemKey].maintain
- if debug == true then print("Item: " .. item.displayName .. " Have: " .. stored .. " Need: " .. target) end
- if stored >= target then
- craftingItemKey = nil
- crafting = false
- status["Crafting"] = "Nothing"
- updateGeneral()
- else
- if craftCheckCount >= 5 and status["ME Crafting CPUs Busy"] == 0 then
- if debug == true then print("Trying to restart crafting due to hang...") end
- local toCraft
- local amt = target - stored
- if item.meta ~= 0 then
- toCraft = item.name .. " " .. item.meta
- else
- toCraft = item.name
- end
- bridge.craft(toCraft, amt)
- craftCheckCount = 0
- end
- return
- end
- end
- -- If we aren't crafting, see if there is anything that needs crafting
- for key, item in pairs(crafts) do
- local key = item.name .. ":" .. item.meta
- if crafting == false and craftMaintain[key] ~= nil and craftMaintain[key].maintain > 0 and item.amount < craftMaintain[key].maintain then
- local toCraft
- local amt = craftMaintain[key].maintain - item.amount
- if item.meta ~= 0 then
- toCraft = item.name .. " " .. item.meta
- else
- toCraft = item.name
- end
- bridge.craft(toCraft, amt)
- status["Crafting"] = item.displayName
- crafting = true
- craftingItemKey = key
- updateGeneral()
- end
- end
- if crafting == false and status["Crafting"] ~= "Nothing" then
- status["Crafting"] = "Nothing"
- updateGeneral()
- end
- end
- -- Button callback functions are not set to local so they can be called from the global properties
- -- table (i.e. call by function name instead of the function object definition)
- -- Button callback handler for the button which toggles filtering on/off for the list of craftables
- function filterCrafts()
- craftFiltering = not craftFiltering
- craftPage = 1
- tabs[tabsByLabel.craft].clear()
- updateCraft()
- end
- -- Button callback handler for the Reset Status button in the header. This will simply empty the
- -- status{} table and let it repopulate
- function resetStatus()
- status = {}
- tabs[tabsByLabel.general].clear()
- updateGeneral()
- end
- -- Button callback handler for the Cancel button on the interactive pop up for craftable maintainers
- function maintCancel()
- craftEditItem = nil
- buttons.maintCancel = nil
- craftInteractive = false
- buttons.maintSubTen = nil
- buttons.maintSubOne = nil
- buttons.maintSetZero = nil
- buttons.maintAddOne = nil
- buttons.maintAddTen = nil
- buttons.maintCancel = nil
- buttons.maintSubmit = nil
- tabs[tabsByLabel.craft].clear()
- updateCraft()
- end
- -- Button callback handler for the Submit button on the interactive pop up for craftable maintainers
- function maintSubmit()
- local key = craftEditItem.name .. ":" .. craftEditItem.meta
- craftMaintain[key] = craftEditItem
- local file = fs.open(craftMaintainFileName, "w")
- file.write(textutils.serialize(craftMaintain))
- file.close()
- craftEditItem = nil
- buttons.maintCancel = nil
- craftInteractive = false
- buttons.maintSubTen = nil
- buttons.maintSubOne = nil
- buttons.maintSetZero = nil
- buttons.maintAddOne = nil
- buttons.maintAddTen = nil
- buttons.maintCancel = nil
- buttons.maintSubmit = nil
- tabs[tabsByLabel.craft].clear()
- updateCraft()
- checkAutoCraft()
- end
- -- Button callback handler for the "-10" button on the interactive pop up for craftable maintainers
- function maintSubTen()
- craftEditItem.maintain = craftEditItem.maintain - 10
- updateCraft()
- end
- -- Button callback handler for the "-1" button on the interactive pop up for craftable maintainers
- function maintSubOne()
- craftEditItem.maintain = craftEditItem.maintain - 1
- updateCraft()
- end
- -- Button callback handler for the "+1" button on the interactive pop up for craftable maintainers
- function maintAddOne()
- craftEditItem.maintain = craftEditItem.maintain + 1
- updateCraft()
- end
- -- Button callback handler for the "+10" button on the interactive pop up for craftable maintainers
- function maintAddTen()
- craftEditItem.maintain = craftEditItem.maintain + 10
- updateCraft()
- end
- -- Button callback handler for the Zero button on the interactive pop up for craftable maintainers
- function maintSetZero()
- craftEditItem.maintain = 0
- updateCraft()
- end
- -- Button callback handler for the Tab Left button (top left)
- function tabLeft()
- local origTab = curTab
- curTab = curTab - 1
- if curTab < 1 then curTab = 1 end
- if curTab ~= origTab then
- tabs[origTab].setVisible(false)
- tabs[curTab].setVisible(true)
- updateHeader()
- --if speaker ~= nil then speaker.speak(tabTitles[curTab].phon) end
- end
- end
- -- Button callback handler for the Tab Right button (top right)
- function tabRight()
- local origTab = curTab
- curTab = curTab + 1
- if curTab > #tabs then curTab = #tabs end
- if curTab ~= origTab then
- tabs[origTab].setVisible(false)
- tabs[curTab].setVisible(true)
- updateHeader()
- --if speaker ~= nil then speaker.speak(tabTitles[curTab].phon) end
- end
- end
- -- Button callback handler for the Page Left button for craftables (bottom left)
- function craftLeft()
- local origPage = craftPage
- craftPage = craftPage - 1
- if craftPage < 1 then craftPage = 1 end
- if craftPage ~= origPage then
- tabs[tabsByLabel.craft].setBackgroundColor(colors.black)
- tabs[tabsByLabel.craft].clear()
- updateCraft()
- end
- end
- -- Button callback handler for the Page Right button for craftables (bottom right)
- function craftRight()
- local origPage = craftPage
- local itemCount = 0
- for name, item in pairs(crafts) do
- itemCount = itemCount + 1
- end
- local lastPage = math.ceil(itemCount/craftLineCount)
- craftPage = craftPage + 1
- if craftPage > lastPage then craftPage = lastPage end
- if craftPage ~= origPage then
- tabs[tabsByLabel.craft].setBackgroundColor(colors.black)
- tabs[tabsByLabel.craft].clear()
- updateCraft()
- end
- end
- -- Define the buttons which are always available on all tabs
- -- Format: { startX pos, startY pos, endX pos, endY pos, fg color, bg color, button text, tab number, callback function name }
- buttons.resetStatus = { startX = 1, startY = 1, endX = 1, endY = 1, fg = colors.black, bg = colors.yellow, text = "R", tab = 0, callBack = "resetStatus" }
- buttons.filterCrafts = { startX = tabDims[tabsByLabel.craft].width, startY = tabDims[tabsByLabel.craft].height, endX = tabDims[tabsByLabel.craft].width, endY = tabDims[tabsByLabel.craft].height, fg = colors.black, bg = colors.yellow, text = "F", tab = tabsByLabel.craft, callBack = "filterCrafts" }
- buttons.leftMain = { startX = 3, startY = 1, endX = 7, endY = 1, fg = colors.black, bg = colors.lime, text = " < ", tab = 0, callBack = "tabLeft" }
- buttons.rightMain = { startX = (monWidth - 6), startY = 1, endX = (monWidth - 2), endY = 1, fg = colors.black, bg = colors.lime, text = " > ", tab = 0, callBack = "tabRight" }
- buttons.leftCraft = { startX = 6, startY = tabDims[tabsByLabel.craft].height, endX = 10, endY = tabDims[tabsByLabel.craft].height, fg = colors.black, bg = colors.yellow, text = " < ", tab = tabsByLabel.craft, callBack = "craftLeft" }
- buttons.rightCraft = { startX = (tabDims[tabsByLabel.craft].width - 9), startY = tabDims[tabsByLabel.craft].height, endX = (tabDims[tabsByLabel.craft].width - 5), endY = tabDims[tabsByLabel.craft].height, fg = colors.black, bg = colors.yellow, text = " > ", tab = tabsByLabel.craft, callBack = "craftRight" }
- if useMonitor == true then
- term.clear()
- term.setCursorPos(1,1)
- print("Status Monitor...")
- print()
- if monitor ~= nil then print("Monitor: Present") else print("Monitor: Absent") end
- if bridge ~= nil then print("ME Bridge: Present") else print("ME Bridge: Absent") end
- if modem ~= nil then print("Wireless Modem: Present") else print("Wireless Modem: Absent") end
- if speaker ~= nil then print("Speaker: Present") else print("Speaker: Absent") end
- print()
- print("Press 'q' to quit")
- end
- display.clear()
- updateHeader()
- -- Read the persisted craftables maintain data if it exists
- if fs.exists(craftMaintainFileName) == true then
- local file = fs.open(craftMaintainFileName, "r")
- local data = file.readAll()
- file.close()
- craftMaintain = textutils.unserialize(data)
- end
- local pollTimer = os.startTimer(0)
- while true do
- local event, p1, p2, p3, p4, p5 = os.pullEvent()
- -- If 'q' is pressed, then we quit
- if event == "key" then
- if p1 == keys.q then
- term.setCursorPos(1,11)
- return
- end
- -- If we get a modem message, process it for status messages
- elseif event == "modem_message" and p2 == statusChannelID then
- local msgstatus = textutils.unserialize(p4)
- for key, value in pairs(msgstatus) do
- if key == "Inventory" then
- inventory = value
- else
- status[key] = value
- end
- end
- updateGeneral()
- -- If we get a click event, see if there is an associated line (craftables) or button to process
- elseif event == clickEvent then
- local but = identifyButton(p2, p3)
- if but ~= nil then
- getfenv()[but.callBack]()
- elseif curTab == tabsByLabel.craft then
- local itemIndex = p3 - tabDims[tabsByLabel.craft].offsetY
- if craftList[itemIndex] ~= nil then
- craftEditItem = craftList[itemIndex]
- local key = craftEditItem.name .. ":" .. craftEditItem.meta
- if craftMaintain[key] ~= nil then
- craftEditItem.maintain = craftMaintain[key].maintain
- else
- craftEditItem.maintain = 0
- end
- craftInteractive = true
- updateCraft()
- end
- else
- --print("No button found")
- end
- -- If we get a crafting complete message from the PPP ME Bridge then trigger a craft check
- elseif event == "craftingComplete" and bridge ~= nil then
- updateCraft()
- updateGeneral()
- --checkAutoCraft()
- -- If we get our timer event then check for autocrafting and update the status pages
- elseif event == "timer" and p1 == pollTimer and bridge ~= nil then
- -- The initial crafting status message (for local display)
- if status["Crafting"] == nil then status["Crafting"] = "Nothing" end
- if crafting == true then craftCheckCount = craftCheckCount + 1 end
- updateCraft()
- checkAutoCraft()
- local transmitStatus = {}
- transmitStatus["Crafting"] = status["Crafting"]
- if modem ~= nil then modem.transmit(statusChannelID, 0, textutils.serialize(transmitStatus)) end
- pollTimer = os.startTimer(5)
- end
- end
Advertisement
Add Comment
Please, Sign In to add comment
Advertisement