Advertisement
Guest User

Untitled

a guest
May 1st, 2016
58
0
Never
Not a member of Pastebin yet? Sign Up, it unlocks many cool features!
  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.     print(padRight("Max Energy Storage: "..(totalCapacity * 75).." RF"))
  791.  
  792.     local totalPercentRemaining = math.floor((totalEnergyAvailable / totalCapacity) * 100)
  793.     emitRedstoneSignalOnLowPower(totalPercentRemaining)
  794.  
  795.     printZoneText(totalPercentRemaining, function() print(padRight("Energy Available: "..(totalEnergyAvailable * 75).." RF")) end)
  796.  
  797.     if totalFlowRate < 0 then
  798.         term.setTextColor(colors.red)
  799.     elseif totalFlowRate > 0 then
  800.         term.setTextColor(colors.green)
  801.     else
  802.         term.setTextColor(colors.white)
  803.     end
  804.  
  805.     print(padRight("Flow Rate: "..totalFlowRate.." RF/t"))
  806.     term.setTextColor(colors.white)
  807.  
  808.     local currentX, currentY = term.getCursorPos()
  809.     term.setCursorPos(1, currentY+1)
  810.  
  811.     clickableLines[monitorName] = {}
  812.     local pagination = dashboardButtons[monitorName] or {}
  813.     local offset = pagination.offset or 1
  814.  
  815.     local count = 0
  816.     for i = offset, #capacitors do
  817.         local v = capacitors[i]
  818.         local name = string.format(" %03d", i)..": "
  819.         local percent = v.percent
  820.  
  821.         printZoneText(percent, function() term.write(name) end)
  822.  
  823.         local labelLength = string.len(name)
  824.         local powerBarLength = width - labelLength - 1
  825.         local powerBarReading = math.floor((width - labelLength - 1) * (percent/100))
  826.  
  827.         local zoneColor = colors.red
  828.         local textColor = colors.white
  829.         if percent >= GREEN_ZONE then
  830.             zoneColor = colors.green
  831.         elseif percent >= YELLOW_ZONE and percent < GREEN_ZONE then
  832.             zoneColor = colors.yellow
  833.             textColor = colors.blue
  834.         end
  835.  
  836.         local stats = padRight(string.format(" %d", percent).."%, "..v.flowRate.." RF/t", powerBarLength)
  837.  
  838.         term.setTextColor(textColor)
  839.         term.setBackgroundColor(zoneColor)
  840.         j = 1
  841.         for c in stats:gmatch(".") do
  842.             if(j>powerBarReading) then
  843.                 term.setBackgroundColor(colors.black)
  844.             end
  845.  
  846.             term.write(c)
  847.  
  848.             j = j + 1
  849.         end
  850.         term.setTextColor(colors.white)
  851.         term.setBackgroundColor(colors.black)
  852.  
  853.         local currentX, currentY = getCursorPositionRelativeToParent(term.current())
  854.         addClickableLine(monitorName, v.name, currentY)
  855.  
  856.         local termX, termY = term.getCursorPos()
  857.         term.setCursorPos(1, termY+2)
  858.         count = count + 1
  859.  
  860.         if termY > (height - 4) then
  861.             max = count
  862.             break
  863.         end
  864.     end
  865.  
  866.     local currentX, currentY = term.getCursorPos()
  867.     for k = currentY, height-1 do
  868.         term.setCursorPos(1, k)
  869.         term.clearLine()
  870.     end
  871.  
  872.     renderPaginationButtons(monitorName, count)
  873. end
  874.  
  875. local function displaySummary(totalEnergyAvailable, totalCapacity, totalFlowRate, targetMonitor)
  876.     local listOfSummaryWindows = {
  877.         native = nativeDisplayTabs.getDashboardWindows().getSummaryWindow()
  878.     }
  879.  
  880.     for k, v in pairs(monitors) do
  881.         listOfSummaryWindows[k] = v.windows.getSummaryWindow()
  882.     end
  883.  
  884.     for k, v in pairs(listOfSummaryWindows) do
  885.         if targetMonitor == nil or (k == targetMonitor) then
  886.             local currentTerm = term.current()
  887.  
  888.             term.redirect(v)
  889.  
  890.             writeSummary(k, totalEnergyAvailable, totalCapacity, totalFlowRate)
  891.  
  892.             term.redirect(currentTerm)
  893.  
  894.             if k == targetMonitor then
  895.                 return
  896.             end
  897.         end
  898.     end
  899. end
  900.  
  901. local function monitorCapacitors()
  902.     totalEnergyAvailable, totalCapacity, totalFlowRate = 0, 0, 0
  903.  
  904.     while true do
  905.         -- show reading
  906.         displaySummary(totalEnergyAvailable, totalCapacity, totalFlowRate)
  907.  
  908.         -- need to call this first to get most current sample
  909.         getReading()
  910.  
  911.         local samplingTimer = os.startTimer(PAUSE_TIME_IN_SECONDS)
  912.         while true do
  913.             local event, p1 = os.pullEvent()
  914.             if event == "timer" and p1 == samplingTimer then
  915.                 totalEnergyAvailable, totalCapacity, totalFlowRate = getReading()
  916.                 break
  917.             elseif event == "pause_monitor" then
  918.                 os.pullEvent("resume_monitor")
  919.                 break
  920.             end
  921.         end
  922.     end
  923. end
  924.  
  925. local function changePages(monitor, x, y, isInformationWindowActive)
  926.     local selectedButton = getSelectedDashboardButton(monitor, x, y)
  927.     local showSummary = false
  928.  
  929.     if selectedButton == "next" and not isInformationWindowActive then
  930.         local newOffset = dashboardButtons[monitor].offset + (dashboardButtons[monitor].max or 0)
  931.         if newOffset <= #capacitors then
  932.             dashboardButtons[monitor].offset = newOffset
  933.  
  934.             showSummary = true
  935.         end
  936.     elseif selectedButton == "prev" and not isInformationWindowActive then
  937.         local newOffset = dashboardButtons[monitor].offset - (dashboardButtons[monitor].max or 0)
  938.         if newOffset > 0 then
  939.             dashboardButtons[monitor].offset = newOffset
  940.         else
  941.             dashboardButtons[monitor].offset = 1
  942.         end
  943.  
  944.         showSummary = true
  945.     end
  946.  
  947.     if showSummary then
  948.         displaySummary(totalEnergyAvailable, totalCapacity, totalFlowRate, p1)
  949.         return true
  950.     end
  951.  
  952.     return false
  953. end
  954.  
  955. local function nativeDashboardHandler()
  956.     while true do
  957.         local event, x, y = os.pullEvent("dashboard_clicked")
  958.         local isInformationWindowActive = nativeDisplayTabs.getDashboardWindows().getInformationWindow().active
  959.  
  960.         if not changePages("native", x, y, isInformationWindowActive) then
  961.             local selectedCapacitor = checkForSelectableLine("native", x, y)
  962.  
  963.             local summaryWindow = nativeDisplayTabs.getDashboardWindows().getSummaryWindow()
  964.             local informationWindow = nativeDisplayTabs.getDashboardWindows().getInformationWindow()
  965.  
  966.             toggleInformationWindow(summaryWindow, informationWindow, selectedCapacitor)
  967.         end
  968.     end
  969. end
  970.  
  971. local function monitorDashboardHandler()
  972.     while true do
  973.         local event, monitor, x, y = os.pullEvent("monitor_touch")
  974.  
  975.         if monitors[monitor].active == true then
  976.             local summaryWindow = monitors[monitor].windows.getSummaryWindow()
  977.             local informationWindow = monitors[monitor].windows.getInformationWindow()
  978.  
  979.             if not changePages(monitor, x, y, informationWindow.active) then
  980.                 local selectedCapacitor = checkForSelectableLine(monitor, x, y)
  981.                 toggleInformationWindow(summaryWindow, informationWindow, selectedCapacitor)
  982.             end
  983.         end
  984.     end
  985. end
  986. -- main display
  987.  
  988.  
  989. -- monitor selection screen (if monitor is attached)
  990. local function addClickableOutputMonitor(k, currentY)
  991.     clickableOutputMonitors[k] = {
  992.         line = currentY
  993.     }
  994. end
  995.  
  996. local function toggleMonitor(monitorName)
  997.     monitors[monitorName].active = not monitors[monitorName].active
  998.  
  999.     if monitors[monitorName].active then
  1000.         console.log("Enabling "..monitorName)
  1001.         MONITORS_ACTIVE[monitorName] = true
  1002.     else
  1003.         console.log("Disabling "..monitorName)
  1004.         MONITORS_ACTIVE[monitorName] = nil
  1005.  
  1006.         hideWindows(unpack(monitors[monitorName].windows))
  1007.         monitors[monitorName].peripheral.setBackgroundColor(colors.black)
  1008.         monitors[monitorName].peripheral.clear()
  1009.     end
  1010.  
  1011.     saveSettings()
  1012. end
  1013.  
  1014. local function showMonitorSelection(targetWindow)
  1015.     local currentTerm = term.current()
  1016.  
  1017.     term.redirect(targetWindow)
  1018.     term.setCursorPos(1, 1)
  1019.     term.clear()
  1020.  
  1021.     local width, height = term.getSize()
  1022.  
  1023.     if tableSize(monitors) > 0 then
  1024.         printToWindow(term, 0, "Select Output Monitor: ")
  1025.     else
  1026.         printToWindow(term, 0, "No Monitors found.")
  1027.     end
  1028.  
  1029.     printToWindow(term, 0, "")
  1030.  
  1031.     local currentX, currentY = term.getCursorPos()
  1032.     term.setCursorPos(currentX + 2, currentY)
  1033.  
  1034.     clickableOutputMonitors = {}
  1035.     for k, v in pairs(monitors) do
  1036.         currentX, currentY = getCursorPositionRelativeToParent(targetWindow)
  1037.         term.setBackgroundColor(colors.black)
  1038.  
  1039.         if v.active == true then
  1040.             term.setBackgroundColor(colors.blue)
  1041.             showWindows(unpack(v.windows))
  1042.         end
  1043.  
  1044.         label = padRight("  "..k, width-4)
  1045.         printToWindow(term, 0, label)
  1046.  
  1047.         addClickableOutputMonitor(k, currentY)
  1048.     end
  1049.     term.setBackgroundColor(colors.black)
  1050.  
  1051.     term.redirect(currentTerm)
  1052.  
  1053.     while true do
  1054.         local event, x, y = os.pullEvent()
  1055.  
  1056.         if "monitors_clicked" == event then
  1057.             for k, v in pairs(clickableOutputMonitors) do
  1058.                 if v.line == y then
  1059.                     toggleMonitor(k)
  1060.                     return
  1061.                 end
  1062.             end
  1063.         elseif event == "peripheral" or event == "peripheral_detach" then
  1064.             coroutine.yield()
  1065.             return
  1066.         end
  1067.     end
  1068. end
  1069.  
  1070. local function monitorSelection()
  1071.     for k, v in pairs(MONITORS_ACTIVE) do
  1072.         if monitors[k] then
  1073.             monitors[k].active = true
  1074.         end
  1075.     end
  1076.  
  1077.     while true do
  1078.         showMonitorSelection(monitorSelectionWindow)
  1079.     end
  1080. end
  1081.  
  1082. local function nativeDisplay()
  1083.     while true do
  1084.         local currentTerm = term.current()
  1085.  
  1086.         term.redirect(nativeMonitorTabWindow)
  1087.         nativeMonitorTabWindow.setVisible(true)
  1088.  
  1089.         term.setCursorPos(1, 1)
  1090.         term.setBackgroundColor(colors.gray)
  1091.         term.clearLine()
  1092.         term.setTextColor(colors.yellow)
  1093.  
  1094.         for i, v in ipairs(nativeDisplayTabs) do
  1095.             hideWindows(unpack(v.windows))
  1096.         end
  1097.  
  1098.         for i, v in ipairs(nativeDisplayTabs) do
  1099.             local tab = v.tab
  1100.             tab.startX, tab.startY = getCursorPositionRelativeToParent(term.current())
  1101.  
  1102.             if tab.active then
  1103.                 term.setBackgroundColor(colors.black)
  1104.                 showWindows(unpack(v.windows))
  1105.             else
  1106.                 term.setBackgroundColor(colors.gray)
  1107.             end
  1108.  
  1109.             term.write(" "..tab.label.." ")
  1110.             tab.endX, tab.endY = getCursorPositionRelativeToParent(term.current())
  1111.         end
  1112.         term.setTextColor(colors.white)
  1113.         term.redirect(currentTerm)
  1114.  
  1115.         while true do
  1116.             local event, selectedTab = os.pullEvent("selected_tab")
  1117.  
  1118.             if selectedTab then
  1119.                 nativeDisplayTabs.setSelectedTab(selectedTab)
  1120.                 break
  1121.             end
  1122.         end
  1123.     end
  1124. end
  1125.  
  1126. local function mouseClickEventMonitor()
  1127.     while true do
  1128.         local event, type, x, y = os.pullEvent("mouse_click")
  1129.         local selectedTab = nativeDisplayTabs.getSelectedTab(x, y)
  1130.  
  1131.         if selectedTab and nativeDisplayTabs.getDashboardWindows().getInformationWindow().active == false then
  1132.             os.queueEvent("selected_tab", selectedTab)
  1133.         elseif selectedTab == nil then
  1134.             local activeTab = nativeDisplayTabs[nativeDisplayTabs.getActiveTab()]
  1135.  
  1136.             os.queueEvent(activeTab.tab.event, x, y)
  1137.         end
  1138.     end
  1139. end
  1140.  
  1141. -- Initialization
  1142. initializeNativeDisplayTabs()
  1143. resetRedstoneState()
  1144. addCapacitors()
  1145. addMonitors()
  1146.  
  1147. while true do
  1148.     parallel.waitForAll(mouseClickEventMonitor, nativeDisplay, monitorSelection, hotplugPeripherals, monitorCapacitors, nativeDashboardHandler, monitorDashboardHandler)
  1149. end
Advertisement
Add Comment
Please, Sign In to add comment
Advertisement