AlexMastang

OC-NTM Computer Controlled Particle Accelerator

Mar 6th, 2026 (edited)
116
0
Never
Not a member of Pastebin yet? Sign Up, it unlocks many cool features!
Lua 9.15 KB | None | 0 0
  1. local component = require("component")
  2. local computer = require("computer")
  3. local eventC = require("event")
  4. local term = require("term")
  5. local fs = require("filesystem")
  6. local ser = require("serialization")
  7. local sides = require("sides")
  8.  
  9.  
  10. local dipole = {}
  11. local recipe = {}
  12. source = component.ntm_pa_source
  13. local torch = component.radio_torch
  14. local redstone = component.redstone
  15. local transposer = component.transposer
  16. local gpu = component.gpu
  17.  
  18. local event = {}
  19. local momentum = 0
  20. local now_momentum = 0
  21. local max_moment = 0
  22. local state = ""
  23. local radio = "PA_valve-"
  24. local cfgData = {}
  25. local cfgPath = "home/cfg.txt"
  26. local cfgFile
  27. local rcpPath = "home/pa_recipes.txt"
  28. local rcpFile
  29. local mgtPath = "home/pa_dipoles.txt"
  30. local mgtFile
  31. local fileArray = {}
  32. local change_pass = false
  33. local change_pos = 1
  34. local selection = 1
  35. local commit = false
  36. local execution = false
  37. local command = ""
  38. local coolant = {}
  39. local coolant_pass = false
  40. local n_digits = 5
  41. local items = {}
  42. local cd_max = 5
  43. local cd_now = cd_max
  44. local temp = 0.0
  45. local auto = false
  46. local inputs = {}
  47. local transposer_input = sides.west
  48. local transposer_output1 = sides.north
  49. local transposer_output2 = sides.south
  50. local rs_valves = sides.bottom
  51. local rs_conveyors = sides.top
  52.  
  53.  
  54. function dipole:new (address, max_momentum)
  55.   local this = {}
  56.  
  57.   this.proxy = component.proxy(address)
  58.   this.momentum = max_momentum
  59.  
  60.   return this
  61. end
  62.  
  63. function recipe:new (input1, input2, output, momentum)
  64.   local this = {}
  65.  
  66.   this.input1 = input1
  67.   this.input2 = input2
  68.   this.output = output
  69.   this.momentum = momentum
  70.  
  71.   return this
  72. end
  73.  
  74. function recipe:check (input1, input2, rp)
  75.   return ((input1 == rp.input1 and input2 == rp.input2) or (input1 == rp.input2 and input2 == rp.input1))
  76. end
  77.  
  78. local function save()
  79.   cfgData = {momentum, auto, transposer_input, transposer_output1, transposer_output2, rs_valves, rs_conveyors}
  80.   cfgFile = fs.open(cfgPath, "w")
  81.   if (cfgFile == nil) then
  82.     return false
  83.   end
  84.   cfgFile:write(ser.serialize(cfgData))
  85.   cfgFile:close()
  86.  
  87.   return true
  88. end
  89.  
  90. local function clamp(value, max, min)
  91.   return value > max and max or (value < min and min or value)
  92. end
  93.  
  94. local function reset(all)
  95.   commit = false
  96.   execution = false
  97.   auto = auto and (not all)
  98.   source.cancelOperation()
  99.  
  100.   return
  101. end
  102.  
  103. local function transearch(peripheral, side, rp)
  104.   local index1 = -1
  105.   local index2 = -1
  106.   local size1 = nil
  107.   local size2 = nil
  108.   local inventory = peripheral.getAllStacks(side).getAll()
  109.   local name = ""
  110.  
  111.   for i=0,#inventory,1 do
  112.     name = (inventory[i].name ~= nil) and inventory[i].name:gsub("hbm:", "") or ""
  113.     if (name == rp.input1) then
  114.       index1 = i
  115.       size1 = inventory[index1].size
  116.       break
  117.     end
  118.   end
  119.   for i=0,#inventory,1 do
  120.     name = (inventory[i].name ~= nil) and inventory[i].name:gsub("hbm:", "") or ""
  121.     if (name == rp.input2 and i ~= index1) then
  122.       index2 = i
  123.       size2 = inventory[index2].size
  124.       break
  125.     end
  126.   end
  127.  
  128.   return (index1 >= 0 and index2 >= 0 and size1 ~= nil and size2 ~= nil) and {index1+1, index2+1, (size1 < size2) and size1 or size2} or nil
  129. end
  130.  
  131.  
  132. cfgData = {momentum, auto, transposer_input, transposer_output1, transposer_output2, rs_valves, rs_conveyors}
  133. if (fs.exists(cfgPath)) then
  134.   cfgFile = fs.open(cfgPath, "r")
  135.   cfgData = ser.unserialize(cfgFile:read(fs.size(cfgPath)*8))
  136. else
  137.   cfgFile = fs.open(cfgPath, "w")
  138.   cfgFile:write(ser.serialize(cfgData))
  139. end
  140. cfgFile:close()
  141. momentum = cfgData[1]
  142. auto = cfgData[2]
  143. transposer_input = cfgData[3]
  144. transposer_output1 = cfgData[4]
  145. transposer_output2 = cfgData[5]
  146. rs_valves = cfgData[6]
  147. rs_conveyors = cfgData[7]
  148.  
  149. local dipoles = {}
  150.  
  151. if (fs.exists(mgtPath)) then
  152.   mgtFile = fs.open(mgtPath, "r")
  153.   fileArray = ser.unserialize(mgtFile:read(fs.size(mgtPath)*8))
  154.  
  155.   for i=1,#fileArray,1 do
  156.     dipoles[i] = dipole:new(fileArray[i][1], fileArray[i][2])
  157.   end
  158. else
  159.   mgtFile = fs.open(mgtPath, "w")
  160.   fileArray = {}
  161.   mgtFile:write(ser.serialize(fileArray))
  162. end
  163. mgtFile:close()
  164.  
  165. local recipes = {}
  166.  
  167. if (fs.exists(rcpPath)) then
  168.   rcpFile = fs.open(rcpPath, "r")
  169.   fileArray = ser.unserialize(rcpFile:read(fs.size(rcpPath)*8))
  170.  
  171.   for i=1,#fileArray,1 do
  172.     recipes[i] = recipe:new(fileArray[i][1], fileArray[i][2], fileArray[i][3], fileArray[i][4])
  173.   end
  174. else
  175.   rcpFile = fs.open(rcpPath, "w")
  176.   fileArray = {}
  177.   rcpFile:write(ser.serialize(fileArray))
  178. end
  179. rcpFile:close()
  180.  
  181. for i=1,#dipoles,1 do
  182.   if (dipoles[i].momentum > max_moment) then
  183.     max_moment = dipoles[i].momentum
  184.   end
  185. end
  186.  
  187. for i=0,#sides-1,1 do
  188.   redstone.setOutput(sides[sides[i]], 0)
  189. end
  190.  
  191. term.clear()
  192. gpu.setBackground(0x0024c0)
  193. gpu.setForeground(0xffffff)
  194. term.setCursor(2, 2)
  195. print("Coil Loop")
  196. term.setCursor(12, 2)
  197. print("Command  ")
  198. term.setCursor(22, 2)
  199. print("Countdown")
  200. term.setCursor(32, 2)
  201. print("Auto mode")
  202. term.setCursor(2, 7)
  203. print("Target   ")
  204. term.setCursor(12, 7)
  205. print("Momentum ")
  206. term.setCursor(22, 7)
  207. print("Status   ")
  208. term.setCursor(2, 12)
  209. gpu.setBackground(0x00ee00)
  210. print("> Save <")
  211. term.setCursor(12, 12)
  212. gpu.setBackground(0x99aa00)
  213. print("> Exec <")
  214. term.setCursor(22, 12)
  215. gpu.setBackground(0xff0000)
  216. print("> Canc <")
  217.  
  218. term.setCursor(2, 8)
  219. gpu.setBackground(0xffffff)
  220. gpu.setForeground(0xff0000)
  221. --print("↑↑↑↑↑")
  222. for i=1,n_digits,1 do
  223.   term.write("↑")
  224. end
  225. term.setCursor(2, 10)
  226. gpu.setForeground(0x00bfff)
  227. --print("↓↓↓↓↓")
  228. for i=1,n_digits,1 do
  229.   term.write("↓")
  230. end
  231.  
  232. gpu.setForeground(0xffffff)
  233. gpu.setBackground(0x000000)
  234.  
  235. while (true) do
  236.   event = {eventC.pull(1, "touch")}
  237.  
  238.   now_momentum = source.getMomentum()
  239.   state = source.getState()
  240.   items = {source.getCrafting()}
  241.  
  242.   if (event[1] == "touch") then
  243.     if (event[4] == 12) then
  244.       if (event[3] >= 2 and event[3] <= 9) then
  245.         save()
  246.       end
  247.       if (event[3] >= 12 and event[3] <= 19) then
  248.         commit = true
  249.       end
  250.       if (event[3] >= 22 and event[3] <= 29) then
  251.         reset(true)
  252.       end
  253.     end
  254.     if (event[4] == 4) then
  255.       if (event[3] >= 32 and event[3] <= 40) then
  256.         auto = not auto
  257.       end
  258.     end
  259.    
  260.     if (not auto) then
  261.       if (event[4] == 8) then
  262.         change_pos = 1
  263.         change_pass = true
  264.       elseif (event[4] == 10) then
  265.         change_pos = -1
  266.         change_pass = true
  267.       end
  268.      
  269.       if (change_pass and event[3] >= 2 and event[3] <= 6) then
  270.         change_pass = false
  271.         momentum = momentum + 10^(2 + n_digits - event[3] - 1) * change_pos
  272.       end
  273.      
  274.       momentum = momentum > max_moment and max_moment or (momentum < 0 and 0 or momentum)
  275.     end
  276.   end
  277.  
  278.   if (auto and not (commit or execution)) then
  279.     for i=1,#recipes,1 do
  280.       inputs = transearch(transposer, transposer_input, recipes[i])
  281.       if (inputs ~= nil) then
  282.         transposer.transferItem(transposer_input, transposer_output1, inputs[3], inputs[1], 12)
  283.         transposer.transferItem(transposer_input, transposer_output2, inputs[3], inputs[2], 13)
  284.         momentum = recipes[i].momentum
  285.         commit = true
  286.         break
  287.       end
  288.     end
  289.   end
  290.  
  291.   selection = 1
  292.   for i=1,#dipoles,1 do
  293.     if (momentum > dipoles[i].momentum) then
  294.       selection = i+1
  295.     end
  296.   end
  297.  
  298.   if (commit) then
  299.     command = "CHK & SET"
  300.     coolant_pass = true
  301.     for i=1,selection,1 do
  302.       coolant = {dipoles[i].proxy.getCoolant()}
  303.       if (coolant[1] < coolant[3] or coolant[1] < coolant[2]/2) then
  304.         coolant_pass = false
  305.       end
  306.     end
  307.     if (coolant_pass) then
  308.       commit = false
  309.       execution = true
  310.     end
  311.     for i=1,#dipoles,1 do
  312.       dipoles[i].proxy.setThreshold((dipoles[i] == dipoles[selection]) and momentum or dipoles[i].momentum)
  313.     end
  314.   elseif (execution) then
  315.     command = "EXECUTING"
  316.   else
  317.     command = "IDLE"
  318.   end
  319.  
  320.   if (state:find("CRASH") ~= nil) then
  321.     command = "CRASH DET"
  322.     reset(true)
  323.   end
  324.  
  325.   if (execution and (items[2] <= 0 or items[4] <= 0) and state ~= "RUNNING") then
  326.     if (math.abs(computer.uptime() - temp) > 1.0) then
  327.       temp = computer.uptime()
  328.       cd_now = cd_now - 1
  329.     end
  330.   else
  331.     cd_now = cd_max
  332.   end
  333.  
  334.   if (cd_now < 0) then
  335.     cd_now = cd_max
  336.     reset(false)
  337.   end
  338.  
  339.   redstone.setOutput(rs_valves, (commit or execution) and 15 or 0) --valves
  340.   redstone.setOutput(rs_conveyors, execution and 15 or 0) --conveyors
  341.   torch.setChannel(radio .. selection)
  342.  
  343.   term.setCursor(2, 4)
  344.   print(("%1d"):format(selection))
  345.   term.setCursor(12, 4)
  346.   print(("%-9s"):format(command))
  347.   term.setCursor(2, 9)
  348.   print(("%5d"):format(momentum))
  349.   term.setCursor(12, 9)
  350.   print(("%5d"):format(now_momentum))
  351.   term.setCursor(12, 10)
  352.   print(("%5.1f%1s"):format(clamp(100.0*now_momentum/(momentum == 0 and 1 or momentum), 100.0, 0.0), "%"))
  353.   term.setCursor(22, 9)
  354.   print(("%-14s"):format(state))
  355.   term.setCursor(22, 4)
  356.   print(("%02d | %02d"):format(cd_now, cd_max))
  357.   term.setCursor(32, 4)
  358.   gpu.setForeground(0xffffff)
  359.   gpu.setBackground(auto and 0x00ee00 or 0xee0000)
  360.   print(("   %-3s   "):format(auto and "ON" or "OFF"))
  361.   gpu.setBackground(0x000000)
  362.   gpu.setForeground(0xffffff)
  363. end
Advertisement
Add Comment
Please, Sign In to add comment