Advertisement
Guest User

Untitled

a guest
Dec 3rd, 2016
73
0
Never
Not a member of Pastebin yet? Sign Up, it unlocks many cool features!
Lua 33.64 KB | None | 0 0
  1. -- RF Control Center (RFCC) v0.3
  2. --     by dlord
  3.  
  4.  
  5. -- Main configuration
  6. local tArgs = {...}
  7. local CONFIG_FILE = "power_conf"
  8.  
  9. local CONFIG_TEMPLATE = [[-- adjust these configuration options as necessary.
  10. -- delay for checking all capacitors
  11. TICK_DELAY = ${tickDelay}
  12.  
  13. -- threshold in percentages
  14. GREEN_ZONE = ${greenZone}
  15. YELLOW_ZONE = ${yellowZone}
  16.  
  17. NORMAL_POWER_THRESHOLD = ${nomalPowerThreshold}
  18. LOW_POWER_THRESHOLD = ${lowPowerThreshold}
  19.  
  20. -- configures what side to emit when low power
  21. -- a valid side is required.
  22. SIDE_TO_EMIT_REDSTONE_ON_LOW_POWER = "${sideForRedstone}"
  23.  
  24. -- Active monitors on startup
  25. MONITORS_ACTIVE = ${monitorsActive}
  26. ]]
  27.  
  28. local MONITORS_ACTIVE = {}
  29.  
  30. do
  31.     if #tArgs > 0 and tArgs[1] == "update" then
  32.         print("Updating RFCC...")
  33.         local updateFile = "/rfcc_update"
  34.         local pastebinKey = "TfeHE7Wy"
  35.         shell.run("pastebin", "get", pastebinKey, updateFile)
  36.  
  37.         if fs.exists(updateFile) then
  38.             local programPath = shell.getRunningProgram()
  39.             fs.delete(programPath)
  40.             fs.move(updateFile, programPath)
  41.             print("Success!")
  42.             return
  43.         else
  44.             print("Unable to retrieve update from pastebin.")
  45.             print("Check your connection, and try again.")
  46.             error()
  47.         end
  48.     end
  49. end
  50.  
  51. local function interpolate(s, params)
  52.     return s:gsub('($%b{})', function(w) return params[w:sub(3, -2)] or w end)
  53. end
  54.  
  55. local function saveSettings()
  56.     local h = fs.open("/"..CONFIG_FILE, "w")
  57.  
  58.     local settings = {
  59.         tickDelay = TICK_DELAY or 100,
  60.         greenZone = GREEN_ZONE or 70,
  61.         yellowZone = YELLOW_ZONE or 30,
  62.         nomalPowerThreshold = NORMAL_POWER_THRESHOLD or 90,
  63.         lowPowerThreshold = LOW_POWER_THRESHOLD or 10,
  64.         sideForRedstone = SIDE_TO_EMIT_REDSTONE_ON_LOW_POWER or "bottom",
  65.         monitorsActive = textutils.serialize(MONITORS_ACTIVE)
  66.     }
  67.  
  68.     h.write(interpolate(CONFIG_TEMPLATE, settings))
  69.     h.close()
  70. end
  71.  
  72.  
  73. if fs.exists(CONFIG_FILE) == false then
  74.     print("I can't find my configuration file.")
  75.     print("Generating one for you.")
  76.  
  77.     saveSettings()
  78.  
  79.     print("")
  80.     print("Configuration file is located at /"..CONFIG_FILE)
  81.     print("You may edit this file to change my default settings.")
  82.     print("Once satisfied, run me again.")
  83.     return
  84. else
  85.     os.unloadAPI(CONFIG_FILE)
  86.  
  87.     if os.loadAPI("/"..CONFIG_FILE) == false then
  88.         error("Could not load the config file!")
  89.     end
  90.  
  91.     CONFIG = nil
  92.     for k, v in pairs(_G) do
  93.         if k == CONFIG_FILE then
  94.             CONFIG = v
  95.             break
  96.         end
  97.     end
  98.  
  99.     if CONFIG == nil then
  100.         print("I could not find the necessary config.")
  101.         print("You probably screwed something up.")
  102.         error()
  103.     end
  104. end
  105.  
  106. term.setCursorPos(1, 1)
  107. term.clear()
  108. print("Starting RF Control Center...")
  109. sleep(2)
  110.  
  111. -- Constants
  112. local GET_ENERGY_STORED_FUNCTION="getEnergyStored"
  113. local GET_MAX_ENERGY_STORED_FUNCTION="getMaxEnergyStored"
  114.  
  115. local TICK_DELAY = CONFIG.TICK_DELAY
  116. local PAUSE_TIME_IN_SECONDS = TICK_DELAY / 20
  117.  
  118. -- threshold in percentages
  119. local GREEN_ZONE = CONFIG.GREEN_ZONE
  120. local YELLOW_ZONE = CONFIG.YELLOW_ZONE
  121.  
  122. local NORMAL_POWER_THRESHOLD = CONFIG.NORMAL_POWER_THRESHOLD
  123. local LOW_POWER_THRESHOLD = CONFIG.LOW_POWER_THRESHOLD
  124.  
  125. -- configures what side to emit when low power
  126. local SIDE_TO_EMIT_REDSTONE_ON_LOW_POWER = CONFIG.SIDE_TO_EMIT_REDSTONE_ON_LOW_POWER
  127.  
  128. MONITORS_ACTIVE = CONFIG.MONITORS_ACTIVE
  129.  
  130. -- state variables
  131. local clickableLines = {}
  132. local clickableOutputMonitors = {}
  133. local monitors = {}
  134. local capacitors = {}
  135. local dashboardButtons = {}
  136. local totalEnergyAvailable, totalCapacity, totalFlowRate = 0, 0, 0
  137.  
  138. -- Capacitor basic functions
  139. do
  140.     capacitors.add = function(params)
  141.         table.insert(capacitors, params)
  142.     end
  143.  
  144.     capacitors.get = function(name)
  145.         for i, v in ipairs(capacitors) do
  146.             if name == v.name then
  147.                 return v
  148.             end
  149.         end
  150.  
  151.         return nil
  152.     end
  153.  
  154.     capacitors.remove = function(name)
  155.         local found = nil
  156.         for i, v in ipairs(capacitors) do
  157.             if name == v.name then
  158.                 found = i
  159.                 break
  160.             end
  161.         end
  162.  
  163.         if found then
  164.             table.remove(capacitors, found)
  165.         end
  166.     end
  167.  
  168.     capacitors.clear = function()
  169.         for i, v in ipairs(capacitors) do
  170.             capacitors[i] = nil
  171.         end
  172.     end
  173. end
  174.  
  175.  
  176. -- Special Windows
  177. local nativeDisplayTabs = {}
  178. local nativeMonitorTabWindow
  179. local consoleWindow
  180. local monitorSelectionWindow
  181.  
  182. do
  183.     local nativeTerm = term.native()
  184.     local width, height = term.getSize()
  185.     local x, y = 1, 2
  186.     local newWidth, newHeight = width, height - 1
  187.  
  188.     nativeTerm.setCursorPos(x, y)
  189.  
  190.     nativeMonitorTabWindow = window.create(nativeTerm, 1, 1, width, 1, false)
  191.  
  192.     consoleWindow = window.create(nativeTerm, x, y, newWidth, newHeight, false)
  193.     consoleWindow.active = true
  194.  
  195.     monitorSelectionWindow = window.create(nativeTerm, x, y, newWidth, newHeight, false)
  196.     monitorSelectionWindow.active = true
  197. end
  198.  
  199. -- TODO: break up this humongous script into smaller chunks that can be loaded
  200. --       via os.loadAPI().
  201.  
  202.  
  203. -- basic functions
  204. local function tableSize(targetTable)
  205.     local i = 0
  206.     for k, v in pairs(targetTable) do
  207.         i = i + 1
  208.     end
  209.  
  210.     return i
  211. end
  212.  
  213. local function padRight(text, width, padCharacter)
  214.     if width == nil then
  215.         width = term.getSize()
  216.     end
  217.  
  218.     padCount = width - string.len(text)
  219.  
  220.     if padCharacter == nil then
  221.         padCharacter = " "
  222.     end
  223.  
  224.     if padCount > 0 then
  225.         return text..string.rep(padCharacter, padCount)
  226.     else
  227.         return text
  228.     end
  229. end
  230.  
  231. local function padLeft(text, width, padCharacter)
  232.     if width == nil then
  233.         width = term.getSize()
  234.     end
  235.  
  236.     padCount = width - string.len(text)
  237.  
  238.     if padCharacter == nil then
  239.         padCharacter = " "
  240.     end
  241.  
  242.     if padCount > 0 then
  243.         return string.rep(padCharacter, padCount)..text
  244.     else
  245.         return text
  246.     end
  247. end
  248.  
  249. local function printZoneText(percent, callback)
  250.     if percent >= GREEN_ZONE then
  251.         term.setTextColor(colors.green)
  252.     elseif percent >= YELLOW_ZONE and percent < GREEN_ZONE then
  253.         term.setTextColor(colors.yellow)
  254.     else
  255.         term.setTextColor(colors.red)
  256.     end
  257.  
  258.     callback()
  259.  
  260.     term.setTextColor(colors.white)
  261. end
  262.  
  263. local function resetRedstoneState()
  264.     for k,v in pairs(rs.getSides()) do
  265.         rs.setOutput(v, false)
  266.     end
  267. end
  268. -- basic functions
  269.  
  270.  
  271. -- line drawing API
  272. local function drawVerticalLine(targetWindow, x, y, height)
  273.     targetWindow.setCursorPos(x, y)
  274.  
  275.     targetWindow.setBackgroundColor(colors.blue)
  276.     for i = 1, height do
  277.         targetWindow.write(" ")
  278.         targetWindow.setCursorPos(x, i)
  279.     end
  280.     targetWindow.setBackgroundColor(colors.black)
  281. end
  282.  
  283. local function drawHorizontalLine(targetWindow, x, y, width)
  284.     targetWindow.setCursorPos(x, y)
  285.     targetWindow.setBackgroundColor(colors.blue)
  286.     targetWindow.write(string.rep(" ", width))
  287.     targetWindow.setBackgroundColor(colors.black)
  288. end
  289. -- line drawing API
  290.  
  291.  
  292. -- window management
  293. local console = {
  294.     log = function(message)
  295.         local currentTerm = term.current()
  296.         term.redirect(consoleWindow)
  297.  
  298.         print(message)
  299.  
  300.         term.redirect(currentTerm)
  301.     end
  302. }
  303.  
  304. local function showWindows(...)
  305.     for i, v in ipairs(arg) do
  306.         if v.active == true then
  307.             v.setVisible(true)
  308.         else
  309.             v.setVisible(false)
  310.         end
  311.     end
  312. end
  313.  
  314. local function hideWindows(...)
  315.     for i, v in ipairs(arg) do
  316.         v.setVisible(false)
  317.     end
  318. end
  319.  
  320. local function getCursorPositionRelativeToParent(currentWindow)
  321.     -- determine offset of current window from parent
  322.     local x, y = currentWindow.getPosition()
  323.     local xOffset, yOffset = x - 1, y - 1
  324.    
  325.     local cursorX, cursorY = currentWindow.getCursorPos()
  326.     return cursorX + xOffset, cursorY + yOffset
  327. end
  328.  
  329. local function createInformationWindow(parentWindow)
  330.     local width, height = parentWindow.getSize()
  331.  
  332.     local widthOffset = 2
  333.     local heightOffset = 2
  334.  
  335.     local windowWidth = width - (widthOffset * 2)
  336.     local windowHeight = height - (heightOffset * 2)
  337.  
  338.     local informationWindow = window.create(parentWindow, 1 + widthOffset, 1 + heightOffset, windowWidth, windowHeight, false)
  339.     informationWindow.active = false
  340.  
  341.     drawHorizontalLine(informationWindow, 1, 1, windowWidth)
  342.     drawHorizontalLine(informationWindow, 1, windowHeight, windowWidth)
  343.  
  344.     drawVerticalLine(informationWindow, 1, 1, windowHeight)
  345.     drawVerticalLine(informationWindow, windowWidth, 1, windowHeight)
  346.  
  347.     return informationWindow
  348. end
  349.  
  350. local function createSummaryWindow(parentWindow, x, y)
  351.     local width, height = parentWindow.getSize()
  352.  
  353.     -- we make use of the parent window's cursor position to make it more convenient.
  354.     local x, y = parentWindow.getCursorPos()
  355.     local newHeight = height - (y - 1)
  356.  
  357.     local summaryWindow = window.create(parentWindow, x, y, width, newHeight, false)
  358.     summaryWindow.active = false
  359.  
  360.     return summaryWindow
  361. end
  362.  
  363. local function printToWindow(targetWindow, widthOffset, text)
  364.     local x, y = targetWindow.getCursorPos()
  365.     local width, height = targetWindow.getSize()
  366.     local maxTextSize = width - (widthOffset * 2)
  367.  
  368.     targetWindow.write(text:sub(1, maxTextSize))
  369.     targetWindow.setCursorPos(x, y+1)
  370. end
  371.  
  372. local function createDashboardWindows(parentWindow)
  373.     -- order is important here!
  374.     local summaryWindow = createSummaryWindow(parentWindow)
  375.     summaryWindow.active = true
  376.     local informationWindow = createInformationWindow(parentWindow)
  377.     informationWindow.active = false
  378.  
  379.     local windows = {
  380.         [1] = summaryWindow,
  381.         [2] = informationWindow,
  382.  
  383.         getSummaryWindow = function()
  384.             return summaryWindow
  385.         end,
  386.  
  387.         getInformationWindow = function()
  388.             return informationWindow
  389.         end
  390.     }
  391.  
  392.     return windows
  393. end
  394.  
  395. local function initializeNativeDisplayTabs()
  396.     local nativeTerm = term.native()
  397.     nativeTerm.setCursorPos(1, 2)
  398.  
  399.     local dashboardWindows = createDashboardWindows(nativeTerm)
  400.  
  401.     table.insert(nativeDisplayTabs, {
  402.         tab = {
  403.             label = "Dashboard",
  404.             event = "dashboard_clicked",
  405.             active = true,
  406.             startX = 0,
  407.             startY = 0
  408.         },
  409.  
  410.         windows = dashboardWindows
  411.     })
  412.     table.insert(nativeDisplayTabs, {
  413.         tab = {
  414.             label = "Monitors",
  415.             event = "monitors_clicked",
  416.             startX = 0,
  417.             startY = 0
  418.         },
  419.  
  420.         windows = { monitorSelectionWindow }
  421.     })
  422.     table.insert(nativeDisplayTabs, {
  423.         tab = {
  424.             label = "Console",
  425.             event = "console_clicked",
  426.             startX = 0,
  427.             startY = 0
  428.         },
  429.  
  430.         windows = { consoleWindow }
  431.     })
  432.  
  433.     nativeDisplayTabs.getSelectedTab = function(x, y)
  434.         if x == nil or y == nil then
  435.             return nil
  436.         end
  437.  
  438.         for i, v in ipairs(nativeDisplayTabs) do
  439.             local tab = v.tab
  440.             local withinX = x >= tab.startX and x <= tab.endX
  441.             local withinY = y >= tab.startY and y <= tab.endY
  442.  
  443.             if withinX and withinY then
  444.                 return i
  445.             end
  446.         end
  447.  
  448.         return nil
  449.     end
  450.  
  451.     nativeDisplayTabs.setSelectedTab = function(selected)
  452.         for i, v in ipairs(nativeDisplayTabs) do
  453.             if i == selected then
  454.                 v.tab.active = true
  455.             else
  456.                 v.tab.active = false
  457.             end
  458.         end
  459.     end
  460.  
  461.     nativeDisplayTabs.getActiveTab = function()
  462.         for i, v in ipairs(nativeDisplayTabs) do
  463.             if v.tab.active == true then
  464.                 return i
  465.             end
  466.         end
  467.     end
  468.  
  469.     nativeDisplayTabs.getDashboardWindows = function()
  470.         return dashboardWindows
  471.     end
  472. end
  473.  
  474. -- window management
  475.  
  476.  
  477. -- capacitor management
  478. local function addCapacitors(...)
  479.     local peripheralList = arg
  480.  
  481.     if #peripheralList == 0 then
  482.         peripheralList = peripheral.getNames()
  483.         capacitors.clear()
  484.     end
  485.  
  486.     for i, p in ipairs(peripheralList) do
  487.         local currentPeripheral = peripheral.wrap(p)
  488.  
  489.         if currentPeripheral[GET_ENERGY_STORED_FUNCTION] ~= nil and currentPeripheral[GET_MAX_ENERGY_STORED_FUNCTION] ~= nil and currentPeripheral[GET_ENERGY_STORED_FUNCTION]("north") ~= nil then
  490.             console.log("Adding new capacitor: "..p)
  491.             capacitors.add({
  492.                 name = p,
  493.                 peripheral = currentPeripheral,
  494.                 lastReading = 0,
  495.                 flowRate = 0,
  496.                 percent = 0
  497.             })
  498.         end
  499.     end
  500. end
  501.  
  502. local function removeCapacitors(...)
  503.     for i, k in ipairs(arg) do
  504.         capacitors.remove(k)
  505.     end
  506. end
  507.  
  508. local function getReading()
  509.     local totalEnergyAvailable, totalCapacity, totalFlowRate = 0, 0, 0
  510.  
  511.     for i, v in ipairs(capacitors) do
  512.         local currentReading = v.peripheral[GET_ENERGY_STORED_FUNCTION]("north") or 0
  513.         local capacity = v.peripheral[GET_MAX_ENERGY_STORED_FUNCTION]("north") or 0
  514.  
  515.         if currentReading ~= nil then
  516.             v.flowRate = (currentReading - v.lastReading) / TICK_DELAY
  517.             v.lastReading = currentReading
  518.  
  519.             if capacity == 0 then
  520.                 v.percent = 0
  521.             else
  522.                 v.percent = math.floor((currentReading / capacity) * 100)
  523.             end
  524.  
  525.             totalEnergyAvailable = totalEnergyAvailable + v.lastReading
  526.             totalFlowRate = totalFlowRate + v.flowRate
  527.         end
  528.  
  529.         totalCapacity = totalCapacity + capacity
  530.     end
  531.  
  532.     local sortByLastReading = function(a, b)
  533.         return a.percent > b.percent
  534.     end
  535.  
  536.     table.sort(capacitors, sortByLastReading)
  537.  
  538.     return totalEnergyAvailable, totalCapacity, totalFlowRate
  539. end
  540.  
  541. local function emitRedstoneSignalOnLowPower(percent)
  542.     if percent < LOW_POWER_THRESHOLD and rs.getOutput(SIDE_TO_EMIT_REDSTONE_ON_LOW_POWER) == false then
  543.         console.log("Low power threshold reached.")
  544.         rs.setOutput(SIDE_TO_EMIT_REDSTONE_ON_LOW_POWER, true)
  545.     elseif percent >= NORMAL_POWER_THRESHOLD and rs.getOutput(SIDE_TO_EMIT_REDSTONE_ON_LOW_POWER) == true then
  546.         console.log("Back to normal power levels.")
  547.         rs.setOutput(SIDE_TO_EMIT_REDSTONE_ON_LOW_POWER, false)
  548.     end
  549. end
  550. -- capacitor management
  551.  
  552.  
  553. -- monitor management
  554. local function addMonitors(...)
  555.     local monitorList = arg
  556.  
  557.     if #monitorList == 0 then
  558.         monitorList = peripheral.getNames()
  559.         monitors = {}
  560.     end
  561.  
  562.     for i, m in ipairs(monitorList) do
  563.         local currentPeripheral = peripheral.wrap(m)
  564.  
  565.         if "monitor" == peripheral.getType(m) and currentPeripheral.isColour() == true then
  566.             console.log("Adding new monitor: "..m)
  567.             currentPeripheral.setCursorPos(1, 1)
  568.             monitors[m] = {
  569.                 peripheral = currentPeripheral,
  570.                 windows = createDashboardWindows(currentPeripheral),
  571.                 active = false
  572.             }
  573.         end
  574.     end
  575. end
  576.  
  577. local function removeMonitors(...)
  578.     local activeMonitorsCount = tableSize(MONITORS_ACTIVE)
  579.  
  580.     for i, k in ipairs(arg) do
  581.         monitors[k] = nil
  582.         dashboardButtons[k] = nil
  583.         MONITORS_ACTIVE[k] = nil
  584.     end
  585.  
  586.     if activeMonitorsCount ~= tableSize(MONITORS_ACTIVE) then
  587.         saveSettings()
  588.     end
  589. end
  590. -- monitor management
  591.  
  592.  
  593. -- hotplug system
  594. local function doWhileMonitorSuspended(callback)
  595.     os.queueEvent("pause_monitor")
  596.     callback()
  597.     os.queueEvent("resume_monitor")
  598. end
  599.  
  600. local function hotplugPeripherals()
  601.     while true do
  602.         local event, name = os.pullEvent()
  603.         local callback = nil
  604.  
  605.         if event == "peripheral" then
  606.             console.log("Detected new peripheral: "..name)
  607.  
  608.             callback = function()
  609.                 addMonitors(name)
  610.                 addCapacitors(name)
  611.             end
  612.         elseif event == "peripheral_detach" then
  613.             console.log("Peripheral removed: "..name)
  614.  
  615.             callback = function()
  616.                 removeMonitors(name)
  617.                 removeCapacitors(name)
  618.             end
  619.         elseif event == "monitor_resize" then
  620.             console.log("Monitor resized: "..name)
  621.  
  622.             callback = function()
  623.                 monitors[name].peripheral.setCursorPos(1, 1)
  624.                 monitors[name].windows = createDashboardWindows(monitors[name].peripheral)
  625.                 dashboardButtons[name] = nil
  626.  
  627.                 if monitors[name].active == true then
  628.                     showWindows(unpack(monitors[name].windows))
  629.                 end
  630.             end
  631.         end
  632.  
  633.         if callback ~= nil then
  634.             doWhileMonitorSuspended(callback)
  635.         end
  636.     end
  637. end
  638. -- hotplug system
  639.  
  640.  
  641. -- information window for the capacitors
  642. local function addClickableLine(monitorName, key, currentY)
  643.     clickableLines[monitorName][key] = {
  644.         line = currentY
  645.     }
  646. end
  647.  
  648. local function toggleInformationWindow(summaryWindow, informationWindow, capacitorName)
  649.     if capacitorName == nil then
  650.         summaryWindow.active = true
  651.         informationWindow.active = false
  652.     else
  653.         summaryWindow.active = not summaryWindow.active
  654.         informationWindow.active = not informationWindow.active
  655.     end
  656.  
  657.     local capacitor = capacitors.get(capacitorName)
  658.  
  659.     if informationWindow.active == true then
  660.         widthOffset = 3
  661.         heightOffset = 3
  662.  
  663.         informationWindow.setCursorPos(widthOffset, heightOffset)
  664.         local width, height = informationWindow.getSize()
  665.         local labelWidth = width - (widthOffset * 2)
  666.         local capacity = capacitor.peripheral[GET_MAX_ENERGY_STORED_FUNCTION]("north")
  667.  
  668.         printToWindow(informationWindow, widthOffset, "Capacitor name:")
  669.         printToWindow(informationWindow, widthOffset, padRight("    "..capacitorName, labelWidth))
  670.         printToWindow(informationWindow, widthOffset, "Capacitor type:")
  671.         printToWindow(informationWindow, widthOffset, padRight("    "..peripheral.getType(capacitorName), labelWidth))
  672.         printToWindow(informationWindow, widthOffset, "Capacity:")
  673.         printToWindow(informationWindow, widthOffset, padRight("    "..capacity.." RF", labelWidth))
  674.         printToWindow(informationWindow, widthOffset, "Available:")
  675.         printToWindow(informationWindow, widthOffset, padRight("    "..capacitor.lastReading.." RF", labelWidth))
  676.  
  677.         local closeLabel = " Click anywhere to close "
  678.    
  679.         local x = math.floor(((width - string.len(closeLabel)) / 2 ) + 0.5)
  680.    
  681.         informationWindow.setCursorPos(x, height-2)
  682.  
  683.         informationWindow.setBackgroundColor(colors.red)
  684.         informationWindow.write(closeLabel)
  685.         informationWindow.setBackgroundColor(colors.black)
  686.     end
  687.  
  688.     showWindows(summaryWindow, informationWindow)
  689. end
  690.  
  691. local function checkForSelectableLine(monitorName, x, y)
  692.     if clickableLines[monitorName] == nil then
  693.         return nil
  694.     end
  695.  
  696.     for k,v in pairs(clickableLines[monitorName]) do
  697.         if y == v.line then
  698.             return k
  699.         end
  700.     end
  701.  
  702.     return nil
  703. end
  704.  
  705. local function getSelectedDashboardButton(monitorName, x, y)
  706.     if x == nil or y == nil then
  707.         return nil
  708.     end
  709.  
  710.     local v = dashboardButtons[monitorName]
  711.  
  712.     local nextButtonSelected = (x >= v.next.startX and x <= v.next.endX) and (y >= v.next.startY and y <= v.next.endY)
  713.     local prevButtonSelected = (x >= v.prev.startX and x <= v.prev.endX) and (y >= v.prev.startY and y <= v.prev.endY)
  714.  
  715.     if nextButtonSelected then
  716.         return "next"
  717.     elseif prevButtonSelected then
  718.         return "prev"
  719.     end
  720.  
  721.     return nil
  722. end
  723.  
  724. -- information window for the capacitors
  725.  
  726.  
  727. -- main display
  728. local function renderPaginationButtons(monitorName, max)
  729.     local width, height = term.getSize()
  730.     local nextButton = " Next "
  731.     local previousButton = " Prev "
  732.     local spacer = "     "
  733.  
  734.     local dashboardButtonsToRender = previousButton..spacer..nextButton
  735.     local buttonOffset = (width - (string.len(dashboardButtonsToRender))) / 2
  736.  
  737.     term.setCursorPos(buttonOffset, height)
  738.     local x, y = getCursorPositionRelativeToParent(term.current())
  739.  
  740.     if dashboardButtons[monitorName] ==  nil then
  741.         dashboardButtons[monitorName] = {
  742.             prev = {
  743.                 startX = x,
  744.                 startY = y,
  745.                 endX = x,
  746.                 endY = y
  747.             },
  748.  
  749.             next = {
  750.                 startX = x,
  751.                 startY = y,
  752.                 endX = x,
  753.                 endY = y
  754.             },
  755.  
  756.             offset = 1,
  757.             max = max
  758.         }
  759.     end
  760.  
  761.     if dashboardButtons[monitorName].offset == 1 then
  762.         dashboardButtons[monitorName].max = max
  763.     end
  764.  
  765.     term.setBackgroundColor(colors.red)
  766.     term.write(previousButton)
  767.     dashboardButtons[monitorName].prev.endX, dashboardButtons[monitorName].prev.endY = getCursorPositionRelativeToParent(term.current())
  768.  
  769.     term.setBackgroundColor(colors.black)
  770.     term.write(spacer)
  771.  
  772.     dashboardButtons[monitorName].next.startX, dashboardButtons[monitorName].next.startY = getCursorPositionRelativeToParent(term.current())
  773.     term.setBackgroundColor(colors.red)
  774.     term.write(nextButton)
  775.     dashboardButtons[monitorName].next.endX, dashboardButtons[monitorName].next.endY = getCursorPositionRelativeToParent(term.current())
  776.  
  777.     term.setBackgroundColor(colors.black)
  778. end
  779.  
  780. local function writeSummary(monitorName, totalEnergyAvailable, totalCapacity, totalFlowRate)
  781.     local width, height = term.getSize()
  782.     local gridLabel = os.getComputerLabel() or "No name set"
  783.     local gridLabelOffset = (width - (string.len(gridLabel))) / 2
  784.  
  785.     term.setCursorPos(gridLabelOffset, 1)
  786.     term.write(gridLabel)
  787.     term.setCursorPos(1, 3)
  788.  
  789.     print(padRight("Total Capacitors: "..tostring(#capacitors)))
  790.     monitor.setTextScale(4)
  791.     print(padRight("Max Energy Storage: "..totalCapacity.." RF"))
  792.     monitor.setTextScale(4)
  793.  
  794.     local totalPercentRemaining = math.floor((totalEnergyAvailable / totalCapacity) * 100)
  795.     emitRedstoneSignalOnLowPower(totalPercentRemaining)
  796.  
  797.     printZoneText(totalPercentRemaining, function() print(padRight("Energy Available: "..totalEnergyAvailable.." RF"))
  798.     monitor.setTextScale(4) end)
  799.                        
  800.     if totalFlowRate < 0 then
  801.         term.setTextColor(colors.red)
  802.     elseif totalFlowRate > 0 then
  803.         term.setTextColor(colors.green)
  804.     else
  805.         term.setTextColor(colors.white)
  806.     end
  807.  
  808.     print(padRight("Flow Rate: "..totalFlowRate.." RF/t"))
  809.     term.setTextColor(colors.white)
  810.     monitor.setTextScale(4)
  811.  
  812.     local currentX, currentY = term.getCursorPos()
  813.     term.setCursorPos(1, currentY+1)
  814.  
  815.     clickableLines[monitorName] = {}
  816.     local pagination = dashboardButtons[monitorName] or {}
  817.     local offset = pagination.offset or 1
  818.  
  819.     local count = 0
  820.     for i = offset, #capacitors do
  821.         local v = capacitors[i]
  822.         local name = string.format(" %03d", i)..": "
  823.         local percent = v.percent
  824.  
  825.         printZoneText(percent, function() term.write(name) monitor.setTextScale(4) end)
  826.  
  827.         local labelLength = string.len(name)
  828.         local powerBarLength = width - labelLength - 1
  829.         local powerBarReading = math.floor((width - labelLength - 1) * (percent/100))
  830.  
  831.         local zoneColor = colors.red
  832.         local textColor = colors.white
  833.         if percent >= GREEN_ZONE then
  834.             zoneColor = colors.green
  835.         elseif percent >= YELLOW_ZONE and percent < GREEN_ZONE then
  836.             zoneColor = colors.yellow
  837.             textColor = colors.blue
  838.         end
  839.  
  840.         local stats = padRight(string.format(" %d", percent).."%, "..v.flowRate.." RF/t", powerBarLength)
  841.  
  842.         term.setTextColor(textColor)
  843.         term.setBackgroundColor(zoneColor)
  844.         j = 1
  845.         for c in stats:gmatch(".") do
  846.             if(j>powerBarReading) then
  847.                 term.setBackgroundColor(colors.black)
  848.             end
  849.  
  850.             term.write(c)
  851.  
  852.             j = j + 1
  853.         end
  854.         term.setTextColor(colors.white)
  855.         term.setBackgroundColor(colors.black)
  856.  
  857.         local currentX, currentY = getCursorPositionRelativeToParent(term.current())
  858.         addClickableLine(monitorName, v.name, currentY)
  859.  
  860.         local termX, termY = term.getCursorPos()
  861.         term.setCursorPos(1, termY+2)
  862.         count = count + 1
  863.  
  864.         if termY > (height - 4) then
  865.             max = count
  866.             break
  867.         end
  868.     end
  869.  
  870.     local currentX, currentY = term.getCursorPos()
  871.     for k = currentY, height-1 do
  872.         term.setCursorPos(1, k)
  873.         term.clearLine()
  874.     end
  875.  
  876.     renderPaginationButtons(monitorName, count)
  877. end
  878.  
  879. local function displaySummary(totalEnergyAvailable, totalCapacity, totalFlowRate, targetMonitor)
  880.     local listOfSummaryWindows = {
  881.         native = nativeDisplayTabs.getDashboardWindows().getSummaryWindow()
  882.     }
  883.  
  884.     for k, v in pairs(monitors) do
  885.         listOfSummaryWindows[k] = v.windows.getSummaryWindow()
  886.     end
  887.  
  888.     for k, v in pairs(listOfSummaryWindows) do
  889.         if targetMonitor == nil or (k == targetMonitor) then
  890.             local currentTerm = term.current()
  891.  
  892.             term.redirect(v)
  893.  
  894.             writeSummary(k, totalEnergyAvailable, totalCapacity, totalFlowRate)
  895.  
  896.             term.redirect(currentTerm)
  897.  
  898.             if k == targetMonitor then
  899.                 return
  900.             end
  901.         end
  902.     end
  903. end
  904.  
  905. local function monitorCapacitors()
  906.     totalEnergyAvailable, totalCapacity, totalFlowRate = 0, 0, 0
  907.  
  908.     while true do
  909.         -- show reading
  910.         displaySummary(totalEnergyAvailable, totalCapacity, totalFlowRate)
  911.  
  912.         -- need to call this first to get most current sample
  913.         getReading()
  914.  
  915.         local samplingTimer = os.startTimer(PAUSE_TIME_IN_SECONDS)
  916.         while true do
  917.             local event, p1 = os.pullEvent()
  918.             if event == "timer" and p1 == samplingTimer then
  919.                 totalEnergyAvailable, totalCapacity, totalFlowRate = getReading()
  920.                 break
  921.             elseif event == "pause_monitor" then
  922.                 os.pullEvent("resume_monitor")
  923.                 break
  924.             end
  925.         end
  926.     end
  927. end
  928.  
  929. local function changePages(monitor, x, y, isInformationWindowActive)
  930.     local selectedButton = getSelectedDashboardButton(monitor, x, y)
  931.     local showSummary = false
  932.  
  933.     if selectedButton == "next" and not isInformationWindowActive then
  934.         local newOffset = dashboardButtons[monitor].offset + (dashboardButtons[monitor].max or 0)
  935.         if newOffset <= #capacitors then
  936.             dashboardButtons[monitor].offset = newOffset
  937.  
  938.             showSummary = true
  939.         end
  940.     elseif selectedButton == "prev" and not isInformationWindowActive then
  941.         local newOffset = dashboardButtons[monitor].offset - (dashboardButtons[monitor].max or 0)
  942.         if newOffset > 0 then
  943.             dashboardButtons[monitor].offset = newOffset
  944.         else
  945.             dashboardButtons[monitor].offset = 1
  946.         end
  947.  
  948.         showSummary = true
  949.     end
  950.  
  951.     if showSummary then
  952.         displaySummary(totalEnergyAvailable, totalCapacity, totalFlowRate, p1)
  953.         return true
  954.     end
  955.  
  956.     return false
  957. end
  958.  
  959. local function nativeDashboardHandler()
  960.     while true do
  961.         local event, x, y = os.pullEvent("dashboard_clicked")
  962.         local isInformationWindowActive = nativeDisplayTabs.getDashboardWindows().getInformationWindow().active
  963.  
  964.         if not changePages("native", x, y, isInformationWindowActive) then
  965.             local selectedCapacitor = checkForSelectableLine("native", x, y)
  966.  
  967.             local summaryWindow = nativeDisplayTabs.getDashboardWindows().getSummaryWindow()
  968.             local informationWindow = nativeDisplayTabs.getDashboardWindows().getInformationWindow()
  969.  
  970.             toggleInformationWindow(summaryWindow, informationWindow, selectedCapacitor)
  971.         end
  972.     end
  973. end
  974.  
  975. local function monitorDashboardHandler()
  976.     while true do
  977.         local event, monitor, x, y = os.pullEvent("monitor_touch")
  978.  
  979.         if monitors[monitor].active == true then
  980.             local summaryWindow = monitors[monitor].windows.getSummaryWindow()
  981.             local informationWindow = monitors[monitor].windows.getInformationWindow()
  982.  
  983.             if not changePages(monitor, x, y, informationWindow.active) then
  984.                 local selectedCapacitor = checkForSelectableLine(monitor, x, y)
  985.                 toggleInformationWindow(summaryWindow, informationWindow, selectedCapacitor)
  986.             end
  987.         end
  988.     end
  989. end
  990. -- main display
  991.  
  992.  
  993. -- monitor selection screen (if monitor is attached)
  994. local function addClickableOutputMonitor(k, currentY)
  995.     clickableOutputMonitors[k] = {
  996.         line = currentY
  997.     }
  998. end
  999.  
  1000. local function toggleMonitor(monitorName)
  1001.     monitors[monitorName].active = not monitors[monitorName].active
  1002.  
  1003.     if monitors[monitorName].active then
  1004.         console.log("Enabling "..monitorName)
  1005.         MONITORS_ACTIVE[monitorName] = true
  1006.     else
  1007.         console.log("Disabling "..monitorName)
  1008.         MONITORS_ACTIVE[monitorName] = nil
  1009.  
  1010.         hideWindows(unpack(monitors[monitorName].windows))
  1011.         monitors[monitorName].peripheral.setBackgroundColor(colors.black)
  1012.         monitors[monitorName].peripheral.clear()
  1013.     end
  1014.  
  1015.     saveSettings()
  1016. end
  1017.  
  1018. local function showMonitorSelection(targetWindow)
  1019.     local currentTerm = term.current()
  1020.  
  1021.     term.redirect(targetWindow)
  1022.     term.setCursorPos(1, 1)
  1023.     term.clear()
  1024.  
  1025.     local width, height = term.getSize()
  1026.  
  1027.     if tableSize(monitors) > 0 then
  1028.         printToWindow(term, 0, "Select Output Monitor: ")
  1029.     else
  1030.         printToWindow(term, 0, "No Monitors found.")
  1031.     end
  1032.  
  1033.     printToWindow(term, 0, "")
  1034.  
  1035.     local currentX, currentY = term.getCursorPos()
  1036.     term.setCursorPos(currentX + 2, currentY)
  1037.  
  1038.     clickableOutputMonitors = {}
  1039.     for k, v in pairs(monitors) do
  1040.         currentX, currentY = getCursorPositionRelativeToParent(targetWindow)
  1041.         term.setBackgroundColor(colors.black)
  1042.  
  1043.         if v.active == true then
  1044.             term.setBackgroundColor(colors.blue)
  1045.             showWindows(unpack(v.windows))
  1046.         end
  1047.  
  1048.         label = padRight("  "..k, width-4)
  1049.         printToWindow(term, 0, label)
  1050.  
  1051.         addClickableOutputMonitor(k, currentY)
  1052.     end
  1053.     term.setBackgroundColor(colors.black)
  1054.  
  1055.     term.redirect(currentTerm)
  1056.  
  1057.     while true do
  1058.         local event, x, y = os.pullEvent()
  1059.  
  1060.         if "monitors_clicked" == event then
  1061.             for k, v in pairs(clickableOutputMonitors) do
  1062.                 if v.line == y then
  1063.                     toggleMonitor(k)
  1064.                     return
  1065.                 end
  1066.             end
  1067.         elseif event == "peripheral" or event == "peripheral_detach" then
  1068.             coroutine.yield()
  1069.             return
  1070.         end
  1071.     end
  1072. end
  1073.  
  1074. local function monitorSelection()
  1075.     for k, v in pairs(MONITORS_ACTIVE) do
  1076.         if monitors[k] then
  1077.             monitors[k].active = true
  1078.         end
  1079.     end
  1080.  
  1081.     while true do
  1082.         showMonitorSelection(monitorSelectionWindow)
  1083.     end
  1084. end
  1085.  
  1086. local function nativeDisplay()
  1087.     while true do
  1088.         local currentTerm = term.current()
  1089.  
  1090.         term.redirect(nativeMonitorTabWindow)
  1091.         nativeMonitorTabWindow.setVisible(true)
  1092.  
  1093.         term.setCursorPos(1, 1)
  1094.         term.setBackgroundColor(colors.gray)
  1095.         term.clearLine()
  1096.         term.setTextColor(colors.yellow)
  1097.  
  1098.         for i, v in ipairs(nativeDisplayTabs) do
  1099.             hideWindows(unpack(v.windows))
  1100.         end
  1101.  
  1102.         for i, v in ipairs(nativeDisplayTabs) do
  1103.             local tab = v.tab
  1104.             tab.startX, tab.startY = getCursorPositionRelativeToParent(term.current())
  1105.  
  1106.             if tab.active then
  1107.                 term.setBackgroundColor(colors.black)
  1108.                 showWindows(unpack(v.windows))
  1109.             else
  1110.                 term.setBackgroundColor(colors.gray)
  1111.             end
  1112.  
  1113.             term.write(" "..tab.label.." ")
  1114.             tab.endX, tab.endY = getCursorPositionRelativeToParent(term.current())
  1115.         end
  1116.         term.setTextColor(colors.white)
  1117.         term.redirect(currentTerm)
  1118.  
  1119.         while true do
  1120.             local event, selectedTab = os.pullEvent("selected_tab")
  1121.  
  1122.             if selectedTab then
  1123.                 nativeDisplayTabs.setSelectedTab(selectedTab)
  1124.                 break
  1125.             end
  1126.         end
  1127.     end
  1128. end
  1129.  
  1130. local function mouseClickEventMonitor()
  1131.     while true do
  1132.         local event, type, x, y = os.pullEvent("mouse_click")
  1133.         local selectedTab = nativeDisplayTabs.getSelectedTab(x, y)
  1134.  
  1135.         if selectedTab and nativeDisplayTabs.getDashboardWindows().getInformationWindow().active == false then
  1136.             os.queueEvent("selected_tab", selectedTab)
  1137.         elseif selectedTab == nil then
  1138.             local activeTab = nativeDisplayTabs[nativeDisplayTabs.getActiveTab()]
  1139.  
  1140.             os.queueEvent(activeTab.tab.event, x, y)
  1141.         end
  1142.     end
  1143. end
  1144.  
  1145. -- Initialization
  1146. initializeNativeDisplayTabs()
  1147. resetRedstoneState()
  1148. addCapacitors()
  1149. addMonitors()
  1150.  
  1151. while true do
  1152.     parallel.waitForAll(mouseClickEventMonitor, nativeDisplay, monitorSelection, hotplugPeripherals, monitorCapacitors, nativeDashboardHandler, monitorDashboardHandler)
  1153. end
Advertisement
Add Comment
Please, Sign In to add comment
Advertisement