View difference between Paste ID: HX9Fzv54 and UfDUdcSs
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