View difference between Paste ID: 2FaxaZqV and 7M3hziBV
SHOW: | | - or go back to the newest paste.
1
----------------------
2
-- SafeReactor - a Big Reactors control program [ComputerCraft version]
3
-- by Kai Kikuchi
4
-- version: 0.23 - (BETA - STILL IN DEVELOP)
5
--
6
-- Source code: http://pastebin.com/7M3hziBV
7
-- Sample screenshot: https://imgur.com/higRKAX
8
-- OpenComputers WIP: http://pastebin.com/k40ktpxK
9
--
10
-- This program manages a Big Reactors reactor (both passive and active)
11
-- and turbines, making it very fuel efficient
12
--
13
-- How to install on ComputerCraft:
14
-- - type: pastebin run nPwUtAHc
15
-- - press Enter
16
----------------------
17
18
vern=2301
19
version="0.23"
20
21
updateTimer=0
22
23
local function checkUpdate()
24
	print("checking for update...")
25
	shell.run("pastebin","get","2geNdJma","srver")
26
	local updverfile = io.open("srver", "r")
27
28
	if updverfile then
29
		local updverfilel=""
30
		updverfilel=updverfile:read()
31
		
32
		updverfile:close()
33
		shell.run("rm","srver")
34
		updverfilel=tonumber(updverfilel)
35
		
36
		print("Current version number is "..vern)
37
		print("Online version number is "..updverfilel)
38
		
39
		if updverfilel > vern then
40
			print("new version found... updating!")
41
			shell.run("pastebin","get","7M3hziBV","srtmp")
42
			local srtmpf=io.open("srtmp","r")
43
			if srtmpf~=nil then
44
				srtmpf:close(srtmpf)
45
				shell.run("rm", "sr")
46
				shell.run("rename","srtmp","sr")
47
				print()
48
				print("Rebooting...")
49
				print()
50
				sleep(3)
51
				shell.run("reboot")
52
				error()
53
			else
54
				print("Update failed... :(")
55
			end
56
		end
57
	else
58
		print("Failed to check for update...")
59
	end
60
	
61
	updateTimer = os.startTimer(100000)
62
end
63
64
checkUpdate()
65
66
local function round(num, idp)
67
  local mult = 10^(idp or 0)
68
  return math.floor(num * mult + 0.5) / mult
69
end
70
71
local function curln(m, x)
72
	if m then
73
		curX, curY=m.getCursorPos()
74
		m.setCursorPos(x, curY+1)
75
	end
76
end
77
78
local function curxm(m, x)
79
	if m then
80
		curX, curY=m.getCursorPos()
81
		m.setCursorPos(x, curY)
82
	end
83
end
84
85
local function rfkrf(rf)
86
	if rf >= 1000 then
87
		return round(rf/1000, 2).." kRF"
88
	else
89
		return rf.." RF"
90
	end
91
end
92
93
local function periList(peripheralName)
94
	local periList = peripheral.getNames()
95
	local j=1
96
	local result={}
97
	for i=1, #periList do
98
		if peripheral.getType(periList[i]) == peripheralName then
99
			result[j]=periList[i]
100
			j=j+1
101
		end
102
	end
103
	if j==1 then
104
		return false
105
	else
106
		return result
107
	end
108
end
109
110
activeSignState=false
111
local function activeSign()
112
	if activeSignState then
113
		activeSignState=false
114
		return "/"
115
	else
116
		activeSignState=true
117
		return "\\"
118
	end
119
end
120
121
122
scoreT={}
123
scoreTi=1
124
125
local function scoreCalc(energy, fuel, tCore, tCasing)
126
	if energy>0 and fuel>0 then
127
128
		scoreT[scoreTi]=(((energy/20)+(energy/fuel))/18)-(tCore-tCasing)
129
		if scoreT[scoreTi] < 0 then
130
			scoreT[scoreTi]=0
131
		end
132
		
133
		if scoreTi>49 then
134
			scoreTi=1
135
		else
136
			scoreTi=scoreTi+1
137
		end
138
	end
