Gintarus

5reactors+

Jan 12th, 2026 (edited)
7
0
Never
Not a member of Pastebin yet? Sign Up, it unlocks many cool features!
text 81.34 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 screenAssign
  383. local screenOverview
  384. local assignMode = nil
  385. local firstStartCompleted = false
  386. local assignState = {reactorIndex = nil, reactorAdr = nil, shieldGateIdx = nil, shieldGateAdr = nil, outGateIdx = nil, outGateAdr = nil, step = "reactor", message = nil}
  387. local assignUi = {reactors = {}, gates = {}, gateAddrs = {}, reactorAddrs = {}, gateUse = {}, selectedAdr = nil, back = {x=nil,y=nil,w=0}}
  388.  
  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. if not firstStartCompleted then
  926. printf("Эта страница для настройки программы при первом запуске или после сбоя")
  927. end
  928. drawSeparator(x)
  929. term.setCursor(1,screenH - 2)
  930. menuItem.gates.x,menuItem.gates.y = term.getCursor()
  931. gpu.setForeground(color.blue)
  932. printf(menuItem.gates.name)
  933. menuItem.gates.w = textWidth(menuItem.gates.name)
  934. gpu.setForeground(color.white)
  935. local hadFile = readReactorsFile() ~= nil
  936. while true do
  937. if not ops then return end
  938. reactors = buildReactors()
  939. if reactors and #reactors > 0 then
  940. setActive(1)
  941. firstStartCompleted = true
  942. if not hadFile then
  943. screenAssign()
  944. return
  945. end
  946. break
  947. end
  948. if not hadFile then
  949. local reactorsList = listAddresses("draconic_reactor")
  950. local gates = listAddresses("flux_gate")
  951. if #reactorsList > 0 and #gates >= 2 then
  952. reactors = reactors or {}
  953. firstStartCompleted = true
  954. screenOverview()
  955. return
  956. end
  957. end
  958. guiClear(2)
  959. printf("Подключите реакторы и флюкс-гейты (2 гейта на каждый реактор)\n")
  960. printf("Максимум: %d реакторов. Адреса можно сохранить в %s\n",MAX_REACTORS,reactorsFile)
  961. os.sleep(1)
  962. end
  963. end
  964. -- Экран настроек
  965. local function screenOptions()
  966. handleMain = false
  967. handleStart = false
  968. handleOptions = true
  969. handleOverview = false
  970. handleAssign = false
  971. canedit = true
  972. canclose = true
  973. local x = drawHeader("HiTech Classic is the best (Options)")
  974. menuItem.save.x,menuItem.save.y =term.getCursor()
  975. gpu.setForeground(color.blue)
  976. printf(menuItem.save.name)
  977. menuItem.save.w = textWidth(menuItem.save.name)
  978. menuItem.cancel.x,menuItem.cancel.y =term.getCursor()
  979. printf(menuItem.cancel.name)
  980. menuItem.cancel.w = textWidth(menuItem.cancel.name)
  981. menuItem.optionsBack.x,menuItem.optionsBack.y =term.getCursor()
  982. printf(menuItem.optionsBack.name)
  983. menuItem.optionsBack.w = textWidth(menuItem.optionsBack.name)
  984. gpu.setForeground(color.white)
  985. drawSeparator(x)
  986. printf(" Интервал для щелчка: ")
  987. OptionDefault["x"],OptionDefault["y"] = term.getCursor()
  988. printf("%d\n",OptionDefault.value)
  989. printf(" Интервал для CTRL: ")
  990. OptionCtrl["x"],OptionCtrl["y"] = term.getCursor()
  991. printf("%d\n",OptionCtrl.value)
  992. printf(" Интервал для SHIFT: ")
  993. OptionShift["x"],OptionShift["y"] = term.getCursor()
  994. printf("%d\n",OptionShift.value)
  995. printf(" Интервал для CTRL+SHIFT: ")
  996. OptionCtrlShift["x"],OptionCtrlShift["y"] = term.getCursor()
  997. printf("%d\n",OptionCtrlShift.value)
  998. printf(" Уровень щитов: ")
  999. OptionShield["x"],OptionShield["y"] = term.getCursor()
  1000. printf("%d\n",OptionShield.value)
  1001. printf(" Отключение по топливу (%%): ")
  1002. OptionFuelStop["x"],OptionFuelStop["y"] = term.getCursor()
  1003. printf("%d\n",OptionFuelStop.value)
  1004. end
  1005. -- Назначение гейтов
  1006. local function clearPromptLine()
  1007. local _, y = term.getCursor()
  1008. if y > 1 then
  1009. term.setCursor(1, y - 1)
  1010. term.clearLine()
  1011. term.setCursor(1, y - 1)
  1012. end
  1013. end
  1014.  
  1015. local function readIndex(prompt,max,used)
  1016. while true do
  1017. printf("%s",prompt)
  1018. local input = term.read(false,false) or ""
  1019. clearPromptLine()
  1020. local num = tonumber(input:match("%d+"))
  1021. if num and num >= 1 and num <= max and not used[num] then
  1022. return num
  1023. end
  1024. printf("Неверный выбор, попробуйте снова.\n")
  1025. end
  1026. end
  1027.  
  1028. local function readIndexAllowZero(prompt,max)
  1029. while true do
  1030. printf("%s",prompt)
  1031. local input = term.read(false,false) or ""
  1032. clearPromptLine()
  1033. local lower = input:lower()
  1034. if lower:find("назад") or lower:find("back") or lower:match("^b%s*$") then
  1035. return -1
  1036. end
  1037. local num = tonumber(input:match("%d+"))
  1038. if num and num >= 0 and num <= max then
  1039. return num
  1040. end
  1041. printf("Неверный выбор, попробуйте снова.\n")
  1042. end
  1043. end
  1044.  
  1045. local saveAssignedGates
  1046.  
  1047. local function getChatBox()
  1048. if chatBox then
  1049. return chatBox
  1050. end
  1051. if com.isAvailable("chat_box") then
  1052. chatBox = com.chat_box
  1053. end
  1054. return chatBox
  1055. end
  1056.  
  1057. local function chatSay(message, color_code)
  1058. local box = getChatBox()
  1059. if not box or not message then
  1060. return false
  1061. end
  1062. if box.say and pcall(function() box.say(message) end) then
  1063. return true
  1064. end
  1065. if box.sendMessage and pcall(function() box.sendMessage(message) end) then
  1066. return true
  1067. end
  1068. if box.sendMessage and pcall(function() box.sendMessage(message, color_code or 64) end) then
  1069. return true
  1070. end
  1071. return false
  1072. end
  1073.  
  1074. local function maybeChatSay(step, message, color_code)
  1075. if step and easyAssign.lastChatStep ~= step then
  1076. easyAssign.lastChatStep = step
  1077. easyAssign.lastChatMessage = nil
  1078. end
  1079. if message and easyAssign.lastChatMessage ~= message then
  1080. easyAssign.lastChatMessage = message
  1081. chatSay(message, color_code)
  1082. end
  1083. end
  1084.  
  1085. local function snapshotComponents(typeName)
  1086. local list = {}
  1087. for adr in com.list(typeName) do
  1088. list[#list+1] = adr
  1089. end
  1090. return list
  1091. end
  1092.  
  1093. local function initEasyKnown()
  1094. easyAssign.known = {draconic_reactor = {}, flux_gate = {}}
  1095. for _, addr in ipairs(snapshotComponents("draconic_reactor")) do
  1096. easyAssign.known.draconic_reactor[addr] = true
  1097. end
  1098. for _, addr in ipairs(snapshotComponents("flux_gate")) do
  1099. easyAssign.known.flux_gate[addr] = true
  1100. end
  1101. end
  1102.  
  1103. local function findNewComponent(typeName)
  1104. if not easyAssign.known or not easyAssign.known[typeName] then
  1105. initEasyKnown()
  1106. end
  1107. for addr in com.list(typeName) do
  1108. if not easyAssign.known[typeName][addr] then
  1109. easyAssign.known[typeName][addr] = true
  1110. return addr
  1111. end
  1112. end
  1113. return nil
  1114. end
  1115.  
  1116. local function isAddressUsed(addr)
  1117. if not addr then
  1118. return false
  1119. end
  1120. local entries = readReactorsFile() or {}
  1121. for i=1,#entries do
  1122. if entries[i].reactorAdr == addr or entries[i].upAdr == addr or entries[i].downAdr == addr then
  1123. return true
  1124. end
  1125. end
  1126. return false
  1127. end
  1128.  
  1129. local function clearAssignedByAdr(reactorAdr)
  1130. if not reactorAdr then
  1131. return false
  1132. end
  1133. local entries = readReactorsFile() or {}
  1134. local newEntries = {}
  1135. local removed = false
  1136. for i=1,#entries do
  1137. if entries[i].reactorAdr ~= reactorAdr then
  1138. newEntries[#newEntries+1] = entries[i]
  1139. else
  1140. removed = true
  1141. end
  1142. end
  1143. if removed then
  1144. writeReactorsFile(newEntries)
  1145. end
  1146. return removed
  1147. end
  1148.  
  1149. local function startEasyAssign()
  1150. local entries = readReactorsFile() or {}
  1151. if #entries >= MAX_REACTORS then
  1152. easyAssign.active = false
  1153. easyAssign.message = "Достигнут лимит реакторов."
  1154. return
  1155. end
  1156. if not getChatBox() then
  1157. easyAssign.active = false
  1158. easyAssign.message = "Ошибка: для работы нужен chat_box."
  1159. return
  1160. end
  1161. easyAssign.active = true
  1162. easyAssign.step = "reactor"
  1163. easyAssign.core = nil
  1164. easyAssign.shield = nil
  1165. easyAssign.output = nil
  1166. easyAssign.saved = false
  1167. easyAssign.message = nil
  1168. easyAssign.index = #entries + 1
  1169. easyAssign.lastChatStep = nil
  1170. easyAssign.lastChatMessage = nil
  1171. initEasyKnown()
  1172. maybeChatSay("intro", "Легкий режим: подключите адаптер к реактору #" .. tostring(easyAssign.index) .. " и смотрите монитор.")
  1173. end
  1174.  
  1175. local function screenAssignChoice()
  1176. handleMain = false
  1177. handleStart = false
  1178. handleOptions = false
  1179. handleOverview = false
  1180. handleAssign = true
  1181. local x = drawHeader("HiTech Classic is the best (Гейты)")
  1182. drawSeparator(x)
  1183. assignUi.reactors = {}
  1184. assignUi.gates = {}
  1185. assignUi.gateAddrs = {}
  1186. assignUi.reactorAddrs = {}
  1187. assignUi.gateUse = {}
  1188. assignUi.selectedAdr = nil
  1189. gpu.setBackground(color.grey)
  1190. gpu.setForeground(color.white)
  1191. gpu.fill(1,4,x,21," ")
  1192. term.setCursor(1,2)
  1193. menuItem.back.x,menuItem.back.y = term.getCursor()
  1194. assignUi.back.x,assignUi.back.y,assignUi.back.w = menuItem.back.x,menuItem.back.y,textWidth(menuItem.back.name)
  1195. gpu.setForeground(color.blue)
  1196. printf(menuItem.back.name)
  1197. menuItem.back.w = textWidth(menuItem.back.name)
  1198. gpu.setForeground(color.white)
  1199. term.setCursor(2,5)
  1200. printf("Выберите способ добавления гейтов:")
  1201. local heavyLabel = " Тяжелый способ (анализатор) "
  1202. local easyLabel = " Легкий способ (подключение) "
  1203. local heavyX, heavyY = 2, 7
  1204. local easyX, easyY = 2, 9
  1205. easyAssign.heavyBtn = {x=heavyX,y=heavyY,w=textWidth(heavyLabel)}
  1206. easyAssign.easyBtn = {x=easyX,y=easyY,w=textWidth(easyLabel)}
  1207. guiWrite(heavyX,heavyY,color.white,color.red,"%s",heavyLabel)
  1208. guiWrite(easyX,easyY,color.white,color.green,"%s",easyLabel)
  1209. if easyAssign.message then
  1210. guiWrite(2,12,color.yellow,-1,"%s",easyAssign.message)
  1211. end
  1212. end
  1213.  
  1214. local function screenAssignEasy()
  1215. handleMain = false
  1216. handleStart = false
  1217. handleOptions = false
  1218. handleOverview = false
  1219. handleAssign = true
  1220. local x = drawHeader("HiTech Classic is the best (Гейты - Легкий)")
  1221. drawSeparator(x)
  1222. gpu.setBackground(color.grey)
  1223. gpu.setForeground(color.white)
  1224. gpu.fill(1,4,x,21," ")
  1225. term.setCursor(1,2)
  1226. menuItem.back.x,menuItem.back.y = term.getCursor()
  1227. easyAssign.backBtn = {x=menuItem.back.x,y=menuItem.back.y,w=textWidth(menuItem.back.name)}
  1228. gpu.setForeground(color.blue)
  1229. printf(menuItem.back.name)
  1230. menuItem.back.w = textWidth(menuItem.back.name)
  1231. gpu.setForeground(color.white)
  1232. term.setCursor(2,5)
  1233. printf("РЕАКТОР #%d", easyAssign.index or 1)
  1234. term.setCursor(2,7)
  1235. if easyAssign.step == "reactor" then
  1236. guiWrite(2,7,color.green,-1,"Подключите адаптер к ядру реактора.")
  1237. maybeChatSay("reactor", "Подключите адаптер к ядру реактора.", 255)
  1238. elseif easyAssign.step == "shield" then
  1239. guiWrite(2,7,color.green,-1,"Подключите адаптер к гейту ЩИТОВ.")
  1240. maybeChatSay("shield", "Подключите адаптер к гейту ЩИТОВ.", 4096)
  1241. elseif easyAssign.step == "output" then
  1242. guiWrite(2,7,color.green,-1,"Подключите адаптер к гейту ВЫВОДА.")
  1243. maybeChatSay("output", "Подключите адаптер к гейту ВЫВОДА.", 16711680)
  1244. elseif easyAssign.step == "done" then
  1245. guiWrite(2,7,color.green,-1,"Реактор добавлен.")
  1246. maybeChatSay("done", "Реактор добавлен. Смотрите монитор.", 65280)
  1247. end
  1248. term.setCursor(2,9)
  1249. printf("Ожидаю компонент...")
  1250. local infoY = 11
  1251. local coreLine = "Ядро: " .. (easyAssign.core or "-")
  1252. local shieldLine = "Щиты: " .. (easyAssign.shield or "-")
  1253. local outputLine = "Вывод: " .. (easyAssign.output or "-")
  1254. local coreColor = (easyAssign.step == "reactor") and color.blue or (easyAssign.core and color.green or color.white)
  1255. local shieldColor = (easyAssign.step == "shield") and color.blue or (easyAssign.shield and color.green or color.white)
  1256. local outputColor = (easyAssign.step == "output") and color.blue or (easyAssign.output and color.green or color.white)
  1257. guiWrite(2,infoY,coreColor,-1,"%s",coreLine)
  1258. guiWrite(2,infoY + 1,shieldColor,-1,"%s",shieldLine)
  1259. guiWrite(2,infoY + 2,outputColor,-1,"%s",outputLine)
  1260. if easyAssign.message then
  1261. guiWrite(2,infoY + 4,color.yellow,-1,"%s",easyAssign.message)
  1262. end
  1263. if easyAssign.step == "done" then
  1264. local contLabel = " [Продолжить] "
  1265. local finLabel = " [Завершить] "
  1266. local contX, contY = 2, infoY + 6
  1267. local finX, finY = 2 + textWidth(contLabel) + 2, infoY + 6
  1268. easyAssign.continueBtn = {x=contX,y=contY,w=textWidth(contLabel)}
  1269. easyAssign.finishBtn = {x=finX,y=finY,w=textWidth(finLabel)}
  1270. guiWrite(contX,contY,color.white,color.green,"%s",contLabel)
  1271. guiWrite(finX,finY,color.white,color.red,"%s",finLabel)
  1272. end
  1273. end
  1274.  
  1275. local function screenAssignManual()
  1276. handleMain = false
  1277. handleStart = false
  1278. handleOptions = false
  1279. handleOverview = false
  1280. handleAssign = true
  1281. local x = drawHeader("HiTech Classic is the best (Гейты)")
  1282. drawSeparator(x)
  1283. assignUi.reactors = {}
  1284. assignUi.gates = {}
  1285. assignUi.gateAddrs = {}
  1286. assignUi.reactorAddrs = {}
  1287. assignUi.gateUse = {}
  1288. assignUi.selectedAdr = nil
  1289. gpu.setBackground(color.grey)
  1290. gpu.setForeground(color.white)
  1291. gpu.fill(1,4,x,21," ")
  1292. term.setCursor(1,2)
  1293. menuItem.back.x,menuItem.back.y = term.getCursor()
  1294. assignUi.back.x,assignUi.back.y,assignUi.back.w = menuItem.back.x,menuItem.back.y,textWidth(menuItem.back.name)
  1295. gpu.setForeground(color.blue)
  1296. printf(menuItem.back.name)
  1297. menuItem.back.w = textWidth(menuItem.back.name)
  1298. gpu.setForeground(color.white)
  1299. term.setCursor(2,4)
  1300. printf("Выберите реактор")
  1301. local reactorsList = listAddresses("draconic_reactor")
  1302. local gates = listAddresses("flux_gate")
  1303. assignUi.gateAddrs = gates
  1304. assignUi.reactorAddrs = reactorsList
  1305. if #reactorsList == 0 or #gates < 2 then
  1306. printf("Недостаточно реакторов или флюкс-гейтов.\n")
  1307. os.sleep(1)
  1308. screenOverview()
  1309. return
  1310. end
  1311. local count = math.min(#reactorsList, MAX_REACTORS)
  1312. term.setCursor(2,5)
  1313. printf("Реакторы:")
  1314. local rowY = 6
  1315. for i=1,count do
  1316. term.setCursor(2,rowY)
  1317. local label = string.format("%d) %s",i,reactorsList[i])
  1318. if assignState.reactorIndex == i then
  1319. guiWrite(2,rowY,color.black,color.blue,"%s",label)
  1320. else
  1321. guiWrite(2,rowY,color.white,-1,"%s",label)
  1322. end
  1323. assignUi.reactors[i] = {x=2,y=rowY,w=textWidth(label)}
  1324. rowY = rowY + 1
  1325. end
  1326.  
  1327. local entries = readReactorsFile() or {}
  1328. local gateUse = {}
  1329. for i=1,#entries do
  1330. gateUse[entries[i].upAdr] = entries[i].reactorAdr
  1331. gateUse[entries[i].downAdr] = entries[i].reactorAdr
  1332. end
  1333. assignUi.gateUse = gateUse
  1334. local selectedAdr = assignState.reactorIndex and reactorsList[assignState.reactorIndex] or nil
  1335. assignUi.selectedAdr = selectedAdr
  1336. local selectedEntry = nil
  1337. if selectedAdr then
  1338. for i=1,#entries do
  1339. if entries[i].reactorAdr == selectedAdr then
  1340. selectedEntry = entries[i]
  1341. break
  1342. end
  1343. end
  1344. end
  1345. assignUi.selectedEntry = selectedEntry
  1346.  
  1347. term.setCursor(40,5)
  1348. printf("Гейты:")
  1349. local gateY = 6
  1350. for i=1,#gates do
  1351. if gateY > 24 then
  1352. break
  1353. end
  1354. term.setCursor(40,gateY)
  1355. local label = string.format("%d) %s",i,gates[i])
  1356. local colorGate = color.dim
  1357. if selectedAdr then
  1358. if selectedEntry and (gates[i] == selectedEntry.upAdr or gates[i] == selectedEntry.downAdr) then
  1359. colorGate = color.green
  1360. elseif assignState.shieldGateIdx == i or assignState.outGateIdx == i then
  1361. colorGate = color.green
  1362. elseif gateUse[gates[i]] and gateUse[gates[i]] ~= selectedAdr then
  1363. colorGate = color.red
  1364. else
  1365. colorGate = color.dim
  1366. end
  1367. end
  1368. guiWrite(40,gateY,colorGate,-1,"%s",label)
  1369. assignUi.gates[i] = {x=40,y=gateY,w=textWidth(label)}
  1370. gateY = gateY + 1
  1371. end
  1372. end
  1373.  
  1374. local function screenAssign()
  1375. if assignMode == "manual" then
  1376. screenAssignManual()
  1377. elseif assignMode == "easy" then
  1378. screenAssignEasy()
  1379. else
  1380. screenAssignChoice()
  1381. end
  1382. end
  1383.  
  1384. local function acceptEasyComponent(address, componentType)
  1385. if easyAssign.step == "reactor" then
  1386. if componentType ~= "draconic_reactor" then
  1387. easyAssign.message = "Нужен draconic_reactor."
  1388. screenAssignEasy()
  1389. return
  1390. end
  1391. if isAddressUsed(address) then
  1392. easyAssign.message = "Адрес уже используется."
  1393. screenAssignEasy()
  1394. return
  1395. end
  1396. easyAssign.core = address
  1397. easyAssign.step = "shield"
  1398. easyAssign.message = "Реактор принят."
  1399. maybeChatSay("accepted", "Реактор принят. Смотри монитор.")
  1400. screenAssignEasy()
  1401. return
  1402. end
  1403. if easyAssign.step == "shield" then
  1404. if componentType ~= "flux_gate" then
  1405. easyAssign.message = "Нужен flux_gate."
  1406. screenAssignEasy()
  1407. return
  1408. end
  1409. if isAddressUsed(address) then
  1410. easyAssign.message = "Адрес уже используется."
  1411. screenAssignEasy()
  1412. return
  1413. end
  1414. easyAssign.shield = address
  1415. easyAssign.step = "output"
  1416. easyAssign.message = "Гейт щитов принят."
  1417. maybeChatSay("accepted", "Гейт щитов принят. Смотри монитор.")
  1418. screenAssignEasy()
  1419. return
  1420. end
  1421. if easyAssign.step == "output" then
  1422. if componentType ~= "flux_gate" then
  1423. easyAssign.message = "Нужен flux_gate."
  1424. screenAssignEasy()
  1425. return
  1426. end
  1427. if isAddressUsed(address) or address == easyAssign.shield then
  1428. easyAssign.message = "Нужны два разных гейта."
  1429. screenAssignEasy()
  1430. return
  1431. end
  1432. easyAssign.output = address
  1433. local saved = saveAssignedGates(easyAssign.core, easyAssign.shield, easyAssign.output)
  1434. if not saved then
  1435. easyAssign.message = "Не удалось сохранить."
  1436. screenAssignEasy()
  1437. return
  1438. end
  1439. easyAssign.saved = true
  1440. easyAssign.step = "done"
  1441. easyAssign.message = "Успешно сохранено."
  1442. maybeChatSay("accepted", "Успешно сохранено. Смотри монитор.")
  1443. screenAssignEasy()
  1444. return
  1445. end
  1446. end
  1447.  
  1448. local function handleComponentAdded(_, address, componentType)
  1449. if not handleAssign or assignMode ~= "easy" or not easyAssign.active then
  1450. return
  1451. end
  1452. acceptEasyComponent(address, componentType)
  1453. end
  1454.  
  1455. local function pollEasyAssign()
  1456. if not handleAssign or assignMode ~= "easy" or not easyAssign.active then
  1457. return
  1458. end
  1459. if easyAssign.step == "reactor" then
  1460. local addr = findNewComponent("draconic_reactor")
  1461. if addr then
  1462. acceptEasyComponent(addr, "draconic_reactor")
  1463. end
  1464. elseif easyAssign.step == "shield" or easyAssign.step == "output" then
  1465. local addr = findNewComponent("flux_gate")
  1466. if addr then
  1467. acceptEasyComponent(addr, "flux_gate")
  1468. end
  1469. end
  1470. end
  1471.  
  1472. local function refreshReactors(openAssign)
  1473. autostateByAdr = {}
  1474. flowInitByAdr = {}
  1475. autoWaitTempByAdr = {}
  1476. chargeRequestByAdr = {}
  1477. for i=1,#reactors do
  1478. local r = reactors[i]
  1479. autostateByAdr[r.reactorAdr] = r.autostate
  1480. flowInitByAdr[r.reactorAdr] = r.flowInit
  1481. chargeRequestByAdr[r.reactorAdr] = r.chargeRequested
  1482. end
  1483. syncActive()
  1484. local prevAdr = reactors[activeIndex] and reactors[activeIndex].reactorAdr
  1485. reactors = buildReactors() or reactors
  1486. local idx = 1
  1487. if pendingActiveReactorAdr then
  1488. for i=1,#reactors do
  1489. if reactors[i].reactorAdr == pendingActiveReactorAdr then
  1490. idx = i
  1491. break
  1492. end
  1493. end
  1494. pendingActiveReactorAdr = nil
  1495. elseif lastAddedReactorAdr then
  1496. for i=1,#reactors do
  1497. if reactors[i].reactorAdr == lastAddedReactorAdr then
  1498. idx = i
  1499. break
  1500. end
  1501. end
  1502. lastAddedReactorAdr = nil
  1503. elseif prevAdr then
  1504. for i=1,#reactors do
  1505. if reactors[i].reactorAdr == prevAdr then
  1506. idx = i
  1507. break
  1508. end
  1509. end
  1510. end
  1511. setActive(idx)
  1512. if openAssign and newEntriesAdded then
  1513. resetAssignState()
  1514. screenAssign()
  1515. return
  1516. end
  1517. if handleMain then
  1518. screenMain()
  1519. else
  1520. screenOverview()
  1521. end
  1522. end
  1523.  
  1524. local function resetAssignState()
  1525. assignState.reactorIndex = nil
  1526. assignState.reactorAdr = nil
  1527. assignState.shieldGateIdx = nil
  1528. assignState.shieldGateAdr = nil
  1529. assignState.outGateIdx = nil
  1530. assignState.outGateAdr = nil
  1531. assignState.step = "reactor"
  1532. end
  1533.  
  1534. saveAssignedGates = function(reactorAdr, shieldAdr, outAdr)
  1535. if not reactorAdr or not shieldAdr or not outAdr then
  1536. return false
  1537. end
  1538. local entries = readReactorsFile() or {}
  1539. local updated = false
  1540. for i=1,#entries do
  1541. if entries[i].reactorAdr == reactorAdr then
  1542. entries[i].upAdr = outAdr
  1543. entries[i].downAdr = shieldAdr
  1544. updated = true
  1545. break
  1546. end
  1547. end
  1548. if not updated then
  1549. entries[#entries+1] = {
  1550. reactorAdr = reactorAdr,
  1551. upAdr = outAdr,
  1552. downAdr = shieldAdr
  1553. }
  1554. end
  1555. if #entries > MAX_REACTORS then
  1556. local trimmed = {}
  1557. for i=1,MAX_REACTORS do
  1558. trimmed[i] = entries[i]
  1559. end
  1560. entries = trimmed
  1561. end
  1562. writeReactorsFile(entries)
  1563. pendingActiveReactorAdr = reactorAdr
  1564. return true
  1565. end
  1566.  
  1567. local function clearAssignedGates(reactorIndex)
  1568. local reactorsList = listAddresses("draconic_reactor")
  1569. if not reactorsList[reactorIndex] then
  1570. return false
  1571. end
  1572. local entries = readReactorsFile() or {}
  1573. local newEntries = {}
  1574. for i=1,#entries do
  1575. if entries[i].reactorAdr ~= reactorsList[reactorIndex] then
  1576. newEntries[#newEntries+1] = entries[i]
  1577. end
  1578. end
  1579. writeReactorsFile(newEntries)
  1580. return true
  1581. end
  1582. -- Экран обзора реакторов
  1583. screenOverview = function()
  1584. handleMain = false
  1585. handleStart = false
  1586. handleOptions = false
  1587. handleOverview = true
  1588. handleAssign = false
  1589. local x = drawHeader("HiTech Classic is the best")
  1590. reactors = reactors or {}
  1591. local cols = overviewCols(x)
  1592. term.setCursor(1,2)
  1593. menuItem.options.x,menuItem.options.y = term.getCursor()
  1594. gpu.setForeground(color.blue)
  1595. printf(menuItem.options.name)
  1596. menuItem.options.w = textWidth(menuItem.options.name)
  1597. gpu.setForeground(color.white)
  1598. menuItem.overview.x,menuItem.overview.y = term.getCursor()
  1599. gpu.setForeground(color.blue)
  1600. printf(menuItem.overview.name)
  1601. menuItem.overview.w = textWidth(menuItem.overview.name)
  1602. gpu.setForeground(color.white)
  1603. menuItem.refresh.x,menuItem.refresh.y = term.getCursor()
  1604. gpu.setForeground(color.blue)
  1605. printf(menuItem.refresh.name)
  1606. menuItem.refresh.w = textWidth(menuItem.refresh.name)
  1607. gpu.setForeground(color.white)
  1608. menuItem.gates.x,menuItem.gates.y = term.getCursor()
  1609. gpu.setForeground(color.blue)
  1610. printf(menuItem.gates.name)
  1611. menuItem.gates.w = textWidth(menuItem.gates.name)
  1612. gpu.setForeground(color.white)
  1613. for i=1,#reactors do
  1614. local label = string.format("[R%d]",i)
  1615. reactors[i].tab.x,reactors[i].tab.y = term.getCursor()
  1616. reactors[i].tab.w = textWidth(label)
  1617. if i == activeIndex then
  1618. guiWrite(reactors[i].tab.x,reactors[i].tab.y,color.black,color.orange,"%s",label)
  1619. else
  1620. guiWrite(reactors[i].tab.x,reactors[i].tab.y,color.blue,color.white,"%s",label)
  1621. end
  1622. printf(" ")
  1623. end
  1624. drawSeparator(x)
  1625. gpu.setBackground(color.grey)
  1626. gpu.setForeground(color.white)
  1627. gpu.fill(1,4,x,21," ")
  1628. if #reactors == 0 then
  1629. term.setCursor(2,5)
  1630. printf("Нет настроенных реакторов.")
  1631. term.setCursor(2,6)
  1632. printf("Откройте \"Гейты\" и назначьте гейты.")
  1633. return
  1634. end
  1635.  
  1636. gpu.setBackground(color.panel)
  1637. gpu.setForeground(color.white)
  1638. gpu.fill(2,4,x-2,6," ")
  1639. term.setCursor(3,4)
  1640. printf("Сводка")
  1641. term.setCursor(3,5)
  1642. printf("Суммарная прибыль:")
  1643. term.setCursor(28,5)
  1644. getCord(summaryProfitCord)
  1645. term.setCursor(3,6)
  1646. printf("Суммарная EU:")
  1647. term.setCursor(28,6)
  1648. getCord(summaryEuCord)
  1649. term.setCursor(3,7)
  1650. printf("Тратим на щиты RF:")
  1651. term.setCursor(28,7)
  1652. getCord(summaryShieldCord)
  1653. term.setCursor(3,8)
  1654. printf("Суммарная выработка:")
  1655. term.setCursor(28,8)
  1656. getCord(summaryGenCord)
  1657. term.setCursor(3,9)
  1658. printf("Максимум прибыли RF/EU:")
  1659. term.setCursor(28,9)
  1660. getCord(summaryMaxProfitCord)
  1661. local autoX = math.max(40, x - 33)
  1662. term.setCursor(autoX,4)
  1663. printf("Выключены автоматически:")
  1664. term.setCursor(autoX,5)
  1665. getCord(autoStoppedCord)
  1666.  
  1667. gpu.setBackground(color.dark)
  1668. gpu.setForeground(color.white)
  1669. gpu.fill(2,11,x-2,1," ")
  1670. term.setCursor(2,11)
  1671. printf("#")
  1672. term.setCursor(cols.status,11)
  1673. printf("СТАТУС")
  1674. term.setCursor(cols.temp,11)
  1675. printf(" ТЕМП")
  1676. term.setCursor(cols.fuel,11)
  1677. printf("ТОПЛИВО")
  1678. term.setCursor(cols.profit,11)
  1679. printf("ПРИБЫЛЬ")
  1680. term.setCursor(cols.gen,11)
  1681. printf("ГЕН")
  1682. term.setCursor(cols.flow,11)
  1683. printf("ПОТОК")
  1684. term.setCursor(cols.ctrl,11)
  1685. printf("УПР")
  1686. gpu.setForeground(color.dim)
  1687. gpu.fill(2,12,x-2,1,"-")
  1688. gpu.setForeground(color.white)
  1689. gpu.setBackground(color.grey)
  1690. local rowY = 13
  1691. for i=1,#reactors do
  1692. local r = reactors[i]
  1693. term.setCursor(2,rowY)
  1694. printf("#%d",i)
  1695. term.setCursor(cols.status,rowY)
  1696. r.row.status = {x=cols.status,y=rowY}
  1697. term.setCursor(cols.temp,rowY)
  1698. r.row.temp = {x=cols.temp,y=rowY}
  1699. term.setCursor(cols.fuel,rowY)
  1700. r.row.fuel = {x=cols.fuel,y=rowY}
  1701. term.setCursor(cols.profit,rowY)
  1702. r.row.profit = {x=cols.profit,y=rowY}
  1703. term.setCursor(cols.gen,rowY)
  1704. r.row.gen = {x=cols.gen,y=rowY}
  1705. term.setCursor(cols.flow,rowY)
  1706. r.row.flow = {x=cols.flow,y=rowY}
  1707. term.setCursor(cols.ctrl,rowY)
  1708. r.control = r.control or {}
  1709. r.control.dec = {x=cols.ctrl,y=rowY,w=3}
  1710. term.setCursor(cols.ctrl + 4,rowY)
  1711. r.control.inc = {x=cols.ctrl + 4,y=rowY,w=3}
  1712. term.setCursor(cols.ctrl + 8,rowY)
  1713. r.control.auto = {x=cols.ctrl + 8,y=rowY,w=4}
  1714. term.setCursor(cols.ctrl + 13,rowY)
  1715. r.powerBtn.x,r.powerBtn.y = term.getCursor()
  1716. r.powerBtn.w = 3
  1717. rowY = rowY + 1
  1718. end
  1719. end
  1720. -- Инициализация главного экрана
  1721. local function screenMain()
  1722. handleOptions = false
  1723. handleStart = false
  1724. handleMain = true
  1725. handleOverview = false
  1726. handleAssign = false
  1727. if not reactor or not upgate or not downgate then
  1728. screenOverview()
  1729. return
  1730. end
  1731. if reactors[activeIndex] and (not isComponentAlive(reactors[activeIndex].reactorAdr) or not isComponentAlive(reactors[activeIndex].upAdr) or not isComponentAlive(reactors[activeIndex].downAdr)) then
  1732. refreshReactors(false)
  1733. screenOverview()
  1734. return
  1735. end
  1736. local x = drawHeader("HiTech Classic is the best")
  1737. local ok, inf = pcall(reactor.getReactorInfo)
  1738. if not ok or type(inf) ~= "table" then
  1739. refreshReactors(false)
  1740. screenOverview()
  1741. return
  1742. end
  1743. if reactors[activeIndex] and (not isComponentAlive(reactors[activeIndex].reactorAdr) or not isComponentAlive(reactors[activeIndex].upAdr) or not isComponentAlive(reactors[activeIndex].downAdr)) then
  1744. refreshReactors(false)
  1745. screenOverview()
  1746. return
  1747. end
  1748. infcord.status.value = inf.status
  1749. menuItem.options.x,menuItem.options.y =term.getCursor()
  1750. gpu.setForeground(color.blue)
  1751. printf(menuItem.options.name)
  1752. menuItem.options.w = textWidth(menuItem.options.name)
  1753. gpu.setForeground(color.white)
  1754. menuItem.overview.x,menuItem.overview.y = term.getCursor()
  1755. gpu.setForeground(color.blue)
  1756. printf(menuItem.overview.name)
  1757. menuItem.overview.w = textWidth(menuItem.overview.name)
  1758. gpu.setForeground(color.white)
  1759. menuItem.refresh.x,menuItem.refresh.y = term.getCursor()
  1760. gpu.setForeground(color.blue)
  1761. printf(menuItem.refresh.name)
  1762. menuItem.refresh.w = textWidth(menuItem.refresh.name)
  1763. gpu.setForeground(color.white)
  1764. menuItem.gates.x,menuItem.gates.y = term.getCursor()
  1765. gpu.setForeground(color.blue)
  1766. printf(menuItem.gates.name)
  1767. menuItem.gates.w = textWidth(menuItem.gates.name)
  1768. gpu.setForeground(color.white)
  1769. for i=1,#reactors do
  1770. local label = string.format("[R%d]",i)
  1771. reactors[i].tab.x,reactors[i].tab.y = term.getCursor()
  1772. reactors[i].tab.w = textWidth(label)
  1773. if i == activeIndex then
  1774. guiWrite(reactors[i].tab.x,reactors[i].tab.y,color.black,color.orange,"%s",label)
  1775. else
  1776. guiWrite(reactors[i].tab.x,reactors[i].tab.y,color.blue,color.white,"%s",label)
  1777. end
  1778. printf(" ")
  1779. end
  1780. guiWrite(x-25,1,color.yellow,color.panel,"Макс. выраб.: ")
  1781. getCord(infcord.maxgen)
  1782. if inf.generationRate > maxGenerationRate then
  1783. maxGenerationRate = inf.generationRate
  1784. end
  1785. guiWrite(infcord.maxgen.x,infcord.maxgen.y,color.green,color.panel,"%s",numformat(maxGenerationRate))
  1786. drawSeparator(x)
  1787. gpu.setBackground(color.panel)
  1788. gpu.setForeground(color.blue)
  1789. printf(" ПАРАМЕТРЫ ")
  1790. term.setCursor(30,4)
  1791. printf(" УПРАВЛЕНИЕ ")
  1792. gpu.setBackground(color.grey)
  1793. gpu.setForeground(color.white)
  1794. term.setCursor(1,6)
  1795. gpu.setBackground(color.panel)
  1796. printf(" Температура: ")
  1797. gpu.setBackground(color.grey)
  1798. printf(" ")
  1799. getCord(infcord.temp)
  1800. guiWrite(infcord.temp.x,infcord.temp.y,-1,-1,"%0.2f\n",inf.temperature)
  1801. printf(" Вырабатывает: ")
  1802. getCord(infcord.generation)
  1803. guiWrite(infcord.generation.x,infcord.generation.y,-1,-1,"%s \n",numformat(inf.generationRate))
  1804. gpu.setBackground(color.panel)
  1805. printf (" Поток: ")
  1806. gpu.setBackground(color.grey)
  1807. printf(" ")
  1808. getCord(infcord.flow)
  1809. infcord.flow.value = getGateFlow(upgate)
  1810. guiWrite(infcord.flow.x,infcord.flow.y,-1,-1,"%s ",numformat(infcord.flow.value))
  1811. getCord(button.add)
  1812. makeButton(button.add.x + 4, button.add.y ,button.add.name)
  1813. getCord(button.sub)
  1814. makeButton(button.sub.x+2,button.sub.y,button.sub.name)
  1815.  
  1816. printf("\n")
  1817. printf (" Итоговая мосч: ")
  1818. getCord(infcord.puregen)
  1819. guiWrite(infcord.puregen.x,infcord.puregen.y,-1,-1,"%s \n",numformat(inf.generationRate - getGateFlow(downgate)))
  1820. gpu.setBackground(color.panel)
  1821. printf (" Поглощает: ")
  1822. gpu.setBackground(color.grey)
  1823. printf(" ")
  1824. getCord(infcord.drain)
  1825. guiWrite(infcord.drain.x,infcord.drain.y,-1,-1,"%s \n",numformat(getGateFlow(downgate)))
  1826.  
  1827. printf (" Мощность поля: ")
  1828. getCord(infcord.fstrth)
  1829. if inf.maxFieldStrength > 0 then
  1830. 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)
  1831. else
  1832. guiWrite(infcord.fstrth.x,infcord.fstrth.y,-1,-1,"0 / 0 (0 %%) \n")
  1833. end
  1834. gpu.setBackground(color.panel)
  1835. printf (" Насыщенность: ")
  1836. gpu.setBackground(color.grey)
  1837. printf(" ")
  1838. getCord(infcord.esturn)
  1839. if inf.maxEnergySaturation > 0 then
  1840. guiWrite(infcord.esturn.x,infcord.esturn.y,-1,-1,"%d / %d (%0.2f %%) \n",inf.energySaturation,inf.maxEnergySaturation,(inf.energySaturation/inf.maxEnergySaturation)*100)
  1841. else
  1842. guiWrite(infcord.esturn.x,infcord.esturn.y,-1,-1,"0 / 0 (0 %%) \n")
  1843. end
  1844. printf (" Топливо: ")
  1845. getCord(infcord.fuel)
  1846.  
  1847. if inf.fuelConversion/inf.maxFuelConversion < 0.78 then
  1848. guiWrite(infcord.fuel.x,infcord.fuel.y,-1,-1,"%d / %d (%0.2f %%) \n",inf.fuelConversion,inf.maxFuelConversion,(inf.fuelConversion/inf.maxFuelConversion)*100)
  1849. else
  1850. if inf.maxFuelConversion > 0 then
  1851. if inf.status == "online" or inf.status == "charging" or inf.status == "charged" then
  1852. guiWrite(infcord.fuel.x,infcord.fuel.y,color.red,-1,"%d / %d (%0.2f %%) Критический уровень топлива\n",inf.fuelConversion,inf.maxFuelConversion,(inf.fuelConversion/inf.maxFuelConversion)*100)
  1853. else
  1854. guiWrite(infcord.fuel.x,infcord.fuel.y,-1,-1,"%d / %d (%0.2f %%) Критический уровень топлива\n",inf.fuelConversion,inf.maxFuelConversion,(inf.fuelConversion/inf.maxFuelConversion)*100)
  1855. end
  1856. else
  1857. guiWrite(infcord.fuel.x,infcord.fuel.y,-1,-1,"0 / 0 (0 %%) \n")
  1858. end
  1859. end
  1860. gpu.setBackground(color.panel)
  1861. printf (" Расход топлива: ")
  1862. gpu.setBackground(color.grey)
  1863. printf(" ")
  1864. getCord(infcord.fuelconv)
  1865. guiWrite(infcord.fuelconv.x,infcord.fuelconv.y,-1,-1,"%d\n",inf.fuelConversionRate)
  1866.  
  1867. getCord(infcord.core)
  1868. if com.isAvailable("draconic_rf_storage") then
  1869. guiWrite(infcord.core.x,infcord.core.y,-1,-1,coreformat())
  1870. end
  1871. printf("\n")
  1872. button.stop.x,button.stop.y = term.getCursor()
  1873. button.start.x,button.start.y = button.stop.x,button.stop.y + 1
  1874. button.charge.x,button.charge.y = button.stop.x,button.stop.y + 2
  1875. button.stop.w = textWidth(button.stop.name)
  1876. button.start.w = textWidth(button.start.name)
  1877. button.charge.w = textWidth(button.charge.name)
  1878. local controlsY = button.stop.y + 3
  1879. if not chargeHintDismissed then
  1880. local hint1 = "Перед первым запуском поставь поток на 535 000."
  1881. local hint2 = "Потом включай."
  1882. chargeHint.x = 1
  1883. chargeHint.y = math.max(1, screenH - 1)
  1884. local hintY2 = math.min(screenH, chargeHint.y + 1)
  1885. local prevFg = gpu.getForeground()
  1886. local prevBg = gpu.getBackground()
  1887. gpu.setForeground(color.green)
  1888. gpu.setBackground(color.grey)
  1889. gpu.set(chargeHint.x, chargeHint.y, hint1)
  1890. if hintY2 ~= chargeHint.y then
  1891. gpu.set(chargeHint.x, hintY2, hint2)
  1892. end
  1893. gpu.setForeground(prevFg)
  1894. gpu.setBackground(prevBg)
  1895. chargeHint.w = math.max(textWidth(hint1), textWidth(hint2))
  1896. chargeHint.visible = true
  1897. else
  1898. chargeHint.visible = false
  1899. end
  1900. term.setCursor(button.stop.x, controlsY)
  1901. printf(" Автономный режим: ")
  1902. getCord(button.autoon)
  1903. getCord(button.autooff)
  1904. if not autostate then
  1905. guiWrite(button.autooff.x,button.autooff.y,color.red,color.black,"%s\n",button.autooff.name)
  1906. else
  1907. guiWrite(button.autoon.x,button.autoon.y,color.green,color.black,"%s\n",button.autoon.name)
  1908. end
  1909. checkButtons()
  1910.  
  1911. end
  1912. -- Обновление обзора реакторов
  1913. local function refreshOverview()
  1914. if not handleOverview then
  1915. return
  1916. end
  1917. if not reactors or #reactors == 0 then
  1918. return
  1919. end
  1920. gpu.setForeground(color.white)
  1921. local stopPct = cfg.fuelStopPct or 98
  1922. local totalGen = 0
  1923. local totalProfit = 0
  1924. local totalShield = 0
  1925. local maxProfit = 0
  1926. gpu.setBackground(color.grey)
  1927. for i=1,#reactors do
  1928. local r = reactors[i]
  1929. local ok, inf = pcall(r.reactor.getReactorInfo)
  1930. if not ok or type(inf) ~= "table" then
  1931. guiWrite(r.row.status.x,r.row.status.y,color.red,-1,"ERR")
  1932. guiWrite(r.row.temp.x,r.row.temp.y,color.red,-1,"----")
  1933. guiWrite(r.row.fuel.x,r.row.fuel.y,color.red,-1,"----")
  1934. guiWrite(r.row.profit.x,r.row.profit.y,color.red,-1,"----")
  1935. guiWrite(r.row.gen.x,r.row.gen.y,color.red,-1,"----")
  1936. guiWrite(r.row.flow.x,r.row.flow.y,color.red,-1,"----")
  1937. else
  1938. totalGen = totalGen + inf.generationRate
  1939. guiWrite(r.row.gen.x,r.row.gen.y,-1,-1,"%s",numformat(inf.generationRate))
  1940. local flow = getGateFlow(r.upgate)
  1941. guiWrite(r.row.flow.x,r.row.flow.y,-1,-1,"%s",numformat(flow))
  1942. local shieldFlow = getGateFlow(r.downgate)
  1943. totalShield = totalShield + shieldFlow
  1944. local profit = inf.generationRate - shieldFlow
  1945. totalProfit = totalProfit + profit
  1946. if profit > maxProfit then
  1947. maxProfit = profit
  1948. end
  1949. guiWrite(r.row.profit.x,r.row.profit.y,-1,-1,"%s",numformat(profit))
  1950. local tempColor = color.white
  1951. if inf.temperature >= cfg.tempCriticalEdge then
  1952. tempColor = color.red
  1953. elseif inf.temperature >= cfg.safeModeTempWaitEdge then
  1954. tempColor = color.yellow
  1955. end
  1956. guiWrite(r.row.temp.x,r.row.temp.y,tempColor,-1,"%4.0fC",inf.temperature)
  1957. local fuelPct = 0
  1958. if inf.maxFuelConversion > 0 then
  1959. fuelPct = (inf.fuelConversion/inf.maxFuelConversion)*100
  1960. end
  1961. if autoStopped[r.reactorAdr] and (inf.status == "online" or inf.status == "charging" or inf.status == "charged") then
  1962. autoStopped[r.reactorAdr] = nil
  1963. end
  1964. if fuelPct >= stopPct and (inf.status == "online" or inf.status == "charging" or inf.status == "charged") then
  1965. if not autoStopped[r.reactorAdr] then
  1966. r.reactor.stopReactor()
  1967. autoStopped[r.reactorAdr] = true
  1968. end
  1969. end
  1970. local fuelColor = color.white
  1971. if fuelPct >= 80 then
  1972. fuelColor = color.red
  1973. end
  1974. guiWrite(r.row.fuel.x,r.row.fuel.y,fuelColor,-1,"%5.1f%%",fuelPct)
  1975. local stColor = color.white
  1976. if inf.status == "online" or inf.status == "charging" or inf.status == "charged" then
  1977. stColor = color.green
  1978. elseif inf.status == "offline" or inf.status == "stopping" then
  1979. stColor = color.red
  1980. end
  1981. guiWrite(r.row.status.x,r.row.status.y,stColor,-1,"%s",statusText(inf.status))
  1982. makePowerButton(r.control.dec.x,r.control.dec.y,"[-]",color.dim,color.white)
  1983. makePowerButton(r.control.inc.x,r.control.inc.y,"[+]",color.dim,color.white)
  1984. local autoColor = r.autostate and color.green or color.red
  1985. makePowerButton(r.control.auto.x,r.control.auto.y,"AUTO",autoColor,color.white)
  1986. if inf.status == "online" or inf.status == "charging" or inf.status == "charged" then
  1987. r.powerBtn.action = "stop"
  1988. makePowerButton(r.powerBtn.x,r.powerBtn.y,"PWR",color.red,color.white)
  1989. else
  1990. r.powerBtn.action = "start"
  1991. makePowerButton(r.powerBtn.x,r.powerBtn.y,"PWR",color.green,color.white)
  1992. end
  1993. end
  1994. end
  1995. if totalProfit > maxSummaryProfit then
  1996. maxSummaryProfit = totalProfit
  1997. end
  1998. guiWrite(summaryProfitCord.x,summaryProfitCord.y,color.white,color.panel,"%s",numformat(totalProfit))
  1999. guiWrite(summaryEuCord.x,summaryEuCord.y,color.white,color.panel,"%s",numformat(math.floor(totalProfit/8)))
  2000. guiWrite(summaryShieldCord.x,summaryShieldCord.y,color.white,color.panel,"%s",numformat(totalShield))
  2001. guiWrite(summaryGenCord.x,summaryGenCord.y,color.white,color.panel,"%s",numformat(totalGen))
  2002. guiWrite(summaryMaxProfitCord.x,summaryMaxProfitCord.y,color.white,color.panel,"%s / %s",numformat(maxSummaryProfit),numformat(math.floor(maxSummaryProfit/8)))
  2003. local autoList = {}
  2004. for i=1,#reactors do
  2005. if autoStopped[reactors[i].reactorAdr] then
  2006. autoList[#autoList+1] = "R"..i
  2007. end
  2008. end
  2009. local autoText = "нет"
  2010. if #autoList > 0 then
  2011. autoText = table.concat(autoList, ", ")
  2012. end
  2013. guiWrite(autoStoppedCord.x,autoStoppedCord.y,color.red,-1,"%s",autoText)
  2014. end
  2015. local screen = {}
  2016. screen["overview"] = screenOverview
  2017. screen["detail"] = screenMain
  2018. screen["options"] = screenOptions
  2019.  
  2020. local function editOption(param)
  2021. local rd = true
  2022. while rd do
  2023. gpu.fill(param.x, param.y, #tostring(param.value), 1, " ")
  2024. term.setCursor(param.x,param.y)
  2025.  
  2026. param.value = term.read(false,false)
  2027. local val = tonumber(param.value)
  2028. if val then
  2029. param.value = val
  2030. show(color.black,color.grey,param)
  2031. rd = false
  2032. end
  2033. end
  2034. canedit = true
  2035. canclose = true
  2036. screen.options()
  2037. end
  2038.  
  2039. local function add(n,i)
  2040. n.value=n.value+i
  2041. upgate.setSignalLowFlow(n.value)
  2042. return n.value
  2043. end
  2044.  
  2045. local function sub(n,i)
  2046. term.setCursor(n.x,n.y)
  2047. n.value=n.value-i
  2048. return n.value
  2049. end
  2050. -- Обновление информации на экране + анализ поведения температуры
  2051. local function refreshInfo()
  2052. local ok, inf = pcall(reactor.getReactorInfo)
  2053. if not ok or type(inf) ~= "table" then
  2054. refreshReactors(false)
  2055. screenOverview()
  2056. return
  2057. end
  2058. infcord.status.value = inf.status
  2059. gpu.setForeground(color.white)
  2060. local tbuf1 = inf.temperature
  2061. os.sleep(0.1)
  2062. local ok2, inf2 = pcall(reactor.getReactorInfo)
  2063. local tbuf2 = ok2 and type(inf2) == "table" and inf2.temperature or tbuf1
  2064. if handleMain then
  2065. local stopPct = cfg.fuelStopPct or 98
  2066. if cfg.autoProtectTempEdge and inf.temperature >= cfg.autoProtectTempEdge and not autostate then
  2067. autostate = true
  2068. guiWrite(button.autoon.x,button.autoon.y,color.green,color.black,"%s\n",button.autoon.name)
  2069. end
  2070. end
  2071. local fuelPct = 0
  2072. if inf.maxFuelConversion > 0 then
  2073. fuelPct = (inf.fuelConversion/inf.maxFuelConversion)*100
  2074. end
  2075. if autoStopped[reactors[activeIndex].reactorAdr] and (inf.status == "online" or inf.status == "charging" or inf.status == "charged") then
  2076. autoStopped[reactors[activeIndex].reactorAdr] = nil
  2077. end
  2078. if fuelPct >= stopPct and (inf.status == "online" or inf.status == "charging" or inf.status == "charged") then
  2079. if not autoStopped[reactors[activeIndex].reactorAdr] then
  2080. reactor.stopReactor()
  2081. autoStopped[reactors[activeIndex].reactorAdr] = true
  2082. end
  2083. end
  2084. if tbuf2>tbuf1 then
  2085. guiWrite(infcord.temp.x,infcord.temp.y,color.red,-1,"%0.2f \n",inf.temperature)
  2086. temprise = true
  2087. elseif tbuf2<tbuf1 then
  2088. guiWrite(infcord.temp.x,infcord.temp.y,color.blue,-1,"%0.2f \n",inf.temperature)
  2089. temprise = false
  2090. else
  2091. if inf.temperature == 2000 then
  2092. guiWrite(infcord.temp.x,infcord.temp.y,-1,-1,"%0.2f \n",inf.temperature)
  2093. end
  2094. end
  2095. guiWrite(infcord.generation.x,infcord.generation.y,-1,-1,"%s\n",numformat(inf.generationRate))
  2096. if inf.generationRate > maxGenerationRate then
  2097. maxGenerationRate = inf.generationRate
  2098. end
  2099. guiWrite(infcord.maxgen.x,infcord.maxgen.y,color.green,color.panel,"%s",numformat(maxGenerationRate))
  2100. infcord.flow.value = getGateFlow(upgate)
  2101. guiWrite(infcord.flow.x,infcord.flow.y,-1,-1,"%s",numformat(infcord.flow.value))
  2102. guiWrite(infcord.puregen.x,infcord.puregen.y,-1,-1,"%s\n",numformat(inf.generationRate - getGateFlow(downgate)))
  2103. infcord.drain.value = inf.fieldDrainRate
  2104. guiWrite(infcord.drain.x,infcord.drain.y,-1,-1,"%s\n",numformat(getGateFlow(downgate)))
  2105. if inf.maxFieldStrength > 0 then
  2106. 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)
  2107. else
  2108. guiWrite(infcord.fstrth.x,infcord.fstrth.y,-1,-1,"0 / 0 (0 %%) \n")
  2109. end
  2110. if inf.maxEnergySaturation > 0 then
  2111. guiWrite(infcord.esturn.x,infcord.esturn.y,-1,-1,"%d / %d (%0.2f %%) \n",inf.energySaturation,inf.maxEnergySaturation,(inf.energySaturation/inf.maxEnergySaturation)*100)
  2112. else
  2113. guiWrite(infcord.esturn.x,infcord.esturn.y,-1,-1,"0 / 0 (0 %%) \n")
  2114. end
  2115. if inf.fuelConversion/inf.maxFuelConversion < 0.78 then
  2116. guiWrite(infcord.fuel.x,infcord.fuel.y,-1,-1,"%d / %d (%0.2f %%) \n",inf.fuelConversion,inf.maxFuelConversion,(inf.fuelConversion/inf.maxFuelConversion)*100)
  2117. else
  2118. if inf.maxFuelConversion > 0 then
  2119. if inf.status == "online" or inf.status == "charging" or inf.status == "charged" then
  2120. guiWrite(infcord.fuel.x,infcord.fuel.y,color.red,-1,"%d / %d (%0.2f %%) Критический уровень топлива\n",inf.fuelConversion,inf.maxFuelConversion,(inf.fuelConversion/inf.maxFuelConversion)*100)
  2121. else
  2122. guiWrite(infcord.fuel.x,infcord.fuel.y,-1,-1,"%d / %d (%0.2f %%) Критический уровень топлива\n",inf.fuelConversion,inf.maxFuelConversion,(inf.fuelConversion/inf.maxFuelConversion)*100)
  2123. end
  2124. else
  2125. guiWrite(infcord.fuel.x,infcord.fuel.y,-1,-1,"0 / 0 (0 %%)\n")
  2126. end
  2127. end
  2128. guiWrite(infcord.fuelconv.x,infcord.fuelconv.y,-1,-1,"%d\n",inf.fuelConversionRate)
  2129. if com.isAvailable("draconic_rf_storage") then
  2130. guiWrite(infcord.core.x,infcord.core.y,-1,-1,coreformat())
  2131. if button.stop.y ~= infcord.core.y + 2 then
  2132. screenMain()
  2133. end
  2134. elseif button.stop.y ~= infcord.fuelconv.y + 2 then
  2135. screenMain()
  2136. end
  2137. checkButtons()
  2138. syncActive()
  2139. end
  2140. end
  2141. -- Алгоритм автономного режима
  2142. local function autoForReactor(r, state)
  2143. if not r or not r.reactor or not r.upgate or not r.downgate then
  2144. return
  2145. end
  2146. local ok, inf = pcall(r.reactor.getReactorInfo)
  2147. if not ok or type(inf) ~= "table" then
  2148. return
  2149. end
  2150. local now = computer.uptime()
  2151. if r.chargeRequested and now <= r.chargeRequested then
  2152. local downflow = 900000
  2153. r.downgate.setOverrideEnabled(true)
  2154. r.downgate.setFlowOverride(downflow)
  2155. return
  2156. end
  2157. if inf.status == "charging" then
  2158. local downflow = 900000
  2159. r.downgate.setOverrideEnabled(true)
  2160. r.downgate.setFlowOverride(downflow)
  2161. return
  2162. end
  2163. local isActive = reactors[activeIndex] and reactors[activeIndex].reactorAdr == r.reactorAdr
  2164. if cfg.autoProtectTempEdge and inf.temperature >= cfg.autoProtectTempEdge and not r.autostate then
  2165. r.autostate = true
  2166. if isActive then
  2167. autostate = true
  2168. if handleMain and button.autoon.x then
  2169. guiWrite(button.autoon.x,button.autoon.y,color.green,color.black,"%s\n",button.autoon.name)
  2170. end
  2171. end
  2172. end
  2173. local shieldPct = cfg.shield or 25
  2174. local flow = getGateFlow(r.upgate)
  2175. if type(flow) ~= "number" then
  2176. flow = 0
  2177. end
  2178. local drain = inf.fieldDrainRate
  2179. if state then
  2180. local forceEdge = cfg.forceModeTempLowEdge or 7600
  2181. if forceEdge < 7600 then
  2182. forceEdge = 7600
  2183. end
  2184. local waittemp = autoWaitTempByAdr[r.reactorAdr]
  2185. local tempRise = false
  2186. if r.lastTemp then
  2187. if inf.temperature > r.lastTemp then
  2188. tempRise = true
  2189. elseif inf.temperature < r.lastTemp then
  2190. tempRise = false
  2191. else
  2192. tempRise = r.temprise or false
  2193. end
  2194. end
  2195. r.lastTemp = inf.temperature
  2196. r.temprise = tempRise
  2197. local downflow = drain / (1 - (shieldPct/100))
  2198. r.downgate.setOverrideEnabled(true)
  2199. r.downgate.setFlowOverride(downflow)
  2200. if inf.temperature <= forceEdge then
  2201. if flow - inf.generationRate <= cfg.forceModeStepCase then
  2202. flow = flow + cfg.forceModeStep
  2203. r.upgate.setSignalLowFlow(flow)
  2204. end
  2205. elseif flow - inf.generationRate <= cfg.safeModeStepCase and inf.temperature >= forceEdge then
  2206. if not waittemp then
  2207. flow = getGateFlow(r.upgate) + cfg.safemodeStep
  2208. r.upgate.setSignalLowFlow(flow)
  2209. elseif inf.temperature < cfg.safeModeTempToWaitEdge then
  2210. waittemp = false
  2211. end
  2212. elseif tempRise and inf.temperature >= cfg.safeModeTempWaitEdge then
  2213. if inf.temperature > cfg.safeModeTempWaitEdge then
  2214. waittemp = true
  2215. end
  2216. if inf.temperature > cfg.tempCriticalEdge then
  2217. flow = inf.generationRate - 1000
  2218. r.upgate.setSignalLowFlow(flow)
  2219. end
  2220. end
  2221. autoWaitTempByAdr[r.reactorAdr] = waittemp
  2222. if isActive and handleMain and infcord.flow.x then
  2223. infcord.flow.value = flow
  2224. guiWrite(infcord.flow.x,infcord.flow.y,color.red,color.grey,"%s",numformat(flow))
  2225. end
  2226. else
  2227. local downflow
  2228. if inf.status == "charging" then
  2229. downflow = 900000
  2230. else
  2231. downflow = drain / (1 - (shieldPct/100))
  2232. end
  2233. if inf.status == "charging" then
  2234. r.downgate.setOverrideEnabled(true)
  2235. r.downgate.setFlowOverride(downflow)
  2236. else
  2237. r.downgate.setOverrideEnabled(false)
  2238. r.downgate.setSignalHighFlow(downflow)
  2239. r.downgate.setSignalLowFlow(downflow)
  2240. end
  2241. end
  2242. end
  2243. -- Обработчик событий
  2244. local function tcall(type,scrnAdr,x,y,btn,player)
  2245. local rx,ry = gpu.getResolution()
  2246. --выход
  2247. if x >= rx-2 and x<=rx and y == 1 then
  2248. event.ignore("touch",tcall)
  2249. prog = false
  2250. ops = false
  2251. end
  2252. if handleStart then
  2253. 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
  2254. resetAssignState()
  2255. screenAssign()
  2256. return
  2257. end
  2258. end
  2259. -- Главный экран
  2260. if handleMain then
  2261. -- Увеличение
  2262. if x >= button.add.x+4 and x <= button.add.x+3+#button.add.name and y == button.add.y then
  2263. if keyb.isShiftDown() then
  2264. if keyb.isControlDown() then
  2265. upgate.setSignalLowFlow(add(infcord.flow,cfg.ctrlShift_interval))
  2266. else
  2267. upgate.setSignalLowFlow(add(infcord.flow,cfg.shift_interval))
  2268. end
  2269. else
  2270. if keyb.isControlDown() then
  2271. upgate.setSignalLowFlow(add(infcord.flow,cfg.ctrl_interval))
  2272. else
  2273. upgate.setSignalLowFlow(add(infcord.flow,cfg.default_interval))
  2274. end
  2275. end
  2276. guiWrite(infcord.flow.x,infcord.flow.y,color.red,color.grey,"%s",numformat(infcord.flow.value))
  2277. end
  2278. --Уменьшение
  2279. if x >= button.sub.x+2 and x <= button.sub.x+1+#button.sub.name and y == button.sub.y then
  2280. if keyb.isShiftDown() then
  2281. if keyb.isControlDown() then
  2282. upgate.setSignalLowFlow(sub(infcord.flow,cfg.ctrlShift_interval))
  2283. else
  2284. upgate.setSignalLowFlow(sub(infcord.flow,cfg.shift_interval))
  2285. end
  2286. else
  2287. if keyb.isControlDown() then
  2288. upgate.setSignalLowFlow(sub(infcord.flow,cfg.ctrl_interval))
  2289. else
  2290. upgate.setSignalLowFlow(sub(infcord.flow,cfg.default_interval))
  2291. end
  2292. end
  2293. guiWrite(infcord.flow.x,infcord.flow.y,color.blue,color.grey,"%s",numformat(infcord.flow.value))
  2294. end
  2295.  
  2296. if not autostate then
  2297. if x >= button.autooff.x and x <= button.autooff.x + textWidth(button.autooff.name) - 1 and y == button.autooff.y then
  2298. gpu.set(button.autooff.x, button.autooff.y," ")
  2299. autostate = true
  2300. guiWrite(button.autoon.x,button.autoon.y,color.green,color.black,"%s\n",button.autoon.name)
  2301. end
  2302. else
  2303. if x >= button.autoon.x and x <= button.autoon.x + textWidth(button.autoon.name) - 1 and y == button.autoon.y then
  2304. gpu.set(button.autoon.x, button.autoon.y," ")
  2305. autostate = false
  2306. guiWrite(button.autooff.x,button.autooff.y,color.red,color.black,"%s\n",button.autooff.name)
  2307. end
  2308. end
  2309. do
  2310. local w = button.charge.w or textWidth(button.charge.name)
  2311. 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
  2312. local usedNativeCharge = false
  2313. if reactor and reactor.chargeReactor then
  2314. local ok = pcall(reactor.chargeReactor)
  2315. if ok then
  2316. usedNativeCharge = true
  2317. end
  2318. end
  2319. if not usedNativeCharge then
  2320. ensureFlowInit(reactors[activeIndex], true)
  2321. if upgate then
  2322. upgate.setSignalLowFlow(CHARGE_FLOW)
  2323. end
  2324. infcord.flow.value = CHARGE_FLOW
  2325. if infcord.flow.x then
  2326. guiWrite(infcord.flow.x,infcord.flow.y,color.red,color.grey,"%s",numformat(infcord.flow.value))
  2327. end
  2328. end
  2329. if chargeHint.visible and chargeHint.x and chargeHint.y then
  2330. guiWrite(chargeHint.x, chargeHint.y, color.white, color.grey, "%s", string.rep(" ", chargeHint.w))
  2331. guiWrite(chargeHint.x, chargeHint.y + 1, color.white, color.grey, "%s", string.rep(" ", chargeHint.w))
  2332. chargeHint.visible = false
  2333. chargeHintDismissed = true
  2334. end
  2335. guiWrite(button.charge.x,button.charge.y,-1,color.grey," ",button.charge.name)
  2336. button.charge.visible = false
  2337. if not usedNativeCharge then
  2338. local currentReactor = reactors[activeIndex]
  2339. if currentReactor and currentReactor.reactorAdr then
  2340. local chargeUntil = computer.uptime() + CHARGE_DURATION
  2341. currentReactor.chargeRequested = chargeUntil
  2342. chargeRequestByAdr[currentReactor.reactorAdr] = chargeUntil
  2343. end
  2344. end
  2345. end
  2346. end
  2347. if button.start.visible then
  2348. local w = button.start.w or textWidth(button.start.name)
  2349. if x >= button.start.x and x <= button.start.x + w - 1 and y == button.start.y then
  2350. ensureFlowInit(reactors[activeIndex])
  2351. reactor.activateReactor()
  2352. if reactors[activeIndex] then
  2353. autoStopped[reactors[activeIndex].reactorAdr] = nil
  2354. end
  2355. guiWrite(button.start.x,button.start.y,-1,color.grey," ",button.start.name)
  2356. button.start.visible = false
  2357. end
  2358. end
  2359. if button.stop.visible then
  2360. local w = button.stop.w or textWidth(button.stop.name)
  2361. if x >= button.stop.x and x <= button.stop.x + w - 1 and y == button.stop.y then
  2362. reactor.stopReactor()
  2363. guiWrite(button.stop.x,button.stop.y,-1,color.grey," ",button.stop.name)
  2364. button.stop.visible = false
  2365. end
  2366. end
  2367. --меню
  2368. if x>= menuItem.options.x and x <= (menuItem.options.x + (menuItem.options.w or #menuItem.options.name) - 1) and y == menuItem.options.y then
  2369. screenOptions()
  2370. return
  2371. end
  2372. if x>= menuItem.overview.x and x <= (menuItem.overview.x + (menuItem.overview.w or #menuItem.overview.name) - 1) and y == menuItem.overview.y then
  2373. syncActive()
  2374. screenOverview()
  2375. return
  2376. end
  2377. if x>= menuItem.refresh.x and x <= (menuItem.refresh.x + (menuItem.refresh.w or #menuItem.refresh.name) - 1) and y == menuItem.refresh.y then
  2378. refreshReactors(true)
  2379. return
  2380. end
  2381. if x>= menuItem.gates.x and x <= (menuItem.gates.x + (menuItem.gates.w or #menuItem.gates.name) - 1) and y == menuItem.gates.y then
  2382. resetAssignState()
  2383. screenAssign()
  2384. return
  2385. end
  2386. for i=1,#reactors do
  2387. local tab = reactors[i].tab
  2388. if tab.x and x >= tab.x and x <= tab.x + tab.w - 1 and y == tab.y then
  2389. syncActive()
  2390. setActive(i)
  2391. screenMain()
  2392. return
  2393. end
  2394. end
  2395. if x == 1 and y == 1 then
  2396. event.ignore("touch",tcall)
  2397. prog = false
  2398. end
  2399. end
  2400. -- Экран обзора
  2401. if handleOverview then
  2402. if x>= menuItem.options.x and x <= (menuItem.options.x + (menuItem.options.w or #menuItem.options.name) - 1) and y == menuItem.options.y then
  2403. screenOptions()
  2404. return
  2405. end
  2406. if x>= menuItem.refresh.x and x <= (menuItem.refresh.x + (menuItem.refresh.w or #menuItem.refresh.name) - 1) and y == menuItem.refresh.y then
  2407. refreshReactors(true)
  2408. return
  2409. end
  2410. if x>= menuItem.gates.x and x <= (menuItem.gates.x + (menuItem.gates.w or #menuItem.gates.name) - 1) and y == menuItem.gates.y then
  2411. resetAssignState()
  2412. screenAssign()
  2413. return
  2414. end
  2415. for i=1,#reactors do
  2416. local tab = reactors[i].tab
  2417. if tab.x and x >= tab.x and x <= tab.x + tab.w - 1 and y == tab.y then
  2418. syncActive()
  2419. setActive(i)
  2420. screenMain()
  2421. return
  2422. end
  2423. local ctrl = reactors[i].control
  2424. 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
  2425. local flow = getGateFlow(reactors[i].upgate)
  2426. reactors[i].upgate.setSignalLowFlow(flow - cfg.default_interval)
  2427. return
  2428. end
  2429. 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
  2430. local flow = getGateFlow(reactors[i].upgate)
  2431. reactors[i].upgate.setSignalLowFlow(flow + cfg.default_interval)
  2432. return
  2433. end
  2434. 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
  2435. reactors[i].autostate = not reactors[i].autostate
  2436. if i == activeIndex then
  2437. autostate = reactors[i].autostate
  2438. end
  2439. refreshOverview()
  2440. return
  2441. end
  2442. local btn = reactors[i].powerBtn
  2443. if btn.x and x >= btn.x and x <= btn.x + btn.w - 1 and y == btn.y then
  2444. if btn.action == "start" then
  2445. ensureFlowInit(reactors[i])
  2446. reactors[i].reactor.activateReactor()
  2447. autoStopped[reactors[i].reactorAdr] = nil
  2448. else
  2449. reactors[i].reactor.stopReactor()
  2450. end
  2451. return
  2452. end
  2453. end
  2454. if x == 1 and y == 1 then
  2455. event.ignore("touch",tcall)
  2456. prog = false
  2457. end
  2458. end
  2459. -- Экран настроек
  2460. if handleOptions then
  2461. -- Работа со значениями
  2462. if canedit then
  2463. if x >= OptionDefault.x and x <= OptionDefault.x + #tostring(OptionDefault.value)-1 and y == OptionDefault.y then
  2464. canclose = false
  2465. canedit = false
  2466. editOption(OptionDefault)
  2467. end
  2468. if x >= OptionCtrl.x and x <= OptionCtrl.x + #tostring(OptionCtrl.value)-1 and y == OptionCtrl.y then
  2469. canclose = false
  2470. canedit = false
  2471. editOption(OptionCtrl)
  2472. end
  2473. if x >= OptionShift.x and x <= OptionShift.x + #tostring(OptionShift.value)-1 and y == OptionShift.y then
  2474. canclose = false
  2475. canedit = false
  2476. editOption(OptionShift)
  2477. end
  2478. if x >= OptionCtrlShift.x and x <= OptionCtrlShift.x + #tostring(OptionCtrlShift.value)-1 and y == OptionCtrlShift.y then
  2479. canclose = false
  2480. canedit = false
  2481. editOption(OptionCtrlShift)
  2482. end
  2483. if x >= OptionShield.x and x <= OptionShield.x + #tostring(OptionShield.value)-1 and y == OptionShield.y then
  2484. canclose = false
  2485. canedit = false
  2486. editOption(OptionShield)
  2487. end
  2488. if x >= OptionFuelStop.x and x <= OptionFuelStop.x + #tostring(OptionFuelStop.value)-1 and y == OptionFuelStop.y then
  2489. canclose = false
  2490. canedit = false
  2491. editOption(OptionFuelStop)
  2492. end
  2493. end
  2494. -- меню
  2495. if canclose then
  2496. if x>= menuItem.optionsBack.x and x <= (menuItem.optionsBack.x + (menuItem.optionsBack.w or #menuItem.optionsBack.name) - 1) and y == menuItem.optionsBack.y then
  2497. screenOverview()
  2498. return
  2499. end
  2500. if x>= menuItem.save.x and x <= (menuItem.save.x + (menuItem.save.w or #menuItem.save.name) - 1) and y == menuItem.save.y then
  2501. cfg.default_interval = OptionDefault.value
  2502. cfg.ctrl_interval = OptionCtrl.value
  2503. cfg.shift_interval = OptionShift.value
  2504. cfg.ctrlShift_interval = OptionCtrlShift.value
  2505. cfg.shield = OptionShield.value
  2506. cfg.fuelStopPct = OptionFuelStop.value
  2507. configWrite(cfgName)
  2508. screenOverview()
  2509. return
  2510. end
  2511. if x>= menuItem.cancel.x and x <= (menuItem.cancel.x + (menuItem.cancel.w or #menuItem.cancel.name) - 1) and y == menuItem.cancel.y then
  2512. OptionDefault.value = cfg.default_interval
  2513. OptionCtrl.value = cfg.ctrl_interval
  2514. OptionShift.value = cfg.shift_interval
  2515. OptionCtrlShift.value = cfg.ctrlShift_interval
  2516. OptionShield.value = cfg.shield
  2517. OptionFuelStop.value = cfg.fuelStopPct or 98
  2518. screenOverview()
  2519. return
  2520. end
  2521. end
  2522. end
  2523. -- Экран гейтов
  2524. -- gates screen
  2525. if handleAssign then
  2526. if assignMode ~= "manual" and assignMode ~= "easy" then
  2527. if easyAssign.backBtn.x and x>= easyAssign.backBtn.x and x <= easyAssign.backBtn.x + easyAssign.backBtn.w - 1 and y == easyAssign.backBtn.y then
  2528. assignMode = nil
  2529. easyAssign.active = false
  2530. screenOverview()
  2531. return
  2532. end
  2533. if easyAssign.heavyBtn.x and x >= easyAssign.heavyBtn.x and x <= easyAssign.heavyBtn.x + easyAssign.heavyBtn.w - 1 and y == easyAssign.heavyBtn.y then
  2534. assignMode = "manual"
  2535. resetAssignState()
  2536. screenAssignManual()
  2537. return
  2538. end
  2539. if easyAssign.easyBtn.x and x >= easyAssign.easyBtn.x and x <= easyAssign.easyBtn.x + easyAssign.easyBtn.w - 1 and y == easyAssign.easyBtn.y then
  2540. assignMode = "easy"
  2541. startEasyAssign()
  2542. if not easyAssign.active then
  2543. assignMode = nil
  2544. screenAssignChoice()
  2545. else
  2546. screenAssignEasy()
  2547. end
  2548. return
  2549. end
  2550. return
  2551. elseif assignMode == "easy" then
  2552. if easyAssign.backBtn.x and x>= easyAssign.backBtn.x and x <= easyAssign.backBtn.x + easyAssign.backBtn.w - 1 and y == easyAssign.backBtn.y then
  2553. if easyAssign.saved and easyAssign.core then
  2554. clearAssignedByAdr(easyAssign.core)
  2555. end
  2556. easyAssign.active = false
  2557. easyAssign.step = "reactor"
  2558. easyAssign.core = nil
  2559. easyAssign.shield = nil
  2560. easyAssign.output = nil
  2561. easyAssign.saved = false
  2562. easyAssign.message = nil
  2563. assignMode = nil
  2564. screenAssignChoice()
  2565. return
  2566. end
  2567. if easyAssign.step == "done" then
  2568. if easyAssign.continueBtn.x and x >= easyAssign.continueBtn.x and x <= easyAssign.continueBtn.x + easyAssign.continueBtn.w - 1 and y == easyAssign.continueBtn.y then
  2569. startEasyAssign()
  2570. screenAssignEasy()
  2571. return
  2572. end
  2573. if easyAssign.finishBtn.x and x >= easyAssign.finishBtn.x and x <= easyAssign.finishBtn.x + easyAssign.finishBtn.w - 1 and y == easyAssign.finishBtn.y then
  2574. easyAssign.active = false
  2575. assignMode = nil
  2576. refreshReactors(false)
  2577. screenOverview()
  2578. return
  2579. end
  2580. end
  2581. return
  2582. end
  2583. if x>= menuItem.back.x and x <= (menuItem.back.x + (menuItem.back.w or #menuItem.back.name) - 1) and y == menuItem.back.y then
  2584. if not assignState.reactorIndex and not assignState.shieldGateIdx and not assignState.outGateIdx then
  2585. resetAssignState()
  2586. assignMode = nil
  2587. screenOverview()
  2588. return
  2589. end
  2590. assignState.message = "Выбери гейты!"
  2591. screenAssign()
  2592. return
  2593. end
  2594. if assignUi.reset and x>= assignUi.reset.x and x <= assignUi.reset.x + assignUi.reset.w - 1 and y == assignUi.reset.y then
  2595. if assignState.reactorIndex then
  2596. clearAssignedGates(assignState.reactorIndex)
  2597. reactors = buildReactors() or reactors
  2598. resetAssignState()
  2599. screenAssign()
  2600. end
  2601. return
  2602. end
  2603. for i=1,#assignUi.reactors do
  2604. local btn = assignUi.reactors[i]
  2605. if btn and x >= btn.x and x <= btn.x + btn.w - 1 and y == btn.y then
  2606. assignState.reactorIndex = i
  2607. assignState.reactorAdr = assignUi.reactorAddrs[i]
  2608. assignState.shieldGateIdx = nil
  2609. assignState.shieldGateAdr = nil
  2610. assignState.outGateIdx = nil
  2611. assignState.outGateAdr = nil
  2612. assignState.step = "shield"
  2613. screenAssign()
  2614. return
  2615. end
  2616. end
  2617. for i=1,#assignUi.gates do
  2618. local btn = assignUi.gates[i]
  2619. if btn and x >= btn.x and x <= btn.x + btn.w - 1 and y == btn.y then
  2620. local gateAdr = assignUi.gateAddrs[i]
  2621. if assignState.step == "reactor" then
  2622. return
  2623. end
  2624. if gateAdr and assignUi.gateUse[gateAdr] and assignUi.gateUse[gateAdr] ~= assignUi.selectedAdr then
  2625. return
  2626. end
  2627. local selectedEntry = assignUi.selectedEntry
  2628. if not assignState.reactorIndex then
  2629. assignState.step = "reactor"
  2630. screenAssign()
  2631. return
  2632. end
  2633. if assignState.step == "shield" then
  2634. assignState.shieldGateIdx = i
  2635. assignState.shieldGateAdr = gateAdr
  2636. assignState.step = "output"
  2637. screenAssign()
  2638. return
  2639. elseif assignState.step == "output" then
  2640. if assignState.shieldGateAdr and assignState.shieldGateAdr == gateAdr then
  2641. assignState.message = "Нужны два разных гейта!"
  2642. screenAssign()
  2643. return
  2644. end
  2645. assignState.outGateIdx = i
  2646. assignState.outGateAdr = gateAdr
  2647. if not assignState.reactorAdr and assignState.reactorIndex then
  2648. assignState.reactorAdr = assignUi.reactorAddrs[assignState.reactorIndex]
  2649. end
  2650. if not assignState.shieldGateAdr and assignState.shieldGateIdx then
  2651. assignState.shieldGateAdr = assignUi.gateAddrs[assignState.shieldGateIdx]
  2652. end
  2653. local saved = saveAssignedGates(assignState.reactorAdr, assignState.shieldGateAdr, assignState.outGateAdr)
  2654. if not saved then
  2655. assignState.message = "Не удалось сохранить гейты!"
  2656. screenAssign()
  2657. return
  2658. end
  2659. local targetAdr = assignState.reactorAdr
  2660. resetAssignState()
  2661. assignMode = nil
  2662. handleAssign = false
  2663. handleMain = true
  2664. handleOverview = false
  2665. reactors = buildReactors() or reactors
  2666. local idx = 1
  2667. if targetAdr then
  2668. for j=1,#reactors do
  2669. if reactors[j].reactorAdr == targetAdr then
  2670. idx = j
  2671. break
  2672. end
  2673. end
  2674. end
  2675. setActive(idx)
  2676. if not reactors or #reactors == 0 or not reactor or not upgate or not downgate then
  2677. screenOverview()
  2678. return
  2679. end
  2680. screenMain()
  2681. return
  2682. end
  2683. end
  2684. end
  2685. if x == 1 and y == 1 then
  2686. event.ignore("touch",tcall)
  2687. prog = false
  2688. end
  2689. end
  2690. end
  2691.  
  2692. event.listen("touch",tcall)
  2693. event.listen("component_added", handleComponentAdded)
  2694. screenStart()
  2695. if upgate ~= nil and downgate ~= nil then
  2696. screen.overview()
  2697. end
  2698. while prog do
  2699. local now = computer.uptime()
  2700. if handleMain and now - lastDetailUpdate >= 0.2 then
  2701. lastDetailUpdate = now
  2702. if not pcall(refreshInfo) then
  2703. autostate = false
  2704. if not pcall(screenStart) then
  2705. break
  2706. end
  2707. if not pcall(screenMain) then
  2708. screenStart()
  2709. if not pcall(screenMain) then
  2710. break
  2711. end
  2712. end
  2713. end
  2714. elseif handleOverview and now - lastOverviewUpdate >= 0.5 then
  2715. lastOverviewUpdate = now
  2716. if not pcall(refreshOverview) then
  2717. if not pcall(screenOverview) then
  2718. break
  2719. end
  2720. end
  2721. end
  2722. if reactors and #reactors > 0 then
  2723. for i=1,#reactors do
  2724. autoForReactor(reactors[i], reactors[i].autostate)
  2725. end
  2726. end
  2727. pollEasyAssign()
  2728. os.sleep(0)
  2729. end
  2730. gpu.setBackground(rback)
  2731. gpu.setForeground(rfore)
  2732. gpu.setResolution(xz,yz)
  2733. term.clear()
  2734.  
  2735.  
  2736.  
  2737.  
  2738.  
Add Comment
Please, Sign In to add comment