Guest User

Untitled

a guest
Feb 19th, 2026
332
0
Never
1
Not a member of Pastebin yet? Sign Up, it unlocks many cool features!
text 15.27 KB | None | 0 0
  1. local MONITOR_SIDE = "back"
  2. local UPDATE_DELAY = 0.5
  3. local AVG_SAMPLES = 10
  4. local CORE_TIER = 6
  5. local GRAPH_HISTORY = 4000
  6.  
  7. local THEME = {
  8. bg = colors.black,
  9. header = colors.blue,
  10. border = colors.cyan,
  11. ok = colors.lime,
  12. warn = colors.orange,
  13. bad = colors.red,
  14. text = colors.white,
  15. dim = colors.lightGray,
  16. barBack = colors.gray,
  17. yellow = colors.yellow,
  18. }
  19.  
  20. local function clamp(x, a, b)
  21. if x < a then return a end
  22. if x > b then return b end
  23. return x
  24. end
  25.  
  26. local function formatNumber(n)
  27. n = tonumber(n) or 0
  28. local absn = math.abs(n)
  29. if absn >= 1e12 then return string.format("%.2f T", n / 1e12)
  30. elseif absn >= 1e9 then return string.format("%.2f G", n / 1e9)
  31. elseif absn >= 1e6 then return string.format("%.2f M", n / 1e6)
  32. elseif absn >= 1e3 then return string.format("%.2f K", n / 1e3)
  33. else return string.format("%.0f", n) end
  34. end
  35.  
  36. local function writeAt(mon, x, y, s, fg, bg)
  37. if bg then mon.setBackgroundColor(bg) end
  38. if fg then mon.setTextColor(fg) end
  39. mon.setCursorPos(x, y)
  40. mon.write(s)
  41. end
  42.  
  43. local function safeWrite(mon, x, y, s, fg, bg)
  44. local w, h = mon.getSize()
  45. if y < 1 or y > h or x > w then return end
  46. if x < 1 then
  47. local cut = 1 - x
  48. s = s:sub(cut + 1)
  49. x = 1
  50. end
  51. if #s <= 0 then return end
  52. local maxLen = w - x + 1
  53. if maxLen <= 0 then return end
  54. if #s > maxLen then s = s:sub(1, maxLen) end
  55. writeAt(mon, x, y, s, fg, bg)
  56. end
  57.  
  58. local function fillRect(mon, x, y, w, h, bg)
  59. mon.setBackgroundColor(bg)
  60. for dy = 0, h - 1 do
  61. mon.setCursorPos(x, y + dy)
  62. mon.write(string.rep(" ", w))
  63. end
  64. end
  65.  
  66. local function drawBox(mon, x, y, w, h, borderColor, title)
  67. fillRect(mon, x, y, w, h, THEME.bg)
  68. fillRect(mon, x, y, w, 1, borderColor)
  69. fillRect(mon, x, y + h - 1, w, 1, borderColor)
  70.  
  71. mon.setBackgroundColor(borderColor)
  72. for dy = 0, h - 1 do
  73. mon.setCursorPos(x, y + dy); mon.write(" ")
  74. mon.setCursorPos(x + w - 1, y + dy); mon.write(" ")
  75. end
  76.  
  77. if title and #title > 0 then
  78. local t = " " .. title .. " "
  79. local tx = x + 2
  80. local maxRight = x + w - 2
  81. if tx + #t - 1 > maxRight then
  82. t = t:sub(1, maxRight - tx + 1)
  83. end
  84. writeAt(mon, tx, y, t, THEME.text, THEME.bg)
  85. end
  86. end
  87.  
  88. local function clearInner(mon, x, y, w, h)
  89. fillRect(mon, x + 1, y + 1, w - 2, h - 2, THEME.bg)
  90. end
  91.  
  92. local function push(t, v, maxN)
  93. t[#t + 1] = v
  94. if #t > maxN then table.remove(t, 1) end
  95. end
  96.  
  97. local function drawHeader(mon, text)
  98. local w = (mon.getSize())
  99. fillRect(mon, 1, 1, w, 1, THEME.header)
  100. local t = (#text > w) and text:sub(1, w) or text
  101. local x = math.max(1, math.floor((w - #t) / 2) + 1)
  102. safeWrite(mon, x, 1, t, THEME.text, THEME.header)
  103. end
  104.  
  105. local function drawVerticalBar(mon, x, y, width, height, percent, color)
  106. percent = clamp(percent, 0, 100)
  107. local filled = math.floor(height * percent / 100 + 0.0001)
  108. fillRect(mon, x, y, width, height, THEME.barBack)
  109. mon.setBackgroundColor(color)
  110. for i = 0, filled - 1 do
  111. mon.setCursorPos(x, y + height - 1 - i)
  112. mon.write(string.rep(" ", width))
  113. end
  114. end
  115.  
  116. -- Graph helpers
  117. local function graphUpdateScale(currentScale, newAbs)
  118. newAbs = math.max(newAbs, 1)
  119. if newAbs > currentScale then return newAbs end
  120. return math.max(1, currentScale * 0.992)
  121. end
  122.  
  123. local function graphMapY(v, maxAbs, y, h)
  124. local mid = y + math.floor((h - 1) / 2)
  125. local amp = math.floor((h - 1) / 2)
  126. if amp < 1 then return mid end
  127. local n = clamp(v / maxAbs, -1, 1)
  128. local yy = mid - math.floor(n * amp + (n >= 0 and 0.5 or -0.5))
  129. return clamp(yy, y, y + h - 1)
  130. end
  131.  
  132. local function plot(mon, x, y, gx, gy, gw, gh, bg)
  133. if x < gx or x > gx + gw - 1 or y < gy or y > gy + gh - 1 then return end
  134. mon.setBackgroundColor(bg)
  135. mon.setCursorPos(x, y)
  136. mon.write(" ")
  137. end
  138.  
  139. local function drawGraphLine(mon, gx, gy, gw, gh, data, maxAbs)
  140. fillRect(mon, gx, gy, gw, gh, THEME.bg)
  141. local mid = gy + math.floor((gh - 1) / 2)
  142. mon.setBackgroundColor(THEME.dim)
  143. mon.setCursorPos(gx, mid)
  144. mon.write(string.rep(" ", gw))
  145.  
  146. local start = math.max(1, #data - gw + 1)
  147. local prevX, prevY, prevV
  148.  
  149. for i = start, #data do
  150. local col = (i - start) + 1
  151. local x1 = gx + col - 1
  152. local v = data[i] or 0
  153. local y1 = graphMapY(v, maxAbs, gy, gh)
  154.  
  155. local c = THEME.dim
  156. if v > 0 then c = THEME.ok elseif v < 0 then c = THEME.bad end
  157.  
  158. if prevX then
  159. local x0, y0 = prevX, prevY
  160. local dx = math.abs(x1 - x0)
  161. local dy = math.abs(y1 - y0)
  162. local sx = (x0 < x1) and 1 or -1
  163. local sy = (y0 < y1) and 1 or -1
  164. local err = dx - dy
  165.  
  166. while true do
  167. local cc = c
  168. if prevV and prevV ~= 0 and v ~= 0 and ((prevV > 0 and v < 0) or (prevV < 0 and v > 0)) then
  169. cc = THEME.text
  170. end
  171. plot(mon, x0, y0, gx, gy, gw, gh, cc)
  172. if x0 == x1 and y0 == y1 then break end
  173. local e2 = 2 * err
  174. if e2 > -dy then err = err - dy; x0 = x0 + sx end
  175. if e2 < dx then err = err + dx; y0 = y0 + sy end
  176. end
  177. else
  178. plot(mon, x1, y1, gx, gy, gw, gh, c)
  179. end
  180.  
  181. prevX, prevY, prevV = x1, y1, v
  182. end
  183. end
  184.  
  185. local function drawGraphBars(mon, gx, gy, gw, gh, data, maxAbs)
  186. maxAbs = math.max(maxAbs or 1, 1)
  187. local top = gy
  188. local bot = gy + gh - 1
  189. local mid = gy + math.floor(gh / 2)
  190. if mid > bot then mid = bot end
  191.  
  192. fillRect(mon, gx, gy, gw, gh, THEME.bg)
  193.  
  194. mon.setBackgroundColor(THEME.dim)
  195. mon.setCursorPos(gx, mid)
  196. mon.write(string.rep(" ", gw))
  197.  
  198. local upMax = mid - top
  199. local downMax = bot - mid
  200. local start = math.max(1, #data - gw + 1)
  201.  
  202. for col = 1, gw do
  203. local i = start + col - 1
  204. local v = data[i] or 0
  205. local n = clamp(v / maxAbs, -1, 1)
  206. local x = gx + col - 1
  207.  
  208. if n > 0 and upMax > 0 then
  209. local bh = math.ceil(n * upMax); if bh < 1 then bh = 1 end
  210. mon.setBackgroundColor(THEME.ok)
  211. for k = 1, bh do
  212. local yy = mid - k
  213. if yy >= top then mon.setCursorPos(x, yy); mon.write(" ") end
  214. end
  215. elseif n < 0 and downMax > 0 then
  216. local bh = math.ceil((-n) * downMax); if bh < 1 then bh = 1 end
  217. mon.setBackgroundColor(THEME.bad)
  218. for k = 1, bh do
  219. local yy = mid + k
  220. if yy <= bot then mon.setCursorPos(x, yy); mon.write(" ") end
  221. end
  222. end
  223. end
  224. end
  225.  
  226. local function drawFluxGraphOld(mon, x, y, w, h, data, maxAbs)
  227. fillRect(mon, x, y, w, h, THEME.bg)
  228. maxAbs = math.max(maxAbs or 1, 1)
  229. local start = math.max(1, #data - w + 1)
  230. local col = 0
  231. for i = start, #data do
  232. col = col + 1
  233. local v = data[i] or 0
  234. local absV = math.abs(v)
  235. local barH = math.floor((absV / maxAbs) * h + 0.0001)
  236. barH = clamp(barH, 0, h)
  237. local c = THEME.dim
  238. if v > 0 then c = THEME.ok elseif v < 0 then c = THEME.bad end
  239.  
  240. mon.setBackgroundColor(THEME.bg)
  241. for ry = 0, h - 1 do
  242. mon.setCursorPos(x + col - 1, y + ry)
  243. mon.write(" ")
  244. end
  245. mon.setBackgroundColor(c)
  246. for ry = 0, barH - 1 do
  247. mon.setCursorPos(x + col - 1, y + (h - 1 - ry))
  248. mon.write(" ")
  249. end
  250. end
  251. end
  252.  
  253. -- Peripheral discovery
  254. local function findEnergyCore()
  255. for _, name in ipairs(peripheral.getNames()) do
  256. if peripheral.getType(name) == "draconic_rf_storage" then
  257. return peripheral.wrap(name), name
  258. end
  259. end
  260. return nil, nil
  261. end
  262.  
  263. -- Monitor init
  264. local mon = peripheral.wrap(MONITOR_SIDE)
  265. if not mon then
  266. print("Error: monitor not found on " .. tostring(MONITOR_SIDE))
  267. return
  268. end
  269. if mon.setTextScale then mon.setTextScale(1) end
  270.  
  271. local core, coreName = findEnergyCore()
  272. if not core then
  273. mon.setBackgroundColor(THEME.bg); mon.clear()
  274. writeAt(mon, 2, 2, "ERROR:", THEME.bad, THEME.bg)
  275. writeAt(mon, 2, 3, "Energy Core not detected", THEME.text, THEME.bg)
  276. return
  277. end
  278.  
  279. -- Layout
  280. local bx1x, bx1y, bx1w, bx1h = 2, 3, 19, 21
  281. local bx2x, bx2y, bx2w, bx2h = 22, 3, 18, 8
  282. local bx3x, bx3y, bx3w, bx3h = 41, 3, 30, 8
  283. local bx4x, bx4y, bx4w, bx4h = 22, 12, 18, 12
  284. local bx5x, bx5y, bx5w, bx5h = 41, 12, 30, 12
  285.  
  286. local gx, gy = bx5x + 2, bx5y + 2
  287. local gw, gh = bx5w - 4, bx5h - 4
  288.  
  289. local modeLabels = { "LINE", "BARS", "BARS (OLD)" }
  290. local graphMode = 1
  291. local forceGraphRedraw = true
  292.  
  293. local btnY = bx5y + bx5h - 1
  294. local btnLeftX = bx5x + 1
  295. local btnCenterX = btnLeftX + 2
  296. local btnRightX = btnCenterX + 2
  297.  
  298. local function drawGraphButton(mode)
  299. mon.setBackgroundColor(THEME.border)
  300. mon.setTextColor(THEME.bg)
  301. mon.setCursorPos(btnLeftX, btnY); mon.write("<")
  302. mon.setCursorPos(btnCenterX, btnY); mon.write(tostring(mode))
  303. mon.setCursorPos(btnRightX, btnY); mon.write(">")
  304. end
  305.  
  306. local function inButton(x, y)
  307. if y ~= btnY then return nil end
  308. if x == btnLeftX then return "left" end
  309. if x == btnRightX then return "right" end
  310. return nil
  311. end
  312.  
  313. -- Initial paint
  314. mon.setBackgroundColor(THEME.bg)
  315. mon.clear()
  316.  
  317. drawHeader(mon, "DRACONIC ENERGY CORE MONITOR")
  318. drawBox(mon, bx1x, bx1y, bx1w, bx1h, THEME.header, "Energy Buffer")
  319. drawBox(mon, bx2x, bx2y, bx2w, bx2h, THEME.border, "Capacity")
  320. drawBox(mon, bx3x, bx3y, bx3w, bx3h, THEME.border, "Stats")
  321. drawBox(mon, bx4x, bx4y, bx4w, bx4h, THEME.border, "Current Flow")
  322. drawBox(mon, bx5x, bx5y, bx5w, bx5h, THEME.border, "Graph")
  323.  
  324. safeWrite(mon, bx2x + 2, bx2y + 2, "Stored:", THEME.text, THEME.bg)
  325. safeWrite(mon, bx2x + 2, bx2y + 4, "Max:", THEME.text, THEME.bg)
  326.  
  327. safeWrite(mon, bx3x + 2, bx3y + 2, "Peak In:", THEME.text, THEME.bg)
  328. safeWrite(mon, bx3x + 2, bx3y + 4, "Peak Out:", THEME.text, THEME.bg)
  329.  
  330. drawGraphButton(graphMode)
  331.  
  332. -- State
  333. local previousEnergy = core.getEnergyStored() or 0
  334. local previousTime = os.clock()
  335.  
  336. local fluxSamples = {}
  337. local graphData = {}
  338. local graphMaxAbs = 1
  339. local peakIn, peakOut = 0, 0
  340.  
  341. local STABLE_RF_T = 100
  342.  
  343. local function renderOnce()
  344. if not core or (coreName and not peripheral.isPresent(coreName)) then
  345. core, coreName = findEnergyCore()
  346. end
  347. if not core then
  348. safeWrite(mon, 2, 2, "ERROR: Energy Core not detected", THEME.bad, THEME.bg)
  349. return
  350. end
  351.  
  352. local now = os.clock()
  353. local dt = now - previousTime
  354. if dt <= 0 then dt = UPDATE_DELAY end
  355.  
  356. local energyStored = core.getEnergyStored() or 0
  357. local maxEnergy = core.getMaxEnergyStored() or 1
  358. if maxEnergy <= 0 then maxEnergy = 1 end
  359.  
  360. local percent = clamp((energyStored / maxEnergy) * 100, 0, 100)
  361.  
  362. local deltaRF = energyStored - previousEnergy
  363. local rateRFt = deltaRF / (dt * 20)
  364.  
  365. push(fluxSamples, rateRFt, AVG_SAMPLES)
  366. local sum = 0
  367. for i = 1, #fluxSamples do sum = sum + fluxSamples[i] end
  368. local avgRFt = sum / math.max(#fluxSamples, 1)
  369.  
  370. local currentIn, currentOut = 0, 0
  371. if avgRFt > 0 then currentIn = avgRFt else currentOut = -avgRFt end
  372. if currentIn > peakIn then peakIn = currentIn end
  373. if currentOut > peakOut then peakOut = currentOut end
  374.  
  375. push(graphData, avgRFt, GRAPH_HISTORY)
  376. graphMaxAbs = graphUpdateScale(graphMaxAbs, math.abs(avgRFt))
  377.  
  378. local barColor = THEME.ok
  379. if percent < 20 then barColor = THEME.bad
  380. elseif percent < 50 then barColor = THEME.warn
  381. elseif percent < 75 then barColor = THEME.yellow end
  382.  
  383. -- Energy buffer
  384. drawVerticalBar(mon, bx1x + 3, bx1y + 3, 13, 14, percent, barColor)
  385. fillRect(mon, bx1x + 6, bx1y + bx1h - 3, 12, 1, THEME.bg)
  386. safeWrite(mon, bx1x + 7, bx1y + bx1h - 3, string.format("%.1f%%", percent), THEME.text, THEME.bg)
  387.  
  388. -- Capacity
  389. fillRect(mon, bx2x + 2, bx2y + 3, bx2w - 4, 1, THEME.bg)
  390. fillRect(mon, bx2x + 2, bx2y + 5, bx2w - 4, 1, THEME.bg)
  391. safeWrite(mon, bx2x + 2, bx2y + 3, formatNumber(energyStored) .. " RF", THEME.text, THEME.bg)
  392. safeWrite(mon, bx2x + 2, bx2y + 5, formatNumber(maxEnergy) .. " RF", THEME.text, THEME.bg)
  393.  
  394. -- Stats
  395. fillRect(mon, bx3x + 2, bx3y + 3, bx3w - 4, 1, THEME.bg)
  396. fillRect(mon, bx3x + 2, bx3y + 5, bx3w - 4, 1, THEME.bg)
  397. safeWrite(mon, bx3x + 2, bx3y + 3, formatNumber(peakIn) .. " RF/t", THEME.text, THEME.bg)
  398. safeWrite(mon, bx3x + 2, bx3y + 5, formatNumber(peakOut) .. " RF/t", THEME.text, THEME.bg)
  399. if avgRFt > STABLE_RF_T then
  400. safeWrite(mon, bx4x + 2, bx4y + 2, "INPUT", THEME.ok, THEME.bg)
  401. safeWrite(mon, bx4x + 2, bx4y + 3, "+" .. formatNumber(currentIn) .. " RF/t", THEME.text, THEME.bg)
  402.  
  403. safeWrite(mon, bx4x + 2, bx4y + 5, "DELTA:", THEME.warn, THEME.bg)
  404. safeWrite(mon, bx4x + 2, bx4y + 6, "+" .. formatNumber(deltaRF) .. " RF", THEME.warn, THEME.bg)
  405.  
  406. safeWrite(mon, bx4x + 2, bx4y + 9, ">>> CHARGE >>>", THEME.ok, THEME.bg)
  407.  
  408. elseif avgRFt < -STABLE_RF_T then
  409. safeWrite(mon, bx4x + 2, bx4y + 2, "OUTPUT", THEME.bad, THEME.bg)
  410. safeWrite(mon, bx4x + 2, bx4y + 3, "-" .. formatNumber(currentOut) .. " RF/t", THEME.text, THEME.bg)
  411.  
  412. safeWrite(mon, bx4x + 2, bx4y + 5, "DELTA:", THEME.warn, THEME.bg)
  413. safeWrite(mon, bx4x + 2, bx4y + 6, "-" .. formatNumber(math.abs(deltaRF)) .. " RF", THEME.warn, THEME.bg)
  414.  
  415. safeWrite(mon, bx4x + 2, bx4y + 9, "<<< DISCHG <<<", THEME.bad, THEME.bg)
  416.  
  417. else
  418. safeWrite(mon, bx4x + 2, bx4y + 2, "IDLE", THEME.text, THEME.bg)
  419. safeWrite(mon, bx4x + 2, bx4y + 5, "--- STABLE ---", THEME.dim, THEME.bg)
  420. safeWrite(mon, bx4x + 2, bx4y + 8, "~0 RF/t", THEME.dim, THEME.bg)
  421. end
  422.  
  423. -- Graph
  424. if forceGraphRedraw then
  425. fillRect(mon, gx, gy, gw, gh, THEME.bg)
  426. forceGraphRedraw = false
  427. end
  428.  
  429. if graphMode == 1 then
  430. drawGraphLine(mon, gx, gy, gw, gh, graphData, graphMaxAbs)
  431. elseif graphMode == 2 then
  432. drawGraphBars(mon, gx, gy, gw, gh, graphData, graphMaxAbs)
  433. else
  434. drawFluxGraphOld(mon, gx, gy, gw, gh, graphData, graphMaxAbs)
  435. end
  436. drawGraphButton(graphMode)
  437.  
  438. -- Footer: Tier (right) + Day/Time (left)
  439. local mw, mh = mon.getSize()
  440.  
  441. local tierStr = "TIER " .. tostring(CORE_TIER)
  442. fillRect(mon, mw - #tierStr - 1, mh - 1, #tierStr + 1, 1, THEME.bg)
  443. safeWrite(mon, mw - #tierStr, mh - 1, tierStr, THEME.dim, THEME.bg)
  444.  
  445. local day = os.day()
  446. local tt = os.time()
  447. local hours = math.floor(tt)
  448. local minutes = math.floor((tt - hours) * 60)
  449. local timeStr = string.format("DAY %d %02d:%02d", day, hours, minutes)
  450. fillRect(mon, 1, mh - 1, 30, 1, THEME.bg)
  451. safeWrite(mon, 2, mh - 1, timeStr, THEME.dim, THEME.bg)
  452.  
  453. previousEnergy = energyStored
  454. previousTime = now
  455. end
  456.  
  457. -- Event loops
  458. local function uiLoop()
  459. while true do
  460. local ev = { os.pullEvent() }
  461. if ev[1] == "graph_left" then
  462. graphMode = graphMode - 1
  463. if graphMode < 1 then graphMode = #modeLabels end
  464. forceGraphRedraw = true
  465. fillRect(mon, gx, gy, gw, gh, THEME.bg)
  466. renderOnce()
  467.  
  468. elseif ev[1] == "graph_right" then
  469. graphMode = graphMode + 1
  470. if graphMode > #modeLabels then graphMode = 1 end
  471. forceGraphRedraw = true
  472. fillRect(mon, gx, gy, gw, gh, THEME.bg)
  473. renderOnce()
  474.  
  475. elseif ev[1] == "tick" then
  476. renderOnce()
  477. end
  478. end
  479. end
  480.  
  481. local function tickLoop()
  482. while true do
  483. os.queueEvent("tick")
  484. sleep(UPDATE_DELAY)
  485. end
  486. end
  487.  
  488. local function touchLoop()
  489. while true do
  490. local _, side, x, y = os.pullEvent("monitor_touch")
  491. if side == MONITOR_SIDE then
  492. local hit = inButton(x, y)
  493. if hit == "left" then os.queueEvent("graph_left")
  494. elseif hit == "right" then os.queueEvent("graph_right") end
  495. end
  496. end
  497. end
  498.  
  499. parallel.waitForAny(uiLoop, tickLoop, touchLoop)
  500.  
Advertisement
Comments
  • MFeltmann
    6 days (edited)
    # text 0.51 KB | 0 0
    1. i suggest you search for a monitor instead with this code line 264 - 269
    2.  
    3. -- Monitor init
    4. local function findMonitor()
    5. for _, name in ipairs(peripheral.getNames()) do
    6. if peripheral.getType(name) == "monitor" then
    7. return peripheral.wrap(name), name
    8. end
    9. end
    10. return nil, nil
    11. end
    12.  
    13. local mon, monitorName = findMonitor()
    14.  
    15. if not mon then
    16. print("Error: No monitor found")
    17. return
    18. end
    19.  
    20. if mon.setTextScale then
    21. mon.setTextScale(1)
    22. end
    23.  
    24. it will also error out if no moniter is found
Add Comment
Please, Sign In to add comment