139
	local j=0
140
	local score=0
141
	for i=1,50 do
142
		if scoreT[i] then
143
			score=score+scoreT[i]
144
			j=j+1
145
		end
146
	end
147
	if j<40 then
148
		return "-"
149
	else
150
		return round((score/j), 0)
151
	end
152
end
153
154
local function events()
155
	while true do
156
		p1 = ""
157
		p2 = ""
158
		p1, p2 = os.pullEventRaw()
159
		
160
		if p1=="peripheral" or p1=="peripheral_detach" or (p1=="timer" and p2==updateTimer) then
161
			print("Rebooting...")
162
			shell.run("reboot")
163
			error()
164
		elseif p1=="monitor_resize" then
165
			if mSkipEvent then
166
				mSkipEvent=false
167
			else
168
				mWrap.setTextScale(0.5)
169
				mSizeW, mSizeH = mWrap.getSize()
170
				
171
				if tCount then
172
					monitorTextScaleMult=math.min(mSizeW/55, mSizeH/(16+(tCount*2)))
173
				else
174
					monitorTextScaleMult=math.min(mSizeW/55, mSizeH/24)
175
				end
176
				monitorTextScaleMultFloor=math.floor(monitorTextScaleMult)
177
				if monitorTextScaleMult-monitorTextScaleMultFloor > 0.49 then
178
					monitorTextScaleMultFloor=monitorTextScaleMultFloor+0.5
179
				end
180
				
181
				if monitorTextScaleMultFloor < 0.5 then
182
					monitorTextScaleMultFloor=0.5
183
				end
184
				mWrap.setTextScale(monitorTextScaleMultFloor)
185
				
186
				m.reposition(1, 1, mSizeW, mSizeH)
187
				mSkipEvent=true
188
			end
189
		elseif p1=="terminate" then
190
			--
191
			error("Terminated")
192
		end
193
	end
194
end
195
196
-- still in develop 
197
local function gui()
198
	if mSide then
199
		while true do
200
			m.setCursorPos(1, 1)
201-
			m.write("Kai Industries SafeReactor "..activeSign())
201+
			m.write("Lets hope this works... "..activeSign())
202
			
203
			m.setVisible(true)
204
			m.setVisible(false)
205
			sleep(2)
206
		end
207
	end
208
end
209
210
rSide=periList("BigReactors-Reactor")
211
if rSide then
212
	r=peripheral.wrap(rSide[1])
213
else
214
	print("No reactor found. Exiting...")
215
	error()
216
end
217
218
mSide=periList("monitor")
219
220
if mSide then
221
	mWrap = peripheral.wrap(mSide[1])
222
	mWrap.setTextScale(0.5)
223
	mSizeW, mSizeH = mWrap.getSize()
224
	m=window.create(mWrap, 1, 1, mSizeW, mSizeH, false)
225
else
226
	m=window.create(term.native(), 0,0,0,0, false)
227
end
228
229
tSide=periList("BigReactors-Turbine")
230
231
if tSide then
232
	t={}
233
	for k,v in ipairs(tSide) do
234
		t[k]=peripheral.wrap(v)
235
	end
236
end
237
238
shell.run("label", "set", "\"SafeReactor Controller\"")
239
240
term.clear()
241
term.setCursorPos(1,1)
242
243
print("SafeReactor v."..version.." by Kai Kikuchi")
244
245
print("Tips:")
246
print("- hold Ctrl+R to reboot")
247
print("- hold Ctrl+T to terminate")
248
print("- edit config file with: edit config")
249
term.setCursorPos(1,8)
250
251
252
253
if not fs.exists("config") then
254
	cf=fs.open("config", "w")
255
	if cf then
