Advertisement
HydrantHunter

ccDHD Basic

Feb 8th, 2017
499
0
Never
Not a member of Pastebin yet? Sign Up, it unlocks many cool features!
Lua 58.47 KB | None | 0 0
  1. --[[    SGCraft    ]]--
  2. --[[  ccDHD Basic  ]]--
  3. --[[    by Dog     ]]--
  4. --[[     a k a     ]]--
  5. --[[ HydrantHunter ]]--
  6. --[[  pastebin:    ]]--
  7. --[[     JYpfKQL6  ]]--
  8. local ccDHDbasicVer = "1.0.38"
  9. --[[
  10. Tested with/requires:
  11.   - Minecraft 1.7.10+ AND ComputerCraft 1.75+ || SGCraft1.11.x-mc1.7.10+
  12.   - An advanced computer connected directly or via modem/network cable to...
  13.   - A stargate with a CC adapter
  14.  
  15. Special thanks to theoriginalbit for his custom read function
  16.  
  17. IMPORTANT NOTE: DO NOT EDIT this script - all variables are set automatically
  18. ]]--
  19. if not term.isColor() or pocket or turtle then error("Advanced computer required!\n", 0) end
  20. if not os.getComputerLabel() then os.setComputerLabel("ccDHD.cc#" .. tostring(os.getComputerID())) end
  21. local termX, termY = term.getSize()
  22. if termX ~= 51 or termY < 18 or termY > 19 then error("Screen size must be 51x18 or 51x19.\n", 0) end
  23. local sg = peripheral.find("stargate")
  24. if not sg then error("Unable to locate stargate!\n", 0) end
  25. local thisGate, nrgAvailable, irisState, dialTarget = sg.localAddress(), sg.energyAvailable(), sg.irisState(), sg.remoteAddress()
  26. if dialTarget == "" then dialTarget = "none" end
  27. local sgState, chevronsEngaged, callDirection = sg.stargateState()
  28. local MAXFUEL, abCount, gateChange, shift, gettingInput = 200000, 1, false, false, false
  29. local addressBook = { { name = thisGate, addr = thisGate, rating = "U", iris = "none", callDrop = false, note = "short note", loc = { x = 0, y = 0, z = 0, dim = "Unspecified" } } }
  30. do
  31.   local sgData
  32.   if fs.exists("/data/DHDgates") then
  33.     addressBook[1] = nil
  34.     sgData = fs.open("/data/DHDgates", "r")
  35.     addressBook = textutils.unserialize(sgData.readAll())
  36.     abCount = #addressBook
  37.   else
  38.     if not fs.exists("/data") then fs.makeDir("/data") end
  39.     sgData = fs.open("/data/DHDgates", "w")
  40.     sgData.write(textutils.serialize(addressBook))
  41.   end
  42.   sgData.close()
  43.   local saveIt = false
  44.   for i = 1, abCount do
  45.     if addressBook[i].iris == "open" then
  46.       addressBook[i].iris, saveIt = true, true
  47.     elseif addressBook[i].iris == "close" then
  48.       addressBook[i].iris, saveIt = false, true
  49.     end
  50.   end
  51.   if saveIt then
  52.     sgData = fs.open("/data/DHDgates", "w")
  53.     sgData.write(textutils.serialize(addressBook))
  54.     sgData.close()
  55.   end
  56. end
  57. local currentSelection, numPerPage, pageNum, numPages, logPage, logPages, callHistory, help = 1, 4, 1, math.ceil(abCount / 4), 1, 1, { }, false
  58. local editEntry, drawLabels, drawDetails, drawStargateState, drawHelp, dialOut, button, updateTimer
  59. local classifications = {
  60.   B = { order = 1, color = colors.blue, label = "Base/Outpost/Hub" };
  61.   H = { order = 2, color = colors.lightBlue, label = "Home/Camp" };
  62.   V = { order = 3, color = colors.brown, label = "Village" };
  63.   M = { order = 4, color = colors.purple, label = "Misc/Special" };
  64.   S = { order = 5, color = colors.green, label = "Safe/Secured" };
  65.   C = { order = 6, color = colors.orange, label = "Caution" };
  66.   D = { order = 7, color = colors.red, label = "Danger" };
  67.   U = { order = 8, color = colors.lightGray, label = "Unk/Unclassified", long = "Unknown/Unclassified" };
  68. }
  69.  
  70. --# Below is a subset of Dog's buttonBuddy API...
  71. do
  72.   local bbButtons, bbButtonCount = { }, 0
  73.   local validColors = { [1] = true; [2] = true; [4] = true; [8] = true; [16] = true; [32] = true; [64] = true; [128] = true; [256] = true; [512] = true; [1024] = true; [2048] = true; [4096] = true; [8192] = true; [16384] = true, [32768] = true; }
  74.   button = {
  75.     create = function(sText, bbGroup, x, y, w, h, mouseBtn, activate, funct, txtCol, bgCol, inactiveTxtCol, inactiveBgCol)
  76.       if type(sText) == "string" and (type(bbGroup) == "string" or bbGroup == nil) and type(x) == "number" and type(y) == "number" and type(w) == "number" and type(h) == "number" and (type(mouseButton) == "number" or mouseButton == nil) and (type(funct) == "function" or funct == nil) and type(activate) == "boolean" then
  77.         bbButtonCount = bbButtonCount + 1
  78.         w = math.floor(math.min(math.max(1, math.max(#sText, w)), termX))
  79.         h = math.floor(math.max(1, math.min(h, termY)))
  80.         x = math.floor(math.max(1, math.min(x, termX - w + 1)))
  81.         y = math.floor(math.max(1, math.min(y, termY - h + 1)))
  82.         if mouseBtn then mouseBtn = math.floor(mouseBtn) mouseBtn = (mouseBtn > 0 and mouseBtn < 4) and mouseBtn or 1 end
  83.         bbButtons[bbButtonCount] = {
  84.           text = sText:sub(1, w);
  85.           group = bbGroup;
  86.           startX = x;
  87.           startY = y;
  88.           width = w;
  89.           height = h;
  90.           mouseButton = mouseBtn;
  91.           active = activate;
  92.           func = type(funct) == "function" and funct or function() return true end;
  93.           txtColor = (type(txtCol) == "number" and validColors[txtCol]) and txtCol or colors.black;
  94.           bgColor = (type(bgCol) == "number" and validColors[bgCol]) and bgCol or colors.white;
  95.           inactiveTextColor = (type(inactiveTextCol) == "number" and validColors[inactiveTextCol]) and inactiveTextCol or colors.lightGray;
  96.           inactiveBgColor = (type(inactiveBgCol) == "number" and validColors[inactiveBgCol]) and inactiveBgCol or colors.gray;
  97.         }
  98.         return true, bbButtonCount
  99.       end
  100.       return false
  101.     end;
  102.  
  103.     check = function(x, y, mouseBtn, group)
  104.       if type(x) == "number" and type(y) == "number" and (type(mouseBtn) == "number" or mouseBtn == nil) and (type(group) == "string" or group == nil) and x > 0 and x <= termX and y > 0 and y <= termY then
  105.         local bbGroup, bbMBtn, startX, startY
  106.         if mouseBtn then mouseBtn = math.floor(mouseBtn) mouseBtn = (mouseBtn > 0 and mouseBtn < 4) and mouseBtn or 1 end
  107.         for id = 1, bbButtonCount do
  108.           bbGroup, bbMBtn, startX, startY = bbButtons[id]["group"], bbButtons[id]["mouseButton"], bbButtons[id]["startX"], bbButtons[id]["startY"]
  109.           if (group and group == bbGroup) or not bbGroup then
  110.             if (mouseBtn and (bbMBtn == mouseBtn or not bbMBtn)) or (not mouseBtn and not bbMBtn) then
  111.               if x >= startX and x <= startX + bbButtons[id]["width"] - 1 and y >= startY and y <= startY + bbButtons[id]["height"] - 1 then
  112.                 if bbButtons[id]["active"] then
  113.                   local success, returnData = bbButtons[id]["func"](id, mouseBtn)
  114.                   if type(success) == "boolean" then return success, id, returnData else return true, id, returnData or success end
  115.                 else
  116.                   return false, id
  117.                 end
  118.               end
  119.             end
  120.           end
  121.         end
  122.       end
  123.       return false
  124.     end;
  125.  
  126.     render = function(target, groupOnly)
  127.       local active, line, text, txtLine, txtLen, txtRow, startX, startY, buttonHeight, buttonWidth
  128.       if type(target) == "number" and target > 0 and target <= bbButtonCount then
  129.         startX, startY = bbButtons[target]["startX"], bbButtons[target]["startY"]
  130.         buttonHeight, buttonWidth = bbButtons[target]["height"], bbButtons[target]["width"]
  131.         text = bbButtons[target]["text"]
  132.         txtLen, active = #text, bbButtons[target]["active"]
  133.         txtLine = string.rep(" ", math.floor((buttonWidth - txtLen) / 2)) .. text .. string.rep(" ", math.ceil((buttonWidth - txtLen) / 2))
  134.         term.setTextColor(active and bbButtons[target]["txtColor"] or bbButtons[target]["inactiveTextColor"])
  135.         term.setBackgroundColor(active and bbButtons[target]["bgColor"] or bbButtons[target]["inactiveBgColor"])
  136.         if buttonHeight == 1 then
  137.           term.setCursorPos(startX, startY)
  138.           term.write(txtLine)
  139.         else
  140.           line, txtRow = string.rep(" ", buttonWidth), startY + math.floor(buttonHeight / 2)
  141.           for yPos = startY, startY + buttonHeight - 1 do
  142.             term.setCursorPos(startX, yPos)
  143.             term.write(yPos == txtRow and txtLine or line)
  144.           end
  145.         end
  146.         return true, 1
  147.       elseif type(target) == "string" or target == nil then
  148.         local buttonsRendered, bbGroup = 0
  149.         for id = 1, bbButtonCount do
  150.           bbGroup = bbButtons[id]["group"]
  151.           if (type(target) == "string" and bbGroup == target) or (not bbGroup and not groupOnly) then
  152.             startX, startY = bbButtons[id]["startX"], bbButtons[id]["startY"]
  153.             buttonHeight, buttonWidth = bbButtons[id]["height"], bbButtons[id]["width"]
  154.             text = bbButtons[id]["text"]
  155.             txtLen, active = #text, bbButtons[id]["active"]
  156.             txtLine = string.rep(" ", math.floor((buttonWidth - txtLen) / 2)) .. text .. string.rep(" ", math.ceil((buttonWidth - txtLen) / 2))
  157.             term.setTextColor(active and bbButtons[id]["txtColor"] or bbButtons[id]["inactiveTextColor"])
  158.             term.setBackgroundColor(active and bbButtons[id]["bgColor"] or bbButtons[id]["inactiveBgColor"])
  159.             if buttonHeight == 1 then
  160.               term.setCursorPos(startX, startY)
  161.               term.write(txtLine)
  162.             else
  163.               line, txtRow = string.rep(" ", buttonWidth), startY + math.floor(buttonHeight / 2)
  164.               for yPos = startY, startY + buttonHeight - 1 do
  165.                 term.setCursorPos(startX, yPos)
  166.                 term.write(yPos == txtRow and txtLine or line)
  167.               end
  168.             end
  169.             buttonsRendered = buttonsRendered + 1
  170.           end
  171.         end
  172.         return true, buttonsRendered
  173.       end
  174.       return false, 0
  175.     end;
  176.  
  177.     setFunction = function(id, funct)
  178.       if type(id) == "number" and id > 0 and id <= bbButtonCount and (type(funct) == "function" or funct == nil) then
  179.         bbButtons[id]["func"] = funct or function() return true end
  180.         return true
  181.       end
  182.       return false
  183.     end;
  184.  
  185.     setText = function(id, text)
  186.       if type(id) == "number" and id > 0 and id <= bbButtonCount and type(text) == "string" then
  187.         bbButtons[id]["text"] = #text <= (termX - bbButtons[id]["startX"] + 1) and text or text:sub(1, termX - bbButtons[id]["startX"] + 1)
  188.         bbButtons[id]["width"] = math.max(#bbButtons[id]["text"], bbButtons[id]["width"])
  189.         return true
  190.       end
  191.       return false
  192.     end;
  193.  
  194.     getText = function(id)
  195.       if type(id) == "number" and id > 0 and id <= bbButtonCount then return bbButtons[id]["text"] end
  196.     end;
  197.  
  198.     setColors = function(id, txtColor, bgColor, inactiveTxtCol, inactiveBgCol)
  199.       if type(id) == "number" and id > 0 and id <= bbButtonCount and (txtColor or bgColor or inactiveTxtCol or inactiveBgCol) then
  200.         local returnValue, changedColors = true, 0
  201.         if txtColor then
  202.           if type(txtColor) == "number" and validColors[txtColor] then bbButtons[id]["txtColor"] = txtColor changedColors = changedColors + 1 else returnValue = false end
  203.         end
  204.         if bgColor then
  205.           if type(bgColor) == "number" and validColors[bgColor] then bbButtons[id]["bgColor"] = bgColor changedColors = changedColors + 1 else returnValue = false end
  206.         end
  207.         if inactiveTxtCol then
  208.           if type(inactiveTxtCol) == "number" and validColors[inactiveTxtCol] then bbButtons[id]["inactiveTextColor"] = inactiveTxtCol changedColors = changedColors + 1 else returnValue = false end
  209.         end
  210.         if inactiveBgCol then
  211.           if type(inactiveBgCol) == "number" and validColors[inactiveBgCol] then bbButtons[id]["inactiveBgColor"] = inactiveBgCol changedColors = changedColors + 1 else returnValue = false end
  212.         end
  213.         return returnValue, changedColors
  214.       end
  215.       return false, 0
  216.     end;
  217.  
  218.     setActive = function(id, bState)
  219.       if type(id) == "number" and id > 0 and id <= bbButtonCount and type(bState) == "boolean" then bbButtons[id]["active"] = bState return true end
  220.       return false
  221.     end;
  222.  
  223.     getButtonCount = function()
  224.       return bbButtonCount
  225.     end;
  226.   }
  227. end
  228.  
  229. --# custom read function courtesy of theoriginalbit (modified by Dog)
  230. local function read(_mask, _history, _limit, _noTerminate, _noMouse, _gField)
  231.   if _mask and type(_mask) ~= "string" then
  232.     error("Invalid parameter #1: Expected string, got " .. type(_mask), 2)
  233.   end
  234.   if _history and type(_history) ~= "table" then
  235.     error("Invalid parameter #2: Expected table, got " .. type(_history), 2)
  236.   end
  237.   if _limit and type(_limit) ~= "number" then
  238.     error("Invalid parameter #3: Expected number, got " .. type(_limit), 2)
  239.   end
  240.   if _noTerminate and type(_noTerminate) ~= "boolean" then
  241.     error("Invalid argument #4: Expected boolean, got " .. nativeType(_noTerminate), 2)
  242.   end
  243.   if _noMouse and type(_noMouse) ~= "boolean" then
  244.     error("Invalid argument #5: Expected boolean, got " .. nativeType(_noMouse), 2)
  245.   end
  246.   if _gField and type(_gField) ~= "boolean" then
  247.     error("Invalid argument #6: Expected boolean, got " .. nativeType(_gField), 2)
  248.   end
  249.   gettingInput = true
  250.   term.setCursorBlink(true)
  251.   local symbols = { ["A"] = true, ["B"] = true, ["C"] = true, ["D"] = true, ["E"] = true , ["F"] = true, ["G"] = true, ["H"] = true, ["I"] = true, ["J"] = true, ["K"] = true, ["L"] = true, ["M"] = true, ["N"] = true, ["O"] = true, ["P"] = true, ["Q"] = true, ["R"] = true, ["S"] = true, ["T"] = true, ["U"] = true, ["V"] = true, ["W"] = true, ["X"] = true, ["Y"] = true, ["Z"] = true, ["0"] = true, ["1"] = true, ["2"] = true, ["3"] = true, ["4"] = true, ["5"] = true, ["6"] = true, ["7"] = true, ["8"] = true, ["9"] = true, ["-"] = true, ["+"] = true }
  252.   local mouseLimit = _limit or 0
  253.   local input = ""
  254.   local pos = 0
  255.   local historyPos = nil
  256.   local pullEvent = _noTerminate and os.pullEventRaw or os.pullEvent
  257.   local sw, sh = term.getSize()
  258.   local sx, sy = term.getCursorPos()
  259.   local function redraw(_special)
  260.     local scroll = (sx + pos >= sw and (sx + pos) - sw or 0)
  261.     local replace = _special or _mask
  262.     local output = replace and (string.rep(replace, math.ceil(#input / #replace) - scroll)):sub(1, #input) or input:sub(scroll + 1)
  263.     term.setCursorPos(sx, sy)
  264.     term.write(output)
  265.     term.setCursorPos(sx + pos - scroll, sy)
  266.   end
  267.   local nativeScroll = term.scroll
  268.   term.scroll = function(_n) local ok, err = pcall(function() return nativeScroll(_n) end) if ok then sy = sy - _n return err end error(err, 2) end
  269.   local function historyHandler(value)
  270.     redraw(' ')
  271.     if value == -1 or value == keys.up then
  272.       if not historyPos then
  273.         historyPos = #_history
  274.       elseif historyPos > 1 then
  275.         historyPos = historyPos - 1
  276.       end
  277.     else
  278.       if historyPos ~= nil and historyPos < #_history then
  279.         historyPos = historyPos + 1
  280.       elseif historyPos == #_history then
  281.         historyPos = nil
  282.       end
  283.     end
  284.     if historyPos and #_history > 0 then
  285.       input = string.sub(_history[historyPos], 1, _limit) or ""
  286.       pos = #input
  287.       if not _limit then mouseLimit = pos end
  288.     else
  289.       input = ""
  290.       pos = 0
  291.       if not _limit then mouseLimit = 0 end
  292.     end
  293.   end
  294.   while true do
  295.     local event, code, mX, mY = pullEvent()
  296.     if event == "char" and (not _limit or #input < _limit) then
  297.       local goodData = false
  298.       if _gField then
  299.         if symbols[code:upper()] then
  300.           code = code:upper()
  301.           goodData = true
  302.         end
  303.       else
  304.         goodData = true
  305.       end
  306.       if goodData then
  307.         input = input:sub(1, pos) .. code .. input:sub(pos + 1)
  308.         pos = pos + 1
  309.         if not _limit then mouseLimit = math.min(mouseLimit + 1, sw - (sw - sx)) end
  310.       end
  311.     elseif event == "paste" and (not _limit or #input < _limit) then
  312.       if _limit and #input + #code > _limit then
  313.         code = code:sub(1, _limit - #input)
  314.       end
  315.       if _gField then
  316.         local newWord, glyph = { }, ""
  317.         for i = 1, #code do
  318.           glyph = string.upper(code:sub(i, i))
  319.           newWord[i] = symbols[glyph] and glyph or "?"
  320.         end
  321.         code = table.concat(newWord)
  322.       end
  323.       input = input:sub(1, pos) .. code .. input:sub(pos + 1)
  324.       pos = pos + #code
  325.       if not _limit then mouseLimit = math.min(mouseLimit + #code, sw - (sw - sx)) end
  326.     elseif event == "key" then
  327.       if code == keys.enter or code == keys.numPadEnter then
  328.         break
  329.       elseif code == keys.backspace and pos > 0 then
  330.         redraw(' ')
  331.         input = input:sub(1, math.max(pos - 1, 0))..input:sub(pos + 1)
  332.         pos = math.max(pos - 1, 0)
  333.         if not _limit then mouseLimit = math.max(mouseLimit - 1, 0) end
  334.       elseif code == keys.delete and pos < #input then
  335.         redraw(' ')
  336.         input = input:sub(1, pos)..input:sub(pos + 2)
  337.         if not _limit then mouseLimit = math.max(mouseLimit - 1, 0) end
  338.       elseif code == keys.home then
  339.         pos = 0
  340.       elseif code == keys["end"] then
  341.         pos = #input
  342.       elseif code == keys.left and pos > 0 then
  343.         pos = math.max(pos - 1, 0)
  344.       elseif code == keys.right and pos < #input then
  345.         pos = math.min(pos + 1, #input)
  346.       elseif _history and (code == keys.up or code == keys.down) then
  347.         historyHandler(code)
  348.       end
  349.     elseif event == "mouse_click" and not _noMouse and ((mX < sx or mX >= sx + mouseLimit) or (mY ~= sy)) then
  350.       break
  351.     elseif event == "mouse_scroll" and _history then
  352.       historyHandler(code)
  353.     end
  354.     redraw(_mask)
  355.   end
  356.   term.scroll = nativeScroll
  357.   term.setCursorBlink(false)
  358.   if sy + 1 > sh then
  359.     term.scroll(sy + 1 - sh)
  360.     term.setCursorPos(1, sy)
  361.   else
  362.     term.setCursorPos(1, sy + 1)
  363.   end
  364.   gettingInput = false
  365.   return input
  366. end
  367.  
  368. local function assignColor()
  369.   return classifications[addressBook[currentSelection].rating].color or colors.lightGray
  370. end
  371.  
  372. local function assignRating()
  373.   return classifications[addressBook[currentSelection].rating].long or (classifications[addressBook[currentSelection].rating].label or "Unknown/Unclassified")
  374. end
  375.  
  376. local function drawRatingList(rating)
  377.   local txtColor
  378.   term.setTextColor(colors.white)
  379.   term.setBackgroundColor(colors.blue)
  380.   term.setCursorPos(18, 6)
  381.   term.write("   Classification   ")
  382.   paintutils.drawFilledBox(18, 7, 37, 16, colors.gray) --# menu body
  383.   for k, v in pairs(classifications) do
  384.     if rating == k then
  385.       txtColor = rating == "U" and colors.white or v.color
  386.       term.setCursorPos(37, v.order + 7)
  387.       term.setBackgroundColor(v.color)
  388.       term.write(" ")                                  --# selected rating color pip
  389.     else
  390.       txtColor = colors.lightGray
  391.     end
  392.     term.setCursorPos(18, v.order + 7)
  393.     term.setBackgroundColor(v.color)
  394.     term.write(" ")                                    --# color pip
  395.     term.setCursorPos(20, v.order + 7)
  396.     term.setTextColor(txtColor)
  397.     term.setBackgroundColor(colors.gray)
  398.     term.write(v.label)
  399.   end
  400. end
  401.  
  402. local function selectRating()
  403.   local selected = false
  404.   drawRatingList(addressBook[currentSelection].rating)
  405.   while true do
  406.     local event, data, x, y = os.pullEvent("mouse_click")
  407.     if x > 17 and x < 38 and y > 5 and y < 17 then --# menu body (so clicking on the body doesn't make the menu disappear)
  408.       if y > 7 and y < 16 and data == 1 then       --# actual menu options
  409.         for k, v in pairs(classifications) do
  410.           if y == v.order + 7 then
  411.             if addressBook[currentSelection].rating ~= k then
  412.               addressBook[currentSelection].rating = k
  413.               gateChange = true
  414.             end
  415.             selected = true
  416.             break
  417.           end
  418.         end
  419.         if selected then break end
  420.       end
  421.     else
  422.       break
  423.     end
  424.   end
  425.   return drawDetails(currentSelection, true)
  426. end
  427.  
  428. local function repositionCursor(curX, curY, txtColor, bgColor)
  429.   term.setTextColor(txtColor)
  430.   term.setBackgroundColor(bgColor)
  431.   term.setCursorPos(curX, curY)
  432. end
  433.  
  434. local function drawSaveButton()
  435.   term.setBackgroundColor(colors.orange)
  436.   term.setTextColor(colors.black)
  437.   term.setCursorPos(12, termY)
  438.   term.write("     Click here to save Address Book    ")
  439. end
  440.  
  441. do
  442.   local labelTable = {
  443.     [1] = { 6, "Name:" };
  444.     [2] = { 8, "Address:" };
  445.     [3] = { 10, "Class:" };
  446.     [4] = { 12, "Note:" };
  447.     [5] = { 14, "Loc/Dim:" };
  448.     [6] = { 15, "X:           Y:           Z:          " };
  449.     [7] = { 17, "Call Drop:       Auto Iris:" };
  450.   }
  451.  
  452.   drawLabels = function()
  453.     term.setTextColor(colors.gray)
  454.     for i = 1, 7 do
  455.       term.setCursorPos(14, labelTable[i][1])
  456.       term.write(labelTable[i][2])
  457.     end
  458.   end
  459. end
  460.  
  461. local function drawSwitch(x, y, position)
  462.   if type(x) == "number" and type(y) == "number" then
  463.     x = math.floor(math.max(1, math.min(x, termX - 4))) --# Validate x coord
  464.     y = math.floor(math.max(1, math.min(y, termY)))     --# Validate y coord
  465.     term.setCursorPos(x, y)
  466.     if type(position) == "string" then --# Switch (Neutral)
  467.       term.setBackgroundColor(colors.green)
  468.       term.write(" ")
  469.       term.setBackgroundColor(colors.gray)
  470.       term.write("  ")
  471.       term.setBackgroundColor(colors.red)
  472.       term.write(" ")
  473.     elseif type(position) == "boolean" then --# Switch (ON/OFF)
  474.       term.setBackgroundColor(position and colors.green or colors.gray)
  475.       term.write("  ")
  476.       term.setBackgroundColor(position and colors.gray or colors.red)
  477.       term.write("  ")
  478.     end
  479.   end
  480. end
  481.  
  482. drawDetails = function(id, bClearRatingMenu)
  483.   os.queueEvent("drawSGDialButton")
  484.   if bClearRatingMenu then paintutils.drawFilledBox(18, 6, 37, 16, colors.black) paintutils.drawLine(34, 6, 37, 6, colors.lightGray) end
  485.   term.setBackgroundColor(colors.black)
  486.   if currentSelection == 0 or bClearRatingMenu then drawLabels() end
  487.   currentSelection = id
  488.   term.setTextColor(colors.cyan)
  489.   term.setCursorPos(20, 6)
  490.   term.write(addressBook[currentSelection].name .. string.rep(" ", 12 - #addressBook[currentSelection].name))
  491.   term.setBackgroundColor(colors.black)
  492.   term.setTextColor(colors.yellow)
  493.   term.setCursorPos(23, 8)
  494.   term.write(addressBook[currentSelection].addr .. "  ")
  495.   term.setTextColor(colors.gray)
  496.   term.setCursorPos(34, 8)
  497.   term.write(addressBook[currentSelection].addr == thisGate and "This Gate" or "         ")
  498.   local gRating = assignRating(currentSelection)
  499.   term.setTextColor(assignColor(currentSelection))
  500.   term.setCursorPos(23, 10)
  501.   term.write(gRating .. string.rep(" ", 20 - #gRating))
  502.   term.setTextColor(colors.white)
  503.   term.setCursorPos(23, 12)
  504.   term.write(addressBook[currentSelection].note:sub(1, 28) .. string.rep(" ", 29 - #addressBook[currentSelection].note:sub(1, 28)))
  505.   term.setCursorPos(23, 13)
  506.   if #addressBook[currentSelection].note > 28 then
  507.     term.write(addressBook[currentSelection].note:sub(29, 43) .. string.rep(" ", 15 - #addressBook[currentSelection].note:sub(29, 43)))
  508.   else
  509.     term.write(string.rep(" ", 15))
  510.   end
  511.   if addressBook[currentSelection].note == "short note" then
  512.     term.setCursorPos(34, 12)
  513.     term.setTextColor(colors.gray)
  514.     term.write("(43 characters)")
  515.   end
  516.   term.setTextColor(colors.brown)
  517.   term.setCursorPos(23, 14)
  518.   term.write(addressBook[currentSelection].loc.dim .. string.rep(" ", 29 - #addressBook[currentSelection].loc.dim))
  519.   term.setTextColor(colors.lightGray)
  520.   term.setCursorPos(16, 15)
  521.   term.write(tostring(addressBook[currentSelection].loc.x):sub(1, 9) .. string.rep(" ", 9 - #tostring(addressBook[currentSelection].loc.x)))
  522.   term.setCursorPos(29, 15)
  523.   term.write(tostring(addressBook[currentSelection].loc.y):sub(1, 9) .. string.rep(" ", 9 - #tostring(addressBook[currentSelection].loc.y)))
  524.   term.setCursorPos(42, 15)
  525.   term.write(tostring(addressBook[currentSelection].loc.z):sub(1, 9) .. string.rep(" ", 9 - #tostring(addressBook[currentSelection].loc.z)))
  526.   drawSwitch(25, 17, addressBook[currentSelection].callDrop)
  527.   drawSwitch(42, 17, addressBook[currentSelection].iris)
  528.   if gateChange then drawSaveButton() end
  529. end
  530.  
  531. local function drawAddressButtons(override)
  532.   local txtColor, bgColor = term.getTextColor(), term.getBackgroundColor()
  533.   local curX, curY = term.getCursorPos()
  534.   local yPos, line, textLine, addr = 5, "            "
  535.   pageNum = override or pageNum
  536.   for i = ((pageNum - 1) * numPerPage) + 1, ((pageNum - 1) * numPerPage) + 4 do
  537.     if i > abCount then
  538.       term.setBackgroundColor(colors.black) --# instead of clearing the area before calling drawAddressButtons() on the last page
  539.       textLine = line                       --# we draw blanks at the end of the list - this avoids flicker
  540.     else
  541.       term.setTextColor(i == currentSelection and colors.blue or colors.white)
  542.       addr = addressBook[i].addr
  543.       if (sgState == "Dialling" or sgState == "Dialing" or sgState == "Opening" or sgState == "Connected") and (addr == dialTarget or addr:sub(1, 7) == dialTarget or addr == dialTarget:sub(1, 7)) then
  544.         term.setBackgroundColor(colors.lightBlue)
  545.       else
  546.         term.setBackgroundColor(i % 2 == 0 and colors.gray or colors.lightGray)
  547.       end
  548.       textLine = string.rep(" ", math.floor((12 - #addressBook[i].name) / 2)) .. addressBook[i].name .. string.rep(" " ,math.ceil((12 - #addressBook[i].name) / 2))
  549.     end
  550.     for j = 1, 3 do
  551.       yPos = yPos + 1
  552.       term.setCursorPos(1, yPos)
  553.       term.write(j == 2 and textLine or line)
  554.     end
  555.   end
  556.   if gettingInput then repositionCursor(curX, curY, txtColor, bgColor) end
  557. end
  558.  
  559. local function drawFuelPercent()
  560.   local txtColor, bgColor = term.getTextColor(), term.getBackgroundColor()
  561.   local curX, curY = term.getCursorPos()
  562.   term.setTextColor(colors.lightGray)
  563.   term.setCursorPos(42, 4)
  564.   term.write("Fuel: ")
  565.   local fuelPercent = math.min(100, math.floor((nrgAvailable / MAXFUEL) * 100))
  566.   local fuelColor = fuelPercent > 24 and colors.lime or colors.orange
  567.   fuelColor = fuelPercent < 6 and colors.red or fuelColor
  568.   term.setTextColor(fuelColor)
  569.   term.write(tostring(fuelPercent))
  570.   term.setTextColor(colors.lightGray)
  571.   term.write("% ")
  572.   if gettingInput then repositionCursor(curX, curY, txtColor, bgColor) end
  573. end
  574.  
  575. do
  576.   local stateTable = {
  577.     Incoming = "In : ";
  578.     Outgoing = "Out: ";
  579.     Opening = colors.lightBlue;
  580.     Connected = colors.lime;
  581.     Closing = colors.orange;
  582.   }
  583.  
  584.   drawStargateState = function()
  585.     local txtColor, bgColor = term.getTextColor(), term.getBackgroundColor()
  586.     local curX, curY = term.getCursorPos()
  587.     term.setBackgroundColor(colors.gray)
  588.     term.setCursorPos(13, 4)
  589.     term.write(string.rep(" ", termX - 11))
  590.     if sgState == "Dialling" or sgState == "Dialing" or sgState == "Opening" or sgState == "Closing" or sgState == "Connected" then
  591.       term.setCursorPos(14, 4)
  592.       term.setTextColor(colors.lightGray)
  593.       term.write(stateTable[callDirection] or "Unk: ")
  594.       if sgState == "Dialling" or sgState == "Dialing" then
  595.         term.write(dialTarget)
  596.         term.setCursorPos(19, 4)
  597.         term.setTextColor(colors.yellow)
  598.         term.write(dialTarget:sub(1, chevronsEngaged))
  599.       else
  600.         term.setTextColor(stateTable[sgState])
  601.         term.write(dialTarget)
  602.       end
  603.       for i = 1, abCount do
  604.         if addressBook[i].addr == dialTarget then
  605.           term.setCursorPos(28, 4)
  606.           term.setTextColor(colors.lightGray)
  607.           term.write("/" .. addressBook[i].name)
  608.           break
  609.         end
  610.       end
  611.     elseif sgState == "Offline" then
  612.       term.setCursorPos(14, 4)
  613.       term.setTextColor(colors.red)
  614.       term.write("Gate OFF-LINE")
  615.     end
  616.     drawFuelPercent()
  617.     if gettingInput then repositionCursor(curX, curY, txtColor, bgColor) end
  618.     if currentSelection == 0 then paintutils.drawFilledBox(13, 6, termX, termY, colors.black) end --# if coming from the logs view, clear the data area
  619.   end
  620. end
  621.  
  622. local function drawHeader()
  623.   paintutils.drawFilledBox(4, 1, termX - 3, 3, colors.blue)
  624.   term.setTextColor(colors.lightBlue)
  625.   local headerText = thisGate
  626.   for i = 1, abCount do
  627.     if addressBook[i].addr == thisGate then
  628.       headerText = addressBook[i].name .. " (" .. thisGate .. ")"
  629.       break
  630.     end
  631.   end
  632.   term.setCursorPos(math.floor((termX - #headerText) / 2), 2)
  633.   term.write(headerText)
  634. end
  635.  
  636. do
  637.   local helpTable = {
  638.     [1] = { 6, "Middle click an entry to delete", "" };
  639.     [2] = { 8, "Hold shift when scrolling to jump to", "the beginning or end of the list" };
  640.     [3] = { 11, "Log: Click 'X' to clear the logs", "" };
  641.     [4] = { 13, "Log: Left click an address in the log", "     to dial" };
  642.     [5] = { 16, "Log: Right click an address in the", "     log to add to the address book" };
  643.   }
  644.  
  645.   drawHelp = function()
  646.     paintutils.drawFilledBox(13, 6, termX, termY, colors.black)
  647.     term.setTextColor(colors.white)
  648.     for i = 1, 5 do
  649.       term.setCursorPos(14, helpTable[i][1])
  650.       term.write(helpTable[i][2])
  651.       term.setCursorPos(14, helpTable[i][1] + 1)
  652.       term.write(helpTable[i][3])
  653.     end
  654.   end
  655. end
  656.  
  657. local function drawLogData()
  658.   local currentEntry = ((logPage - 1) * 12) + 1 --# Set the first entry to show (based on page number)
  659.   local spacer, line, callHistoryCount = "         ", string.rep(" ", termX - 11), #callHistory
  660.   local callDir, callAddr, gName, addr
  661.   for i = currentEntry, currentEntry + 11 do    --# Display logs
  662.     if i > callHistoryCount then                --# if we've reached the end of the log then draw blank lines to clear entries from the previous page
  663.       term.setCursorPos(13, i - currentEntry + 6)
  664.       term.write(line)
  665.     else
  666.       callDir = callHistory[i]:sub(callHistory[i]:find("<") + 1, callHistory[i]:find(">") - 1) --# get call direction
  667.       term.setTextColor((callDir == "Inbound" or callDir == "Incoming") and colors.lightGray or ((callDir == "Outbound" or callDir == "Outgoing") and colors.gray or colors.red))
  668.       term.setCursorPos(14, i - currentEntry + 6) --# position entry
  669.       term.write(callHistory[i]:sub(1, callHistory[i]:find("@") - 2) .. "   ") --# write day
  670.       term.setCursorPos(20, i - currentEntry + 6) --# position entry
  671.       term.write(callHistory[i]:sub(callHistory[i]:find("@") + 2, callHistory[i]:find("M")) .. " ") --# write time
  672.       term.setCursorPos(30, i - currentEntry + 6) --# position entry
  673.       term.write(callDir .. " ")                  --# write direction
  674.       term.setCursorPos(39, i - currentEntry + 6) --# position entry
  675.       term.setTextColor((callDir == "Inbound" or callDir == "Incoming") and colors.lightBlue or ((callDir == "Outbound" or callDir == "Outgoing") and colors.cyan or colors.orange))
  676.       callAddr = callHistory[i]:sub(callHistory[i]:find(">") + 2) --# get address
  677.       gName = nil
  678.       for j = 1, abCount do
  679.         addr = addressBook[j].addr
  680.         if addr == callAddr or addr:sub(1, 7) == callAddr or addr == callAddr:sub(1, 7) then
  681.           gName = addressBook[j].name
  682.           break
  683.         end
  684.       end
  685.       term.write((gName or callAddr) .. string.rep(" ", 12 - (gName and #gName or #callAddr))) --# write address
  686.     end
  687.   end
  688. end
  689.  
  690. local function drawLogs()
  691.   term.setBackgroundColor(colors.gray)
  692.   term.setTextColor(colors.white)
  693.   term.setCursorPos(13, 4)
  694.   term.write(" Day   Time      Vector   Address      ")
  695.   term.setCursorPos(12, termY)
  696.   term.write("         << <              > >>         ")
  697.   local pNum = tostring(logPage) .. " of " .. tostring(logPages)
  698.   term.setCursorPos(math.floor((termX - #pNum) / 2) + 7, termY)
  699.   term.write(pNum)
  700.   term.setBackgroundColor(colors.black)
  701.   if callHistory[1] then
  702.     drawLogData()
  703.   else
  704.     term.setCursorPos(24, 10)
  705.     term.setTextColor(colors.gray)
  706.     term.write("No Logs")
  707.   end
  708. end
  709.  
  710. local function ingestLogs()
  711.   if currentSelection ~= 0 or help then
  712.     help = false
  713.     currentSelection = 0
  714.     button.setActive(1, false)
  715.     drawAddressButtons()
  716.     paintutils.drawFilledBox(13, 6, termX, termY - 1, colors.black)
  717.   end
  718.   for i = #callHistory, 1, -1 do
  719.     callHistory[i] = nil
  720.   end
  721.   if fs.exists("/data/DHDhistory") then
  722.     for log_entry in io.lines("/data/DHDhistory") do
  723.       table.insert(callHistory, 1, log_entry)
  724.     end
  725.   end
  726.   logPages = math.max(1, math.ceil(#callHistory / 12)) --# paginate call logs
  727.   drawLogs()
  728. end
  729.  
  730. local function changePage(id)
  731.   pageNum = button.getText(id) == " \\/ " and (shift and numPages or math.min(pageNum + 1, numPages)) or (shift and 1 or math.max(pageNum - 1, 1))
  732.   drawAddressButtons()
  733.   return true
  734. end
  735.  
  736. local function enableDisablePageButtons()
  737.   for id = 1, button.getButtonCount() do
  738.     if button.getText(id) == " /\\ " or button.getText(id) == " \\/ " then
  739.       button.setActive(id, numPages > 1)
  740.       button.render(id)
  741.     end
  742.   end
  743. end
  744.  
  745. local function addAddress(id, mBtn, newAddress)
  746.   local oldPages = numPages
  747.   abCount = abCount + 1
  748.   addressBook[abCount] = { name = newAddress or "NEW GATE", addr = newAddress or "ADDRESS", rating = "U", iris = "none", callDrop = false, note = newAddress and "Added from logs" or "short note", loc = { x = 0, y = 0, z = 0, dim = "Unspecified" } } --# ...create new entry
  749.   numPages = math.ceil(abCount / numPerPage)
  750.   if numPages > oldPages then enableDisablePageButtons() end
  751.   gateChange = true
  752.   if help then paintutils.drawFilledBox(13, 6, termX, termY, colors.black) help = false drawLabels() end --# if coming from help, clear the data area
  753.   if currentSelection == 0 then drawStargateState() drawLabels() end
  754.   currentSelection = abCount
  755.   drawDetails(currentSelection)
  756.   drawAddressButtons(numPages)
  757.   return true
  758. end
  759.  
  760. local function deleteAddress(entry)
  761.   if abCount > 1 then
  762.     local oldPages = numPages
  763.     if currentSelection > entry or (currentSelection == entry and entry == abCount) then currentSelection = math.max(1, currentSelection - 1) end
  764.     table.remove(addressBook, entry)
  765.     abCount = abCount - 1
  766.     numPages = math.ceil(abCount / numPerPage)
  767.     pageNum = math.min(pageNum, numPages)
  768.     if numPages < oldPages then enableDisablePageButtons() end
  769.     gateChange = true
  770.     drawAddressButtons()
  771.     drawHeader()
  772.     if currentSelection ~= 0 and not help then drawDetails(currentSelection) end
  773.     return true
  774.   end
  775.   return false
  776. end
  777.  
  778. do
  779.   local dataTable = { --# color, x, y, clear line, character limit, symbol match, history entry
  780.     name = { colors.cyan, 20, 6, "            ", 12, false, { addressBook[currentSelection].addr, addressBook[currentSelection].name } };
  781.     addr = { colors.yellow, 23, 8, "         ", 9, true, { addressBook[currentSelection].addr } };
  782.     note = { colors.white, 23, 12, string.rep(" ", 28), 43, false, { addressBook[currentSelection].note } };
  783.     dim = { colors.brown, 23, 14, string.rep(" ", 19), 19, false, { "Overworld", "Nether", "The End", addressBook[currentSelection].loc.dim } };
  784.     x = { colors.lightGray, 16, 15, "         ", 9, false, { addressBook[currentSelection].loc.x } };
  785.     y = { colors.lightGray, 29, 15, "         ", 9, false, { addressBook[currentSelection].loc.y } };
  786.     z = { colors.lightGray, 42, 15, "         ", 9, false, { addressBook[currentSelection].loc.z } };
  787.   }
  788.  
  789.   editEntry = function(which)
  790.     term.setBackgroundColor(colors.black)
  791.     term.setTextColor(dataTable[which][1])
  792.     term.setCursorPos(dataTable[which][2], dataTable[which][3])
  793.     term.write(dataTable[which][4])
  794.     if which == "note" then
  795.       term.setCursorPos(23, 13)
  796.       term.write(string.rep(" ", 15))
  797.     end
  798.     term.setCursorPos(dataTable[which][2], dataTable[which][3])
  799.     local userData = read(nil, dataTable[which][7], dataTable[which][5], nil, nil, dataTable[which][6])
  800.     if which == "name" then
  801.       if userData ~= "" and userData ~= addressBook[currentSelection].name then addressBook[currentSelection].name = userData gateChange = true drawHeader() drawAddressButtons() end
  802.     elseif which == "addr" then
  803.       if #userData == 7 or #userData == 9 and not userData:find("?") and userData ~= addressBook[currentSelection].addr then addressBook[currentSelection].addr = userData gateChange = true drawHeader() end
  804.     elseif which == "note" then
  805.       if userData ~= "" and userData ~= addressBook[currentSelection].note then addressBook[currentSelection].note = userData gateChange = true end
  806.     elseif which == "dim" then
  807.       if userData ~= "" and userData ~= addressBook[currentSelection].loc.dim then addressBook[currentSelection].loc.dim = userData gateChange = true end
  808.     elseif which == "x" then
  809.       local newX = tonumber(userData)
  810.       if newX and newX ~= addressBook[currentSelection].loc.x then addressBook[currentSelection].loc.x = newX gateChange = true end
  811.     elseif which == "y" then
  812.       local newY = tonumber(userData)
  813.       if newY and newY ~= addressBook[currentSelection].loc.y then addressBook[currentSelection].loc.y = newY gateChange = true end
  814.     elseif which == "z" then
  815.       local newZ = tonumber(userData)
  816.       if newZ and newZ ~= addressBook[currentSelection].loc.z then addressBook[currentSelection].loc.z = newZ gateChange = true end
  817.     end
  818.     drawDetails(currentSelection)
  819.   end
  820. end
  821.  
  822. local function toggleIris()
  823.   if irisState == "Closed" or irisState == "Closing" then
  824.     sg.openIris()
  825.   elseif irisState == "Open" or irisState == "Opening" then
  826.     sg.closeIris()
  827.   end
  828. end
  829.  
  830. local function exitScreen()
  831.   if help then --# Exit Help
  832.     help = false
  833.     paintutils.drawFilledBox(13, 6, termX, termY - 1, colors.black)
  834.     if currentSelection == 0 then
  835.       drawLogs()
  836.     else
  837.       drawLabels()
  838.       drawDetails(currentSelection)
  839.       drawAddressButtons()
  840.     end
  841.   elseif currentSelection == 0 and callHistory[1] then --# Clear Logs
  842.     term.setBackgroundColor(colors.blue)
  843.     term.setTextColor(colors.white)
  844.     term.setCursorPos(21, 8)
  845.     term.write(" Clear Logs? ")
  846.     paintutils.drawFilledBox(21, 9, 33, 11, colors.gray)
  847.     term.setBackgroundColor(colors.green)
  848.     term.setCursorPos(22, 10)
  849.     term.write(" Yes ")
  850.     term.setBackgroundColor(colors.red)
  851.     term.setCursorPos(28, 10)
  852.     term.write(" N o ")
  853.     while true do
  854.       local _, data, x, y = os.pullEvent("mouse_click")
  855.       if y == 10 and x > 21 and x < 33 and data == 1 then
  856.         if x > 21 and x < 27 then
  857.           local logData = fs.open("/data/DHDhistory", "w")
  858.           logData.close()
  859.           paintutils.drawFilledBox(13, 6, termX, termY - 1, colors.black)
  860.           ingestLogs()
  861.           break
  862.         elseif x > 27 and x < 33 then
  863.           paintutils.drawFilledBox(20, 8, 33, 11, colors.black)
  864.           drawLogData()
  865.           break
  866.         end
  867.       end
  868.     end
  869.   elseif currentSelection == 0 then --# Exit Logs
  870.     drawStargateState()
  871.     drawDetails(((pageNum - 1) * numPerPage) + 1)
  872.     drawAddressButtons()
  873.   else --# Exit Program
  874.     if gateChange then
  875.       term.setBackgroundColor(colors.blue)
  876.       term.setTextColor(colors.white)
  877.       term.setCursorPos(15, 8)
  878.       term.write(" Save Address Book? ")
  879.       paintutils.drawFilledBox(15, 9, 34, 11, colors.gray)
  880.       term.setBackgroundColor(colors.green)
  881.       term.setCursorPos(18, 10)
  882.       term.write(" Yes ")
  883.       term.setBackgroundColor(colors.red)
  884.       term.setCursorPos(27, 10)
  885.       term.write(" N o ")
  886.       while true do
  887.         local _, data, x, y = os.pullEvent("mouse_click")
  888.         if y == 10 and x > 17 and x < 32 then
  889.           if x > 17 and x < 23 then --# Yes
  890.             local sgData = fs.open("/data/DHDgates", "w")
  891.             sgData.write(textutils.serialize(addressBook))
  892.             sgData.close()
  893.             break
  894.           elseif x > 26 and x < 32 then --# No
  895.             break
  896.           end
  897.         end
  898.       end
  899.     end
  900.     term.setBackgroundColor(colors.black)
  901.     term.setTextColor(colors.white)
  902.     term.clear()
  903.     term.setCursorPos(1, 1)
  904.     error()
  905.   end
  906. end
  907.  
  908. local function userInput()
  909.   while true do
  910.     local event, data, x, y = os.pullEvent()
  911.     if event == "mouse_click" then
  912.       local success, btnID, returnData = button.check(x, y, data) --# check pre-defined buttons (via buttonBuddy)
  913.       if not success then                                         --# if no pre-defined buttons were clicked, check the address book...
  914.         if x < 13 and y > 5 and y < 18 then --# select a gate entry
  915.           local entry = ((pageNum - 1) * numPerPage) + 1
  916.           for i = 6, 17, 3 do
  917.             if y == i or y == i + 1 or y == i + 2 then
  918.               if data == 1 then
  919.                 if help then --# Exit help and display selected gate entry
  920.                   help = false
  921.                   paintutils.drawFilledBox(13, 6, termX, termY - 1, colors.black)
  922.                   drawLabels()
  923.                 end
  924.                 if currentSelection == 0 then drawStargateState() end --# if returning from the log screen, draw the stargate state
  925.                 drawDetails(entry)
  926.                 drawAddressButtons()
  927.                 paintutils.drawLine(12, termY, 13, termY, colors.black)
  928.               elseif data == 3 then --# Delete gate entry
  929.                 deleteAddress(entry)
  930.               end
  931.               break
  932.             end
  933.             entry = entry + 1
  934.             if entry > abCount then break end
  935.           end
  936.         elseif not help then
  937.           if currentSelection ~= 0 and data == 1 then --# Edit gate details
  938.             if y == 6 and x > 19 and x < 20 + #addressBook[currentSelection].name then --# Name
  939.               editEntry("name")
  940.             elseif y == 8 and x > 22 and x < 23 + #addressBook[currentSelection].addr then --# Address
  941.               editEntry("addr")
  942.             elseif y == 10 and x > 22 and x < 23 + #assignRating(addressBook[currentSelection].rating) then --# Rating
  943.               selectRating()
  944.             elseif y == 12 and x > 22 and x < 23 + #addressBook[currentSelection].note then --# Note
  945.               editEntry("note")
  946.             elseif y == 14 and x > 22 and x < 23 + #addressBook[currentSelection].loc.dim then --# Dimension
  947.               editEntry("dim")
  948.             elseif y == 15 and x > 15 and x < 42 + #tostring(addressBook[currentSelection].loc.z) then --# X, Y, Z
  949.               if x > 15 and x < 16 + #tostring(addressBook[currentSelection].loc.x) then --# X Coord (x > 15 and x < 24)
  950.                 editEntry("x")
  951.               elseif x > 28 and x < 29 + #tostring(addressBook[currentSelection].loc.y) then --# Y Coord (x > 28 and x < 39)
  952.                 editEntry("y")
  953.               elseif x > 41 and x < 42 + #tostring(addressBook[currentSelection].loc.z) then --# Z Coord (x > 41 and x < 52)
  954.                 editEntry("z")
  955.               end
  956.             elseif y == 17 and x > 24 and x < 46 then --# Switches
  957.               if x > 24 and x < 29 then     --# callDrop
  958.                 addressBook[currentSelection].callDrop = not addressBook[currentSelection].callDrop
  959.                 gateChange = true
  960.                 drawSwitch(25, 17, addressBook[currentSelection].callDrop)
  961.               elseif x > 41 and x < 46 then --# auto-iris
  962.                 if addressBook[currentSelection].iris == "none" then
  963.                   addressBook[currentSelection].iris = true
  964.                 elseif addressBook[currentSelection].iris then
  965.                   addressBook[currentSelection].iris = false
  966.                 else
  967.                   addressBook[currentSelection].iris = "none"
  968.                 end
  969.                 gateChange = true
  970.                 drawSwitch(42, 17, addressBook[currentSelection].iris)
  971.               end
  972.               if gateChange then drawSaveButton() end
  973.             elseif y == termY and x > 11 and gateChange then --# Save address book
  974.               local sgData = fs.open("/data/DHDgates", "w")
  975.               sgData.write(textutils.serialize(addressBook))
  976.               sgData.close()
  977.               gateChange = false
  978.               term.setBackgroundColor(colors.black)
  979.               term.setCursorPos(12, termY)
  980.               term.write(string.rep(" ", termX - 11))
  981.             end
  982.           elseif currentSelection == 0 then --# Logs
  983.             if y == termY and x > 20 and x < 43 and data == 1 then
  984.               if x > 20 and x < 23 then
  985.                 logPage = 1
  986.                 drawLogData()
  987.               elseif x == 24 then
  988.                 logPage = math.max(1, logPage - 1)
  989.                 drawLogData()
  990.               elseif x == 39 then
  991.                 logPage = math.min(logPage + 1, logPages)
  992.                 drawLogData()
  993.               elseif x > 40 and x < 43 then
  994.                 logPage = logPages
  995.                 drawLogData()
  996.               end
  997.             elseif x > 38 and x < termX and y > 5 and y < 18 then
  998.               local magicNumber, abEntry, callAddr, addr = ((logPage - 1) * 12) + 1, 0
  999.               if callHistory[magicNumber + y - 6] then
  1000.                 callAddr = callHistory[magicNumber + y - 6]:sub(callHistory[magicNumber + y - 6]:find(">") + 2) --# get logged address
  1001.                 for i = 1, abCount do
  1002.                   addr = addressBook[i].addr
  1003.                   if addr == callAddr or addr:sub(1, 7) == callAddr or addr == callAddr:sub(1, 7) then
  1004.                     abEntry = i
  1005.                     break
  1006.                   end
  1007.                 end
  1008.                 local redraw = false
  1009.                 if data == 1 then --# dial out from logs
  1010.                   if sgState == "Idle" then sg.dial(callAddr) end
  1011.                   if abEntry == 0 then
  1012.                     if sgState == "Idle" then redraw = true end
  1013.                   else
  1014.                     redraw = true
  1015.                   end
  1016.                 elseif data == 2 then --# add to addressBook from logs
  1017.                   if abEntry == 0 then
  1018.                     addAddress(nil, nil, callAddr)
  1019.                   else
  1020.                     redraw = true
  1021.                   end
  1022.                 end
  1023.                 if redraw then
  1024.                   drawStargateState()
  1025.                   drawDetails(abEntry == 0 and 1 or abEntry)
  1026.                   drawAddressButtons(abEntry == 0 and 1 or math.ceil(abEntry / numPerPage))
  1027.                   paintutils.drawLine(12, termY, 13, termY, colors.black)
  1028.                 end
  1029.               end
  1030.             end
  1031.           end
  1032.         end
  1033.       end
  1034.     elseif event == "mouse_scroll" then
  1035.       if currentSelection == 0 then
  1036.         logPage = data == 1 and (shift and logPages or math.min(logPage + 1, logPages)) or (shift and 1 or math.max(1, logPage - 1))
  1037.         drawLogData()
  1038.       else
  1039.         pageNum = data == 1 and (shift and numPages or math.min(pageNum + 1, numPages)) or (shift and 1 or math.max(1, pageNum - 1))
  1040.         drawAddressButtons()
  1041.       end
  1042.     elseif event == "key" and (data == keys.f1 or data == keys.home or data == keys["end"] or data == keys.pageUp or data == keys.pageDown or data == keys.leftShift or data == keys.rightShift) then
  1043.       if data == keys.home or data == keys["end"] then
  1044.         if currentSelection == 0 then
  1045.           logPage = data == keys.home and 1 or logPages
  1046.           drawLogData()
  1047.         else
  1048.           pageNum = data == keys.home and 1 or numPages
  1049.           drawAddressButtons()
  1050.         end
  1051.       elseif data == keys.pageUp or data == keys.pageDown then
  1052.         if currentSelection == 0 then
  1053.           logPage = data == keys.pageDown and math.min(logPage + 1, logPages) or math.max(1, logPage - 1)
  1054.           drawLogData()
  1055.         else
  1056.           pageNum = data == keys.pageDown and math.min(pageNum + 1, numPages) or math.max(1, pageNum - 1)
  1057.           drawAddressButtons()
  1058.         end
  1059.       elseif data == keys.f1 then
  1060.         help = not help
  1061.         if help then
  1062.           button.setActive(1, false)
  1063.           drawHelp()
  1064.         else
  1065.           paintutils.drawFilledBox(13, 6, termX, termY - 1, colors.black)
  1066.           if currentSelection == 0 then
  1067.             drawLogs()
  1068.           else
  1069.             drawLabels()
  1070.             drawDetails(currentSelection)
  1071.             drawAddressButtons()
  1072.           end
  1073.         end
  1074.       else
  1075.         shift = not shift --# if the running version of CC doesn't support key_up, this allows shift to be toggled on and off
  1076.       end
  1077.     elseif event == "key_up" and (data == keys.leftShift or data == keys.rightShift) then
  1078.       shift = false
  1079.     elseif event == "char" and data:lower() == "q" then
  1080.       exitScreen()
  1081.     end
  1082.   end
  1083. end
  1084.  
  1085. local function dataPoller()
  1086.   local _, timer, newFuel, update
  1087.   while true do
  1088.     _, timer = os.pullEvent("timer")
  1089.     if timer == updateTimer then
  1090.       newFuel = math.min(math.floor((nrgAvailable / MAXFUEL) * 100), 100)
  1091.       update = newFuel ~= fuelPercent
  1092.       fuelPercent = newFuel
  1093.       if update and currentSelection ~= 0 then term.setBackgroundColor(colors.gray) drawFuelPercent() end
  1094.       if sgState == "Connected" and callDirection == "Outgoing" then updateTimer = os.startTimer(5) end
  1095.     end
  1096.   end
  1097. end
  1098.  
  1099. local function monitorDialButtonRedraw()
  1100.   while true do
  1101.     os.pullEvent("drawSGDialButton")
  1102.     if currentSelection ~= 0 then
  1103.       local curX, curY = term.getCursorPos()
  1104.       local txtColor, bgColor = term.getTextColor(), term.getBackgroundColor()
  1105.       local nrgToDial, ableToDial = sg.energyToDial(addressBook[currentSelection].addr)
  1106.       term.setBackgroundColor(colors.lightGray)
  1107.       term.setCursorPos(34, 6)
  1108.       if sgState == "Offline" then
  1109.         ableToDial = false
  1110.         term.setTextColor(colors.red)
  1111.         term.write(" O F F - L I N E ")
  1112.       elseif addressBook[currentSelection].addr == thisGate then
  1113.         ableToDial = false
  1114.         term.setTextColor(colors.orange)
  1115.         term.write(" Not  Applicable ")
  1116.       elseif not nrgToDial then
  1117.         ableToDial = false
  1118.         term.setTextColor(colors.orange)
  1119.         term.write(" Invalid Address ")
  1120.       else
  1121.         ableToDial = (nrgToDial or 9999999999) <= nrgAvailable
  1122.         term.setTextColor(ableToDial and colors.lime or colors.orange)
  1123.         term.write(ableToDial and " Sufficient Fuel " or "Insufficient Fuel")
  1124.       end
  1125.       if sgState == "Dialling" or sgState == "Dialing" or sgState == "Opening" or sgState == "Connected" then
  1126.         button.setText(1, " END. ")
  1127.         button.setColors(1, nil, colors.orange)
  1128.         button.setFunction(1, function() sg.disconnect() end)
  1129.         button.setActive(1, true)
  1130.       else
  1131.         button.setText(1, " Dial ")
  1132.         button.setColors(1, nil, colors.green)
  1133.         button.setFunction(1, function() sg.dial(addressBook[currentSelection].addr) end)
  1134.         button.setActive(1, ableToDial)
  1135.       end
  1136.       button.render(1)
  1137.       if gettingInput then repositionCursor(curX, curY, txtColor, bgColor) end
  1138.     end
  1139.   end
  1140. end
  1141.  
  1142. local function monitorGate()
  1143.   local ableToDial, event, _, x, lastState, dialAddress
  1144.   while true do
  1145.     event, _, x, lastState = os.pullEvent()
  1146.     local curX, curY = term.getCursorPos()
  1147.     local txtColor, bgColor = term.getTextColor(), term.getBackgroundColor()
  1148.     if event == "sgDialIn" then
  1149.       dialTarget = sg.remoteAddress() --# dialTarget = x
  1150.       callDirection = "Incoming"
  1151.       sgState = "Dialing"
  1152.       if currentSelection ~= 0 then
  1153.         term.setCursorPos(14, 4)
  1154.         term.setBackgroundColor(colors.gray)
  1155.         term.setTextColor(colors.lightGray)
  1156.         term.write("In : " .. dialTarget)
  1157.         os.queueEvent("drawSGDialButton")
  1158.       end
  1159.       for i = 1, abCount do
  1160.         if addressBook[i].addr == dialTarget or addressBook[i].addr:sub(1, 7) == dialTarget or addressBook[i].addr == dialTarget:sub(1, 7) then
  1161.           if currentSelection ~= 0 then term.write("/" .. addressBook[i].name) end
  1162.           --if currentSelection ~= 0 then drawDetails(i) end
  1163.           drawAddressButtons()
  1164.           if addressBook[i].callDrop then
  1165.             sg.disconnect()
  1166.           end
  1167.           if type(addressBook[i].iris) == "boolean" then
  1168.             if addressBook[i].iris then
  1169.               sg.openIris()
  1170.             else
  1171.               sg.closeIris()
  1172.             end
  1173.           end
  1174.           break
  1175.         end
  1176.       end
  1177.     elseif event == "sgDialOut" then
  1178.       dialTarget = sg.remoteAddress() --# dialTarget = x
  1179.       callDirection = "Outgoing"
  1180.       sgState = "Dialing"
  1181.       if currentSelection ~= 0 then
  1182.         term.setCursorPos(14, 4)
  1183.         term.setBackgroundColor(colors.gray)
  1184.         term.setTextColor(colors.lightGray)
  1185.         term.write("Out: " .. dialTarget)
  1186.         for i = 1, abCount do
  1187.           if addressBook[i].addr == dialTarget then
  1188.             term.write("/" .. addressBook[i].name)
  1189.             break
  1190.           end
  1191.         end
  1192.         os.queueEvent("drawSGDialButton")
  1193.       end
  1194.       drawAddressButtons()
  1195.     elseif event == "sgChevronEngaged" then
  1196.       chevronsEngaged = x
  1197.       if chevronsEngaged == 1 and dialTarget == "none" then
  1198.         callDirection = "Outgoing"
  1199.         dialTarget = lastState .. string.rep("?", 8)
  1200.         if currentSelection ~= 0 then os.queueEvent("drawSGDialButton") end
  1201.       elseif x > 1 and dialTarget:find("?") then
  1202.         dialTarget = dialTarget:sub(1, chevronsEngaged - 1) .. lastState .. string.rep("?", 9 - chevronsEngaged)
  1203.       end
  1204.       if currentSelection ~= 0 then
  1205.         term.setCursorPos(chevronsEngaged == 1 and 14 or 19, 4)
  1206.         term.setBackgroundColor(colors.gray)
  1207.         if chevronsEngaged == 1 then
  1208.           term.setTextColor(colors.lightGray)
  1209.           term.write("Out: ")
  1210.         end
  1211.         term.setTextColor(colors.yellow)
  1212.         dialAddress = dialTarget:sub(1, chevronsEngaged)
  1213.         term.write(dialAddress)
  1214.       end
  1215.       sgState = "Dialing"
  1216.     elseif event == "sgChevronUnset" then
  1217.       chevronsEngaged = x
  1218.       if chevronsEngaged == 0 then
  1219.         sgState, dialTarget, callDirection = "Idle", "none", "none"
  1220.         if currentSelection ~= 0 then
  1221.           os.queueEvent("drawSGDialButton")
  1222.           term.setCursorPos(14, 4)
  1223.           term.setBackgroundColor(colors.gray)
  1224.           term.write("              ")
  1225.         end
  1226.       else
  1227.         dialTarget = dialTarget:sub(1, chevronsEngaged) .. string.rep("?", 9 - chevronsEngaged)
  1228.         if currentSelection ~= 0 then
  1229.           dialAddress = dialTarget:sub(1, chevronsEngaged)
  1230.           term.setCursorPos(19, 4)
  1231.           term.setBackgroundColor(colors.gray)
  1232.           term.setTextColor(colors.yellow)
  1233.           term.write(dialAddress .. " ")
  1234.         end
  1235.       end
  1236.     elseif event == "sgStargateStateChange" then
  1237.       term.setCursorPos(14, 4)
  1238.       term.setBackgroundColor(colors.gray)
  1239.       sgState = x
  1240.       if sgState == "Idle" or sgState == "Offline" then
  1241.         if currentSelection ~= 0 then
  1242.           term.write(string.rep(" ", 26))
  1243.           os.queueEvent("drawSGDialButton")
  1244.           if sgState == "Offline" then
  1245.             term.setCursorPos(14, 4)
  1246.             term.setTextColor(colors.red)
  1247.             term.write("Gate OFF-LINE")
  1248.           end
  1249.           drawFuelPercent()
  1250.         end
  1251.         chevronsEngaged = 0
  1252.         callDirection, dialTarget = "none", "none"
  1253.         drawAddressButtons()
  1254.       elseif (sgState == "Opening" or sgState == "Closing") and currentSelection ~= 0 then
  1255.         term.setTextColor(sgState == "Opening" and colors.lightBlue or colors.orange)
  1256.         term.setCursorPos(19, 4)
  1257.         term.write(dialTarget)
  1258.       elseif sgState == "Connected" then
  1259.         sgState, chevronsEngaged, callDirection = sg.stargateState() --# this is only necessary if ccDHDbasic is started while the gate is dialing (direction is only exposed upon connection currently)
  1260.         if callDirection == "Outgoing" then
  1261.           nrgAvailable = sg.energyAvailable()
  1262.           updateTimer = os.startTimer(5)
  1263.           if dialTarget:find("?") then dialTarget = dialTarget:sub(1, dialTarget:find("?") - 1) end
  1264.         end
  1265.         if currentSelection ~= 0 then
  1266.           term.setTextColor(colors.lime)
  1267.           term.setCursorPos(19, 4)
  1268.           term.write(dialTarget)
  1269.           for i = 1, abCount do
  1270.             if addressBook[i].addr == dialTarget or addressBook[i].addr:sub(1, 7) == dialTarget or addressBook[i].addr == dialTarget:sub(1, 7) then
  1271.               term.setTextColor(colors.yellow)
  1272.               term.write("/" .. addressBook[i].name)
  1273.               break
  1274.             end
  1275.           end
  1276.           drawFuelPercent()
  1277.         end
  1278.         local logAddress = dialTarget or "ERROR"                --# set logAddress
  1279.         local callDir = callDirection == "Incoming" and "Incoming" or "Outgoing" --# set callDirection
  1280.         local callTime = textutils.formatTime(os.time(), false) --# format the time
  1281.         if #callTime == 7 then callTime = " " .. callTime end   --# move single digit hour times to the right one space
  1282.         local dataLine = tostring(os.day()) .. " @ " .. callTime .. " <" .. callDir .. "> " .. logAddress
  1283.         local callArchive = fs.open("/data/DHDhistory", fs.exists("/data/DHDhistory") and "a" or "w")
  1284.         callArchive.writeLine(dataLine)
  1285.         callArchive.close()
  1286.         local previousCall = fs.open("/data/DHDlastCall", "w")  --# record last call
  1287.         previousCall.writeLine(dataLine)
  1288.         previousCall.close()
  1289.       end
  1290.     elseif event == "sgIrisStateChange" then
  1291.       irisState = x
  1292.       if irisState == "Offline" then
  1293.         button.setActive(2, false)
  1294.       elseif irisState == "Open" or irisState == "Closed" then
  1295.         if lastState == "Offline" then button.setActive(2, true) end --# If the iris was previously offline then activate the button
  1296.         button.setColors(2, colors.white, irisState == "Open" and colors.orange or colors.green)
  1297.       elseif irisState == "Opening" or irisState == "Closing" then
  1298.         if lastState == "Offline" then button.setActive(2, true) end --# If the iris was previously offline then activate the button
  1299.         if (irisState == "Opening" and lastState == "Closing") or (irisState == "Closing" and lastState == "Opening") then
  1300.           button.setColors(2, nil, irisState == "Opening" and colors.green or colors.orange)
  1301.         end
  1302.         button.setColors(2, irisState == "Opening" and colors.orange or colors.green)
  1303.       end
  1304.       button.render(2)
  1305.     end
  1306.     if gettingInput then repositionCursor(curX, curY, txtColor, bgColor) end
  1307.   end
  1308. end
  1309.  
  1310. button.create(" Dial ", nil, 45, 8, 1, 3, 1, false, function() sg.dial(addressBook[currentSelection].addr) end, colors.white, colors.green)
  1311. button.create(" I r i s ", nil, 1, 4, 12, 1, 1, irisState ~= "Offline", toggleIris, colors.white, (irisState == "Open" or irisState == "Closing") and colors.orange or colors.green, colors.gray, colors.lightGray)
  1312. button.create("-", nil, 1, 1, 3, 3, 1, true, ingestLogs, colors.white, colors.lightBlue) --# logs button (center dash on burger)
  1313. button.create(" X ", nil, termX - 2, 1, 3, 3, 1, true, exitScreen, colors.white, colors.red)
  1314. button.create(" /\\ ", nil, 1, termY, 4, 1, 1, numPages > 1, changePage, colors.white, colors.cyan)
  1315. button.create(" \\/ ", nil, 8, termY, 4, 1, 1, numPages > 1, changePage, colors.white, colors.cyan)
  1316. button.create(" + ", nil, 5, termY, 1, 1, 1, true, addAddress, colors.white, colors.green)
  1317.  
  1318. term.setBackgroundColor(colors.black)
  1319. term.clear()
  1320. drawHeader()
  1321. button.render()
  1322. term.setBackgroundColor(colors.lightBlue) --# Finish the burger for the logs button
  1323. term.setTextColor(colors.white)
  1324. term.setCursorPos(2, 1)
  1325. write("-\n\n -")
  1326. drawStargateState()
  1327. drawAddressButtons()
  1328. term.setBackgroundColor(colors.black)
  1329. drawLabels()
  1330. drawDetails(1)
  1331. if sgState == "Connected" and callDirection == "Outgoing" then updateTimer = os.startTimer(5) end
  1332. parallel.waitForAny(userInput, dataPoller, monitorDialButtonRedraw, monitorGate)
Advertisement
Add Comment
Please, Sign In to add comment
Advertisement