Advertisement
OmegaRogue

testt

Nov 6th, 2017
119
0
Never
Not a member of Pastebin yet? Sign Up, it unlocks many cool features!
Lua 61.53 KB | None | 0 0
  1. if not term.isColor() then
  2.   print("Advanced computer required")
  3.   exit()
  4. end
  5. print("loading...")
  6.  
  7. monitor_textScale = 0.5
  8.  
  9. Style = {
  10.   CDefault = colors.white,
  11.   BGDefault = colors.blue,
  12.  
  13.   CTitle = colors.black,
  14.   BGTitle = colors.cyan,
  15.  
  16.   CWarning = colors.white,
  17.   BGWarning = colors.red,
  18.  
  19.   CSuccess = colors.white,
  20.   BGSuccess = colors.lime,
  21.  
  22.   CDisabled = colors.gray,
  23.   BGDisabled = colors.blue,
  24.  
  25.   CRadarmap = colors.gray,
  26.   BGRadarmap = colors.green,
  27.  
  28.   CRadarborder = colors.white,
  29.   BGRadarborder = colors.black,
  30.  
  31.   CRadarself = colors.white,
  32.   BGRadarself = colors.lime,
  33.   TextRadarself = "R",
  34.  
  35.   CRadarother = colors.black,
  36.   BGRadarother = colors.red,
  37.   TextRadarother = "#"
  38. }
  39.  
  40. ----------- Monitor support
  41.  
  42. function SetMonitorColorFrontBack(frontColor, backgroundColor)
  43.   term.setBackgroundColor(backgroundColor)
  44.   term.setTextColor(frontColor)
  45.   if monitors ~= nil then
  46.     for key,monitor in pairs(monitors) do
  47.       monitor.setTextColor(frontColor)
  48.       monitor.setBackgroundColor(backgroundColor)
  49.     end
  50.   end
  51. end
  52.  
  53. function Write(text)
  54.   term.write(text)
  55.   if monitors ~= nil then
  56.     for key,monitor in pairs(monitors) do
  57.       if key ~= data.radar_monitorIndex then
  58.         monitor.write(text)
  59.       end
  60.     end
  61.   end
  62. end
  63.  
  64. function SetCursorPos(x, y)
  65.   term.setCursorPos(x, y)
  66.   if monitors ~= nil then
  67.     for key,monitor in pairs(monitors) do
  68.       if key ~= data.radar_monitorIndex then
  69.         monitor.setCursorPos(x, y)
  70.       end
  71.     end
  72.   end
  73. end
  74.  
  75. function SetColorDefault()
  76.   SetMonitorColorFrontBack(Style.CDefault, Style.BGDefault)
  77. end
  78.  
  79. function SetColorTitle()
  80.   SetMonitorColorFrontBack(Style.CTitle, Style.BGTitle)
  81. end
  82.  
  83. function SetColorWarning()
  84.   SetMonitorColorFrontBack(Style.CWarning, Style.BGWarning)
  85. end
  86.  
  87. function SetColorSuccess()
  88.   SetMonitorColorFrontBack(Style.CSuccess, Style.BGSuccess)
  89. end
  90.  
  91. function SetColorDisabled()
  92.   SetMonitorColorFrontBack(Style.CDisabled, Style.BGDisabled)
  93. end
  94.  
  95. function SetColorRadarmap()
  96.   SetMonitorColorFrontBack(Style.CRadarmap, Style.BGRadarmap)
  97. end
  98.  
  99. function SetColorRadarborder()
  100.   SetMonitorColorFrontBack(Style.CRadarborder, Style.BGRadarborder)
  101. end
  102.  
  103. function Clear()
  104.   clearWarningTick = -1
  105.   SetColorDefault()
  106.   term.clear()
  107.   if monitors ~= nil then
  108.     for key,monitor in pairs(monitors) do
  109.       if key ~= data.radar_monitorIndex then
  110.         monitor.clear()
  111.       end
  112.     end
  113.   end
  114.   SetCursorPos(1, 1)
  115. end
  116.  
  117. function ClearLine()
  118.   SetColorDefault()
  119.   term.clearLine()
  120.   if monitors ~= nil then
  121.     for key,monitor in pairs(monitors) do
  122.       if key ~= data.radar_monitorIndex then
  123.         monitor.clearLine()
  124.       end
  125.     end
  126.   end
  127.   SetCursorPos(1, 1)
  128. end
  129.  
  130. function WriteLn(text)
  131.   Write(text)
  132.   local x, y = term.getCursorPos()
  133.   local width, height = term.getSize()
  134.   if y > height - 1 then
  135.     y = 1
  136.   end
  137.   SetCursorPos(1, y + 1)
  138. end
  139.  
  140. function WriteCentered(y, text)
  141.   SetCursorPos((51 - text:len()) / 2, y)
  142.   term.write(text)
  143.   if monitors ~= nil then
  144.     for key,monitor in pairs(monitors) do
  145.       if key ~= data.radar_monitorIndex then
  146.         local sizeX, sizeY = monitor.getSize()
  147.         monitor.setCursorPos((sizeX - text:len()) / 2, y)
  148.         monitor.write(text)
  149.       end
  150.     end
  151.   end
  152.   local xt, yt = term.getCursorPos()
  153.   SetCursorPos(1, yt + 1)
  154. end
  155.  
  156. function ShowTitle(text)
  157.   Clear()
  158.   SetColorTitle()
  159.   WriteCentered(1, text)
  160.   SetColorDefault()
  161. end
  162.  
  163. function ShowMenu(text)
  164.   Write(text)
  165.   local sizeX, sizeY = term.getSize()
  166.   local xt, yt = term.getCursorPos()
  167.   for i = xt, sizeX do
  168.     Write(" ")
  169.   end
  170.   SetCursorPos(1, yt + 1)
  171. end
  172.  
  173. local clearWarningTick = -1
  174. function ShowWarning(text)
  175.   local sizeX, sizeY = term.getSize()
  176.   SetCursorPos(1, sizeY)
  177.   ClearLine()
  178.   SetColorWarning()
  179.   SetCursorPos((sizeX - text:len() - 2) / 2, sizeY)
  180.   Write(" " .. text .. " ")
  181.   SetColorDefault()
  182.   clearWarningTick = 5
  183. end
  184. function ClearWarning()
  185.   if clearWarningTick > 0 then
  186.     clearWarningTick = clearWarningTick - 1
  187.   elseif clearWarningTick == 0 then
  188.     SetColorDefault()
  189.     local sizeX, sizeY = term.getSize()
  190.     SetCursorPos(1, sizeY)
  191.     ClearLine()
  192.     clearWarningTick = -1
  193.   end
  194. end
  195.  
  196. ----------- Formatting & popups
  197.  
  198. function FormatFloat(value, nbchar)
  199.   local str = "?"
  200.   if value ~= nil then
  201.     str = string.format("%g", value)
  202.   end
  203.   if nbchar ~= nil then
  204.     str = string.sub("               " .. str, -nbchar)
  205.   end
  206.   return str
  207. end
  208. function FormatInteger(value, nbchar)
  209.   local str = "?"
  210.   if value ~= nil then
  211.     str = string.format("%d", value)
  212.   end
  213.   if nbchar ~= nil then
  214.     str = string.sub("               " .. str, -nbchar)
  215.   end
  216.   return str
  217. end
  218.  
  219. function boolToYesNo(bool)
  220.   if bool then
  221.     return "YES"
  222.   else
  223.     return "no"
  224.   end
  225. end
  226.  
  227. function readInputNumber(currentValue)
  228.   local inputAbort = false
  229.   local input = string.format(currentValue)
  230.   if input == "0" then
  231.     input = ""
  232.   end
  233.   local x, y = term.getCursorPos()
  234.   repeat
  235.     ClearWarning()
  236.     SetColorDefault()
  237.     SetCursorPos(x, y)
  238.     Write(input .. "            ")
  239.     input = string.sub(input, -9)
  240.    
  241.     local params = { os.pullEventRaw() }
  242.     local eventName = params[1]
  243.     local address = params[2]
  244.     if address == nil then address = "none" end
  245.     if eventName == "key" then
  246.       local keycode = params[2]
  247.       if keycode >= 2 and keycode <= 10 then -- 1 to 9
  248.         input = input .. string.format(keycode - 1)
  249.       elseif keycode == 11 or keycode == 82 then -- 0 & keypad 0
  250.         input = input .. "0"
  251.       elseif keycode >= 79 and keycode <= 81 then -- keypad 1 to 3
  252.         input = input .. string.format(keycode - 78)
  253.       elseif keycode >= 75 and keycode <= 77 then -- keypad 4 to 6
  254.         input = input .. string.format(keycode - 71)
  255.       elseif keycode >= 71 and keycode <= 73 then -- keypad 7 to 9
  256.         input = input .. string.format(keycode - 64)
  257.       elseif keycode == 14 then -- Backspace
  258.         input = string.sub(input, 1, string.len(input) - 1)
  259.       elseif keycode == 211 then -- Delete
  260.         input = ""
  261.       elseif keycode == 28 then -- Enter
  262.         inputAbort = true
  263.       elseif keycode == 74 or keycode == 12 or keycode == 49 then -- - on numeric keypad or - on US top or n letter
  264.         if string.sub(input, 1, 1) == "-" then
  265.           input = string.sub(input, 2)
  266.         else
  267.           input = "-" .. input
  268.         end
  269.       elseif keycode == 78 then -- +
  270.         if string.sub(input, 1, 1) == "-" then
  271.           input = string.sub(input, 2)
  272.         end
  273.       else
  274.         ShowWarning("Key " .. keycode .. " is invalid")
  275.       end
  276.     elseif eventName == "terminate" then
  277.       inputAbort = true
  278.     elseif not common_event(eventName, params[2]) then
  279.       ShowWarning("Event '" .. eventName .. "', " .. address .. " is unsupported")
  280.     end
  281.   until inputAbort
  282.   SetCursorPos(1, y + 1)
  283.   if input == "" or input == "-" then
  284.     return currentValue
  285.   else
  286.     return tonumber(input)
  287.   end
  288. end
  289.  
  290. function readInputText(currentValue)
  291.   local inputAbort = false
  292.   local input = string.format(currentValue)
  293.   local x, y = term.getCursorPos()
  294.   Write(input)
  295.   os.pullEventRaw() -- skip first char event
  296.   repeat
  297.     ClearWarning()
  298.     SetColorDefault()
  299.     SetCursorPos(x, y)
  300.     Write(input .. "                              ")
  301.     input = string.sub(input, -30)
  302.    
  303.     local params = { os.pullEventRaw() }
  304.     local eventName = params[1]
  305.     local address = params[2]
  306.     if address == nil then address = "none" end
  307.     if eventName == "key" then
  308.       local keycode = params[2]
  309.       if keycode == 14 then -- Backspace
  310.         input = string.sub(input, 1, string.len(input) - 1)
  311.       elseif keycode == 211 then -- Delete
  312.         input = ""
  313.       elseif keycode == 28 then -- Enter
  314.         inputAbort = true
  315.       else
  316.         ShowWarning("Key " .. keycode .. " is invalid")
  317.       end
  318.     elseif eventName == "char" then
  319.       local char = params[2]
  320.       if char >= ' ' and char <= '~' then -- 1 to 9
  321.         input = input .. char
  322.       else
  323.         ShowWarning("Char #" .. string.byte(char) .. " is invalid")
  324.       end
  325.     elseif eventName == "terminate" then
  326.       inputAbort = true
  327.     elseif not common_event(eventName, params[2]) then
  328.       ShowWarning("Event '" .. eventName .. "', " .. address .. " is unsupported")
  329.     end
  330.   until inputAbort
  331.   SetCursorPos(1, y + 1)
  332.   if input == "" then
  333.     return currentValue
  334.   else
  335.     return input
  336.   end
  337. end
  338.  
  339. function readConfirmation(msg)
  340.   if msg == nil then
  341.     ShowWarning("Are you sure? (y/n)")
  342.   else
  343.     ShowWarning(msg)
  344.   end
  345.   repeat
  346.     local params = { os.pullEventRaw() }
  347.     local eventName = params[1]
  348.     local address = params[2]
  349.     if address == nil then address = "none" end
  350.     if eventName == "key" then
  351.       local keycode = params[2]
  352.       if keycode == 21 then -- Y
  353.         return true
  354.       else
  355.         return false
  356.       end
  357.     elseif eventName == "terminate" then
  358.       return false
  359.     elseif not common_event(eventName, params[2]) then
  360.       ShowWarning("Event '" .. eventName .. "', " .. address .. " is unsupported")
  361.     end
  362.   until false
  363. end
  364.  
  365. ----------- commons: menu, event handlers, etc.
  366.  
  367. function common_event(eventName, param)
  368.   if eventName == "redstone" then
  369.     redstone_event(param)
  370.   elseif eventName == "timer" then
  371.     if param == radar_timerId then
  372.       radar_timerEvent()
  373.     end
  374.   elseif eventName == "shipCoreCooldownDone" then
  375.     ShowWarning("Ship core cooldown done")
  376.   elseif eventName == "reactorPulse" then
  377.     reactor_pulse(param)
  378. --  elseif eventName == "reactorDeactivation" then
  379. --    ShowWarning("Reactor deactivated")
  380. --  elseif eventName == "reactorActivation" then
  381. --    ShowWarning("Reactor activated")
  382.   elseif eventName == "char" then
  383.   elseif eventName == "key_up" then
  384.   elseif eventName == "mouse_click" then
  385.   elseif eventName == "mouse_up" then
  386.   elseif eventName == "mouse_drag" then
  387.   elseif eventName == "monitor_touch" then
  388.   elseif eventName == "monitor_resize" then
  389.   elseif eventName == "peripheral" then
  390.   elseif eventName == "peripheral_detach" then
  391.   else
  392.     return false
  393.   end
  394.   return true
  395. end
  396.  
  397. function menu_common()
  398.   SetCursorPos(1, 18)
  399.   SetColorTitle()
  400.   ShowMenu("1 Reactor, 2 Cloak, 3 Mining, 4 Core, 5 Radar, eXit")
  401. end
  402.  
  403. ----------- Redstone support
  404.  
  405. local tblRedstoneState = {-- Remember redstone state on each side
  406.   ["top"] = rs.getInput("top"),
  407.   ["front"] = rs.getInput("front"),
  408.   ["left"] = rs.getInput("left"),
  409.   ["right"] = rs.getInput("right"),
  410.   ["back"] = rs.getInput("back"),
  411.   ["bottom"] = rs.getInput("bottom"),
  412. }
  413. local tblSides = {-- list all sides and offset coordinates
  414.   ["top"   ] = { 3, 1},
  415.   ["front" ] = { 1, 3},
  416.   ["left"  ] = { 3, 3},
  417.   ["right" ] = { 5, 3},
  418.   ["back"  ] = { 5, 5},
  419.   ["bottom"] = { 3, 5},
  420. }
  421.  
  422. function redstone_event()
  423.   -- Event only returns nil so we need to check sides manually
  424.   local message = ""
  425.   for side, state in pairs(tblRedstoneState) do
  426.     if rs.getInput(side) ~= state then
  427.       -- print(side .. " is now " .. tostring(rs.getInput(side)))
  428.       message = message .. side .. " "
  429.       tblRedstoneState[side] = rs.getInput(side)
  430.     end
  431.   end
  432.   if message ~= "" then
  433.     message = "Redstone changed on " .. message
  434.     showWarning(message)
  435.   end
  436. end
  437.  
  438. ----------- Cloaking support
  439.  
  440. cloaking_highTier = false
  441. cloaking_currentKey = 1
  442. function cloaking_key(keycode)
  443.   if keycode == 31 then -- S
  444.     cloaking_start()
  445.     return true
  446.   elseif keycode == 25 then -- P
  447.     cloaking_stop()
  448.     return true
  449.   elseif keycode == 20 then -- T
  450.     cloaking_highTier = not cloaking_highTier
  451.     return true
  452.   end
  453.   return false
  454. end
  455.  
  456. function cloaking_page()
  457.   ShowTitle(label .. " - Cloaking status")
  458.  
  459.   local cloakingcore = nil
  460.   if cloakingcores ~= nil then
  461.     if cloaking_currentKey > #cloakingcores then
  462.       cloaking_currentKey = 1
  463.     end
  464.     cloakingcore = cloakingcores[cloaking_currentKey]
  465.   end
  466.  
  467.   SetCursorPos(1, 2)
  468.   if #cloakingcores == 0 then
  469.     SetColorDisabled()
  470.     Write("No cloaking core detected...")
  471.   elseif cloakingcore == nil then
  472.     SetColorWarning()
  473.     Write("Cloaking core " .. cloaking_currentKey .. " of " .. #cloakingcores .. " is invalid")
  474.   else
  475.     SetColorDefault()
  476.     Write("Cloaking core " .. cloaking_currentKey .. " of " .. #cloakingcores)
  477.     local isAssemblyValid = cloakingcore.isAssemblyValid()
  478.     local energy, energyMax = cloakingcore.energy()
  479.     local isEnabled = cloakingcore.enable()
  480.    
  481.     if not isAssemblyValid then
  482.       SetColorWarning()
  483.       SetCursorPos(1, 3)
  484.       Write("Invalid assembly!")
  485.       SetColorDefault()
  486.       SetCursorPos(1, 4)
  487.       print("In each direction, you need to place exactly 2 Cloaking device coils, for a total of 12 coils.")
  488.       print("The 6 inner coils shall be exactly one block away from the core.")
  489.       print("The cloaking field will extend 5 blocks past the outer 6 coils.")
  490.       print("Power consumption scales with the amount of cloaked blocks.")
  491.     else
  492.       SetCursorPos(1, 4)
  493.       Write("Assembly is valid")
  494.      
  495.       if energy < 50000 then
  496.         SetColorWarning()
  497.       else
  498.         SetColorDefault()
  499.       end
  500.       SetCursorPos(1, 6)
  501.       Write("Energy level is " .. energy .. " EU")
  502.  
  503.       SetCursorPos(1, 8)
  504.       if isEnabled then
  505.         if energy <= 100 then
  506.           SetColorWarning()
  507.         else
  508.           SetColorSuccess()
  509.         end
  510.         Write("Cloak is enabled")
  511.       else
  512.         SetColorNormal()
  513.         Write("Cloak is disabled")
  514.       end
  515.     end
  516.   end
  517.   os.sleep(0.1)
  518.   cloaking_currentKey = cloaking_currentKey + 1
  519.  
  520.   SetColorDefault()
  521.   SetCursorPos(1, 12)
  522.   Write("  -----------------------------------------------")
  523.   SetCursorPos(1, 13)
  524.   if cloaking_highTier then
  525.     Write("Cloak tier: HIGH")
  526.   else
  527.     Write("Cloak tier: low")
  528.   end
  529.  
  530.   SetColorTitle()
  531.   SetCursorPos(1, 16)
  532.   ShowMenu("S - Start cloaking, P - stoP cloaking")
  533.   SetCursorPos(1, 17)
  534.   ShowMenu("T - change low/high Tier")
  535. end
  536.  
  537. function cloaking_start()
  538.   for key,cloakingcore in pairs(cloakingcores) do
  539.     cloakingcore.enable(false)
  540.     if cloaking_highTier then
  541.       cloakingcore.tier(2)
  542.     else
  543.       cloakingcore.tier(1)
  544.     end
  545.     cloakingcore.enable(true)
  546.   end
  547. end
  548.  
  549. function cloaking_stop()
  550.   for key,cloakingcore in pairs(cloakingcores) do
  551.     cloakingcore.enable(false)
  552.   end
  553. end
  554.  
  555. ----------- Mining lasers support
  556.  
  557. mining_currentKey = 1
  558. mining_layerOffset = 1
  559. mining_mineAll = true
  560. mining_useDeuterium = false
  561. function mining_key(keycode)
  562.   if keycode == 31 then -- S
  563.     mining_start()
  564.     return true
  565.   elseif keycode == 25 then -- P
  566.     mining_stop()
  567.     return true
  568.   elseif keycode == 30 then -- A
  569.     mining_mineAll = not mining_mineAll
  570.     return true
  571.   elseif keycode == 32 then -- D
  572.     mining_useDeuterium = not mining_useDeuterium
  573.     return true
  574.   elseif keycode == 74 then -- -
  575.     mining_layerOffset = mining_layerOffset - 1
  576.     if mining_layerOffset < 1 then
  577.       mining_layerOffset = 1
  578.     end
  579.     return true
  580.   elseif keycode == 78 then -- +
  581.     mining_layerOffset = mining_layerOffset + 1
  582.     return true
  583.   elseif keycode == 46 then -- C
  584.     mining_page_config()
  585.     return true
  586.   end
  587.   return false
  588. end
  589.  
  590. function mining_page()
  591.   ShowTitle(label .. " - Mining status")
  592.  
  593.   local mininglaser = nil
  594.   if mininglasers ~= nil then
  595.     if mining_currentKey > #mininglasers then
  596.       mining_currentKey = 1
  597.     end
  598.     mininglaser = mininglasers[mining_currentKey]
  599.   end
  600.  
  601.   SetCursorPos(1, 2)
  602.   if #mininglasers == 0 then
  603.     SetColorDisabled()
  604.     Write("No mining laser detected...")
  605.   elseif mininglaser == nil then
  606.     SetColorWarning()
  607.     Write("Mining laser " .. mining_currentKey .. " of " .. #mininglasers .. " is invalid")
  608.   else
  609.     SetColorDefault()
  610.     Write("Mining laser " .. mining_currentKey .. " of " .. #mininglasers)
  611.     local status, energy, currentLayer, mined, total = mininglaser.state()
  612.     SetCursorPos(1, 3)
  613.     Write("Status: " .. status .. "   ")
  614.     SetCursorPos(1, 5)
  615.     Write("Energy level is " .. energy .. " EU")
  616.     SetCursorPos(1, 7)
  617.     Write("Mined " .. mined .. " out of " .. total .. " blocks at layer " .. currentLayer .. "   ")
  618.   end
  619.   os.sleep(0.1)
  620.   mining_currentKey = mining_currentKey + 1
  621.  
  622.   SetColorDefault()
  623.   SetCursorPos(1, 11)
  624.   Write("  -----------------------------------------------")
  625.   SetCursorPos(1, 12)
  626.   Write("Layer offset: " .. mining_layerOffset)
  627.   SetCursorPos(1, 13)
  628.   Write("Mine all: " .. boolToYesNo(mining_mineAll))
  629.   SetCursorPos(1, 14)
  630.   Write("Use Deuterium: " .. boolToYesNo(mining_useDeuterium))
  631.  
  632.   SetColorTitle()
  633.   SetCursorPos(1, 16)
  634.   ShowMenu("S - Start mining, P - stoP mining, A - mine All")
  635.   SetCursorPos(1, 17)
  636.   ShowMenu("D - use Deuterium, +/-/C - adjust offset")
  637. end
  638.  
  639. function mining_page_config()
  640.   ShowTitle(label .. " - Mining configuration")
  641.   Write(" Layer offset (".. mining_layerOffset ..") : ")
  642.   mining_layerOffset = readInputNumber(mining_layerOffset)
  643.   if mining_layerOffset < 1 then
  644.     mining_layerOffset = 1
  645.   end
  646. end
  647.  
  648. function mining_start()
  649.   for key,mininglaser in pairs(mininglasers) do
  650.     if not mininglaser.isMining() then
  651.       mininglaser.offset(mining_layerOffset)
  652.       if mining_mineAll then
  653.         if mining_useDeuterium then
  654.           mininglaser.quarry(mining_useDeuterium)
  655.         else
  656.           mininglaser.quarry()
  657.         end
  658.       else
  659.         if mining_useDeuterium then
  660.           mininglaser.mine(mining_useDeuterium)
  661.         else
  662.           mininglaser.mine()
  663.         end
  664.       end
  665.     end
  666.   end
  667. end
  668.  
  669. function mining_stop()
  670.   if #mininglasers == 0 then
  671.     SetColorWarning()
  672.     Write("No mining laser detected")
  673.   else
  674.     for key,mininglaser in pairs(mininglasers) do
  675.       SetCursorPos(1, 2 + key)
  676.       if not mininglaser.isMining() then
  677.         SetColorDisabled()
  678.         Write("Mining laser " .. key .. " of " .. #mininglasers .. " is already stopped")
  679.       else
  680.         mininglaser.stop()
  681.         SetColorSuccess()
  682.         Write("Mining laser " .. key .. " of " .. #mininglasers .. " has been stopped")
  683.       end
  684.     end
  685.   end
  686. end
  687.  
  688. ----------- Configuration
  689.  
  690. function data_save()
  691.   local file = fs.open("shipdata.txt", "w")
  692.   if file ~= nil then
  693.     file.writeLine(textutils.serialize(data))
  694.     file.close()
  695.   else
  696.     ShowWarning("No file system")
  697.     os.sleep(3)
  698.   end
  699. end
  700.  
  701. function data_read()
  702.   data = { }
  703.   if fs.exists("shipdata.txt") then
  704.     local file = fs.open("shipdata.txt", "r")
  705.     data = textutils.unserialize(file.readAll())
  706.     file.close()
  707.     if data == nil then data = {}; end
  708.   end
  709.   if data.core_summon == nil then data.core_summon = false; end
  710.   if data.reactor_mode == nil then data.reactor_mode = 0; end
  711.   if data.reactor_rate == nil then data.reactor_rate = 100; end
  712.   if data.reactor_targetStability == nil then data.reactor_targetStability = 50; end
  713.   if data.reactor_laserAmount == nil then data.reactor_laserAmount = 10000; end
  714.   if data.radar_monitorIndex == nil then data.radar_monitorIndex = 0; end
  715.   if data.radar_radius == nil then data.radar_radius = 500; end
  716.   if data.radar_autoscan == nil then data.radar_autoscan = false; end
  717.   if data.radar_autoscanDelay == nil then data.radar_autoscanDelay = 3; end
  718.   if data.radar_results == nil then data.radar_results = {}; end
  719.   if data.radar_scale == nil then data.radar_scale = 500; end
  720.   if data.radar_offsetX == nil then data.radar_offsetX = 0; end
  721.   if data.radar_offsetY == nil then data.radar_offsetY = 0; end
  722. end
  723.  
  724. function data_setName()
  725.   if ship ~= nil then
  726.     ShowTitle("<==== Set ship name ====>")
  727.   else
  728.     ShowTitle("<==== Set name ====>")
  729.   end
  730.  
  731.   SetCursorPos(1, 2)
  732.   Write("Enter ship name: ")
  733.   label = readInputText(label)
  734.   os.setComputerLabel(label)
  735.   if ship ~= nil then
  736.     ship.coreFrequency(label)
  737.   end
  738.   os.reboot()
  739. end
  740.  
  741. function string_split(source, sep)
  742.   local sep = sep or ":"
  743.   local fields = {}
  744.   local pattern = string.format("([^%s]+)", sep)
  745.   source:gsub(pattern, function(c) fields[#fields + 1] = c end)
  746.   return fields
  747. end
  748.  
  749. ----------- Ship support
  750.  
  751. core_front = 0
  752. core_right = 0
  753. core_up = 0
  754. core_back = 0
  755. core_left = 0
  756. core_down = 0
  757. core_isInHyper = false
  758. core_jumpCost = 0
  759. core_shipSize = 0
  760. core_movement = { 0, 0, 0 }
  761. core_rotationSteps = 0
  762.  
  763. function core_boot()
  764.   if ship == nil then
  765.     return
  766.   end
  767.  
  768.   Write("Booting Ship Core")
  769.  
  770.   if data.core_summon then
  771.     ship.summon_all()
  772.   end
  773.  
  774.   WriteLn("...")
  775.   core_front, core_right, core_up = ship.dim_positive()
  776.   core_back, core_left, core_down = ship.dim_negative()
  777.   core_isInHyper = ship.isInHyperspace()
  778.   core_rotationSteps = ship.rotationSteps()
  779.   core_movement = { ship.movement() }
  780.   if ship.direction ~= nil then
  781.     ship.direction(666)
  782.     ship.distance(0)
  783.   end
  784.   WriteLn("Ship core detected...")
  785.  
  786.   repeat
  787.     pos = ship.position()
  788.     os.sleep(0.3)
  789.   until pos ~= nil
  790.   X, Y, Z = ship.position()
  791.   WriteLn("Ship position triangulated...")
  792.  
  793.   repeat
  794.     isAttached = ship.isAttached()
  795.     os.sleep(0.3)
  796.   until isAttached ~= false
  797.   WriteLn("Ship core linked...")
  798.  
  799.   repeat
  800.     core_shipSize = ship.getShipSize()
  801.     os.sleep(0.3)
  802.   until core_shipSize ~= nil
  803.   WriteLn("Ship size updated...")
  804.  
  805.   ship.mode(1)
  806. end
  807.  
  808. function core_writeMovement()
  809.   local message = " Movement         = "
  810.   local count = 0
  811.   if core_movement[1] > 0 then
  812.     message = message .. core_movement[1] .. " front"
  813.     count = count + 1
  814.   elseif core_movement[1] < 0 then
  815.     message = message .. (- core_movement[1]) .. " back"
  816.     count = count + 1
  817.   end
  818.   if core_movement[2] > 0 then
  819.     if count > 0 then message = message .. ", "; end
  820.     message = message .. core_movement[2] .. " up"
  821.     count = count + 1
  822.   elseif core_movement[2] < 0 then
  823.     if count > 0 then message = message .. ", "; end
  824.     message = message .. (- core_movement[2]) .. " down"
  825.     count = count + 1
  826.   end
  827.   if core_movement[3] > 0 then
  828.     if count > 0 then message = message .. ", "; end
  829.     message = message .. core_movement[3] .. " right"
  830.     count = count + 1
  831.   elseif core_movement[3] < 0 then
  832.     if count > 0 then message = message .. ", "; end
  833.     message = message .. (- core_movement[3]) .. " left"
  834.     count = count + 1
  835.   end
  836.  
  837.   if core_rotationSteps == 1 then
  838.     if count > 0 then message = message .. ", "; end
  839.     message = message .. "Turn right"
  840.     count = count + 1
  841.   elseif core_rotationSteps == 2 then
  842.     if count > 0 then message = message .. ", "; end
  843.     message = message .. "Turn back"
  844.     count = count + 1
  845.   elseif core_rotationSteps == 3 then
  846.     if count > 0 then message = message .. ", "; end
  847.     message = message .. "Turn left"
  848.     count = count + 1
  849.   end
  850.  
  851.   if count == 0 then
  852.     message = message .. "(none)"
  853.   end
  854.   WriteLn(message)
  855. end
  856.  
  857. function core_writeRotation()
  858.   if core_rotationSteps == 0 then
  859.     WriteLn(" Rotation         = Front")
  860.   elseif core_rotationSteps == 1 then
  861.     WriteLn(" Rotation         = Right +90")
  862.   elseif core_rotationSteps == 2 then
  863.     WriteLn(" Rotation         = Back 180")
  864.   elseif core_rotationSteps == 3 then
  865.     WriteLn(" Rotation         = Left -90")
  866.   end
  867. end
  868.  
  869. function core_computeNewCoordinates(cx, cy, cz)
  870.   local res = { x = cx, y = cy, z = cz }
  871.   local dx, dy, dz = ship.getOrientation()
  872.   local worldMovement = { x = 0, y = 0, z = 0 }
  873.   worldMovement.x = dx * core_movement[1] - dz * core_movement[3]
  874.   worldMovement.y = core_movement[2]
  875.   worldMovement.z = dz * core_movement[1] + dx * core_movement[3]
  876.   core_actualDistance = math.ceil(math.sqrt(worldMovement.x * worldMovement.x + worldMovement.y * worldMovement.y + worldMovement.z * worldMovement.z))
  877.   core_jumpCost = ship.getEnergyRequired(core_actualDistance)
  878.   res.x = res.x + worldMovement.x
  879.   res.y = res.y + worldMovement.y
  880.   res.z = res.z + worldMovement.z
  881.   return res
  882. end
  883.  
  884. function core_warp()
  885.   -- rs.setOutput(alarm_side, true)
  886.   if readConfirmation() then
  887.     -- rs.setOutput(alarm_side, false)
  888.     ship.movement(core_movement[1], core_movement[2], core_movement[3])
  889.     ship.rotationSteps(core_rotationSteps)
  890.     ship.mode(1)
  891.     ship.jump()
  892.     -- ship = nil
  893.   end
  894.   -- rs.setOutput(alarm_side, false)
  895. end
  896.  
  897. function core_page_setMovement()
  898.   ShowTitle("<==== Set movement ====>")
  899.   SetCursorPos(1, 15)
  900.   SetColorTitle()
  901.   ShowMenu("Enter 0 to keep position on that axis")
  902.   ShowMenu("Use - or n keys to move in opposite direction")
  903.   ShowMenu("Press Enter to confirm")
  904.   SetColorDefault()
  905.   SetCursorPos(1, 3)
  906.  
  907.   core_movement[1] = core_page_setDistanceAxis(2, "Forward" , "Front", "Back", core_movement[1], math.abs(core_front + core_back + 1))
  908.   core_movement[2] = core_page_setDistanceAxis(4, "Vertical", "Up"   , "Down", core_movement[2], math.abs(core_up + core_down + 1))
  909.   core_movement[3] = core_page_setDistanceAxis(6, "Lateral" , "Right", "Left", core_movement[3], math.abs(core_left + core_right + 1))
  910.   core_movement = { ship.movement(core_movement[1], core_movement[2], core_movement[3]) }
  911. end
  912.  
  913. function core_page_setDistanceAxis(line, axis, positive, negative, userEntry, shipLength)
  914.   local maximumDistance = shipLength + 127
  915.   if core_isInHyper and line ~= 3 then
  916.     maximumDistance = shipLength + 127 * 100
  917.   end
  918.   SetColorDisabled()
  919.   SetCursorPos(3, line + 1)
  920.   Write(positive .. " is " .. ( shipLength + 1) .. ", maximum is " ..  maximumDistance .. "      ")
  921.   SetCursorPos(3, line + 2)
  922.   Write(negative .. " is " .. (-shipLength - 1) .. ", maximum is " .. -maximumDistance .. "      ")
  923.  
  924.   SetColorDefault()
  925.   repeat
  926.     SetCursorPos(1, line)
  927.     Write(axis .. " movement: ")
  928.     userEntry = readInputNumber(userEntry)
  929.     if userEntry ~= 0 and (math.abs(userEntry) <= shipLength or math.abs(userEntry) > maximumDistance) then
  930.       ShowWarning("Wrong distance. Try again.")
  931.     end
  932.   until userEntry == 0 or (math.abs(userEntry) > shipLength and math.abs(userEntry) <= maximumDistance)
  933.   SetCursorPos(1, line + 1)
  934.   ClearLine()
  935.   SetCursorPos(1, line + 2)
  936.   ClearLine()
  937.  
  938.   return userEntry
  939. end
  940.  
  941. function core_page_setRotation()
  942.   local inputAbort = false
  943.   local drun = true
  944.   repeat
  945.     ShowTitle("<==== Set rotation ====>")
  946.     core_writeRotation()
  947.     SetCursorPos(1, 16)
  948.     SetColorTitle()
  949.     ShowMenu("Use directional keys")
  950.     ShowMenu("Press Enter to confirm")
  951.     SetColorDefault()
  952.     local params = { os.pullEventRaw() }
  953.     local eventName = params[1]
  954.     local address = params[2]
  955.     if address == nil then address = "none" end
  956.     if eventName == "key" then
  957.       local keycode = params[2]
  958.       if keycode == 200 then
  959.         core_rotationSteps = 0
  960.       elseif keycode == 203 then
  961.         core_rotationSteps = 3
  962.       elseif keycode == 205 then
  963.         core_rotationSteps = 1
  964.       elseif keycode == 208 then
  965.         core_rotationSteps = 2
  966.       elseif keycode == 28 then
  967.         inputAbort = true
  968.       else
  969.         ShowWarning("Key " .. keycode .. " is invalid")
  970.       end
  971.     elseif eventName == "terminate" then
  972.       inputAbort = true
  973.     elseif not common_event(eventName, params[2]) then
  974.       ShowWarning("Event '" .. eventName .. "', " .. address .. " is unsupported")
  975.     end
  976.   until inputAbort
  977.   core_rotationSteps = ship.rotationSteps(core_rotationSteps)
  978. end
  979.  
  980. function core_page_setDimensions()
  981.   ShowTitle("<==== Set dimensions ====>")
  982.   Write(" Front (".. core_front ..") : ")
  983.   core_front = readInputNumber(core_front)
  984.   Write(" Right (".. core_right ..") : ")
  985.   core_right = readInputNumber(core_right)
  986.   Write(" Up    (".. core_up ..") : ")
  987.   core_up = readInputNumber(core_up)
  988.   Write(" Back  (".. core_back ..") : ")
  989.   core_back = readInputNumber(core_back)
  990.   Write(" Left  (".. core_left ..") : ")
  991.   core_left = readInputNumber(core_left)
  992.   Write(" Down  (".. core_down ..") : ")
  993.   core_down = readInputNumber(core_down)
  994.   Write("Setting dimensions...")
  995.   core_front, core_right, core_up = ship.dim_positive(core_front, core_right, core_up)
  996.   core_back, core_left, core_down = ship.dim_negative(core_back, core_left, core_down)
  997.   core_shipSize = ship.getShipSize()
  998.   if core_shipSize == nil then core_shipSize = 0 end
  999. end
  1000.  
  1001. function core_page_summon()
  1002.   ShowTitle("<==== Summon players ====>")
  1003.   local playersString = ship.getAttachedPlayers()
  1004.   if playersString == "" then
  1005.     WriteLn("~ no players registered ~")
  1006.     WriteLn("")
  1007.     SetColorTitle()
  1008.     ShowMenu("Press enter to exit")
  1009.     SetColorDefault()
  1010.     readInputNumber("")
  1011.     return
  1012.   end
  1013.   local playersArray = string_split(playersString, ",")
  1014.   for i = 1, #playersArray do
  1015.     WriteLn(i .. ". " .. playersArray[i])
  1016.   end
  1017.   SetColorTitle()
  1018.   ShowMenu("Enter player number")
  1019.   ShowMenu("or press enter to summon everyone")
  1020.   SetColorDefault()
  1021.  
  1022.   Write(":")
  1023.   local input = readInputNumber("")
  1024.   if input == "" then
  1025.     ship.summon_all()
  1026.   else
  1027.     input = tonumber(input)
  1028.     ship.summon(input - 1)
  1029.   end
  1030. end
  1031.  
  1032. function core_page_jumpToBeacon()
  1033.   ShowTitle("<==== Jump to beacon ====>")
  1034.  
  1035.   Write("Enter beacon frequency: ")
  1036.   local freq = readInputText("")
  1037.   -- rs.setOutput(alarm_side, true)
  1038.   if readConfirmation() then
  1039.     -- rs.setOutput(alarm_side, false)
  1040.     ship.mode(4)
  1041.     ship.beaconFrequency(freq)
  1042.     ship.jump()
  1043.     -- ship = nil
  1044.   end
  1045.   -- rs.setOutput(alarm_side, false)
  1046. end
  1047.  
  1048. function core_page_jumpToGate()
  1049.   ShowTitle("<==== Jump to Jumpgate ====>")
  1050.  
  1051.   Write("Enter jumpgate name: ")
  1052.   local name = readInputText("")
  1053.   -- rs.setOutput(alarm_side, true)
  1054.   if readConfirmation() then
  1055.     -- rs.setOutput(alarm_side, false)
  1056.     ship.mode(6)
  1057.     ship.targetJumpgate(name)
  1058.     ship.jump()
  1059.     -- ship = nil
  1060.   end
  1061.   -- rs.setOutput(alarm_side, false)
  1062. end
  1063.  
  1064. function core_page()
  1065.   ShowTitle(label .. " - Ship status")
  1066.   if ship ~= nil then
  1067.     -- WriteLn("")
  1068.     X, Y, Z = ship.position()
  1069.     WriteLn("Core:")
  1070.     WriteLn(" x, y, z          = " .. X .. ", " .. Y .. ", " .. Z)
  1071.     local energy, energyMax = ship.energy()
  1072.     if energy == nil then energy = 0 end
  1073.     if energyMax == nil or energyMax == 0 then energyMax = 1 end
  1074.     WriteLn(" Energy           = " .. math.floor(energy / energyMax * 100) .. " % (" .. energy .. "EU)")
  1075.     local playersString, playersArray = ship.getAttachedPlayers()
  1076.     if playersString == "" then players = "-" end
  1077.     WriteLn(" Attached players = " .. playersString)
  1078.     -- WriteLn("")
  1079.     WriteLn("Dimensions:")
  1080.     WriteLn(" Front, Right, Up = " .. FormatInteger(core_front) .. ", " .. FormatInteger(core_right) .. ", " .. FormatInteger(core_up))
  1081.     WriteLn(" Back, Left, Down = " .. FormatInteger(core_back) .. ", " .. FormatInteger(core_left) .. ", " .. FormatInteger(core_down))
  1082.     WriteLn(" Size             = " .. core_shipSize .. " blocks")
  1083.     -- WriteLn("")
  1084.     WriteLn("Warp data:")
  1085.     core_writeMovement()
  1086.     local dest = core_computeNewCoordinates(X, Y, Z)
  1087.     WriteLn(" Distance         = " .. core_actualDistance .. " (" .. core_jumpCost .. "EU, " .. math.floor(energy / core_jumpCost) .. " jumps)")
  1088.     WriteLn(" Dest.coordinates = " .. FormatInteger(dest.x) .. ", " .. FormatInteger(dest.y) .. ", " .. FormatInteger(dest.z))
  1089.     if data.core_summon then
  1090.       WriteLn(" Summon after     = Yes")
  1091.     else
  1092.       WriteLn(" Summon after     = No")
  1093.     end
  1094.   else
  1095.     ShowWarning("No ship controller detected")
  1096.   end
  1097.  
  1098.   SetCursorPos(1, 15)
  1099.   SetColorTitle()
  1100.   ShowMenu("D - Dimensions, N - set ship Name, M - set Movement")
  1101.   ShowMenu("J - Jump, G - jump through Gate, B - jump to Beacon")
  1102.   ShowMenu("H - Hyperspace, C - summon Crew, T - Toggle summon")
  1103. end
  1104.  
  1105. function core_key(char, keycode)
  1106.   if keycode == 50 then -- M
  1107.     core_page_setMovement()
  1108.     core_page_setRotation()
  1109.     return true
  1110.   elseif keycode == 20 then -- T
  1111.     if data.core_summon then
  1112.       data.core_summon = false
  1113.     else
  1114.       data.core_summon = true
  1115.     end
  1116.     data_save()
  1117.     return true
  1118.   elseif keycode == 32 then -- D
  1119.     core_page_setDimensions()
  1120.     return true
  1121.   elseif keycode == 36 then -- J
  1122.     core_warp()
  1123.     return true
  1124.   elseif keycode == 46 then -- C
  1125.     core_page_summon()
  1126.     return true
  1127.   elseif keycode == 48 then -- B
  1128.     core_page_jumpToBeacon()
  1129.     return true
  1130.   elseif keycode == 34 then -- G
  1131.     core_page_jumpToGate()
  1132.     return true
  1133.   elseif keycode == 35 then -- H
  1134.     -- rs.setOutput(alarm_side, true)
  1135.     if readConfirmation() then
  1136.       -- rs.setOutput(alarm_side, false)
  1137.       ship.mode(5)
  1138.       ship.jump()
  1139.       -- ship = nil
  1140.     end
  1141.     -- rs.setOutput(alarm_side, false)
  1142.     return true
  1143.   elseif keycode == 49 then
  1144.     data_setName()
  1145.     return true
  1146.   end
  1147.   return false
  1148. end
  1149.  
  1150. ----------- Reactor support
  1151.  
  1152. reactor_output = 0
  1153.  
  1154. function reactor_boot()
  1155.   if reactor ~= nil then
  1156.     WriteLn("Booting Reactor...")
  1157.     local isActive, strMode, releaseRate = reactor.active()
  1158.     if strMode == "OFF" then
  1159.       data.reactor_mode = 0
  1160.     elseif strMode == "MANUAL" then
  1161.       data.reactor_mode = 1
  1162.     elseif strMode == "ABOVE" then
  1163.       data.reactor_mode = 2
  1164.     elseif strMode == "RATE" then
  1165.       data.reactor_mode = 3
  1166.     else
  1167.       data.reactor_mode = 0
  1168.     end
  1169.   end
  1170. end
  1171.  
  1172. function reactor_key(char, keycode)
  1173.   if char == 83 or char == 115 or keycode == 31 then -- S
  1174.     reactor_start()
  1175.     return true
  1176.   elseif char == 80 or char == 112 or keycode == 25 then -- P
  1177.     reactor_stop()
  1178.     return true
  1179.   elseif char == 76 or char == 108 or keycode == 38 then -- L
  1180.     reactor_laser()
  1181.     return true
  1182.   elseif char == 79 or char == 111 or keycode == 24 then -- O
  1183.     data.reactor_mode = (data.reactor_mode + 1) % 4
  1184.     reactor_setMode()
  1185.     data_save()
  1186.     return true
  1187.   elseif char == 71 or char == 103 or keycode == 34 then -- G
  1188.     data.reactor_rate = data.reactor_rate - 1000
  1189.     reactor_setMode()
  1190.     data_save()
  1191.     return true
  1192.   elseif char == 84 or char == 116 or keycode == 20 then -- T
  1193.     data.reactor_rate = data.reactor_rate + 1000
  1194.     reactor_setMode()
  1195.     data_save()
  1196.     return true
  1197.   elseif char == 74 or char == 106 or keycode == 36 then -- J
  1198.     data.reactor_laserAmount = data.reactor_laserAmount - 500
  1199.     reactor_setLaser()
  1200.     data_save()
  1201.     return true
  1202.   elseif char == 85 or char == 117 or keycode == 22 then -- U
  1203.     data.reactor_laserAmount = data.reactor_laserAmount + 500
  1204.     reactor_setLaser()
  1205.     data_save()
  1206.     return true
  1207.   elseif char == 45 or keycode == 74 then -- -
  1208.     data.reactor_targetStability = data.reactor_targetStability - 1
  1209.     reactor_setTargetStability()
  1210.     data_save()
  1211.     return true
  1212.   elseif char == 43 or keycode == 78 then -- +
  1213.     data.reactor_targetStability = data.reactor_targetStability + 1
  1214.     reactor_setTargetStability()
  1215.     data_save()
  1216.     return true
  1217.   elseif char == 67 or char == 99 or keycode == 46 then -- C
  1218.     reactor_config()
  1219.     data_save()
  1220.     return true
  1221.   end
  1222.   return false
  1223. end
  1224.  
  1225. function reactor_page()
  1226.   ShowTitle(label .. " - Reactor status")
  1227.  
  1228.   SetCursorPos(1, 2)
  1229.   if reactor == nil then
  1230.     SetColorDisabled()
  1231.     Write("Reactor not detected")
  1232.   else
  1233.     SetColorDefault()
  1234.     Write("Reactor stability")
  1235.     instabilities = { reactor.instability() }
  1236.     for key,instability in pairs(instabilities) do
  1237.       SetCursorPos(12, 2 + key)
  1238.       stability = math.floor((100.0 - instability) * 10) / 10
  1239.       if stability >= data.reactor_targetStability then
  1240.         SetColorSuccess()
  1241.       else
  1242.         SetColorWarning()
  1243.       end
  1244.       Write(FormatFloat(stability, 5) .. " %")
  1245.     end
  1246.    
  1247.     SetColorDefault()
  1248.     local energy = { reactor.energy() }
  1249.     SetCursorPos(1, 7)
  1250.     Write("Energy   : ")
  1251.     if energy[2] ~= nil then
  1252.       Write(FormatInteger(energy[1], 10) .. " / " .. energy[2] .. " RF +" .. FormatInteger(reactor_output, 5) .. " RF/t")
  1253.     else
  1254.       Write("???")
  1255.     end
  1256.     SetCursorPos(1, 8)
  1257.     Write("Outputing: ")
  1258.     if energy[3] ~= nil then
  1259.       Write(energy[3] .. " RF/t")
  1260.     end
  1261.    
  1262.     SetColorDefault()
  1263.     SetCursorPos(1, 9)
  1264.     Write("Activated: ")
  1265.     isActive = reactor.active()
  1266.     if isActive then SetColorSuccess() else SetColorDefault() end
  1267.     Write(boolToYesNo(isActive))
  1268.   end
  1269.  
  1270.   if #reactorlasers == 0 then
  1271.     SetColorDisabled()
  1272.     SetCursorPos(30, 2)
  1273.     Write("Lasers not detected")
  1274.   else
  1275.     SetColorDefault()
  1276.     SetCursorPos(30, 2)
  1277.     Write("Lasers")
  1278.    
  1279.     for key,reactorlaser in pairs(reactorlasers) do
  1280.       local side = reactorlaser.side
  1281.       if side ~= nil then
  1282.         side = side % 4
  1283.         SetColorDefault()
  1284.         SetCursorPos(4, 3 + side)
  1285.         Write("Side " .. side .. ":")
  1286.         SetCursorPos(30, 3 + side)
  1287.         local energy = reactorlaser.wrap.energy()
  1288.         if not reactorlaser.wrap.hasReactor() then
  1289.           SetColorDisabled()
  1290.         elseif energy > 3 * data.reactor_laserAmount then
  1291.           SetColorSuccess()
  1292.         else
  1293.           SetColorWarning()
  1294.         end
  1295.         Write(FormatInteger(energy, 6))
  1296.       end
  1297.     end
  1298.   end
  1299.  
  1300.   SetColorDefault()
  1301.   SetCursorPos(1, 10)
  1302.   Write("  -----------------------------------------------")
  1303.   SetCursorPos(1, 11)
  1304.   Write("Output mode     : ")
  1305.   if data.reactor_mode == 0 then
  1306.     SetColorDisabled()
  1307.     Write("hold")
  1308.   elseif data.reactor_mode == 1 then
  1309.     Write("manual/unlimited")
  1310.   elseif data.reactor_mode == 2 then
  1311.     Write("surplus above " .. data.reactor_rate .. " RF")
  1312.   else
  1313.     Write("rated at " .. data.reactor_rate .. " RF")
  1314.   end
  1315.   SetColorDefault()
  1316.   SetCursorPos( 1, 12)
  1317.   Write("Target stability: " .. data.reactor_targetStability .. "%")
  1318.   SetCursorPos(30, 12)
  1319.   Write("Laser amount: " .. data.reactor_laserAmount)
  1320.  
  1321.   SetColorTitle()
  1322.   SetCursorPos(1, 14)
  1323.   ShowMenu("S - Start reactor, P - Stop reactor, L - Use lasers")
  1324.   SetCursorPos(1, 15)
  1325.   ShowMenu("O - Output mode, C - Configuration")
  1326.   SetCursorPos(1, 16)
  1327.   ShowMenu("+/- - Target stability, U/J - Laser amount")
  1328.   SetCursorPos(1, 17)
  1329.   ShowMenu("G/T - Output rate/threshold")
  1330. end
  1331.  
  1332. function reactor_setMode()
  1333.   if data.reactor_rate < 1 then
  1334.     data.reactor_rate = 1
  1335.   elseif data.reactor_rate > 100000 then
  1336.     data.reactor_rate = 100000
  1337.   end
  1338.   if reactor ~= nil then
  1339.     if data.reactor_mode == 0 then
  1340.       reactor.release(false)
  1341.     elseif data.reactor_mode == 1 then
  1342.       reactor.release(true)
  1343.     elseif data.reactor_mode == 2 then
  1344.       reactor.releaseAbove(data.reactor_rate)
  1345.     else
  1346.       reactor.releaseRate(data.reactor_rate)
  1347.     end
  1348.   end
  1349. end
  1350.  
  1351. function reactor_setLaser()
  1352.   if data.reactor_laserAmount < 1 then
  1353.     data.reactor_laserAmount = 1
  1354.   elseif data.reactor_laserAmount > 100000 then
  1355.     data.reactor_laserAmount = 100000
  1356.   end
  1357. end
  1358.  
  1359. function reactor_setTargetStability()
  1360.   if data.reactor_targetStability < 1 then
  1361.     data.reactor_targetStability = 1
  1362.   elseif data.reactor_targetStability > 100 then
  1363.     data.reactor_targetStability = 100
  1364.   end
  1365. end
  1366.  
  1367. function reactor_start()
  1368.   if reactor ~= nil then
  1369.     reactor_setMode()
  1370.     reactor.active(true)
  1371.   end
  1372. end
  1373.  
  1374. function reactor_stop()
  1375.   if reactor ~= nil then
  1376.     reactor.active(false)
  1377.   end
  1378. end
  1379.  
  1380. function reactor_laser(side)
  1381.   for key,reactorlaser in pairs(reactorlasers) do
  1382.     if (side == nil) or (reactorlaser.side == side) then
  1383.       reactorlaser.wrap.stabilize(data.reactor_laserAmount)
  1384.     end
  1385.   end
  1386. end
  1387.  
  1388. local reactor_configPageLoaded = false
  1389. function reactor_pulse(output)
  1390.   reactor_output = output
  1391.   if reactor == nil then
  1392.     os.reboot()
  1393.   end
  1394.   local instabilities = { reactor.instability() }
  1395.   for key,instability in pairs(instabilities) do
  1396.     local stability = 100.0 - instability
  1397.     if stability < data.reactor_targetStability then
  1398.       reactor_laser(key - 1)
  1399.     end
  1400.   end
  1401.   if page == reactor_page and (not reactor_configPageLoaded) then
  1402.     for key,instability in pairs(instabilities) do
  1403.       SetCursorPos(12, 2 + key)
  1404.       stability = math.floor((100.0 - instability) * 10) / 10
  1405.       if stability >= data.reactor_targetStability then
  1406.         SetColorSuccess()
  1407.       else
  1408.         SetColorWarning()
  1409.       end
  1410.       Write(FormatFloat(stability, 5) .. " %")
  1411.     end
  1412.    
  1413.     SetColorDefault()
  1414.     local energy = { reactor.energy() }
  1415.     SetCursorPos(12, 7)
  1416.     if energy[2] ~= nil then
  1417.       Write(FormatInteger(energy[1], 10))
  1418.       SetCursorPos(39, 7)
  1419.       Write(FormatInteger(reactor_output, 5))
  1420.     else
  1421.       Write("???")
  1422.     end
  1423.     if energy[3] ~= nil then
  1424.       SetCursorPos(12, 8)
  1425.       Write(energy[3] .. " RF/t    ")
  1426.     end
  1427.    
  1428.     if #reactorlasers ~= 0 then
  1429.       for key,reactorlaser in pairs(reactorlasers) do
  1430.         local side = reactorlaser.side
  1431.         if side ~= nil then
  1432.           side = side % 4
  1433.           SetCursorPos(30, 3 + side)
  1434.           local energy = reactorlaser.wrap.energy()
  1435.           if not reactorlaser.wrap.hasReactor() then
  1436.             SetColorDisabled()
  1437.           elseif energy > 3 * data.reactor_laserAmount then
  1438.             SetColorSuccess()
  1439.           else
  1440.             SetColorWarning()
  1441.           end
  1442.           Write(FormatInteger(energy, 6))
  1443.         end
  1444.       end
  1445.     end
  1446.   end
  1447. end
  1448.  
  1449. function reactor_config()
  1450.   reactor_configPageLoaded = true
  1451.   ShowTitle(label .. " - Reactor configuration")
  1452.  
  1453.   SetCursorPos(1, 2)
  1454.   if reactor == nil then
  1455.     SetColorDisabled()
  1456.     Write("Reactor not detected")
  1457.   else
  1458.     SetColorDefault()
  1459.     SetCursorPos(1, 4)
  1460.     Write("Reactor output rate (" .. data.reactor_rate .. " RF): ")
  1461.     data.reactor_rate = readInputNumber(data.reactor_rate)
  1462.     reactor_setMode()
  1463.     SetCursorPos(1, 5)
  1464.     Write("Reactor output rate set")
  1465.    
  1466.     SetCursorPos(1, 7)
  1467.     Write("Laser energy level (" .. data.reactor_laserAmount .. "): ")
  1468.     data.reactor_laserAmount = readInputNumber(data.reactor_laserAmount)
  1469.     reactor_setLaser()
  1470.     SetCursorPos(1, 8)
  1471.     Write("Laser energy level set")
  1472.    
  1473.     SetCursorPos(1, 10)
  1474.     Write("Reactor target stability (" .. data.reactor_targetStability .. "%): ")
  1475.     data.reactor_targetStability = readInputNumber(data.reactor_targetStability)
  1476.     reactor_setTargetStability()
  1477.     SetCursorPos(1, 11)
  1478.     Write("Reactor target stability set")
  1479.   end
  1480.   reactor_configPageLoaded = false
  1481. end
  1482.  
  1483. ----------- Radar support
  1484.  
  1485. radar_listOffset = 0
  1486. radar_timerId = -1
  1487. radar_timerLength = 1
  1488. radar_x = 0
  1489. radar_y = 0
  1490. radar_z = 0
  1491.  
  1492. function radar_boot()
  1493.   if radar ~= nil then
  1494.     WriteLn("Booting Radar...")
  1495.     if data.radar_monitorIndex > 0 then
  1496.       radar_x, radar_y, radar_z = radar.pos()
  1497.       radar_drawMap()
  1498.     end
  1499.     if data.radar_autoscan then
  1500.       radar_scan()
  1501.     end
  1502.   end
  1503. end
  1504.  
  1505. function radar_key(keycode)
  1506.   if keycode == 31 then -- S
  1507.     data.radar_autoscan = false
  1508.     radar_scan()
  1509.     return true
  1510.   elseif keycode == 30 then -- A
  1511.     data.radar_autoscan = true
  1512.     radar_scan()
  1513.     return true
  1514.   elseif keycode == 25 then -- P
  1515.     data.radar_autoscan = false
  1516.     return true
  1517.   elseif keycode == 49 then -- N
  1518.     radar_setMonitorIndex(data.radar_monitorIndex + 1)
  1519.     data_save()
  1520.     radar_drawMap()
  1521.     return true
  1522.   elseif keycode == 34 then -- G
  1523.     radar_setRadius(data.radar_radius - 100)
  1524.     data_save()
  1525.     return true
  1526.   elseif keycode == 20 then -- T
  1527.     if data.radar_radius < 100 then
  1528.       radar_setRadius(100)
  1529.     else
  1530.       radar_setRadius(data.radar_radius + 100)
  1531.     end
  1532.     data_save()
  1533.     return true
  1534.   elseif keycode == 36 then -- J
  1535.     radar_listOffset = math.max(0, radar_listOffset - 3)
  1536.     return true
  1537.   elseif keycode == 22 then -- U
  1538.     radar_listOffset = math.min(#data.radar_results - 1, radar_listOffset + 3)
  1539.     return true
  1540.   elseif keycode == 74 then -- -
  1541.     data.radar_scale = math.min(10000, math.floor(data.radar_scale * 1.2 + 0.5))
  1542.     data_save()
  1543.     radar_drawMap()
  1544.     return true
  1545.   elseif keycode == 78 then -- +
  1546.     data.radar_scale = math.max(20, math.floor(data.radar_scale * 0.8 + 0.5))
  1547.     data_save()
  1548.     radar_drawMap()
  1549.     return true
  1550.   elseif keycode == 199 then -- home
  1551.     data.radar_offsetX = 0;
  1552.     data.radar_offsetY = 0;
  1553.     data.radar_scale = 20
  1554.     for i = 0, #data.radar_results - 1 do
  1555.       data.radar_scale = math.max(data.radar_scale, math.max(math.abs(radar_x - data.radar_results[i].x), math.abs(radar_z - data.radar_results[i].z)))
  1556.     end
  1557.     data.radar_scale = math.min(10000, math.floor(data.radar_scale * 1.1 + 0.5))
  1558.     data_save()
  1559.     radar_drawMap()
  1560.     return true
  1561.   elseif keycode == 203 then -- left
  1562.     data.radar_offsetX = data.radar_offsetX - 0.20 * data.radar_scale;
  1563.     data_save()
  1564.     radar_drawMap()
  1565.     return true
  1566.   elseif keycode == 205 then -- right
  1567.     data.radar_offsetX = data.radar_offsetX + 0.20 * data.radar_scale;
  1568.     data_save()
  1569.     radar_drawMap()
  1570.     return true
  1571.   elseif keycode == 200 then -- up
  1572.     data.radar_offsetY = data.radar_offsetY - 0.20 * data.radar_scale;
  1573.     data_save()
  1574.     radar_drawMap()
  1575.     return true
  1576.   elseif keycode == 208 then -- down
  1577.     data.radar_offsetY = data.radar_offsetY + 0.20 * data.radar_scale;
  1578.     data_save()
  1579.     radar_drawMap()
  1580.     return true
  1581.   elseif keycode == 46 then -- C
  1582.     radar_page_config()
  1583.     data_save()
  1584.     return true
  1585.   end
  1586.   return false
  1587. end
  1588.  
  1589. function radar_page()
  1590.   local radar_resultsPerPage = 9
  1591.  
  1592.   ShowTitle(label .. " - Radar map")
  1593.  
  1594.   SetCursorPos(1, 2)
  1595.   if radar == nil then
  1596.     SetColorDisabled()
  1597.     Write("Radar not detected")
  1598.   else
  1599.     SetColorDefault()
  1600.     if #data.radar_results == 0 then
  1601.       Write("No contacts in range...")
  1602.     else
  1603.       local lastResultShown = radar_listOffset + radar_resultsPerPage - 1
  1604.       if lastResultShown >= #data.radar_results then
  1605.         lastResultShown = #data.radar_results - 1
  1606.       end
  1607.       Write("Displaying results " .. (radar_listOffset + 1) .. " to " .. (lastResultShown + 1) .. " of " .. #data.radar_results)
  1608.       for i = radar_listOffset, lastResultShown do
  1609.         SetCursorPos(4, 3 + i - radar_listOffset)
  1610.         if data.radar_results ~= nil then
  1611.           Write(FormatInteger(data.radar_results[i].x, 7) .. ", " .. FormatInteger(data.radar_results[i].y, 4) .. ", " .. FormatInteger(data.radar_results[i].z, 7))
  1612.           Write(": " .. data.radar_results[i].frequency)
  1613.         else
  1614.           Write("~nil~")
  1615.         end
  1616.       end
  1617.     end
  1618.  
  1619.     SetColorDefault()
  1620.     local energy = { radar.energy() }
  1621.     SetCursorPos(1, 12)
  1622.     Write("Energy: ")
  1623.     if energy ~= nil then
  1624.       if energy[1] > (data.radar_radius * data.radar_radius) then
  1625.         SetColorSuccess()
  1626.       else
  1627.         SetColorWarning()
  1628.       end
  1629.       Write(FormatInteger(energy[1], 10) .. " EU")
  1630.     else
  1631.       SetColorDisabled()
  1632.       Write("???")
  1633.     end
  1634.     SetColorDefault()
  1635.     SetCursorPos(1, 13)
  1636.     Write("Radius: " .. data.radar_radius)
  1637.  
  1638.     SetCursorPos(30, 13)
  1639.     Write("Monitor# " .. data.radar_monitorIndex .. "/" .. #monitors)
  1640.  
  1641.     SetCursorPos(1, 14)
  1642.     Write("Autoscan: ")
  1643.     if data.radar_autoscan then SetColorSuccess() else SetColorDefault() end
  1644.     Write(boolToYesNo(data.radar_autoscan))
  1645.  
  1646.     SetColorDefault()
  1647.     SetCursorPos(30, 14)
  1648.     Write("Delay " .. data.radar_autoscanDelay .. "s")
  1649.   end
  1650.  
  1651.   SetColorTitle()
  1652.   SetCursorPos(1, 15)
  1653.   ShowMenu("S - Scan once, A - Autoscan, P - Stop autoscan")
  1654.   SetCursorPos(1, 16)
  1655.   ShowMenu("T/G - Scan radius, U/J - Scroll list")
  1656.   SetCursorPos(1, 17)
  1657.   ShowMenu("+/- - Scale, N - Next monitor, C - Configuration")
  1658. end
  1659.  
  1660. function radar_page_config()
  1661.   ShowTitle(label .. " - Radar configuration")
  1662.  
  1663.   SetCursorPos(1, 2)
  1664.   if radar == nil then
  1665.     SetColorDisabled()
  1666.     Write("No radar detected")
  1667.   else
  1668.     SetColorDefault()
  1669.     SetCursorPos(1, 3)
  1670.     Write("Radar scan radius (" .. data.radar_radius .. " blocks): ")
  1671.     radar_setRadius(readInputNumber(data.radar_radius))
  1672.    
  1673.     SetCursorPos(1, 5)
  1674.     Write("Autoscan delay in seconds (" .. data.radar_autoscanDelay .. "): ")
  1675.     radar_setAutoscanDelay(readInputNumber(data.radar_autoscanDelay))
  1676.    
  1677.     SetCursorPos(1, 7)
  1678.     Write("Output monitor (" .. data.radar_monitorIndex .. "/" .. #monitors .. "): ")
  1679.     radar_setMonitorIndex(readInputNumber(data.radar_monitorIndex))
  1680.    
  1681.     data_save()
  1682.   end
  1683. end
  1684.  
  1685. function radar_setRadius(newRadius)
  1686.   if newRadius < 1 then
  1687.     data.radar_radius = 1
  1688.   elseif newRadius >= 10000 then
  1689.     data.radar_radius = 10000
  1690.   else
  1691.     data.radar_radius = newRadius
  1692.   end
  1693. end
  1694.  
  1695. function radar_setAutoscanDelay(newAutoscanDelay)
  1696.   if newAutoscanDelay < 1 then
  1697.     data.radar_autoscanDelay = 1
  1698.   elseif newAutoscanDelay >= 3600 then  -- 1 hour
  1699.     data.radar_autoscanDelay = 3600
  1700.   else
  1701.     data.radar_autoscanDelay = newAutoscanDelay
  1702.   end
  1703. end
  1704.  
  1705. function radar_setMonitorIndex(newIndex)
  1706.   if #monitors == 0 or newIndex < 0 or newIndex > #monitors then
  1707.     data.radar_monitorIndex = 0
  1708.   else
  1709.     data.radar_monitorIndex = newIndex
  1710.   end
  1711. end
  1712.  
  1713. function radar_getMonitor()
  1714.   if data.radar_monitorIndex > 0 and data.radar_monitorIndex <= #monitors then
  1715.     return monitors[data.radar_monitorIndex]
  1716.   else
  1717.     return nil
  1718.   end
  1719. end
  1720.  
  1721. function radar_scan()
  1722.   local monitor = radar_getMonitor()
  1723.   if radar == nil then
  1724.     draw_warning(monitor, "No radar")
  1725.     return false
  1726.   end
  1727.   if radar.energy() < (data.radar_radius * data.radar_radius) then
  1728.     draw_warning(monitor, "LOW POWER")
  1729.     return false
  1730.   end
  1731.   if radar_timerId ~= -1 and radar.getResultsCount() == -1 then
  1732.     draw_warning(monitor, "Already scanning...")
  1733.     return false
  1734.   end
  1735.   radar_timerId = os.startTimer(radar_timerLength)
  1736.  
  1737.   radar.radius(data.radar_radius)
  1738.   if radar.start() then
  1739.     draw_warning(monitor, "Scanning...")
  1740.   end
  1741.   return false
  1742. end
  1743.  
  1744. function radar_scanDone()
  1745.   local numResults = radar.getResultsCount();
  1746.   data.radar_results = {}
  1747.   if (numResults ~= 0) then
  1748.     for i = 0, numResults do
  1749.       local success, type, name, x, y, z = radar.getResult(i)
  1750.       if success then
  1751.         if name == "default" then
  1752.           name = "?"
  1753.         end
  1754.         data.radar_results[i] = { x = x, y = y, z = z, name = name, type = type }
  1755.       end
  1756.     end
  1757.     data.radar_scale = data.radar_radius
  1758.   end
  1759.   data_save()
  1760.   radar_drawMap()
  1761. end
  1762.  
  1763. function draw_text(monitor, x, y, text, textColor, backgroundColor)
  1764.   if monitor == nil then
  1765.     term.setCursorPos(x, y)
  1766.     if textColor ~= nil then term.setTextColor(textColor) end
  1767.     if backgroundColor ~= nil then term.setBackgroundColor(backgroundColor) end
  1768.     term.write(text)
  1769.     local xt, yt = term.getCursorPos()
  1770.     term.setCursorPos(1, yt + 1)
  1771.   else
  1772.     monitor.setCursorPos(x, y)
  1773.     if textColor ~= nil then monitor.setTextColor(textColor) end
  1774.     if backgroundColor ~= nil then monitor.setBackgroundColor(backgroundColor) end
  1775.     monitor.write(text)
  1776.     local xt, yt = monitor.getCursorPos()
  1777.     monitor.setCursorPos(1, yt + 1)
  1778.   end
  1779. end  
  1780.  
  1781. function draw_warning(monitor, text)
  1782.   local screenWidth, screenHeight
  1783.   if monitor == nil then
  1784.     screenWidth, screenHeight = term.getSize()
  1785.   else
  1786.     screenWidth, screenHeight = monitor.getSize()
  1787.   end
  1788.   local centerX = math.floor(screenWidth / 2);
  1789.   local centerY = math.floor(screenHeight / 2);
  1790.   local halfWidth = math.ceil(string.len(text) / 2);
  1791.   local blank = string.sub("                              ", - (string.len(text) + 2))
  1792.  
  1793.   draw_text(monitor, centerX - halfWidth - 1, centerY - 1, blank, colors.white, colors.red);
  1794.   draw_text(monitor, centerX - halfWidth - 1, centerY    , " " .. text .. " ", colors.white, colors.red);
  1795.   draw_text(monitor, centerX - halfWidth - 1, centerY + 1, blank, colors.white, colors.red);
  1796. end
  1797.  
  1798. function draw_centeredText(monitor, y, text)
  1799.   local screenWidth, screenHeight
  1800.   if monitor == nil then
  1801.     screenWidth, screenHeight = term.getSize()
  1802.   else
  1803.     screenWidth, screenHeight = monitor.getSize()
  1804.   end
  1805.   local x = math.floor(screenWidth / 2 - string.len(text) / 2 + 0.5);
  1806.  
  1807.   draw_text(monitor, x, y, text, nil, nil);
  1808. end
  1809.  
  1810. function radar_drawContact(monitor, contact)
  1811.   local screenWidth, screenHeight
  1812.   if monitor == nil then
  1813.     screenWidth, screenHeight = term.getSize()
  1814.   else
  1815.     screenWidth, screenHeight = monitor.getSize()
  1816.   end
  1817.  
  1818.   local screenX = (radar_x + data.radar_offsetX - contact.x) / data.radar_scale
  1819.   local screenY = (radar_z + data.radar_offsetY - contact.z) / data.radar_scale
  1820.   local visible = true
  1821.  
  1822.   if screenX <= -1 or screenX >= 1 or screenY <= -1 or screenY >= 1 then
  1823.     screenX = math.min(1, math.max(-1, screenX))
  1824.     screenY = math.min(1, math.max(-1, screenY))
  1825.     visible = false
  1826.   end
  1827.  
  1828.   screenX = math.floor(screenX * (screenWidth  - 3) / 2 + ((screenWidth  - 1)  / 2) + 1.5)
  1829.   screenY = math.floor(screenY * (screenHeight - 3) / 2 + ((screenHeight - 1) / 2) + 1.5)
  1830.  
  1831.   if contact.type == "self" then
  1832.     draw_text(monitor, screenX, screenY, Style.TextRadarself, Style.CRadarself, Style.BGRadarself)
  1833.   else
  1834.     draw_text(monitor, screenX, screenY, Style.TextRadarother, Style.CRadarother, Style.BGRadarother)
  1835.   end
  1836.   if visible then
  1837.     local text = contact.name
  1838.     screenX = math.min(screenWidth - 1 - string.len(text), math.max(2, math.floor(screenX - string.len(text) / 2 + 0.5)))
  1839.     if screenY == (screenHeight - 1) then
  1840.       screenY = screenY - 1
  1841.     else
  1842.       screenY = screenY + 1
  1843.     end
  1844.     draw_text(monitor, screenX, screenY, text, Style.CRadarother, Style.BGRadarother)
  1845.   end
  1846. end
  1847.  
  1848. function radar_drawMap()
  1849.   local screenWidth, screenHeight, x, y
  1850.   local monitor = radar_getMonitor()
  1851.   -- center area
  1852.   SetColorRadarmap()
  1853.   if monitor == nil then
  1854.     term.clear()
  1855.     screenWidth, screenHeight = term.getSize()
  1856.   else
  1857.     monitor.clear()
  1858.     screenWidth, screenHeight = monitor.getSize()
  1859.   end
  1860.   -- borders
  1861.   SetColorRadarborder()
  1862.   for x = 1, screenWidth do
  1863.     if monitor == nil then
  1864.       term.setCursorPos(x, 1)
  1865.       term.write(" ")
  1866.       term.setCursorPos(x, screenHeight)
  1867.       term.write(" ")
  1868.     else
  1869.       monitor.setCursorPos(x, 1)
  1870.       monitor.write(" ")
  1871.       monitor.setCursorPos(x, screenHeight)
  1872.       monitor.write(" ")
  1873.     end
  1874.   end
  1875.   for y = 2, screenHeight - 1 do
  1876.     if monitor == nil then
  1877.       term.setCursorPos(1, y)
  1878.       term.write(" ")
  1879.       term.setCursorPos(screenWidth, y)
  1880.       term.write(" ")
  1881.     else
  1882.       monitor.setCursorPos(1, y)
  1883.       monitor.write(" ")
  1884.       monitor.setCursorPos(screenWidth, y)
  1885.       monitor.write(" ")
  1886.     end
  1887.   end
  1888.   -- title
  1889.   local text = label .. " - Radar map"
  1890.   if #data.radar_results == 0 then
  1891.     text = text .. " (no contacts)"
  1892.   else
  1893.     text = text .. " (" .. #data.radar_results .. " contacts)"
  1894.   end
  1895.      draw_centeredText(monitor, 1, text)
  1896.   -- status
  1897.   local text = "Scan radius: " .. data.radar_radius
  1898.   if radar ~= nil then
  1899.     text = text .. " | Energy: " .. radar.energy() .. " EU"
  1900.   end
  1901.   text = text .. " | Scale: " .. data.radar_scale
  1902.   draw_centeredText(monitor, screenHeight, text)
  1903.   -- results
  1904.   SetCursorPos(1, 12)
  1905.   radar_drawContact(monitor, {x = radar_x, y = radar_y, z = radar_z, name = "", type = "self"})
  1906.   for i = 0, #data.radar_results - 1 do
  1907.     radar_drawContact(monitor, data.radar_results[i])
  1908.   end
  1909.  
  1910.   -- restore defaults
  1911.   SetColorDefault()
  1912. end
  1913.  
  1914. radar_waitingNextScan = false
  1915. function radar_timerEvent()
  1916.   radar_timerId = -1
  1917.   if radar_waitingNextScan then
  1918.     radar_waitingNextScan = false
  1919.     radar_scan() -- will restart timer
  1920.   else
  1921.     local numResults = radar.getResultsCount();
  1922.     if numResults ~= -1 then
  1923.       radar_scanDone()
  1924.       if data.radar_autoscan then
  1925.         radar_waitingNextScan = true
  1926.         radar_timerId = os.startTimer(data.radar_autoscanDelay)
  1927.       end
  1928.     else -- still scanning
  1929.       radar_timerId = os.startTimer(radar_timerLength)
  1930.     end
  1931.   end
  1932. end
  1933.  
  1934. ----------- Boot sequence
  1935. math.randomseed(os.time())
  1936. label = os.getComputerLabel()
  1937. if not label then
  1938.   label = "" .. os.getComputerID()
  1939. end
  1940.  
  1941. -- read configuration
  1942. data_read()
  1943. Clear()
  1944. print("data_read...")
  1945.  
  1946. -- initial scanning
  1947. monitors = {}
  1948. ShowTitle(label .. " - Connecting...")
  1949. WriteLn("")
  1950.  
  1951. sides = peripheral.getNames()
  1952. reactor = nil
  1953. mininglasers = {}
  1954. reactorlasers = {}
  1955. cloakingcores = {}
  1956. ship = nil
  1957. radar = nil
  1958. for key,side in pairs(sides) do
  1959.   os.sleep(0)
  1960.   Write("Checking " .. side .. " ")
  1961.   local componentType = peripheral.getType(side)
  1962.   Write(componentType .. " ")
  1963.   if componentType == "warpdriveShipController" then
  1964.     Write("wrapping!")
  1965.     ship = peripheral.wrap(side)
  1966.   elseif componentType == "warpdriveEnanReactorCore" then
  1967.     Write("wrapping!")
  1968.     reactor = peripheral.wrap(side)
  1969.   elseif componentType == "warpdriveEnanReactorLaser" then
  1970.     Write("wrapping!")
  1971.     local wrap = peripheral.wrap(side)
  1972.     table.insert(reactorlasers, { side = wrap.side(), wrap = wrap })
  1973.   elseif componentType == "warpdriveMiningLaser" then
  1974.     WriteLn("Wrapping " .. side)
  1975.     table.insert(mininglasers, peripheral.wrap(side))
  1976.   elseif componentType == "warpdriveCloakingCore" then
  1977.     Write("wrapping!")
  1978.     table.insert(cloakingcores, peripheral.wrap(side))
  1979.   elseif componentType == "warpdriveRadar" then
  1980.     Write("wrapping!")
  1981.     radar = peripheral.wrap(side);
  1982.   elseif componentType == "monitor" then
  1983.     Write("wrapping!")
  1984.     lmonitor = peripheral.wrap(side)
  1985.     table.insert(monitors, lmonitor)
  1986.     lmonitor.setTextScale(monitor_textScale)
  1987.   end
  1988.   WriteLn("")
  1989. end
  1990.  
  1991. if not os.getComputerLabel() and (ship ~= nil or reactor ~= nil) then
  1992.   data_setName()
  1993. end
  1994.  
  1995. -- peripherals status
  1996. function connections_page()
  1997.   ShowTitle(label .. " - Connections")
  1998.  
  1999.   WriteLn("")
  2000.   if #monitors == 0 then
  2001.     SetColorDisabled()
  2002.     WriteLn("No Monitor detected")
  2003.   elseif #monitors == 1 then
  2004.     SetColorSuccess()
  2005.     WriteLn("1 monitor detected")
  2006.   else
  2007.     SetColorSuccess()
  2008.     WriteLn(#monitors .. " Monitors detected")
  2009.   end
  2010.  
  2011.   if ship == nil then
  2012.     SetColorDisabled()
  2013.     WriteLn("No ship controller detected")
  2014.   else
  2015.     SetColorSuccess()
  2016.     WriteLn("Ship controller detected")
  2017.   end
  2018.  
  2019.   if reactor == nil then
  2020.     SetColorDisabled()
  2021.     WriteLn("No Enantiomorphic reactor detected")
  2022.   else
  2023.     SetColorSuccess()
  2024.     WriteLn("Enantiomorphic reactor detected")
  2025.   end
  2026.  
  2027.   if #reactorlasers == 0 then
  2028.     SetColorDisabled()
  2029.     WriteLn("No reactor stabilisation laser detected")
  2030.   elseif #reactorlasers == 1 then
  2031.     SetColorSuccess()
  2032.     WriteLn("1 reactor stabilisation laser detected")
  2033.   else
  2034.     SetColorSuccess()
  2035.     WriteLn(#reactorlasers .. " reactor stabilisation lasers detected")
  2036.   end
  2037.  
  2038.   if #mininglasers == 0 then
  2039.     SetColorDisabled()
  2040.     WriteLn("No mining laser detected")
  2041.   elseif #mininglasers == 1 then
  2042.     SetColorSuccess()
  2043.     WriteLn("1 mining laser detected")
  2044.   else
  2045.     SetColorSuccess()
  2046.     WriteLn(#mininglasers .. " mining lasers detected")
  2047.   end
  2048.  
  2049.   if #cloakingcores == 0 then
  2050.     SetColorDisabled()
  2051.     WriteLn("No cloaking core detected")
  2052.   elseif #cloakingcores == 1 then
  2053.     SetColorSuccess()
  2054.     WriteLn("1 cloaking core detected")
  2055.   else
  2056.     SetColorSuccess()
  2057.     WriteLn(#cloakingcores .. " cloaking cores detected")
  2058.   end
  2059.  
  2060.   if radar == nil then
  2061.     SetColorDisabled()
  2062.     WriteLn("No radar detected")
  2063.   else
  2064.     SetColorSuccess()
  2065.     WriteLn("Radar detected")
  2066.   end
  2067.  
  2068.   WriteLn("")
  2069.   SetColorTitle()
  2070.   WriteLn("Please refer to below menu for keyboard controls")
  2071.   WriteLn("For example, press 1 to access Reactor page")
  2072. end
  2073.  
  2074. -- peripheral boot up
  2075. Clear()
  2076. connections_page()
  2077. SetColorDefault()
  2078. WriteLn("")
  2079. os.sleep(0)
  2080. radar_boot()
  2081. core_boot()
  2082. reactor_boot()
  2083. os.sleep(0)
  2084.  
  2085. -- main loop
  2086. abort = false
  2087. refresh = true
  2088. page = connections_page
  2089. keyHandler = nil
  2090. repeat
  2091.   ClearWarning()
  2092.   if refresh then
  2093.     Clear()
  2094.     page()
  2095.     menu_common()
  2096.     refresh = false
  2097.   end
  2098.   params = { os.pullEventRaw() }
  2099.   eventName = params[1]
  2100.   address = params[2]
  2101.   if address == nil then address = "none" end
  2102.   -- WriteLn("...")
  2103.   -- WriteLn("Event '" .. eventName .. "', " .. address .. ", " .. params[3] .. ", " .. params[4] .. " received")
  2104.   -- os.sleep(0.2)
  2105.   if eventName == "key" then
  2106.     keycode = params[2]
  2107.     if char == 88 or char == 120 or keycode == 45 then -- x for eXit
  2108.       os.pullEventRaw()
  2109.       abort = true
  2110.     elseif char == 48 or keycode == 11 or keycode == 82 then -- 0
  2111.       page = connections_page
  2112.       keyHandler = nil
  2113.       refresh = true
  2114.     elseif char == 49 or keycode == 2 or keycode == 79 then -- 1
  2115.       page = reactor_page
  2116.       keyHandler = reactor_key
  2117.       refresh = true
  2118.     elseif char == 50 or keycode == 3 or keycode == 80 then -- 2
  2119.       page = cloaking_page
  2120.       keyHandler = cloaking_key
  2121.       refresh = true
  2122.     elseif char == 51 or keycode == 4 or keycode == 81 then -- 3
  2123.       page = mining_page
  2124.       keyHandler = mining_key
  2125.       refresh = true
  2126.     elseif char == 52 or keycode == 5 or keycode == 75 then -- 4
  2127.       page = core_page
  2128.       keyHandler = core_key
  2129.       refresh = true
  2130.     elseif char == 53 or keycode == 6  or keycode == 76 then -- 5
  2131.       page = radar_page
  2132.       keyHandler = radar_key
  2133.       refresh = true
  2134.     elseif keyHandler ~= nil and keyHandler(char, keycode) then
  2135.       refresh = true
  2136.       os.sleep(0)
  2137.     elseif char == 0 then -- control chars
  2138.       refresh = false
  2139.       os.sleep(0)
  2140.     else
  2141.       ShowWarning("Key " .. keycode .. " is invalid")
  2142.       os.sleep(0.2)
  2143.     end
  2144.   elseif eventName == "reactorPulse" then
  2145.     reactor_pulse(params[2])
  2146.     refresh = (page == reactor_page)
  2147.   elseif eventName == "terminate" then
  2148.     abort = true
  2149.   elseif not common_event(eventName, params[2]) then
  2150.     ShowWarning("Event '" .. eventName .. "', " .. address .. " is unsupported")
  2151.     refresh = true
  2152.     os.sleep(0.2)
  2153.   end
  2154. until abort
  2155.  
  2156. -- exiting
  2157. if data.core_summon then
  2158.   data.core_summon = false
  2159.   data_save()
  2160. end
  2161.  
  2162. if ship ~= nil then
  2163.   ship.mode(0)
  2164. end
  2165.  
  2166. -- clear screens on exit
  2167. SetMonitorColorFrontBack(colors.white, colors.black)
  2168. term.clear()
  2169. if monitors ~= nil then
  2170.   for key,monitor in pairs(monitors) do
  2171.     monitor.clear()
  2172.   end
  2173. end
  2174. SetCursorPos(1, 1)
  2175. WriteLn("Program terminated")
  2176. WriteLn("Type startup to restart it")
Advertisement
Add Comment
Please, Sign In to add comment
Advertisement