256
		configDefault = [[
257
-- passive reactor settings
258
-- when running, this is the level of all rods
259
-- (0-100)
260
	runningRodLevel=0
261
262
-- buffers level (0-100)
263
--- overload level
264
---- if buffer is under this %, it will alert you
265
---- with a message on screen and outputs a inverted
266
---- redstone signal on the right side of computer
267
	bOverloadLevel=10
268
269
--- running level
270
---- under this level, the computer will start
271
---- producing energy
272
	bRunningLevel=75
273
274
--- standby level
275
---- if buffer is more than this value, it will
276
---- stop generating energy
277
	bStandbyLevel=90
278
	
279
-- acttive reactor/turbines settings
280
-- turbines optimal speed (RPM)
281
	turbineSetSpeed=1800
282
-- turbines flow rate (mB/t)
283
	fluidFlowRate=2000
284
285
		]]
286
		cf.write(configDefault)
287
		cf.close()
288
		
289
		print("A new config file has been created! You may edit it with: edit config")
290
	else
291
		print("An error occurred while opening config file")
292
	end
293
end
294
295
if not os.loadAPI("config") then
296
	print("An error occurred while opening config file")
297
	error()
298
end
299
300
301
if r.isActivelyCooled() then
302
	if t then
303
		if config.turbineSetSpeed then
304
			turbineSetSpeed=config.turbineSetSpeed
305
		else
306
			turbineSetSpeed=1800
307
		end
308
309
		if config.fluidFlowRate then
310
			fluidFlowRate=config.fluidFlowRate
311
		else
312
			fluidFlowRate=2000
313
		end
314
	
315
		lastStoredPower={}
316
		storedPower={}
317
		status={}
318
		storedPowerTick={}
319
		maxEnergy={}
320
		energyOutput={}
321
		tCount=0
322
		
323
		for k,turbine in ipairs(t) do
324
			storedPower[k]=0
325
			lastStoredPower[k]=0
326
			status[k]=0
327
			storedPowerTick[k]=os.clock()
328
			maxEnergy[k]=0
329
			energyOutput[k]=0
330
			turbine.setInductorEngaged(true)
331
			sleep(0.10)
332
			turbine.setFluidFlowRateMax(fluidFlowRate)
333
			tCount=tCount+1
334
		end
335
		
336
		if mSide then
337
			monitorTextScaleMult=math.min(mSizeW/55, mSizeH/(16+(tCount*2)))
338
			monitorTextScaleMultFloor=math.floor(monitorTextScaleMult)
339
			if monitorTextScaleMult-monitorTextScaleMultFloor > 0.49 then
340
				monitorTextScaleMultFloor=monitorTextScaleMultFloor+0.5
341
			end
342
			
343
			if monitorTextScaleMultFloor < 0.5 then
344
				monitorTextScaleMultFloor=0.5
345
			end
346
			mWrap.setTextScale(monitorTextScaleMultFloor)
347
			
348
			mSkipEvent=true
349
		end
350
		
351
		reactorSetEcoModeCount=100
352
		
353
354
		
355
		function activeReactor()
356
			while true do
357
				m.clear()
358
359
				m.setCursorPos(1, 3)
360
				
361
				turbineCount=0
362
				turbineFlowRate=0
363
				
364
				reactorSetEcoMode=true
365
				totalMaxEnergy=0
366
				totalEnergyOutput=0
367
				
368
				
369
				for k,turbine in ipairs(t) do
370
					
371
					if turbine.getConnected() then
372
						if turbine.getActive() then
373
							turbineCount=turbineCount+1
374
							turbineSpeed=turbine.getRotorSpeed();
375
							
376
							startTick=storedPowerTick[k]
377
							storedPowerTick[k]=os.clock()
378
							
379
							lastStoredPower[k]=storedPower[k]
380
							storedPower[k]=turbine.getEnergyStored()
381
							
382
							energy=round(turbine.getEnergyProducedLastTick(), 0)
383
							
384
							timeElapsed=round((storedPowerTick[k]-startTick)*20, 2)
385
							
386
							energyOutputCalculated=false
387
							if (lastStoredPower[k] < 980000 and storedPower[k] < 980000) then
388
								energyOutput[k]=round((lastStoredPower[k] - storedPower[k] + (energy*timeElapsed)) / timeElapsed, 0)
389
								if energyOutput[k] < 0 then
390
									energyOutput[k] = 0
