CCCPaste

Reactor control server V2

local configPath = "config"

-- ========= TROVA PERIFERICHE =========
local function findPeripheral(t)
    for _, side in ipairs(rs.getSides()) do
        if peripheral.isPresent(side) and peripheral.getType(side) == t then
            return peripheral.wrap(side), side
        end
    end
    return nil
end

-- ========= CONFIGURAZIONE =========
local function loadConfig()
    if not fs.exists(configPath) then return nil end
    local f = fs.open(configPath,"r")
    local data=f.readAll() f.close()
    local func=loadstring(data)
    if func then return func() else error("Errore nel config") end
end

term.setTextColor(colors.yellow)
print("Avvio centrale di controllo...")
sleep(0.3)
local config = loadConfig()

if not config then
    term.setTextColor(colors.white)
    print("Configurazione non trovata. Creazione guidata...\n")
    local validColors = {}
    for k,v in pairs(colors) do validColors[k]=v end
    local reactors = {}
    while true do
        write("Nome reattore: ") local name = read()
        local id
        repeat write("ID rednet: ") id = tonumber(read()) until id
        local color
        repeat write("Colore principale (white, blue, ...): ") color = read() until validColors[color]
        local scramColor
        repeat write("Colore reset SCRAM: ") scramColor = read() until validColors[scramColor]

        table.insert(reactors,{name=name,id=id,color=color,scram_color=scramColor})
        if #reactors >= 8 then break end
        write("Altro reattore? (s/n): ") if read():lower()~="s" then break end
    end
    config = {reactors=reactors, update_interval=2}
    local f = fs.open(configPath,"w")
    f.write("return "..textutils.serialize(config))
    f.close()
end

if type(config.update_interval)~="number" then config.update_interval=2 end

term.setTextColor(colors.cyan)
print("\n[ Inizializzazione periferiche ]")
sleep(0.3)

local modem, modemSide = findPeripheral("modem")
if not modem then error("Nessun modem trovato!") end
rednet.open(modemSide)
term.setTextColor(colors.lime)
print("✔ Modem su "..modemSide)
sleep(0.2)

local mon, monSide = findPeripheral("monitor")
if not mon then error("Nessun monitor trovato!") end
mon.setBackgroundColor(colors.black)
mon.setTextColor(colors.white)
mon.clear()
local monitorSizeX, monitorSizeY = mon.getSize()
term.setTextColor(colors.lime)
print("✔ Monitor su "..monSide)
sleep(0.5)

term.setTextColor(colors.yellow)
print("Inizializzazione completata.")
sleep(1)
term.clear()
term.setCursorPos(1,1)

-- ========= VARIABILI =========
local reactors = {}
local previousStates = {}
local scramActive = false
local reactorsInSCRAM = {} -- mappa id -> true/false

-- ========= UTILITY =========
local function colorByTemp(p)
    if p < 60 then return colors.green
    elseif p < 85 then return colors.orange
    else return colors.red end
end

local function drawBar(x,y,w,perc,color)
    local filled = math.floor(w*perc/100)
    mon.setCursorPos(x,y)
    mon.setBackgroundColor(colors.gray)
    mon.write(string.rep(" ",w))
    mon.setCursorPos(x,y)
    mon.setBackgroundColor(color)
    mon.write(string.rep(" ",filled))
    mon.setBackgroundColor(colors.black)
end

-- ========= RACCOLTA DATI =========
local function getReactorsInfo(config)
    local reactors = {}
    for _,r in ipairs(config.reactors) do
        term.setTextColor(colors.lightBlue)
        print("Richiesta dati a "..r.name.." (ID "..r.id..")...")
        local command = textutils.serialize({command = "reactor_info"})
        rednet.send(r.id, command)
        local start=os.clock()
        local sender,msg
        repeat
            sender,msgTmp=rednet.receive(5)
            if msgTmp then msg=textutils.unserialize(msgTmp) end
        until sender==r.id or os.clock()-start>5

        if sender==r.id and type(msg)=="table" and msg.type=="info" then
            term.setTextColor(colors.lime)
            print("Dati ricevuti da "..r.name)
            reactors[r.id]=msg.data
        else
            term.setTextColor(colors.red)
            print("Nessuna risposta da "..r.name)
            reactors[r.id]=nil
        end
    end
    return reactors
end

