View difference between Paste ID: 656cFtwF and G77y0k3j
SHOW: | | - or go back to the newest paste.
1-
local computer = require("computer")
1+
local computer = require("computer")
2-
computer.beep(440, .1)
2+
local component = require("component")
3-
local component = require("component")
3+
local event = require("event")
4-
local reactors = {}
4+
local term = require("term")
5-
do
5+
6-
  local t = component.list("nc_fission_reactor")
6+
-- control just one reactor per computer. Simpler that way.
7-
  for address in pairs(t) do table.insert(reactors, component.proxy(address)) end
7+
local reactor
8-
end
8+
do
9-
local event = require("event")
9+
	local t = component.list("nc_fission_reactor")
10-
local term = require("term")
10+
	if not next(t) then -- none!
11-
if term then term.clear() end
11+
		print("Error: no reactors found!")
12-
local controls, formatstring, header = {}, "", ""
12+
		os.exit()
13-
do
13+
	end
14-
  for i = 1, #reactors do
14+
	if next(t, (next(t))) then -- more than one!
15-
    controls[i] = {fuzzyenergyshutdown = false, fuzzyheatshutdown = false, shutdown = true}
15+
		print("Error: this program can only control one reactor!")
16-
  end
16+
		os.exit()
17-
  header = string.format(string.format("%%-%ds   Fuel       Heat  Energy  Status", tostring(#reactors):len()), "#")
17+
	end
18-
  formatstring = string.format("%%-0%dd   %%-7s  %%5.1f%%%%  %%5.1f%%%%  %%s", tostring(#reactors):len())
18+
	reactor = component.nc_fission_reactor
19-
end
19+
end
20-
local low, high = 0.25, 0.5
20+
local isproblem = function()
21-
if term then
21+
	local problem = reactor.getProblem()
22-
  term.clear()
22+
	if (problem == "No Problem") and (reactor.getFissionFuelName() == "No Fuel") then problem = "No Fuel" end
23-
  print(header)
23+
	return problem
24-
end
24+
end
25-
repeat
25+
reactor.deactivate() -- just so we know.
26-
  local keypress = event.pull(0, "key_down")
26+
27-
  if keypress then
27+
-- scale a number in the 0 to 1 range to an integer in the 1 to n range in such a way that all integers are equally represented.
28-
    print("Keypress detected! Shutting down all reactors.")
28+
local scalenumber = function(x, n)
29-
    for _, reactor in pairs(reactors) do
29+
	return math.floor(math.max(math.min(x * n + 1, n), 1))
30-
      reactor.deactivate()
30+
end
31-
    end
31+
32-
    os.exit()
32+
-- stubs for term not being available.
33-
  end
33+
local t = {
34-
  if term then term.setCursor(1, 2) end
34+
	drawdisplay = function(t)
35-
  for i = 1, #reactors do
35+
		if isproblem() ~= "No Problem" then computer.beep(440, .1) end
36-
    local reactor = reactors[i]
36+
	end,
37-
    local energylevel = reactor.getEnergyStored() / reactor.getMaxEnergyStored()
37+
	err = function(s)
38-
    local heatlevel = reactor.getHeatLevel() / reactor.getMaxHeatLevel()
38+
		print(s)
39-
    local newfuzzyenergyshutdown = controls[i].fuzzyenergyshutdown and (energylevel > low) or (energylevel > high)
39+
		os.exit()
40-
    local newfuzzyheatshutdown = controls[i].fuzzyheatshutdown and (heatlevel > low) or (heatlevel > high)
40+
	end,
41-
    local newshutdown = newfuzzyenergyshutdown or newfuzzyheatshutdown
41+
}
42-
    if newshutdown then reactor.deactivate() else reactor.activate() end
42+
-- set up display stuff.
43-
    if term then
43+
if term.isAvailable() then
44-
      print(string.format(formatstring, i, reactor.getFissionFuelName(), heatlevel * 100, energylevel * 100, outoffuel and "Out of fuel!" or (newshutdown and "Off         " or "On          ")))
44+
	local gpu = component.gpu
45-
    end
45+
	local sf, sb = gpu.setForeground, gpu.setBackground
46-
     controls[i].fuzzyenergyshutdown, controls[i].fuzzyheatshutdown, controls[i].shutdown = newfuzzyenergyshutdown, newfuzzyheatshutdown, newshutdown
46+
	t.err = function(s)
47-
  end
47+
		sf(0xffffff)
48-
until false
48+
		sb(0x000000)
49
		term.clear()
50
		term.write(s, true)
51
		os.exit()
52
	end
53
	sf(0xffffff)
54
	sb(0x000000)
55
	term.clear()
56
	local colorscreen = gpu.getDepth() ~= 1
57
	local width, height = gpu.maxResolution()
58
	local aspectratio = 1
59
	width = math.min(width, height * aspectratio * 2) -- * 2 because of character size
60
	-- we want the height to be a multiple of 4 plus 3.
61
	height = math.floor((width / 2 / aspectratio - 3) / 4) * 4 + 3
62
	-- resize the width accordingly.
63
	width = math.floor(height * 2 * aspectratio)
64
	-- and set bar tops and height.
65
	local barheight = math.floor((height - 3) / 4)
66
	local bartops = {
67
		energy = 1,
68
		heat = 2 + barheight,
69
		fueltime = 3 + barheight * 2,
70
		runtime = 4 + barheight * 3
71
	}
72
	gpu.setResolution(width, height)
73
	local sevenths = {
74
		energy = {0xff0000, 0xff8000, 0xffff00, 0x00ff00, 0xffff00, 0xff8000, 0xff0000},
75
		heat = {0x00ff00, 0x00ff00, 0x00ff00, 0x00ff00, 0xffff00, 0xff8000, 0xff0000},
76
		fueltime = {0xff0000, 0xff8000, 0xffff00, 0x00ff00, 0x00ff00, 0x00ff00, 0x00ff00},
77
		runtime = {0xffff00, 0xffff00, 0xffff00, 0xffff00, 0xffff00, 0xffff00, 0xffff00}
78
	}
79
	if not colorscreen then
80
		for i = 1, 7 do
81
			sevenths.energy[i] = 0xffffff
82
		end
83
		sevenths.heat, sevenths.fueltime, sevenths.runtime = sevenths.energy, sevenths.energy, sevenths.energy
84
	end
85
	-- draw a line of the display.
86
	local line = function(bartype, x, y, isblack)
87
		sb(isblack and 0 or sevenths[bartype][scalenumber((x - 1) / (width - 1), 7)])
88
		gpu.fill(x, bartops[bartype], 1, y, " ")
89
	end
90
	-- initialize the display.
91
	for bartype, wedges in pairs(sevenths) do
92
		for x = 1, width do
93
			line(bartype, x, barheight)
94
		end
95
	end
96
	
97
	local lastreadings = {energy = -1, heat = -1, fueltime = -1, runtime = -1}
98
	local lastnoproblem = true
99
	local operatingtrack = {}
100
	for i = 1, width do table.insert(operatingtrack, false) end
101
	local tickson = 0
102
	local currenttick = 0
103
	
104
	-- draw the display.
105
	t.drawdisplay = function(t)
106
		sf(0xffffff)
107
		currenttick = (currenttick % width) + 1
108
		if t.reactoron ~= operatingtrack[currenttick] then
109
			tickson = tickson + (t.reactoron and 1 or -1)
110
			operatingtrack[currenttick] = t.reactoron
111
		end
112
		t.runtime, t.reactoron = tickson / width, nil
113
		for bartype, fraction in pairs(t) do
114
			local reading = scalenumber(fraction, width)
115
			if lastreadings[bartype] ~= reading then
116
				line(bartype, lastreadings[bartype], math.floor(barheight / 2))
117
				line(bartype, reading, math.floor(barheight / 2), true)
118
				lastreadings[bartype] = reading
119
			end
120
		end
121
		local problem = isproblem()
122
		local noproblem = (problem == "No Problem")
123
		if lastnoproblem ~= noproblem then
124
			problem = string.format("Error: %s!", problem)
125
			problem = string.format("%s%s", string.rep(" ", math.floor((width - problem:len()) / 2)), problem)			
126
			sf(0xff0000)
127
			for _, bartype in pairs({"heat", "fueltime", "runtime"}) do
128
				local y = bartops[bartype] - 1
129
				gpu.fill(1, y, width - 1, 1, " ")
130
				if not noproblem then
131
					term.setCursor(1, y)
132
					term.write(problem)
133
				end
134
			end
135
			sf(0x000000)
136
			lastnoproblem = noproblem
137
		end
138
		if not noproblem then computer.beep(440, .1) end
139
	end
140
end
141
local drawdisplay, err = t.drawdisplay, t.err
142
143
local scrub = function(reason)
144
	reactor.deactivate()
145
	err(string.format("%s! Shutting down reactor.", reason))
146
end
147
148
local MaxEnergyStoredConstant, MaxHeatLevelConstant = reactor.getMaxEnergyStored(), reactor.getMaxHeatLevel()
149
150
-- and here we go.
151
computer.beep(440, .1)
152
repeat
153
	local keypress = event.pull(0, "key_down")
154
	if keypress then scrub("Keypress detected") end
155
	local status = {
156
		energy = reactor.getEnergyStored() / MaxEnergyStoredConstant,
157
		heat = reactor.getHeatLevel() / MaxHeatLevelConstant,
158
		fueltime = reactor.getFissionFuelTime(),
159
	}
160
	if status.fueltime ~= 0 then status.fueltime = 1 - reactor.getCurrentProcessTime() / status.fueltime end -- avoiding divide by zero for no fuel
161
	status.reactoron = (status.energy <= 0.5) and (status.heat <= 0.5)
162
	reactor[status.reactoron and "activate" or "deactivate"]()
163
	drawdisplay(status)
164
until false
165