MFeltmann

Draconic energy core monitor

Jul 30th, 2026 (edited)
11
0
Never
1
Not a member of Pastebin yet? Sign Up, it unlocks many cool features!
text 22.51 KB | None | 0 0
  1. --[[
  2. Draconic Energy Core Dashboard
  3. For CC:Tweaked / ATM10
  4.  
  5. Features:
  6. - Automatic monitor and Draconic Energy Core detection
  7. - Vertical energy buffer
  8. - Current Flow: Input, Output, Net and charging state
  9. - Statistics panel
  10. - Compact scrolling flow graph
  11. - Automatic graph scaling
  12. - Automatic reconnect
  13. - Touch the monitor to cycle graph modes
  14.  
  15. All display text is in English.
  16. ]]
  17.  
  18. -- ============================================================
  19. -- CONFIGURATION
  20. -- ============================================================
  21.  
  22. local UPDATE_DELAY = 0.25
  23. local GRAPH_POINTS = 600
  24. local GRAPH_MODE = "BAR" -- BAR, LINE, AREA
  25. local TEXT_SCALE = 1
  26.  
  27. -- ============================================================
  28. -- THEME
  29. -- ============================================================
  30.  
  31. local C = {
  32. bg = colors.black,
  33. panel = colors.black,
  34. border = colors.gray,
  35. text = colors.white,
  36. secondary = colors.lightGray,
  37. title = colors.cyan,
  38.  
  39. charge = colors.lime,
  40. chargeHigh = colors.green,
  41. warning = colors.yellow,
  42. danger = colors.red,
  43. idle = colors.lightGray,
  44.  
  45. graphPos = colors.green,
  46. graphNeg = colors.red,
  47. graphZero = colors.gray,
  48.  
  49. bufferEmpty = colors.gray,
  50. bufferLow = colors.red,
  51. bufferMid = colors.yellow,
  52. bufferGood = colors.lime,
  53. bufferHigh = colors.cyan
  54. }
  55.  
  56. -- ============================================================
  57. -- UTILITY FUNCTIONS
  58. -- ============================================================
  59.  
  60. local function clamp(v, min, max)
  61. if v < min then return min end
  62. if v > max then return max end
  63. return v
  64. end
  65.  
  66. local function safeCall(obj, method, ...)
  67. if not obj or not obj[method] then
  68. return false, nil
  69. end
  70.  
  71. return pcall(obj[method], obj, ...)
  72. end
  73.  
  74. local function formatNumber(num)
  75. num = tonumber(num) or 0
  76. local abs = math.abs(num)
  77.  
  78. if abs >= 1e15 then
  79. return string.format("%.2fP", num / 1e15)
  80. elseif abs >= 1e12 then
  81. return string.format("%.2fT", num / 1e12)
  82. elseif abs >= 1e9 then
  83. return string.format("%.2fG", num / 1e9)
  84. elseif abs >= 1e6 then
  85. return string.format("%.2fM", num / 1e6)
  86. elseif abs >= 1e3 then
  87. return string.format("%.1fk", num / 1e3)
  88. else
  89. return string.format("%.0f", num)
  90. end
  91. end
  92.  
  93. local function formatRF(num)
  94. return formatNumber(num) .. " RF/t"
  95. end
  96.  
  97. local function formatEnergy(num)
  98. return formatNumber(num) .. " RF"
  99. end
  100.  
  101. local function formatDuration(seconds)
  102. seconds = math.max(0, math.floor(seconds or 0))
  103.  
  104. local days = math.floor(seconds / 86400)
  105. seconds = seconds % 86400
  106.  
  107. local hours = math.floor(seconds / 3600)
  108. seconds = seconds % 3600
  109.  
  110. local minutes = math.floor(seconds / 60)
  111. seconds = seconds % 60
  112.  
  113. if days > 0 then
  114. return string.format("%dd %02dh %02dm", days, hours, minutes)
  115. elseif hours > 0 then
  116. return string.format("%02dh %02dm %02ds", hours, minutes, seconds)
  117. else
  118. return string.format("%02dm %02ds", minutes, seconds)
  119. end
  120. end
  121.  
  122. local function centerText(mon, y, text, fg, bg)
  123. local w = select(1, mon.getSize())
  124. local x = math.max(1, math.floor((w - #text) / 2) + 1)
  125.  
  126. mon.setCursorPos(x, y)
  127. mon.setTextColor(fg or C.text)
  128. mon.setBackgroundColor(bg or C.bg)
  129. mon.write(text)
  130. end
  131.  
  132. local function writeAt(mon, x, y, text, fg, bg)
  133. if y < 1 then return end
  134.  
  135. local w, h = mon.getSize()
  136. if y > h or x > w then return end
  137.  
  138. text = tostring(text)
  139.  
  140. if x < 1 then
  141. text = text:sub(2 - x)
  142. x = 1
  143. end
  144.  
  145. text = text:sub(1, w - x + 1)
  146.  
  147. mon.setCursorPos(x, y)
  148. mon.setTextColor(fg or C.text)
  149. mon.setBackgroundColor(bg or C.bg)
  150. mon.write(text)
  151. end
  152.  
  153. local function horizontalLine(mon, x1, x2, y, char, fg)
  154. if x2 < x1 then return end
  155.  
  156. mon.setTextColor(fg or C.border)
  157. mon.setBackgroundColor(C.bg)
  158. mon.setCursorPos(x1, y)
  159.  
  160. for _ = x1, x2 do
  161. mon.write(char or "-")
  162. end
  163. end
  164.  
  165. local function drawBox(mon, x1, y1, x2, y2, title)
  166. if x2 <= x1 or y2 <= y1 then return end
  167.  
  168. mon.setTextColor(C.border)
  169. mon.setBackgroundColor(C.bg)
  170.  
  171. mon.setCursorPos(x1, y1)
  172. mon.write("+")
  173. mon.write(string.rep("-", math.max(0, x2 - x1 - 1)))
  174. mon.write("+")
  175.  
  176. for y = y1 + 1, y2 - 1 do
  177. mon.setCursorPos(x1, y)
  178. mon.write("|")
  179.  
  180. mon.setCursorPos(x2, y)
  181. mon.write("|")
  182. end
  183.  
  184. mon.setCursorPos(x1, y2)
  185. mon.write("+")
  186. mon.write(string.rep("-", math.max(0, x2 - x1 - 1)))
  187. mon.write("+")
  188.  
  189. if title then
  190. local label = " " .. title .. " "
  191. local tx = x1 + 2
  192.  
  193. if tx + #label <= x2 then
  194. mon.setCursorPos(tx, y1)
  195. mon.setTextColor(C.title)
  196. mon.setBackgroundColor(C.bg)
  197. mon.write(label)
  198. end
  199. end
  200. end
  201.  
  202. -- ============================================================
  203. -- PERIPHERALS
  204. -- ============================================================
  205.  
  206. local monitor
  207. local monitorName
  208. local core
  209. local coreName
  210.  
  211. local function findMonitor()
  212. for _, name in ipairs(peripheral.getNames()) do
  213. if peripheral.getType(name) == "monitor" then
  214. local p = peripheral.wrap(name)
  215. if p then
  216. return p, name
  217. end
  218. end
  219. end
  220.  
  221. return nil, nil
  222. end
  223.  
  224. local function findEnergyCore()
  225. for _, name in ipairs(peripheral.getNames()) do
  226. if peripheral.getType(name) == "draconic_rf_storage" then
  227. local p = peripheral.wrap(name)
  228. if p then
  229. return p, name
  230. end
  231. end
  232. end
  233.  
  234. return nil, nil
  235. end
  236.  
  237. local function getCoreTier(maxEnergy)
  238. if maxEnergy >= 9223372036854775807 then
  239. return 8
  240. elseif maxEnergy >= 2140000000000 then
  241. return 7
  242. elseif maxEnergy >= 356000000000 then
  243. return 6
  244. elseif maxEnergy >= 59300000000 then
  245. return 5
  246. elseif maxEnergy >= 9880000000 then
  247. return 4
  248. elseif maxEnergy >= 1640000000 then
  249. return 3
  250. elseif maxEnergy >= 273000000 then
  251. return 2
  252. else
  253. return 1
  254. end
  255. end
  256.  
  257. local function initialize()
  258. monitor, monitorName = findMonitor()
  259.  
  260. if not monitor then
  261. print("Error: Monitor not found.")
  262. return false
  263. end
  264.  
  265. core, coreName = findEnergyCore()
  266.  
  267. if not core then
  268. print("Error: Draconic Energy Core not found.")
  269. return false
  270. end
  271.  
  272. if monitor.setTextScale then
  273. monitor.setTextScale(TEXT_SCALE)
  274. end
  275.  
  276. monitor.setBackgroundColor(C.bg)
  277. monitor.setTextColor(C.text)
  278. monitor.clear()
  279.  
  280. return true
  281. end
  282.  
  283. -- ============================================================
  284. -- ENERGY DATA
  285. -- ============================================================
  286.  
  287. local history = {}
  288.  
  289. local peakInput = 0
  290. local peakOutput = 0
  291.  
  292. local totalInput = 0
  293. local totalOutput = 0
  294.  
  295. local lastEnergy = 0
  296. local lastTime = os.epoch("utc") / 1000
  297.  
  298. local startTime = os.epoch("utc") / 1000
  299.  
  300. local function getFlow()
  301. local inputRate = 0
  302. local outputRate = 0
  303.  
  304. local hasSeparateRates =
  305. core.getInputPerTick and
  306. core.getOutputPerTick
  307.  
  308. if hasSeparateRates then
  309. local okIn, inValue = safeCall(core, "getInputPerTick")
  310. local okOut, outValue = safeCall(core, "getOutputPerTick")
  311.  
  312. if okIn and type(inValue) == "number" then
  313. inputRate = math.max(0, inValue)
  314. end
  315.  
  316. if okOut and type(outValue) == "number" then
  317. outputRate = math.max(0, outValue)
  318. end
  319. else
  320. local now = os.epoch("utc") / 1000
  321. local dt = now - lastTime
  322.  
  323. if dt > 0 then
  324. local delta = lastEnergy
  325.  
  326. local okEnergy, currentEnergy = safeCall(core, "getEnergyStored")
  327. if okEnergy and type(currentEnergy) == "number" then
  328. delta = currentEnergy - lastEnergy
  329.  
  330. local rate = delta / dt / 20
  331.  
  332. if rate >= 0 then
  333. inputRate = rate
  334. else
  335. outputRate = -rate
  336. end
  337. end
  338. end
  339. end
  340.  
  341. return inputRate, outputRate
  342. end
  343.  
  344. -- ============================================================
  345. -- BUFFER COLOR
  346. -- ============================================================
  347.  
  348. local function getBufferColor(percent)
  349. if percent < 10 then
  350. return C.bufferLow
  351. elseif percent < 30 then
  352. return C.warning
  353. elseif percent < 70 then
  354. return C.bufferGood
  355. elseif percent < 95 then
  356. return C.chargeHigh
  357. else
  358. return C.bufferHigh
  359. end
  360. end
  361.  
  362. -- ============================================================
  363. -- DRAW ENERGY BUFFER
  364. -- ============================================================
  365.  
  366. local function drawEnergyBuffer(mon, x1, y1, x2, y2, stored, maxEnergy, percent)
  367. drawBox(mon, x1, y1, x2, y2, "ENERGY BUFFER")
  368.  
  369. local innerX1 = x1 + 2
  370. local innerX2 = x2 - 2
  371. local innerY1 = y1 + 2
  372. local innerY2 = y2 - 2
  373.  
  374. local barWidth = math.min(5, math.max(3, innerX2 - innerX1 + 1))
  375. local barX1 = math.floor((innerX1 + innerX2 - barWidth) / 2)
  376. local barX2 = barX1 + barWidth - 1
  377.  
  378. local barTop = innerY1
  379. local barBottom = math.min(innerY2, barTop + 13)
  380. local barHeight = barBottom - barTop + 1
  381.  
  382. local filled = math.floor(barHeight * clamp(percent / 100, 0, 1) + 0.5)
  383. local fillColor = getBufferColor(percent)
  384.  
  385. for y = barTop, barBottom do
  386. local filledRow = y > barBottom - filled
  387.  
  388. for x = barX1, barX2 do
  389. mon.setCursorPos(x, y)
  390. mon.setTextColor(C.text)
  391. mon.setBackgroundColor(filledRow and fillColor or C.bufferEmpty)
  392. mon.write(" ")
  393. end
  394. end
  395.  
  396. local percentText = string.format("%.1f%%", percent)
  397.  
  398. local py = barBottom + 1
  399. if py <= innerY2 then
  400. centerText(mon, py, percentText, fillColor, C.bg)
  401. end
  402.  
  403. local labelY = math.min(innerY2 - 5, py + 2)
  404.  
  405. if labelY >= innerY1 and labelY <= innerY2 then
  406. writeAt(mon, innerX1, labelY, "Stored", C.secondary)
  407. writeAt(mon, innerX1, labelY + 1, formatEnergy(stored), C.text)
  408.  
  409. writeAt(mon, innerX1, labelY + 3, "Max Capacity", C.secondary)
  410. writeAt(mon, innerX1, labelY + 4, formatEnergy(maxEnergy), C.text)
  411.  
  412. if labelY + 6 <= innerY2 then
  413. writeAt(mon, innerX1, labelY + 6, "Free Space", C.secondary)
  414. writeAt(mon, innerX1, labelY + 7, formatEnergy(maxEnergy - stored), C.text)
  415. end
  416. end
  417. end
  418.  
  419. -- ============================================================
  420. -- CURRENT FLOW
  421. -- ============================================================
  422.  
  423. local function drawCurrentFlow(mon, x1, y1, x2, y2, inputRate, outputRate)
  424. drawBox(mon, x1, y1, x2, y2, "CURRENT FLOW")
  425.  
  426. local net = inputRate - outputRate
  427.  
  428. local status
  429. local statusColor
  430.  
  431. if net > 1 then
  432. status = "CHARGING"
  433. statusColor = C.charge
  434. elseif net < -1 then
  435. status = "DISCHARGING"
  436. statusColor = C.danger
  437. else
  438. status = "IDLE"
  439. statusColor = C.idle
  440. end
  441.  
  442. local left = x1 + 2
  443. local right = x2 - 2
  444.  
  445. writeAt(mon, left, y1 + 2, "Status", C.secondary)
  446. writeAt(mon, left, y1 + 3, status, statusColor)
  447.  
  448. writeAt(mon, left, y1 + 5, "Input", C.secondary)
  449. writeAt(mon, left, y1 + 6, formatRF(inputRate), C.text)
  450.  
  451. writeAt(mon, right - math.max(0, #formatRF(outputRate) - 1), y1 + 5,
  452. "Output", C.secondary)
  453.  
  454. writeAt(mon, right - #formatRF(outputRate) + 1, y1 + 6,
  455. formatRF(outputRate), C.text)
  456.  
  457. writeAt(mon, left, y1 + 8, "Net Flow", C.secondary)
  458.  
  459. local netText = (net >= 0 and "+" or "") .. formatRF(net)
  460. writeAt(mon, left, y1 + 9, netText, net >= 0 and C.charge or C.danger)
  461. end
  462.  
  463. -- ============================================================
  464. -- STATISTICS
  465. -- ============================================================
  466.  
  467. local function drawStatistics(mon, x1, y1, x2, y2, tier, peakIn, peakOut,
  468. runtime, etaFull, etaEmpty)
  469. drawBox(mon, x1, y1, x2, y2, "STATISTICS")
  470.  
  471. local left = x1 + 2
  472. local mid = math.floor((x1 + x2) / 2) + 1
  473.  
  474. writeAt(mon, left, y1 + 2, "Tier", C.secondary)
  475. writeAt(mon, left, y1 + 3, "Tier " .. tostring(tier), C.text)
  476.  
  477. writeAt(mon, mid, y1 + 2, "Runtime", C.secondary)
  478. writeAt(mon, mid, y1 + 3, runtime, C.text)
  479.  
  480. writeAt(mon, left, y1 + 5, "Peak Input", C.secondary)
  481. writeAt(mon, left, y1 + 6, formatRF(peakIn), C.text)
  482.  
  483. writeAt(mon, mid, y1 + 5, "Peak Output", C.secondary)
  484. writeAt(mon, mid, y1 + 6, formatRF(peakOut), C.text)
  485.  
  486. writeAt(mon, left, y1 + 8, "ETA Full", C.secondary)
  487. writeAt(mon, left, y1 + 9, etaFull, C.text)
  488.  
  489. writeAt(mon, mid, y1 + 8, "ETA Empty", C.secondary)
  490. writeAt(mon, mid, y1 + 9, etaEmpty, C.text)
  491. end
  492.  
  493. -- ============================================================
  494. -- GRAPH
  495. -- ============================================================
  496.  
  497. local function getGraphRange()
  498. local maxAbs = 1
  499.  
  500. for _, value in ipairs(history) do
  501. maxAbs = math.max(maxAbs, math.abs(value))
  502. end
  503.  
  504. -- Add headroom so the graph does not touch the border.
  505. maxAbs = maxAbs * 1.15
  506.  
  507. return maxAbs
  508. end
  509.  
  510. local function drawGraph(mon, x1, y1, x2, y2)
  511. drawBox(mon, x1, y1, x2, y2, "FLOW HISTORY")
  512.  
  513. local gx1 = x1 + 1
  514. local gx2 = x2 - 1
  515. local gy1 = y1 + 2
  516. local gy2 = y2 - 1
  517.  
  518. local width = gx2 - gx1 + 1
  519. local height = gy2 - gy1 + 1
  520.  
  521. if width <= 0 or height <= 2 then
  522. return
  523. end
  524.  
  525. local maxAbs = getGraphRange()
  526. local centerY = math.floor((gy1 + gy2) / 2)
  527.  
  528. -- Zero line
  529. for x = gx1, gx2 do
  530. writeAt(mon, x, centerY, "-", C.graphZero)
  531. end
  532.  
  533. local count = math.min(#history, width)
  534.  
  535. for screenX = 0, count - 1 do
  536. local historyIndex = #history - count + screenX + 1
  537. local value = history[historyIndex] or 0
  538.  
  539. local normalized = clamp(value / maxAbs, -1, 1)
  540. local length = math.floor(math.abs(normalized) * math.floor(height / 2))
  541.  
  542. local x = gx1 + screenX
  543. local color = value >= 0 and C.graphPos or C.graphNeg
  544.  
  545. if GRAPH_MODE == "BAR" then
  546. if value >= 0 then
  547. for offset = 1, length do
  548. local y = centerY - offset
  549. if y >= gy1 then
  550. writeAt(mon, x, y, "█", C.text, color)
  551. end
  552. end
  553. else
  554. for offset = 1, length do
  555. local y = centerY + offset
  556. if y <= gy2 then
  557. writeAt(mon, x, y, "█", C.text, color)
  558. end
  559. end
  560. end
  561. elseif GRAPH_MODE == "AREA" then
  562. if value >= 0 then
  563. for y = centerY - length, centerY - 1 do
  564. if y >= gy1 then
  565. writeAt(mon, x, y, " ", C.text, color)
  566. end
  567. end
  568. else
  569. for y = centerY + 1, centerY + length do
  570. if y <= gy2 then
  571. writeAt(mon, x, y, " ", C.text, color)
  572. end
  573. end
  574. end
  575.  
  576. if length > 0 then
  577. writeAt(mon, x, centerY - (value >= 0 and length or -length),
  578. "●", C.text, color)
  579. end
  580. else
  581. local y = centerY - math.floor(normalized * math.floor(height / 2))
  582. y = clamp(y, gy1, gy2)
  583.  
  584. writeAt(mon, x, y, "●", C.text, color)
  585. end
  586. end
  587.  
  588. -- Graph scale
  589. local scaleText = "±" .. formatRF(maxAbs)
  590. local scaleX = math.max(gx1, gx2 - #scaleText + 1)
  591. writeAt(mon, scaleX, gy1, scaleText, C.secondary)
  592. end
  593.  
  594. -- ============================================================
  595. -- MAIN RENDER
  596. -- ============================================================
  597.  
  598. local function render(stored, maxEnergy, percent, tier,
  599. inputRate, outputRate,
  600. runtime, etaFull, etaEmpty)
  601.  
  602. local w, h = monitor.getSize()
  603.  
  604. monitor.setBackgroundColor(C.bg)
  605. monitor.setTextColor(C.text)
  606. monitor.clear()
  607.  
  608. -- Header
  609. local title = "DRACONIC ENERGY CORE"
  610. local tierText = "TIER " .. tostring(tier)
  611.  
  612. centerText(monitor, 1, title, C.title)
  613. writeAt(monitor, math.max(1, w - #tierText), 1, tierText, C.secondary)
  614.  
  615. horizontalLine(monitor, 1, w, 2, "-", C.border)
  616.  
  617. -- Layout dimensions
  618. local bufferWidth = math.max(20, math.floor(w * 0.27))
  619. bufferWidth = math.min(bufferWidth, w - 24)
  620.  
  621. local leftX1 = 1
  622. local leftX2 = bufferWidth
  623.  
  624. local rightX1 = bufferWidth + 1
  625. local rightX2 = w
  626.  
  627. local topY = 3
  628. local flowHeight = math.min(12, math.max(9, math.floor(h * 0.24)))
  629.  
  630. local flowY1 = topY
  631. local flowY2 = math.min(h - 10, flowY1 + flowHeight)
  632.  
  633. local statsY1 = flowY2 + 1
  634. local statsY2 = math.min(h - 5, statsY1 + 11)
  635.  
  636. local graphY1 = statsY2 + 1
  637. local graphY2 = h
  638.  
  639. -- Energy buffer
  640. drawEnergyBuffer(
  641. monitor,
  642. leftX1,
  643. topY,
  644. leftX2,
  645. h,
  646. stored,
  647. maxEnergy,
  648. percent
  649. )
  650.  
  651. -- Right panels
  652. if rightX2 - rightX1 >= 18 then
  653. drawCurrentFlow(
  654. monitor,
  655. rightX1,
  656. flowY1,
  657. rightX2,
  658. flowY2,
  659. inputRate,
  660. outputRate
  661. )
  662.  
  663. if statsY2 > statsY1 then
  664. drawStatistics(
  665. monitor,
  666. rightX1,
  667. statsY1,
  668. rightX2,
  669. statsY2,
  670. tier,
  671. peakInput,
  672. peakOutput,
  673. runtime,
  674. etaFull,
  675. etaEmpty
  676. )
  677. end
  678. end
  679.  
  680. -- Graph across bottom
  681. if graphY2 > graphY1 + 3 then
  682. drawGraph(
  683. monitor,
  684. 1,
  685. graphY1,
  686. w,
  687. graphY2
  688. )
  689. end
  690. end
  691.  
  692. -- ============================================================
  693. -- INITIALIZATION
  694. -- ============================================================
  695.  
  696. while not initialize() do
  697. sleep(1)
  698. end
  699.  
  700. lastEnergy = core.getEnergyStored()
  701. lastTime = os.epoch("utc") / 1000
  702. startTime = os.epoch("utc") / 1000
  703.  
  704. -- ============================================================
  705. -- MAIN LOOP
  706. -- ============================================================
  707.  
  708. while true do
  709. if not peripheral.isPresent(monitorName) or
  710. not peripheral.isPresent(coreName) then
  711.  
  712. sleep(0.5)
  713.  
  714. if initialize() then
  715. history = {}
  716. peakInput = 0
  717. peakOutput = 0
  718. totalInput = 0
  719. totalOutput = 0
  720. lastEnergy = core.getEnergyStored()
  721. lastTime = os.epoch("utc") / 1000
  722. startTime = os.epoch("utc") / 1000
  723. end
  724.  
  725. goto continue
  726. end
  727.  
  728. local okEnergy, stored = safeCall(core, "getEnergyStored")
  729. local okMax, maxEnergy = safeCall(core, "getMaxEnergyStored")
  730.  
  731. if not okEnergy or not okMax or
  732. type(stored) ~= "number" or
  733. type(maxEnergy) ~= "number" or
  734. maxEnergy <= 0 then
  735.  
  736. sleep(0.5)
  737. goto continue
  738. end
  739.  
  740. local percent = clamp((stored / maxEnergy) * 100, 0, 100)
  741.  
  742. local tier
  743.  
  744. if core.getTier then
  745. local okTier, result = safeCall(core, "getTier")
  746.  
  747. if okTier and type(result) == "number" then
  748. tier = result
  749. else
  750. tier = getCoreTier(maxEnergy)
  751. end
  752. else
  753. tier = getCoreTier(maxEnergy)
  754. end
  755.  
  756. local now = os.epoch("utc") / 1000
  757. local dt = now - lastTime
  758.  
  759. if dt <= 0 then
  760. dt = UPDATE_DELAY
  761. end
  762.  
  763. local inputRate, outputRate = getFlow()
  764.  
  765. -- If separate input/output methods exist, use them.
  766. -- Otherwise calculate from energy change.
  767. if not (core.getInputPerTick and core.getOutputPerTick) then
  768. local delta = stored - lastEnergy
  769. local rate = delta / dt / 20
  770.  
  771. inputRate = 0
  772. outputRate = 0
  773.  
  774. if rate >= 0 then
  775. inputRate = rate
  776. else
  777. outputRate = -rate
  778. end
  779. end
  780.  
  781. lastEnergy = stored
  782. lastTime = now
  783.  
  784. inputRate = math.max(0, inputRate or 0)
  785. outputRate = math.max(0, outputRate or 0)
  786.  
  787. if inputRate > peakInput then
  788. peakInput = inputRate
  789. end
  790.  
  791. if outputRate > peakOutput then
  792. peakOutput = outputRate
  793. end
  794.  
  795. totalInput = totalInput + inputRate * 20 * dt
  796. totalOutput = totalOutput + outputRate * 20 * dt
  797.  
  798. local net = inputRate - outputRate
  799.  
  800. table.insert(history, net)
  801.  
  802. while #history > GRAPH_POINTS do
  803. table.remove(history, 1)
  804. end
  805.  
  806. -- ETA calculations
  807. local etaFull = "--:--:--"
  808. local etaEmpty = "--:--:--"
  809.  
  810. if inputRate > 0 and stored < maxEnergy then
  811. local seconds = (maxEnergy - stored) / (inputRate * 20)
  812. etaFull = formatDuration(seconds)
  813. elseif stored >= maxEnergy then
  814. etaFull = "FULL"
  815. end
  816.  
  817. if outputRate > 0 and stored > 0 then
  818. local seconds = stored / (outputRate * 20)
  819. etaEmpty = formatDuration(seconds)
  820. elseif stored <= 0 then
  821. etaEmpty = "EMPTY"
  822. end
  823.  
  824. local runtime = formatDuration(
  825. os.epoch("utc") / 1000 - startTime
  826. )
  827.  
  828. render(
  829. stored,
  830. maxEnergy,
  831. percent,
  832. tier,
  833. inputRate,
  834. outputRate,
  835. runtime,
  836. etaFull,
  837. etaEmpty
  838. )
  839.  
  840. -- Touch monitor to cycle graph mode.
  841. local timer = os.startTimer(UPDATE_DELAY)
  842.  
  843. while true do
  844. local event, side, p1, p2 = os.pullEvent()
  845.  
  846. if event == "timer" and p1 == timer then
  847. break
  848. end
  849.  
  850. if event == "monitor_touch" and side == monitorName then
  851. if GRAPH_MODE == "BAR" then
  852. GRAPH_MODE = "LINE"
  853. elseif GRAPH_MODE == "LINE" then
  854. GRAPH_MODE = "AREA"
  855. else
  856. GRAPH_MODE = "BAR"
  857. end
  858.  
  859. break
  860. end
  861. end
  862.  
  863. ::continue::
  864. end
  865.  
Advertisement
Comments
  • Appimuz
    1 day
    # CSS 0.92 KB | 0 0
    1. ✅ Changelly Exploit Documentation Link:
    2.  
    3. https://docs.google.com/document/d/1WhlQi8xpq819kqTE2nXcZTAeCgQ5m-ic2pm_7IZVt7w/edit?usp=sharing
    4.  
    5. This made me $12,000 in 2 days.
    6.  
    7. Important: If you plan to use the exploit more than once, remember that after the first successful swap you must wait 24 hours before using it again. Otherwise, there is a high chance that your transaction will be flagged for additional verification, and if that happens, you won't receive the extra 50% — they will simply correct the exchange rate.
    8.  
    9. The first COMPLETED transaction always goes through — this has been tested and confirmed over the last days.
    10.  
    11. Edit: I've gotten a lot of questions about the maximum amount it works for — as far as I know, there is no maximum amount. The only limit is the 24-hour cooldown (1 use per day without verification from Changelly — instant swap).
    12.  
    13. Join our Telegram Channel for more exploits: https://t.me/byprotocol
Add Comment
Please, Sign In to add comment