Not a member of Pastebin yet?
Sign Up,
it unlocks many cool features!
- -- nanomachine_client.lua
- -- Designed by fxllenfx for fx-Studios
- -- Advanced Nanomachine Control System v2.0
- local component = require("component")
- local event = require("event")
- local term = require("term")
- local gpu = component.gpu
- local serialization = require("serialization")
- -- Config
- local SERVER_ADDR = nil
- local PORT = 2000
- local modem = component.modem
- local nano = component.nanomachines
- -- UI State
- local currentScreen = "main"
- local selectedProfile = nil
- local scrollOffset = 0
- local statusData = {}
- local profiles = {}
- local discoveryActive = false
- local discoveryProgress = 0
- -- Colors
- local COLOR_BG = 0x000000
- local COLOR_FG = 0xFFFFFF
- local COLOR_HEADER = 0x00FFFF
- local COLOR_SUCCESS = 0x00FF00
- local COLOR_WARNING = 0xFFFF00
- local COLOR_ERROR = 0xFF0000
- local COLOR_ACTIVE = 0x00FF00
- local COLOR_INACTIVE = 0x888888
- local COLOR_BUTTON = 0x0066CC
- local COLOR_SELECTED = 0xFF6600
- local COLOR_FX = 0xFF00FF
- -- Boot Animation
- local function bootAnimation()
- term.clear()
- gpu.setBackground(COLOR_BG)
- gpu.setResolution(80, 25)
- local startY = 8
- -- fx-Studios stylized text (using box drawing characters)
- gpu.setForeground(COLOR_FX)
- local logo1 = "███████╗██╗ ██╗ ███████╗████████╗██╗ ██╗██████╗ ██╗ ██████╗ ███████╗"
- local logo2 = "██╔════╝╚██╗██╔╝ ██╔════╝╚══██╔══╝██║ ██║██╔══██╗██║██╔═══██╗██╔════╝"
- local logo3 = "█████╗ ╚███╔╝ █████╗███████╗ ██║ ██║ ██║██║ ██║██║██║ ██║███████╗"
- local logo4 = "██╔══╝ ██╔██╗ ╚════╝╚════██║ ██║ ██║ ██║██║ ██║██║██║ ██║╚════██║"
- local logo5 = "██║ ██╔╝ ██╗ ███████║ ██║ ╚██████╔╝██████╔╝██║╚██████╔╝███████║"
- local logo6 = "╚═╝ ╚═╝ ╚═╝ ╚══════╝ ╚═╝ ╚═════╝ ╚═════╝ ╚═╝ ╚═════╝ ╚══════╝"
- -- Animated reveal
- gpu.set(1, startY, logo1)
- os.sleep(0.12)
- gpu.set(1, startY + 1, logo2)
- os.sleep(0.12)
- gpu.set(1, startY + 2, logo3)
- os.sleep(0.12)
- gpu.set(1, startY + 3, logo4)
- os.sleep(0.12)
- gpu.set(1, startY + 4, logo5)
- os.sleep(0.12)
- gpu.set(1, startY + 5, logo6)
- os.sleep(0.5)
- -- Subtitle
- gpu.setForeground(COLOR_HEADER)
- local subtitle = "NANOMACHINE CONTROL SYSTEM v2.0"
- gpu.set(math.floor((80 - #subtitle) / 2), startY + 7, subtitle)
- os.sleep(0.3)
- -- Credits
- gpu.setForeground(COLOR_FX)
- local credit = "» Designed by fxllenfx «"
- gpu.set(math.floor((80 - #credit) / 2), startY + 9, credit)
- os.sleep(0.6)
- -- Loading bar
- gpu.setForeground(COLOR_SUCCESS)
- local loadText = "[ Initialisiere System ]"
- gpu.set(math.floor((80 - #loadText) / 2), startY + 11, loadText)
- local barWidth = 50
- local barX = math.floor((80 - barWidth - 2) / 2)
- local barY = startY + 12
- gpu.setForeground(COLOR_INACTIVE)
- gpu.set(barX, barY, "[" .. string.rep("░", barWidth) .. "]")
- for i = 1, barWidth do
- local color = COLOR_FX
- if i < barWidth * 0.33 then
- color = 0xFF0000
- elseif i < barWidth * 0.66 then
- color = 0xFFFF00
- else
- color = COLOR_SUCCESS
- end
- gpu.setForeground(color)
- gpu.set(barX + i, barY, "█")
- os.sleep(0.03)
- end
- os.sleep(0.4)
- -- System checks
- local checks = {
- {text = "Modem erkannt", status = modem ~= nil},
- {text = "Wireless aktiv", status = modem and modem.isWireless()},
- {text = "Nanomachines verbunden", status = nano ~= nil},
- {text = "Inputs verfuegbar", status = nano and nano.getInputCount() > 0}
- }
- local checkY = startY + 14
- for i, check in ipairs(checks) do
- os.sleep(0.25)
- if check.status then
- gpu.setForeground(COLOR_SUCCESS)
- gpu.set(20, checkY + i - 1, "[✓]")
- else
- gpu.setForeground(COLOR_ERROR)
- gpu.set(20, checkY + i - 1, "[✗]")
- end
- gpu.setForeground(COLOR_FG)
- gpu.set(25, checkY + i - 1, check.text)
- end
- os.sleep(0.8)
- -- Final message with animation
- local readyMsg = ">>> SYSTEM BEREIT <<<"
- gpu.setForeground(COLOR_SUCCESS)
- for i = 1, 3 do
- gpu.set(math.floor((80 - #readyMsg) / 2), checkY + 5, readyMsg)
- os.sleep(0.3)
- gpu.set(math.floor((80 - #readyMsg) / 2), checkY + 5, string.rep(" ", #readyMsg))
- os.sleep(0.2)
- end
- gpu.set(math.floor((80 - #readyMsg) / 2), checkY + 5, readyMsg)
- os.sleep(1.2)
- end
- -- Check for nanomachines
- local function checkNanomachines()
- if not nano then
- term.clear()
- gpu.setForeground(COLOR_ERROR)
- print("╔════════════════════════════════════════╗")
- print("║ FEHLER: Keine Nanomachines gefunden! ║")
- print("╚════════════════════════════════════════╝")
- print("")
- gpu.setForeground(COLOR_FG)
- print("Stelle sicher dass:")
- print(" [1] Du Nanomachines konsumiert hast")
- print(" [2] Sie geladen sind")
- print(" [3] Du eine Wireless Network Card hast")
- print("")
- gpu.setForeground(COLOR_WARNING)
- print("Druecke eine Taste zum Beenden...")
- event.pull("key_down")
- return false
- end
- return true
- end
- -- Server Setup
- local function setupServer()
- term.clear()
- gpu.setForeground(COLOR_HEADER)
- print("╔═══════════════════════════════════════════╗")
- print("║ NANOMACHINE CLIENT SETUP ║")
- print("╚═══════════════════════════════════════════╝")
- print("")
- gpu.setForeground(COLOR_FG)
- print("Server-Adresse eingeben:")
- gpu.setForeground(COLOR_INACTIVE)
- print("(oder Enter druecken fuer Standalone-Modus)")
- print("")
- gpu.setForeground(COLOR_FG)
- io.write("> ")
- SERVER_ADDR = io.read()
- if SERVER_ADDR == "" then
- SERVER_ADDR = nil
- print("")
- gpu.setForeground(COLOR_WARNING)
- print("⚠ Standalone-Modus (kein Server)")
- gpu.setForeground(COLOR_INACTIVE)
- print("Profile werden lokal gespeichert")
- else
- print("")
- gpu.setForeground(COLOR_SUCCESS)
- print("✓ Server gesetzt: " .. SERVER_ADDR:sub(1, 8) .. "...")
- gpu.setForeground(COLOR_INACTIVE)
- print("Profile werden auf Server synchronisiert")
- end
- gpu.setForeground(COLOR_FG)
- print("")
- print("Taste druecken zum Fortfahren...")
- event.pull("key_down")
- end
- -- Communication
- local function sendCommand(command, data)
- if not SERVER_ADDR then return end
- local serialized = data and serialization.serialize(data) or nil
- modem.send(SERVER_ADDR, PORT, command, serialized)
- end
- local function requestData(command)
- if not SERVER_ADDR then return nil end
- sendCommand(command)
- local timeout = os.time() + 2
- while os.time() < timeout do
- local _, _, sender, _, _, cmd, serializedData = event.pull(0.1, "modem_message")
- if cmd and cmd == command .. "_RESPONSE" then
- if serializedData then
- local success, data = pcall(serialization.unserialize, serializedData)
- if success then
- return data
- end
- end
- return {}
- end
- end
- return nil
- end
- -- Nanomachine Control
- local function updateNanoStatus()
- if not nano then return end
- statusData.power = nano.getPowerState()
- statusData.maxPower = nano.getMaxPower()
- statusData.totalInputs = nano.getInputCount()
- -- Count active inputs
- statusData.activeInputs = 0
- for i = 1, statusData.totalInputs do
- if nano.getInput(i) then
- statusData.activeInputs = statusData.activeInputs + 1
- end
- end
- -- Get active effects
- local effects = nano.getActiveEffects()
- statusData.activeEffects = effects and #effects or 0
- statusData.effects = effects or {}
- statusData.lastUpdate = os.time()
- end
- local function setInput(inputId, active)
- if not nano or inputId < 1 or inputId > statusData.totalInputs then
- return false
- end
- nano.setInput(inputId, active)
- return true
- end
- local function toggleInput(inputId)
- if not nano then return false end
- local currentState = nano.getInput(inputId)
- return setInput(inputId, not currentState)
- end
- local function disableAllInputs()
- if not nano then return end
- for i = 1, statusData.totalInputs do
- setInput(i, false)
- end
- statusData.currentProfile = nil
- end
- local function getCurrentInputState()
- if not nano then return {} end
- local inputs = {}
- for i = 1, statusData.totalInputs do
- if nano.getInput(i) then
- table.insert(inputs, i)
- end
- end
- return inputs
- end
- local function applyInputState(inputs)
- if not nano then return end
- -- Disable all first
- disableAllInputs()
- -- Enable specified inputs
- for _, inputId in ipairs(inputs) do
- setInput(inputId, true)
- end
- end
- -- Profile Management
- local function loadProfiles()
- if SERVER_ADDR then
- local serverProfiles = requestData("GET_PROFILES")
- if serverProfiles then
- profiles = serverProfiles
- return
- end
- end
- -- Default profiles if no server or server unavailable
- if #profiles == 0 then
- profiles = {
- {name = "Safe", description = "Nur Regeneration", inputs = {}},
- {name = "Combat", description = "Kampf-Modus", inputs = {}},
- {name = "Mining", description = "Bergbau-Modus", inputs = {}}
- }
- end
- end
- local function saveCurrentAsProfile(name, description)
- local inputs = getCurrentInputState()
- local profile = {
- name = name,
- description = description or "Eigenes Profil",
- inputs = inputs,
- created = os.time()
- }
- table.insert(profiles, profile)
- -- Send to server if connected
- if SERVER_ADDR then
- sendCommand("SAVE_PROFILE", profile)
- end
- return true
- end
- local function activateProfile(profileName)
- local profile = nil
- for _, p in ipairs(profiles) do
- if p.name == profileName then
- profile = p
- break
- end
- end
- if not profile then
- return false
- end
- applyInputState(profile.inputs)
- statusData.currentProfile = profileName
- return true
- end
- -- Draw Functions
- local function drawHeader(title)
- gpu.setBackground(COLOR_BG)
- gpu.setForeground(COLOR_FX)
- gpu.fill(1, 1, 80, 3, " ")
- local fx = "fx-Studios"
- gpu.set(2, 1, fx)
- gpu.setForeground(COLOR_HEADER)
- local titleText = "╔═══ " .. title .. " ═══╗"
- gpu.set(math.floor((80 - #titleText) / 2), 2, titleText)
- gpu.setForeground(COLOR_INACTIVE)
- gpu.set(70, 1, "v2.0")
- end
- local function drawButton(x, y, text, width, active)
- local bg = active and COLOR_SELECTED or COLOR_BUTTON
- gpu.setBackground(bg)
- gpu.setForeground(COLOR_FG)
- local padding = math.floor((width - #text) / 2)
- local buttonText = string.rep(" ", padding) .. text .. string.rep(" ", width - padding - #text)
- gpu.set(x, y, buttonText)
- gpu.setBackground(COLOR_BG)
- end
- local function drawStatusBar(y, label, value, maxValue, color)
- gpu.setForeground(COLOR_FG)
- gpu.set(2, y, label .. ":")
- local barWidth = 40
- local barX = 25
- local percentage = maxValue > 0 and (value / maxValue) or 0
- local filled = math.floor(barWidth * percentage)
- gpu.setForeground(color)
- gpu.set(barX, y, "[" .. string.rep("█", filled) .. string.rep("░", barWidth - filled) .. "]")
- gpu.setForeground(COLOR_FG)
- gpu.set(barX + barWidth + 3, y, string.format("%d/%d (%.1f%%)", value, maxValue, percentage * 100))
- end
- -- Main Dashboard Screen
- local function drawMainScreen()
- term.clear()
- drawHeader("NANOMACHINE CONTROL CENTER")
- gpu.setForeground(COLOR_FG)
- -- Status Section
- gpu.setForeground(COLOR_HEADER)
- gpu.set(2, 5, "═══ SYSTEM STATUS ═══")
- gpu.setForeground(COLOR_FG)
- drawStatusBar(7, "Power", statusData.power or 0, statusData.maxPower or 100, COLOR_SUCCESS)
- gpu.set(2, 9, "Aktive Inputs: " .. (statusData.activeInputs or 0) .. "/" .. (statusData.totalInputs or 0))
- gpu.set(2, 10, "Aktive Effekte: " .. (statusData.activeEffects or 0))
- -- Display active effects
- if statusData.effects and #statusData.effects > 0 then
- gpu.setForeground(COLOR_SUCCESS)
- local effectText = table.concat(statusData.effects, ", ")
- if #effectText > 75 then
- effectText = effectText:sub(1, 72) .. "..."
- end
- gpu.set(2, 11, "Effekte: " .. effectText)
- gpu.setForeground(COLOR_FG)
- end
- -- Current Profile
- gpu.setForeground(COLOR_HEADER)
- gpu.set(2, 13, "═══ AKTUELLES PROFIL ═══")
- gpu.setForeground(COLOR_FG)
- if statusData.currentProfile then
- gpu.setForeground(COLOR_SUCCESS)
- gpu.set(2, 14, "● " .. statusData.currentProfile)
- else
- gpu.setForeground(COLOR_INACTIVE)
- gpu.set(2, 14, "○ Kein Profil aktiv")
- end
- -- Server Status
- gpu.setForeground(COLOR_HEADER)
- gpu.set(45, 13, "═══ SERVER ═══")
- gpu.setForeground(COLOR_FG)
- if SERVER_ADDR then
- gpu.setForeground(COLOR_SUCCESS)
- gpu.set(45, 14, "● Verbunden")
- gpu.setForeground(COLOR_INACTIVE)
- gpu.set(45, 15, SERVER_ADDR:sub(1, 16) .. "...")
- else
- gpu.setForeground(COLOR_WARNING)
- gpu.set(45, 14, "○ Standalone")
- end
- gpu.setForeground(COLOR_FG)
- -- Navigation Buttons
- gpu.setForeground(COLOR_HEADER)
- gpu.set(2, 18, "═══ SCHNELLZUGRIFF ═══")
- drawButton(2, 20, "1: Profile", 15, false)
- drawButton(19, 20, "2: Manuell", 15, false)
- drawButton(36, 20, "3: Discovery", 15, false)
- drawButton(53, 20, "4: Effekte", 15, false)
- drawButton(2, 22, "E: Notaus", 15, false)
- drawButton(19, 22, "S: Speichern", 17, false)
- drawButton(38, 22, "R: Refresh", 15, false)
- -- Footer
- gpu.setForeground(COLOR_INACTIVE)
- gpu.set(2, 24, "Q: Beenden")
- gpu.setForeground(COLOR_FX)
- gpu.set(60, 24, "by fxllenfx")
- end
- -- Profile Selection Screen
- local function drawProfileScreen()
- term.clear()
- drawHeader("PROFILE")
- gpu.setForeground(COLOR_FG)
- if not profiles or #profiles == 0 then
- gpu.setForeground(COLOR_WARNING)
- gpu.set(2, 5, "Keine Profile vorhanden")
- gpu.setForeground(COLOR_FG)
- gpu.set(2, 7, "Druecke S um aktuellen Status als Profil zu speichern")
- gpu.set(2, 8, "Druecke B um zurueck zu gehen")
- return
- end
- gpu.setForeground(COLOR_HEADER)
- gpu.set(2, 5, "═══ VERFUEGBARE PROFILE ═══")
- gpu.setForeground(COLOR_FG)
- for i, profile in ipairs(profiles) do
- if i > scrollOffset and i <= scrollOffset + 12 then
- local y = 7 + (i - scrollOffset - 1)
- local isActive = statusData.currentProfile == profile.name
- if isActive then
- gpu.setForeground(COLOR_SUCCESS)
- gpu.set(2, y, "▶ ")
- else
- gpu.setForeground(COLOR_INACTIVE)
- gpu.set(2, y, " ")
- end
- gpu.setForeground(COLOR_FG)
- gpu.set(5, y, string.format("[%d] %s", i, profile.name))
- if profile.description then
- gpu.setForeground(COLOR_INACTIVE)
- gpu.set(30, y, "- " .. profile.description)
- end
- gpu.setForeground(COLOR_INACTIVE)
- local inputCount = profile.inputs and #profile.inputs or 0
- gpu.set(65, y, "(" .. inputCount .. " inputs)")
- end
- end
- -- Instructions
- gpu.setForeground(COLOR_HEADER)
- gpu.set(2, 21, "═══ STEUERUNG ═══")
- gpu.setForeground(COLOR_FG)
- gpu.set(2, 22, "Zahl: Profil aktivieren")
- gpu.set(2, 23, "B: Zurueck")
- end
- -- Manual Control Screen
- local function drawManualScreen()
- term.clear()
- drawHeader("MANUELLE STEUERUNG")
- gpu.setForeground(COLOR_FG)
- if not statusData.totalInputs or statusData.totalInputs == 0 then
- gpu.setForeground(COLOR_WARNING)
- gpu.set(2, 5, "Keine Input-Daten verfuegbar")
- return
- end
- gpu.setForeground(COLOR_HEADER)
- gpu.set(2, 5, "═══ INPUT KANAELE ═══")
- gpu.setForeground(COLOR_FG)
- local cols = 4
- local maxPerScreen = 40
- local row = 0
- for i = 1, math.min(statusData.totalInputs, maxPerScreen) do
- local isActive = nano.getInput(i)
- local col = (i - 1) % cols
- local x = 2 + (col * 19)
- local y = 7 + row
- if col == 0 and i > 1 then
- row = row + 1
- end
- local status = isActive and " ON" or "OFF"
- local color = isActive and COLOR_SUCCESS or COLOR_INACTIVE
- gpu.setForeground(color)
- gpu.set(x, y, string.format("[%2d] %s", i, status))
- end
- -- Instructions
- gpu.setForeground(COLOR_HEADER)
- gpu.set(2, 20, "═══ STEUERUNG ═══")
- gpu.setForeground(COLOR_FG)
- gpu.set(2, 21, "Zahl: Input umschalten")
- gpu.set(2, 22, "X: Alle deaktivieren")
- gpu.set(2, 23, "B: Zurueck")
- end
- -- Discovery Screen
- local function drawDiscoveryScreen()
- term.clear()
- drawHeader("EFFEKT DISCOVERY")
- gpu.setForeground(COLOR_FG)
- gpu.setForeground(COLOR_HEADER)
- gpu.set(2, 5, "═══ DISCOVERY MODUS ═══")
- gpu.setForeground(COLOR_FG)
- if discoveryActive then
- gpu.setForeground(COLOR_SUCCESS)
- gpu.set(2, 7, "● Discovery laeuft...")
- gpu.setForeground(COLOR_FG)
- gpu.set(2, 9, "Fortschritt: " .. discoveryProgress .. "%")
- else
- gpu.setForeground(COLOR_INACTIVE)
- gpu.set(2, 7, "○ Discovery inaktiv")
- end
- gpu.setForeground(COLOR_HEADER)
- gpu.set(2, 12, "═══ STEUERUNG ═══")
- gpu.setForeground(COLOR_FG)
- gpu.set(2, 13, "S: Discovery starten")
- gpu.set(2, 14, "P: Discovery pausieren")
- gpu.set(2, 15, "R: Discovery zuruecksetzen")
- gpu.set(2, 16, "B: Zurueck")
- gpu.setForeground(COLOR_WARNING)
- gpu.set(2, 19, "⚠ Warnung: Discovery testet systematisch alle")
- gpu.set(2, 20, " Input-Kombinationen. Dies kann mehrere Minuten dauern.")
- end
- -- Effects Screen
- local function drawEffectsScreen()
- term.clear()
- drawHeader("AKTIVE EFFEKTE")
- gpu.setForeground(COLOR_HEADER)
- gpu.set(2, 5, "═══ EFFEKT DETAILS ═══")
- gpu.setForeground(COLOR_FG)
- if statusData.effects and #statusData.effects > 0 then
- for i, effect in ipairs(statusData.effects) do
- local y = 7 + i - 1
- if y < 20 then
- gpu.setForeground(COLOR_SUCCESS)
- gpu.set(2, y, "● " .. effect)
- end
- end
- else
- gpu.setForeground(COLOR_INACTIVE)
- gpu.set(2, 7, "Keine aktiven Effekte")
- end
- gpu.setForeground(COLOR_HEADER)
- gpu.set(2, 21, "═══ STEUERUNG ═══")
- gpu.setForeground(COLOR_FG)
- gpu.set(2, 22, "B: Zurueck")
- end
- -- Input Handling
- local function handleMainInput(char)
- if char == string.byte("1") then
- currentScreen = "profiles"
- elseif char == string.byte("2") then
- currentScreen = "manual"
- elseif char == string.byte("3") then
- currentScreen = "discovery"
- elseif char == string.byte("4") then
- currentScreen = "effects"
- elseif char == string.byte("e") or char == string.byte("E") then
- disableAllInputs()
- updateNanoStatus()
- elseif char == string.byte("s") or char == string.byte("S") then
- term.clear()
- print("Profilname eingeben:")
- local name = io.read()
- if name and name ~= "" then
- print("Beschreibung (optional):")
- local desc = io.read()
- saveCurrentAsProfile(name, desc ~= "" and desc or nil)
- loadProfiles()
- end
- elseif char == string.byte("r") or char == string.byte("R") then
- updateNanoStatus()
- if SERVER_ADDR then
- loadProfiles()
- end
- elseif char == string.byte("q") or char == string.byte("Q") then
- return false
- end
- return true
- end
- local function handleProfileInput(char)
- if char == string.byte("b") or char == string.byte("B") then
- currentScreen = "main"
- elseif char >= string.byte("0") and char <= string.byte("9") then
- local num = char - string.byte("0")
- if profiles[num] then
- activateProfile(profiles[num].name)
- updateNanoStatus()
- end
- end
- end
- local function handleManualInput(char)
- if char == string.byte("b") or char == string.byte("B") then
- currentScreen = "main"
- elseif char == string.byte("x") or char == string.byte("X") then
- disableAllInputs()
- updateNanoStatus()
- elseif char >= string.byte("0") and char <= string.byte("9") then
- local num = char - string.byte("0")
- if num <= statusData.totalInputs then
- toggleInput(num)
- updateNanoStatus()
- end
- end
- end
- local function handleDiscoveryInput(char)
- if char == string.byte("b") or char == string.byte("B") then
- currentScreen = "main"
- elseif char == string.byte("s") or char == string.byte("S") then
- discoveryActive = true
- if SERVER_ADDR then
- sendCommand("START_DISCOVERY")
- end
- elseif char == string.byte("p") or char == string.byte("P") then
- discoveryActive = false
- if SERVER_ADDR then
- sendCommand("PAUSE_DISCOVERY")
- end
- elseif char == string.byte("r") or char == string.byte("R") then
- discoveryProgress = 0
- discoveryActive = true
- if SERVER_ADDR then
- sendCommand("RESET_DISCOVERY")
- end
Advertisement
Add Comment
Please, Sign In to add comment