Gintarus

new_reactor_5

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