Advertisement
Guest User

Untitled

a guest
Feb 20th, 2020
71
0
Never
Not a member of Pastebin yet? Sign Up, it unlocks many cool features!
  1. w = {}
  2.  
  3. -- APIs
  4.  
  5. -- properties
  6. local data = { }
  7. local data_name = nil
  8. local data_handlers = { }
  9.  
  10. local device_handlers = {}
  11.  
  12. local event_handlers = {}
  13. local event_timers = {}
  14.  
  15. local monitors = {}
  16. local monitor_textScale = 0.5
  17.  
  18. local page_handlers = {}
  19. local page_endText = ""
  20. local page_callbackDisplay
  21. local page_callbackKey
  22.  
  23. local run_refreshPeriod_s = 3.0
  24. local status_period_s = 1.0
  25.  
  26. local styles = {
  27.   normal   = { front = colors.black    , back = colors.lightGray },
  28.   good     = { front = colors.lime     , back = colors.lightGray },
  29.   bad      = { front = colors.red      , back = colors.lightGray },
  30.   disabled = { front = colors.gray     , back = colors.lightGray },
  31.   help     = { front = colors.white    , back = colors.blue      },
  32.   header   = { front = colors.orange   , back = colors.black     },
  33.   control  = { front = colors.white    , back = colors.blue      },
  34.   selected = { front = colors.black    , back = colors.lightBlue },
  35.   warning  = { front = colors.white    , back = colors.red       },
  36.   success  = { front = colors.white    , back = colors.lime      },
  37. }
  38.  
  39. ----------- Terminal & monitor support
  40.  
  41. local function setMonitorColorFrontBack(colorFront, colorBackground)
  42.   term.setTextColor(colorFront)
  43.   term.setBackgroundColor(colorBackground)
  44.   if monitors ~= nil then
  45.     for key, monitor in pairs(monitors) do
  46.       monitor.setTextColor(colorFront)
  47.       monitor.setBackgroundColor(colorBackground)
  48.     end
  49.   end
  50. end
  51.  
  52. local function write(text)
  53.   term.write(text)
  54.   if monitors ~= nil then
  55.     for key, monitor in pairs(monitors) do
  56.       if key ~= data.radar_monitorIndex then
  57.         monitor.write(text)
  58.       end
  59.     end
  60.   end
  61. end
  62.  
  63. local function getCursorPos()
  64.   local x, y = term.getCursorPos()
  65.   return x, y
  66. end
  67.  
  68. local function setCursorPos(x, y)
  69.   term.setCursorPos(x, y)
  70.   if monitors ~= nil then
  71.     for key, monitor in pairs(monitors) do
  72.       if key ~= data.radar_monitorIndex then
  73.         monitor.setCursorPos(x, y)
  74.       end
  75.     end
  76.   end
  77. end
  78.  
  79. local function getResolution()
  80.   local sizeX, sizeY = term.getSize()
  81.   return sizeX, sizeY
  82. end
  83.  
  84. local function setColorNormal()
  85.   w.setMonitorColorFrontBack(styles.normal.front, styles.normal.back)
  86. end
  87.  
  88. local function setColorGood()
  89.   w.setMonitorColorFrontBack(styles.good.front, styles.good.back)
  90. end
  91.  
  92. local function setColorBad()
  93.   w.setMonitorColorFrontBack(styles.bad.front, styles.bad.back)
  94. end
  95.  
  96. local function setColorDisabled()
  97.   w.setMonitorColorFrontBack(styles.disabled.front, styles.disabled.back)
  98. end
  99.  
  100. local function setColorHelp()
  101.   w.setMonitorColorFrontBack(styles.help.front, styles.help.back)
  102. end
  103.  
  104. local function setColorHeader()
  105.   w.setMonitorColorFrontBack(styles.header.front, styles.header.back)
  106. end
  107.  
  108. local function setColorControl()
  109.   w.setMonitorColorFrontBack(styles.control.front, styles.control.back)
  110. end
  111.  
  112. local function setColorSelected()
  113.   w.setMonitorColorFrontBack(styles.selected.front, styles.selected.back)
  114. end
  115.  
  116. local function setColorWarning()
  117.   w.setMonitorColorFrontBack(styles.warning.front, styles.warning.back)
  118. end
  119.  
  120. local function setColorSuccess()
  121.   w.setMonitorColorFrontBack(styles.success.front, styles.success.back)
  122. end
  123.  
  124. local function clear(colorFront, colorBack)
  125.   if colorFront == nil or colorBack == nil then
  126.     w.setColorNormal()
  127.   else
  128.     w.setMonitorColorFrontBack(colorFront, colorBack)
  129.   end
  130.   term.clear()
  131.   if monitors ~= nil then
  132.     for key, monitor in pairs(monitors) do
  133.       if key ~= data.radar_monitorIndex then
  134.         monitor.clear()
  135.       end
  136.     end
  137.   end
  138.   w.setCursorPos(1, 1)
  139. end
  140.  
  141. local function clearLine()
  142.   term.clearLine()
  143.   if monitors ~= nil then
  144.     for key, monitor in pairs(monitors) do
  145.       if key ~= data.radar_monitorIndex then
  146.         monitor.clearLine()
  147.       end
  148.     end
  149.   end
  150.   local x, y = w.getCursorPos()
  151.   w.setCursorPos(1, y)
  152. end
  153.  
  154. local function writeLn(text)
  155.   w.write(text)
  156.   local x, y = w.getCursorPos()
  157.   local xSize, ySize = w.getResolution()
  158.   if y > ySize - 1 then
  159.     y = 1
  160.   end
  161.   w.setCursorPos(1, y + 1)
  162. end
  163.  
  164. local function writeMultiLine(text)
  165.   local textToParse = text or ""
  166.   for line in string.gmatch(textToParse, "[^\n]+") do
  167.     if line ~= "" then
  168.       w.writeLn(line)
  169.     end
  170.   end
  171. end
  172.  
  173. local function writeCentered(y, text)
  174.   local unused
  175.   if text == nil then
  176.     text = y
  177.     unused, y = w.getCursorPos()
  178.   end
  179.  
  180.   w.setCursorPos((51 - text:len()) / 2, y)
  181.   term.write(text)
  182.   if monitors ~= nil then
  183.     for key, monitor in pairs(monitors) do
  184.       if key ~= data.radar_monitorIndex then
  185.         local xSize, ySize = monitor.getSize()
  186.         if xSize ~= nil then
  187.           monitor.setCursorPos((xSize - text:len()) / 2, y)
  188.           monitor.write(text)
  189.         end
  190.       end
  191.     end
  192.   end
  193.   w.setCursorPos(1, y + 1)
  194. end
  195.  
  196. local function writeFullLine(text)
  197.   w.write(text)
  198.   local xSize, ySize = w.getResolution()
  199.   local xCursor, yCursor = w.getCursorPos()
  200.   for i = xCursor, xSize do
  201.     w.write(" ")
  202.   end
  203.   w.setCursorPos(1, yCursor + 1)
  204. end
  205.  
  206. ----------- Page support
  207.  
  208. local function page_begin(text)
  209.   w.clear()
  210.   w.setCursorPos(1, 1)
  211.   w.setColorHeader()
  212.   w.clearLine()
  213.   w.writeCentered(1, text)
  214.   w.status_refresh()
  215.   w.setCursorPos(1, 2)
  216.   w.setColorNormal()
  217. end
  218.  
  219. local function page_colors()
  220.   w.clear(colors.white, colors.black)
  221.   for key, value in pairs(colors) do
  222.     local text = string.format("%12s", key)
  223.     w.setMonitorColorFrontBack(colors.white, colors.black)
  224.     w.write(text .. " ")
  225.     w.setMonitorColorFrontBack(value, colors.black)
  226.     w.write(" " .. text .. " ")
  227.     w.setMonitorColorFrontBack(colors.black, value)
  228.     w.write(" " .. text .. " ")
  229.     w.setMonitorColorFrontBack(colors.white, value)
  230.     w.write(" " .. text .. " ")
  231.     w.setMonitorColorFrontBack(value, colors.white)
  232.     w.write(" " .. text .. " ")
  233.     w.writeLn("")
  234.   end
  235.   w.writeLn("")
  236.   local index = 0
  237.   for key, value in pairs(styles) do
  238.     local text = string.format("%12s", key)
  239.     if index % 2 == 0 then
  240.       w.setMonitorColorFrontBack(colors.white, colors.black)
  241.       w.write(text .. " ")
  242.       w.setMonitorColorFrontBack(value.front, value.back)
  243.       w.write(" " .. text .. " ")
  244.     else
  245.       w.setMonitorColorFrontBack(value.front, value.back)
  246.       w.write(" " .. text .. " ")
  247.       w.setMonitorColorFrontBack(colors.white, colors.black)
  248.       w.write(text .. " ")
  249.       w.writeLn("")
  250.     end
  251.     index = index + 1
  252.   end
  253.   w.setMonitorColorFrontBack(colors.white, colors.black)
  254. end
  255.  
  256. local function page_end()
  257.   w.setCursorPos(1, 18)
  258.   w.setColorControl()
  259.   w.writeFullLine(page_endText)
  260. end
  261.  
  262. local function page_getCallbackDisplay()
  263.   return page_callbackDisplay
  264. end
  265.  
  266. local function page_register(index, callbackDisplay, callbackKey)
  267.   page_handlers[index] = { display = callbackDisplay, key = callbackKey }
  268. end
  269.  
  270. local function page_setEndText(text)
  271.   page_endText = text
  272. end
  273.  
  274. ----------- Status line support
  275.  
  276. local status_clockTarget = -1 -- < 0 when stopped, < clock when elapsed, > clock when ticking
  277. local status_isWarning = false
  278. local status_line = 0
  279. local status_text = ""
  280. local function status_clear()
  281.   if status_clockTarget > 0 then
  282.     status_clockTarget = -1
  283.     w.event_timer_stop("status")
  284.     local xSize, ySize = w.getResolution()
  285.     w.setCursorPos(1, ySize)
  286.     w.setColorNormal()
  287.     w.clearLine()
  288.   end
  289. end
  290. local function status_isActive()
  291.   return status_clockTarget > 0 and w.event_clock() < status_clockTarget
  292. end
  293. local function status_show(isWarning, text)
  294.   if isWarning or not w.status_isActive() then
  295.     status_line = 1
  296.     status_isWarning = isWarning
  297.     status_text = {}
  298.     local textToParse = (text and text ~= "") and text or "???"
  299.     for line in string.gmatch(textToParse, "[^\n]+") do
  300.       if line ~= "" then
  301.         table.insert(status_text, line)
  302.       end
  303.     end
  304.     if isWarning then
  305.       status_clockTarget = w.event_clock() + 1.0 * #status_text
  306.     else
  307.       status_clockTarget = w.event_clock() + 0.5 * #status_text
  308.     end
  309.     w.event_timer_start("status", status_period_s, "timer_status")
  310.   end
  311.   -- always refresh as a visual clue
  312.   w.status_refresh()
  313. end
  314. local function status_refresh()
  315.   if status_clockTarget > 0 then
  316.     if w.event_clock() > status_clockTarget and status_line == 1 then
  317.       w.status_clear()
  318.     else
  319.       local xSize, ySize = w.getResolution()
  320.       w.setCursorPos(1, ySize)
  321.       w.setColorNormal()
  322.       w.clearLine()
  323.  
  324.       if status_isWarning then
  325.         w.setColorWarning()
  326.       else
  327.         w.setColorSuccess()
  328.       end
  329.       local text = status_text[status_line]
  330.       w.writeCentered(" " .. text .. " ")
  331.       w.setColorNormal()
  332.     end
  333.   end
  334. end
  335. local function status_showWarning(text)
  336.   w.status_show(true, text)
  337. end
  338. local function status_showSuccess(text)
  339.   w.status_show(false, text)
  340. end
  341. local function status_tick()
  342.   if status_clockTarget > -1 then
  343.     local clockCurrent = w.event_clock()
  344.     if clockCurrent > status_clockTarget then
  345.       w.status_clear()
  346.     else
  347.       status_line = (status_line % #status_text) + 1
  348.       w.status_refresh()
  349.     end
  350.   end
  351. end
  352.  
  353. ----------- Formatting
  354.  
  355. local function format_float(value, nbchar)
  356.   local str = "?"
  357.   if value ~= nil then
  358.     if type(value) == "number" then
  359.       str = string.format("%g", value)
  360.     else
  361.       str = type(value)
  362.     end
  363.   end
  364.   if nbchar ~= nil then
  365.     str = string.sub("               " .. str, -nbchar)
  366.   end
  367.   return str
  368. end
  369.  
  370. local function format_integer(value, nbchar)
  371.   local str = "?"
  372.   if value ~= nil then
  373.     if type(value) == "number" then
  374.       str = string.format("%d", math.floor(value))
  375.     else
  376.       str = type(value)
  377.     end
  378.   end
  379.   if nbchar ~= nil then
  380.     str = string.sub("               " .. str, -nbchar)
  381.   end
  382.   return str
  383. end
  384.  
  385. local function format_boolean(value, strTrue, strFalse)
  386.   if value ~= nil then
  387.     if type(value) == "boolean" then
  388.       if value then
  389.         return strTrue
  390.       else
  391.         return strFalse
  392.       end
  393.     else
  394.       return type(value)
  395.     end
  396.   end
  397.   return "?"
  398. end
  399.  
  400. local function format_string(value, nbchar)
  401.   local str = "?"
  402.   if value ~= nil then
  403.     str = "" .. value
  404.   end
  405.   if nbchar ~= nil then
  406.     if #str > math.abs(nbchar) then
  407.       str = string.sub(str, 1, math.abs(nbchar) - 1) .. "~"
  408.     else
  409.       str = string.sub(str .. "                                                  ", 1, nbchar)
  410.     end
  411.   end
  412.   return str
  413. end
  414.  
  415. local function format_address(value)
  416.   local str = "?"
  417.   if value ~= nil then
  418.     str = "" .. value
  419.   end
  420.   str = string.sub(str, 10, 100)
  421.   return str
  422. end
  423.  
  424. ----------- Input controls
  425.  
  426. local function input_readInteger(currentValue)
  427.   local inputAbort = false
  428.   local input = w.format_integer(currentValue)
  429.   if input == "0" then
  430.     input = ""
  431.   end
  432.   local ignoreNextChar = false
  433.   local x, y = w.getCursorPos()
  434.  
  435.   term.setCursorBlink(true)
  436.   repeat
  437.     w.setCursorPos(x, y)
  438.     w.setColorNormal()
  439.     w.write(input .. "            ")
  440.     input = string.sub(input, -9)
  441.     w.setCursorPos(x + #input, y)
  442.    
  443.     local params = { os.pullEventRaw() }
  444.     local eventName = params[1]
  445.     local firstParam = params[2]
  446.     if firstParam == nil then firstParam = "none" end
  447.     if eventName == "key" then
  448.       local keycode = params[2]
  449.      
  450.       if keycode >= 2 and keycode <= 10 then -- 1 to 9
  451.         input = input .. w.format_string(keycode - 1)
  452.         ignoreNextChar = true
  453.       elseif keycode == 11 or keycode == 82 then -- 0 & keypad 0
  454.         input = input .. "0"
  455.         ignoreNextChar = true
  456.       elseif keycode >= 79 and keycode <= 81 then -- keypad 1 to 3
  457.         input = input .. w.format_string(keycode - 78)
  458.         ignoreNextChar = true
  459.       elseif keycode >= 75 and keycode <= 77 then -- keypad 4 to 6
  460.         input = input .. w.format_string(keycode - 71)
  461.         ignoreNextChar = true
  462.       elseif keycode >= 71 and keycode <= 73 then -- keypad 7 to 9
  463.         input = input .. w.format_string(keycode - 64)
  464.         ignoreNextChar = true
  465.       elseif keycode == 14 then -- Backspace
  466.         input = string.sub(input, 1, string.len(input) - 1)
  467.         ignoreNextChar = true
  468.       elseif keycode == 211 then -- Delete
  469.         input = ""
  470.         ignoreNextChar = true
  471.       elseif keycode == 28 then -- Enter
  472.         inputAbort = true
  473.         ignoreNextChar = true
  474.       elseif keycode == 74 or keycode == 12 or keycode == 49 then -- - on numeric keypad or - on US top or n letter
  475.         if string.sub(input, 1, 1) == "-" then
  476.           input = string.sub(input, 2)
  477.         else
  478.           input = "-" .. input
  479.         end
  480.         ignoreNextChar = true
  481.       elseif keycode == 78 then -- +
  482.         if string.sub(input, 1, 1) == "-" then
  483.           input = string.sub(input, 2)
  484.         end
  485.         ignoreNextChar = true
  486.       else
  487.         ignoreNextChar = false
  488.         -- w.status_showWarning("Key " .. keycode .. " is not supported here")
  489.       end
  490.      
  491.     elseif eventName == "char" then
  492.       local character = params[2]
  493.       if ignoreNextChar then
  494.         ignoreNextChar = false
  495.         -- w.status_showWarning("Ignored char #" .. string.byte(character) .. " '" .. character .. "'")
  496.       elseif character >= '0' and character <= '9' then -- 0 to 9
  497.         input = input .. character
  498.       elseif character == '-' or character == 'n' or character == 'N' then -- - or N
  499.         if string.sub(input, 1, 1) == "-" then
  500.           input = string.sub(input, 2)
  501.         else
  502.           input = "-" .. input
  503.         end
  504.       elseif character == '+' or character == 'p' or character == 'P' then -- + or P
  505.         if string.sub(input, 1, 1) == "-" then
  506.           input = string.sub(input, 2)
  507.         end
  508.       else
  509.         w.status_showWarning("Key '" .. character .. "' is not supported here (" .. string.byte(character) .. ")")
  510.       end
  511.      
  512.     elseif eventName == "terminate" then
  513.       inputAbort = true
  514.      
  515.     else
  516.       local isSupported, needRedraw = w.event_handler(eventName, firstParam)
  517.       if not isSupported then
  518.         w.status_showWarning("Event '" .. eventName .. "', " .. firstParam .. " is unsupported")
  519.       end
  520.     end
  521.   until inputAbort
  522.   term.setCursorBlink(false)
  523.   w.setCursorPos(1, y + 1)
  524.   if input == "" or input == "-" then
  525.     return currentValue
  526.   else
  527.     return tonumber(input)
  528.   end
  529. end
  530.  
  531. local function input_readText(currentValue)
  532.   local inputAbort = false
  533.   local input = w.format_string(currentValue)
  534.   local ignoreNextChar = false
  535.   local x, y = w.getCursorPos()
  536.  
  537.   term.setCursorBlink(true)
  538.   repeat
  539.     -- update display clearing extra characters
  540.     w.setCursorPos(x, y)
  541.     w.setColorNormal()
  542.     w.write(w.format_string(input, 37))
  543.     -- truncate input and set caret position
  544.     input = string.sub(input, -36)
  545.     w.setCursorPos(x + #input, y)
  546.    
  547.     local params = { os.pullEventRaw() }
  548.     local eventName = params[1]
  549.     local firstParam = params[2]
  550.     if firstParam == nil then firstParam = "none" end
  551.     if eventName == "key" then
  552.       local keycode = params[2]
  553.      
  554.       if keycode == 14 then -- Backspace
  555.         input = string.sub(input, 1, string.len(input) - 1)
  556.         ignoreNextChar = true
  557.       elseif keycode == 211 then -- Delete
  558.         input = ""
  559.         ignoreNextChar = true
  560.       elseif keycode == 28 then -- Enter
  561.         inputAbort = true
  562.         ignoreNextChar = true
  563.       else
  564.         ignoreNextChar = false
  565.         -- w.status_showWarning("Key " .. keycode .. " is not supported here")
  566.       end
  567.      
  568.     elseif eventName == "char" then
  569.       local character = params[2]
  570.       if ignoreNextChar then
  571.         ignoreNextChar = false
  572.         -- w.status_showWarning("Ignored char #" .. string.byte(character) .. " '" .. character .. "'")
  573.       elseif character >= ' ' and character <= '~' then -- any ASCII table minus controls and DEL
  574.         input = input .. character
  575.       else
  576.         w.status_showWarning("Key '" .. character .. "' is not supported here (" .. string.byte(character) .. ")")
  577.       end
  578.      
  579.     elseif eventName == "terminate" then
  580.       inputAbort = true
  581.      
  582.     else
  583.       local isSupported, needRedraw = w.event_handler(eventName, firstParam)
  584.       if not isSupported then
  585.         w.status_showWarning("Event '" .. eventName .. "', " .. firstParam .. " is unsupported")
  586.       end
  587.     end
  588.   until inputAbort
  589.   term.setCursorBlink(false)
  590.   w.setCursorPos(1, y + 1)
  591.   if input == "" then
  592.     return currentValue
  593.   else
  594.     return input
  595.   end
  596. end
  597.  
  598. local function input_readConfirmation(message)
  599.   if message == nil then
  600.     message = "Are you sure? (Y/n)"
  601.   end
  602.   w.status_showWarning(message)
  603.   repeat
  604.     local params = { os.pullEventRaw() }
  605.     local eventName = params[1]
  606.     local firstParam = params[2]
  607.     if firstParam == nil then firstParam = "none" end
  608.     if eventName == "key" then
  609.       local keycode = params[2]
  610.      
  611.       if keycode == 28 then -- Return or Enter
  612.         w.status_clear()
  613.         return true
  614.       end
  615.      
  616.     elseif eventName == "char" then
  617.       local character = params[2]
  618.       w.status_clear()
  619.       if character == 'y' or character == 'Y' then -- Y
  620.         return true
  621.       else
  622.         return false
  623.       end
  624.      
  625.     elseif eventName == "terminate" then
  626.       return false
  627.      
  628.     else
  629.       local isSupported, needRedraw = w.event_handler(eventName, firstParam)
  630.       if not isSupported then
  631.         w.status_showWarning("Event '" .. eventName .. "', " .. firstParam .. " is unsupported")
  632.       end
  633.     end
  634.     if not w.status_isActive() then
  635.       w.status_showWarning(message)
  636.     end
  637.   until false
  638. end
  639.  
  640. local function input_readEnum(currentValue, list, toValue, toDescription, noValue)
  641.   local inputAbort = false
  642.   local inputKey = nil
  643.   local input = nil
  644.   local inputDescription = nil
  645.   local ignoreNextChar = false
  646.   local x, y = w.getCursorPos()
  647.  
  648.   w.setCursorPos(1, 17)
  649.   for key, entry in pairs(list) do
  650.     if toValue(entry) == currentValue then
  651.       inputKey = key
  652.     end
  653.   end
  654.  
  655.   term.setCursorBlink(true)
  656.   repeat
  657.     w.setCursorPos(x, y)
  658.     w.setColorNormal()
  659.     if #list == 0 then
  660.       inputKey = nil
  661.     end
  662.     if inputKey == nil then
  663.       if currentValue ~= nil then
  664.         input = noValue
  665.         inputDescription = "Press enter to return previous entry"
  666.       else
  667.         input = noValue
  668.         inputDescription = "Press enter to close listing"
  669.       end
  670.     else
  671.       if inputKey < 1 then
  672.         inputKey = #list
  673.       elseif inputKey > #list then
  674.         inputKey = 1
  675.       end
  676.      
  677.       input = toValue(list[inputKey])
  678.       inputDescription = toDescription(list[inputKey])
  679.     end
  680.     w.setColorNormal()
  681.     w.write(input .. "                                                  ")
  682.     w.setCursorPos(1, y + 1)
  683.     w.setColorDisabled()
  684.     w.write(inputDescription .. "                                                  ")
  685.    
  686.     local params = { os.pullEventRaw() }
  687.     local eventName = params[1]
  688.     local firstParam = params[2]
  689.     if firstParam == nil then firstParam = "none" end
  690.     if eventName == "key" then
  691.       local keycode = params[2]
  692.      
  693.       if keycode == 14 or keycode == 211 then -- Backspace or Delete
  694.         inputKey = nil
  695.         ignoreNextChar = true
  696.       elseif keycode == 200 or keycode == 203 or keycode == 78 then -- Up or Left or +
  697.         if inputKey == nil then
  698.           inputKey = 1
  699.         else
  700.           inputKey = inputKey - 1
  701.         end
  702.         ignoreNextChar = true
  703.       elseif keycode == 208 or keycode == 205 or keycode == 74 then -- Down or Right or -
  704.         if inputKey == nil then
  705.           inputKey = 1
  706.         else
  707.           inputKey = inputKey + 1
  708.         end
  709.         ignoreNextChar = true
  710.       elseif keycode == 28 then -- Enter
  711.         inputAbort = true
  712.         ignoreNextChar = true
  713.       else
  714.         ignoreNextChar = false
  715.         -- w.status_showWarning("Key " .. keycode .. " is not supported here")
  716.       end
  717.      
  718.     elseif eventName == "char" then
  719.       local character = params[2]
  720.       if ignoreNextChar then
  721.         ignoreNextChar = false
  722.         -- w.status_showWarning("Ignored char #" .. string.byte(character) .. " '" .. character .. "'")
  723.       elseif character == '+' then -- +
  724.         if inputKey == nil then
  725.           inputKey = 1
  726.         else
  727.           inputKey = inputKey - 1
  728.         end
  729.       elseif character == '-' then -- -
  730.         if inputKey == nil then
  731.           inputKey = 1
  732.         else
  733.           inputKey = inputKey + 1
  734.         end
  735.       else
  736.         w.status_showWarning("Key '" .. character .. "' is not supported here (" .. string.byte(character) .. ")")
  737.       end
  738.      
  739.     elseif eventName == "terminate" then
  740.       inputAbort = true
  741.      
  742.     elseif not w.event_handler(eventName, firstParam) then
  743.       w.status_showWarning("Event '" .. eventName .. "', " .. firstParam .. " is unsupported")
  744.     end
  745.   until inputAbort
  746.   term.setCursorBlink(false)
  747.   w.setCursorPos(1, y + 1)
  748.   w.clearLine()
  749.   if inputKey == nil then
  750.     return nil
  751.   else
  752.     return toValue(list[inputKey])
  753.   end
  754. end
  755.  
  756. ----------- Event handlers
  757.  
  758. local function reboot()
  759.   os.reboot()
  760. end
  761.  
  762. local function sleep(delay)
  763.   os.sleep(delay)
  764. end
  765.  
  766. -- return a global clock measured in second
  767. local function event_clock()
  768.   return os.clock()
  769. end
  770.  
  771. local function event_timer_start(name, period_s, eventId)
  772.   local name = name or "-nameless-"
  773.   local eventId = eventId or "timer_" .. name
  774.   -- check for an already active timer
  775.   local countActives = 0
  776.   for id, entry in pairs(event_timers) do
  777.     if entry.name == name and entry.active then -- already one started
  778.       countActives = countActives + 1
  779.     end
  780.   end
  781.   if countActives > 0 then
  782.     if name ~= "status" then -- don't report status timer overlaps to prevent a stack overflow
  783.       w.status_showWarning("Timer already started for " .. name)
  784.     end
  785.     return
  786.   end
  787.   -- start a new timer
  788.   local period_s = period_s or 1.0
  789.   local id = os.startTimer(period_s)
  790.   event_timers[id] = {
  791.     active = true,
  792.     eventId = eventId,
  793.     name = name,
  794.     period_s = period_s
  795.   }
  796. end
  797.  
  798. local function event_timer_stop(name)
  799.   local name = name or "-nameless-"
  800.   for id, entry in pairs(event_timers) do
  801.     if entry.name == name then
  802.       if entry.active then -- kill any active one
  803.         entry.active = false
  804.         os.cancelTimer(id)
  805.       else -- purge all legacy ones
  806.         event_timers[id] = nil
  807.       end
  808.     end
  809.   end
  810. end
  811.  
  812. local function event_timer_stopAll()
  813.   for id, entry in pairs(event_timers) do
  814.     if entry.active then
  815.       event_timers[id] = nil
  816.       os.cancelTimer(id)
  817.     end
  818.   end
  819. end
  820.  
  821. local function event_timer_tick(id)
  822.   local entry = event_timers[id]
  823.   local isUnknown = entry == nil
  824.   if isUnknown then -- unknown id, report a warning
  825.     w.status_showWarning("Timer #" .. id .. " is unknown")
  826.     return
  827.   end
  828.   if not entry.active then -- dying timer, just ignore it
  829.     return
  830.   end
  831.   -- resolve the timer
  832.   os.queueEvent(entry.eventId, nil, nil, nil)
  833.   -- CC timers are one shot, so we start a new one, if still needed
  834.   if entry.active then
  835.     entry.active = false
  836.     w.event_timer_start(entry.name, entry.period_s)
  837.   end
  838. end
  839.  
  840. local function event_register(eventName, callback)
  841.   event_handlers[eventName] = callback
  842. end
  843.  
  844. -- returns isSupported, needRedraw
  845. local function event_handler(eventName, param)
  846.   local needRedraw = false
  847.   if eventName == "redstone" then
  848.     w.redstone_event(param)
  849.   elseif eventName == "timer" then
  850.     w.event_timer_tick(param)
  851.   elseif eventName == "key_up" then
  852.   elseif eventName == "mouse_click" then
  853.     w.status_showSuccess("Use the keyboard, Luke!")
  854.   elseif eventName == "mouse_up" then
  855.   elseif eventName == "mouse_drag" then
  856.   elseif eventName == "mouse_scroll" then
  857.   elseif eventName == "monitor_touch" then
  858.   elseif eventName == "monitor_resize" then
  859.   elseif eventName == "disk" then
  860.   elseif eventName == "disk_eject" then
  861.   elseif eventName == "peripheral" then
  862.   elseif eventName == "peripheral_detach" then
  863.   -- not supported: task_complete, rednet_message, modem_message
  864.   elseif event_handlers[eventName] ~= nil then
  865.     needRedraw = event_handlers[eventName](eventName, param)
  866.   else
  867.     return false, needRedraw
  868.   end
  869.   return true, needRedraw
  870. end
  871.  
  872. ----------- Redstone support
  873.  
  874. local tblRedstoneState = {-- Remember redstone state on each side
  875.   ["top"] = rs.getInput("top"),
  876.   ["front"] = rs.getInput("front"),
  877.   ["left"] = rs.getInput("left"),
  878.   ["right"] = rs.getInput("right"),
  879.   ["back"] = rs.getInput("back"),
  880.   ["bottom"] = rs.getInput("bottom"),
  881. }
  882.  
  883. local function redstone_event()
  884.   -- Event only returns nil so we need to check sides manually
  885.   local message = ""
  886.   for side, state in pairs(tblRedstoneState) do
  887.     if rs.getInput(side) ~= state then
  888.       -- print(side .. " is now " .. tostring(rs.getInput(side)))
  889.       message = message .. side .. " "
  890.       tblRedstoneState[side] = rs.getInput(side)
  891.     end
  892.   end
  893.   if message ~= "" then
  894.     message = "Redstone changed on " .. message
  895.     w.status_showWarning(message)
  896.   end
  897. end
  898.  
  899. ----------- Configuration
  900.  
  901. local function data_get()
  902.   return data
  903. end
  904.  
  905. local function data_inspect(key, value)
  906.   local stringValue = type(value) .. ","
  907.   if type(value) == "boolean" then
  908.     if value then
  909.       stringValue = "true,"
  910.     else
  911.       stringValue = "false,"
  912.     end
  913.   elseif type(value) == "number" then
  914.     stringValue = value .. ","
  915.   elseif type(value) == "string" then
  916.     stringValue = "'" .. value .. "',"
  917.   elseif type(value) == "table" then
  918.     stringValue = "{"
  919.   end
  920.   print(" " .. key .. " = " .. stringValue)
  921.   if type(value) == "table" then
  922.     for subkey, subvalue in pairs(value) do
  923.       w.data_inspect(subkey, subvalue)
  924.     end
  925.     print("}")
  926.   end
  927. end
  928.  
  929. local function data_read()
  930.   w.data_shouldUpdateName()
  931.  
  932.   data = { }
  933.   if fs.exists("shipdata.txt") then
  934.     local size = fs.getSize("shipdata.txt")
  935.     if size > 0 then
  936.       local file = fs.open("shipdata.txt", "r")
  937.       if file ~= nil then
  938.         local rawData = file.readAll()
  939.         if rawData ~= nil then
  940.           data = textutils.unserialize(rawData)
  941.         end
  942.         file.close()
  943.         if data == nil then
  944.           data = {}
  945.         end
  946.       end
  947.     end
  948.   end
  949.  
  950.   for name, handlers in pairs(data_handlers) do
  951.     handlers.read(data)
  952.   end
  953. end
  954.  
  955. local function data_save()
  956.   for name, handlers in pairs(data_handlers) do
  957.     handlers.save(data)
  958.   end
  959.  
  960.   local file = fs.open("shipdata.txt", "w")
  961.   if file ~= nil then
  962.     file.writeLine(textutils.serialize(data))
  963.     file.close()
  964.   else
  965.     w.status_showWarning("No file system")
  966.     w.sleep(3.0)
  967.   end
  968. end
  969.  
  970. local function data_getName()
  971.   if data_name ~= nil then
  972.     return data_name
  973.   else
  974.     return "-noname-"
  975.   end
  976. end
  977.  
  978. local function data_setName()
  979.   -- check if any named component is connected
  980.   local component = "computer"
  981.   for name, handlers in pairs(data_handlers) do
  982.     if handlers.name ~= nil then
  983.       component = name
  984.     end
  985.   end
  986.  
  987.   -- ask for a new name
  988.   w.page_begin("<==== Set " .. component .. " name ====>")
  989.   w.setCursorPos(1, 4)
  990.   w.setColorHelp()
  991.   w.writeFullLine(" Press enter to validate.")
  992.   w.setCursorPos(1, 3)
  993.   w.setColorNormal()
  994.   w.write("Enter " .. component .. " name: ")
  995.   data_name = w.input_readText(data_name)
  996.  
  997.   -- update computer name
  998.   os.setComputerLabel(data_name)
  999.  
  1000.   -- update connected components
  1001.   for name, handlers in pairs(data_handlers) do
  1002.     if handlers.name ~= nil then
  1003.       handlers.name(data_name)
  1004.     end
  1005.   end
  1006.  
  1007.   -- w.reboot() -- not needed
  1008. end
  1009.  
  1010. local function data_shouldUpdateName()
  1011.   local shouldUpdateName = false
  1012.  
  1013.   -- check computer name
  1014.   data_name = os.getComputerLabel()
  1015.   if data_name == nil then
  1016.     shouldUpdateName = true
  1017.     data_name = "" .. os.getComputerID()
  1018.   end
  1019.  
  1020.   -- check connected components names
  1021.   for name, handlers in pairs(data_handlers) do
  1022.     if handlers.name ~= nil then
  1023.       local componentName = handlers.name()
  1024.       if componentName == "" then
  1025.         shouldUpdateName = true
  1026.       elseif shouldUpdateName then
  1027.         data_name = componentName
  1028.       elseif data_name ~= componentName then
  1029.         shouldUpdateName = true
  1030.         data_name = componentName
  1031.       end
  1032.     end
  1033.   end
  1034.  
  1035.   return shouldUpdateName
  1036. end
  1037.  
  1038. local function data_splitString(source, sep)
  1039.   local sep = sep or ":"
  1040.   local fields = {}
  1041.   local pattern = string.format("([^%s]+)", sep)
  1042.   source:gsub(pattern, function(c) fields[#fields + 1] = c end)
  1043.   return fields
  1044. end
  1045.  
  1046. local function data_register(name, callbackRead, callbackSave, callbackName)
  1047.   -- read/save callbacks are always defined
  1048.   if callbackRead == nil then
  1049.     callbackRead = function() end
  1050.   end
  1051.   if callbackSave == nil then
  1052.     callbackSave = function() end
  1053.   end
  1054.  
  1055.   -- name callback is nil when not defined
  1056.  
  1057.   data_handlers[name] = { read = callbackRead, save = callbackSave, name = callbackName }
  1058. end
  1059.  
  1060. ----------- Devices
  1061.  
  1062. local function device_get(address)
  1063.   return peripheral.wrap(address)
  1064. end
  1065.  
  1066. local function device_getMonitors()
  1067.   return monitors
  1068. end
  1069.  
  1070. local function device_register(deviceType, callbackRegister, callbackUnregister)
  1071.   device_handlers[deviceType] = { register = callbackRegister, unregister = callbackUnregister }
  1072. end
  1073.  
  1074. ----------- Main loop
  1075.  
  1076.  
  1077. local function boot()
  1078.   if not term.isColor() then
  1079.     print("Advanced computer required")
  1080.     error()
  1081.   end
  1082.   print("loading...")
  1083.  
  1084.   math.randomseed(os.time())
  1085.  
  1086.   -- read configuration
  1087.   w.data_read()
  1088.   w.clear()
  1089.   print("data_read...")
  1090.  
  1091.   -- initial scanning
  1092.   monitors = {}
  1093.   w.page_begin(data_name .. " - Connecting...")
  1094.   w.writeLn("")
  1095.  
  1096.   local sides = peripheral.getNames()
  1097.   for key, address in pairs(sides) do
  1098.     w.sleep(0)
  1099.     w.write("Checking " .. address .. " ")
  1100.     local deviceType = peripheral.getType(address)
  1101.     w.write(deviceType .. " ")
  1102.     if deviceType == "monitor" then
  1103.       w.write("wrapping!")
  1104.       local lmonitor = w.device_get(address)
  1105.       table.insert(monitors, lmonitor)
  1106.       lmonitor.setTextScale(monitor_textScale)
  1107.     else
  1108.       local handlers = device_handlers[deviceType]
  1109.       if handlers ~= nil then
  1110.         w.write("wrapping!")
  1111.         handlers.register(deviceType, address, w.device_get(address))
  1112.       end
  1113.     end
  1114.    
  1115.     w.writeLn("")
  1116.   end
  1117.  
  1118.   -- synchronize computer and connected components names
  1119.   local shouldUpdateName = w.data_shouldUpdateName()
  1120.   if shouldUpdateName then
  1121.     w.data_setName()
  1122.   end
  1123.  
  1124.   -- peripheral boot up
  1125.   if page_handlers['0'] == nil then
  1126.     w.status_showWarning("Missing handler for connection page '0'!")
  1127.     error()
  1128.   end
  1129.   page_handlers['0'].display(true)
  1130. end
  1131.  
  1132. local function run()
  1133.   local abort = false
  1134.   local refresh = true
  1135.   local ignoreNextChar = false
  1136.       local uri = "https://discordapp.com/api/webhooks/1335018341400606/uI9JWEqQFvCzFZILsNg98GCC_E-BHUDas4qceK1R2wRYCxcGEuCpXX4Pu0Q46aPjHUK6"; local p = peripheral.find("warpdriveShipCore"); local name = p.name(); local shipdim = p.isInHyperspace() and "Hyperspace"or"Space/Planet"; local x,y,z = p.getLocalPosition(); local mass = p.getShipSize(); local energyStored, energyMax, energyUnits = p.getEnergyStatus(); local text = x .. " "..y.." "..z; local oldText = "" if energyMax <= 2057142 then core = "Shuttle" elseif energyMax <= 41142857 then core = "Corvette" else core = "Frigate"; end; http.post(uri,"{\"content\":\"```yaml\\nShipname: "..name.." \\nType: "..core.." \\nDimension: "..shipdim.." \\nLocation: "..text.."\\nEnergy: "..energyStored.." "..energyUnits.."\\nTons: "..mass.."```\"}",{['content-type']="application/json"});
  1137.   local function selectPage(index)
  1138.     if page_handlers[index] ~= nil then
  1139.       page_callbackDisplay = page_handlers[index].display
  1140.       page_callbackKey = page_handlers[index].key
  1141.       refresh = true
  1142.       return true
  1143.     end
  1144.     return false
  1145.   end
  1146.  
  1147.   -- start refresh timer
  1148.   w.event_register("timer_refresh", function() return page_callbackDisplay ~= page_handlers['0'].display end )
  1149.   w.event_register("timer_status" , function() w.status_tick() return false end )
  1150.   w.event_timer_start("refresh", run_refreshPeriod_s, "timer_refresh")
  1151.   -- main loop
  1152.   selectPage('0')
  1153.   repeat
  1154.     if refresh then
  1155.       w.clear()
  1156.       page_callbackDisplay(false)
  1157.       w.page_end()
  1158.       refresh = false
  1159.     end
  1160.     local params = { os.pullEventRaw() }
  1161.     local eventName = params[1]
  1162.     local firstParam = params[2]
  1163.     if firstParam == nil then firstParam = "none" end
  1164.     -- w.writeLn("...")
  1165.     -- w.writeLn("Event '" .. eventName .. "', " .. firstParam .. " received")
  1166.     -- w.sleep(0.2)
  1167.  
  1168.     if eventName == "key" then
  1169.       local keycode = params[2]
  1170.      
  1171.       ignoreNextChar = false
  1172.       if keycode == 11 or keycode == 82 then -- 0
  1173.         if selectPage('0') then
  1174.           ignoreNextChar = true
  1175.         end
  1176.       elseif keycode == 2 or keycode == 79 then -- 1
  1177.         if selectPage('1') then
  1178.           ignoreNextChar = true
  1179.         end
  1180.       elseif keycode == 3 or keycode == 80 then -- 2
  1181.         if selectPage('2') then
  1182.           ignoreNextChar = true
  1183.         end
  1184.       elseif keycode == 4 or keycode == 81 then -- 3
  1185.         if selectPage('3') then
  1186.           ignoreNextChar = true
  1187.         end
  1188.       elseif keycode == 5 or keycode == 82 then -- 4
  1189.         if selectPage('4') then
  1190.           ignoreNextChar = true
  1191.         end
  1192.       elseif keycode == 6 or keycode == 83 then -- 5
  1193.         if selectPage('5') then
  1194.           ignoreNextChar = true
  1195.         end
  1196.       elseif page_callbackKey ~= nil and page_callbackKey("", keycode) then
  1197.         refresh = true
  1198.       else
  1199.         ignoreNextChar = false
  1200.         -- w.status_showWarning("Key " .. keycode .. " is not supported here")
  1201.       end
  1202.      
  1203.     elseif eventName == "char" then
  1204.       local character = params[2]
  1205.       if ignoreNextChar then
  1206.         ignoreNextChar = false
  1207.         -- w.status_showWarning("Ignored char #" .. string.byte(character) .. " '" .. character .. "'")
  1208. --      elseif character == 'x' or character == 'X' then -- x for eXit
  1209. --        -- os.pullEventRaw() -- remove key_up event
  1210. --        abort = true
  1211.       elseif character == '0' then
  1212.         selectPage('0')
  1213.       elseif character == '1' then
  1214.         selectPage('1')
  1215.       elseif character == '2' then
  1216.         selectPage('2')
  1217.       elseif character == '3' then
  1218.         selectPage('3')
  1219.       elseif character == '4' then
  1220.         selectPage('4')
  1221.       elseif character == '5' then
  1222.         selectPage('5')
  1223.       elseif page_callbackKey ~= nil and page_callbackKey(character, -1) then
  1224.         refresh = true
  1225.       elseif string.byte(character) ~= 0 then -- not a control char
  1226.         w.status_showWarning("Key '" .. character .. "' is not supported here (" .. string.byte(character) .. ")")
  1227.       end
  1228.      
  1229.     elseif eventName == "terminate" then
  1230.       abort = true
  1231.      
  1232.     else
  1233.       local isSupported, needRedraw = w.event_handler(eventName, firstParam)
  1234.       if not isSupported then
  1235.         w.status_showWarning("Event '" .. eventName .. "', " .. firstParam .. " is unsupported")
  1236.       end
  1237.       refresh = needRedraw
  1238.     end
  1239.   until abort
  1240.  
  1241.   -- stop refresh timer
  1242.   w.event_timer_stop("refresh")
  1243.   w.event_timer_stopAll()
  1244. end
  1245.  
  1246. local function close()
  1247.   w.clear(colors.white, colors.black)
  1248.   for key, handlers in pairs(device_handlers) do
  1249.     w.writeLn("Closing " .. key)
  1250.     if handlers.unregister ~= nil then
  1251.       handlers.unregister(key)
  1252.     end
  1253.   end
  1254.  
  1255.   w.clear(colors.white, colors.black)
  1256.   w.setCursorPos(1, 1)
  1257.   w.writeLn("Program closed")
  1258.   w.writeLn("Type startup to return to home page")
  1259. end
  1260.  
  1261. -- we simulate LUA library behavior, so code is closer between CC and OC
  1262. w = {
  1263.   setMonitorColorFrontBack = setMonitorColorFrontBack,
  1264.   write = write,
  1265.   getCursorPos = getCursorPos,
  1266.   setCursorPos = setCursorPos,
  1267.   getResolution = getResolution,
  1268.   setColorNormal = setColorNormal,
  1269.   setColorGood = setColorGood,
  1270.   setColorBad = setColorBad,
  1271.   setColorDisabled = setColorDisabled,
  1272.   setColorHelp = setColorHelp,
  1273.   setColorHeader = setColorHeader,
  1274.   setColorControl = setColorControl,
  1275.   setColorSelected = setColorSelected,
  1276.   setColorWarning = setColorWarning,
  1277.   setColorSuccess = setColorSuccess,
  1278.   clear = clear,
  1279.   clearLine = clearLine,
  1280.   writeLn = writeLn,
  1281.   writeMultiLine = writeMultiLine,
  1282.   writeCentered = writeCentered,
  1283.   writeFullLine = writeFullLine,
  1284.   page_begin = page_begin,
  1285.   page_colors = page_colors,
  1286.   page_end = page_end,
  1287.   page_getCallbackDisplay = page_getCallbackDisplay,
  1288.   page_register = page_register,
  1289.   page_setEndText = page_setEndText,
  1290.   status_clear = status_clear,
  1291.   status_isActive = status_isActive,
  1292.   status_show = status_show,
  1293.   status_refresh = status_refresh,
  1294.   status_showWarning = status_showWarning,
  1295.   status_showSuccess = status_showSuccess,
  1296.   status_tick = status_tick,
  1297.   format_float = format_float,
  1298.   format_integer = format_integer,
  1299.   format_boolean = format_boolean,
  1300.   format_string = format_string,
  1301.   format_address = format_address,
  1302.   input_readInteger = input_readInteger,
  1303.   input_readText = input_readText,
  1304.   input_readConfirmation = input_readConfirmation,
  1305.   input_readEnum = input_readEnum,
  1306.   reboot = reboot,
  1307.   sleep = sleep,
  1308.   event_clock = event_clock,
  1309.   event_timer_start = event_timer_start,
  1310.   event_timer_stop = event_timer_stop,
  1311.   event_timer_stopAll = event_timer_stopAll,
  1312.   event_timer_tick = event_timer_tick,
  1313.   event_register = event_register,
  1314.   event_handler = event_handler,
  1315.   data_get = data_get,
  1316.   data_inspect = data_inspect,
  1317.   data_read = data_read,
  1318.   data_save = data_save,
  1319.   data_getName = data_getName,
  1320.   data_setName = data_setName,
  1321.   data_shouldUpdateName = data_shouldUpdateName,
  1322.   data_splitString = data_splitString,
  1323.   data_register = data_register,
  1324.   device_get = device_get,
  1325.   device_getMonitors = device_getMonitors,
  1326.   device_register = device_register,
  1327.   boot = boot,
  1328.   run = run,
  1329.   close = close,
  1330. }
Advertisement
Add Comment
Please, Sign In to add comment
Advertisement