Not a member of Pastebin yet?
Sign Up,
it unlocks many cool features!
- local event = require("event")
- local term = require("term")
- local os = require("os")
- local computer = require("computer")
- local com = require("component")
- local unicode = require("unicode")
- local keyb = require("keyboard")
- local gpu = com.gpu
- local reactorsFile = "/home/reactors.txt"
- local cfgName = "/home/DracReactorConfig.cfg"
- local MAX_REACTORS = 5
- local CHARGE_FLOW = 535000
- local CHARGE_DURATION = 12
- local autostateByAdr = {}
- local flowInitByAdr = {}
- local chargeRequestByAdr = {}
- local DEFAULT_CONFIG = [[
- -- Интервалы для кнопок +/-
- default_interval = 1000
- ctrl_interval = 5000
- shift_interval = 10000
- ctrlShift_interval = 20000
- -- Автономный режим:
- -- Основные константы
- shield = 25 - Щиты будут автоматически поддерживаться на этом уровне ( в %)
- tempCriticalEdge = 8100 -- Если температура превысит это значение, программа экстренно понизит поток вывода;
- -- Форсированный режим
- forceModeTempLowEdge = 7500 -- Пока температура не превысит это значение, программа будет работать в форсированном режиме, иначе - перейдет в безопасный режим;
- forceModeStepCase = 5000 -- Если разница между текущей выработкой энергии и выставленным потоком превысит это значение, то к потоку добавится
- forceModeStep = 20000 -- это значение
- -- безопасный режим
- safeModeTempWaitEdge = 8000 -- Если температура превысит это значение, программа будет ожидать,
- safeModeTempToWaitEdge = 7850 -- пока температура не понизится до этого значения;
- safeModeStepCase = 0 -- Если разница между текущей выработкой энергии и выставленным потоком превысит это значение, то к потоку добавится
- safemodeStep = 8000 -- это значение
- autoProtectTempEdge = 8300 -- При достижении этой температуры включается автономный режим
- screen_w = 80 -- Ширина экрана
- screen_h = 25 -- Высота экрана
- fuelStopPct = 98 -- % топлива, при котором реактор выключается]]
- local function parseNum(str)
- local n = ""
- for i = 1, #str do
- local ch = str:byte(i, i)
- if ch >= 48 and ch <= 57 or ch == 46 then
- n = n .. string.char(ch)
- end
- end
- if n ~= "" then
- return tonumber(n)
- else
- return n
- end
- end
- local cfg = {}
- local confnames = {
- [1] = "default_interval",
- [2] = "ctrl_interval",
- [3] = "shift_interval",
- [4] = "ctrlShift_interval",
- [5] = "shield",
- [6] = "tempCriticalEdge",
- [7] = "forceModeTempLowEdge",
- [8] = "forceModeStepCase",
- [9] = "forceModeStep",
- [10] = "safeModeTempWaitEdge",
- [11] = "safeModeTempToWaitEdge",
- [12] = "safeModeStepCase",
- [13] = "safemodeStep",
- [14] = "autoProtectTempEdge",
- [15] = "screen_w",
- [16] = "screen_h",
- [17] = "fuelStopPct"
- }
- local function readConfig(name)
- local file = io.open(name, "r")
- if not file then
- return nil
- end
- local tab = {}
- for line in file:lines() do
- local key, val = line:match("^%s*([%w_]+)%s*=%s*([%d%.]+)")
- if key and val then
- tab[key] = tonumber(val)
- end
- end
- file:close()
- return tab
- end
- local function hasConfigKeys(parsed)
- if not parsed then
- return false
- end
- for i = 1, #confnames do
- if parsed[confnames[i]] == nil then
- return false
- end
- end
- return true
- end
- local function readParse(name)
- local file = io.open(name, "r")
- if file then
- local tab = {}
- local i = 1
- while true do
- local str = file:read("*l")
- if str == nil then
- break
- end
- if parseNum(str) ~= "" then
- tab[i] = parseNum(str)
- i = i + 1
- end
- end
- file:close()
- return tab
- else
- return false
- end
- end
- local function writeText(name, text)
- local file = io.open(name, "w")
- file:write(text)
- file:close()
- end
- local function configWrite(name)
- local parsed = readConfig(name)
- if not parsed or not hasConfigKeys(parsed) then
- writeText(name, DEFAULT_CONFIG)
- elseif cfg.default_interval ~= nil and
- cfg.ctrl_interval ~= nil and
- cfg.shift_interval ~= nil and
- cfg.ctrlShift_interval ~= nil and
- cfg.shield ~= nil and
- cfg.tempCriticalEdge ~= nil and
- cfg.forceModeTempLowEdge ~= nil and
- cfg.forceModeStepCase ~= nil and
- cfg.forceModeStep ~= nil and
- cfg.safeModeTempWaitEdge ~= nil and
- cfg.safeModeTempToWaitEdge ~= nil and
- cfg.safeModeStepCase ~= nil and
- cfg.safemodeStep ~= nil and
- cfg.autoProtectTempEdge ~= nil and
- cfg.screen_w ~= nil and
- cfg.screen_h ~= nil and
- cfg.fuelStopPct ~= nil then
- writeText(name, string.format([[
- -- Интервалы для кнопок +/-
- default_interval = %d
- ctrl_interval = %d
- shift_interval = %d
- ctrlShift_interval = %d
- -- Автономный режим:
- -- Основные константы
- shield = %0.2f - Щиты будут автоматически поддерживаться на этом уровне ( в %)
- tempCriticalEdge = %d -- Если температура превысит это значение, программа экстренно понизит поток вывода;
- -- Форсированный режим
- forceModeTempLowEdge = %d -- Пока температура не превысит это значение, программа будет работать в форсированном режиме, иначе - перейдет в безопасный режим;
- forceModeStepCase = %d -- Если разница между текущей выработкой энергии и выставленным потоком превысит это значение, то к потоку добавится
- forceModeStep = %d -- это значение
- -- Безопасный режим
- safeModeTempWaitEdge = %d -- Если температура превысит это значение, программа будет ожидать,
- safeModeTempToWaitEdge = %d -- пока температура не понизится до этого значения;
- safeModeStepCase = %d -- Если разница между текущей выработкой энергии и выставленным потоком превысит это значение, то к потоку добавится
- safemodeStep = %d -- это значение
- autoProtectTempEdge = %d -- При достижении этой температуры включается автономный режим
- screen_w = %d -- Ширина экрана
- screen_h = %d -- Высота экрана
- fuelStopPct = %d -- % топлива, при котором реактор выключается]],
- cfg.default_interval,
- cfg.ctrl_interval,
- cfg.shift_interval,
- cfg.ctrlShift_interval,
- cfg.shield,
- cfg.tempCriticalEdge,
- cfg.forceModeTempLowEdge,
- cfg.forceModeStepCase,
- cfg.forceModeStep,
- cfg.safeModeTempWaitEdge,
- cfg.safeModeTempToWaitEdge,
- cfg.safeModeStepCase,
- cfg.safemodeStep,
- cfg.autoProtectTempEdge,
- cfg.screen_w,
- cfg.screen_h,
- cfg.fuelStopPct
- ))
- end
- end
- local function makeConfig(tab, tab2)
- local config = {}
- for i = 1, #tab do
- config[tostring(tab[i])] = tab2[i]
- end
- return config
- end
- local function listAddresses(typeName)
- local list = {}
- for adr in com.list(typeName) do
- list[#list + 1] = adr
- end
- return list
- end
- local function readReactorsFile()
- local file = io.open(reactorsFile, "r")
- if not file then
- return nil
- end
- local list = {}
- for line in file:lines() do
- local r, u, d = line:match("(%S+)%s+(%S+)%s+(%S+)")
- if r and u and d then
- list[#list + 1] = {reactorAdr = r, upAdr = u, downAdr = d}
- end
- end
- file:close()
- if #list == 0 then
- return nil
- end
- return list
- end
- local function writeReactorsFile(list)
- local file = io.open(reactorsFile, "w")
- for i = 1, #list do
- file:write(string.format("%s %s %s\n", list[i].reactorAdr, list[i].upAdr, list[i].downAdr))
- end
- file:close()
- end
- local function validEntry(entry)
- return com.get(entry.reactorAdr) ~= nil and com.get(entry.upAdr) ~= nil and com.get(entry.downAdr) ~= nil
- end
- local function mergeEntries(entries)
- local usedReactors = {}
- local usedGates = {}
- for i = 1, #entries do
- usedReactors[entries[i].reactorAdr] = true
- usedGates[entries[i].upAdr] = true
- usedGates[entries[i].downAdr] = true
- end
- local reactorsList = listAddresses("draconic_reactor")
- local gates = listAddresses("flux_gate")
- local freeReactors = {}
- local freeGates = {}
- for i = 1, #reactorsList do
- if not usedReactors[reactorsList[i]] then
- freeReactors[#freeReactors + 1] = reactorsList[i]
- end
- end
- for i = 1, #gates do
- if not usedGates[gates[i]] then
- freeGates[#freeGates + 1] = gates[i]
- end
- end
- local addCount = math.min(#freeReactors, math.floor(#freeGates / 2), MAX_REACTORS - #entries)
- for i = 1, addCount do
- entries[#entries + 1] = {
- reactorAdr = freeReactors[i],
- upAdr = freeGates[(i - 1) * 2 + 1],
- downAdr = freeGates[(i - 1) * 2 + 2]
- }
- end
- return entries
- end
- local function buildReactors()
- newEntriesAdded = false
- lastAddedReactorAdr = nil
- local entries = readReactorsFile()
- local currentReactors = reactors or {}
- if entries then
- local valid = {}
- for i = 1, #entries do
- if validEntry(entries[i]) then
- valid[#valid + 1] = entries[i]
- end
- end
- if #valid > 0 then
- entries = valid
- end
- end
- if entries and #entries > 0 then
- local reactorsList = listAddresses("draconic_reactor")
- if #reactorsList > #entries then
- newEntriesAdded = true
- end
- end
- if not entries or #entries == 0 then
- return nil
- end
- local oldByAdr = {}
- for i = 1, #currentReactors do
- oldByAdr[currentReactors[i].reactorAdr] = currentReactors[i]
- end
- local reactors = {}
- for i = 1, #entries do
- local e = entries[i]
- local old = oldByAdr[e.reactorAdr]
- local savedAuto = autostateByAdr[e.reactorAdr]
- local savedFlowInit = flowInitByAdr[e.reactorAdr]
- local savedCharge = chargeRequestByAdr[e.reactorAdr]
- reactors[i] = {
- index = i,
- reactorAdr = e.reactorAdr,
- upAdr = e.upAdr,
- downAdr = e.downAdr,
- reactor = com.proxy(com.get(e.reactorAdr)),
- upgate = com.proxy(com.get(e.upAdr)),
- downgate = com.proxy(com.get(e.downAdr)),
- maxGenerationRate = old and old.maxGenerationRate or 0,
- autostate = old and old.autostate or (savedAuto ~= nil and savedAuto or false),
- temprise = old and old.temprise or false,
- flowInit = old and old.flowInit or (savedFlowInit ~= nil and savedFlowInit or false),
- chargeRequested = old and old.chargeRequested or (savedCharge or 0),
- lastTemp = nil,
- row = {},
- powerBtn = {},
- tab = {}
- }
- if not old then
- lastAddedReactorAdr = e.reactorAdr
- end
- end
- return reactors
- end
- configWrite(cfgName)
- cfg = readConfig(cfgName)
- if not cfg then
- cfg = makeConfig(confnames, readParse(cfgName))
- end
- local reactors = {}
- local activeIndex = 1
- local summaryProfitCord = {x = nil, y = nil}
- local summaryEuCord = {x = nil, y = nil}
- local summaryShieldCord = {x = nil, y = nil}
- local summaryGenCord = {x = nil, y = nil}
- local summaryMaxProfitCord = {x = nil, y = nil}
- local maxSummaryProfit = 0
- local newEntriesAdded = false
- local pendingActiveReactorAdr = nil
- autostateByAdr = {}
- flowInitByAdr = {}
- local color = {}
- color["red"] = 0xFF0000
- color["green"] = 0x00FF00
- color["yellow"] = 0xFFD166
- color["skyblue"] = 0x4FC3F7
- color["black"] = 0x0F1115
- color["grey"] = 0x0F1115
- color["panel"] = 0x1A1F27
- color["blue"] = 0x4FC3F7
- color["orange"] = 0xFF9800
- color["white"] = 0xE6EDF3
- color["dark"] = 0x242B36
- color["dim"] = 0x7A8599
- local rback = gpu.getBackground()
- local rfore = gpu.getForeground()
- local chatBox = nil
- local handleMain
- local handleOptions
- local handleStart
- local screenAssign
- local screenOverview
- local assignMode = nil
- local firstStartCompleted = false
- local assignState = {
- reactorIndex = nil,
- reactorAdr = nil,
- shieldGateIdx = nil,
- shieldGateAdr = nil,
- outGateIdx = nil,
- outGateAdr = nil,
- step = "reactor",
- message = nil
- }
- local assignUi = {
- reactors = {},
- gates = {},
- gateAddrs = {},
- reactorAddrs = {},
- gateUse = {},
- selectedAdr = nil,
- back = {x = nil, y = nil, w = 0}
- }
- local easyAssign = {
- active = false,
- step = "reactor",
- index = 1,
- core = nil,
- shield = nil,
- output = nil,
- saved = false,
- message = nil,
- heavyBtn = {},
- easyBtn = {},
- continueBtn = {},
- finishBtn = {},
- backBtn = {},
- known = {},
- lastChatStep = nil,
- lastChatMessage = nil
- }
- local autoStopped = {}
- local autoWaitTempByAdr = {}
- local chargeRequestByAdr = {}
- local autoStoppedCord = {x = nil, y = nil}
- local chargeHintDismissed = false
- local chargeHint = {x = nil, y = nil, w = 0, visible = false}
- local menuItem = {}
- menuItem["options"] = {
- ["name"] = "Настройки |",
- ["x"] = 1,
- ["y"] = 2
- }
- menuItem["save"] = {
- ["name"] = "Сохранить |",
- ["x"] = 1,
- ["y"] = 2
- }
- menuItem["cancel"] = {
- ["name"] = " Отменить |",
- ["x"] = 12,
- ["y"] = 2
- }
- menuItem["overview"] = {
- ["name"] = "Главный |",
- ["x"] = 1,
- ["y"] = 2
- }
- menuItem["refresh"] = {
- ["name"] = "Обновить |",
- ["x"] = 1,
- ["y"] = 2
- }
- menuItem["gates"] = {
- ["name"] = "Гейты |",
- ["x"] = 1,
- ["y"] = 2
- }
- menuItem["back"] = {
- ["name"] = "Назад |",
- ["x"] = 1,
- ["y"] = 2
- }
- menuItem["reset"] = {
- ["name"] = "Сброс |",
- ["x"] = 1,
- ["y"] = 2
- }
- menuItem["optionsBack"] = {
- ["name"] = " Назад |",
- ["x"] = 1,
- ["y"] = 2
- }
- local xz, yz = gpu.maxResolution()
- local screenW = math.min(120, xz)
- local screenH = math.min(40, yz)
- gpu.setResolution(screenW, screenH)
- gpu.setBackground(color.grey)
- gpu.setForeground(color.white)
- local prog = true
- local OptionDefault = {}
- local OptionCtrl = {}
- local OptionShift = {}
- local OptionCtrlShift = {}
- local OptionShield = {}
- local OptionFuelStop = {}
- OptionDefault["value"] = cfg.default_interval
- OptionCtrl["value"] = cfg.ctrl_interval
- OptionShift["value"] = cfg.shift_interval
- OptionCtrlShift["value"] = cfg.ctrlShift_interval
- OptionShield["value"] = cfg.shield
- OptionFuelStop["value"] = cfg.fuelStopPct or 98
- local infcord = {
- ["status"] = {
- ["value"] = nil,
- ["x"] = nil,
- ["y"] = nil
- },
- ["temp"] = {
- ["value"] = nil,
- ["x"] = nil,
- ["y"] = nil
- },
- ["generation"] = {
- ["value"] = nil,
- ["x"] = nil,
- ["y"] = nil
- },
- ["maxgen"] = {
- ["value"] = nil,
- ["x"] = nil,
- ["y"] = nil
- },
- ["flow"] = {
- ["value"] = nil,
- ["x"] = nil,
- ["y"] = nil
- },
- ["puregen"] = {
- ["value"] = nil,
- ["x"] = nil,
- ["y"] = nil
- },
- ["drain"] = {
- ["value"] = nil,
- ["x"] = nil,
- ["y"] = nil
- },
- ["fstrth"] = {
- ["value"] = nil,
- ["x"] = nil,
- ["y"] = nil
- },
- ["esturn"] = {
- ["value"] = nil,
- ["x"] = nil,
- ["y"] = nil
- },
- ["fuel"] = {
- ["value"] = nil,
- ["x"] = nil,
- ["y"] = nil
- },
- ["fuelconv"] = {
- ["value"] = nil,
- ["x"] = nil,
- ["y"] = nil
- },
- ["core"] = {
- ["value"] = nil,
- ["x"] = nil,
- ["y"] = nil
- }
- }
- local button = {
- ["continue"] = {
- ["name"] = "Продолжить",
- ["x"] = nil,
- ["y"] = nil
- },
- ["change"] = {
- ["name"] = "Изменить",
- ["x"] = nil,
- ["y"] = nil
- },
- ["add"] = {
- ["name"] = " + ",
- ["x"] = nil,
- ["y"] = nil
- },
- ["sub"] = {
- ["name"] = " - ",
- ["x"] = nil,
- ["y"] = nil
- },
- ["start"] = {
- ["name"] = " [PWR] ЗАПУСК ",
- ["x"] = nil,
- ["y"] = nil,
- ["visible"] = nil
- },
- ["stop"] = {
- ["name"] = " [PWR] СТОП ",
- ["x"] = nil,
- ["y"] = nil,
- ["visible"] = nil
- },
- ["charge"] = {
- ["name"] = "Зарядить реактор ",
- ["x"] = nil,
- ["y"] = nil,
- ["visible"] = nil
- },
- ["autoon"] = {
- ["name"] = "[ON] ",
- ["x"] = nil,
- ["y"] = nil,
- },
- ["autooff"] = {
- ["name"] = "[OFF]",
- ["x"] = nil,
- ["y"] = nil,
- }
- }
- local ops = true
- local canedit = true
- local canclose = true
- local temprise
- local autostate = false
- local maxGenerationRate = 0
- local lastDetailUpdate = 0
- local lastOverviewUpdate = 0
- printf = function(s, ...)
- return io.write(s:format(...))
- end
- local function textWidth(s)
- local ok, len = pcall(unicode.len, s)
- if ok and len then
- return len
- end
- return #s
- end
- local function guiWrite(x, y, cf, cb, s, ...)
- term.setCursor(x, y)
- if cf >= 0 and cb >= 0 then
- local fg = gpu.getForeground()
- local bg = gpu.getBackground()
- gpu.setForeground(cf)
- gpu.setBackground(cb)
- printf(s, ...)
- gpu.setForeground(fg)
- gpu.setBackground(bg)
- elseif cb < 0 and cf >= 0 then
- local fg = gpu.getForeground()
- gpu.setForeground(cf)
- printf(s, ...)
- gpu.setForeground(fg)
- elseif cf < 0 and cb >= 0 then
- local bg = gpu.getBackground()
- printf(s, ...)
- gpu.setBackground(bg)
- else
- local fg = gpu.getForeground()
- gpu.setForeground(color.white)
- printf(s, ...)
- gpu.setForeground(fg)
- end
- end
- local function getCord(param)
- param.x, param.y = term.getCursor()
- return param.x, param.y
- end
- local function guiClear(y)
- local fg = gpu.getForeground()
- local bg = gpu.getBackground()
- gpu.setForeground(color.white)
- gpu.setBackground(color.grey)
- for i = y + 3, 3, -1 do
- term.setCursor(1, i)
- term.clearLine()
- end
- gpu.setForeground(fg)
- gpu.setBackground(bg)
- end
- local function setActive(index)
- if not reactors[index] then
- return
- end
- activeIndex = index
- reactor = reactors[index].reactor
- upgate = reactors[index].upgate
- downgate = reactors[index].downgate
- autostate = reactors[index].autostate
- temprise = reactors[index].temprise
- maxGenerationRate = reactors[index].maxGenerationRate
- end
- local function syncActive()
- if not reactors[activeIndex] then
- return
- end
- reactors[activeIndex].autostate = autostate
- reactors[activeIndex].temprise = temprise
- reactors[activeIndex].maxGenerationRate = maxGenerationRate
- end
- local function drawHeader(title)
- local x = gpu.getResolution()
- gpu.setBackground(color.grey)
- gpu.setForeground(color.white)
- term.clear()
- gpu.setBackground(color.panel)
- gpu.setForeground(color.white)
- term.clearLine()
- printf(" %s", title)
- gpu.setForeground(color.green)
- printf(" | Разработал : GintaRus")
- gpu.setForeground(color.white)
- printf("\n")
- gpu.setBackground(color.grey)
- gpu.setForeground(color.white)
- term.clearLine()
- gpu.setBackground(0xFF0000)
- gpu.set(x - 2, 1, " X ")
- gpu.setBackground(color.grey)
- gpu.setForeground(color.white)
- return x
- end
- local function drawSeparator(x)
- gpu.setBackground(color.grey)
- gpu.setForeground(color.dim)
- gpu.fill(1, 3, x, 1, "-")
- gpu.setBackground(color.grey)
- gpu.setForeground(color.white)
- term.setCursor(1, 4)
- end
- local function makeButton(x, y, text)
- term.setCursor(x, y)
- local fg = gpu.getForeground()
- local bg = gpu.getBackground()
- gpu.setBackground(color.blue)
- gpu.setForeground(color.white)
- printf(text)
- gpu.setBackground(bg)
- gpu.setForeground(fg)
- end
- local function makePowerButton(x, y, text, bg, fg)
- term.setCursor(x, y)
- local rfg = gpu.getForeground()
- local rbg = gpu.getBackground()
- gpu.setBackground(bg)
- gpu.setForeground(fg)
- printf(text)
- gpu.setBackground(rbg)
- gpu.setForeground(rfg)
- end
- local function getGateFlow(gate)
- if not gate then
- return 0
- end
- local ok, value = pcall(gate.getSignalLowFlow)
- if ok and type(value) == "number" then
- return value
- end
- local ok2, value2 = pcall(gate.getFlow)
- if ok2 and type(value2) == "number" then
- return value2
- end
- return 0
- end
- local function isComponentAlive(addr)
- if not addr then
- return false
- end
- return com.get(addr) ~= nil
- end
- local function ensureFlowInit(r, force)
- if not r or (r.flowInit and not force) then
- return
- end
- pcall(r.upgate.setSignalLowFlow, r.upgate, CHARGE_FLOW)
- r.flowInit = true
- flowInitByAdr[r.reactorAdr] = true
- if reactors[activeIndex] and reactors[activeIndex].reactorAdr == r.reactorAdr then
- infcord.flow.value = CHARGE_FLOW
- if handleMain and infcord.flow.x then
- guiWrite(infcord.flow.x, infcord.flow.y, color.red, color.grey, "%s", numformat(infcord.flow.value))
- end
- end
- end
- local function canChargeStatus(status)
- return status == "offline" or status == "stopping" or status == "cold" or status == "cooling" or status == "warming_up"
- end
- local function statusText(status)
- if status == "online" then
- return "ВКЛ"
- elseif status == "offline" then
- return "ВЫК"
- elseif status == "charging" then
- return "ЗАР"
- elseif status == "charged" then
- return "ГОТ"
- elseif status == "stopping" then
- return "СТП"
- elseif status == "cold" then
- return "ХОЛ"
- elseif status == "cooling" then
- return "ОСТ"
- elseif status == "warming_up" then
- return "РАЗ"
- end
- return status
- end
- local function show(fc, bc, param)
- local fg = gpu.getForeground()
- local bg = gpu.getBackground()
- term.setCursor(param.x, param.y)
- gpu.setForeground(fc)
- gpu.setBackground(bc)
- local st = " "
- for i = 0, #tostring(param.value) do
- st = st .. " "
- end
- gpu.set(param.x, param.y, st)
- printf("%d", param.value)
- gpu.setForeground(fg)
- gpu.setBackground(bg)
- end
- local function numformat(n)
- local s = tostring(n)
- if n >= 1000 and n < 1000000 then
- local t = s:sub(1, #s - 3)
- local e = s:sub(#s - 2)
- s = t .. " " .. e .. " "
- return s
- elseif n >= 1000000 then
- local m = s:sub(1, #s - 6)
- local t = s:sub(#s - 5, #s - 3)
- local e = s:sub(#s - 2)
- s = m .. " " .. t .. " " .. e .. " "
- return s
- else
- s = s .. " "
- return s
- end
- end
- local function overviewCols(x)
- local cols
- if x >= 120 then
- cols = {status = 6, temp = 15, fuel = 27, profit = 43, gen = 60, flow = 77}
- else
- cols = {status = 5, temp = 11, fuel = 20, profit = 33, gen = 48, flow = 63}
- end
- local ctrl = cols.flow + 12
- if ctrl < 65 then
- ctrl = 65
- end
- if ctrl + 16 > x then
- ctrl = math.max(65, x - 16)
- end
- cols.ctrl = ctrl
- return cols
- end
- local function coreformat()
- local num = com.draconic_rf_storage.getEnergyStored()
- if num > 10 ^ 12 then
- return string.format(" Накоплено в ядре: %0.3f T \n", num / 10 ^ 12)
- elseif num > 10 ^ 9 then
- return string.format(" Накоплено в ядре: %0.3f B \n", num / 10 ^ 9)
- elseif num > 10 ^ 6 then
- return string.format(" Накоплено в ядре: %0.3f M \n", num / 10 ^ 6)
- elseif num > 10 ^ 3 then
- return string.format(" Накоплено в ядре: %0.3f K \n", num / 10 ^ 3)
- else
- return string.format(" Накоплено в ядре: %d \n", num)
- end
- end
- local function checkButtons()
- local ok, inf = pcall(reactor.getReactorInfo)
- if not ok or type(inf) ~= "table" then
- return
- end
- infcord.status.value = inf.status
- button.start.visible = false
- button.stop.visible = false
- button.charge.visible = false
- if canChargeStatus(infcord.status.value) then
- guiWrite(button.charge.x, button.charge.y, color.skyblue, color.black, "%s", button.charge.name)
- button.charge.visible = true
- elseif infcord.status.value == "charged" then
- guiWrite(button.start.x, button.start.y, color.green, color.black, "%s", button.start.name)
- button.start.visible = true
- guiWrite(button.stop.x, button.stop.y, color.red, color.black, "%s", button.stop.name)
- button.stop.visible = true
- elseif infcord.status.value == "online" or infcord.status.value == "charging" then
- guiWrite(button.stop.x, button.stop.y, color.red, color.black, "%s", button.stop.name)
- button.stop.visible = true
- elseif infcord.status.value == "stopping" then
- if (inf.energySaturation / inf.maxEnergySaturation) * 100 >= 50 and
- (inf.fieldStrength / inf.maxFieldStrength) * 100 >= 50 and
- inf.temperature > 2000 then
- guiWrite(button.start.x, button.start.y, color.green, color.black, "%s", button.start.name)
- button.start.visible = true
- end
- end
- end
- local function screenStart()
- handleMain = false
- handleOptions = false
- handleStart = true
- local x = drawHeader("HiTech Classic is the best (Preparation)")
- if not firstStartCompleted then
- printf("Эта страница для настройки программы при первом запуске или после сбоя")
- end
- drawSeparator(x)
- term.setCursor(1, screenH - 2)
- menuItem.gates.x, menuItem.gates.y = term.getCursor()
- gpu.setForeground(color.blue)
- printf(menuItem.gates.name)
- menuItem.gates.w = textWidth(menuItem.gates.name)
- gpu.setForeground(color.white)
- local hadFile = readReactorsFile() ~= nil
- while true do
- if not ops then
- return
- end
- reactors = buildReactors()
- if reactors and #reactors > 0 then
- setActive(1)
- firstStartCompleted = true
- if not hadFile then
- screenAssign()
- return
- end
- break
- end
- if not hadFile then
- local reactorsList = listAddresses("draconic_reactor")
- local gates = listAddresses("flux_gate")
- if #reactorsList > 0 and #gates >= 2 then
- reactors = reactors or {}
- firstStartCompleted = true
- screenOverview()
- return
- end
- end
- guiClear(2)
- printf("Подключите реакторы и флюкс-гейты (2 гейта на каждый реактор)\n")
- printf("Максимум: %d реакторов. Адреса можно сохранить в %s\n", MAX_REACTORS, reactorsFile)
- os.sleep(1)
- end
- end
- local function screenOptions()
- handleMain = false
- handleStart = false
- handleOptions = true
- handleOverview = false
- handleAssign = false
- canedit = true
- canclose = true
- local x = drawHeader("HiTech Classic is the best (Options)")
- menuItem.save.x, menuItem.save.y = term.getCursor()
- gpu.setForeground(color.blue)
- printf(menuItem.save.name)
- menuItem.save.w = textWidth(menuItem.save.name)
- menuItem.cancel.x, menuItem.cancel.y = term.getCursor()
- printf(menuItem.cancel.name)
- menuItem.cancel.w = textWidth(menuItem.cancel.name)
- menuItem.optionsBack.x, menuItem.optionsBack.y = term.getCursor()
- printf(menuItem.optionsBack.name)
- menuItem.optionsBack.w = textWidth(menuItem.optionsBack.name)
- gpu.setForeground(color.white)
- drawSeparator(x)
- printf(" Интервал для щелчка: ")
- OptionDefault["x"], OptionDefault["y"] = term.getCursor()
- printf("%d\n", OptionDefault.value)
- printf(" Интервал для CTRL: ")
- OptionCtrl["x"], OptionCtrl["y"] = term.getCursor()
- printf("%d\n", OptionCtrl.value)
- printf(" Интервал для SHIFT: ")
- OptionShift["x"], OptionShift["y"] = term.getCursor()
- printf("%d\n", OptionShift.value)
- printf(" Интервал для CTRL+SHIFT: ")
- OptionCtrlShift["x"], OptionCtrlShift["y"] = term.getCursor()
- printf("%d\n", OptionCtrlShift.value)
- printf(" Уровень щитов: ")
- OptionShield["x"], OptionShield["y"] = term.getCursor()
- printf("%d\n", OptionShield.value)
- printf(" Отключение по топливу (%%): ")
- OptionFuelStop["x"], OptionFuelStop["y"] = term.getCursor()
- printf("%d\n", OptionFuelStop.value)
- end
- local function clearPromptLine()
- local _, y = term.getCursor()
- if y > 1 then
- term.setCursor(1, y - 1)
- term.clearLine()
- term.setCursor(1, y - 1)
- end
- end
- local function readIndex(prompt, max, used)
- while true do
- printf("%s", prompt)
- local input = term.read(false, false) or ""
- clearPromptLine()
- local num = tonumber(input:match("%d+"))
- if num and num >= 1 and num <= max and not used[num] then
- return num
- end
- printf("Неверный выбор, попробуйте снова.\n")
- end
- end
- local function readIndexAllowZero(prompt, max)
- while true do
- printf("%s", prompt)
- local input = term.read(false, false) or ""
- clearPromptLine()
- local lower = input:lower()
- if lower:find("назад") or lower:find("back") or lower:match("^b%s*$") then
- return -1
- end
- local num = tonumber(input:match("%d+"))
- if num and num >= 0 and num <= max then
- return num
- end
- printf("Неверный выбор, попробуйте снова.\n")
- end
- end
- local saveAssignedGates
- local function getChatBox()
- if chatBox then
- return chatBox
- end
- if com.isAvailable("chat_box") then
- chatBox = com.chat_box
- end
- return chatBox
- end
- local function chatSay(message, color_code)
- local box = getChatBox()
- if not box or not message then
- return false
- end
- if box.say and pcall(function()
- box.say(message)
- end) then
- return true
- end
- if box.sendMessage and pcall(function()
- box.sendMessage(message)
- end) then
- return true
- end
- if box.sendMessage and pcall(function()
- box.sendMessage(message, color_code or 64)
- end) then
- return true
- end
- return false
- end
- local function maybeChatSay(step, message, color_code)
- if step and easyAssign.lastChatStep ~= step then
- easyAssign.lastChatStep = step
- easyAssign.lastChatMessage = nil
- end
- if message and easyAssign.lastChatMessage ~= message then
- easyAssign.lastChatMessage = message
- chatSay(message, color_code)
- end
- end
- local function snapshotComponents(typeName)
- local list = {}
- for adr in com.list(typeName) do
- list[#list + 1] = adr
- end
- return list
- end
- local function initEasyKnown()
- easyAssign.known = {draconic_reactor = {}, flux_gate = {}}
- for _, addr in ipairs(snapshotComponents("draconic_reactor")) do
- easyAssign.known.draconic_reactor[addr] = true
- end
- for _, addr in ipairs(snapshotComponents("flux_gate")) do
- easyAssign.known.flux_gate[addr] = true
- end
- end
- local function findNewComponent(typeName)
- if not easyAssign.known or not easyAssign.known[typeName] then
- initEasyKnown()
- end
- for addr in com.list(typeName) do
- if not easyAssign.known[typeName][addr] then
- easyAssign.known[typeName][addr] = true
- return addr
- end
- end
- return nil
- end
- local function isAddressUsed(addr)
- if not addr then
- return false
- end
- local entries = readReactorsFile() or {}
- for i = 1, #entries do
- if entries[i].reactorAdr == addr or entries[i].upAdr == addr or entries[i].downAdr == addr then
- return true
- end
- end
- return false
- end
- local function clearAssignedByAdr(reactorAdr)
- if not reactorAdr then
- return false
- end
- local entries = readReactorsFile() or {}
- local newEntries = {}
- local removed = false
- for i = 1, #entries do
- if entries[i].reactorAdr ~= reactorAdr then
- newEntries[#newEntries + 1] = entries[i]
- else
- removed = true
- end
- end
- if removed then
- writeReactorsFile(newEntries)
- end
- return removed
- end
- local function startEasyAssign()
- local entries = readReactorsFile() or {}
- if #entries >= MAX_REACTORS then
- easyAssign.active = false
- easyAssign.message = "Достигнут лимит реакторов."
- return
- end
- if not getChatBox() then
- easyAssign.active = false
- easyAssign.message = "Ошибка: для работы нужен chat_box."
- return
- end
- easyAssign.active = true
- easyAssign.step = "reactor"
- easyAssign.core = nil
- easyAssign.shield = nil
- easyAssign.output = nil
- easyAssign.saved = false
- easyAssign.message = nil
- easyAssign.index = #entries + 1
- easyAssign.lastChatStep = nil
- easyAssign.lastChatMessage = nil
- initEasyKnown()
- maybeChatSay("intro", "Легкий режим: подключите адаптер к реактору #" .. tostring(easyAssign.index) .. " и смотрите монитор.")
- end
- local function screenAssignChoice()
- handleMain = false
- handleStart = false
- handleOptions = false
- handleOverview = false
- handleAssign = true
- local x = drawHeader("HiTech Classic is the best (Гейты)")
- drawSeparator(x)
- assignUi.reactors = {}
- assignUi.gates = {}
- assignUi.gateAddrs = {}
- assignUi.reactorAddrs = {}
- assignUi.gateUse = {}
- assignUi.selectedAdr = nil
- gpu.setBackground(color.grey)
- gpu.setForeground(color.white)
- gpu.fill(1, 4, x, 21, " ")
- term.setCursor(1, 2)
- menuItem.back.x, menuItem.back.y = term.getCursor()
- assignUi.back.x, assignUi.back.y, assignUi.back.w = menuItem.back.x, menuItem.back.y, textWidth(menuItem.back.name)
- gpu.setForeground(color.blue)
- printf(menuItem.back.name)
- menuItem.back.w = textWidth(menuItem.back.name)
- gpu.setForeground(color.white)
- term.setCursor(2, 5)
- printf("Выберите способ добавления гейтов:")
- local heavyLabel = " Тяжелый способ (анализатор) "
- local easyLabel = " Легкий способ (подключение) "
- local heavyX, heavyY = 2, 7
- local easyX, easyY = 2, 9
- easyAssign.heavyBtn = {x = heavyX, y = heavyY, w = textWidth(heavyLabel)}
- easyAssign.easyBtn = {x = easyX, y = easyY, w = textWidth(easyLabel)}
- guiWrite(heavyX, heavyY, color.white, color.red, "%s", heavyLabel)
- guiWrite(easyX, easyY, color.white, color.green, "%s", easyLabel)
- if easyAssign.message then
- guiWrite(2, 12, color.yellow, -1, "%s", easyAssign.message)
- end
- end
- local function screenAssignEasy()
- handleMain = false
- handleStart = false
- handleOptions = false
- handleOverview = false
- handleAssign = true
- local x = drawHeader("HiTech Classic is the best (Гейты - Легкий)")
- drawSeparator(x)
- gpu.setBackground(color.grey)
- gpu.setForeground(color.white)
- gpu.fill(1, 4, x, 21, " ")
- term.setCursor(1, 2)
- menuItem.back.x, menuItem.back.y = term.getCursor()
- easyAssign.backBtn = {x = menuItem.back.x, y = menuItem.back.y, w = textWidth(menuItem.back.name)}
- gpu.setForeground(color.blue)
- printf(menuItem.back.name)
- menuItem.back.w = textWidth(menuItem.back.name)
- gpu.setForeground(color.white)
- term.setCursor(2, 5)
- printf("РЕАКТОР #%d", easyAssign.index or 1)
- term.setCursor(2, 7)
- if easyAssign.step == "reactor" then
- guiWrite(2, 7, color.green, -1, "Подключите адаптер к ядру реактора.")
- maybeChatSay("reactor", "Подключите адаптер к ядру реактора.", 255)
- elseif easyAssign.step == "shield" then
- guiWrite(2, 7, color.green, -1, "Подключите адаптер к гейту ЩИТОВ.")
- maybeChatSay("shield", "Подключите адаптер к гейту ЩИТОВ.", 4096)
- elseif easyAssign.step == "output" then
- guiWrite(2, 7, color.green, -1, "Подключите адаптер к гейту ВЫВОДА.")
- maybeChatSay("output", "Подключите адаптер к гейту ВЫВОДА.", 16711680)
- elseif easyAssign.step == "done" then
- guiWrite(2, 7, color.green, -1, "Реактор добавлен.")
- maybeChatSay("done", "Реактор добавлен. Смотрите монитор.", 65280)
- end
- term.setCursor(2, 9)
- printf("Ожидаю компонент...")
- local infoY = 11
- local coreLine = "Ядро: " .. (easyAssign.core or "-")
- local shieldLine = "Щиты: " .. (easyAssign.shield or "-")
- local outputLine = "Вывод: " .. (easyAssign.output or "-")
- local coreColor = (easyAssign.step == "reactor") and color.blue or (easyAssign.core and color.green or color.white)
- local shieldColor = (easyAssign.step == "shield") and color.blue or (easyAssign.shield and color.green or color.white)
- local outputColor = (easyAssign.step == "output") and color.blue or (easyAssign.output and color.green or color.white)
- guiWrite(2, infoY, coreColor, -1, "%s", coreLine)
- guiWrite(2, infoY + 1, shieldColor, -1, "%s", shieldLine)
- guiWrite(2, infoY + 2, outputColor, -1, "%s", outputLine)
- if easyAssign.message then
- guiWrite(2, infoY + 4, color.yellow, -1, "%s", easyAssign.message)
- end
- if easyAssign.step == "done" then
- local contLabel = " [Продолжить] "
- local finLabel = " [Завершить] "
- local contX, contY = 2, infoY + 6
- local finX, finY = 2 + textWidth(contLabel) + 2, infoY + 6
- easyAssign.continueBtn = {x = contX, y = contY, w = textWidth(contLabel)}
- easyAssign.finishBtn = {x = finX, y = finY, w = textWidth(finLabel)}
- guiWrite(contX, contY, color.white, color.green, "%s", contLabel)
- guiWrite(finX, finY, color.white, color.red, "%s", finLabel)
- end
- end
- local function screenAssignManual()
- handleMain = false
- handleStart = false
- handleOptions = false
- handleOverview = false
- handleAssign = true
- local x = drawHeader("HiTech Classic is the best (Гейты)")
- drawSeparator(x)
- assignUi.reactors = {}
- assignUi.gates = {}
- assignUi.gateAddrs = {}
- assignUi.reactorAddrs = {}
- assignUi.gateUse = {}
- assignUi.selectedAdr = nil
- gpu.setBackground(color.grey)
- gpu.setForeground(color.white)
- gpu.fill(1, 4, x, 21, " ")
- term.setCursor(1, 2)
- menuItem.back.x, menuItem.back.y = term.getCursor()
- assignUi.back.x, assignUi.back.y, assignUi.back.w = menuItem.back.x, menuItem.back.y, textWidth(menuItem.back.name)
- gpu.setForeground(color.blue)
- printf(menuItem.back.name)
- menuItem.back.w = textWidth(menuItem.back.name)
- gpu.setForeground(color.white)
- term.setCursor(2, 4)
- printf("Выберите реактор")
- local reactorsList = listAddresses("draconic_reactor")
- local gates = listAddresses("flux_gate")
- assignUi.gateAddrs = gates
- assignUi.reactorAddrs = reactorsList
- if #reactorsList == 0 or #gates < 2 then
- printf("Недостаточно реакторов или флюкс-гейтов.\n")
- os.sleep(1)
- screenOverview()
- return
- end
- local count = math.min(#reactorsList, MAX_REACTORS)
- term.setCursor(2, 5)
- printf("Реакторы:")
- local rowY = 6
- for i = 1, count do
- term.setCursor(2, rowY)
- local label = string.format("%d) %s", i, reactorsList[i])
- if assignState.reactorIndex == i then
- guiWrite(2, rowY, color.black, color.blue, "%s", label)
- else
- guiWrite(2, rowY, color.white, -1, "%s", label)
- end
- assignUi.reactors[i] = {x = 2, y = rowY, w = textWidth(label)}
- rowY = rowY + 1
- end
- local entries = readReactorsFile() or {}
- local gateUse = {}
- for i = 1, #entries do
- gateUse[entries[i].upAdr] = entries[i].reactorAdr
- gateUse[entries[i].downAdr] = entries[i].reactorAdr
- end
- assignUi.gateUse = gateUse
- local selectedAdr = assignState.reactorIndex and reactorsList[assignState.reactorIndex] or nil
- assignUi.selectedAdr = selectedAdr
- local selectedEntry = nil
- if selectedAdr then
- for i = 1, #entries do
- if entries[i].reactorAdr == selectedAdr then
- selectedEntry = entries[i]
- break
- end
- end
- end
- assignUi.selectedEntry = selectedEntry
- term.setCursor(40, 5)
- printf("Гейты:")
- local gateY = 6
- for i = 1, #gates do
- if gateY > 24 then
- break
- end
- term.setCursor(40, gateY)
- local label = string.format("%d) %s", i, gates[i])
- local colorGate = color.dim
- if selectedAdr then
- if selectedEntry and (gates[i] == selectedEntry.upAdr or gates[i] == selectedEntry.downAdr) then
- colorGate = color.green
- elseif assignState.shieldGateIdx == i or assignState.outGateIdx == i then
- colorGate = color.green
- elseif gateUse[gates[i]] and gateUse[gates[i]] ~= selectedAdr then
- colorGate = color.red
- else
- colorGate = color.dim
- end
- end
- guiWrite(40, gateY, colorGate, -1, "%s", label)
- assignUi.gates[i] = {x = 40, y = gateY, w = textWidth(label)}
- gateY = gateY + 1
- end
- end
- local function screenAssign()
- if assignMode == "manual" then
- screenAssignManual()
- elseif assignMode == "easy" then
- screenAssignEasy()
- else
- screenAssignChoice()
- end
- end
- local function acceptEasyComponent(address, componentType)
- if easyAssign.step == "reactor" then
- if componentType ~= "draconic_reactor" then
- easyAssign.message = "Нужен draconic_reactor."
- screenAssignEasy()
- return
- end
- if isAddressUsed(address) then
- easyAssign.message = "Адрес уже используется."
- screenAssignEasy()
- return
- end
- easyAssign.core = address
- easyAssign.step = "shield"
- easyAssign.message = "Реактор принят."
- maybeChatSay("accepted", "Реактор принят. Смотри монитор.")
- screenAssignEasy()
- return
- end
- if easyAssign.step == "shield" then
- if componentType ~= "flux_gate" then
- easyAssign.message = "Нужен flux_gate."
- screenAssignEasy()
- return
- end
- if isAddressUsed(address) then
- easyAssign.message = "Адрес уже используется."
- screenAssignEasy()
- return
- end
- easyAssign.shield = address
- easyAssign.step = "output"
- easyAssign.message = "Гейт щитов принят."
- maybeChatSay("accepted", "Гейт щитов принят. Смотри монитор.")
- screenAssignEasy()
- return
- end
- if easyAssign.step == "output" then
- if componentType ~= "flux_gate" then
- easyAssign.message = "Нужен flux_gate."
- screenAssignEasy()
- return
- end
- if isAddressUsed(address) or address == easyAssign.shield then
- easyAssign.message = "Нужны два разных гейта."
- screenAssignEasy()
- return
- end
- easyAssign.output = address
- local saved = saveAssignedGates(easyAssign.core, easyAssign.shield, easyAssign.output)
- if not saved then
- easyAssign.message = "Не удалось сохранить."
- screenAssignEasy()
- return
- end
- easyAssign.saved = true
- easyAssign.step = "done"
- easyAssign.message = "Успешно сохранено."
- maybeChatSay("accepted", "Успешно сохранено. Смотри монитор.")
- screenAssignEasy()
- return
- end
- end
- local function handleComponentAdded(_, address, componentType)
- if not handleAssign or assignMode ~= "easy" or not easyAssign.active then
- return
- end
- acceptEasyComponent(address, componentType)
- end
- local function pollEasyAssign()
- if not handleAssign or assignMode ~= "easy" or not easyAssign.active then
- return
- end
- if easyAssign.step == "reactor" then
- local addr = findNewComponent("draconic_reactor")
- if addr then
- acceptEasyComponent(addr, "draconic_reactor")
- end
- elseif easyAssign.step == "shield" or easyAssign.step == "output" then
- local addr = findNewComponent("flux_gate")
- if addr then
- acceptEasyComponent(addr, "flux_gate")
- end
- end
- end
- local function refreshReactors(openAssign)
- autostateByAdr = {}
- flowInitByAdr = {}
- autoWaitTempByAdr = {}
- chargeRequestByAdr = {}
- for i = 1, #reactors do
- local r = reactors[i]
- autostateByAdr[r.reactorAdr] = r.autostate
- flowInitByAdr[r.reactorAdr] = r.flowInit
- chargeRequestByAdr[r.reactorAdr] = r.chargeRequested
- end
- syncActive()
- local prevAdr = reactors[activeIndex] and reactors[activeIndex].reactorAdr
- reactors = buildReactors() or reactors
- local idx = 1
- if pendingActiveReactorAdr then
- for i = 1, #reactors do
- if reactors[i].reactorAdr == pendingActiveReactorAdr then
- idx = i
- break
- end
- end
- pendingActiveReactorAdr = nil
- elseif lastAddedReactorAdr then
- for i = 1, #reactors do
- if reactors[i].reactorAdr == lastAddedReactorAdr then
- idx = i
- break
- end
- end
- lastAddedReactorAdr = nil
- elseif prevAdr then
- for i = 1, #reactors do
- if reactors[i].reactorAdr == prevAdr then
- idx = i
- break
- end
- end
- end
- setActive(idx)
- if openAssign and newEntriesAdded then
- resetAssignState()
- screenAssign()
- return
- end
- if handleMain then
- screenMain()
- else
- screenOverview()
- end
- end
- local function resetAssignState()
- assignState.reactorIndex = nil
- assignState.reactorAdr = nil
- assignState.shieldGateIdx = nil
- assignState.shieldGateAdr = nil
- assignState.outGateIdx = nil
- assignState.outGateAdr = nil
- assignState.step = "reactor"
- end
- saveAssignedGates = function(reactorAdr, shieldAdr, outAdr)
- if not reactorAdr or not shieldAdr or not outAdr then
- return false
- end
- local entries = readReactorsFile() or {}
- local updated = false
- for i = 1, #entries do
- if entries[i].reactorAdr == reactorAdr then
- entries[i].upAdr = outAdr
- entries[i].downAdr = shieldAdr
- updated = true
- break
- end
- end
- if not updated then
- entries[#entries + 1] = {
- reactorAdr = reactorAdr,
- upAdr = outAdr,
- downAdr = shieldAdr
- }
- end
- if #entries > MAX_REACTORS then
- local trimmed = {}
- for i = 1, MAX_REACTORS do
- trimmed[i] = entries[i]
- end
- entries = trimmed
- end
- writeReactorsFile(entries)
- pendingActiveReactorAdr = reactorAdr
- return true
- end
- local function clearAssignedGates(reactorIndex)
- local reactorsList = listAddresses("draconic_reactor")
- if not reactorsList[reactorIndex] then
- return false
- end
- local entries = readReactorsFile() or {}
- local newEntries = {}
- for i = 1, #entries do
- if entries[i].reactorAdr ~= reactorsList[reactorIndex] then
- newEntries[#newEntries + 1] = entries[i]
- end
- end
- writeReactorsFile(newEntries)
- return true
- end
- screenOverview = function()
- handleMain = false
- handleStart = false
- handleOptions = false
- handleOverview = true
- handleAssign = false
- local x = drawHeader("HiTech Classic is the best")
- reactors = reactors or {}
- local cols = overviewCols(x)
- term.setCursor(1, 2)
- menuItem.options.x, menuItem.options.y = term.getCursor()
- gpu.setForeground(color.blue)
- printf(menuItem.options.name)
- menuItem.options.w = textWidth(menuItem.options.name)
- gpu.setForeground(color.white)
- menuItem.overview.x, menuItem.overview.y = term.getCursor()
- gpu.setForeground(color.blue)
- printf(menuItem.overview.name)
- menuItem.overview.w = textWidth(menuItem.overview.name)
- gpu.setForeground(color.white)
- menuItem.refresh.x, menuItem.refresh.y = term.getCursor()
- gpu.setForeground(color.blue)
- printf(menuItem.refresh.name)
- menuItem.refresh.w = textWidth(menuItem.refresh.name)
- gpu.setForeground(color.white)
- menuItem.gates.x, menuItem.gates.y = term.getCursor()
- gpu.setForeground(color.blue)
- printf(menuItem.gates.name)
- menuItem.gates.w = textWidth(menuItem.gates.name)
- gpu.setForeground(color.white)
- for i = 1, #reactors do
- local label = string.format("[R%d]", i)
- reactors[i].tab.x, reactors[i].tab.y = term.getCursor()
- reactors[i].tab.w = textWidth(label)
- if i == activeIndex then
- guiWrite(reactors[i].tab.x, reactors[i].tab.y, color.black, color.orange, "%s", label)
- else
- guiWrite(reactors[i].tab.x, reactors[i].tab.y, color.blue, color.white, "%s", label)
- end
- printf(" ")
- end
- drawSeparator(x)
- gpu.setBackground(color.grey)
- gpu.setForeground(color.white)
- gpu.fill(1, 4, x, 21, " ")
- if #reactors == 0 then
- term.setCursor(2, 5)
- printf("Нет настроенных реакторов.")
- term.setCursor(2, 6)
- printf("Откройте \"Гейты\" и назначьте гейты.")
- return
- end
- gpu.setBackground(color.panel)
- gpu.setForeground(color.white)
- gpu.fill(2, 4, x - 2, 6, " ")
- term.setCursor(3, 4)
- printf("Сводка")
- term.setCursor(3, 5)
- printf("Суммарная прибыль:")
- term.setCursor(28, 5)
- getCord(summaryProfitCord)
- term.setCursor(3, 6)
- printf("Суммарная EU:")
- term.setCursor(28, 6)
- getCord(summaryEuCord)
- term.setCursor(3, 7)
- printf("Тратим на щиты RF:")
- term.setCursor(28, 7)
- getCord(summaryShieldCord)
- term.setCursor(3, 8)
- printf("Суммарная выработка:")
- term.setCursor(28, 8)
- getCord(summaryGenCord)
- term.setCursor(3, 9)
- printf("Максимум прибыли RF/EU:")
- term.setCursor(28, 9)
- getCord(summaryMaxProfitCord)
- local autoX = math.max(40, x - 33)
- term.setCursor(autoX, 4)
- printf("Выключены автоматически:")
- term.setCursor(autoX, 5)
- getCord(autoStoppedCord)
- gpu.setBackground(color.dark)
- gpu.setForeground(color.white)
- gpu.fill(2, 11, x - 2, 1, " ")
- term.setCursor(2, 11)
- printf("#")
- term.setCursor(cols.status, 11)
- printf("СТАТУС")
- term.setCursor(cols.temp, 11)
- printf(" ТЕМП")
- term.setCursor(cols.fuel, 11)
- printf("ТОПЛИВО")
- term.setCursor(cols.profit, 11)
- printf("ПРИБЫЛЬ")
- term.setCursor(cols.gen, 11)
- printf("ГЕН")
- term.setCursor(cols.flow, 11)
- printf("ПОТОК")
- term.setCursor(cols.ctrl, 11)
- printf("УПР")
- gpu.setForeground(color.dim)
- gpu.fill(2, 12, x - 2, 1, "-")
- gpu.setForeground(color.white)
- gpu.setBackground(color.grey)
- local rowY = 13
- for i = 1, #reactors do
- local r = reactors[i]
- term.setCursor(2, rowY)
- printf("#%d", i)
- term.setCursor(cols.status, rowY)
- r.row.status = {x = cols.status, y = rowY}
- term.setCursor(cols.temp, rowY)
- r.row.temp = {x = cols.temp, y = rowY}
- term.setCursor(cols.fuel, rowY)
- r.row.fuel = {x = cols.fuel, y = rowY}
- term.setCursor(cols.profit, rowY)
- r.row.profit = {x = cols.profit, y = rowY}
- term.setCursor(cols.gen, rowY)
- r.row.gen = {x = cols.gen, y = rowY}
- term.setCursor(cols.flow, rowY)
- r.row.flow = {x = cols.flow, y = rowY}
- term.setCursor(cols.ctrl, rowY)
- r.control = r.control or {}
- r.control.dec = {x = cols.ctrl, y = rowY, w = 3}
- term.setCursor(cols.ctrl + 4, rowY)
- r.control.inc = {x = cols.ctrl + 4, y = rowY, w = 3}
- term.setCursor(cols.ctrl + 8, rowY)
- r.control.auto = {x = cols.ctrl + 8, y = rowY, w = 4}
- term.setCursor(cols.ctrl + 13, rowY)
- r.powerBtn.x, r.powerBtn.y = term.getCursor()
- r.powerBtn.w = 3
- rowY = rowY + 1
- end
- end
- local function screenMain()
- handleOptions = false
- handleStart = false
- handleMain = true
- handleOverview = false
- handleAssign = false
- if not reactor or not upgate or not downgate then
- screenOverview()
- return
- end
- if reactors[activeIndex] and (not isComponentAlive(reactors[activeIndex].reactorAdr) or
- not isComponentAlive(reactors[activeIndex].upAdr) or
- not isComponentAlive(reactors[activeIndex].downAdr)) then
- refreshReactors(false)
- screenOverview()
- return
- end
- local x = drawHeader("HiTech Classic is the best")
- local ok, inf = pcall(reactor.getReactorInfo)
- if not ok or type(inf) ~= "table" then
- refreshReactors(false)
- screenOverview()
- return
- end
- if reactors[activeIndex] and (not isComponentAlive(reactors[activeIndex].reactorAdr) or
- not isComponentAlive(reactors[activeIndex].upAdr) or
- not isComponentAlive(reactors[activeIndex].downAdr)) then
- refreshReactors(false)
- screenOverview()
- return
- end
- infcord.status.value = inf.status
- menuItem.options.x, menuItem.options.y = term.getCursor()
- gpu.setForeground(color.blue)
- printf(menuItem.options.name)
- menuItem.options.w = textWidth(menuItem.options.name)
- gpu.setForeground(color.white)
- menuItem.overview.x, menuItem.overview.y = term.getCursor()
- gpu.setForeground(color.blue)
- printf(menuItem.overview.name)
- menuItem.overview.w = textWidth(menuItem.overview.name)
- gpu.setForeground(color.white)
- menuItem.refresh.x, menuItem.refresh.y = term.getCursor()
- gpu.setForeground(color.blue)
- printf(menuItem.refresh.name)
- menuItem.refresh.w = textWidth(menuItem.refresh.name)
- gpu.setForeground(color.white)
- menuItem.gates.x, menuItem.gates.y = term.getCursor()
- gpu.setForeground(color.blue)
- printf(menuItem.gates.name)
- menuItem.gates.w = textWidth(menuItem.gates.name)
- gpu.setForeground(color.white)
- for i = 1, #reactors do
- local label = string.format("[R%d]", i)
- reactors[i].tab.x, reactors[i].tab.y = term.getCursor()
- reactors[i].tab.w = textWidth(label)
- if i == activeIndex then
- guiWrite(reactors[i].tab.x, reactors[i].tab.y, color.black, color.orange, "%s", label)
- else
- guiWrite(reactors[i].tab.x, reactors[i].tab.y, color.blue, color.white, "%s", label)
- end
- printf(" ")
- end
- guiWrite(x - 25, 1, color.yellow, color.panel, "Макс. выраб.: ")
- getCord(infcord.maxgen)
- if inf.generationRate > maxGenerationRate then
- maxGenerationRate = inf.generationRate
- end
- guiWrite(infcord.maxgen.x, infcord.maxgen.y, color.green, color.panel, "%s", numformat(maxGenerationRate))
- drawSeparator(x)
- gpu.setBackground(color.panel)
- gpu.setForeground(color.blue)
- printf(" ПАРАМЕТРЫ ")
- term.setCursor(30, 4)
- printf(" УПРАВЛЕНИЕ ")
- gpu.setBackground(color.grey)
- gpu.setForeground(color.white)
- term.setCursor(1, 6)
- gpu.setBackground(color.panel)
- printf(" Температура: ")
- gpu.setBackground(color.grey)
- printf(" ")
- getCord(infcord.temp)
- guiWrite(infcord.temp.x, infcord.temp.y, -1, -1, "%0.2f\n", inf.temperature)
- printf(" Вырабатывает: ")
- getCord(infcord.generation)
- guiWrite(infcord.generation.x, infcord.generation.y, -1, -1, "%s \n", numformat(inf.generationRate))
- gpu.setBackground(color.panel)
- printf(" Поток: ")
- gpu.setBackground(color.grey)
- printf(" ")
- getCord(infcord.flow)
- infcord.flow.value = getGateFlow(upgate)
- guiWrite(infcord.flow.x, infcord.flow.y, -1, -1, "%s ", numformat(infcord.flow.value))
- getCord(button.add)
- makeButton(button.add.x + 4, button.add.y, button.add.name)
- getCord(button.sub)
- makeButton(button.sub.x + 2, button.sub.y, button.sub.name)
- printf("\n")
- printf(" Итоговая мосч: ")
- getCord(infcord.puregen)
- guiWrite(infcord.puregen.x, infcord.puregen.y, -1, -1, "%s \n", numformat(inf.generationRate - getGateFlow(downgate)))
- gpu.setBackground(color.panel)
- printf(" Поглощает: ")
- gpu.setBackground(color.grey)
- printf(" ")
- getCord(infcord.drain)
- guiWrite(infcord.drain.x, infcord.drain.y, -1, -1, "%s \n", numformat(getGateFlow(downgate)))
- printf(" Мощность поля: ")
- getCord(infcord.fstrth)
- if inf.maxFieldStrength > 0 then
- guiWrite(infcord.fstrth.x, infcord.fstrth.y, -1, -1, "%d / %d (%0.2f %%) \n",
- inf.fieldStrength - inf.fieldDrainRate,
- inf.maxFieldStrength,
- ((inf.fieldStrength - inf.fieldDrainRate) / inf.maxFieldStrength) * 100)
- else
- guiWrite(infcord.fstrth.x, infcord.fstrth.y, -1, -1, "0 / 0 (0 %%) \n")
- end
- gpu.setBackground(color.panel)
- printf(" Насыщенность: ")
- gpu.setBackground(color.grey)
- printf(" ")
- getCord(infcord.esturn)
- if inf.maxEnergySaturation > 0 then
- guiWrite(infcord.esturn.x, infcord.esturn.y, -1, -1, "%d / %d (%0.2f %%) \n",
- inf.energySaturation,
- inf.maxEnergySaturation,
- (inf.energySaturation / inf.maxEnergySaturation) * 100)
- else
- guiWrite(infcord.esturn.x, infcord.esturn.y, -1, -1, "0 / 0 (0 %%) \n")
- end
- printf(" Топливо: ")
- getCord(infcord.fuel)
- if inf.fuelConversion / inf.maxFuelConversion < 0.78 then
- guiWrite(infcord.fuel.x, infcord.fuel.y, -1, -1, "%d / %d (%0.2f %%) \n",
- inf.fuelConversion,
- inf.maxFuelConversion,
- (inf.fuelConversion / inf.maxFuelConversion) * 100)
- else
- if inf.maxFuelConversion > 0 then
- if inf.status == "online" or inf.status == "charging" or inf.status == "charged" then
- guiWrite(infcord.fuel.x, infcord.fuel.y, color.red, -1, "%d / %d (%0.2f %%) Критический уровень топлива\n",
- inf.fuelConversion,
- inf.maxFuelConversion,
- (inf.fuelConversion / inf.maxFuelConversion) * 100)
- else
- guiWrite(infcord.fuel.x, infcord.fuel.y, -1, -1, "%d / %d (%0.2f %%) Критический уровень топлива\n",
- inf.fuelConversion,
- inf.maxFuelConversion,
- (inf.fuelConversion / inf.maxFuelConversion) * 100)
- end
- else
- guiWrite(infcord.fuel.x, infcord.fuel.y, -1, -1, "0 / 0 (0 %%) \n")
- end
- end
- gpu.setBackground(color.panel)
- printf(" Расход топлива: ")
- gpu.setBackground(color.grey)
- printf(" ")
- getCord(infcord.fuelconv)
- guiWrite(infcord.fuelconv.x, infcord.fuelconv.y, -1, -1, "%d\n", inf.fuelConversionRate)
- getCord(infcord.core)
- if com.isAvailable("draconic_rf_storage") then
- guiWrite(infcord.core.x, infcord.core.y, -1, -1, coreformat())
- end
- printf("\n")
- button.stop.x, button.stop.y = term.getCursor()
- button.start.x, button.start.y = button.stop.x, button.stop.y + 1
- button.charge.x, button.charge.y = button.stop.x, button.stop.y + 2
- button.stop.w = textWidth(button.stop.name)
- button.start.w = textWidth(button.start.name)
- button.charge.w = textWidth(button.charge.name)
- local controlsY = button.stop.y + 3
- if not chargeHintDismissed then
- local hint1 = "Перед первым запуском поставь поток на 535 000."
- local hint2 = "Потом включай."
- chargeHint.x = 1
- chargeHint.y = math.max(1, screenH - 1)
- local hintY2 = math.min(screenH, chargeHint.y + 1)
- local prevFg = gpu.getForeground()
- local prevBg = gpu.getBackground()
- gpu.setForeground(color.green)
- gpu.setBackground(color.grey)
- gpu.set(chargeHint.x, chargeHint.y, hint1)
- if hintY2 ~= chargeHint.y then
- gpu.set(chargeHint.x, hintY2, hint2)
- end
- gpu.setForeground(prevFg)
- gpu.setBackground(prevBg)
- chargeHint.w = math.max(textWidth(hint1), textWidth(hint2))
- chargeHint.visible = true
- else
- chargeHint.visible = false
- end
- term.setCursor(button.stop.x, controlsY)
- printf(" Автономный режим: ")
- getCord(button.autoon)
- getCord(button.autooff)
- if not autostate then
- guiWrite(button.autooff.x, button.autooff.y, color.red, color.black, "%s\n", button.autooff.name)
- else
- guiWrite(button.autoon.x, button.autoon.y, color.green, color.black, "%s\n", button.autoon.name)
- end
- checkButtons()
- end
- local function refreshOverview()
- if not handleOverview then
- return
- end
- if not reactors or #reactors == 0 then
- return
- end
- gpu.setForeground(color.white)
- local stopPct = cfg.fuelStopPct or 98
- local totalGen = 0
- local totalProfit = 0
- local totalShield = 0
- local maxProfit = 0
- gpu.setBackground(color.grey)
- for i = 1, #reactors do
- local r = reactors[i]
- local ok, inf = pcall(r.reactor.getReactorInfo)
- if not ok or type(inf) ~= "table" then
- guiWrite(r.row.status.x, r.row.status.y, color.red, -1, "ERR")
- guiWrite(r.row.temp.x, r.row.temp.y, color.red, -1, "----")
- guiWrite(r.row.fuel.x, r.row.fuel.y, color.red, -1, "----")
- guiWrite(r.row.profit.x, r.row.profit.y, color.red, -1, "----")
- guiWrite(r.row.gen.x, r.row.gen.y, color.red, -1, "----")
- guiWrite(r.row.flow.x, r.row.flow.y, color.red, -1, "----")
- else
- totalGen = totalGen + inf.generationRate
- guiWrite(r.row.gen.x, r.row.gen.y, -1, -1, "%s", numformat(inf.generationRate))
- local flow = getGateFlow(r.upgate)
- guiWrite(r.row.flow.x, r.row.flow.y, -1, -1, "%s", numformat(flow))
- local shieldFlow = getGateFlow(r.downgate)
- totalShield = totalShield + shieldFlow
- local profit = inf.generationRate - shieldFlow
- totalProfit = totalProfit + profit
- if profit > maxProfit then
- maxProfit = profit
- end
- guiWrite(r.row.profit.x, r.row.profit.y, -1, -1, "%s", numformat(profit))
- local tempColor = color.white
- if inf.temperature >= cfg.tempCriticalEdge then
- tempColor = color.red
- elseif inf.temperature >= cfg.safeModeTempWaitEdge then
- tempColor = color.yellow
- end
- guiWrite(r.row.temp.x, r.row.temp.y, tempColor, -1, "%4.0fC", inf.temperature)
- local fuelPct = 0
- if inf.maxFuelConversion > 0 then
- fuelPct = (inf.fuelConversion / inf.maxFuelConversion) * 100
- end
- if autoStopped[r.reactorAdr] and (inf.status == "online" or inf.status == "charging" or inf.status == "charged") then
- autoStopped[r.reactorAdr] = nil
- end
- if fuelPct >= stopPct and (inf.status == "online" or inf.status == "charging" or inf.status == "charged") then
- if not autoStopped[r.reactorAdr] then
- r.reactor.stopReactor()
- autoStopped[r.reactorAdr] = true
- end
- end
- local fuelColor = color.white
- if fuelPct >= 80 then
- fuelColor = color.red
- end
- guiWrite(r.row.fuel.x, r.row.fuel.y, fuelColor, -1, "%5.1f%%", fuelPct)
- local stColor = color.white
- if inf.status == "online" or inf.status == "charging" or inf.status == "charged" then
- stColor = color.green
- elseif inf.status == "offline" or inf.status == "stopping" then
- stColor = color.red
- end
- guiWrite(r.row.status.x, r.row.status.y, stColor, -1, "%s", statusText(inf.status))
- makePowerButton(r.control.dec.x, r.control.dec.y, "[-]", color.dim, color.white)
- makePowerButton(r.control.inc.x, r.control.inc.y, "[+]", color.dim, color.white)
- local autoColor = r.autostate and color.green or color.red
- makePowerButton(r.control.auto.x, r.control.auto.y, "AUTO", autoColor, color.white)
- if inf.status == "online" or inf.status == "charging" or inf.status == "charged" then
- r.powerBtn.action = "stop"
- makePowerButton(r.powerBtn.x, r.powerBtn.y, "PWR", color.red, color.white)
- else
- r.powerBtn.action = "start"
- makePowerButton(r.powerBtn.x, r.powerBtn.y, "PWR", color.green, color.white)
- end
- end
- end
- if totalProfit > maxSummaryProfit then
- maxSummaryProfit = totalProfit
- end
- guiWrite(summaryProfitCord.x, summaryProfitCord.y, color.white, color.panel, "%s", numformat(totalProfit))
- guiWrite(summaryEuCord.x, summaryEuCord.y, color.white, color.panel, "%s", numformat(math.floor(totalProfit / 8)))
- guiWrite(summaryShieldCord.x, summaryShieldCord.y, color.white, color.panel, "%s", numformat(totalShield))
- guiWrite(summaryGenCord.x, summaryGenCord.y, color.white, color.panel, "%s", numformat(totalGen))
- guiWrite(summaryMaxProfitCord.x, summaryMaxProfitCord.y, color.white, color.panel, "%s / %s",
- numformat(maxSummaryProfit),
- numformat(math.floor(maxSummaryProfit / 8)))
- local autoList = {}
- for i = 1, #reactors do
- if autoStopped[reactors[i].reactorAdr] then
- autoList[#autoList + 1] = "R" .. i
- end
- end
- local autoText = "нет"
- if #autoList > 0 then
- autoText = table.concat(autoList, ", ")
- end
- guiWrite(autoStoppedCord.x, autoStoppedCord.y, color.red, -1, "%s", autoText)
- end
- local screen = {}
- screen["overview"] = screenOverview
- screen["detail"] = screenMain
- screen["options"] = screenOptions
- local function editOption(param)
- local rd = true
- while rd do
- gpu.fill(param.x, param.y, #tostring(param.value), 1, " ")
- term.setCursor(param.x, param.y)
- param.value = term.read(false, false)
- local val = tonumber(param.value)
- if val then
- param.value = val
- show(color.black, color.grey, param)
- rd = false
- end
- end
- canedit = true
- canclose = true
- screen.options()
- end
- local function add(n, i)
- n.value = n.value + i
- upgate.setSignalLowFlow(n.value)
- return n.value
- end
- local function sub(n, i)
- term.setCursor(n.x, n.y)
- n.value = n.value - i
- return n.value
- end
- local function refreshInfo()
- local ok, inf = pcall(reactor.getReactorInfo)
- if not ok or type(inf) ~= "table" then
- refreshReactors(false)
- screenOverview()
- return
- end
- infcord.status.value = inf.status
- gpu.setForeground(color.white)
- local tbuf1 = inf.temperature
- os.sleep(0.1)
- local ok2, inf2 = pcall(reactor.getReactorInfo)
- local tbuf2 = ok2 and type(inf2) == "table" and inf2.temperature or tbuf1
- if handleMain then
- local stopPct = cfg.fuelStopPct or 98
- if cfg.autoProtectTempEdge and inf.temperature >= cfg.autoProtectTempEdge and not autostate then
- autostate = true
- guiWrite(button.autoon.x, button.autoon.y, color.green, color.black, "%s\n", button.autoon.name)
- end
- end
- local fuelPct = 0
- if inf.maxFuelConversion > 0 then
- fuelPct = (inf.fuelConversion / inf.maxFuelConversion) * 100
- end
- if autoStopped[reactors[activeIndex].reactorAdr] and (inf.status == "online" or inf.status == "charging" or inf.status == "charged") then
- autoStopped[reactors[activeIndex].reactorAdr] = nil
- end
- if fuelPct >= stopPct and (inf.status == "online" or inf.status == "charging" or inf.status == "charged") then
- if not autoStopped[reactors[activeIndex].reactorAdr] then
- reactor.stopReactor()
- autoStopped[reactors[activeIndex].reactorAdr] = true
- end
- end
- if tbuf2 > tbuf1 then
- guiWrite(infcord.temp.x, infcord.temp.y, color.red, -1, "%0.2f \n", inf.temperature)
- temprise = true
- elseif tbuf2 < tbuf1 then
- guiWrite(infcord.temp.x, infcord.temp.y, color.blue, -1, "%0.2f \n", inf.temperature)
- temprise = false
- else
- if inf.temperature == 2000 then
- guiWrite(infcord.temp.x, infcord.temp.y, -1, -1, "%0.2f \n", inf.temperature)
- end
- end
- guiWrite(infcord.generation.x, infcord.generation.y, -1, -1, "%s\n", numformat(inf.generationRate))
- if inf.generationRate > maxGenerationRate then
- maxGenerationRate = inf.generationRate
- end
- guiWrite(infcord.maxgen.x, infcord.maxgen.y, color.green, color.panel, "%s", numformat(maxGenerationRate))
- infcord.flow.value = getGateFlow(upgate)
- guiWrite(infcord.flow.x, infcord.flow.y, -1, -1, "%s", numformat(infcord.flow.value))
- guiWrite(infcord.puregen.x, infcord.puregen.y, -1, -1, "%s\n", numformat(inf.generationRate - getGateFlow(downgate)))
- infcord.drain.value = inf.fieldDrainRate
- guiWrite(infcord.drain.x, infcord.drain.y, -1, -1, "%s\n", numformat(getGateFlow(downgate)))
- if inf.maxFieldStrength > 0 then
- guiWrite(infcord.fstrth.x, infcord.fstrth.y, -1, -1, "%d / %d (%0.2f %%) \n",
- inf.fieldStrength - inf.fieldDrainRate,
- inf.maxFieldStrength,
- ((inf.fieldStrength - inf.fieldDrainRate) / inf.maxFieldStrength) * 100)
- else
- guiWrite(infcord.fstrth.x, infcord.fstrth.y, -1, -1, "0 / 0 (0 %%) \n")
- end
- if inf.maxEnergySaturation > 0 then
- guiWrite(infcord.esturn.x, infcord.esturn.y, -1, -1, "%d / %d (%0.2f %%) \n",
- inf.energySaturation,
- inf.maxEnergySaturation,
- (inf.energySaturation / inf.maxEnergySaturation) * 100)
- else
- guiWrite(infcord.esturn.x, infcord.esturn.y, -1, -1, "0 / 0 (0 %%) \n")
- end
- if inf.fuelConversion / inf.maxFuelConversion < 0.78 then
- guiWrite(infcord.fuel.x, infcord.fuel.y, -1, -1, "%d / %d (%0.2f %%) \n",
- inf.fuelConversion,
- inf.maxFuelConversion,
- (inf.fuelConversion / inf.maxFuelConversion) * 100)
- else
- if inf.maxFuelConversion > 0 then
- if inf.status == "online" or inf.status == "charging" or inf.status == "charged" then
- guiWrite(infcord.fuel.x, infcord.fuel.y, color.red, -1, "%d / %d (%0.2f %%) Критический уровень топлива\n",
- inf.fuelConversion,
- inf.maxFuelConversion,
- (inf.fuelConversion / inf.maxFuelConversion) * 100)
- else
- guiWrite(infcord.fuel.x, infcord.fuel.y, -1, -1, "%d / %d (%0.2f %%) Критический уровень топлива\n",
- inf.fuelConversion,
- inf.maxFuelConversion,
- (inf.fuelConversion / inf.maxFuelConversion) * 100)
- end
- else
- guiWrite(infcord.fuel.x, infcord.fuel.y, -1, -1, "0 / 0 (0 %%)\n")
- end
- end
- guiWrite(infcord.fuelconv.x, infcord.fuelconv.y, -1, -1, "%d\n", inf.fuelConversionRate)
- if com.isAvailable("draconic_rf_storage") then
- guiWrite(infcord.core.x, infcord.core.y, -1, -1, coreformat())
- if button.stop.y ~= infcord.core.y + 2 then
- screenMain()
- end
- elseif button.stop.y ~= infcord.fuelconv.y + 2 then
- screenMain()
- end
- checkButtons()
- syncActive()
- end
- local function autoForReactor(r, state)
- if not r or not r.reactor or not r.upgate or not r.downgate then
- return
- end
- local ok, inf = pcall(r.reactor.getReactorInfo)
- if not ok or type(inf) ~= "table" then
- return
- end
- local now = computer.uptime()
- if r.chargeRequested and now <= r.chargeRequested then
- local downflow = 900000
- r.downgate.setOverrideEnabled(true)
- r.downgate.setFlowOverride(downflow)
- return
- end
- if inf.status == "charging" then
- local downflow = 900000
- r.downgate.setOverrideEnabled(true)
- r.downgate.setFlowOverride(downflow)
- return
- end
- local isActive = reactors[activeIndex] and reactors[activeIndex].reactorAdr == r.reactorAdr
- if cfg.autoProtectTempEdge and inf.temperature >= cfg.autoProtectTempEdge and not r.autostate then
- r.autostate = true
- if isActive then
- autostate = true
- if handleMain and button.autoon.x then
- guiWrite(button.autoon.x, button.autoon.y, color.green, color.black, "%s\n", button.autoon.name)
- end
- end
- end
- local shieldPct = cfg.shield or 25
- local flow = getGateFlow(r.upgate)
- if type(flow) ~= "number" then
- flow = 0
- end
- local drain = inf.fieldDrainRate
- if state then
- local forceEdge = cfg.forceModeTempLowEdge or 7600
- if forceEdge < 7600 then
- forceEdge = 7600
- end
- local waittemp = autoWaitTempByAdr[r.reactorAdr]
- local tempRise = false
- if r.lastTemp then
- if inf.temperature > r.lastTemp then
- tempRise = true
- elseif inf.temperature < r.lastTemp then
- tempRise = false
- else
- tempRise = r.temprise or false
- end
- end
- r.lastTemp = inf.temperature
- r.temprise = tempRise
- local downflow = drain / (1 - (shieldPct / 100))
- r.downgate.setOverrideEnabled(true)
- r.downgate.setFlowOverride(downflow)
- if inf.temperature <= forceEdge then
- if flow - inf.generationRate <= cfg.forceModeStepCase then
- flow = flow + cfg.forceModeStep
- r.upgate.setSignalLowFlow(flow)
- end
- elseif flow - inf.generationRate <= cfg.safeModeStepCase and inf.temperature >= forceEdge then
- if not waittemp then
- flow = getGateFlow(r.upgate) + cfg.safemodeStep
- r.upgate.setSignalLowFlow(flow)
- elseif inf.temperature < cfg.safeModeTempToWaitEdge then
- waittemp = false
- end
- elseif tempRise and inf.temperature >= cfg.safeModeTempWaitEdge then
- if inf.temperature > cfg.safeModeTempWaitEdge then
- waittemp = true
- end
- if inf.temperature > cfg.tempCriticalEdge then
- flow = inf.generationRate - 1000
- r.upgate.setSignalLowFlow(flow)
- end
- end
- autoWaitTempByAdr[r.reactorAdr] = waittemp
- if isActive and handleMain and infcord.flow.x then
- infcord.flow.value = flow
- guiWrite(infcord.flow.x, infcord.flow.y, color.red, color.grey, "%s", numformat(flow))
- end
- else
- local downflow
- if inf.status == "charging" then
- downflow = 900000
- else
- downflow = drain / (1 - (shieldPct / 100))
- end
- if inf.status == "charging" then
- r.downgate.setOverrideEnabled(true)
- r.downgate.setFlowOverride(downflow)
- else
- r.downgate.setOverrideEnabled(false)
- r.downgate.setSignalHighFlow(downflow)
- r.downgate.setSignalLowFlow(downflow)
- end
- end
- end
- local function tcall(type, scrnAdr, x, y, btn, player)
- local rx, ry = gpu.getResolution()
- if x >= rx - 2 and x <= rx and y == 1 then
- event.ignore("touch", tcall)
- prog = false
- ops = false
- end
- if handleStart then
- if menuItem.gates.x and x >= menuItem.gates.x and x <= (menuItem.gates.x + (menuItem.gates.w or #menuItem.gates.name) - 1) and y == menuItem.gates.y then
- resetAssignState()
- screenAssign()
- return
- end
- end
- if handleMain then
- if x >= button.add.x + 4 and x <= button.add.x + 3 + #button.add.name and y == button.add.y then
- if keyb.isShiftDown() then
- if keyb.isControlDown() then
- upgate.setSignalLowFlow(add(infcord.flow, cfg.ctrlShift_interval))
- else
- upgate.setSignalLowFlow(add(infcord.flow, cfg.shift_interval))
- end
- else
- if keyb.isControlDown() then
- upgate.setSignalLowFlow(add(infcord.flow, cfg.ctrl_interval))
- else
- upgate.setSignalLowFlow(add(infcord.flow, cfg.default_interval))
- end
- end
- guiWrite(infcord.flow.x, infcord.flow.y, color.red, color.grey, "%s", numformat(infcord.flow.value))
- end
- if x >= button.sub.x + 2 and x <= button.sub.x + 1 + #button.sub.name and y == button.sub.y then
- if keyb.isShiftDown() then
- if keyb.isControlDown() then
- upgate.setSignalLowFlow(sub(infcord.flow, cfg.ctrlShift_interval))
- else
- upgate.setSignalLowFlow(sub(infcord.flow, cfg.shift_interval))
- end
- else
- if keyb.isControlDown() then
- upgate.setSignalLowFlow(sub(infcord.flow, cfg.ctrl_interval))
- else
- upgate.setSignalLowFlow(sub(infcord.flow, cfg.default_interval))
- end
- end
- guiWrite(infcord.flow.x, infcord.flow.y, color.blue, color.grey, "%s", numformat(infcord.flow.value))
- end
- if not autostate then
- if x >= button.autooff.x and x <= button.autooff.x + textWidth(button.autooff.name) - 1 and y == button.autooff.y then
- gpu.set(button.autooff.x, button.autooff.y, " ")
- autostate = true
- guiWrite(button.autoon.x, button.autoon.y, color.green, color.black, "%s\n", button.autoon.name)
- end
- else
- if x >= button.autoon.x and x <= button.autoon.x + textWidth(button.autoon.name) - 1 and y == button.autoon.y then
- gpu.set(button.autoon.x, button.autoon.y, " ")
- autostate = false
- guiWrite(button.autooff.x, button.autooff.y, color.red, color.black, "%s\n", button.autooff.name)
- end
- end
- do
- local w = button.charge.w or textWidth(button.charge.name)
- if button.charge.x and button.charge.y and x >= button.charge.x and x <= button.charge.x + w - 1 and y == button.charge.y then
- local usedNativeCharge = false
- if reactor and reactor.chargeReactor then
- local ok = pcall(reactor.chargeReactor)
- if ok then
- usedNativeCharge = true
- end
- end
- if not usedNativeCharge then
- ensureFlowInit(reactors[activeIndex], true)
- if upgate then
- upgate.setSignalLowFlow(CHARGE_FLOW)
- end
- infcord.flow.value = CHARGE_FLOW
- if infcord.flow.x then
- guiWrite(infcord.flow.x, infcord.flow.y, color.red, color.grey, "%s", numformat(infcord.flow.value))
- end
- end
- if chargeHint.visible and chargeHint.x and chargeHint.y then
- guiWrite(chargeHint.x, chargeHint.y, color.white, color.grey, "%s", string.rep(" ", chargeHint.w))
- guiWrite(chargeHint.x, chargeHint.y + 1, color.white, color.grey, "%s", string.rep(" ", chargeHint.w))
- chargeHint.visible = false
- chargeHintDismissed = true
- end
- guiWrite(button.charge.x, button.charge.y, -1, color.grey, " ", button.charge.name)
- button.charge.visible = false
- if not usedNativeCharge then
- local currentReactor = reactors[activeIndex]
- if currentReactor and currentReactor.reactorAdr then
- local chargeUntil = computer.uptime() + CHARGE_DURATION
- currentReactor.chargeRequested = chargeUntil
- chargeRequestByAdr[currentReactor.reactorAdr] = chargeUntil
- end
- end
- end
- end
- if button.start.visible then
- local w = button.start.w or textWidth(button.start.name)
- if x >= button.start.x and x <= button.start.x + w - 1 and y == button.start.y then
- ensureFlowInit(reactors[activeIndex])
- reactor.activateReactor()
- if reactors[activeIndex] then
- autoStopped[reactors[activeIndex].reactorAdr] = nil
- end
- guiWrite(button.start.x, button.start.y, -1, color.grey, " ", button.start.name)
- button.start.visible = false
- end
- end
- if button.stop.visible then
- local w = button.stop.w or textWidth(button.stop.name)
- if x >= button.stop.x and x <= button.stop.x + w - 1 and y == button.stop.y then
- reactor.stopReactor()
- guiWrite(button.stop.x, button.stop.y, -1, color.grey, " ", button.stop.name)
- button.stop.visible = false
- end
- end
- if x >= menuItem.options.x and x <= (menuItem.options.x + (menuItem.options.w or #menuItem.options.name) - 1) and y == menuItem.options.y then
- screenOptions()
- return
- end
- if x >= menuItem.overview.x and x <= (menuItem.overview.x + (menuItem.overview.w or #menuItem.overview.name) - 1) and y == menuItem.overview.y then
- syncActive()
- screenOverview()
- return
- end
- if x >= menuItem.refresh.x and x <= (menuItem.refresh.x + (menuItem.refresh.w or #menuItem.refresh.name) - 1) and y == menuItem.refresh.y then
- refreshReactors(true)
- return
- end
- if x >= menuItem.gates.x and x <= (menuItem.gates.x + (menuItem.gates.w or #menuItem.gates.name) - 1) and y == menuItem.gates.y then
- resetAssignState()
- screenAssign()
- return
- end
- for i = 1, #reactors do
- local tab = reactors[i].tab
- if tab.x and x >= tab.x and x <= tab.x + tab.w - 1 and y == tab.y then
- syncActive()
- setActive(i)
- screenMain()
- return
- end
- end
- if x == 1 and y == 1 then
- event.ignore("touch", tcall)
- prog = false
- end
- end
- if handleOverview then
- if x >= menuItem.options.x and x <= (menuItem.options.x + (menuItem.options.w or #menuItem.options.name) - 1) and y == menuItem.options.y then
- screenOptions()
- return
- end
- if x >= menuItem.refresh.x and x <= (menuItem.refresh.x + (menuItem.refresh.w or #menuItem.refresh.name) - 1) and y == menuItem.refresh.y then
- refreshReactors(true)
- return
- end
- if x >= menuItem.gates.x and x <= (menuItem.gates.x + (menuItem.gates.w or #menuItem.gates.name) - 1) and y == menuItem.gates.y then
- resetAssignState()
- screenAssign()
- return
- end
- for i = 1, #reactors do
- local tab = reactors[i].tab
- if tab.x and x >= tab.x and x <= tab.x + tab.w - 1 and y == tab.y then
- syncActive()
- setActive(i)
- screenMain()
- return
- end
- local ctrl = reactors[i].control
- if ctrl and ctrl.dec and x >= ctrl.dec.x and x <= ctrl.dec.x + ctrl.dec.w - 1 and y == ctrl.dec.y then
- local flow = getGateFlow(reactors[i].upgate)
- reactors[i].upgate.setSignalLowFlow(flow - cfg.default_interval)
- return
- end
- if ctrl and ctrl.inc and x >= ctrl.inc.x and x <= ctrl.inc.x + ctrl.inc.w - 1 and y == ctrl.inc.y then
- local flow = getGateFlow(reactors[i].upgate)
- reactors[i].upgate.setSignalLowFlow(flow + cfg.default_interval)
- return
- end
- if ctrl and ctrl.auto and x >= ctrl.auto.x and x <= ctrl.auto.x + ctrl.auto.w - 1 and y == ctrl.auto.y then
- reactors[i].autostate = not reactors[i].autostate
- if i == activeIndex then
- autostate = reactors[i].autostate
- end
- refreshOverview()
- return
- end
- local btn = reactors[i].powerBtn
- if btn.x and x >= btn.x and x <= btn.x + btn.w - 1 and y == btn.y then
- if btn.action == "start" then
- ensureFlowInit(reactors[i])
- reactors[i].reactor.activateReactor()
- autoStopped[reactors[i].reactorAdr] = nil
- else
- reactors[i].reactor.stopReactor()
- end
- return
- end
- end
- if x == 1 and y == 1 then
- event.ignore("touch", tcall)
- prog = false
- end
- end
- if handleOptions then
- if canedit then
- if x >= OptionDefault.x and x <= OptionDefault.x + #tostring(OptionDefault.value) - 1 and y == OptionDefault.y then
- canclose = false
- canedit = false
- editOption(OptionDefault)
- end
- if x >= OptionCtrl.x and x <= OptionCtrl.x + #tostring(OptionCtrl.value) - 1 and y == OptionCtrl.y then
- canclose = false
- canedit = false
- editOption(OptionCtrl)
- end
- if x >= OptionShift.x and x <= OptionShift.x + #tostring(OptionShift.value) - 1 and y == OptionShift.y then
- canclose = false
- canedit = false
- editOption(OptionShift)
- end
- if x >= OptionCtrlShift.x and x <= OptionCtrlShift.x + #tostring(OptionCtrlShift.value) - 1 and y == OptionCtrlShift.y then
- canclose = false
- canedit = false
- editOption(OptionCtrlShift)
- end
- if x >= OptionShield.x and x <= OptionShield.x + #tostring(OptionShield.value) - 1 and y == OptionShield.y then
- canclose = false
- canedit = false
- editOption(OptionShield)
- end
- if x >= OptionFuelStop.x and x <= OptionFuelStop.x + #tostring(OptionFuelStop.value) - 1 and y == OptionFuelStop.y then
- canclose = false
- canedit = false
- editOption(OptionFuelStop)
- end
- end
- if canclose then
- if x >= menuItem.optionsBack.x and x <= (menuItem.optionsBack.x + (menuItem.optionsBack.w or #menuItem.optionsBack.name) - 1) and y == menuItem.optionsBack.y then
- screenOverview()
- return
- end
- if x >= menuItem.save.x and x <= (menuItem.save.x + (menuItem.save.w or #menuItem.save.name) - 1) and y == menuItem.save.y then
- cfg.default_interval = OptionDefault.value
- cfg.ctrl_interval = OptionCtrl.value
- cfg.shift_interval = OptionShift.value
- cfg.ctrlShift_interval = OptionCtrlShift.value
- cfg.shield = OptionShield.value
- cfg.fuelStopPct = OptionFuelStop.value
- configWrite(cfgName)
- screenOverview()
- return
- end
- if x >= menuItem.cancel.x and x <= (menuItem.cancel.x + (menuItem.cancel.w or #menuItem.cancel.name) - 1) and y == menuItem.cancel.y then
- OptionDefault.value = cfg.default_interval
- OptionCtrl.value = cfg.ctrl_interval
- OptionShift.value = cfg.shift_interval
- OptionCtrlShift.value = cfg.ctrlShift_interval
- OptionShield.value = cfg.shield
- OptionFuelStop.value = cfg.fuelStopPct or 98
- screenOverview()
- return
- end
- end
- end
- if handleAssign then
- if assignMode ~= "manual" and assignMode ~= "easy" then
- if easyAssign.backBtn.x and x >= easyAssign.backBtn.x and x <= easyAssign.backBtn.x + easyAssign.backBtn.w - 1 and y == easyAssign.backBtn.y then
- assignMode = nil
- easyAssign.active = false
- screenOverview()
- return
- end
- if easyAssign.heavyBtn.x and x >= easyAssign.heavyBtn.x and x <= easyAssign.heavyBtn.x + easyAssign.heavyBtn.w - 1 and y == easyAssign.heavyBtn.y then
- assignMode = "manual"
- resetAssignState()
- screenAssignManual()
- return
- end
- if easyAssign.easyBtn.x and x >= easyAssign.easyBtn.x and x <= easyAssign.easyBtn.x + easyAssign.easyBtn.w - 1 and y == easyAssign.easyBtn.y then
- assignMode = "easy"
- startEasyAssign()
- if not easyAssign.active then
- assignMode = nil
- screenAssignChoice()
- else
- screenAssignEasy()
- end
- return
- end
- return
- elseif assignMode == "easy" then
- if easyAssign.backBtn.x and x >= easyAssign.backBtn.x and x <= easyAssign.backBtn.x + easyAssign.backBtn.w - 1 and y == easyAssign.backBtn.y then
- if easyAssign.saved and easyAssign.core then
- clearAssignedByAdr(easyAssign.core)
- end
- easyAssign.active = false
- easyAssign.step = "reactor"
- easyAssign.core = nil
- easyAssign.shield = nil
- easyAssign.output = nil
- easyAssign.saved = false
- easyAssign.message = nil
- assignMode = nil
- screenAssignChoice()
- return
- end
- if easyAssign.step == "done" then
- if easyAssign.continueBtn.x and x >= easyAssign.continueBtn.x and x <= easyAssign.continueBtn.x + easyAssign.continueBtn.w - 1 and y == easyAssign.continueBtn.y then
- startEasyAssign()
- screenAssignEasy()
- return
- end
- if easyAssign.finishBtn.x and x >= easyAssign.finishBtn.x and x <= easyAssign.finishBtn.x + easyAssign.finishBtn.w - 1 and y == easyAssign.finishBtn.y then
- easyAssign.active = false
- assignMode = nil
- refreshReactors(false)
- screenOverview()
- return
- end
- end
- return
- end
- if x >= menuItem.back.x and x <= (menuItem.back.x + (menuItem.back.w or #menuItem.back.name) - 1) and y == menuItem.back.y then
- if not assignState.reactorIndex and not assignState.shieldGateIdx and not assignState.outGateIdx then
- resetAssignState()
- assignMode = nil
- screenOverview()
- return
- end
- assignState.message = "Выбери гейты!"
- screenAssign()
- return
- end
- if assignUi.reset and x >= assignUi.reset.x and x <= assignUi.reset.x + assignUi.reset.w - 1 and y == assignUi.reset.y then
- if assignState.reactorIndex then
- clearAssignedGates(assignState.reactorIndex)
- reactors = buildReactors() or reactors
- resetAssignState()
- screenAssign()
- end
- return
- end
- for i = 1, #assignUi.reactors do
- local btn = assignUi.reactors[i]
- if btn and x >= btn.x and x <= btn.x + btn.w - 1 and y == btn.y then
- assignState.reactorIndex = i
- assignState.reactorAdr = assignUi.reactorAddrs[i]
- assignState.shieldGateIdx = nil
- assignState.shieldGateAdr = nil
- assignState.outGateIdx = nil
- assignState.outGateAdr = nil
- assignState.step = "shield"
- screenAssign()
- return
- end
- end
- for i = 1, #assignUi.gates do
- local btn = assignUi.gates[i]
- if btn and x >= btn.x and x <= btn.x + btn.w - 1 and y == btn.y then
- local gateAdr = assignUi.gateAddrs[i]
- if assignState.step == "reactor" then
- return
- end
- if gateAdr and assignUi.gateUse[gateAdr] and assignUi.gateUse[gateAdr] ~= assignUi.selectedAdr then
- return
- end
- local selectedEntry = assignUi.selectedEntry
- if not assignState.reactorIndex then
- assignState.step = "reactor"
- screenAssign()
- return
- end
- if assignState.step == "shield" then
- assignState.shieldGateIdx = i
- assignState.shieldGateAdr = gateAdr
- assignState.step = "output"
- screenAssign()
- return
- elseif assignState.step == "output" then
- if assignState.shieldGateAdr and assignState.shieldGateAdr == gateAdr then
- assignState.message = "Нужны два разных гейта!"
- screenAssign()
- return
- end
- assignState.outGateIdx = i
- assignState.outGateAdr = gateAdr
- if not assignState.reactorAdr and assignState.reactorIndex then
- assignState.reactorAdr = assignUi.reactorAddrs[assignState.reactorIndex]
- end
- if not assignState.shieldGateAdr and assignState.shieldGateIdx then
- assignState.shieldGateAdr = assignUi.gateAddrs[assignState.shieldGateIdx]
- end
- local saved = saveAssignedGates(assignState.reactorAdr, assignState.shieldGateAdr, assignState.outGateAdr)
- if not saved then
- assignState.message = "Не удалось сохранить гейты!"
- screenAssign()
- return
- end
- local targetAdr = assignState.reactorAdr
- resetAssignState()
- assignMode = nil
- handleAssign = false
- handleMain = true
- handleOverview = false
- reactors = buildReactors() or reactors
- local idx = 1
- if targetAdr then
- for j = 1, #reactors do
- if reactors[j].reactorAdr == targetAdr then
- idx = j
- break
- end
- end
- end
- setActive(idx)
- if not reactors or #reactors == 0 or not reactor or not upgate or not downgate then
- screenOverview()
- return
- end
- screenMain()
- return
- end
- end
- end
- if x == 1 and y == 1 then
- event.ignore("touch", tcall)
- prog = false
- end
- end
- end
- event.listen("touch", tcall)
- event.listen("component_added", handleComponentAdded)
- screenStart()
- if upgate ~= nil and downgate ~= nil then
- screen.overview()
- end
- while prog do
- local now = computer.uptime()
- if handleMain and now - lastDetailUpdate >= 0.2 then
- lastDetailUpdate = now
- if not pcall(refreshInfo) then
- autostate = false
- if not pcall(screenStart) then
- break
- end
- if not pcall(screenMain) then
- screenStart()
- if not pcall(screenMain) then
- break
- end
- end
- end
- elseif handleOverview and now - lastOverviewUpdate >= 0.5 then
- lastOverviewUpdate = now
- if not pcall(refreshOverview) then
- if not pcall(screenOverview) then
- break
- end
- end
- end
- if reactors and #reactors > 0 then
- for i = 1, #reactors do
- autoForReactor(reactors[i], reactors[i].autostate)
- end
- end
- pollEasyAssign()
- os.sleep(0)
- end
- gpu.setBackground(rback)
- gpu.setForeground(rfore)
- gpu.setResolution(xz, yz)
- term.clear()
Add Comment
Please, Sign In to add comment