SHOW:
|
|
- or go back to the newest paste.
1 | local component = require("component") | |
2 | local event = require("event") | |
3 | local term = require("term") | |
4 | local gpu = component.gpu | |
5 | ||
6 | -- Safety Checks | |
7 | ||
8 | if not component.isAvailable("draconic_reactor") then | |
9 | print("Reactor not connected. Please connect computer to reactor with an Adapter block.") | |
10 | os.exit() | |
11 | end | |
12 | reactor = component.draconic_reactor | |
13 | local flux_gates = {} | |
14 | for x,y in pairs(component.list("flux_gate")) do | |
15 | flux_gates[#flux_gates+1] = x | |
16 | end | |
17 | if #flux_gates < 2 then | |
18 | print("Not enough flux gates connected; please connect inflow and outflow flux gates with Adapter blocks.") | |
19 | os.exit() | |
20 | end | |
21 | flux_in = component.proxy(flux_gates[1]) | |
22 | flux_out = component.proxy(flux_gates[2]) | |
23 | if not flux_in or not flux_out then | |
24 | print("Not enough flux gates connected; please connect inflow and outflow flux gates with Adapter blocks.") | |
25 | os.exit() | |
26 | end | |
27 | ||
28 | -- Functions | |
29 | ||
30 | function exit_msg(msg) | |
31 | term.clear() | |
32 | print(msg) | |
33 | os.exit() | |
34 | end | |
35 | ||
36 | function modify_temp(offset) | |
37 | local new_temp = ideal_temp + offset | |
38 | if new_temp > 14000 then | |
39 | new_temp = 14000 | |
40 | elseif new_temp < 2001 then | |
41 | new_temp = 2001 | |
42 | end | |
43 | ideal_temp = new_temp | |
44 | end | |
45 | ||
46 | function modify_field(offset) | |
47 | local new_strength = ideal_strength + offset | |
48 | if new_strength > 100 then | |
49 | new_strength = 100 | |
50 | elseif new_strength < 0.1 then | |
51 | new_strength = 0.5 | |
52 | end | |
53 | ideal_strength = new_strength | |
54 | end | |
55 | ||
56 | -- Buttons | |
57 | ||
58 | local adj_button_width = 19 | |
59 | local temp_adjust_x_offset = 68 | |
60 | local temp_adjust_y_offset = 2 | |
61 | local field_adjust_x_offset = temp_adjust_x_offset + adj_button_width + 2 | |
62 | local field_adjust_y_offset = 2 | |
63 | ||
64 | local buttons = { | |
65 | start={ | |
66 | x=42, | |
67 | y=2, | |
68 | width=24, | |
69 | height=7, | |
70 | text="Start", | |
71 | action=function() | |
72 | if safe then | |
73 | state = "Charging" | |
74 | reactor.chargeReactor() | |
75 | elseif shutting_down then | |
76 | state = "Active" | |
77 | reactor.activateReactor() | |
78 | end | |
79 | end, | |
80 | condition=function() return safe or shutting_down end | |
81 | }, | |
82 | shutdown={ | |
83 | x=42, | |
84 | y=12, | |
85 | width=24, | |
86 | height=7, | |
87 | text="Shutdown", | |
88 | action=function() | |
89 | state = "Manual Shutdown" | |
90 | reactor.stopReactor() | |
91 | end, | |
92 | condition=function() return running end | |
93 | }, | |
94 | switch_gates={ | |
95 | x=2, | |
96 | y=20, | |
97 | width=24, | |
98 | height=3, | |
99 | text="Swap flux gates", | |
100 | action=function() | |
101 | local old_addr = flux_in.address | |
102 | flux_in = component.proxy(flux_out.address) | |
103 | flux_out = component.proxy(old_addr) | |
104 | end, | |
105 | condition=function() return safe end | |
106 | }, | |
107 | exit={ | |
108 | x=42, | |
109 | y=12, | |
110 | width=24, | |
111 | height=7, | |
112 | text="Exit", | |
113 | action=function() | |
114 | event_loop = false | |
115 | end, | |
116 | condition=function() return safe end | |
117 | }, | |
118 | temp_up_thousand={ | |
119 | x=temp_adjust_x_offset, | |
120 | y=temp_adjust_y_offset, | |
121 | width=adj_button_width, | |
122 | height=1, | |
123 | text="+ 1000", | |
124 | action=function() modify_temp(1000) end | |
125 | }, | |
126 | temp_up_hundred={ | |
127 | x=temp_adjust_x_offset, | |
128 | y=temp_adjust_y_offset+2, | |
129 | width=adj_button_width, | |
130 | height=1, | |
131 | text="+ 100", | |
132 | action=function() modify_temp(100) end | |
133 | }, | |
134 | temp_up_ten={ | |
135 | x=temp_adjust_x_offset, | |
136 | y=temp_adjust_y_offset+4, | |
137 | width=adj_button_width, | |
138 | height=1, | |
139 | text="+ 10", | |
140 | action=function() modify_temp(10) end | |
141 | }, | |
142 | temp_up_one={ | |
143 | x=temp_adjust_x_offset, | |
144 | y=temp_adjust_y_offset+6, | |
145 | width=adj_button_width, | |
146 | height=1, | |
147 | text="+ 1", | |
148 | action=function() modify_temp(1) end | |
149 | }, | |
150 | temp_down_thousand={ | |
151 | x=temp_adjust_x_offset, | |
152 | y=temp_adjust_y_offset+16, | |
153 | width=adj_button_width, | |
154 | height=1, | |
155 | text="- 1000", | |
156 | action=function() modify_temp(-1000) end | |
157 | }, | |
158 | temp_down_hundred={ | |
159 | x=temp_adjust_x_offset, | |
160 | y=temp_adjust_y_offset+14, | |
161 | width=adj_button_width, | |
162 | height=1, | |
163 | text=" - 100", | |
164 | action=function() modify_temp(-100) end | |
165 | }, | |
166 | temp_down_ten={ | |
167 | x=temp_adjust_x_offset, | |
168 | y=temp_adjust_y_offset+12, | |
169 | width=adj_button_width, | |
170 | height=1, | |
171 | text="- 10", | |
172 | action=function() modify_temp(-10) end | |
173 | }, | |
174 | temp_down_one={ | |
175 | x=temp_adjust_x_offset, | |
176 | y=temp_adjust_y_offset+10, | |
177 | width=adj_button_width, | |
178 | height=1, | |
179 | text="- 1", | |
180 | action=function() modify_temp(-1) end | |
181 | }, | |
182 | field_up_ten={ | |
183 | x=field_adjust_x_offset, | |
184 | y=field_adjust_y_offset+4, | |
185 | width=adj_button_width, | |
186 | height=1, | |
187 | text="+ 10", | |
188 | action=function() modify_field(10) end | |
189 | }, | |
190 | field_up_one={ | |
191 | x=field_adjust_x_offset, | |
192 | y=field_adjust_y_offset+6, | |
193 | width=adj_button_width, | |
194 | height=1, | |
195 | text="+ 0.5", | |
196 | action=function() modify_field(0.5) end | |
197 | }, | |
198 | field_down_ten={ | |
199 | x=field_adjust_x_offset, | |
200 | y=field_adjust_y_offset+12, | |
201 | width=adj_button_width, | |
202 | height=1, | |
203 | text="- 10", | |
204 | action=function() modify_field(-10) end | |
205 | }, | |
206 | field_down_one={ | |
207 | x=field_adjust_x_offset, | |
208 | y=field_adjust_y_offset+10, | |
209 | width=adj_button_width, | |
210 | height=1, | |
211 | text="- 0.5", | |
212 | action=function() modify_field(-0.5) end | |
213 | } | |
214 | } | |
215 | ||
216 | -- main code | |
217 | ||
218 | flux_in.setFlowOverride(0) | |
219 | flux_out.setFlowOverride(0) | |
220 | flux_in.setOverrideEnabled(true) | |
221 | flux_out.setOverrideEnabled(true) | |
222 | ||
223 | local condition = reactor.getReactorInfo() | |
224 | if not condition then | |
225 | print("You Done Goofed Moron") | |
226 | os.exit() | |
227 | end | |
228 | ||
229 | ideal_strength = 25 | |
230 | ||
231 | ideal_temp = 7950 | |
232 | cutoff_temp = 14100 | |
233 | ||
234 | -- tweakable pid gains | |
235 | ||
236 | inflow_P_gain = 1 | |
237 | inflow_I_gain = 0.04 | |
238 | inflow_D_gain = 0.1 | |
239 | ||
240 | outflow_P_gain = 500 | |
241 | outflow_I_gain = 0.5 | |
242 | outflow_II_gain = 0.0000003 | |
243 | outflow_D_gain = 60000 | |
244 | ||
245 | -- initialize main loop | |
246 | ||
247 | inflow_I_sum = 0 | |
248 | inflow_D_last = 0 | |
249 | ||
250 | outflow_I_sum = 0 | |
251 | outflow_II_sum = 0 | |
252 | outflow_D_last = 0 | |
253 | ||
254 | state = "Standby" | |
255 | shutting_down = false | |
256 | ||
257 | if condition.temperature > 25 then | |
258 | state = "Cooling" | |
259 | end | |
260 | if condition.temperature > 2000 then | |
261 | state = "Active" | |
262 | end | |
263 | ||
264 | -- Possible states: | |
265 | --Standby | |
266 | --Charging | |
267 | --Active | |
268 | --Manual Shutdown | |
269 | --Emergency Shutdown | |
270 | --Cooling | |
271 | ||
272 | event_loop = true | |
273 | while event_loop do | |
274 | ||
275 | if not component.isAvailable("draconic_reactor") then | |
276 | exit_msg("Reactor disconnected, exiting") | |
277 | end | |
278 | ||
279 | if not component.isAvailable("flux_gate") then | |
280 | exit_msg("Flux gates disconnected, exiting") | |
281 | end | |
282 | ||
283 | local info = reactor.getReactorInfo() | |
284 | ||
285 | local inflow = 0 | |
286 | local outflow = 0 | |
287 | ||
288 | shutting_down = state == "Manual Shutdown" or state == "Emergency Shutdown" | |
289 | running = state == "Charging" or state == "Active" | |
290 | safe = state == "Standby" or state == "Cooling" | |
291 | ||
292 | if state == "Charging" then | |
293 | inflow = 3200000 | |
294 | ||
295 | if info.temperature > 2000 then | |
296 | reactor.activateReactor() | |
297 | state = "Active" | |
298 | end | |
299 | elseif state == "Cooling" then | |
300 | if info.temperature < 25 then | |
301 | state = "Standby" | |
302 | end | |
303 | inflow = 10 | |
304 | outflow = 20 | |
305 | elseif state == "Standby" then | |
306 | inflow = 10 | |
307 | outflow = 20 | |
308 | else | |
309 | -- adjust inflow rate based on field strength | |
310 | ||
311 | local field_error = (info.maxFieldStrength * (ideal_strength / 100)) - info.fieldStrength | |
312 | local proportional_field_error = field_error * inflow_P_gain | |
313 | inflow_I_sum = inflow_I_sum + field_error | |
314 | local integral_field_error = inflow_I_sum * inflow_I_gain | |
315 | local derivative_field_error = (field_error - inflow_D_last) * inflow_D_gain | |
316 | inflow_D_last = field_error | |
317 | local inflow_correction = proportional_field_error + integral_field_error + derivative_field_error | |
318 | if inflow_correction < 0 then | |
319 | inflow_I_sum = inflow_I_sum - field_error | |
320 | end | |
321 | inflow = inflow_correction | |
322 | ||
323 | if not shutting_down then | |
324 | ||
325 | -- adjust outflow rate based on core temperature | |
326 | ||
327 | local temp_error = ideal_temp - info.temperature | |
328 | local proportional_temp_error = temp_error * outflow_P_gain | |
329 | outflow_I_sum = outflow_I_sum + temp_error | |
330 | local integral_temp_error = outflow_I_sum * outflow_I_gain | |
331 | if math.abs(temp_error) < 100 then | |
332 | outflow_II_sum = outflow_II_sum + integral_temp_error | |
333 | else | |
334 | outflow_II_sum = 0 | |
335 | end | |
336 | local second_integral_temp_error = outflow_II_sum * outflow_II_gain | |
337 | local derivative_temp_error = (temp_error - outflow_D_last) * outflow_D_gain | |
338 | outflow_D_last = temp_error | |
339 | local outflow_correction = proportional_temp_error + integral_temp_error + second_integral_temp_error + derivative_temp_error | |
340 | if outflow_correction < 0 then | |
341 | outflow_I_sum = outflow_I_sum - temp_error | |
342 | end | |
343 | outflow = outflow_correction | |
344 | ||
345 | -- cut off reactor in case of emergency | |
346 | - | local chaos = ((info.fuelConversion / info.maxFuelConversion) * 100) |
346 | + | if (1 - info.fuelConversion / info.maxFuelConversion) > 97 then |
347 | print("Reactor Fuel Low, Shutting Down") | |
348 | - | if chaos == 97.5 then |
348 | + | |
349 | reactor.stopReactor() | |
350 | end | |
351 | else | |
352 | if info.temperature < 2000 then | |
353 | state = "Cooling" | |
354 | end | |
355 | end | |
356 | end | |
357 | ||
358 | if state ~= "Active" and not shutting_down then | |
359 | inflow_I_sum = 0 | |
360 | inflow_D_last = 0 | |
361 | outflow_I_sum = 0 | |
362 | outflow_II_sum = 0 | |
363 | outflow_D_last = 0 | |
364 | end | |
365 | ||
366 | if inflow < 0 then | |
367 | inflow = 0 | |
368 | end | |
369 | if outflow < 0 then | |
370 | outflow = 0 | |
371 | end | |
372 | ||
373 | inflow = math.floor(inflow) | |
374 | outflow = math.floor(outflow) | |
375 | ||
376 | flux_in.setFlowOverride(inflow) | |
377 | flux_out.setFlowOverride(outflow) | |
378 | ||
379 | -- Draw screen | |
380 | ||
381 | if term.isAvailable() then | |
382 | ||
383 | -- Draw Values | |
384 | ||
385 | local left_margin = 2 | |
386 | local spacing = 2 | |
387 | ||
388 | local values = { | |
389 | "Status: " .. state, | |
390 | "Field Strength: " .. ((info.fieldStrength / info.maxFieldStrength) * 100) .. "%", | |
391 | "Energy Saturation: " .. ((info.energySaturation / info.maxEnergySaturation) * 100) .. "%", | |
392 | "Fuel Concentration: " .. ((1 - info.fuelConversion / info.maxFuelConversion) * 100) .. "%", | |
393 | "Temperature: " .. info.temperature .. " F", | |
394 | "Reactor Efficiency: " .. info.fuelConversionRate .. " nb/t", | |
395 | "Energy Inflow Rate: " .. inflow .. " RF/t", | |
396 | "Energy Outflow Rate: " .. outflow .. " RF/t" | |
397 | } | |
398 | ||
399 | if safe then | |
400 | values[#values+1] = "Click if flux gates need to be swapped" | |
401 | end | |
402 | ||
403 | term.clear() | |
404 | ||
405 | for i, v in ipairs(values) do | |
406 | term.setCursor(left_margin, i * spacing) | |
407 | term.write(v) | |
408 | end | |
409 | ||
410 | -- Draw button values | |
411 | ||
412 | term.setCursor(temp_adjust_x_offset, temp_adjust_y_offset+8) | |
413 | term.write("Target Temp: " .. ideal_temp .. " F") | |
414 | term.setCursor(field_adjust_x_offset, field_adjust_y_offset+8) | |
415 | term.write("Target Strength: " .. ideal_strength .. "%") | |
416 | ||
417 | -- Draw Buttons | |
418 | ||
419 | gpu.setForeground(0x000000) | |
420 | ||
421 | for bname, button in pairs(buttons) do | |
422 | if button.depressed then | |
423 | ||
424 | button.depressed = button.depressed - 1 | |
425 | if button.depressed == 0 then | |
426 | button.depressed = nil | |
427 | end | |
428 | end | |
429 | if button.condition == nil or button.condition() then | |
430 | local center_color = 0xAAAAAA | |
431 | local highlight_color = 0xCCCCCC | |
432 | local lowlight_color = 0x808080 | |
433 | if button.depressed then | |
434 | center_color = 0x999999 | |
435 | highlight_color = 0x707070 | |
436 | lowlight_color = 0xBBBBBB | |
437 | end | |
438 | gpu.setBackground(center_color) | |
439 | gpu.fill(button.x, button.y, button.width, button.height, " ") | |
440 | if button.width > 1 and button.height > 1 then | |
441 | gpu.setBackground(lowlight_color) | |
442 | gpu.fill(button.x+1, button.y+button.height-1, button.width-1, 1, " ") | |
443 | gpu.fill(button.x+button.width-1, button.y, 1, button.height, " ") | |
444 | gpu.setBackground(highlight_color) | |
445 | gpu.fill(button.x, button.y, 1, button.height, " ") | |
446 | gpu.fill(button.x, button.y, button.width, 1, " ") | |
447 | end | |
448 | gpu.setBackground(center_color) | |
449 | term.setCursor(button.x + math.floor(button.width / 2 - #button.text / 2), button.y + math.floor(button.height / 2)) | |
450 | term.write(button.text) | |
451 | end | |
452 | end | |
453 | ||
454 | gpu.setBackground(0x000000) | |
455 | gpu.setForeground(0xFFFFFF) | |
456 | end | |
457 | ||
458 | -- Wait for next tick, or manual shutdown | |
459 | ||
460 | local event, id, op1, op2 = event.pull(0.05) | |
461 | if event == "interrupted" then | |
462 | if safe then | |
463 | break | |
464 | end | |
465 | elseif event == "touch" then | |
466 | ||
467 | -- Handle Button Presses | |
468 | ||
469 | local x = op1 | |
470 | local y = op2 | |
471 | ||
472 | for bname, button in pairs(buttons) do | |
473 | if (button.condition == nil or button.condition()) and x >= button.x and x <= button.x + button.width and y >= button.y and y <= button.y + button.height then | |
474 | button.action() | |
475 | button.depressed = 3 | |
476 | end | |
477 | end | |
478 | end | |
479 | end | |
480 | ||
481 | term.clear() | |
482 |