391
								end
392
								energyOutputCalculated=true
393
							end
394
395
							
396
							totalEnergyOutput=totalEnergyOutput+energyOutput[k]
397
							
398
							if energy > 0 then
399
								maxEnergy[k] = energy
400
							end
401
							
402
							totalMaxEnergy=totalMaxEnergy+maxEnergy[k]
403
							
404
							--m.write(k..": "..round(turbineSpeed,0).."RPM "..round(storedPower[k]/10000, 0).."% "..rfkrf(energyOutput[k]).."/t")
405
							m.write(k..": "..round(turbineSpeed,0).."RPM ")
406
							if turbineSpeed > turbineSetSpeed+5 or (status[k]==4 and turbineSpeed > turbineSetSpeed) then
407
								-- overspeed!
408
								m.write(rfkrf(energyOutput[k]).."/t")
409
								
410
								turbine.setInductorEngaged(true)
411
								turbine.setFluidFlowRateMax(0)
412
								status[k]=4
413
							elseif turbineSpeed < turbineSetSpeed-20 or (status[k]==3 and turbineSpeed < turbineSetSpeed) then
414
								-- spool up
415
								m.write("Spooling-up")
416
								
417
								turbine.setInductorEngaged(false)
418
								turbine.setFluidFlowRateMax(fluidFlowRate)
419
420
								turbineFlowRate=turbineFlowRate+turbine.getFluidFlowRateMax()
421
								status[k]=3
422
							else
423
								m.write(rfkrf(energyOutput[k]).."/t")
424
								if storedPower[k] < 200000 then
425
									if storedPower[k] < 100000 and energyOutputCalculated and energyOutput[k] >= energy then
426
										-- overload
427
										status[k]=2
428
									else
429
										status[k]=0
430
									end
431
									-- running
432
									turbine.setInductorEngaged(true)
433
434
									if energy-energyOutput[k] > energy/2 then
435
										-- little energy output, no reactor activation
436
										sleep(0.2)
437
										turbine.setInductorEngaged(false)
438
										turbine.setFluidFlowRateMax(0)
439
										status[k]=1
440
									else
441
										turbineFlowRate=turbineFlowRate+turbine.getFluidFlowRateMax()
442
										if turbineSpeed < turbineSetSpeed+100 then
443
											turbine.setFluidFlowRateMax(fluidFlowRate)
444
										end
445
									end
446
								elseif storedPower[k] >= 800000 then
447
									-- full
448
									turbine.setInductorEngaged(false)
449
									turbine.setFluidFlowRateMax(0)
450
451
									status[k]=1
452
								end
453
							end
454
							
455
							
456
							if status[k]==0 then
457
								-- m.write("RUN")
458
								reactorSetEcoMode=false
459
							elseif status[k]==1 then
460
								-- m.write("ECO")
461
							elseif status[k]==2 then
462
								-- m.write("OL!")
463
								reactorSetEcoMode=false
464
							elseif status[k]==3 then
465
								-- m.write("SUP")
466
								reactorSetEcoMode=false
467
							elseif status[k]==4 then
468
								-- m.write("OS!")
469
							end
470
						else
471
							m.write(k..": not active")
472
						end
473
					else
474
						m.write(k..": not connected")
475
					end
476
					curln(m, 1)
477
				end
478
				
479
				-- reactor
480
				casingTemp=r.getCasingTemperature()
481
				coreTemp=r.getFuelTemperature()
482
				
483
				-- rodLevel=0
484
				-- c=r.getNumberOfControlRods()
485
486
				rodLevel=round(r.getControlRodLevel(0), 0)
487
				if rodLevel > 100 then
488
					rodLevel = 100
489
				elseif rodLevel < 0 then
490
					rodLevel = 0
491
				end
492
				
493
				fuelConsumed=r.getFuelConsumedLastTick()
494
				
495
				m.write("R: "..rodLevel.."% "..round(r.getHotFluidProducedLastTick()/1000, 0).." B/t "..round(casingTemp, 0).."C ")
496
				
