asteroidsteam icon

Extreme Reactors Control Program

asteroidsteam | PRO | 07/13/22 12:08:40 AM UTC (Edited) | 0 ⭐ | 562 👁️ | Never ⏰ | []
Lua |

6.25 KB

|

None

|

0 👍

/

0 👎

local reactor = peripheral.wrap("BigReactors-Reactor_0")
local monitor = peripheral.wrap("monitor_0")
rednet.open("top")
 
controllers = {}
 
controllers[1] = true -- Allow computer ID#1 to access reactor control
 
local target_power = 5000 -- RF/Tick
local control_rod_level = 50
 
function clamp(val, min, max) 
    if val > max then
        return max
    elseif val < min then
        return min
    else
        return val
    end
end
 
function drawBar(x, y, size, perc)
    local bgColor = monitor.getBackgroundColor()
    local ox, oy = monitor.getCursorPos()
 
    monitor.setCursorPos(x, y)
    monitor.setBackgroundColor(colors.green)
 
    local percGreen = clamp(math.floor(perc * size), 0, size)
    local percGray = clamp(size - percGreen, 0, size - percGreen)
    if percGray < 0 then
        percGray = 0
    end
 
    for i = percGreen,1,-1 do
        monitor.write(" ")
    end
    monitor.setBackgroundColor(colors.lightGray)
    for i = percGray,1,-1 do
        monitor.write(" ")
    end
 
    monitor.setBackgroundColor(bgColor)
    monitor.setCursorPos(ox, oy)
end
 
function getControlRodDiff(RFDiff)
    if RFDiff > 10000 then
        return 5
    elseif RFDiff > 5000 then
        return 3
    elseif RFDiff > 1000 then
        return 1
    elseif RFDiff > 500 then
        return 0.5
    elseif RFDiff > 100 then
        return 0.1
    else
        return 0.05
    end
end
 
function formatRF(rf)
    if rf >= 1000000 then
        return round(rf/1000000, 2) .. " MiRF"
    elseif rf >= 1000 then
        return round(rf/1000, 2) .. " KiRF"
    else 
        return math.floor(rf) .. " RF"
    end
end
 
function round(num, numDecimalPlaces)
    local mult = 10^(numDecimalPlaces or 0)
    return math.floor(num * mult + 0.5) / mult
end
 
function drawBoxWithCenteredText(x,y,w,h,text,color)
    local ox,oy = monitor.getCursorPos()
    local bgColor = monitor.getBackgroundColor()
 
    monitor.setBackgroundColor(color)
    for cy=1,h,1 do
        for cx=1,w,1 do
            monitor.setCursorPos(x+cx,y+cy)
            monitor.write(" ")
        end
    end
 
    local cx = math.floor(w / 2 + x - string.len(text) / 2 + 1)
    local cy = math.floor(h / 2 + y + 1)
 
    monitor.setCursorPos(cx, cy)
    monitor.write(text)
 
    monitor.setBackgroundColor(bgColor)
    monitor.setCursorPos(ox, oy)
end
 
monitor.setBackgroundColor(colors.black)
monitor.clear()
local mw, mh = monitor.getSize()
local reactor_enabled = false
 
local buttons = {}
 
function renderButtons()
    for i = 1, #buttons do
        local button = buttons[i]
        if not reactor_enabled then
            if button.drod then
                drawBoxWithCenteredText(button.x,button.y,button.w,button.h,button.text,button.color)
            end
        else
            drawBoxWithCenteredText(button.x,button.y,button.w,button.h,button.text,button.color)
        end
    end
end
 
function inBounds(n, min, max)
    return n <= max and n >= min
end
 
function addButton(x,y,w,h,text,color,doRenderOnDisable, executor)
    local button = {
        x = x,
        y = y,
        w = w,
        h = h,
        text = text,
        color = color,
        drod = doRenderOnDisable,
        executor = executor
    }
    buttons[#buttons+1] = button
end
 
function startReactor(btn)
    monitor.clear()
    reactor_enabled = true
end
 
function stopReactor(btn)
    monitor.clear()
    reactor_enabled = false
end
 
function changeTargetPower(btn)
    local num = btn.text:sub(2)
    num = tonumber(num)
    if btn.color == colours.red then
        num = num * -1
    end
 
    target_power = target_power + num
end
 
addButton(2,mh - 8,15,5,"SHUT DOWN",colours.red, true, stopReactor)
addButton(19,mh - 8,15,5,"START",colours.green, true, startReactor)
 
addButton(2, 9, 7, 3, "-10", colours.red, false, changeTargetPower)
addButton(11, 9, 7, 3, "-100", colours.red, false, changeTargetPower)
addButton(20, 9, 7, 3, "-1000", colours.red, false, changeTargetPower)
 
addButton(29, 9, 7, 3, "+1000", colours.green, false, changeTargetPower)
addButton(38, 9, 7, 3, "+100", colours.green, false, changeTargetPower)
addButton(47, 9, 7, 3, "+10", colours.green, false, changeTargetPower)
local cur_power_gen = 0
 
function controlReactor()
    while true do
        cur_power_gen = reactor.getEnergyProducedLastTick()
        reactor.setActive(reactor_enabled)
 
        if cur_power_gen ~= 0 and reactor_enabled then
            local diff = getControlRodDiff(math.abs(cur_power_gen - target_power))
 
            if cur_power_gen > target_power then
                control_rod_level = clamp(control_rod_level + diff, 0, 100)
            elseif cur_power_gen < target_power then
                control_rod_level = clamp(control_rod_level - diff, 0, 100)
            end
 
            reactor.setAllControlRodLevels(control_rod_level)
 
 
            monitor.setCursorPos(2,2)
            monitor.write("Control Rod Level: ")
            drawBar(22,2,40,control_rod_level/100)
            monitor.setCursorPos(22,3)
            monitor.write(math.floor(control_rod_level) .. "\%  ")
 
            monitor.setCursorPos(2,5)
            monitor.write("Power Generation: ")
            drawBar(22,5,40,cur_power_gen/target_power)
            monitor.setCursorPos(22,6)
            monitor.write(formatRF(cur_power_gen) .. "/t        ")
 
            monitor.setCursorPos(2,8)
            monitor.write("Target power generation: " .. formatRF(target_power) .. "/t")
        end
        if not reactor_enabled then
            monitor.setCursorPos(2,2)
            monitor.write("Reactor is offline")
        end
        renderButtons()
        sleep(0.1)
    end
end
 
function pullEvents()
    while true do
        event, side, x, y = os.pullEvent("monitor_touch")
        for i=1, #buttons do
            local button = buttons[i]
            if inBounds(x, button.x, button.x + button.w) and inBounds(y, button.y, button.y + button.h) then
                button.executor(button)
                break
            end
        end
    end
end
 
function waitForRednetCommand()
    while true do
        local senderId, command, protocol = rednet.receive("reactor_control")
        command = textutils.unserialize(command)
 
        if controllers[senderId] ~= nil and controllers[senderId] then
            print("Received rednet command from " .. senderId)
            print(command)
            local reactorStatus = {
                control_rod_level = control_rod_level,
                cur_power_gen = cur_power_gen,
                target_power = target_power,
                reactor_enabled = reactor_enabled,
                command_executed = false
            }
 
            for i=1, #buttons do
                local button = buttons[i]
                if command.button == button.text then
                    button.executor(button)
                    reactorStatus.command_executed = true
                    break
                end
            end
 
            rednet.send(senderId, textutils.serialize(reactorStatus), "reactor_response")
        end
    end
end
 
parallel.waitForAny(pullEvents, controlReactor, waitForRednetCommand)

Comments