Gintarus

reactor_5

Jan 9th, 2026 (edited)
59
0
Never
Not a member of Pastebin yet? Sign Up, it unlocks many cool features!
text 65.80 KB | None | 0 0
  1. local event = require("event")
  2. local term = require("term")
  3. local os = require("os")
  4. local computer = require("computer")
  5. local com = require("component")
  6. local unicode = require("unicode")
  7. local keyb = require("keyboard")
  8. local gpu = com.gpu
  9.  
  10. local reactorsFile = "/home/reactors.txt"
  11. local cfgName = "/home/DracReactorConfig.cfg"
  12. local MAX_REACTORS = 5
  13. local autostateByAdr = {}
  14. local flowInitByAdr = {}
  15. local DEFAULT_CONFIG = [[
  16. -- Интервалы для кнопок +/-
  17. default_interval = 1000
  18. ctrl_interval = 5000
  19. shift_interval = 10000
  20. ctrlShift_interval = 20000
  21. -- Автономный режим:
  22. -- Основные константы
  23. shield = 25 - Щиты будут автоматически поддерживаться на этом уровне ( в %)
  24. tempCriticalEdge = 8100 -- Если температура превысит это значение, программа экстренно понизит поток вывода;
  25. -- Форсированный режим
  26. forceModeTempLowEdge = 7500 -- Пока температура не превысит это значение, программа будет работать в форсированном режиме, иначе - перейдет в безопасный режим;
  27. forceModeStepCase = 5000 -- Если разница между текущей выработкой энергии и выставленным потоком превысит это значение, то к потоку добавится
  28. forceModeStep = 20000 -- это значение
  29. -- безопасный режим
  30. safeModeTempWaitEdge = 8000 -- Если температура превысит это значение, программа будет ожидать,
  31. safeModeTempToWaitEdge = 7850 -- пока температура не понизится до этого значения;
  32. safeModeStepCase = 0 -- Если разница между текущей выработкой энергии и выставленным потоком превысит это значение, то к потоку добавится
  33. safemodeStep = 8000 -- это значение
  34. autoProtectTempEdge = 8300 -- При достижении этой температуры включается автономный режим
  35. screen_w = 80 -- Ширина экрана
  36. screen_h = 25 -- Высота экрана
  37. fuelStopPct = 98 -- % топлива, при котором реактор выключается]]
  38.  
  39. local function parseNum(str)
  40. local n = ""
  41. for i=1,#str do
  42. local ch = str:byte(i,i)
  43. if ch >= 48 and ch <= 57 or ch == 46 then
  44. n = n..string.char(ch)
  45. end
  46. end
  47. if n ~= "" then
  48. return tonumber(n)
  49. else return n
  50. end
  51. end
  52.  
  53. local cfg = {}
  54. local confnames =
  55. {
  56. [1] = "default_interval",
  57. [2] = "ctrl_interval",
  58. [3] = "shift_interval",
  59. [4] = "ctrlShift_interval",
  60. [5] = "shield",
  61. [6] = "tempCriticalEdge",
  62. [7] = "forceModeTempLowEdge",
  63. [8] = "forceModeStepCase",
  64. [9] = "forceModeStep",
  65. [10] = "safeModeTempWaitEdge",
  66. [11] = "safeModeTempToWaitEdge",
  67. [12] = "safeModeStepCase",
  68. [13] = "safemodeStep",
  69. [14] = "autoProtectTempEdge",
  70. [15] = "screen_w",
  71. [16] = "screen_h",
  72. [17] = "fuelStopPct"
  73. }
  74.  
  75. local function readConfig(name)
  76. local file = io.open(name,"r")
  77. if not file then
  78. return nil
  79. end
  80. local tab = {}
  81. for line in file:lines() do
  82. local key, val = line:match("^%s*([%w_]+)%s*=%s*([%d%.]+)")
  83. if key and val then
  84. tab[key] = tonumber(val)
  85. end
  86. end
  87. file:close()
  88. return tab
  89. end
  90.  
  91. local function hasConfigKeys(parsed)
  92. if not parsed then
  93. return false
  94. end
  95. for i=1,#confnames do
  96. if parsed[confnames[i]] == nil then
  97. return false
  98. end
  99. end
  100. return true
  101. end
  102.  
  103. local function readParse(name)
  104. local file = io.open(name,"r")
  105. if file then
  106. local tab = {}
  107. local i = 1
  108. while true do
  109. local str = file:read("*l")
  110. if str == nil then
  111. break
  112. end
  113. if parseNum(str) ~= "" then
  114. tab[i] = parseNum(str)
  115. i=i+1
  116. end
  117. end
  118. file:close()
  119. return tab
  120. else
  121. return false
  122. end
  123. end
  124.  
  125. local function writeText(name,text)
  126. local file = io.open(name,"w")
  127. file:write(text)
  128. file:close()
  129. end
  130.  
  131. local function configWrite(name)
  132. local parsed = readConfig(name)
  133. if not parsed or not hasConfigKeys(parsed) then
  134. writeText(name,DEFAULT_CONFIG)
  135. elseif cfg.default_interval ~= nil and
  136. cfg.ctrl_interval ~= nil and
  137. cfg.shift_interval ~= nil and
  138. cfg.ctrlShift_interval ~= nil and
  139. cfg.shield ~= nil and
  140. cfg.tempCriticalEdge ~= nil and
  141. cfg.forceModeTempLowEdge ~= nil and
  142. cfg.forceModeStepCase ~= nil and
  143. cfg.forceModeStep ~= nil and
  144. cfg.safeModeTempWaitEdge ~= nil and
  145. cfg.safeModeTempToWaitEdge ~= nil and
  146. cfg.safeModeStepCase ~= nil and
  147. cfg.safemodeStep ~= nil and
  148. cfg.autoProtectTempEdge ~= nil and
  149. cfg.screen_w ~= nil and
  150. cfg.screen_h ~= nil and
  151. cfg.fuelStopPct ~= nil then
  152.  
  153. writeText(name,string.format(
  154. [[
  155. -- Интервалы для кнопок +/-
  156. default_interval = %d
  157. ctrl_interval = %d
  158. shift_interval = %d
  159. ctrlShift_interval = %d
  160. -- Автономный режим:
  161. -- Основные константы
  162. shield = %0.2f - Щиты будут автоматически поддерживаться на этом уровне ( в %)
  163. tempCriticalEdge = %d -- Если температура превысит это значение, программа экстренно понизит поток вывода;
  164. -- Форсированный режим
  165. forceModeTempLowEdge = %d -- Пока температура не превысит это значение, программа будет работать в форсированном режиме, иначе - перейдет в безопасный режим;
  166. forceModeStepCase = %d -- Если разница между текущей выработкой энергии и выставленным потоком превысит это значение, то к потоку добавится
  167. forceModeStep = %d -- это значение
  168. -- Безопасный режим
  169. safeModeTempWaitEdge = %d -- Если температура превысит это значение, программа будет ожидать,
  170. safeModeTempToWaitEdge = %d -- пока температура не понизится до этого значения;
  171. safeModeStepCase = %d -- Если разница между текущей выработкой энергии и выставленным потоком превысит это значение, то к потоку добавится
  172. safemodeStep = %d -- это значение
  173. autoProtectTempEdge = %d -- При достижении этой температуры включается автономный режим
  174. screen_w = %d -- Ширина экрана
  175. screen_h = %d -- Высота экрана
  176. fuelStopPct = %d -- % топлива, при котором реактор выключается]],
  177. cfg.default_interval,
  178. cfg.ctrl_interval,
  179. cfg.shift_interval,
  180. cfg.ctrlShift_interval,
  181. cfg.shield,
  182. cfg.tempCriticalEdge,
  183. cfg.forceModeTempLowEdge,
  184. cfg.forceModeStepCase,
  185. cfg.forceModeStep,
  186. cfg.safeModeTempWaitEdge,
  187. cfg.safeModeTempToWaitEdge,
  188. cfg.safeModeStepCase,
  189. cfg.safemodeStep,
  190. cfg.autoProtectTempEdge,
  191. cfg.screen_w,
  192. cfg.screen_h,
  193. cfg.fuelStopPct
  194. ))
  195. end
  196. end
  197.  
  198. local function makeConfig(tab,tab2)
  199. local config = {}
  200. for i=1,#tab do
  201. config[tostring(tab[i])] = tab2[i]
  202. end
  203. return config
  204. end
  205.  
  206. local function listAddresses(typeName)
  207. local list = {}
  208. for adr in com.list(typeName) do
  209. list[#list+1] = adr
  210. end
  211. return list
  212. end
  213.  
  214. local function readReactorsFile()
  215. local file = io.open(reactorsFile,"r")
  216. if not file then
  217. return nil
  218. end
  219. local list = {}
  220. for line in file:lines() do
  221. local r,u,d = line:match("(%S+)%s+(%S+)%s+(%S+)")
  222. if r and u and d then
  223. list[#list+1] = {reactorAdr = r, upAdr = u, downAdr = d}
  224. end
  225. end
  226. file:close()
  227. if #list == 0 then
  228. return nil
  229. end
  230. return list
  231. end
  232.  
  233. local function writeReactorsFile(list)
  234. local file = io.open(reactorsFile,"w")
  235. for i=1,#list do
  236. file:write(string.format("%s %s %s\n",list[i].reactorAdr,list[i].upAdr,list[i].downAdr))
  237. end
  238. file:close()
  239. end
  240.  
  241. local function validEntry(entry)
  242. return com.get(entry.reactorAdr) ~= nil and com.get(entry.upAdr) ~= nil and com.get(entry.downAdr) ~= nil
  243. end
  244.  
  245. local function mergeEntries(entries)
  246. local usedReactors = {}
  247. local usedGates = {}
  248. for i=1,#entries do
  249. usedReactors[entries[i].reactorAdr] = true
  250. usedGates[entries[i].upAdr] = true
  251. usedGates[entries[i].downAdr] = true
  252. end
  253. local reactorsList = listAddresses("draconic_reactor")
  254. local gates = listAddresses("flux_gate")
  255. local freeReactors = {}
  256. local freeGates = {}
  257. for i=1,#reactorsList do
  258. if not usedReactors[reactorsList[i]] then
  259. freeReactors[#freeReactors+1] = reactorsList[i]
  260. end
  261. end
  262. for i=1,#gates do
  263. if not usedGates[gates[i]] then
  264. freeGates[#freeGates+1] = gates[i]
  265. end
  266. end
  267. local addCount = math.min(#freeReactors, math.floor(#freeGates/2), MAX_REACTORS - #entries)
  268. for i=1,addCount do
  269. entries[#entries+1] = {
  270. reactorAdr = freeReactors[i],
  271. upAdr = freeGates[(i-1)*2+1],
  272. downAdr = freeGates[(i-1)*2+2]
  273. }
  274. end
  275. return entries
  276. end
  277.  
  278. local function buildReactors()
  279. newEntriesAdded = false
  280. lastAddedReactorAdr = nil
  281. local entries = readReactorsFile()
  282. local currentReactors = reactors or {}
  283. if entries then
  284. local valid = {}
  285. for i=1,#entries do
  286. if validEntry(entries[i]) then
  287. valid[#valid+1] = entries[i]
  288. end
  289. end
  290. if #valid > 0 then
  291. entries = valid
  292. end
  293. end
  294. if entries and #entries > 0 then
  295. local reactorsList = listAddresses("draconic_reactor")
  296. if #reactorsList > #entries then
  297. newEntriesAdded = true
  298. end
  299. end
  300. if not entries or #entries == 0 then
  301. return nil
  302. end
  303. local oldByAdr = {}
  304. for i=1,#currentReactors do
  305. oldByAdr[currentReactors[i].reactorAdr] = currentReactors[i]
  306. end
  307. local reactors = {}
  308. for i=1,#entries do
  309. local e = entries[i]
  310. local old = oldByAdr[e.reactorAdr]
  311. local savedAuto = autostateByAdr[e.reactorAdr]
  312. local savedFlowInit = flowInitByAdr[e.reactorAdr]
  313. local savedCharge = chargeRequestByAdr[e.reactorAdr]
  314. reactors[i] = {
  315. index = i,
  316. reactorAdr = e.reactorAdr,
  317. upAdr = e.upAdr,
  318. downAdr = e.downAdr,
  319. reactor = com.proxy(com.get(e.reactorAdr)),
  320. upgate = com.proxy(com.get(e.upAdr)),
  321. downgate = com.proxy(com.get(e.downAdr)),
  322. maxGenerationRate = old and old.maxGenerationRate or 0,
  323. autostate = old and old.autostate or (savedAuto ~= nil and savedAuto or false),
  324. temprise = old and old.temprise or false,
  325. flowInit = old and old.flowInit or (savedFlowInit ~= nil and savedFlowInit or false),
  326. chargeRequested = old and old.chargeRequested or (savedCharge or 0),
  327. lastTemp = nil,
  328. row = {},
  329. powerBtn = {},
  330. tab = {}
  331. }
  332. if not old then
  333. lastAddedReactorAdr = e.reactorAdr
  334. end
  335. end
  336. return reactors
  337. end
  338.  
  339. configWrite(cfgName)
  340. cfg = readConfig(cfgName)
  341. if not cfg then
  342. cfg = makeConfig(confnames,readParse(cfgName))
  343. end
  344.  
  345. local reactors = {}
  346. local activeIndex = 1
  347. local summaryProfitCord = {x=nil,y=nil}
  348. local summaryEuCord = {x=nil,y=nil}
  349. local summaryShieldCord = {x=nil,y=nil}
  350. local summaryGenCord = {x=nil,y=nil}
  351. local summaryMaxProfitCord = {x=nil,y=nil}
  352. local maxSummaryProfit = 0
  353. local newEntriesAdded = false
  354. local pendingActiveReactorAdr = nil
  355. autostateByAdr = {}
  356. flowInitByAdr = {}
  357.  
  358. local color = { }
  359. color["red"] = 0xFF0000
  360. color["green"] = 0x00FF00
  361. color["yellow"] = 0xFFD166
  362. color["skyblue"] = 0x4FC3F7
  363. color["black"] = 0x0F1115
  364. color["grey"] = 0x0F1115
  365. color["panel"] = 0x1A1F27
  366. color["blue"] = 0x4FC3F7
  367. color["orange"] = 0xFF9800
  368. color["white"] = 0xE6EDF3
  369. color["dark"] = 0x242B36
  370. color["dim"] = 0x7A8599
  371.  
  372. local rback = gpu.getBackground()
  373. local rfore = gpu.getForeground()
  374.  
  375. local handleMain
  376. local handleOptions
  377. local handleStart
  378. local handleOverview
  379. local handleAssign
  380. local screenAssign
  381. local screenOverview
  382. local assignState = {reactorIndex = nil, shieldGateIdx = nil, outGateIdx = nil, step = "reactor", message = nil}
  383. local assignUi = {reactors = {}, gates = {}, back = {x=nil,y=nil,w=0}}
  384. local autoStopped = {}
  385. local autoWaitTempByAdr = {}
  386. local chargeRequestByAdr = {}
  387. local autoStoppedCord = {x=nil,y=nil}
  388.  
  389. local menuItem = {}
  390. menuItem["options"] =
  391. {
  392. ["name"] ="Настройки |",
  393. ["x"] = 1,
  394. ["y"] = 2
  395. }
  396. menuItem["save"] =
  397. {
  398. ["name"] ="Сохранить |",
  399. ["x"] = 1,
  400. ["y"] = 2
  401. }
  402. menuItem["cancel"] =
  403. {
  404. ["name"] =" Отменить |",
  405. ["x"] = 12,
  406. ["y"] = 2
  407. }
  408. menuItem["overview"] =
  409. {
  410. ["name"] ="Главный |",
  411. ["x"] = 1,
  412. ["y"] = 2
  413. }
  414. menuItem["refresh"] =
  415. {
  416. ["name"] ="Обновить |",
  417. ["x"] = 1,
  418. ["y"] = 2
  419. }
  420. menuItem["gates"] =
  421. {
  422. ["name"] ="Гейты |",
  423. ["x"] = 1,
  424. ["y"] = 2
  425. }
  426. menuItem["back"] =
  427. {
  428. ["name"] ="Назад |",
  429. ["x"] = 1,
  430. ["y"] = 2
  431. }
  432. menuItem["reset"] =
  433. {
  434. ["name"] ="Сброс |",
  435. ["x"] = 1,
  436. ["y"] = 2
  437. }
  438. menuItem["optionsBack"] =
  439. {
  440. ["name"] =" Назад |",
  441. ["x"] = 1,
  442. ["y"] = 2
  443. }
  444. menuItem["optionsBack"] =
  445. {
  446. ["name"] =" Назад |",
  447. ["x"] = 1,
  448. ["y"] = 2
  449. }
  450.  
  451. local xz,yz = gpu.maxResolution()
  452. local screenW = math.min(120, xz)
  453. local screenH = math.min(40, yz)
  454. gpu.setResolution(screenW,screenH)
  455.  
  456. gpu.setBackground(color.grey)
  457. gpu.setForeground(color.white)
  458.  
  459. local prog = true
  460. local OptionDefault = {}
  461. local OptionCtrl = {}
  462. local OptionShift = {}
  463. local OptionCtrlShift = {}
  464. local OptionShield = {}
  465. local OptionFuelStop = {}
  466. OptionDefault["value"] = cfg.default_interval
  467. OptionCtrl["value"] = cfg.ctrl_interval
  468. OptionShift["value"] = cfg.shift_interval
  469. OptionCtrlShift["value"] = cfg.ctrlShift_interval
  470. OptionShield["value"] = cfg.shield
  471. OptionFuelStop["value"] = cfg.fuelStopPct or 98
  472.  
  473. local infcord =
  474. {
  475. ["status"] =
  476. {
  477. ["value"] = nil,
  478. ["x"] = nil,
  479. ["y"] = nil
  480. },
  481. ["temp"] =
  482. {
  483. ["value"] = nil,
  484. ["x"] = nil,
  485. ["y"] = nil
  486. },
  487. ["generation"] =
  488. {
  489. ["value"] = nil,
  490. ["x"] = nil,
  491. ["y"] = nil
  492. },
  493. ["maxgen"] =
  494. {
  495. ["value"] = nil,
  496. ["x"] = nil,
  497. ["y"] = nil
  498. },
  499. ["flow"] =
  500. {
  501. ["value"] = nil,
  502. ["x"] = nil,
  503. ["y"] = nil
  504. },
  505. ["puregen"] =
  506. {
  507. ["value"] = nil,
  508. ["x"] = nil,
  509. ["y"] = nil
  510. },
  511. ["drain"] =
  512. {
  513. ["value"] = nil,
  514. ["x"] = nil,
  515. ["y"] = nil
  516. },
  517. ["fstrth"] =
  518. {
  519. ["value"] = nil,
  520. ["x"] = nil,
  521. ["y"] = nil
  522. },
  523. ["esturn"] =
  524. {
  525. ["value"] = nil,
  526. ["x"] = nil,
  527. ["y"] = nil
  528. },
  529. ["fuel"] =
  530. {
  531. ["value"] = nil,
  532. ["x"] = nil,
  533. ["y"] = nil
  534. },
  535. ["fuelconv"] =
  536. {
  537. ["value"] = nil,
  538. ["x"] = nil,
  539. ["y"] = nil
  540. },
  541. ["core"] =
  542. {
  543. ["value"] = nil,
  544. ["x"] = nil,
  545. ["y"] = nil
  546. }
  547. }
  548.  
  549. local button =
  550. {
  551. ["continue"] =
  552. {
  553. ["name"] = "Продолжить",
  554. ["x"] = nil,
  555. ["y"] = nil
  556. },
  557. ["change"] =
  558. {
  559. ["name"] = "Изменить",
  560. ["x"] = nil,
  561. ["y"] = nil
  562. },
  563. ["add"] =
  564. {
  565. ["name"] = " + ",
  566. ["x"] = nil,
  567. ["y"] = nil
  568. },
  569. ["sub"] =
  570. {
  571. ["name"] = " - ",
  572. ["x"] = nil,
  573. ["y"] = nil
  574. },
  575. ["start"] =
  576. {
  577. ["name"] = " [PWR] ЗАПУСК ",
  578. ["x"] = nil,
  579. ["y"] = nil,
  580. ["visible"] = nil
  581. },
  582. ["stop"] =
  583. {
  584. ["name"] = " [PWR] СТОП ",
  585. ["x"] = nil,
  586. ["y"] = nil,
  587. ["visible"] = nil
  588. },
  589. ["charge"] =
  590. {
  591. ["name"] = "Зарядить реактор ",
  592. ["x"] = nil,
  593. ["y"] = nil,
  594. ["visible"] = nil
  595. },
  596. ["autoon"] =
  597. {
  598. ["name"] = "[ON] ",
  599. ["x"] = nil,
  600. ["y"] = nil,
  601. },
  602. ["autooff"] =
  603. {
  604. ["name"] = "[OFF]",
  605. ["x"] = nil,
  606. ["y"] = nil,
  607. }
  608. }
  609.  
  610. local ops = true
  611. local canedit = true
  612. local canclose = true
  613. local temprise
  614. local autostate = false
  615. local maxGenerationRate = 0
  616. local lastDetailUpdate = 0
  617. local lastOverviewUpdate = 0
  618.  
  619. printf = function (s,...)
  620. return io.write(s:format(...))
  621. end
  622.  
  623. local function textWidth(s)
  624. local ok, len = pcall(unicode.len, s)
  625. if ok and len then
  626. return len
  627. end
  628. return #s
  629. end
  630.  
  631. local function guiWrite(x,y,cf,cb,s,...)
  632. term.setCursor(x,y)
  633. if cf >=0 and cb >=0 then
  634. local fg = gpu.getForeground()
  635. local bg = gpu.getBackground()
  636. gpu.setForeground(cf)
  637. gpu.setBackground(cb)
  638. printf(s,...)
  639. gpu.setForeground(fg)
  640. gpu.setBackground(bg)
  641. elseif cb <0 and cf>=0 then
  642. local fg = gpu.getForeground()
  643. gpu.setForeground(cf)
  644. printf(s,...)
  645. gpu.setForeground(fg)
  646. elseif cf < 0 and cb >= 0 then
  647. local bg = gpu.getBackground()
  648. printf(s,...)
  649. gpu.setBackground(bg)
  650. else
  651. local fg = gpu.getForeground()
  652. gpu.setForeground(color.white)
  653. printf(s,...)
  654. gpu.setForeground(fg)
  655. end
  656. end
  657.  
  658. local function getCord(param)
  659. param.x,param.y = term.getCursor()
  660. return param.x,param.y
  661. end
  662.  
  663. local function guiClear(y)
  664. local fg = gpu.getForeground()
  665. local bg = gpu.getBackground()
  666. gpu.setForeground(color.white)
  667. gpu.setBackground(color.grey)
  668. for i=y+3,3,-1 do
  669. term.setCursor(1,i)
  670. term.clearLine()
  671. end
  672. gpu.setForeground(fg)
  673. gpu.setBackground(bg)
  674. end
  675.  
  676. local function setActive(index)
  677. if not reactors[index] then
  678. return
  679. end
  680. activeIndex = index
  681. reactor = reactors[index].reactor
  682. upgate = reactors[index].upgate
  683. downgate = reactors[index].downgate
  684. autostate = reactors[index].autostate
  685. temprise = reactors[index].temprise
  686. maxGenerationRate = reactors[index].maxGenerationRate
  687. end
  688.  
  689. local function syncActive()
  690. if not reactors[activeIndex] then
  691. return
  692. end
  693. reactors[activeIndex].autostate = autostate
  694. reactors[activeIndex].temprise = temprise
  695. reactors[activeIndex].maxGenerationRate = maxGenerationRate
  696. end
  697.  
  698. local function drawHeader(title)
  699. local x = gpu.getResolution()
  700. gpu.setBackground(color.grey)
  701. gpu.setForeground(color.white)
  702. term.clear()
  703. gpu.setBackground(color.panel)
  704. gpu.setForeground(color.white)
  705. term.clearLine()
  706. printf(" %s",title)
  707. gpu.setForeground(color.green)
  708. printf(" | Разработал : GintaRus")
  709. gpu.setForeground(color.white)
  710. printf("\n")
  711. gpu.setBackground(color.grey)
  712. gpu.setForeground(color.white)
  713. term.clearLine()
  714. gpu.setBackground(0xFF0000)
  715. gpu.set(x-2,1," X ")
  716. gpu.setBackground(color.grey)
  717. gpu.setForeground(color.white)
  718. return x
  719. end
  720.  
  721. local function drawSeparator(x)
  722. gpu.setBackground(color.grey)
  723. gpu.setForeground(color.dim)
  724. gpu.fill(1,3,x,1,"-")
  725. gpu.setBackground(color.grey)
  726. gpu.setForeground(color.white)
  727. term.setCursor(1,4)
  728. end
  729.  
  730. local function makeButton(x,y,text)
  731. term.setCursor(x,y)
  732. local fg = gpu.getForeground()
  733. local bg = gpu.getBackground()
  734. gpu.setBackground(color.blue)
  735. gpu.setForeground(color.white)
  736. printf(text)
  737. gpu.setBackground(bg)
  738. gpu.setForeground(fg)
  739.  
  740. end
  741.  
  742. local function makePowerButton(x,y,text,bg,fg)
  743. term.setCursor(x,y)
  744. local rfg = gpu.getForeground()
  745. local rbg = gpu.getBackground()
  746. gpu.setBackground(bg)
  747. gpu.setForeground(fg)
  748. printf(text)
  749. gpu.setBackground(rbg)
  750. gpu.setForeground(rfg)
  751. end
  752.  
  753. local function getGateFlow(gate)
  754. if not gate then
  755. return 0
  756. end
  757. local ok, value = pcall(gate.getSignalLowFlow)
  758. if ok and type(value) == "number" then
  759. return value
  760. end
  761. local ok2, value2 = pcall(gate.getFlow)
  762. if ok2 and type(value2) == "number" then
  763. return value2
  764. end
  765. return 0
  766. end
  767.  
  768. local function ensureFlowInit(r, force)
  769. if not r or (r.flowInit and not force) then
  770. return
  771. end
  772. pcall(r.upgate.setSignalLowFlow, r.upgate, 535000)
  773. r.flowInit = true
  774. flowInitByAdr[r.reactorAdr] = true
  775. if reactors[activeIndex] and reactors[activeIndex].reactorAdr == r.reactorAdr then
  776. infcord.flow.value = 535000
  777. if handleMain and infcord.flow.x then
  778. guiWrite(infcord.flow.x,infcord.flow.y,color.red,color.grey,"%s",numformat(infcord.flow.value))
  779. end
  780. end
  781. end
  782.  
  783. local function statusText(status)
  784. if status == "online" then
  785. return "ВКЛ"
  786. elseif status == "offline" then
  787. return "ВЫК"
  788. elseif status == "charging" then
  789. return "ЗАР"
  790. elseif status == "charged" then
  791. return "ГОТ"
  792. elseif status == "stopping" then
  793. return "СТП"
  794. end
  795. return status
  796. end
  797.  
  798. local function show(fc,bc,param)
  799. local fg = gpu.getForeground()
  800. local bg = gpu.getBackground()
  801. term.setCursor(param.x,param.y)
  802. gpu.setForeground(fc)
  803. gpu.setBackground(bc)
  804. local st = " "
  805. for i = 0,#tostring(param.value) do
  806. st=st.." "
  807. end
  808. gpu.set(param.x,param.y,st)
  809. printf("%d",param.value)
  810. gpu.setForeground(fg)
  811. gpu.setBackground(bg)
  812. end
  813.  
  814. local function numformat(n)
  815. local s = tostring(n)
  816. if n >= 1000 and n < 1000000 then
  817. local t = s:sub(1,#s-3)
  818. local e = s:sub(#s-2)
  819. s = t.." "..e.." "
  820. return s
  821. elseif n >= 1000000 then
  822. local m = s:sub(1,#s-6)
  823. local t = s:sub(#s-5,#s-3)
  824. local e = s:sub(#s-2)
  825. s = m.." "..t.." "..e.." "
  826. return s
  827. else
  828. s=s.." "
  829. return s
  830. end
  831. end
  832.  
  833. local function overviewCols(x)
  834. local cols
  835. if x >= 120 then
  836. cols = {status=6,temp=15,fuel=27,profit=43,gen=60,flow=77}
  837. else
  838. cols = {status=5,temp=11,fuel=20,profit=33,gen=48,flow=63}
  839. end
  840. local ctrl = cols.flow + 12
  841. if ctrl < 65 then
  842. ctrl = 65
  843. end
  844. if ctrl + 16 > x then
  845. ctrl = math.max(65, x - 16)
  846. end
  847. cols.ctrl = ctrl
  848. return cols
  849. end
  850.  
  851. local function coreformat()
  852. local num = com.draconic_rf_storage.getEnergyStored()
  853. if num > 10^12 then
  854. return string.format(" Накоплено в ядре: %0.3f T \n",num/10^12)
  855. elseif num > 10^9 then
  856. return string.format(" Накоплено в ядре: %0.3f B \n",num/10^9)
  857. elseif num > 10^6 then
  858. return string.format(" Накоплено в ядре: %0.3f M \n",num/10^6)
  859. elseif num > 10^3 then
  860. return string.format(" Накоплено в ядре: %0.3f K \n",num/10^3)
  861. else
  862. return string.format(" Накоплено в ядре: %d \n",num)
  863. end
  864. end
  865.  
  866. -- Анализ и корректировка запомненных адресов
  867. local function checkButtons()
  868. local ok, inf = pcall(reactor.getReactorInfo)
  869. if not ok or type(inf) ~= "table" then
  870. return
  871. end
  872. infcord.status.value = inf.status
  873. if infcord.status.value == "offline" then
  874. guiWrite(button.charge.x,button.charge.y,color.skyblue,color.black,"%s",button.charge.name)
  875. button.charge.visible = true
  876. elseif infcord.status.value == "stopping" then
  877. if (inf.energySaturation/inf.maxEnergySaturation)*100 >=50 and (inf.fieldStrength/inf.maxFieldStrength)*100 >= 50 and inf.temperature > 2000 then
  878. guiWrite(button.start.x,button.start.y,color.green,color.black,"%s",button.start.name)
  879. button.start.visible = true
  880. elseif infcord.status.value ~= "charging" then
  881. guiWrite(button.charge.x,button.charge.y,color.skyblue,color.black,"%s",button.charge.name)
  882. button.charge.visible = true
  883. end
  884. elseif infcord.status.value == "online" or infcord.status.value == "charging" then
  885. guiWrite(button.stop.x,button.stop.y,color.red,color.black,"%s",button.stop.name)
  886. button.stop.visible = true
  887. elseif infcord.status.value == "charged" then
  888. guiWrite(button.start.x,button.start.y,color.green,color.black,"%s",button.start.name)
  889. button.start.visible = true
  890. guiWrite(button.stop.x,button.stop.y,color.red,color.black,"%s",button.stop.name)
  891. button.stop.visible = true
  892. end
  893. end
  894. -- Инициализация программы, анализ и настройка всей технической белеберды
  895. local function screenStart()
  896. handleMain = false
  897. handleOptions = false
  898. handleStart = true
  899. local x = drawHeader("HiTech Classic is the best (Preparation)")
  900. printf("Это страница для настройки программы при первом запуске или после сбоя")
  901. drawSeparator(x)
  902. local hadFile = readReactorsFile() ~= nil
  903. while true do
  904. if not ops then return end
  905. reactors = buildReactors()
  906. if reactors and #reactors > 0 then
  907. setActive(1)
  908. if not hadFile then
  909. screenAssign()
  910. return
  911. end
  912. break
  913. end
  914. if not hadFile then
  915. local reactorsList = listAddresses("draconic_reactor")
  916. local gates = listAddresses("flux_gate")
  917. if #reactorsList > 0 and #gates >= 2 then
  918. reactors = reactors or {}
  919. screenOverview()
  920. return
  921. end
  922. end
  923. guiClear(2)
  924. printf("Подключите реакторы и флюкс-гейты (2 гейта на каждый реактор)\n")
  925. printf("Максимум: %d реакторов. Адреса можно сохранить в %s\n",MAX_REACTORS,reactorsFile)
  926. os.sleep(1)
  927. end
  928. end
  929. -- Экран настроек
  930. local function screenOptions()
  931. handleMain = false
  932. handleStart = false
  933. handleOptions = true
  934. handleOverview = false
  935. handleAssign = false
  936. canedit = true
  937. canclose = true
  938. local x = drawHeader("HiTech Classic is the best (Options)")
  939. menuItem.save.x,menuItem.save.y =term.getCursor()
  940. gpu.setForeground(color.blue)
  941. printf(menuItem.save.name)
  942. menuItem.save.w = textWidth(menuItem.save.name)
  943. menuItem.cancel.x,menuItem.cancel.y =term.getCursor()
  944. printf(menuItem.cancel.name)
  945. menuItem.cancel.w = textWidth(menuItem.cancel.name)
  946. menuItem.optionsBack.x,menuItem.optionsBack.y =term.getCursor()
  947. printf(menuItem.optionsBack.name)
  948. menuItem.optionsBack.w = textWidth(menuItem.optionsBack.name)
  949. gpu.setForeground(color.white)
  950. drawSeparator(x)
  951. printf(" Интервал для щелчка: ")
  952. OptionDefault["x"],OptionDefault["y"] = term.getCursor()
  953. printf("%d\n",OptionDefault.value)
  954. printf(" Интервал для CTRL: ")
  955. OptionCtrl["x"],OptionCtrl["y"] = term.getCursor()
  956. printf("%d\n",OptionCtrl.value)
  957. printf(" Интервал для SHIFT: ")
  958. OptionShift["x"],OptionShift["y"] = term.getCursor()
  959. printf("%d\n",OptionShift.value)
  960. printf(" Интервал для CTRL+SHIFT: ")
  961. OptionCtrlShift["x"],OptionCtrlShift["y"] = term.getCursor()
  962. printf("%d\n",OptionCtrlShift.value)
  963. printf(" Уровень щитов: ")
  964. OptionShield["x"],OptionShield["y"] = term.getCursor()
  965. printf("%d\n",OptionShield.value)
  966. printf(" Отключение по топливу (%%): ")
  967. OptionFuelStop["x"],OptionFuelStop["y"] = term.getCursor()
  968. printf("%d\n",OptionFuelStop.value)
  969. end
  970. -- Назначение гейтов
  971. local function clearPromptLine()
  972. local _, y = term.getCursor()
  973. if y > 1 then
  974. term.setCursor(1, y - 1)
  975. term.clearLine()
  976. term.setCursor(1, y - 1)
  977. end
  978. end
  979.  
  980. local function readIndex(prompt,max,used)
  981. while true do
  982. printf("%s",prompt)
  983. local input = term.read(false,false) or ""
  984. clearPromptLine()
  985. local num = tonumber(input:match("%d+"))
  986. if num and num >= 1 and num <= max and not used[num] then
  987. return num
  988. end
  989. printf("Неверный выбор, попробуйте снова.\n")
  990. end
  991. end
  992.  
  993. local function readIndexAllowZero(prompt,max)
  994. while true do
  995. printf("%s",prompt)
  996. local input = term.read(false,false) or ""
  997. clearPromptLine()
  998. local lower = input:lower()
  999. if lower:find("назад") or lower:find("back") or lower:match("^b%s*$") then
  1000. return -1
  1001. end
  1002. local num = tonumber(input:match("%d+"))
  1003. if num and num >= 0 and num <= max then
  1004. return num
  1005. end
  1006. printf("Неверный выбор, попробуйте снова.\n")
  1007. end
  1008. end
  1009.  
  1010. function screenAssign()
  1011. handleMain = false
  1012. handleStart = false
  1013. handleOptions = false
  1014. handleOverview = false
  1015. handleAssign = true
  1016. local x = drawHeader("HiTech Classic is the best (Гейты)")
  1017. drawSeparator(x)
  1018. assignUi.reactors = {}
  1019. assignUi.gates = {}
  1020. assignUi.gateAddrs = {}
  1021. assignUi.reactorAddrs = {}
  1022. assignUi.gateUse = {}
  1023. assignUi.selectedAdr = nil
  1024. gpu.setBackground(color.grey)
  1025. gpu.setForeground(color.white)
  1026. gpu.fill(1,4,x,21," ")
  1027. term.setCursor(1,2)
  1028. menuItem.back.x,menuItem.back.y = term.getCursor()
  1029. assignUi.back.x,assignUi.back.y,assignUi.back.w = menuItem.back.x,menuItem.back.y,textWidth(menuItem.back.name)
  1030. gpu.setForeground(color.blue)
  1031. printf(menuItem.back.name)
  1032. menuItem.back.w = textWidth(menuItem.back.name)
  1033. menuItem.reset.x,menuItem.reset.y = term.getCursor()
  1034. assignUi.reset = {x=menuItem.reset.x,y=menuItem.reset.y,w=textWidth(menuItem.reset.name)}
  1035. if assignState.reactorIndex then
  1036. gpu.setForeground(color.blue)
  1037. else
  1038. gpu.setForeground(color.dim)
  1039. end
  1040. printf(menuItem.reset.name)
  1041. menuItem.reset.w = textWidth(menuItem.reset.name)
  1042. gpu.setForeground(color.white)
  1043. local reactorsList = listAddresses("draconic_reactor")
  1044. local gates = listAddresses("flux_gate")
  1045. assignUi.gateAddrs = gates
  1046. assignUi.reactorAddrs = reactorsList
  1047. if #reactorsList == 0 or #gates < 2 then
  1048. printf("Недостаточно реакторов или флюкс-гейтов.\n")
  1049. os.sleep(1)
  1050. screenOverview()
  1051. return
  1052. end
  1053. local count = math.min(#reactorsList, MAX_REACTORS)
  1054. term.setCursor(2,4)
  1055. if assignState.step == "reactor" then
  1056. printf("Выберите реактор")
  1057. elseif assignState.step == "shield" then
  1058. printf("Выберите гейт ЩИТЫ для R%d",assignState.reactorIndex or 0)
  1059. else
  1060. printf("Выберите гейт ВЫВОД для R%d",assignState.reactorIndex or 0)
  1061. end
  1062. if assignState.message then
  1063. term.setCursor(2,3)
  1064. guiWrite(2,3,color.red,-1,"%s",assignState.message)
  1065. assignState.message = nil
  1066. end
  1067.  
  1068. term.setCursor(2,5)
  1069. printf("Реакторы:")
  1070. local rowY = 6
  1071. for i=1,count do
  1072. term.setCursor(2,rowY)
  1073. local label = string.format("%d) %s",i,reactorsList[i])
  1074. if assignState.reactorIndex == i then
  1075. guiWrite(2,rowY,color.black,color.blue,"%s",label)
  1076. else
  1077. guiWrite(2,rowY,color.white,-1,"%s",label)
  1078. end
  1079. assignUi.reactors[i] = {x=2,y=rowY,w=textWidth(label)}
  1080. rowY = rowY + 1
  1081. end
  1082.  
  1083. local entries = readReactorsFile() or {}
  1084. local gateUse = {}
  1085. for i=1,#entries do
  1086. gateUse[entries[i].upAdr] = entries[i].reactorAdr
  1087. gateUse[entries[i].downAdr] = entries[i].reactorAdr
  1088. end
  1089. assignUi.gateUse = gateUse
  1090. local selectedAdr = assignState.reactorIndex and reactorsList[assignState.reactorIndex] or nil
  1091. assignUi.selectedAdr = selectedAdr
  1092. local selectedEntry = nil
  1093. if selectedAdr then
  1094. for i=1,#entries do
  1095. if entries[i].reactorAdr == selectedAdr then
  1096. selectedEntry = entries[i]
  1097. break
  1098. end
  1099. end
  1100. end
  1101. assignUi.selectedEntry = selectedEntry
  1102.  
  1103. term.setCursor(40,5)
  1104. printf("Гейты:")
  1105. local gateY = 6
  1106. for i=1,#gates do
  1107. if gateY > 24 then
  1108. break
  1109. end
  1110. term.setCursor(40,gateY)
  1111. local label = string.format("%d) %s",i,gates[i])
  1112. local colorGate = color.dim
  1113. if selectedAdr then
  1114. if selectedEntry and (gates[i] == selectedEntry.upAdr or gates[i] == selectedEntry.downAdr) then
  1115. colorGate = color.green
  1116. elseif assignState.shieldGateIdx == i or assignState.outGateIdx == i then
  1117. colorGate = color.green
  1118. elseif gateUse[gates[i]] and gateUse[gates[i]] ~= selectedAdr then
  1119. colorGate = color.red
  1120. else
  1121. colorGate = color.dim
  1122. end
  1123. end
  1124. guiWrite(40,gateY,colorGate,-1,"%s",label)
  1125. assignUi.gates[i] = {x=40,y=gateY,w=textWidth(label)}
  1126. gateY = gateY + 1
  1127. end
  1128. end
  1129.  
  1130. local function refreshReactors(openAssign)
  1131. autostateByAdr = {}
  1132. flowInitByAdr = {}
  1133. autoWaitTempByAdr = {}
  1134. chargeRequestByAdr = {}
  1135. for i=1,#reactors do
  1136. local r = reactors[i]
  1137. autostateByAdr[r.reactorAdr] = r.autostate
  1138. flowInitByAdr[r.reactorAdr] = r.flowInit
  1139. chargeRequestByAdr[r.reactorAdr] = r.chargeRequested
  1140. end
  1141. syncActive()
  1142. local prevAdr = reactors[activeIndex] and reactors[activeIndex].reactorAdr
  1143. reactors = buildReactors() or reactors
  1144. local idx = 1
  1145. if pendingActiveReactorAdr then
  1146. for i=1,#reactors do
  1147. if reactors[i].reactorAdr == pendingActiveReactorAdr then
  1148. idx = i
  1149. break
  1150. end
  1151. end
  1152. pendingActiveReactorAdr = nil
  1153. elseif lastAddedReactorAdr then
  1154. for i=1,#reactors do
  1155. if reactors[i].reactorAdr == lastAddedReactorAdr then
  1156. idx = i
  1157. break
  1158. end
  1159. end
  1160. lastAddedReactorAdr = nil
  1161. elseif prevAdr then
  1162. for i=1,#reactors do
  1163. if reactors[i].reactorAdr == prevAdr then
  1164. idx = i
  1165. break
  1166. end
  1167. end
  1168. end
  1169. setActive(idx)
  1170. if openAssign and newEntriesAdded then
  1171. resetAssignState()
  1172. screenAssign()
  1173. return
  1174. end
  1175. if handleMain then
  1176. screenMain()
  1177. else
  1178. screenOverview()
  1179. end
  1180. end
  1181.  
  1182. local function resetAssignState()
  1183. assignState.reactorIndex = nil
  1184. assignState.shieldGateIdx = nil
  1185. assignState.outGateIdx = nil
  1186. assignState.step = "reactor"
  1187. end
  1188.  
  1189. local function saveAssignedGates(reactorIndex, shieldIdx, outIdx)
  1190. local reactorsList = listAddresses("draconic_reactor")
  1191. local gates = listAddresses("flux_gate")
  1192. if not reactorsList[reactorIndex] or not gates[shieldIdx] or not gates[outIdx] then
  1193. return false
  1194. end
  1195. local entries = readReactorsFile() or {}
  1196. local updated = false
  1197. for i=1,#entries do
  1198. if entries[i].reactorAdr == reactorsList[reactorIndex] then
  1199. entries[i].upAdr = gates[outIdx]
  1200. entries[i].downAdr = gates[shieldIdx]
  1201. updated = true
  1202. break
  1203. end
  1204. end
  1205. if not updated then
  1206. entries[#entries+1] = {
  1207. reactorAdr = reactorsList[reactorIndex],
  1208. upAdr = gates[outIdx],
  1209. downAdr = gates[shieldIdx]
  1210. }
  1211. end
  1212. if #entries > MAX_REACTORS then
  1213. local trimmed = {}
  1214. for i=1,MAX_REACTORS do
  1215. trimmed[i] = entries[i]
  1216. end
  1217. entries = trimmed
  1218. end
  1219. writeReactorsFile(entries)
  1220. pendingActiveReactorAdr = reactorsList[reactorIndex]
  1221. return true
  1222. end
  1223.  
  1224. local function clearAssignedGates(reactorIndex)
  1225. local reactorsList = listAddresses("draconic_reactor")
  1226. if not reactorsList[reactorIndex] then
  1227. return false
  1228. end
  1229. local entries = readReactorsFile() or {}
  1230. local newEntries = {}
  1231. for i=1,#entries do
  1232. if entries[i].reactorAdr ~= reactorsList[reactorIndex] then
  1233. newEntries[#newEntries+1] = entries[i]
  1234. end
  1235. end
  1236. writeReactorsFile(newEntries)
  1237. return true
  1238. end
  1239. -- Экран обзора реакторов
  1240. screenOverview = function()
  1241. handleMain = false
  1242. handleStart = false
  1243. handleOptions = false
  1244. handleOverview = true
  1245. handleAssign = false
  1246. local x = drawHeader("HiTech Classic is the best")
  1247. reactors = reactors or {}
  1248. local cols = overviewCols(x)
  1249. term.setCursor(1,2)
  1250. menuItem.options.x,menuItem.options.y = term.getCursor()
  1251. gpu.setForeground(color.blue)
  1252. printf(menuItem.options.name)
  1253. menuItem.options.w = textWidth(menuItem.options.name)
  1254. gpu.setForeground(color.white)
  1255. menuItem.overview.x,menuItem.overview.y = term.getCursor()
  1256. gpu.setForeground(color.blue)
  1257. printf(menuItem.overview.name)
  1258. menuItem.overview.w = textWidth(menuItem.overview.name)
  1259. gpu.setForeground(color.white)
  1260. menuItem.refresh.x,menuItem.refresh.y = term.getCursor()
  1261. gpu.setForeground(color.blue)
  1262. printf(menuItem.refresh.name)
  1263. menuItem.refresh.w = textWidth(menuItem.refresh.name)
  1264. gpu.setForeground(color.white)
  1265. menuItem.gates.x,menuItem.gates.y = term.getCursor()
  1266. gpu.setForeground(color.blue)
  1267. printf(menuItem.gates.name)
  1268. menuItem.gates.w = textWidth(menuItem.gates.name)
  1269. gpu.setForeground(color.white)
  1270. for i=1,#reactors do
  1271. local label = string.format("[R%d]",i)
  1272. reactors[i].tab.x,reactors[i].tab.y = term.getCursor()
  1273. reactors[i].tab.w = textWidth(label)
  1274. if i == activeIndex then
  1275. guiWrite(reactors[i].tab.x,reactors[i].tab.y,color.black,color.orange,"%s",label)
  1276. else
  1277. guiWrite(reactors[i].tab.x,reactors[i].tab.y,color.blue,color.white,"%s",label)
  1278. end
  1279. printf(" ")
  1280. end
  1281. drawSeparator(x)
  1282. gpu.setBackground(color.grey)
  1283. gpu.setForeground(color.white)
  1284. gpu.fill(1,4,x,21," ")
  1285. if #reactors == 0 then
  1286. term.setCursor(2,5)
  1287. printf("Нет настроенных реакторов.")
  1288. term.setCursor(2,6)
  1289. printf("Откройте \"Гейты\" и назначьте гейты.")
  1290. return
  1291. end
  1292.  
  1293. gpu.setBackground(color.panel)
  1294. gpu.setForeground(color.white)
  1295. gpu.fill(2,4,x-2,6," ")
  1296. term.setCursor(3,4)
  1297. printf("Сводка")
  1298. term.setCursor(3,5)
  1299. printf("Суммарная прибыль:")
  1300. term.setCursor(28,5)
  1301. getCord(summaryProfitCord)
  1302. term.setCursor(3,6)
  1303. printf("Суммарная EU:")
  1304. term.setCursor(28,6)
  1305. getCord(summaryEuCord)
  1306. term.setCursor(3,7)
  1307. printf("Тратим на щиты RF:")
  1308. term.setCursor(28,7)
  1309. getCord(summaryShieldCord)
  1310. term.setCursor(3,8)
  1311. printf("Суммарная выработка:")
  1312. term.setCursor(28,8)
  1313. getCord(summaryGenCord)
  1314. term.setCursor(3,9)
  1315. printf("Максимум прибыли RF/EU:")
  1316. term.setCursor(28,9)
  1317. getCord(summaryMaxProfitCord)
  1318. local autoX = math.max(40, x - 33)
  1319. term.setCursor(autoX,4)
  1320. printf("Выключены автоматически:")
  1321. term.setCursor(autoX,5)
  1322. getCord(autoStoppedCord)
  1323.  
  1324. gpu.setBackground(color.dark)
  1325. gpu.setForeground(color.white)
  1326. gpu.fill(2,11,x-2,1," ")
  1327. term.setCursor(2,11)
  1328. printf("#")
  1329. term.setCursor(cols.status,11)
  1330. printf("СТАТУС")
  1331. term.setCursor(cols.temp,11)
  1332. printf(" ТЕМП")
  1333. term.setCursor(cols.fuel,11)
  1334. printf("ТОПЛИВО")
  1335. term.setCursor(cols.profit,11)
  1336. printf("ПРИБЫЛЬ")
  1337. term.setCursor(cols.gen,11)
  1338. printf("ГЕН")
  1339. term.setCursor(cols.flow,11)
  1340. printf("ПОТОК")
  1341. term.setCursor(cols.ctrl,11)
  1342. printf("УПР")
  1343. gpu.setForeground(color.dim)
  1344. gpu.fill(2,12,x-2,1,"-")
  1345. gpu.setForeground(color.white)
  1346. gpu.setBackground(color.grey)
  1347. local rowY = 13
  1348. for i=1,#reactors do
  1349. local r = reactors[i]
  1350. term.setCursor(2,rowY)
  1351. printf("#%d",i)
  1352. term.setCursor(cols.status,rowY)
  1353. r.row.status = {x=cols.status,y=rowY}
  1354. term.setCursor(cols.temp,rowY)
  1355. r.row.temp = {x=cols.temp,y=rowY}
  1356. term.setCursor(cols.fuel,rowY)
  1357. r.row.fuel = {x=cols.fuel,y=rowY}
  1358. term.setCursor(cols.profit,rowY)
  1359. r.row.profit = {x=cols.profit,y=rowY}
  1360. term.setCursor(cols.gen,rowY)
  1361. r.row.gen = {x=cols.gen,y=rowY}
  1362. term.setCursor(cols.flow,rowY)
  1363. r.row.flow = {x=cols.flow,y=rowY}
  1364. term.setCursor(cols.ctrl,rowY)
  1365. r.control = r.control or {}
  1366. r.control.dec = {x=cols.ctrl,y=rowY,w=3}
  1367. term.setCursor(cols.ctrl + 4,rowY)
  1368. r.control.inc = {x=cols.ctrl + 4,y=rowY,w=3}
  1369. term.setCursor(cols.ctrl + 8,rowY)
  1370. r.control.auto = {x=cols.ctrl + 8,y=rowY,w=4}
  1371. term.setCursor(cols.ctrl + 13,rowY)
  1372. r.powerBtn.x,r.powerBtn.y = term.getCursor()
  1373. r.powerBtn.w = 3
  1374. rowY = rowY + 1
  1375. end
  1376. end
  1377. -- Инициализация главного экрана
  1378. local function screenMain()
  1379. handleOptions = false
  1380. handleStart = false
  1381. handleMain = true
  1382. handleOverview = false
  1383. handleAssign = false
  1384. if not reactor or not upgate or not downgate then
  1385. screenOverview()
  1386. return
  1387. end
  1388. local x = drawHeader("HiTech Classic is the best")
  1389. local ok, inf = pcall(reactor.getReactorInfo)
  1390. if not ok or type(inf) ~= "table" then
  1391. refreshReactors(false)
  1392. screenOverview()
  1393. return
  1394. end
  1395. infcord.status.value = inf.status
  1396. menuItem.options.x,menuItem.options.y =term.getCursor()
  1397. gpu.setForeground(color.blue)
  1398. printf(menuItem.options.name)
  1399. menuItem.options.w = textWidth(menuItem.options.name)
  1400. gpu.setForeground(color.white)
  1401. menuItem.overview.x,menuItem.overview.y = term.getCursor()
  1402. gpu.setForeground(color.blue)
  1403. printf(menuItem.overview.name)
  1404. menuItem.overview.w = textWidth(menuItem.overview.name)
  1405. gpu.setForeground(color.white)
  1406. menuItem.refresh.x,menuItem.refresh.y = term.getCursor()
  1407. gpu.setForeground(color.blue)
  1408. printf(menuItem.refresh.name)
  1409. menuItem.refresh.w = textWidth(menuItem.refresh.name)
  1410. gpu.setForeground(color.white)
  1411. menuItem.gates.x,menuItem.gates.y = term.getCursor()
  1412. gpu.setForeground(color.blue)
  1413. printf(menuItem.gates.name)
  1414. menuItem.gates.w = textWidth(menuItem.gates.name)
  1415. gpu.setForeground(color.white)
  1416. for i=1,#reactors do
  1417. local label = string.format("[R%d]",i)
  1418. reactors[i].tab.x,reactors[i].tab.y = term.getCursor()
  1419. reactors[i].tab.w = textWidth(label)
  1420. if i == activeIndex then
  1421. guiWrite(reactors[i].tab.x,reactors[i].tab.y,color.black,color.orange,"%s",label)
  1422. else
  1423. guiWrite(reactors[i].tab.x,reactors[i].tab.y,color.blue,color.white,"%s",label)
  1424. end
  1425. printf(" ")
  1426. end
  1427. guiWrite(x-25,1,color.yellow,color.panel,"Макс. выраб.: ")
  1428. getCord(infcord.maxgen)
  1429. if inf.generationRate > maxGenerationRate then
  1430. maxGenerationRate = inf.generationRate
  1431. end
  1432. guiWrite(infcord.maxgen.x,infcord.maxgen.y,color.green,color.panel,"%s",numformat(maxGenerationRate))
  1433. drawSeparator(x)
  1434. gpu.setBackground(color.panel)
  1435. gpu.setForeground(color.blue)
  1436. printf(" ПАРАМЕТРЫ ")
  1437. term.setCursor(30,4)
  1438. printf(" УПРАВЛЕНИЕ ")
  1439. gpu.setBackground(color.grey)
  1440. gpu.setForeground(color.white)
  1441. term.setCursor(1,6)
  1442. gpu.setBackground(color.panel)
  1443. printf(" Температура: ")
  1444. gpu.setBackground(color.grey)
  1445. printf(" ")
  1446. getCord(infcord.temp)
  1447. guiWrite(infcord.temp.x,infcord.temp.y,-1,-1,"%0.2f\n",inf.temperature)
  1448. printf(" Вырабатывает: ")
  1449. getCord(infcord.generation)
  1450. guiWrite(infcord.generation.x,infcord.generation.y,-1,-1,"%s \n",numformat(inf.generationRate))
  1451. gpu.setBackground(color.panel)
  1452. printf (" Поток: ")
  1453. gpu.setBackground(color.grey)
  1454. printf(" ")
  1455. getCord(infcord.flow)
  1456. infcord.flow.value = upgate.getFlow()
  1457. guiWrite(infcord.flow.x,infcord.flow.y,-1,-1,"%s ",numformat(infcord.flow.value))
  1458. getCord(button.add)
  1459. makeButton(button.add.x + 4, button.add.y ,button.add.name)
  1460. getCord(button.sub)
  1461. makeButton(button.sub.x+2,button.sub.y,button.sub.name)
  1462.  
  1463. printf("\n")
  1464. printf (" Итоговая мосч: ")
  1465. getCord(infcord.puregen)
  1466. guiWrite(infcord.puregen.x,infcord.puregen.y,-1,-1,"%s \n",numformat(inf.generationRate - downgate.getFlow()))
  1467. gpu.setBackground(color.panel)
  1468. printf (" Поглощает: ")
  1469. gpu.setBackground(color.grey)
  1470. printf(" ")
  1471. getCord(infcord.drain)
  1472. guiWrite(infcord.drain.x,infcord.drain.y,-1,-1,"%s \n",numformat(downgate.getFlow()))
  1473.  
  1474. printf (" Мощность поля: ")
  1475. getCord(infcord.fstrth)
  1476. if inf.maxFieldStrength > 0 then
  1477. 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)
  1478. else
  1479. guiWrite(infcord.fstrth.x,infcord.fstrth.y,-1,-1,"0 / 0 (0 %%) \n")
  1480. end
  1481. gpu.setBackground(color.panel)
  1482. printf (" Насыщенность: ")
  1483. gpu.setBackground(color.grey)
  1484. printf(" ")
  1485. getCord(infcord.esturn)
  1486. if inf.maxEnergySaturation > 0 then
  1487. guiWrite(infcord.esturn.x,infcord.esturn.y,-1,-1,"%d / %d (%0.2f %%) \n",inf.energySaturation,inf.maxEnergySaturation,(inf.energySaturation/inf.maxEnergySaturation)*100)
  1488. else
  1489. guiWrite(infcord.esturn.x,infcord.esturn.y,-1,-1,"0 / 0 (0 %%) \n")
  1490. end
  1491. printf (" Топливо: ")
  1492. getCord(infcord.fuel)
  1493.  
  1494. if inf.fuelConversion/inf.maxFuelConversion < 0.78 then
  1495. guiWrite(infcord.fuel.x,infcord.fuel.y,-1,-1,"%d / %d (%0.2f %%) \n",inf.fuelConversion,inf.maxFuelConversion,(inf.fuelConversion/inf.maxFuelConversion)*100)
  1496. else
  1497. if inf.maxFuelConversion > 0 then
  1498. if inf.status == "online" or inf.status == "charging" or inf.status == "charged" then
  1499. guiWrite(infcord.fuel.x,infcord.fuel.y,color.red,-1,"%d / %d (%0.2f %%) Критический уровень топлива\n",inf.fuelConversion,inf.maxFuelConversion,(inf.fuelConversion/inf.maxFuelConversion)*100)
  1500. else
  1501. guiWrite(infcord.fuel.x,infcord.fuel.y,-1,-1,"%d / %d (%0.2f %%) Критический уровень топлива\n",inf.fuelConversion,inf.maxFuelConversion,(inf.fuelConversion/inf.maxFuelConversion)*100)
  1502. end
  1503. else
  1504. guiWrite(infcord.fuel.x,infcord.fuel.y,-1,-1,"0 / 0 (0 %%) \n")
  1505. end
  1506. end
  1507. gpu.setBackground(color.panel)
  1508. printf (" Расход топлива: ")
  1509. gpu.setBackground(color.grey)
  1510. printf(" ")
  1511. getCord(infcord.fuelconv)
  1512. guiWrite(infcord.fuelconv.x,infcord.fuelconv.y,-1,-1,"%d\n",inf.fuelConversionRate)
  1513.  
  1514. getCord(infcord.core)
  1515. if com.isAvailable("draconic_rf_storage") then
  1516. guiWrite(infcord.core.x,infcord.core.y,-1,-1,coreformat())
  1517. end
  1518. printf("\n")
  1519. button.stop.x,button.stop.y = term.getCursor()
  1520. button.start.x,button.start.y = button.stop.x,button.stop.y + 1
  1521. button.charge.x,button.charge.y = button.stop.x,button.stop.y + 2
  1522. button.stop.w = textWidth(button.stop.name)
  1523. button.start.w = textWidth(button.start.name)
  1524. button.charge.w = textWidth(button.charge.name)
  1525. term.setCursor(button.stop.x, button.stop.y + 3)
  1526. printf(" Автономный режим: ")
  1527. getCord(button.autoon)
  1528. getCord(button.autooff)
  1529. if not autostate then
  1530. guiWrite(button.autooff.x,button.autooff.y,color.red,color.black,"%s\n",button.autooff.name)
  1531. else
  1532. guiWrite(button.autoon.x,button.autoon.y,color.green,color.black,"%s\n",button.autoon.name)
  1533. end
  1534. checkButtons()
  1535.  
  1536. end
  1537. -- Обновление обзора реакторов
  1538. local function refreshOverview()
  1539. if not handleOverview then
  1540. return
  1541. end
  1542. if not reactors or #reactors == 0 then
  1543. return
  1544. end
  1545. gpu.setForeground(color.white)
  1546. local stopPct = cfg.fuelStopPct or 98
  1547. local totalGen = 0
  1548. local totalProfit = 0
  1549. local totalShield = 0
  1550. local maxProfit = 0
  1551. gpu.setBackground(color.grey)
  1552. for i=1,#reactors do
  1553. local r = reactors[i]
  1554. local ok, inf = pcall(r.reactor.getReactorInfo)
  1555. if not ok or type(inf) ~= "table" then
  1556. guiWrite(r.row.status.x,r.row.status.y,color.red,-1,"ERR")
  1557. guiWrite(r.row.temp.x,r.row.temp.y,color.red,-1,"----")
  1558. guiWrite(r.row.fuel.x,r.row.fuel.y,color.red,-1,"----")
  1559. guiWrite(r.row.profit.x,r.row.profit.y,color.red,-1,"----")
  1560. guiWrite(r.row.gen.x,r.row.gen.y,color.red,-1,"----")
  1561. guiWrite(r.row.flow.x,r.row.flow.y,color.red,-1,"----")
  1562. else
  1563. totalGen = totalGen + inf.generationRate
  1564. guiWrite(r.row.gen.x,r.row.gen.y,-1,-1,"%s",numformat(inf.generationRate))
  1565. local flow = getGateFlow(r.upgate)
  1566. guiWrite(r.row.flow.x,r.row.flow.y,-1,-1,"%s",numformat(flow))
  1567. local shieldFlow = getGateFlow(r.downgate)
  1568. totalShield = totalShield + shieldFlow
  1569. local profit = inf.generationRate - shieldFlow
  1570. totalProfit = totalProfit + profit
  1571. if profit > maxProfit then
  1572. maxProfit = profit
  1573. end
  1574. guiWrite(r.row.profit.x,r.row.profit.y,-1,-1,"%s",numformat(profit))
  1575. local tempColor = color.white
  1576. if inf.temperature >= cfg.tempCriticalEdge then
  1577. tempColor = color.red
  1578. elseif inf.temperature >= cfg.safeModeTempWaitEdge then
  1579. tempColor = color.yellow
  1580. end
  1581. guiWrite(r.row.temp.x,r.row.temp.y,tempColor,-1,"%4.0fC",inf.temperature)
  1582. local fuelPct = 0
  1583. if inf.maxFuelConversion > 0 then
  1584. fuelPct = (inf.fuelConversion/inf.maxFuelConversion)*100
  1585. end
  1586. if autoStopped[r.reactorAdr] and (inf.status == "online" or inf.status == "charging" or inf.status == "charged") then
  1587. autoStopped[r.reactorAdr] = nil
  1588. end
  1589. if fuelPct >= stopPct and (inf.status == "online" or inf.status == "charging" or inf.status == "charged") then
  1590. if not autoStopped[r.reactorAdr] then
  1591. r.reactor.stopReactor()
  1592. autoStopped[r.reactorAdr] = true
  1593. end
  1594. end
  1595. local fuelColor = color.white
  1596. if fuelPct >= 80 then
  1597. fuelColor = color.red
  1598. end
  1599. guiWrite(r.row.fuel.x,r.row.fuel.y,fuelColor,-1,"%5.1f%%",fuelPct)
  1600. local stColor = color.white
  1601. if inf.status == "online" or inf.status == "charging" or inf.status == "charged" then
  1602. stColor = color.green
  1603. elseif inf.status == "offline" or inf.status == "stopping" then
  1604. stColor = color.red
  1605. end
  1606. guiWrite(r.row.status.x,r.row.status.y,stColor,-1,"%s",statusText(inf.status))
  1607. makePowerButton(r.control.dec.x,r.control.dec.y,"[-]",color.dim,color.white)
  1608. makePowerButton(r.control.inc.x,r.control.inc.y,"[+]",color.dim,color.white)
  1609. local autoColor = r.autostate and color.green or color.red
  1610. makePowerButton(r.control.auto.x,r.control.auto.y,"AUTO",autoColor,color.white)
  1611. if inf.status == "online" or inf.status == "charging" or inf.status == "charged" then
  1612. r.powerBtn.action = "stop"
  1613. makePowerButton(r.powerBtn.x,r.powerBtn.y,"PWR",color.red,color.white)
  1614. else
  1615. r.powerBtn.action = "start"
  1616. makePowerButton(r.powerBtn.x,r.powerBtn.y,"PWR",color.green,color.white)
  1617. end
  1618. end
  1619. end
  1620. if totalProfit > maxSummaryProfit then
  1621. maxSummaryProfit = totalProfit
  1622. end
  1623. guiWrite(summaryProfitCord.x,summaryProfitCord.y,color.white,color.panel,"%s",numformat(totalProfit))
  1624. guiWrite(summaryEuCord.x,summaryEuCord.y,color.white,color.panel,"%s",numformat(math.floor(totalProfit/8)))
  1625. guiWrite(summaryShieldCord.x,summaryShieldCord.y,color.white,color.panel,"%s",numformat(totalShield))
  1626. guiWrite(summaryGenCord.x,summaryGenCord.y,color.white,color.panel,"%s",numformat(totalGen))
  1627. guiWrite(summaryMaxProfitCord.x,summaryMaxProfitCord.y,color.white,color.panel,"%s / %s",numformat(maxSummaryProfit),numformat(math.floor(maxSummaryProfit/8)))
  1628. local autoList = {}
  1629. for i=1,#reactors do
  1630. if autoStopped[reactors[i].reactorAdr] then
  1631. autoList[#autoList+1] = "R"..i
  1632. end
  1633. end
  1634. local autoText = "нет"
  1635. if #autoList > 0 then
  1636. autoText = table.concat(autoList, ", ")
  1637. end
  1638. guiWrite(autoStoppedCord.x,autoStoppedCord.y,color.red,-1,"%s",autoText)
  1639. end
  1640. local screen = {}
  1641. screen["overview"] = screenOverview
  1642. screen["detail"] = screenMain
  1643. screen["options"] = screenOptions
  1644.  
  1645. local function editOption(param)
  1646. local rd = true
  1647. while rd do
  1648. gpu.fill(param.x, param.y, #tostring(param.value), 1, " ")
  1649. term.setCursor(param.x,param.y)
  1650.  
  1651. param.value = term.read(false,false)
  1652. local val = tonumber(param.value)
  1653. if val then
  1654. param.value = val
  1655. show(color.black,color.grey,param)
  1656. rd = false
  1657. end
  1658. end
  1659. canedit = true
  1660. canclose = true
  1661. screen.options()
  1662. end
  1663.  
  1664. local function add(n,i)
  1665. n.value=n.value+i
  1666. upgate.setSignalLowFlow(n.value)
  1667. return n.value
  1668. end
  1669.  
  1670. local function sub(n,i)
  1671. term.setCursor(n.x,n.y)
  1672. n.value=n.value-i
  1673. return n.value
  1674. end
  1675. -- Обновление информации на экране + анализ поведения температуры
  1676. local function refreshInfo()
  1677. local ok, inf = pcall(reactor.getReactorInfo)
  1678. if not ok or type(inf) ~= "table" then
  1679. refreshReactors(false)
  1680. screenOverview()
  1681. return
  1682. end
  1683. infcord.status.value = inf.status
  1684. gpu.setForeground(color.white)
  1685. local tbuf1 = inf.temperature
  1686. os.sleep(0.1)
  1687. local ok2, inf2 = pcall(reactor.getReactorInfo)
  1688. local tbuf2 = ok2 and type(inf2) == "table" and inf2.temperature or tbuf1
  1689. if handleMain then
  1690. local stopPct = cfg.fuelStopPct or 98
  1691. if cfg.autoProtectTempEdge and inf.temperature >= cfg.autoProtectTempEdge and not autostate then
  1692. autostate = true
  1693. guiWrite(button.autoon.x,button.autoon.y,color.green,color.black,"%s\n",button.autoon.name)
  1694. end
  1695. syncActive()
  1696. local fuelPct = 0
  1697. if inf.maxFuelConversion > 0 then
  1698. fuelPct = (inf.fuelConversion/inf.maxFuelConversion)*100
  1699. end
  1700. if autoStopped[reactors[activeIndex].reactorAdr] and (inf.status == "online" or inf.status == "charging" or inf.status == "charged") then
  1701. autoStopped[reactors[activeIndex].reactorAdr] = nil
  1702. end
  1703. if fuelPct >= stopPct and (inf.status == "online" or inf.status == "charging" or inf.status == "charged") then
  1704. if not autoStopped[reactors[activeIndex].reactorAdr] then
  1705. reactor.stopReactor()
  1706. autoStopped[reactors[activeIndex].reactorAdr] = true
  1707. end
  1708. end
  1709. if tbuf2>tbuf1 then
  1710. guiWrite(infcord.temp.x,infcord.temp.y,color.red,-1,"%0.2f \n",inf.temperature)
  1711. temprise = true
  1712. elseif tbuf2<tbuf1 then
  1713. guiWrite(infcord.temp.x,infcord.temp.y,color.blue,-1,"%0.2f \n",inf.temperature)
  1714. temprise = false
  1715. else
  1716. if inf.temperature == 2000 then
  1717. guiWrite(infcord.temp.x,infcord.temp.y,-1,-1,"%0.2f \n",inf.temperature)
  1718. end
  1719. end
  1720. guiWrite(infcord.generation.x,infcord.generation.y,-1,-1,"%s\n",numformat(inf.generationRate))
  1721. if inf.generationRate > maxGenerationRate then
  1722. maxGenerationRate = inf.generationRate
  1723. end
  1724. guiWrite(infcord.maxgen.x,infcord.maxgen.y,color.green,color.panel,"%s",numformat(maxGenerationRate))
  1725. infcord.flow.value = upgate.getFlow()
  1726. guiWrite(infcord.flow.x,infcord.flow.y,-1,-1,"%s",numformat(infcord.flow.value))
  1727. guiWrite(infcord.puregen.x,infcord.puregen.y,-1,-1,"%s\n",numformat(inf.generationRate - downgate.getFlow()))
  1728. infcord.drain.value = inf.fieldDrainRate
  1729. guiWrite(infcord.drain.x,infcord.drain.y,-1,-1,"%s\n",numformat(downgate.getFlow()))
  1730. if inf.maxFieldStrength > 0 then
  1731. 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)
  1732. else
  1733. guiWrite(infcord.fstrth.x,infcord.fstrth.y,-1,-1,"0 / 0 (0 %%) \n")
  1734. end
  1735. if inf.maxEnergySaturation > 0 then
  1736. guiWrite(infcord.esturn.x,infcord.esturn.y,-1,-1,"%d / %d (%0.2f %%) \n",inf.energySaturation,inf.maxEnergySaturation,(inf.energySaturation/inf.maxEnergySaturation)*100)
  1737. else
  1738. guiWrite(infcord.esturn.x,infcord.esturn.y,-1,-1,"0 / 0 (0 %%) \n")
  1739. end
  1740. if inf.fuelConversion/inf.maxFuelConversion < 0.78 then
  1741. guiWrite(infcord.fuel.x,infcord.fuel.y,-1,-1,"%d / %d (%0.2f %%) \n",inf.fuelConversion,inf.maxFuelConversion,(inf.fuelConversion/inf.maxFuelConversion)*100)
  1742. else
  1743. if inf.maxFuelConversion > 0 then
  1744. if inf.status == "online" or inf.status == "charging" or inf.status == "charged" then
  1745. guiWrite(infcord.fuel.x,infcord.fuel.y,color.red,-1,"%d / %d (%0.2f %%) Критический уровень топлива\n",inf.fuelConversion,inf.maxFuelConversion,(inf.fuelConversion/inf.maxFuelConversion)*100)
  1746. else
  1747. guiWrite(infcord.fuel.x,infcord.fuel.y,-1,-1,"%d / %d (%0.2f %%) Критический уровень топлива\n",inf.fuelConversion,inf.maxFuelConversion,(inf.fuelConversion/inf.maxFuelConversion)*100)
  1748. end
  1749. else
  1750. guiWrite(infcord.fuel.x,infcord.fuel.y,-1,-1,"0 / 0 (0 %%)\n")
  1751. end
  1752. end
  1753. guiWrite(infcord.fuelconv.x,infcord.fuelconv.y,-1,-1,"%d\n",inf.fuelConversionRate)
  1754. if com.isAvailable("draconic_rf_storage") then
  1755. guiWrite(infcord.core.x,infcord.core.y,-1,-1,coreformat())
  1756. if button.stop.y ~= infcord.core.y + 2 then
  1757. screenMain()
  1758. end
  1759. elseif button.stop.y ~= infcord.fuelconv.y + 2 then
  1760. screenMain()
  1761. end
  1762. checkButtons()
  1763. syncActive()
  1764. end
  1765. end
  1766. -- Алгоритм автономного режима
  1767. local function autoForReactor(r, state)
  1768. if not r or not r.reactor or not r.upgate or not r.downgate then
  1769. return
  1770. end
  1771. local ok, inf = pcall(r.reactor.getReactorInfo)
  1772. if not ok or type(inf) ~= "table" then
  1773. return
  1774. end
  1775. local now = computer.uptime()
  1776. if r.chargeRequested and now <= r.chargeRequested then
  1777. local downflow = 900000
  1778. r.downgate.setOverrideEnabled(false)
  1779. r.downgate.setSignalHighFlow(downflow)
  1780. r.downgate.setSignalLowFlow(downflow)
  1781. return
  1782. end
  1783. local isActive = reactors[activeIndex] and reactors[activeIndex].reactorAdr == r.reactorAdr
  1784. if cfg.autoProtectTempEdge and inf.temperature >= cfg.autoProtectTempEdge and not r.autostate then
  1785. r.autostate = true
  1786. if isActive then
  1787. autostate = true
  1788. if handleMain and button.autoon.x then
  1789. guiWrite(button.autoon.x,button.autoon.y,color.green,color.black,"%s\n",button.autoon.name)
  1790. end
  1791. end
  1792. end
  1793. local shieldPct = cfg.shield or 25
  1794. local flow = getGateFlow(r.upgate)
  1795. if type(flow) ~= "number" then
  1796. flow = 0
  1797. end
  1798. local drain = inf.fieldDrainRate
  1799. if state then
  1800. local forceEdge = cfg.forceModeTempLowEdge or 7600
  1801. if forceEdge < 7600 then
  1802. forceEdge = 7600
  1803. end
  1804. local waittemp = autoWaitTempByAdr[r.reactorAdr]
  1805. local tempRise = false
  1806. if r.lastTemp then
  1807. if inf.temperature > r.lastTemp then
  1808. tempRise = true
  1809. elseif inf.temperature < r.lastTemp then
  1810. tempRise = false
  1811. else
  1812. tempRise = r.temprise or false
  1813. end
  1814. end
  1815. r.lastTemp = inf.temperature
  1816. r.temprise = tempRise
  1817. local downflow = drain / (1 - (shieldPct/100))
  1818. r.downgate.setOverrideEnabled(true)
  1819. r.downgate.setFlowOverride(downflow)
  1820. if inf.temperature <= forceEdge then
  1821. if flow - inf.generationRate <= cfg.forceModeStepCase then
  1822. flow = flow + cfg.forceModeStep
  1823. r.upgate.setSignalLowFlow(flow)
  1824. end
  1825. elseif flow - inf.generationRate <= cfg.safeModeStepCase and inf.temperature >= forceEdge then
  1826. if not waittemp then
  1827. flow = getGateFlow(r.upgate) + cfg.safemodeStep
  1828. r.upgate.setSignalLowFlow(flow)
  1829. elseif inf.temperature < cfg.safeModeTempToWaitEdge then
  1830. waittemp = false
  1831. end
  1832. elseif tempRise and inf.temperature >= cfg.safeModeTempWaitEdge then
  1833. if inf.temperature > cfg.safeModeTempWaitEdge then
  1834. waittemp = true
  1835. end
  1836. if inf.temperature > cfg.tempCriticalEdge then
  1837. flow = inf.generationRate - 1000
  1838. r.upgate.setSignalLowFlow(flow)
  1839. end
  1840. end
  1841. autoWaitTempByAdr[r.reactorAdr] = waittemp
  1842. if isActive and handleMain and infcord.flow.x then
  1843. infcord.flow.value = flow
  1844. guiWrite(infcord.flow.x,infcord.flow.y,color.red,color.grey,"%s",numformat(flow))
  1845. end
  1846. else
  1847. local downflow
  1848. if inf.status == "charging" then
  1849. downflow = 900000
  1850. else
  1851. downflow = drain / (1 - (shieldPct/100))
  1852. end
  1853. r.downgate.setOverrideEnabled(false)
  1854. r.downgate.setSignalHighFlow(downflow)
  1855. r.downgate.setSignalLowFlow(downflow)
  1856. end
  1857. end
  1858. -- Обработчик событий
  1859. local function tcall(type,scrnAdr,x,y,btn,player)
  1860. local rx,ry = gpu.getResolution()
  1861. --выход
  1862. if x >= rx-2 and x<=rx and y == 1 then
  1863. event.ignore("touch",tcall)
  1864. prog = false
  1865. ops = false
  1866. end
  1867. -- Главный экран
  1868. if handleMain then
  1869. -- Увеличение
  1870. if x >= button.add.x+4 and x <= button.add.x+3+#button.add.name and y == button.add.y then
  1871. if keyb.isShiftDown() then
  1872. if keyb.isControlDown() then
  1873. upgate.setSignalLowFlow(add(infcord.flow,cfg.ctrlShift_interval))
  1874. else
  1875. upgate.setSignalLowFlow(add(infcord.flow,cfg.shift_interval))
  1876. end
  1877. else
  1878. if keyb.isControlDown() then
  1879. upgate.setSignalLowFlow(add(infcord.flow,cfg.ctrl_interval))
  1880. else
  1881. upgate.setSignalLowFlow(add(infcord.flow,cfg.default_interval))
  1882. end
  1883. end
  1884. guiWrite(infcord.flow.x,infcord.flow.y,color.red,color.grey,"%s",numformat(infcord.flow.value))
  1885. end
  1886. --Уменьшение
  1887. if x >= button.sub.x+2 and x <= button.sub.x+1+#button.sub.name and y == button.sub.y then
  1888. if keyb.isShiftDown() then
  1889. if keyb.isControlDown() then
  1890. upgate.setSignalLowFlow(sub(infcord.flow,cfg.ctrlShift_interval))
  1891. else
  1892. upgate.setSignalLowFlow(sub(infcord.flow,cfg.shift_interval))
  1893. end
  1894. else
  1895. if keyb.isControlDown() then
  1896. upgate.setSignalLowFlow(sub(infcord.flow,cfg.ctrl_interval))
  1897. else
  1898. upgate.setSignalLowFlow(sub(infcord.flow,cfg.default_interval))
  1899. end
  1900. end
  1901. guiWrite(infcord.flow.x,infcord.flow.y,color.blue,color.grey,"%s",numformat(infcord.flow.value))
  1902. end
  1903.  
  1904. if not autostate then
  1905. if x >= button.autooff.x and x <= button.autooff.x + textWidth(button.autooff.name) - 1 and y == button.autooff.y then
  1906. gpu.set(button.autooff.x, button.autooff.y," ")
  1907. autostate = true
  1908. guiWrite(button.autoon.x,button.autoon.y,color.green,color.black,"%s\n",button.autoon.name)
  1909. end
  1910. else
  1911. if x >= button.autoon.x and x <= button.autoon.x + textWidth(button.autoon.name) - 1 and y == button.autoon.y then
  1912. gpu.set(button.autoon.x, button.autoon.y," ")
  1913. autostate = false
  1914. guiWrite(button.autooff.x,button.autooff.y,color.red,color.black,"%s\n",button.autooff.name)
  1915. end
  1916. end
  1917. if button.charge.visible then
  1918. local w = button.charge.w or textWidth(button.charge.name)
  1919. if x >= button.charge.x and x <= button.charge.x + w - 1 and y == button.charge.y then
  1920. ensureFlowInit(reactors[activeIndex], true)
  1921. if reactors[activeIndex] and reactors[activeIndex].downgate then
  1922. pcall(reactors[activeIndex].downgate.setSignalHighFlow, reactors[activeIndex].downgate, 900000)
  1923. pcall(reactors[activeIndex].downgate.setSignalLowFlow, reactors[activeIndex].downgate, 900000)
  1924. pcall(reactors[activeIndex].downgate.setOverrideEnabled, reactors[activeIndex].downgate, false)
  1925. end
  1926. if reactors[activeIndex] then
  1927. reactors[activeIndex].chargeRequested = computer.uptime() + 2
  1928. chargeRequestByAdr[reactors[activeIndex].reactorAdr] = reactors[activeIndex].chargeRequested
  1929. end
  1930. reactor.chargeReactor()
  1931. guiWrite(button.charge.x,button.charge.y,-1,color.grey," ",button.charge.name)
  1932. button.charge.visible = false
  1933. end
  1934. end
  1935. if button.start.visible then
  1936. local w = button.start.w or textWidth(button.start.name)
  1937. if x >= button.start.x and x <= button.start.x + w - 1 and y == button.start.y then
  1938. ensureFlowInit(reactors[activeIndex])
  1939. reactor.activateReactor()
  1940. if reactors[activeIndex] then
  1941. autoStopped[reactors[activeIndex].reactorAdr] = nil
  1942. end
  1943. guiWrite(button.start.x,button.start.y,-1,color.grey," ",button.start.name)
  1944. button.start.visible = false
  1945. end
  1946. end
  1947. if button.stop.visible then
  1948. local w = button.stop.w or textWidth(button.stop.name)
  1949. if x >= button.stop.x and x <= button.stop.x + w - 1 and y == button.stop.y then
  1950. reactor.stopReactor()
  1951. guiWrite(button.stop.x,button.stop.y,-1,color.grey," ",button.stop.name)
  1952. button.stop.visible = false
  1953. end
  1954. end
  1955. --меню
  1956. if x>= menuItem.options.x and x <= (menuItem.options.x + (menuItem.options.w or #menuItem.options.name) - 1) and y == menuItem.options.y then
  1957. screenOptions()
  1958. return
  1959. end
  1960. if x>= menuItem.overview.x and x <= (menuItem.overview.x + (menuItem.overview.w or #menuItem.overview.name) - 1) and y == menuItem.overview.y then
  1961. syncActive()
  1962. screenOverview()
  1963. return
  1964. end
  1965. if x>= menuItem.refresh.x and x <= (menuItem.refresh.x + (menuItem.refresh.w or #menuItem.refresh.name) - 1) and y == menuItem.refresh.y then
  1966. refreshReactors(true)
  1967. return
  1968. end
  1969. if x>= menuItem.gates.x and x <= (menuItem.gates.x + (menuItem.gates.w or #menuItem.gates.name) - 1) and y == menuItem.gates.y then
  1970. resetAssignState()
  1971. screenAssign()
  1972. return
  1973. end
  1974. for i=1,#reactors do
  1975. local tab = reactors[i].tab
  1976. if tab.x and x >= tab.x and x <= tab.x + tab.w - 1 and y == tab.y then
  1977. syncActive()
  1978. setActive(i)
  1979. screenMain()
  1980. return
  1981. end
  1982. end
  1983. if x == 1 and y == 1 then
  1984. event.ignore("touch",tcall)
  1985. prog = false
  1986. end
  1987. end
  1988. -- Экран обзора
  1989. if handleOverview then
  1990. if x>= menuItem.options.x and x <= (menuItem.options.x + (menuItem.options.w or #menuItem.options.name) - 1) and y == menuItem.options.y then
  1991. screenOptions()
  1992. return
  1993. end
  1994. if x>= menuItem.refresh.x and x <= (menuItem.refresh.x + (menuItem.refresh.w or #menuItem.refresh.name) - 1) and y == menuItem.refresh.y then
  1995. refreshReactors(true)
  1996. return
  1997. end
  1998. if x>= menuItem.gates.x and x <= (menuItem.gates.x + (menuItem.gates.w or #menuItem.gates.name) - 1) and y == menuItem.gates.y then
  1999. resetAssignState()
  2000. screenAssign()
  2001. return
  2002. end
  2003. for i=1,#reactors do
  2004. local tab = reactors[i].tab
  2005. if tab.x and x >= tab.x and x <= tab.x + tab.w - 1 and y == tab.y then
  2006. syncActive()
  2007. setActive(i)
  2008. screenMain()
  2009. return
  2010. end
  2011. local ctrl = reactors[i].control
  2012. 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
  2013. local flow = getGateFlow(reactors[i].upgate)
  2014. reactors[i].upgate.setSignalLowFlow(flow - cfg.default_interval)
  2015. return
  2016. end
  2017. 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
  2018. local flow = getGateFlow(reactors[i].upgate)
  2019. reactors[i].upgate.setSignalLowFlow(flow + cfg.default_interval)
  2020. return
  2021. end
  2022. 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
  2023. reactors[i].autostate = not reactors[i].autostate
  2024. if i == activeIndex then
  2025. autostate = reactors[i].autostate
  2026. end
  2027. refreshOverview()
  2028. return
  2029. end
  2030. local btn = reactors[i].powerBtn
  2031. if btn.x and x >= btn.x and x <= btn.x + btn.w - 1 and y == btn.y then
  2032. if btn.action == "start" then
  2033. ensureFlowInit(reactors[i])
  2034. reactors[i].reactor.activateReactor()
  2035. autoStopped[reactors[i].reactorAdr] = nil
  2036. else
  2037. reactors[i].reactor.stopReactor()
  2038. end
  2039. return
  2040. end
  2041. end
  2042. if x == 1 and y == 1 then
  2043. event.ignore("touch",tcall)
  2044. prog = false
  2045. end
  2046. end
  2047. -- Экран настроек
  2048. if handleOptions then
  2049. -- Работа со значениями
  2050. if canedit then
  2051. if x >= OptionDefault.x and x <= OptionDefault.x + #tostring(OptionDefault.value)-1 and y == OptionDefault.y then
  2052. canclose = false
  2053. canedit = false
  2054. editOption(OptionDefault)
  2055. end
  2056. if x >= OptionCtrl.x and x <= OptionCtrl.x + #tostring(OptionCtrl.value)-1 and y == OptionCtrl.y then
  2057. canclose = false
  2058. canedit = false
  2059. editOption(OptionCtrl)
  2060. end
  2061. if x >= OptionShift.x and x <= OptionShift.x + #tostring(OptionShift.value)-1 and y == OptionShift.y then
  2062. canclose = false
  2063. canedit = false
  2064. editOption(OptionShift)
  2065. end
  2066. if x >= OptionCtrlShift.x and x <= OptionCtrlShift.x + #tostring(OptionCtrlShift.value)-1 and y == OptionCtrlShift.y then
  2067. canclose = false
  2068. canedit = false
  2069. editOption(OptionCtrlShift)
  2070. end
  2071. if x >= OptionShield.x and x <= OptionShield.x + #tostring(OptionShield.value)-1 and y == OptionShield.y then
  2072. canclose = false
  2073. canedit = false
  2074. editOption(OptionShield)
  2075. end
  2076. if x >= OptionFuelStop.x and x <= OptionFuelStop.x + #tostring(OptionFuelStop.value)-1 and y == OptionFuelStop.y then
  2077. canclose = false
  2078. canedit = false
  2079. editOption(OptionFuelStop)
  2080. end
  2081. end
  2082. -- меню
  2083. if canclose then
  2084. if x>= menuItem.optionsBack.x and x <= (menuItem.optionsBack.x + (menuItem.optionsBack.w or #menuItem.optionsBack.name) - 1) and y == menuItem.optionsBack.y then
  2085. screenOverview()
  2086. return
  2087. end
  2088. if x>= menuItem.save.x and x <= (menuItem.save.x + (menuItem.save.w or #menuItem.save.name) - 1) and y == menuItem.save.y then
  2089. cfg.default_interval = OptionDefault.value
  2090. cfg.ctrl_interval = OptionCtrl.value
  2091. cfg.shift_interval = OptionShift.value
  2092. cfg.ctrlShift_interval = OptionCtrlShift.value
  2093. cfg.shield = OptionShield.value
  2094. cfg.fuelStopPct = OptionFuelStop.value
  2095. configWrite(cfgName)
  2096. screenOverview()
  2097. return
  2098. end
  2099. if x>= menuItem.cancel.x and x <= (menuItem.cancel.x + (menuItem.cancel.w or #menuItem.cancel.name) - 1) and y == menuItem.cancel.y then
  2100. OptionDefault.value = cfg.default_interval
  2101. OptionCtrl.value = cfg.ctrl_interval
  2102. OptionShift.value = cfg.shift_interval
  2103. OptionCtrlShift.value = cfg.ctrlShift_interval
  2104. OptionShield.value = cfg.shield
  2105. OptionFuelStop.value = cfg.fuelStopPct or 98
  2106. screenOverview()
  2107. return
  2108. end
  2109. end
  2110. end
  2111. -- Экран гейтов
  2112. -- gates screen
  2113. if handleAssign then
  2114. if x>= menuItem.back.x and x <= (menuItem.back.x + (menuItem.back.w or #menuItem.back.name) - 1) and y == menuItem.back.y then
  2115. if not assignState.reactorIndex and not assignState.shieldGateIdx and not assignState.outGateIdx then
  2116. resetAssignState()
  2117. screenOverview()
  2118. return
  2119. end
  2120. assignState.message = "Выбери гейты!"
  2121. screenAssign()
  2122. return
  2123. end
  2124. if assignUi.reset and x>= assignUi.reset.x and x <= assignUi.reset.x + assignUi.reset.w - 1 and y == assignUi.reset.y then
  2125. if assignState.reactorIndex then
  2126. clearAssignedGates(assignState.reactorIndex)
  2127. reactors = buildReactors() or reactors
  2128. resetAssignState()
  2129. screenAssign()
  2130. end
  2131. return
  2132. end
  2133. for i=1,#assignUi.reactors do
  2134. local btn = assignUi.reactors[i]
  2135. if btn and x >= btn.x and x <= btn.x + btn.w - 1 and y == btn.y then
  2136. assignState.reactorIndex = i
  2137. assignState.shieldGateIdx = nil
  2138. assignState.outGateIdx = nil
  2139. assignState.step = "shield"
  2140. screenAssign()
  2141. return
  2142. end
  2143. end
  2144. for i=1,#assignUi.gates do
  2145. local btn = assignUi.gates[i]
  2146. if btn and x >= btn.x and x <= btn.x + btn.w - 1 and y == btn.y then
  2147. local gateAdr = assignUi.gateAddrs[i]
  2148. if assignState.step == "reactor" then
  2149. return
  2150. end
  2151. if gateAdr and assignUi.gateUse[gateAdr] and assignUi.gateUse[gateAdr] ~= assignUi.selectedAdr then
  2152. return
  2153. end
  2154. local selectedEntry = assignUi.selectedEntry
  2155. if not assignState.reactorIndex then
  2156. assignState.step = "reactor"
  2157. screenAssign()
  2158. return
  2159. end
  2160. if assignState.step == "shield" then
  2161. assignState.shieldGateIdx = i
  2162. assignState.step = "output"
  2163. screenAssign()
  2164. return
  2165. elseif assignState.step == "output" then
  2166. if assignState.shieldGateIdx and assignUi.gateAddrs[assignState.shieldGateIdx] == gateAdr then
  2167. assignState.message = "Нужны два разных гейта!"
  2168. screenAssign()
  2169. return
  2170. end
  2171. assignState.outGateIdx = i
  2172. local idx = assignState.reactorIndex
  2173. local saved = saveAssignedGates(assignState.reactorIndex, assignState.shieldGateIdx, assignState.outGateIdx)
  2174. resetAssignState()
  2175. refreshReactors(false)
  2176. if not saved or not reactors or #reactors == 0 then
  2177. screenOverview()
  2178. return
  2179. end
  2180. screenMain()
  2181. return
  2182. end
  2183. end
  2184. end
  2185. if x == 1 and y == 1 then
  2186. event.ignore("touch",tcall)
  2187. prog = false
  2188. end
  2189. end
  2190. end
  2191.  
  2192. event.listen("touch",tcall)
  2193. screenStart()
  2194. if upgate ~= nil and downgate ~= nil then
  2195. screen.overview()
  2196. end
  2197. while prog do
  2198. local now = computer.uptime()
  2199. if handleMain and now - lastDetailUpdate >= 0.2 then
  2200. lastDetailUpdate = now
  2201. if not pcall(refreshInfo) then
  2202. autostate = false
  2203. if not pcall(screenStart) then
  2204. break
  2205. end
  2206. if not pcall(screenMain) then
  2207. screenStart()
  2208. if not pcall(screenMain) then
  2209. break
  2210. end
  2211. end
  2212. end
  2213. elseif handleOverview and now - lastOverviewUpdate >= 0.5 then
  2214. lastOverviewUpdate = now
  2215. if not pcall(refreshOverview) then
  2216. if not pcall(screenOverview) then
  2217. break
  2218. end
  2219. end
  2220. end
  2221. if reactors and #reactors > 0 then
  2222. for i=1,#reactors do
  2223. autoForReactor(reactors[i], reactors[i].autostate)
  2224. end
  2225. end
  2226. os.sleep(0)
  2227. end
  2228. gpu.setBackground(rback)
  2229. gpu.setForeground(rfore)
  2230. gpu.setResolution(xz,yz)
  2231. term.clear()
  2232.  
  2233.  
  2234.  
  2235.  
  2236.  
Add Comment
Please, Sign In to add comment