497
				if reactorSetEcoMode then
498
					if reactorSetEcoModeCount>0 then
499
						reactorSetEcoModeCount=reactorSetEcoModeCount-1
500
					end
501
				else
502
					reactorSetEcoModeCount=20
503
				end
504
				
505
				if turbineFlowRate>0 or reactorSetEcoModeCount>0 then
506
					if not (lastCasingTemp == nil) then	
507
						if casingTemp > 600 then
508
							if lastCasingTemp <= casingTemp then
509
								if casingTemp > 2000 then
510
									r.setAllControlRodLevels(rodLevel+4)
511
									m.write("V")
512
								else
513
									r.setAllControlRodLevels(rodLevel+1)
514
									m.write("v ")
515
								end
516
							else
517
								m.write("v ")
518
							end
519
							
520
							if turbineFlowRate <= r.getHotFluidProducedLastTick() then
521
								-- m.write(">RUN")
522
							elseif (rodLevel==0 and coreTemp < 400) then
523
								-- is this "Tiny Reactors"?
524
							else
525
								-- not enough water
526
								-- m.write(">NEL")
527
							end
528
						elseif casingTemp < 400 then
529
							if lastCasingTemp >= casingTemp then
530
								if turbineFlowRate == r.getHotFluidProducedLastTick() then
531
									r.setAllControlRodLevels(rodLevel-1)
532
								else
533
									r.setAllControlRodLevels(rodLevel-2)
534
								end
535
							end
536
							-- m.write("^ >RUN")
537
						else
538
							-- m.write("* >RUN")
539
						end
540
						
541
					end
542
					lastCasingTemp=casingTemp
543
				else
544
					r.setAllControlRodLevels(100)
545
					-- m.write("- >ECO")
546
				end
547
				curln(m, 1)
548
				curln(m, 1)
549
				
550
				-- Summary info
551
				m.write("Capacity: "..rfkrf(totalMaxEnergy).."/t")
552
				curln(m, 1)
553
				m.write("Output: "..rfkrf(totalEnergyOutput).."/t")
554
				curln(m, 1)
555
				m.write("Fuel burnup: "..round(fuelConsumed, 3).." mB/t")
556
				curln(m, 1)
557
				m.write("Score: "..scoreCalc(totalMaxEnergy, fuelConsumed, coreTemp, casingTemp))
558
				curln(m, 1)
559
				sleep(0.5)
560
			end
561
		end
562
		parallel.waitForAll(activeReactor, events, gui)
563
	else
564
		print("Reactor is actively cooled, but there is no turbine")
565
		error()
566
	end
567
else
568
	rodStat=2
569
	statCol=16
570
571
	bOverloadLevel=config.bOverloadLevel*100000
572
	bRunningLevel=config.bRunningLevel*100000
573
	bStandbyLevel=config.bStandbyLevel*100000
574
575
576
	storedPower=0
577
	lastStoredPower=0
578
	energyOutput=0
579
	maxEnergy=0
580
	r.setAllControlRodLevels(config.runningRodLevel)
581
	if mSide then
582
		monitorTextScaleMult=math.min(mSizeW/55, mSizeH/24)
583
		monitorTextScaleMultFloor=math.floor(monitorTextScaleMult)
584
		if monitorTextScaleMult-monitorTextScaleMultFloor > 0.49 then
585
			monitorTextScaleMultFloor=monitorTextScaleMultFloor+0.5
586
		end
587
		
588
		if monitorTextScaleMultFloor < 0.5 then
589
			monitorTextScaleMultFloor=0.5
590
		end
591
		mWrap.setTextScale(monitorTextScaleMultFloor)
592
		
593
		mSkipEvent=true
594
	end
595
	
596
	local function passiveReactor()
597
		while true do
598
			m.clear()
599
600
			m.setCursorPos(1, 3)
601
602
			if r.getConnected() then
603
				coreTemp=round(r.getFuelTemperature(), 0)
604
				casingTemp=round(r.getCasingTemperature(), 0)
605
				
606
				lastStoredPower=storedPower