-- ========= UI =========
local function drawUI()
    mon.setBackgroundColor(colors.black)
    mon.setTextColor(colors.white)
    mon.clear()
    mon.setCursorPos((monitorSizeX/2)-12,1)
    mon.write("=== CENTRALE NUCLEARE ===")
    mon.setCursorPos((monitorSizeX/2)-9,2)
    mon.write("Aggiornato: " .. textutils.formatTime(os.time(), true))
    local y=4
    local x=2
    local reactorCount = 0
    local reactorPerPage = math.floor(((monitorSizeY-3)/6)+0.5)

    for _,r in ipairs(config.reactors) do
        reactorCount = reactorCount+1
        local info = reactors[r.id]
        mon.setCursorPos(x,y)
        mon.setTextColor(colors.cyan)
        mon.write(r.name)
        y=y+1
        if info then
            mon.setCursorPos(x+15,y-1)
            local perc = math.floor((info.temp/info.maxHeat)*100)
            if info.SCRAMState then
                mon.setTextColor(colors.red) mon.write("STATO: SCRAM")
            elseif info.active then
                mon.setTextColor(colors.lime) mon.write("STATO: ATTIVO")
            else
                mon.setTextColor(colors.orange) mon.write("STATO: SPENTO")
            end
            mon.setTextColor(colors.yellow)
            mon.setCursorPos(x+2,y)
            mon.write(string.format("MaxOut:%d | Out:%d", info.maxOutput, info.effectiveOutput))
            y=y+1
            mon.setCursorPos(x+2,y)
            mon.write(string.format("Temp:%d/%d  (%d%%)", info.temp, info.maxHeat, perc))
            y=y+1
            drawBar(x+2,y,22,perc+30,colorByTemp(perc))
            y=y+1
        else
            mon.setTextColor(colors.red)
            mon.write("  Nessuna risposta")
            y=y+1
        end
        y=y+2
        if reactorCount % reactorPerPage == 0 then
            mon.setTextColor(colors.white)
            for i=4,monitorSizeY do
                mon.setCursorPos(monitorSizeX/2,i)
                mon.write("|")
            end
            x=x+(monitorSizeX/2)
            y=4
        end
    end
end

-- ========= CONTROLLO NORMALE =========
local function checkInput()
    local activeColors = rs.getBundledInput("right")
    for _,r in ipairs(config.reactors) do
        local isActive = colors.test(activeColors, colors[r.color])
        if previousStates[r.id] ~= isActive then
            local command = textutils.serialize({command="reactor_control", newState=isActive})
            rednet.send(r.id, command)
            previousStates[r.id] = isActive
        end
    end
end

-- ========= CONTROLLO SCRAM =========
local function checkSCRAM()
    local foundSCRAM = false
    for _,r in ipairs(config.reactors) do
        local info = reactors[r.id]
        if info and info.SCRAMState then
            reactorsInSCRAM[r.id] = true
            foundSCRAM = true
        else
            reactorsInSCRAM[r.id] = false
        end
    end

    if foundSCRAM and not scramActive then
        term.setTextColor(colors.red)
        print("[SCRAM] Attivato! Impulso su uscita.")
        rs.setBundledOutput("back", colors.orange)
        sleep(1)
        rs.setBundledOutput("back", 0)
        scramActive = true
    elseif not foundSCRAM and scramActive then
        term.setTextColor(colors.lime)
        print("[SCRAM] Tutti i reattori OK. SCRAM disattivo.")
        scramActive = false
    end
end

-- ========= CONTROLLO INPUT SCRAM =========
local function checkInputSCRAM()
    if not scramActive then return end
    local activeColors = rs.getBundledInput("right")
    for _,r in ipairs(config.reactors) do
        if reactorsInSCRAM[r.id] then
            local trigger = colors.test(activeColors, colors[r.scram_color])
            if trigger then
                term.setTextColor(colors.yellow)
                print("[SCRAM RESET] Ricevuto segnale reset da "..r.name)
                rs.setBundledOutput("back", 0)
                rednet.send(r.id, textutils.serialize({command="reset_SCRAM"}))
                reactorsInSCRAM[r.id] = false
            end
        end
    end
end

-- ========= LOOP PRINCIPALE =========
while true do
    reactors = getReactorsInfo(config)
    checkSCRAM()
    checkInputSCRAM()
    checkInput()
    drawUI()
    term.setTextColor(colors.gray)
    print("Aggiornamento completato.\n")
    sleep(config.update_interval)
end