607
				storedPower=r.getEnergyStored()
608
609
				energy=round(r.getEnergyProducedLastTick(), 0)
610
611
				if energy > maxEnergy then
612
					maxEnergy = energy
613
				end
614
				
615
				energyOutput=round((lastStoredPower - storedPower + (energy*20)) / 20, 0)
616
				if energyOutput < 0 then
617
					energyOutput = 0
618
				end
619
				
620
				-- control rods
621
				if storedPower < bOverloadLevel and energyOutput >= energy then
622
					rodStat=1
623
					r.setAllControlRodLevels(config.runningRodLevel)
624
				elseif storedPower < bRunningLevel then
625
					rodStat=2
626
					r.setAllControlRodLevels(config.runningRodLevel)
627
				elseif storedPower >= bStandbyLevel then
628
					rodStat=3
629
					r.setAllControlRodLevels(100)
630
				end
631
				
632
				-- fuel amount
633
				fuelAmount=(r.getFuelAmountMax()/r.getFuelAmount())
634
				
635
				fuelConsumed=r.getFuelConsumedLastTick()
636
				
637
				-- display info
638
				m.clearLine()
639
				m.write("Heat (int|ext)")
640
				curxm(m, statCol)
641
				m.write(": "..coreTemp.."C|"..casingTemp.."C")
642
				
643
				curln(m, 1)
644
				m.clearLine()
645
				m.write("Output")
646
				curxm(m, statCol)
647
				m.write(": "..rfkrf(energyOutput).."/t")
648
				
649
				curln(m, 1)
650
				m.clearLine()
651
				m.write("Buffer (10 mRF)")
652
				curxm(m, statCol)
653
				m.write(": "..round(storedPower/100000, 2).." %")
654
				
655
				curln(m, 1)
656
				m.clearLine()
657
				m.write("Production")
658
				curxm(m, statCol)
659
				m.write(": "..rfkrf(energy).."/t")
660
				
661
				curln(m, 1)
662
				m.clearLine()
663
				m.write("Max. Production")
664
				curxm(m, statCol)
665
				m.write(": "..rfkrf(maxEnergy).."/t")
666
				
667
				curln(m, 1)
668
				m.clearLine()
669
				m.write("Fuel burnup: ")
670
				curxm(m, statCol)
671
				m.write(": "..round(fuelConsumed, 3).." mB/t")
672
673
				curln(m, 1)
674
				m.clearLine()
675
				m.write("Score")
676
				curxm(m, statCol)
677
				m.write(": "..scoreCalc(maxEnergy, fuelConsumed, coreTemp, casingTemp))
678
				
679
				m.setCursorPos(1, 10)
680
				m.clearLine()
681
				
682
				rs.setOutput("right", true)
683
				if r.getActive() then
684
					if fuelAmount > 1.4 then
685
						m.write("Status: online - fuel needed!")
686
						rs.setOutput("right", false)
687
					elseif casingTemp > 2000 then
688
						m.write("Status: online - OVERHEAT!")
689
						rs.setOutput("right", false)
690
						if casingTemp > 3000 then
691
							r.setActive(false)
692
						end
693
					else
694
						if rodStat == 1 then
695
							m.write("Status: online - overload!")
696
							rs.setOutput("right", false)
697
						elseif rodStat == 2 then
698
							m.write("Status: online - running")
699
						elseif rodStat == 3 then
700
							m.write("Status: online - standby")
701
							if (storedPower/100000) > 99 then
702
								bStandbyLevel=bStandbyLevel-1
703
							end
704
						else 
705
							m.write("Status: Error")
706
						end
707
					end
708
				else
709
					m.setCursorPos(1, 10)
710
					m.clearLine()
711
					m.write("Status: offline")
712
				end
713
			else
714
				m.setCursorPos(1, 10)
715
				m.clearLine()
716
				m.write("Status: no reactor")
717
			end
718
			sleep(0.5)
719
		end
720
	end
721
	
722
	parallel.waitForAll(passiveReactor, events, gui)
723
724
end