local Players = game:GetService("Players") local HttpService = game:GetService("HttpService") local RunService = game:GetService("RunService") local TextService = game:GetService("TextService") local player = Players.LocalPlayer local char = player.Character or player.CharacterAdded:Wait() local hrp = char:WaitForChild("HumanoidRootPart") local ex = (getgenv and getgenv()) or _G if ex.OCSimStop then pcall(ex.OCSimStop) end local TOTAL_MEM = 2097152 local T = { panel = Color3.fromRGB(24, 26, 38), btn = Color3.fromRGB(44, 48, 68), accent = Color3.fromRGB(88, 166, 255), ok = Color3.fromRGB(70, 200, 110), bad = Color3.fromRGB(225, 80, 80), text = Color3.fromRGB(235, 238, 245), } local function guiParent() local ok, h = pcall(function() return gethui() end) if ok and typeof(h) == "Instance" then return h end return player:WaitForChild("PlayerGui") end local old = workspace:FindFirstChild("OC_Sim") if old then old:Destroy() end local oldg = guiParent():FindFirstChild("OC_SimGui") if oldg then oldg:Destroy() end local function mk(class, props, parent) local o = Instance.new(class) for k, v in pairs(props) do o[k] = v end o.Parent = parent return o end local function guid() return HttpService:GenerateGUID(false):lower() end local model = mk("Model", {Name = "OC_Sim"}, workspace) local groundY = hrp.Position.Y - 3 local lv, rv = hrp.CFrame.LookVector, hrp.CFrame.RightVector local flat = Vector3.new(lv.X, 0, lv.Z).Unit local rightV = Vector3.new(rv.X, 0, rv.Z).Unit local base = Vector3.new(hrp.Position.X, groundY, hrp.Position.Z) + flat * 10 local function facing(pos) return CFrame.new(pos, Vector3.new(hrp.Position.X, pos.Y, hrp.Position.Z)) end local function part(name, size, cf, color, mat) return mk("Part", { Name = name, Size = size, CFrame = cf, Color = color, Material = mat or Enum.Material.SmoothPlastic, Anchored = true, TopSurface = Enum.SurfaceType.Smooth, BottomSurface = Enum.SurfaceType.Smooth, }, model) end local caseCF = facing(base + rightV * 5 + Vector3.new(0, 1.5, 0)) local case = part("Case", Vector3.new(3, 3, 3), caseCF, Color3.fromRGB(30, 31, 38)) part("CaseTop", Vector3.new(3.05, 0.15, 3.05), caseCF * CFrame.new(0, 1.5, 0), Color3.fromRGB(88, 166, 255), Enum.Material.Metal) local led = part("Led", Vector3.new(0.7, 0.3, 0.1), caseCF * CFrame.new(-0.7, 0.9, -1.52), Color3.fromRGB(40, 40, 40), Enum.Material.Neon) for i = 0, 3 do part(`Vent{i}`, Vector3.new(1.6, 0.15, 0.1), caseCF * CFrame.new(0.2, 0.2 - i * 0.35, -1.52), Color3.fromRGB(5, 5, 5)) end local cd = mk("ClickDetector", {MaxActivationDistance = 40}, case) local deskCF = facing(base + Vector3.new(0, 0.05, 0) + rightV * 1.2) part("Desk", Vector3.new(11, 0.2, 4.5), deskCF, Color3.fromRGB(70, 52, 40), Enum.Material.Wood) local monPos = base - rightV * 2.5 local monCF = facing(monPos + Vector3.new(0, 3.9, 0)) part("Bezel", Vector3.new(9, 5.6, 0.5), monCF, Color3.fromRGB(22, 23, 30)) local display = part("Display", Vector3.new(8.4, 5, 0.1), monCF * CFrame.new(0, 0, -0.28), Color3.new(0, 0, 0)) part("Stand", Vector3.new(1, 1.1, 1), facing(monPos + Vector3.new(0, 0.7, 0)), Color3.fromRGB(40, 42, 52)) part("StandBase", Vector3.new(3, 0.2, 2), facing(monPos + Vector3.new(0, 0.3, 0)), Color3.fromRGB(40, 42, 52)) part("Keyboard", Vector3.new(4.2, 0.15, 1.3), facing(monPos + flat * -1 + Vector3.new(0, 0.38, 0)) , Color3.fromRGB(50, 52, 64)) local FONT, TSIZE = Enum.Font.Code, 16 local CW, CH = 9, 16 pcall(function() local s = TextService:GetTextSize("MMMMMMMMMM", TSIZE, FONT, Vector2.new(10000, 10000)) CW, CH = s.X / 10, s.Y end) local PADX, PADY = 14, 10 local MAXW, MAXH = math.floor(592 / CW), math.floor(360 / CH) local scr = {W = MAXW, H = MAXH, ch = {}, fg = {}, bg = {}, fgc = 0xFFFFFF, bgc = 0, on = false} local dirty, views = {}, {} local function resetBuf(w, h) scr.W, scr.H = w, h scr.ch, scr.fg, scr.bg = {}, {}, {} for i = 1, w * h do scr.ch[i], scr.fg[i], scr.bg[i] = " ", 0xFFFFFF, 0 end for y = 1, MAXH do dirty[y] = true end end resetBuf(MAXW, MAXH) local function clampi(x) return math.floor(tonumber(x) or 0) end local function rgb(c) return Color3.fromRGB(math.floor(c / 65536) % 256, math.floor(c / 256) % 256, c % 256) end local esc = {["&"] = "&", ["<"] = "<", [">"] = ">", ['"'] = """, ["'"] = "'"} local function screenFrame(parent) local outer = mk("Frame", {Size = UDim2.fromScale(1, 1), BackgroundColor3 = Color3.fromRGB(34, 36, 48), BorderSizePixel = 0}, parent) mk("UICorner", {CornerRadius = UDim.new(0, 26)}, outer) local bg = mk("Frame", {Position = UDim2.fromOffset(10, 10), Size = UDim2.new(1, -20, 1, -20), BackgroundColor3 = Color3.new(0, 0, 0), BorderSizePixel = 0}, outer) mk("UICorner", {CornerRadius = UDim.new(0, 18)}, bg) return outer, bg end local function buildView(bg, isActive) local v = {lbl = {}, bgh = {}, active = isActive} for y = 1, MAXH do local pos = UDim2.fromOffset(PADX, PADY + (y - 1) * CH) v.bgh[y] = mk("Frame", {BackgroundTransparency = 1, Position = pos, Size = UDim2.fromOffset(MAXW * CW, CH), ZIndex = 1}, bg) v.lbl[y] = mk("TextLabel", { BackgroundTransparency = 1, Position = pos, Size = UDim2.fromOffset(MAXW * CW + 24, CH + 2), Font = FONT, TextSize = TSIZE, RichText = true, TextColor3 = Color3.new(1, 1, 1), TextXAlignment = Enum.TextXAlignment.Left, TextYAlignment = Enum.TextYAlignment.Top, Text = "", ZIndex = 2, }, bg) end table.insert(views, v) return v end local function rowData(y) if not scr.on or y > scr.H then return "", {} end local W, b0 = scr.W, (y - 1) * scr.W local parts, bgs, x = {}, {}, 1 while x <= W do local f, b = scr.fg[b0 + x], scr.bg[b0 + x] local x2, buf = x, {} while x2 <= W and scr.fg[b0 + x2] == f and scr.bg[b0 + x2] == b do buf[#buf + 1] = scr.ch[b0 + x2] x2 += 1 end if b ~= 0 then bgs[#bgs + 1] = {x, x2 - x, b} end local s = (table.concat(buf):gsub("[&<>\"']", esc)) if f == 0xFFFFFF then parts[#parts + 1] = s else parts[#parts + 1] = string.format('%s', f, s) end x = x2 end return table.concat(parts), bgs end local function flush() for y = 1, MAXH do if dirty[y] then dirty[y] = nil local text, bgs = rowData(y) for _, v in ipairs(views) do if v.active() then v.lbl[y].Text = text for _, c in ipairs(v.bgh[y]:GetChildren()) do c:Destroy() end for _, s in ipairs(bgs) do mk("Frame", {BorderSizePixel = 0, BackgroundColor3 = rgb(s[3]), Position = UDim2.fromOffset((s[1] - 1) * CW, 0), Size = UDim2.fromOffset(s[2] * CW + 0.5, CH)}, v.bgh[y]) end end end end end end local function markAll() for y = 1, MAXH do dirty[y] = true end end local function bufSet(x, y, s, vert) x, y = clampi(x), clampi(y) local W, H = scr.W, scr.H for c in tostring(s):gmatch(utf8.charpattern) do if x >= 1 and x <= W and y >= 1 and y <= H then local i = (y - 1) * W + x scr.ch[i], scr.fg[i], scr.bg[i] = c, scr.fgc, scr.bgc dirty[y] = true end if vert then y += 1 else x += 1 end end end local function put(x, y, s, fg, bg) local f, b = scr.fgc, scr.bgc scr.fgc, scr.bgc = fg or 0xFFFFFF, bg or 0 bufSet(x, y, s) scr.fgc, scr.bgc = f, b end local function center(y, s, fg) put(math.floor((scr.W - #s) / 2) + 1, y, s, fg) end local sg = mk("SurfaceGui", {Face = Enum.NormalId.Front, SizingMode = Enum.SurfaceGuiSizingMode.FixedSize, CanvasSize = Vector2.new(640, 400)}, display) local _, worldBg = screenFrame(sg) buildView(worldBg, function() return true end) local gui = mk("ScreenGui", {Name = "OC_SimGui", ResetOnSpawn = false, DisplayOrder = 50}, guiParent()) local overlay = mk("Frame", {Size = UDim2.fromOffset(640, 400), AnchorPoint = Vector2.new(0.5, 0), Position = UDim2.new(0.5, 0, 0, 10), BackgroundTransparency = 1, Visible = false}, gui) local ovScale = mk("UIScale", {}, overlay) local _, ovBg = screenFrame(overlay) buildView(ovBg, function() return overlay.Visible end) local function styled(class, props, parent) local o = mk(class, props, parent) mk("UICorner", {CornerRadius = UDim.new(0, 8)}, o) return o end local function btn(text, parent, color) return styled("TextButton", {Text = text, Font = Enum.Font.GothamMedium, TextSize = 14, TextColor3 = T.text, BackgroundColor3 = color or T.btn, BorderSizePixel = 0}, parent) end local cfgPanel = mk("Frame", {AnchorPoint = Vector2.new(0.5, 0.5), Position = UDim2.new(0.5, 0, 0.5, 0), Size = UDim2.fromOffset(340, 190), BackgroundColor3 = T.panel, Visible = false, ZIndex = 30, BorderSizePixel = 0}, gui) mk("UICorner", {CornerRadius = UDim.new(0, 12)}, cfgPanel) mk("UIStroke", {Color = T.accent, Transparency = 0.4}, cfgPanel) mk("TextLabel", {Position = UDim2.fromOffset(12, 8), Size = UDim2.new(1, -24, 0, 24), BackgroundTransparency = 1, Font = Enum.Font.GothamMedium, TextSize = 16, TextColor3 = T.text, TextXAlignment = Enum.TextXAlignment.Left, Text = "Configuracao de Tela", ZIndex = 31}, cfgPanel) local cfgInfo = mk("TextLabel", {Position = UDim2.fromOffset(12, 38), Size = UDim2.new(1, -24, 0, 20), BackgroundTransparency = 1, Font = Enum.Font.Code, TextSize = 14, TextColor3 = Color3.fromRGB(160, 165, 185), TextXAlignment = Enum.TextXAlignment.Left, Text = "", ZIndex = 31}, cfgPanel) mk("TextLabel", {Position = UDim2.fromOffset(12, 66), Size = UDim2.new(0, 110, 0, 30), BackgroundTransparency = 1, Font = Enum.Font.Gotham, TextSize = 14, TextColor3 = T.text, TextXAlignment = Enum.TextXAlignment.Left, Text = "Resolucao max:", ZIndex = 31}, cfgPanel) local cfgW = styled("TextBox", {Position = UDim2.fromOffset(122, 66), Size = UDim2.fromOffset(60, 30), Font = Enum.Font.Code, TextSize = 14, TextColor3 = T.text, BackgroundColor3 = Color3.fromRGB(14, 15, 22), Text = "", PlaceholderText = "W", ZIndex = 31, BorderSizePixel = 0}, cfgPanel) local cfgX = mk("TextLabel", {Position = UDim2.fromOffset(186, 66), Size = UDim2.fromOffset(16, 30), BackgroundTransparency = 1, Font = Enum.Font.Code, TextSize = 14, TextColor3 = T.text, Text = "x", ZIndex = 31}, cfgPanel) local cfgH = styled("TextBox", {Position = UDim2.fromOffset(206, 66), Size = UDim2.fromOffset(60, 30), Font = Enum.Font.Code, TextSize = 14, TextColor3 = T.text, BackgroundColor3 = Color3.fromRGB(14, 15, 22), Text = "", PlaceholderText = "H", ZIndex = 31, BorderSizePixel = 0}, cfgPanel) local cfgApply = btn("Aplicar", cfgPanel, T.ok) cfgApply.Position, cfgApply.Size, cfgApply.ZIndex = UDim2.fromOffset(12, 116), UDim2.fromOffset(150, 34), 31 local cfgClose = btn("Fechar", cfgPanel, T.bad) cfgClose.Position, cfgClose.Size, cfgClose.ZIndex = UDim2.fromOffset(178, 116), UDim2.fromOffset(150, 34), 31 local cfgMsg = mk("TextLabel", {Position = UDim2.fromOffset(12, 156), Size = UDim2.new(1, -24, 0, 20), BackgroundTransparency = 1, Font = Enum.Font.Code, TextSize = 13, TextColor3 = T.bad, TextXAlignment = Enum.TextXAlignment.Left, Text = "", ZIndex = 31}, cfgPanel) local function cfgRefresh() cfgInfo.Text = `Atual: {scr.W} x {scr.H} | Limite: {MAXW} x {MAXH}` cfgW.PlaceholderText, cfgH.PlaceholderText = tostring(scr.W), tostring(scr.H) cfgW.Text, cfgH.Text, cfgMsg.Text = "", "", "" end cfgApply.MouseButton1Click:Connect(function() local w, h = tonumber(cfgW.Text), tonumber(cfgH.Text) if not w or not h or w < 20 or h < 5 then cfgMsg.Text = "Use numeros: largura >= 20, altura >= 5" return end w, h = math.min(math.floor(w), MAXW), math.min(math.floor(h), MAXH) resetBuf(w, h) cfgRefresh() cfgMsg.TextColor3 = T.ok cfgMsg.Text = `Resolucao aplicada: {w} x {h}` end) cfgClose.MouseButton1Click:Connect(function() cfgPanel.Visible = false end) local dock = mk("Frame", {AnchorPoint = Vector2.new(0.5, 1), Position = UDim2.new(0.5, 0, 1, -10), Size = UDim2.fromOffset(640, 92), BackgroundColor3 = T.panel, BackgroundTransparency = 0.08, BorderSizePixel = 0}, gui) mk("UICorner", {CornerRadius = UDim.new(0, 14)}, dock) mk("UIStroke", {Color = T.accent, Transparency = 0.55, Thickness = 1}, dock) local dockScale = mk("UIScale", {}, dock) mk("UIPadding", {PaddingTop = UDim.new(0, 6), PaddingBottom = UDim.new(0, 6), PaddingLeft = UDim.new(0, 6), PaddingRight = UDim.new(0, 6)}, dock) local row1 = mk("Frame", {Size = UDim2.new(1, 0, 0, 38), BackgroundTransparency = 1}, dock) local box = styled("TextBox", { Size = UDim2.new(1, -78, 1, 0), Font = Enum.Font.Code, TextSize = 16, PlaceholderText = "digite aqui e toque Enter", PlaceholderColor3 = Color3.fromRGB(120, 125, 150), Text = "", TextColor3 = T.text, BackgroundColor3 = Color3.fromRGB(14, 15, 22), ClearTextOnFocus = false, TextXAlignment = Enum.TextXAlignment.Left, BorderSizePixel = 0, }, row1) mk("UIPadding", {PaddingLeft = UDim.new(0, 10)}, box) local bSend = btn("Enter", row1, T.accent) bSend.Position, bSend.Size = UDim2.new(1, -72, 0, 0), UDim2.new(0, 72, 1, 0) local row2 = mk("Frame", {Position = UDim2.new(0, 0, 0, 44), Size = UDim2.new(1, 0, 0, 36), BackgroundTransparency = 1}, dock) mk("UIListLayout", {FillDirection = Enum.FillDirection.Horizontal, Padding = UDim.new(0, 4), SortOrder = Enum.SortOrder.LayoutOrder}, row2) local function rb(text, order, color) local b = btn(text, row2, color) b.Size, b.LayoutOrder = UDim2.new(1 / 14, -3.6, 1, 0), order return b end local bPower, bTela, bCtrlC, bTab = rb("Power", 1, T.ok), rb("Tela", 2), rb("^C", 3), rb("Tab", 4) local bUp, bDn, bLf, bRt = rb("↑", 5), rb("↓", 6), rb("←", 7), rb("→", 8) local bFont = rb("Fonte", 9) local bItem = rb("Item", 10, T.accent) local bSize = rb("Medium", 11) local bCal = rb("Calibrar", 12) local bEsc = rb("Esc", 13) local bClose = rb("X", 14, T.bad) local editor = mk("Frame", {Size = UDim2.new(0.96, 0, 0, 300), AnchorPoint = Vector2.new(0.5, 0), Position = UDim2.new(0.5, 0, 0, 10), BackgroundColor3 = T.panel, Visible = false, ZIndex = 20, BorderSizePixel = 0}, gui) mk("UICorner", {CornerRadius = UDim.new(0, 12)}, editor) mk("UISizeConstraint", {MaxSize = Vector2.new(640, 300)}, editor) mk("UIStroke", {Color = T.accent, Transparency = 0.4}, editor) local edTitle = mk("TextLabel", {Size = UDim2.new(1, -12, 0, 26), Position = UDim2.fromOffset(8, 2), BackgroundTransparency = 1, Font = Enum.Font.GothamMedium, TextSize = 14, TextColor3 = T.text, TextXAlignment = Enum.TextXAlignment.Left, Text = "editor", ZIndex = 21}, editor) local edBox = styled("TextBox", { Position = UDim2.fromOffset(6, 30), Size = UDim2.new(1, -12, 1, -76), MultiLine = true, ClearTextOnFocus = false, Font = Enum.Font.Code, TextSize = 14, TextColor3 = T.text, BackgroundColor3 = Color3.fromRGB(12, 13, 20), TextXAlignment = Enum.TextXAlignment.Left, TextYAlignment = Enum.TextYAlignment.Top, Text = "", ZIndex = 21, BorderSizePixel = 0, TextWrapped = false, }, editor) local eSave = btn("Salvar", editor, T.ok) eSave.Position, eSave.Size, eSave.ZIndex = UDim2.new(0, 6, 1, -40), UDim2.new(0, 110, 0, 34), 21 local eCancel = btn("Cancelar", editor, T.bad) eCancel.Position, eCancel.Size, eCancel.ZIndex = UDim2.new(0, 124, 1, -40), UDim2.new(0, 110, 0, 34), 21 local M = {state = "off", sig = {}, wake = math.huge, co = nil, bootAddr = nil, t0 = os.clock(), gen = 0, menu = false, input = nil, req = nil} local ledBase = Color3.fromRGB(40, 40, 40) local function setLed(c) ledBase = c led.Color = c end local function flash() if M.state == "running" then led.Color = Color3.fromRGB(255, 190, 60) task.delay(0.06, function() led.Color = ledBase end) end end local function pushSignal(...) if #M.sig < 4096 then table.insert(M.sig, table.pack(...)) end end local lf = loadstring local canLoad = false if lf then local ok, f = pcall(lf, "return 1") canLoad = ok and type(f) == "function" end local comps, byAddr, disks = {}, {}, {} local CPU_MAX_COMPONENTS = 16 -- CPU Tier 3 local function addComp(ctype, methods, addr) if #comps >= CPU_MAX_COMPONENTS then error("limite de componentes da CPU Tier 3 (" .. CPU_MAX_COMPONENTS .. ")", 2) end local c = {addr = addr or guid(), type = ctype, m = methods} table.insert(comps, c) byAddr[c.addr] = c return c end local function pathParts(path) local p = {} for s in tostring(path):gmatch("[^/]+") do if s == ".." then table.remove(p) elseif s ~= "." then p[#p + 1] = s end end return p end local function newNode(t) return {t = t, c = t == "d" and {} or nil, data = t == "f" and "" or nil, mt = os.time()} end local function fsSize(n) if n.t == "f" then return #n.data end local s = 0 for _, v in pairs(n.c) do s += fsSize(v) end return s end local function makeFs(label, restricted) local fs = {label = label, root = newNode("d"), h = {}, hn = 0, restricted = restricted and true or false} local function at(path) local n = fs.root for _, p in ipairs(pathParts(path)) do if n.t ~= "d" then return nil end n = n.c[p] if not n then return nil end end return n end local function par(path) local ps = pathParts(path) local name = table.remove(ps) if not name then return nil end local n = fs.root for _, p in ipairs(ps) do n = n.c and n.c[p] if not n then return nil end end if n.t ~= "d" then return nil end return n, name end local m = {} m.getLabel = function() return fs.label end m.setLabel = function(l) fs.label = tostring(l) return fs.label end m.isReadOnly = function() return false end m.spaceUsed = function() return fsSize(fs.root) end m.spaceTotal = function() return 2097152 end m.exists = function(p) return at(p) ~= nil end m.isDirectory = function(p) local n = at(p) return n ~= nil and n.t == "d" end m.size = function(p) local n = at(p) return (n and n.t == "f") and #n.data or 0 end m.lastModified = function(p) local n = at(p) return n and n.mt * 1000 or 0 end m.list = function(p) local n = at(p) if not n or n.t ~= "d" then return nil, p end local r = {} for k, v in pairs(n.c) do r[#r + 1] = k .. (v.t == "d" and "/" or "") end table.sort(r) return r end m.makeDirectory = function(p) if fs.restricted then return false, "restrito: sistema nao oficial" end local n = fs.root for _, s in ipairs(pathParts(p)) do if not n.c[s] then n.c[s] = newNode("d") elseif n.c[s].t ~= "d" then return false end n = n.c[s] end return true end m.remove = function(p) if fs.restricted then return false, "restrito: sistema nao oficial" end local pr, nm = par(p) if pr and pr.c[nm] then pr.c[nm] = nil return true end return false end m.rename = function(a, b) if fs.restricted then return false, "restrito: sistema nao oficial" end local pa, na = par(a) local pb, nb = par(b) if not (pa and pb and pa.c[na]) then return false end local node = pa.c[na] pa.c[na] = nil pb.c[nb] = node return true end m.open = function(p, mode) mode = tostring(mode or "r"):sub(1, 1) if mode ~= "r" and fs.restricted then return nil, "restrito: sistema nao oficial" end local n = at(p) if mode == "r" then if not n or n.t ~= "f" then return nil, p end else if n and n.t == "d" then return nil, p end local pr, nm = par(p) if not pr then return nil, p end if mode == "w" or not n then n = newNode("f") pr.c[nm] = n end end fs.hn += 1 fs.h[fs.hn] = {n = n, pos = (mode == "a") and #n.data or 0, w = mode ~= "r", r = mode == "r"} flash() return fs.hn end m.read = function(h, count) local o = fs.h[h] if not o or not o.r then return nil, "bad file descriptor" end local d = o.n.data if o.pos >= #d then return nil end local s = d:sub(o.pos + 1, (count == nil or count == math.huge) and #d or o.pos + math.floor(count)) o.pos += #s return s end m.write = function(h, data) local o = fs.h[h] if not o or not o.w then return nil, "bad file descriptor" end data = tostring(data) local d = o.n.data if o.pos >= #d then o.n.data = d .. data else o.n.data = d:sub(1, o.pos) .. data .. d:sub(o.pos + #data + 1) end o.pos += #data o.n.mt = os.time() return true end m.seek = function(h, whence, off) local o = fs.h[h] if not o then return nil, "bad file descriptor" end local b = whence == "cur" and o.pos or (whence == "end" and #o.n.data or 0) o.pos = math.max(0, b + (off or 0)) return o.pos end m.close = function(h) fs.h[h] = nil return true end return fs, m end local function addDisk(label, tmp, restricted) local fs, m = makeFs(label, restricted) local c = addComp("filesystem", m) disks[c.addr] = {fs = fs, m = m, tmp = tmp} return c.addr, disks[c.addr] end local function seed(d, path, data) local prev = d.fs.restricted d.fs.restricted = false -- so sistema (interno) pode gravar mesmo em disco restrito local dir = path:match("^(.*)/[^/]*$") if dir and dir ~= "" then d.m.makeDirectory(dir) end local h = d.m.open(path, "w") d.m.write(h, data) d.m.close(h) d.fs.restricted = prev end local PAL = {0xFFFFFF, 0xFFCC33, 0xCC66CC, 0x6699FF, 0xFFFF33, 0x33CC33, 0xFF6699, 0x333333, 0xCCCCCC, 0x336699, 0x9933CC, 0x333399, 0x663300, 0x336600, 0xFF3333, 0x000000} local function col(c, pal) c = math.floor(tonumber(c) or 0) if pal then return PAL[c + 1] or 0 end return c % 0x1000000 end local scrAddr local gpuM = { bind = function() return true end, getScreen = function() return scrAddr end, getBackground = function() return scr.bgc, false end, setBackground = function(c, p) local o = scr.bgc scr.bgc = col(c, p) return o, nil end, getForeground = function() return scr.fgc, false end, setForeground = function(c, p) local o = scr.fgc scr.fgc = col(c, p) return o, nil end, getDepth = function() return 8 end, setDepth = function() return 8 end, maxDepth = function() return 8 end, getResolution = function() return scr.W, scr.H end, getViewport = function() return scr.W, scr.H end, maxResolution = function() return MAXW, MAXH end, setResolution = function(w, h) w, h = clampi(w), clampi(h) if w < 1 or h < 1 or w > MAXW or h > MAXH then error("unsupported resolution", 2) end if w == scr.W and h == scr.H then return false end resetBuf(w, h) return true end, set = function(x, y, s, v) bufSet(x, y, s, v) return true end, get = function(x, y) x, y = clampi(x), clampi(y) if x < 1 or y < 1 or x > scr.W or y > scr.H then return nil, "index out of bounds" end local i = (y - 1) * scr.W + x return scr.ch[i], scr.fg[i], scr.bg[i] end, fill = function(x, y, w, h, c) x, y, w, h = clampi(x), clampi(y), clampi(w), clampi(h) c = tostring(c):match(utf8.charpattern) or " " for j = math.max(1, y), math.min(scr.H, y + h - 1) do for i = math.max(1, x), math.min(scr.W, x + w - 1) do local k = (j - 1) * scr.W + i scr.ch[k], scr.fg[k], scr.bg[k] = c, scr.fgc, scr.bgc end dirty[j] = true end return true end, copy = function(x, y, w, h, tx, ty) x, y, w, h, tx, ty = clampi(x), clampi(y), clampi(w), clampi(h), clampi(tx), clampi(ty) local W, H = scr.W, scr.H local j0, j1, js = 0, h - 1, 1 if ty > 0 then j0, j1, js = h - 1, 0, -1 end local i0, i1, is = 0, w - 1, 1 if tx > 0 then i0, i1, is = w - 1, 0, -1 end for j = j0, j1, js do for i = i0, i1, is do local sx, sy, dx, dy = x + i, y + j, x + i + tx, y + j + ty if sx >= 1 and sx <= W and sy >= 1 and sy <= H and dx >= 1 and dx <= W and dy >= 1 and dy <= H then local a, b = (sy - 1) * W + sx, (dy - 1) * W + dx scr.ch[b], scr.fg[b], scr.bg[b] = scr.ch[a], scr.fg[a], scr.bg[a] dirty[dy] = true end end end return true end, getPaletteColor = function(i) return PAL[clampi(i) + 1] end, setPaletteColor = function(i, v) local o = PAL[clampi(i) + 1] PAL[clampi(i) + 1] = col(v) return o end, totalMemory = function() return 8000 end, freeMemory = function() return 8000 end, getActiveBuffer = function() return 0 end, buffers = function() return {} end, } local CATALOG = { {"Gabinete de computador", "computer", "Liga o computador e guarda as pecas. Ja existe no simulador."}, {"Tela", "screen", "Mostra texto, controlada por uma GPU. Ja instalada."}, {"Placa de video (GPU)", "gpu", "Desenha texto e cores na tela. Ja instalada."}, {"Teclado", "keyboard", "Envia teclas para a tela. Ja instalado."}, {"Disco rigido (HDD) com init.lua", "filesystem", "Cria um disco novo com /init.lua. Aparece no BIOS para bootar."}, {"Placa de internet", "internet", "Faz requisicoes HTTP. Ja instalada."}, {"Editor de texto", "roblox_editor", "Abre o editor do Roblox com o comando edit. Ja instalado."}, {"Geolyzer", "geolyzer", "Escaneia a dureza dos blocos. Ainda nao emulado."}, {"Redstone I/O", "redstone", "Le e emite sinais de redstone. Ainda nao emulado."}, {"Verificador de codigo (scan)", "antivirus", "Aponta padroes suspeitos em arquivos. Comando scan. Ja instalado."}, {"Gravador (pasta Delta)", "workspace", "Salva arquivos em Delta/Workspace/OpenComputers. Comando save. Ja instalado."}, {"Relogio (Timer)", "timer", "Conta tempo para os programas. Ainda nao emulado."}, {"Bateria (Capacitor)", "capacitor", "Guarda energia para o computador. Ainda nao emulada."}, {"Gerador de energia", "generator", "Gera energia para os blocos. Ainda nao emulado."}, {"Impressora 3D", "printer3d", "Imprime blocos com cores. Ainda nao emulada."}, {"Robo", "robot", "Robo que se move e age no mundo. Ainda nao emulado."}, {"Rack de Servidores", "rack", "Comporta ate 4 servidores. Ainda nao emulado."}, {"Projetor de hologramas", "hologram", "Projeta hologramas 48x32x48. Ainda nao emulado."}, {"Conversor de energia", "powerconverter", "Converte energia de outros mods. Ainda nao emulado."}, {"Distribuidor de energia", "powerdistributor", "Separa redes de energia. Ainda nao emulado."}, {"Alternar (Switch)", "switch", "Liga redes diferentes so com mensagens. Ainda nao emulado."}, {"Ponto de acesso", "accesspoint", "Rede sem fio. Ainda nao emulado."}, {"Cabo", "cable", "Liga blocos de forma barata. Ainda nao emulado."}, {"Unidade de disco (floppy)", "disk_drive", "Le e grava disquetes. Toque para instalar."}, {"Desmontador", "disassembler", "Desmonta itens e blocos. Ainda nao emulado."}, {"Adaptador", "adapter", "Muda o LED e mostra texto no gabinete. Toque para instalar."}, {"Montador de robos", "assembler", "Monta robos a partir das pecas. Ainda nao emulado."}, {"Carregador", "charger", "Carrega a energia dos robos. Ainda nao emulado."}, {"Disquete (floppy)", "floppy", "Toque para criar um disquete e colocar na unidade."}, } local selectedItem = nil local diskCount = 2 local userDisks = {} -- HDDs criados pelo Item (os nativos nao podem ser excluidos) local itemPanel = mk("Frame", { Size = UDim2.new(0.96, 0, 0, 300), AnchorPoint = Vector2.new(0.5, 0), Position = UDim2.new(0.5, 0, 0, 10), BackgroundColor3 = T.panel, Visible = false, ZIndex = 30, BorderSizePixel = 0, }, gui) mk("UICorner", {CornerRadius = UDim.new(0, 12)}, itemPanel) mk("UISizeConstraint", {MaxSize = Vector2.new(640, 300)}, itemPanel) mk("TextLabel", { Size = UDim2.new(1, -12, 0, 26), Position = UDim2.fromOffset(8, 2), BackgroundTransparency = 1, Font = Enum.Font.GothamMedium, TextSize = 14, TextColor3 = T.text, TextXAlignment = Enum.TextXAlignment.Left, Text = "Itens do OpenComputers", ZIndex = 31, }, itemPanel) local itemScroll = mk("ScrollingFrame", { Position = UDim2.fromOffset(6, 30), Size = UDim2.new(1, -12, 1, -72), BackgroundColor3 = Color3.fromRGB(12, 13, 20), BorderSizePixel = 0, CanvasSize = UDim2.new(0, 0, 0, 0), AutomaticCanvasSize = Enum.AutomaticSize.Y, ScrollBarThickness = 6, ZIndex = 31, }, itemPanel) mk("UIListLayout", {Padding = UDim.new(0, 4), SortOrder = Enum.SortOrder.LayoutOrder}, itemScroll) mk("UIPadding", {PaddingTop = UDim.new(0, 4), PaddingLeft = UDim.new(0, 4), PaddingRight = UDim.new(0, 4)}, itemScroll) local itemInfo = mk("TextLabel", { Position = UDim2.new(0, 8, 1, -38), Size = UDim2.new(1, -150, 0, 30), BackgroundTransparency = 1, Font = Enum.Font.Code, TextSize = 13, TextColor3 = T.text, TextXAlignment = Enum.TextXAlignment.Left, TextTruncate = Enum.TextTruncate.AtEnd, Text = "Toque num bloco para selecionar.", ZIndex = 31, }, itemPanel) local itemWorld = styled("TextButton", { Position = UDim2.new(1, -140, 1, -36), Size = UDim2.new(0, 70, 0, 30), Text = "No mundo", Font = Enum.Font.GothamMedium, TextSize = 12, TextColor3 = T.text, BackgroundColor3 = T.accent, BorderSizePixel = 0, ZIndex = 31, }, itemPanel) local itemClose = styled("TextButton", { Position = UDim2.new(1, -66, 1, -36), Size = UDim2.new(0, 60, 0, 30), Text = "Fechar", Font = Enum.Font.GothamMedium, TextSize = 12, TextColor3 = T.text, BackgroundColor3 = T.bad, BorderSizePixel = 0, ZIndex = 31, }, itemPanel) local function isPresent(ctype) for _, c in ipairs(comps) do if c.type == ctype then return true end end return false end local refreshItems, hddOpen, installDrive, installAdapter, makeFloppy refreshItems = function() for _, c in ipairs(itemScroll:GetChildren()) do if c:IsA("TextButton") then c:Destroy() end end for i, it in ipairs(CATALOG) do local name, ctype, desc = it[1], it[2], it[3] local b = styled("TextButton", { Size = UDim2.new(1, 0, 0, 46), LayoutOrder = i, Text = "", BackgroundColor3 = (selectedItem == i) and T.accent or T.btn, BorderSizePixel = 0, ZIndex = 32, AutoButtonColor = true, }, itemScroll) mk("TextLabel", { Position = UDim2.fromOffset(8, 4), Size = UDim2.new(1, -16, 0, 18), BackgroundTransparency = 1, Font = Enum.Font.GothamMedium, TextSize = 14, TextColor3 = T.text, TextXAlignment = Enum.TextXAlignment.Left, Text = name .. (isPresent(ctype) and " [instalado]" or ""), ZIndex = 33, }, b) mk("TextLabel", { Position = UDim2.fromOffset(8, 22), Size = UDim2.new(1, -16, 0, 20), BackgroundTransparency = 1, Font = Enum.Font.Code, TextSize = 12, TextColor3 = Color3.fromRGB(150, 155, 180), TextXAlignment = Enum.TextXAlignment.Left, TextTruncate = Enum.TextTruncate.AtEnd, Text = desc, ZIndex = 33, }, b) b.MouseButton1Click:Connect(function() selectedItem = i if ctype == "filesystem" then hddOpen() elseif ctype == "disk_drive" then installDrive(name) elseif ctype == "adapter" then installAdapter(name) elseif ctype == "floppy" then makeFloppy() elseif isPresent(ctype) then itemInfo.Text = name .. " ja esta instalado. Use component.list() para ver." else itemInfo.Text = name .. " ainda nao e emulado. Só aparece no mundo." end refreshItems() end) end end local worldN = 0 itemWorld.MouseButton1Click:Connect(function() if not selectedItem then itemInfo.Text = "Selecione um bloco primeiro." return end local it = CATALOG[selectedItem] worldN += 1 local pos = display.CFrame * CFrame.new(-6 - ((worldN - 1) % 4) * 2.6, -1.5 - math.floor((worldN - 1) / 4) * 2.6, 0.5) local blk = part("OC_" .. it[2], Vector3.new(2, 2, 2), pos, Color3.fromRGB(88, 166, 255), Enum.Material.Metal) mk("BillboardGui", {Size = UDim2.fromOffset(160, 36), StudsOffset = Vector3.new(0, 2, 0), AlwaysOnTop = true}, blk) local bb = blk:FindFirstChildOfClass("BillboardGui") mk("TextLabel", {Size = UDim2.fromScale(1, 1), BackgroundTransparency = 0.3, BackgroundColor3 = Color3.new(0, 0, 0), Font = Enum.Font.Code, TextSize = 13, TextColor3 = T.text, Text = it[1]}, bb) itemInfo.Text = it[1] .. " colocado no mundo, ao lado do monitor." end) itemClose.MouseButton1Click:Connect(function() itemPanel.Visible = false end) bItem.MouseButton1Click:Connect(function() itemPanel.Visible = not itemPanel.Visible if itemPanel.Visible then refreshItems() end end) local KBS = {} local computerC = addComp("computer", {}) local eeprom = {data = "", label = "EEPROM (Lua BIOS)", code = "-- BIOS simulado no hospedeiro: procura /init.lua nos discos e pergunta quando ha mais de um."} addComp("eeprom", { get = function() return eeprom.code end, set = function(c) eeprom.code = tostring(c) end, getData = function() return eeprom.data end, setData = function(d) eeprom.data = tostring(d or "") end, getLabel = function() return eeprom.label end, setLabel = function(l) eeprom.label = tostring(l) return eeprom.label end, getSize = function() return 4096 end, getDataSize = function() return 256 end, getChecksum = function() return "00000000" end, makeReadonly = function() return false end, }) local diskA, dA = addDisk("OpenOS-Lite") local diskB, dB = addDisk("MiniOS") local gpuC = addComp("gpu", gpuM) local scrC = addComp("screen", { isOn = function() return scr.on end, turnOn = function() return false, scr.on end, turnOff = function() return false, scr.on end, getAspectRatio = function() return 1, 1 end, getKeyboards = function() return KBS end, setPrecise = function() end, isPrecise = function() return false end, setTouchModeInverted = function() end, isTouchModeInverted = function() return false end, }) scrAddr = scrC.addr do local UIS = game:GetService("UserInputService") local function screenToCell(sx, sy) local cam = workspace.CurrentCamera local cf, sz = display.CFrame, display.Size local function proj(lx, ly) return cam:WorldToViewportPoint((cf * CFrame.new(lx, ly, 0)).Position) end local a, b = proj(sz.X / 2, 0), proj(-sz.X / 2, 0) local left, right = a, b if b.X < a.X then left, right = b, a end local t, u = proj(0, sz.Y / 2), proj(0, -sz.Y / 2) local top, bottom = t, u if u.Y < t.Y then top, bottom = u, t end local fx = (sx - left.X) / math.max(1, right.X - left.X) local fy = (sy - top.Y) / math.max(1, bottom.Y - top.Y) if fx < 0 or fx > 1 or fy < 0 or fy > 1 then return nil end local px, py = fx * 640, fy * 400 local col = math.floor((px - (10 + PADX)) / CW) + 1 local row = math.floor((py - (10 + PADY)) / CH) + 1 if col < 1 or col > scr.W or row < 1 or row > scr.H then return nil end return col, row end local calib, calibStep, calibPts, calibSaved = nil, 0, {}, nil local TL = {c = 3, r = 2} -- centro do alvo vermelho (cols 2-4, linha 2) local function brCell() return {c = scr.W - 3, r = scr.H - 1} end -- centro do alvo verde local function saveCell(x, y) local i = (y - 1) * scr.W + x return {x = x, y = y, ch = scr.ch[i], fg = scr.fg[i], bg = scr.bg[i]} end local function calibDraw(on) M.paused = on and true or false if on then local br = brCell() calibSaved = {} for x = 2, 4 do table.insert(calibSaved, saveCell(x, TL.r)) end for x = br.c - 1, br.c + 1 do table.insert(calibSaved, saveCell(x, br.r)) end put(2, TL.r, " ", 0xFFFFFF, 0xFF2020) put(br.c - 1, br.r, " ", 0xFFFFFF, 0x20FF20) elseif calibSaved then for _, c in ipairs(calibSaved) do local i = (c.y - 1) * scr.W + c.x scr.ch[i], scr.fg[i], scr.bg[i] = c.ch, c.fg, c.bg dirty[c.y] = true end calibSaved = nil end end local function calibWhite() local cx, cy = math.floor(scr.W / 2) - 1, math.floor(scr.H / 2) for x = cx, cx + 2 do table.insert(calibSaved, saveCell(x, cy)) end put(cx, cy, " ", 0x000000, 0xFFFFFF) end local function calibCell(sx, sy) local tl, br = calib.tl, calib.br local b = brCell() local col = math.floor(TL.c + (sx - tl.X) / math.max(1, br.X - tl.X) * (b.c - TL.c) + 0.5) local row = math.floor(TL.r + (sy - tl.Y) / math.max(1, br.Y - tl.Y) * (b.r - TL.r) + 0.5) if col < 1 or col > scr.W or row < 1 or row > scr.H then return nil end return col, row end bCal.MouseButton1Click:Connect(function() calib, calibStep, calibPts = nil, 1, {} calibDraw(true) bCal.Text = "toque vermelho" end) ex.OCSimInput = UIS.InputBegan:Connect(function(input, gp) if gp or M.state ~= "running" or not scr.on then return end local kind = input.UserInputType if kind ~= Enum.UserInputType.Touch and kind ~= Enum.UserInputType.MouseButton1 then return end local cam = workspace.CurrentCamera local ray = cam:ViewportPointToRay(input.Position.X, input.Position.Y) local hit = workspace:Raycast(ray.Origin, ray.Direction * 500) if not hit or hit.Instance ~= display then return end local sx, sy = input.Position.X, input.Position.Y if calibStep > 0 then if calibStep == 1 then calibPts.tl = Vector2.new(sx, sy) calibStep = 2 bCal.Text = "toque verde" elseif calibStep == 2 then calibPts.br = Vector2.new(sx, sy) calib = calibPts calibStep = 3 calibWhite() bCal.Text = "toque branco" else calibStep = 0 calibDraw(false) bCal.Text = "Calibrado" end return end local col, row if calib then col, row = calibCell(sx, sy) else col, row = screenToCell(sx, sy) end if not col then return end pushSignal("touch", scrC.addr, col, row, 0, "jogador") end) end local kbC = addComp("keyboard", {}) KBS[1] = kbC.addr local tmpAddr = addDisk("tmpfs", true) local httpFn do local g = (getgenv and getgenv()) or _G httpFn = g.request or g.http_request or (g.syn and g.syn.request) end addComp("internet", { isHttpEnabled = function() return true end, isTcpEnabled = function() return false end, request = function(url, post, headers, method) local req = {done = false} task.spawn(function() if post or headers or (method and method ~= "GET") then if httpFn then local ok, r = pcall(httpFn, {Url = url, Method = method or (post and "POST" or "GET"), Headers = headers, Body = post}) if ok and type(r) == "table" then req.data, req.code = r.Body, r.StatusCode else req.err = tostring(r) end else req.err = "request() indisponivel neste executor" end else local ok, r = pcall(function() return game:HttpGet(url) end) if ok and type(r) == "string" then req.data = r else req.err = "falha de rede" end end req.done = true end) local pos = 1 return { finishConnect = function() if not req.done then return false end if req.err then return nil, req.err end return true end, response = function() return req.code or 200, "OK", {} end, read = function(n) if not req.done or req.err or not req.data or pos > #req.data then return nil end local e = (n == nil or n == math.huge) and #req.data or pos + math.floor(n) - 1 local s = req.data:sub(pos, e) pos = e + 1 return s end, close = function() end, } end, }) do local SAVE_DIR = "OpenComputers" addComp("workspace", { write = function(name, data) local g = (getgenv and getgenv()) or _G local wf = g.writefile or writefile if not wf then return nil, "writefile indisponivel (use o Delta)" end name = tostring(name):gsub("%.%.", ""):gsub("/", "_") if name == "" then return nil, "nome invalido" end local mf = g.makefolder or makefolder local isf = g.isfolder or isfolder if mf and isf and not isf(SAVE_DIR) then mf(SAVE_DIR) end wf(SAVE_DIR .. "/" .. name, tostring(data or "")) return SAVE_DIR .. "/" .. name end, getPath = function() return SAVE_DIR end, }) local SUSPECT = { {"require com ID numerico", "require%s*%(%s*%d", true}, {"loadstring (executa texto como codigo)", "loadstring", false}, {"getfenv/setfenv (esconde escopo)", "getfenv", false}, {"setfenv (esconde escopo)", "setfenv", false}, {"HttpGet (baixa codigo da internet)", "HttpGet", false}, {"GetAsync/PostAsync (requisicao externa)", "GetAsync", false}, {"PostAsync (envia dados para fora)", "PostAsync", false}, {"webhook do Discord", "discord.com/api/webhooks", false}, {"getcookie / cookie", "cookie", false}, {"setclipboard (copia dados)", "setclipboard", false}, {"string.byte com muitos numeros (ofuscacao)", "string.char", false}, } local function analyze(src) src = tostring(src or "") local hits = {} for _, r in ipairs(SUSPECT) do if string.find(src, r[2], 1, not r[3]) then hits[#hits + 1] = r[1] end end local escapes = select(2, string.gsub(src, "\\%d%d%d", "")) if escapes > 20 then hits[#hits + 1] = "muitas sequencias \\ddd (texto escondido, " .. escapes .. ")" end for line in (src .. "\n"):gmatch("(.-)\n") do if #line > 400 then hits[#hits + 1] = "linha muito longa (" .. #line .. " caracteres, ofuscacao?)" break end end return hits end addComp("antivirus", { analyze = function(text) return analyze(text) end, readws = function(name) local g = (getgenv and getgenv()) or _G local rf = g.readfile or readfile local isf = g.isfile or isfile local path = "OpenComputers/" .. tostring(name):gsub("%.%.", ""):gsub("\\", "/") if isf and not isf(path) then return nil, "arquivo nao existe em Workspace/" .. path end local ok, data = pcall(rf, path) if not ok then return nil, "nao foi possivel ler (" .. tostring(data) .. ")" end return data end, }) local ed = {} local function closeEditor(saved) editor.Visible = false if ed.path then pushSignal("editor_closed", ed.path, saved and true or false) end ed.path = nil end addComp("roblox_editor", { open = function(addr, path) local d = disks[addr] if not d then return nil, "disco invalido" end local h = d.m.open(path, "r") local text = "" if h then text = d.m.read(h, math.huge) or "" d.m.close(h) end ed.addr, ed.path = addr, path edTitle.Text = `editando {d.fs.label}:{path}` edBox.Text = text editor.Visible = true return true end, }) eSave.MouseButton1Click:Connect(function() local d = ed.addr and disks[ed.addr] if d and ed.path then local h = d.m.open(ed.path, "w") if h then d.m.write(h, edBox.Text) d.m.close(h) pushSignal("editor_saved", ed.path) closeEditor(true) else edTitle.Text = "erro: nao foi possivel salvar (pasta inexistente?)" end end end) eCancel.MouseButton1Click:Connect(function() closeEditor(false) end) end local function pullFor(co) return co end local function makeEnv() local rawResume, rawYield, rawStatus, rawCreate = coroutine.resume, coroutine.yield, coroutine.status, coroutine.create local SYS = {} local env = {} local function gresume(co, ...) local r = table.pack(rawResume(co, ...)) while r[1] and r[2] == SYS and rawStatus(co) == "suspended" do r = table.pack(rawResume(co, rawYield(SYS))) end return table.unpack(r, 1, r.n) end local gco = { create = rawCreate, resume = gresume, yield = rawYield, status = rawStatus, running = coroutine.running, isyieldable = coroutine.isyieldable, wrap = function(f) local co = rawCreate(f) return function(...) local r = table.pack(gresume(co, ...)) if not r[1] then error(r[2], 0) end return table.unpack(r, 2, r.n) end end, } local function chars(s) local t = {} for c in tostring(s):gmatch(utf8.charpattern) do t[#t + 1] = c end return t end local unicode = { char = function(...) local t = {} for i, c in ipairs({...}) do t[i] = utf8.char(c) end return table.concat(t) end, len = function(s) return utf8.len(tostring(s)) or #tostring(s) end, lower = string.lower, upper = string.upper, reverse = function(s) local t, r = chars(s), {} for i = #t, 1, -1 do r[#r + 1] = t[i] end return table.concat(r) end, sub = function(s, i, j) local t = chars(s) local n = #t i, j = i or 1, j or -1 if i < 0 then i = n + i + 1 end if j < 0 then j = n + j + 1 end if i < 1 then i = 1 end if j > n then j = n end if i > j then return "" end return table.concat(t, "", i, j) end, isWide = function() return false end, charWidth = function() return 1 end, wlen = function(s) return utf8.len(tostring(s)) or #tostring(s) end, wtrunc = function(s, n) return table.concat(chars(s), "", 1, math.max(0, n - 1)) end, } local computer = { address = function() return computerC.addr end, tmpAddress = function() return tmpAddr end, freeMemory = function() return TOTAL_MEM - 180000 - fsSize(dA.fs.root) end, totalMemory = function() return TOTAL_MEM end, energy = function() return 5000 end, maxEnergy = function() return 5000 end, uptime = function() return os.clock() - M.t0 end, beep = function() end, pushSignal = function(...) pushSignal(...) return true end, pullSignal = function(timeout) if timeout == nil then timeout = math.huge end M.wake = os.clock() + math.max(0, tonumber(timeout) or 0) return rawYield(SYS) end, shutdown = function(reboot) M.req = reboot and "reboot" or "off" rawYield(SYS) end, getBootAddress = function() return M.bootAddr or eeprom.data end, setBootAddress = function(a) eeprom.data = tostring(a or "") return true end, users = function() return end, addUser = function() return true end, removeUser = function() return false end, getArchitecture = function() return "Lua 5.3" end, getArchitectures = function() return {"Lua 5.3"} end, setArchitecture = function() return false end, isRobot = function() return false end, runlevel = function() return 1 end, getDeviceInfo = function() return {} end, } local function proxyOf(addr) local c = byAddr[addr] if not c then return nil, "no such component" end local p = {address = addr, type = c.type, slot = -1} for k, f in pairs(c.m) do p[k] = f end return p end local component = { list = function(filter, exact) local i = 0 return function() while true do i += 1 local c = comps[i] if not c then return nil end if not filter or (exact and c.type == filter) or (not exact and c.type:find(filter, 1, true)) then return c.addr, c.type end end end end, type = function(a) local c = byAddr[a] if c then return c.type end return nil, "no such component" end, slot = function() return -1 end, proxy = proxyOf, invoke = function(a, m, ...) local c = byAddr[a] if not c then error("no such component", 2) end local f = c.m[m] if not f then error("no such method", 2) end return f(...) end, methods = function(a) local c = byAddr[a] if not c then return nil, "no such component" end local r = {} for k in pairs(c.m) do r[k] = true end return r end, fields = function() return {} end, doc = function() return nil end, get = function(partial, ctype) for _, c in ipairs(comps) do if (not ctype or c.type == ctype) and c.addr:sub(1, #partial) == partial then return c.addr end end return nil, "no such component" end, isAvailable = function(t) for _, c in ipairs(comps) do if c.type == t then return true end end return false end, getPrimary = function(t) for _, c in ipairs(comps) do if c.type == t then return proxyOf(c.addr) end end error("no primary '" .. t .. "' available", 2) end, } setmetatable(component, {__index = function(_, k) for _, c in ipairs(comps) do if c.type == k then return proxyOf(c.addr) end end end}) local function load2(chunk, name, mode, e) if type(chunk) == "function" then local t = {} while true do local p = chunk() if not p or p == "" then break end t[#t + 1] = p end chunk = table.concat(t) end local f, err = loadstring(chunk, name or "=load") if not f then return nil, err end setfenv(f, e or env) return f end local function checkArg(n, v, ...) local t = type(v) for _, x in ipairs({...}) do if x == t or (x == "nil" and v == nil) then return true end end error("bad argument #" .. n .. " (" .. table.concat({...}, " or ") .. " expected, got " .. t .. ")", 3) end local hostos = {} for _, k in ipairs({"clock", "time", "date", "difftime"}) do hostos[k] = os[k] end env.assert, env.error, env.getmetatable, env.ipairs, env.next, env.pairs = assert, error, getmetatable, ipairs, next, pairs env.pcall, env.rawequal, env.rawget, env.rawset, env.select, env.setmetatable = pcall, rawequal, rawget, rawset, select, setmetatable env.tonumber, env.tostring, env.type, env.xpcall, env.rawlen = tonumber, tostring, type, xpcall, rawlen env.load, env.checkArg, env._VERSION = load2, checkArg, "Lua 5.3" env.unpack = table.unpack local function copyTable(t) local c = {} for k, v in pairs(t) do c[k] = v end return c end env.math, env.string, env.table, env.utf8 = copyTable(math), copyTable(string), copyTable(table), copyTable(utf8) env.bit32 = bit32 and copyTable(bit32) or nil env.coroutine, env.os, env.debug = gco, hostos, {traceback = debug.traceback} env.unicode, env.computer, env.component = unicode, computer, component env._G = env return env end local powerOff, bootSequence local function crash(msg) M.state, M.co = "halted", nil resetBuf(MAXW, MAXH) scr.fgc, scr.bgc, scr.on = 0xFFFFFF, 0, true put(2, 2, "Unrecoverable error", 0xE65050) local y = 4 for line in tostring(msg):gmatch("[^\n]+") do while #line > 0 and y < scr.H do put(2, y, line:sub(1, scr.W - 2), 0xFFFFFF) line = line:sub(scr.W - 1) y += 1 end end put(2, scr.H, "Toque Power para desligar e ligar de novo.", 0x8A8FA3) setLed(Color3.fromRGB(255, 60, 60)) end local function startGuest(addr) local d = disks[addr] local node = d.fs.root.c["init.lua"] local f, err = loadstring(node.data, "=init.lua") resetBuf(MAXW, MAXH) scr.fgc, scr.bgc = 0xFFFFFF, 0 if not f then crash("erro de sintaxe em /init.lua:\n" .. tostring(err)) return end setfenv(f, makeEnv()) M.co, M.sig, M.wake, M.bootAddr, M.t0, M.req = coroutine.create(f), {}, 0, addr, os.clock(), nil M.state = "running" end function bootSequence() if M.state ~= "off" then return end M.gen += 1 local gen = M.gen M.state = "bios" setLed(Color3.fromRGB(255, 200, 60)) resetBuf(MAXW, MAXH) scr.fgc, scr.bgc, scr.on = 0xFFFFFF, 0, true local row = 2 center(row, "O P E N C O M P U T E R S S I M", 0x58A6FF) row += 1 center(row, string.format("BIOS 2.0 | CPU Tier 3 | GPU Tier 3 | %dK RAM", math.floor(TOTAL_MEM / 1024)), 0x8A8FA3) row += 1 center(row, string.format("Componentes: %d/%d | Lua 5.3 (Luau)", #comps, CPU_MAX_COMPONENTS), 0x8A8FA3) row += 1 put(2, row, string.rep("-", scr.W - 2), 0x3A3F55) row += 2 if not canLoad then put(2, row, "loadstring indisponivel. Use o Delta Executor.", 0xE65050) M.state = "halted" return end put(2, row, "Procurando /init.lua nos discos...", 0xFFFFFF) row += 1 task.wait(0.4) if M.gen ~= gen then return end local cands = {} for _, c in ipairs(comps) do local d = disks[c.addr] if d and not d.tmp then local n = d.fs.root.c["init.lua"] local has = n ~= nil and n.t == "f" put(3, row, string.format("%s %-12s %s", c.addr:sub(1, 8), d.fs.label, has and "[ /init.lua ]" or "[ --------- ]"), has and 0x46C86E or 0x6A6F85) row += 1 if has then table.insert(cands, c.addr) end end end if #cands == 0 then put(2, row + 1, "Nenhum /init.lua encontrado. Sistema parado.", 0xE65050) M.state = "halted" return end local pick = cands[1] if #cands > 1 then local def = 1 for i, a in ipairs(cands) do if a == eeprom.data then def = i end end row += 1 put(2, row, `Achei {#cands} arquivos /init.lua. Qual iniciar?`, 0xFFCC33) row += 1 for i, a in ipairs(cands) do if row >= scr.H - 3 then put(4, row, `... e mais {#cands - i + 1} (digite o numero)`, 0x8A8FA3) break end put(4, row, `[{i}] {disks[a].fs.label} ({a:sub(1, 8)}){i == def and " <- padrao" or ""}`, 0xFFFFFF) row += 1 end put(2, row + 1, "Digite o numero na caixa e toque Enter.", 0x8A8FA3) put(2, row + 2, "Enter vazio = padrao.", 0x8A8FA3) M.menu, M.input = true, nil while M.gen == gen and M.input == nil do task.wait(0.05) end M.menu = false if M.gen ~= gen then return end local idx = tonumber(M.input) idx = idx and math.floor(idx) or def if not cands[idx] then idx = def end pick = cands[idx] end eeprom.data = pick put(2, scr.H - 1, `Iniciando {disks[pick].fs.label}...`, 0x46C86E) task.wait(0.7) if M.gen ~= gen then return end setLed(Color3.fromRGB(60, 255, 60)) startGuest(pick) end function powerOff() M.gen += 1 M.state, M.co, M.sig, M.menu = "off", nil, {}, false scr.on = false resetBuf(MAXW, MAXH) setLed(Color3.fromRGB(40, 40, 40)) end local function step() if M.paused then return end local t0 = os.clock() while M.state == "running" and os.clock() - t0 < 0.007 do local sig if #M.sig > 0 then sig = table.remove(M.sig, 1) elseif os.clock() >= M.wake then sig = {n = 0} else break end M.wake = math.huge local ok, err = coroutine.resume(M.co, table.unpack(sig, 1, sig.n)) if M.req then local r = M.req M.req = nil task.spawn(function() powerOff() if r == "reboot" then task.wait(0.6) bootSequence() end end) return end if not ok then crash(debug.traceback(M.co, tostring(err))) return end if coroutine.status(M.co) == "dead" then crash("computer halted (o /init.lua terminou)") return end end end do local KEYCODE = {[" "] = 57, ["-"] = 12, ["="] = 13, ["["] = 26, ["]"] = 27, [";"] = 39, ["'"] = 40, [","] = 51, ["."] = 52, ["/"] = 53, ["\\"] = 43, ["`"] = 41} for _, r in ipairs({{"1234567890", 2}, {"qwertyuiop", 16}, {"asdfghjkl", 30}, {"zxcvbnm", 44}}) do for i = 1, #r[1] do KEYCODE[r[1]:sub(i, i)] = r[2] + i - 1 end end local function pushKey(chr, code) pushSignal("key_down", kbC.addr, chr, code, "jogador") pushSignal("key_up", kbC.addr, chr, code, "jogador") end local function key(chr, code) if M.state == "running" then pushKey(chr, code) end end local function sendText(text) if M.state == "bios" and M.menu then M.input = text return end if M.state ~= "running" then return end pcall(function() for _, cp in utf8.codes(text) do pushKey(cp, KEYCODE[utf8.char(cp):lower()] or 0) end end) pushKey(13, 28) end local function togglePower() if M.state == "off" then task.spawn(bootSequence) else powerOff() end end local function stopAll() powerOff() if ex.OCSimConn then ex.OCSimConn:Disconnect() ex.OCSimConn = nil end if ex.OCSimInput then ex.OCSimInput:Disconnect() ex.OCSimInput = nil end if ex.OCSimVP then ex.OCSimVP:Disconnect() ex.OCSimVP = nil end model:Destroy() gui:Destroy() end ex.OCSimStop = stopAll cd.MouseClick:Connect(togglePower) bPower.MouseButton1Click:Connect(togglePower) local SIZE_NAMES, SIZE_FACTOR, sizeIdx = {"Small", "Medium", "Large"}, {0.5, 0.75, 1}, 2 local function updateScales() local vp = workspace.CurrentCamera.ViewportSize dockScale.Scale = math.clamp(vp.X * 0.96 / 640, 0.5, 1.4) local base = math.clamp(math.min(vp.X * 0.96 / 640, (vp.Y - 130) / 400), 0.2, 1.5) ovScale.Scale = base * SIZE_FACTOR[sizeIdx] bSize.Text = SIZE_NAMES[sizeIdx] end bSize.MouseButton1Click:Connect(function() sizeIdx = sizeIdx % #SIZE_NAMES + 1 updateScales() markAll() end) updateScales() ex.OCSimVP = workspace.CurrentCamera:GetPropertyChangedSignal("ViewportSize"):Connect(function() updateScales() markAll() end) bTela.MouseButton1Click:Connect(function() if cfgPanel.Visible then cfgPanel.Visible = false return end cfgRefresh() cfgPanel.Visible = true overlay.Visible = not overlay.Visible if overlay.Visible then updateScales() markAll() end end) local fontOC = false bFont.MouseButton1Click:Connect(function() fontOC = not fontOC bFont.Text = fontOC and "OC" or "RBX" bFont.BackgroundColor3 = fontOC and T.ok or T.btn for _, v in ipairs(views) do for _, l in ipairs(v.lbl) do l.Font = fontOC and Enum.Font.Arcade or FONT end end end) bCtrlC.MouseButton1Click:Connect(function() key(3, 46) end) bEsc.MouseButton1Click:Connect(function() key(0, 1) end) bTab.MouseButton1Click:Connect(function() key(9, 15) end) bUp.MouseButton1Click:Connect(function() key(0, 200) end) bDn.MouseButton1Click:Connect(function() key(0, 208) end) bLf.MouseButton1Click:Connect(function() key(0, 203) end) bRt.MouseButton1Click:Connect(function() key(0, 205) end) bClose.MouseButton1Click:Connect(stopAll) local function submit() local text = box.Text box.Text = "" sendText(text) end bSend.MouseButton1Click:Connect(submit) box.FocusLost:Connect(function(enter) if enter then submit() task.defer(function() if box.Parent then box:CaptureFocus() end end) end end) local acc = 0 ex.OCSimConn = RunService.Heartbeat:Connect(function(dt) step() acc += dt if acc >= 0.05 then acc = 0 flush() end end) end seed(dA, "/init.lua", [==[ -- OpenOS-Lite 2.0 (/init.lua do disco 1) local component, computer, unicode = component, computer, unicode local gpu = component.proxy(component.list("gpu")()) gpu.bind(component.list("screen")()) local W, H = gpu.maxResolution() gpu.setResolution(W, H) local COL = {fg = 0xE6E6E6, bg = 0x0B0E17, dir = 0x5AA9FF, exe = 0x50DC78, err = 0xFF6B6B, dim = 0x8A8FA3, acc = 0xFFCC33, usr = 0x50DC78, hi = 0x5AA9FF} gpu.setBackground(COL.bg) gpu.setForeground(COL.fg) gpu.fill(1, 1, W, H, " ") ------------------------------------------------ terminal local cx, cy, scrolled = 1, 1, 0 local function newline() cx = 1 if cy >= H then gpu.copy(1, 2, W, H - 1, 0, -1) gpu.fill(1, H, W, 1, " ") scrolled = scrolled + 1 else cy = cy + 1 end end local function twrite(s) s = tostring(s):gsub("\r", ""):gsub("\t", " ") local i, n = 1, #s while i <= n do local nl = s:find("\n", i, true) local seg = s:sub(i, (nl or n + 1) - 1) while #seg > 0 do if cx > W then newline() end local room = W - cx + 1 local piece = unicode.sub(seg, 1, room) gpu.set(cx, cy, piece) cx = cx + unicode.len(piece) seg = unicode.sub(seg, room + 1) end if nl then newline() i = nl + 1 else break end end end local function cwrite(c, s) gpu.setForeground(c) twrite(s) gpu.setForeground(COL.fg) end local function perr(m) cwrite(COL.err, tostring(m) .. "\n") end local term = {} term.write = twrite function term.clear() gpu.fill(1, 1, W, H, " ") cx, cy = 1, 1 end function term.getCursor() return cx, cy end function term.setCursor(x, y) cx, cy = x, y end function term.isAvailable() return true end term.gpu = function() return gpu end function term.getViewport() return W, H end function term.read(opts) opts = opts or {} local hist = opts.history or {} local buf, pos, hi, lastLen = {}, 0, #hist + 1, 0 local sx, sy = cx, cy local function text() return table.concat(buf) end local function pxy(i) local o = sx - 1 + i return o % W + 1, sy + math.floor(o / W) end local function redraw() cx, cy, scrolled = sx, sy, 0 local t = text() twrite(t .. string.rep(" ", math.max(1, lastLen - #buf + 1))) sy = sy - scrolled lastLen = #buf end local function cursor(on) local x, y = pxy(pos) if y > H then return end local c = gpu.get(x, y) if on then gpu.setBackground(0xFFFFFF) gpu.setForeground(0x000000) end gpu.set(x, y, c or " ") gpu.setBackground(COL.bg) gpu.setForeground(COL.fg) end local function setBuf(s) buf = {} for ch in s:gmatch(utf8.charpattern) do buf[#buf + 1] = ch end pos = #buf end local function finish() local x, y = pxy(#buf) cx, cy = x, math.min(y, H) newline() end local blink = true while true do cursor(blink) local e, _, c, k = computer.pullSignal(0.5) cursor(false) if e == "touch" then -- indicador de clique: mostra a posicao no canto superior direito sem mexer no cursor local ox, oy = cx, cy gpu.setForeground(COL.acc) gpu.set(math.max(1, W - 15), 1, string.format("toque %3d,%-3d", c, k)) gpu.setForeground(COL.fg) cx, cy = ox, oy elseif e == nil then blink = not blink else blink = true local changed = false if e == "key_down" then if k == 28 or c == 13 then finish() local s = text() if s ~= "" and opts.history then table.insert(opts.history, s) end return s elseif c == 3 then finish() cwrite(COL.dim, "^C\n") return nil elseif k == 14 then if pos > 0 then table.remove(buf, pos) pos = pos - 1 changed = true end elseif k == 211 then if pos < #buf then table.remove(buf, pos + 1) changed = true end elseif k == 203 then pos = math.max(0, pos - 1) elseif k == 205 then pos = math.min(#buf, pos + 1) elseif k == 199 then pos = 0 elseif k == 207 then pos = #buf elseif k == 200 then if hi > 1 and #hist > 0 then hi = hi - 1 setBuf(hist[hi]) changed = true end elseif k == 208 then if hi < #hist then hi = hi + 1 setBuf(hist[hi]) changed = true elseif hi == #hist then hi = #hist + 1 setBuf("") changed = true end elseif k == 15 then if opts.complete then local r = opts.complete(text()) if r then setBuf(r) changed = true end end elseif c and c >= 32 and c ~= 127 then table.insert(buf, pos + 1, utf8.char(c)) pos = pos + 1 changed = true end elseif e == "touch" then -- sinal: ("touch", endereco, coluna, linha, botao, jogador) local msg = " touch " .. tostring(c) .. "," .. tostring(k) .. " " local ox = math.max(1, W - unicode.len(msg) + 1) local ob, of = gpu.getBackground(), gpu.getForeground() gpu.setBackground(0x5AA9FF) gpu.setForeground(0x000000) gpu.set(ox, 1, msg) gpu.setBackground(ob) gpu.setForeground(of) elseif e == "clipboard" then local s = tostring(c or ""):match("^[^\n]*") for ch in s:gmatch(utf8.charpattern) do table.insert(buf, pos + 1, ch) pos = pos + 1 end changed = true end if changed then redraw() end end end end ------------------------------------------------ unicode / fs local fs = {cwd = "/home"} local mounts = {} function fs.canonical(p) local parts = {} for s in tostring(p):gmatch("[^/]+") do if s == ".." then table.remove(parts) elseif s ~= "." then parts[#parts + 1] = s end end return "/" .. table.concat(parts, "/") end local function abs(p) p = tostring(p) if p:sub(1, 1) ~= "/" then p = fs.cwd .. "/" .. p end return fs.canonical(p) end local function resolve(path) local p = abs(path) local best for _, m in ipairs(mounts) do if m.path == "" or p == m.path or p:sub(1, #m.path + 1) == m.path .. "/" then if not best or #m.path > #best.path then best = m end end end local rel = p:sub(#best.path + 1) if rel == "" then rel = "/" end return best.proxy, rel, p end local bootAddr = computer.getBootAddress() mounts[1] = {path = "", proxy = component.proxy(bootAddr)} mounts[2] = {path = "/tmp", proxy = component.proxy(computer.tmpAddress())} for addr in component.list("filesystem") do if addr ~= bootAddr and addr ~= computer.tmpAddress() then mounts[#mounts + 1] = {path = "/mnt/" .. addr:sub(1, 3), proxy = component.proxy(addr)} end end local function vchildren(p) local r = {} local pre = (p == "/") and "/" or p .. "/" for _, m in ipairs(mounts) do if m.path ~= "" and m.path:sub(1, #pre) == pre then local nm = m.path:sub(#pre + 1):match("^[^/]+") if nm then r[nm] = true end end end return r end function fs.exists(p) local px, rel, a = resolve(p) return px.exists(rel) or next(vchildren(a)) ~= nil end function fs.isDirectory(p) local px, rel, a = resolve(p) return px.isDirectory(rel) or next(vchildren(a)) ~= nil end function fs.size(p) local px, rel = resolve(p) return px.size(rel) end function fs.lastModified(p) local px, rel = resolve(p) return px.lastModified(rel) end function fs.makeDirectory(p) local px, rel = resolve(p) return px.makeDirectory(rel) end function fs.remove(p) local px, rel = resolve(p) return px.remove(rel) end function fs.isLink() return false end function fs.get(p) local px, rel, a = resolve(p) return px, a end function fs.mounts() local i = 0 return function() i = i + 1 local m = mounts[i] if m then return m.proxy, m.path == "" and "/" or m.path end end end function fs.name(p) return ((tostring(p):gsub("/+$", "")):match("([^/]*)$")) end function fs.path(p) return tostring(p):match("^(.*/)[^/]*$") or "" end function fs.concat(...) return fs.canonical(table.concat({...}, "/")) end function fs.list(path) local px, rel, p = resolve(path) local names, seen = {}, {} local l = px.list(rel) if l then for _, n in ipairs(l) do names[#names + 1] = n seen[(n:gsub("/$", ""))] = true end end local v = vchildren(p) local any = l ~= nil for nm in pairs(v) do any = true if not seen[nm] then names[#names + 1] = nm .. "/" end end if not any then return nil, "not a directory" end table.sort(names) local i = 0 return function() i = i + 1 return names[i] end end function fs.open(path, mode) mode = mode or "r" local px, rel = resolve(path) local h, e = px.open(rel, mode) if not h then return nil, e or path end local o = {} function o:read(n) return px.read(h, n or math.huge) end function o:write(d) return px.write(h, d) end function o:seek(w, off) return px.seek(h, w, off) end function o:close() return px.close(h) end return o end local function readFile(path) local h = fs.open(path, "r") if not h then return nil end local parts = {} while true do local d = h:read(math.huge) if not d then break end parts[#parts + 1] = d end h:close() return table.concat(parts) end local function writeFile(path, data) local h, e = fs.open(path, "w") if not h then return nil, e end h:write(data) h:close() return true end function fs.copy(a, b) local d = readFile(a) if not d then return nil, "origem nao existe" end if fs.isDirectory(b) then b = fs.concat(b, fs.name(a)) end return writeFile(b, d) end function fs.rename(a, b) local pa, ra = resolve(a) if fs.isDirectory(b) then b = fs.concat(b, fs.name(a)) end local pb, rb = resolve(b) if pa == pb then return pa.rename(ra, rb) end local ok = fs.copy(a, b) if ok then pa.remove(ra) end return ok end ------------------------------------------------ event / os / io local event, listeners = {}, {} function event.push(...) return computer.pushSignal(...) end function event.listen(name, cb) listeners[#listeners + 1] = {name = name, cb = cb} return true end function event.ignore(name, cb) for i = #listeners, 1, -1 do if listeners[i].name == name and listeners[i].cb == cb then table.remove(listeners, i) return true end end return false end function event.pull(timeout, name) if type(timeout) == "string" then name, timeout = timeout, nil end local deadline = timeout and computer.uptime() + timeout or math.huge while true do local left = deadline - computer.uptime() if left < 0 then return nil end local sig = table.pack(computer.pullSignal(left)) if sig.n > 0 then if sig[1] == "key_down" and sig[3] == 3 then error("interrupted", 0) end for _, l in ipairs(listeners) do if l.name == sig[1] then pcall(l.cb, table.unpack(sig, 1, sig.n)) end end if not name or sig[1] == name then return table.unpack(sig, 1, sig.n) end elseif left <= 0 then return nil end end end local hostos = os local env = {PWD = "/home", HOME = "/home", PATH = "/bin:/usr/bin", USER = "root", SHELL = "/bin/sh"} local os = {} for k, v in pairs(hostos) do os[k] = v end function os.sleep(t) local d = computer.uptime() + (t or 0) repeat event.pull(math.max(0, d - computer.uptime())) until computer.uptime() >= d end function os.exit(c) error({exit = true, code = c}, 0) end function os.getenv(k) if k == nil then return env end if k == "PWD" then return fs.cwd end return env[k] end function os.setenv(k, v) env[k] = v return v end function os.tmpname() return "/tmp/tmp" .. math.floor(computer.uptime() * 1000) end function os.remove(p) return fs.remove(p) end function os.rename(a, b) return fs.rename(a, b) end function os.execute(l) return _G.__shell and _G.__shell.execute(l) end _G.os = os local io = {} local function rd(f, fmt) if type(fmt) == "number" then if f.pos > #f.data then return nil end local s = f.data:sub(f.pos, f.pos + fmt - 1) f.pos = f.pos + #s return s end fmt = (tostring(fmt or "l"):gsub("^%*", "")) if fmt == "a" then local s = f.data:sub(f.pos) f.pos = #f.data + 1 return s end if f.pos > #f.data then return nil end if fmt == "n" then local s, e = f.data:find("^%s*[%+%-]?%d*%.?%d+", f.pos) if not s then return nil end f.pos = e + 1 return tonumber(f.data:sub(s, e)) end local e = f.data:find("\n", f.pos, true) local line if e then line = f.data:sub(f.pos, fmt == "L" and e or e - 1) f.pos = e + 1 else line = f.data:sub(f.pos) f.pos = #f.data + 1 end return line end local fileMT = {} fileMT.__index = fileMT function fileMT:read(...) local f = {...} if #f == 0 then return rd(self, "l") end local out = {} for i, fmt in ipairs(f) do out[i] = rd(self, fmt) end return table.unpack(out, 1, #f) end function fileMT:lines(fmt) return function() return rd(self, fmt or "l") end end function fileMT:write(...) for _, v in ipairs({...}) do self.h:write(tostring(v)) end return self end function fileMT:seek(w, off) if self.h then return self.h:seek(w or "cur", off or 0) end local b = w == "set" and 0 or (w == "end" and #self.data or self.pos - 1) self.pos = math.max(1, b + (off or 0) + 1) return self.pos - 1 end function fileMT:close() if self.h then self.h:close() end return true end function fileMT:flush() return self end function fileMT:setvbuf() return true end function io.open(path, mode) mode = ((mode or "r"):gsub("b", "")) local m = mode:sub(1, 1) if m == "r" then local d = readFile(path) if not d then return nil, path .. ": No such file or directory" end return setmetatable({data = d, pos = 1}, fileMT) end local h, e = fs.open(path, m) if not h then return nil, tostring(e) end return setmetatable({h = h}, fileMT) end function io.lines(path, fmt) local f = io.open(path) if not f then error(path .. ": No such file or directory", 2) end return f:lines(fmt) end function io.write(...) for _, v in ipairs({...}) do twrite(tostring(v)) end return io.stdout end function io.read(fmt) local l = term.read({history = {}}) if l == nil then return nil end fmt = tostring(fmt or "l"):gsub("^%*", "") if fmt == "n" then return tonumber(l) end if fmt == "L" then return l .. "\n" end return l end io.stdout = {write = function(self, ...) io.write(...) return self end, flush = function() end, close = function() end, setvbuf = function() end} io.stderr = {write = function(self, ...) for _, v in ipairs({...}) do cwrite(COL.err, tostring(v)) end return self end, flush = function() end} io.stdin = {read = function(_, f) return io.read(f) end, lines = function() return function() return io.read() end end} _G.io = io _G.print = function(...) local t = table.pack(...) for i = 1, t.n do t[i] = tostring(t[i]) end twrite(table.concat(t, "\t") .. "\n") end ------------------------------------------------ package / require local package = {loaded = {}, preload = {}, path = "/lib/?.lua;/usr/lib/?.lua;./?.lua"} local function loadfile(path) local d = readFile(path) if not d then return nil, "cannot open " .. tostring(path) end if d:sub(1, 2) == "#!" then d = "--" .. d end return load(d, "=" .. abs(path), "t", _G) end local function require(name) if package.loaded[name] ~= nil then return package.loaded[name] end local loader = package.preload[name] if not loader then local nm = name:gsub("%.", "/") for pat in package.path:gmatch("[^;]+") do local p = pat:gsub("%?", nm) if fs.exists(p) and not fs.isDirectory(p) then loader = loadfile(p) break end end end if not loader then error("module '" .. name .. "' not found", 2) end local r = loader(name) if r == nil then r = true end package.loaded[name] = r return r end _G.package, _G.require, _G.loadfile = package, require, loadfile _G.dofile = function(p, ...) local f, e = loadfile(p) if not f then error(e, 0) end return f(...) end local serialization = {} local function ser(v, pretty, ind) local t = type(v) if t == "string" then return string.format("%q", v) elseif t == "table" then local parts, nl = {}, pretty and "\n" or "" local ni = (ind or "") .. (pretty and " " or "") for k, x in pairs(v) do local key = (type(k) == "string" and k:match("^[%a_][%w_]*$")) and k or "[" .. ser(k) .. "]" parts[#parts + 1] = ni .. key .. "=" .. ser(x, pretty, ni) end return "{" .. nl .. table.concat(parts, "," .. nl) .. nl .. (pretty and (ind or "") or "") .. "}" end return tostring(v) end function serialization.serialize(v, pretty) return ser(v, pretty) end function serialization.unserialize(s) local f = load("return " .. tostring(s), "=unserialize", "t", {}) if not f then return nil end local ok, r = pcall(f) return ok and r or nil end local text = {} function text.trim(s) return (tostring(s):gsub("^%s+", ""):gsub("%s+$", "")) end function text.split(s, sep) local r = {} for p in (tostring(s) .. sep):gmatch("(.-)" .. sep:gsub("%p", "%%%0")) do r[#r + 1] = p end return r end local function tokenize(line) local t, i = {}, 1 while i <= #line do local c = line:sub(i, i) if c:match("%s") then i = i + 1 elseif c == '"' then local j = line:find('"', i + 1, true) or (#line + 1) t[#t + 1] = line:sub(i + 1, j - 1) i = j + 1 else local j = line:find("%s", i) or (#line + 1) t[#t + 1] = line:sub(i, j - 1) i = j end end return t end text.tokenize = tokenize local keyboard = {keys = {back = 14, enter = 28, tab = 15, up = 200, down = 208, left = 203, right = 205, delete = 211, home = 199, ["end"] = 207, space = 57, c = 46}} function keyboard.isControlDown() return false end function keyboard.isShiftDown() return false end function keyboard.isAltDown() return false end local internet = {} function internet.request(url, data, headers, method) local ia = component.list("internet")() if not ia then error("sem placa de internet", 2) end local h, e = component.invoke(ia, "request", url, data, headers, method) if not h then error(e or "falha na requisicao", 2) end local connected = false return function() if not connected then while true do local ok, err = h.finishConnect() if ok then break elseif ok == nil then error(err or "conexao falhou", 0) end os.sleep(0.05) end connected = true end local d = h.read(math.huge) if d == nil then h.close() end return d end end function internet.isHttpEnabled() return true end local sides = {bottom = 0, top = 1, back = 2, front = 3, right = 4, left = 5, down = 0, up = 1, north = 2, south = 3, west = 4, east = 5} local colors = {white = 0, orange = 1, magenta = 2, lightblue = 3, yellow = 4, lime = 5, pink = 6, gray = 7, silver = 8, cyan = 9, purple = 10, blue = 11, brown = 12, green = 13, red = 14, black = 15} for k, v in pairs({component = component, computer = computer, unicode = unicode, filesystem = fs, term = term, event = event, serialization = serialization, text = text, keyboard = keyboard, internet = internet, sides = sides, colors = colors, io = io, os = os}) do package.loaded[k] = v end package.loaded.fs = fs ------------------------------------------------ shell local cmds = {} local shell = {} local function parseOpts(t) local a, o = {}, {} for _, x in ipairs(t) do if x:sub(1, 1) == "-" and #x > 1 and not tonumber(x) then for c in x:sub(2):gmatch(".") do o[c] = true end else a[#a + 1] = x end end return a, o end function shell.parse(...) return parseOpts({...}) end function shell.getWorkingDirectory() return fs.cwd end function shell.setWorkingDirectory(p) local a = abs(p) if fs.isDirectory(a) then fs.cwd = a return true end return nil, "not a directory" end function shell.resolve(p) return abs(p) end local function findProgram(name) local c = {} if name:find("/") then c = {name, name .. ".lua"} else for _, d in ipairs({fs.cwd, "/bin", "/usr/bin"}) do c[#c + 1] = d .. "/" .. name c[#c + 1] = d .. "/" .. name .. ".lua" end end for _, p in ipairs(c) do if fs.exists(p) and not fs.isDirectory(p) then return abs(p) end end end function shell.execute(line) local args = tokenize(line) local name = table.remove(args, 1) if not name then return true end local ok, e = pcall(function() if cmds[name] then local a, o = parseOpts(args) cmds[name](a, o) else local p = findProgram(name) if not p then return perr(name .. ": comando nao encontrado") end local f, err = loadfile(p) if not f then return perr(err) end f(table.unpack(args)) end end) if not ok then if type(e) == "table" and e.exit then return true end if tostring(e) == "interrupted" then cwrite(COL.err, "interrompido\n") else perr(e) end return false end return true end _G.__shell = shell package.loaded.shell = shell cmds.clear = function() term.clear() end cmds.cls = cmds.clear cmds.pwd = function() twrite(fs.cwd .. "\n") end cmds.echo = function(a) twrite(table.concat(a, " ") .. "\n") end cmds.date = function() twrite(os.date("%Y-%m-%d %H:%M:%S") .. "\n") end cmds.uname = function() twrite("OpenOS-Lite 2.0 (OC Sim)\n") end cmds.uptime = function() twrite(string.format("uptime: %d s\n", math.floor(computer.uptime()))) end cmds.free = function() local t, f = computer.totalMemory(), computer.freeMemory() twrite(string.format("total %d\nusado %d\nlivre %d\n", t, t - f, f)) end cmds.df = function() twrite("Disco Usado Total Montado\n") for px, mp in fs.mounts() do twrite(string.format("%-12s %8d %10d %s\n", (px.getLabel() or "?"):sub(1, 12), px.spaceUsed(), px.spaceTotal(), mp)) end end cmds.components = function() for a, t in component.list() do cwrite(COL.dim, a:sub(1, 8) .. " ") twrite(t .. "\n") end end cmds.lscomponents = cmds.components cmds.reboot = function() computer.shutdown(true) end cmds.shutdown = function() computer.shutdown(false) end cmds.sleep = function(a) os.sleep(tonumber(a[1]) or 1) end cmds.which = function(a) local p = a[1] and (cmds[a[1]] and "(interno)" or findProgram(a[1])) twrite((p or "nao encontrado") .. "\n") end cmds.label = function(a) local px = fs.get("/") if a[1] then px.setLabel(a[1]) end twrite((px.getLabel() or "") .. "\n") end cmds.cd = function(a) local ok, e = shell.setWorkingDirectory(a[1] or "/home") if not ok then perr("cd: " .. tostring(a[1]) .. ": " .. e) end end cmds.ls = function(a, o) local p = a[1] or "." if not fs.exists(p) then return perr("ls: " .. p .. ": nao existe") end if not fs.isDirectory(p) then return twrite(p .. "\n") end local items = {} for n in fs.list(p) do items[#items + 1] = n end local function color(n) return n:sub(-1) == "/" and COL.dir or (n:match("%.lua$") and COL.exe or COL.fg) end if o.l then for _, n in ipairs(items) do local isd = n:sub(-1) == "/" twrite(string.format("%s %8d ", isd and "d" or "-", isd and 0 or fs.size(fs.concat(p, n)))) cwrite(color(n), n .. "\n") end else local maxw = 1 for _, n in ipairs(items) do maxw = math.max(maxw, unicode.len(n)) end local colw = maxw + 2 local per = math.max(1, math.floor(W / colw)) local k = 0 for _, n in ipairs(items) do cwrite(color(n), n .. string.rep(" ", colw - unicode.len(n))) k = k + 1 if k % per == 0 then twrite("\n") end end if k % per ~= 0 then twrite("\n") end end end cmds.dir = cmds.ls cmds.cat = function(a) for _, p in ipairs(a) do local d = readFile(p) if not d then perr("cat: " .. p .. ": nao existe") else twrite(d) if #d > 0 and d:sub(-1) ~= "\n" then twrite("\n") end end end end cmds.mkdir = function(a) for _, p in ipairs(a) do fs.makeDirectory(p) end end cmds.touch = function(a) for _, p in ipairs(a) do if not fs.exists(p) then writeFile(p, "") end end end cmds.rm = function(a, o) for _, p in ipairs(a) do if not fs.exists(p) then perr("rm: " .. p .. ": nao existe") elseif fs.isDirectory(p) and not (o.r or o.f) then perr("rm: " .. p .. ": e diretorio (use -r)") else local ok, e = fs.remove(p) if not ok then perr("rm: " .. p .. ": " .. tostring(e or "falhou")) end end end end cmds.del = cmds.rm cmds.cp = function(a) if #a < 2 then return twrite("uso: cp origem destino\n") end local ok, e = fs.copy(a[1], a[2]) if not ok then perr("cp: " .. tostring(e)) end end cmds.mv = function(a) if #a < 2 then return twrite("uso: mv origem destino\n") end if not fs.rename(a[1], a[2]) then perr("mv: falhou") end end cmds.wget = function(a) local url = a[1] if not url then return twrite("uso: wget url [arquivo]\n") end local name = a[2] or url:match("([^/]+)$") or "index" local t = {} for c in internet.request(url) do t[#t + 1] = c end local data = table.concat(t) local ok, e = writeFile(name, data) if not ok then return perr("wget: " .. tostring(e)) end twrite(string.format("salvo: %s (%d bytes)\n", name, #data)) end cmds.edit = function(a) local path = a[1] if not path then return twrite("uso: edit arquivo\n") end local ed = component.list("roblox_editor")() if not ed then return perr("edit: sem componente roblox_editor") end local px, rel = resolve(path) local ok, e = component.invoke(ed, "open", px.address, rel) if not ok then return perr("edit: " .. tostring(e)) end cwrite(COL.dim, "Editor aberto. Toque em Salvar ou Cancelar...\n") event.pull(nil, "editor_closed") end cmds.scan = function(a) if not a[1] then return twrite("uso: scan arquivo.lua ou scan ws:NOME.lua (pasta OpenComputers do Delta)\n") end local av = component.list("antivirus")() if not av then return perr("scan: sem verificador") end local data if a[1]:sub(1, 3) == "ws:" then local d, e = component.invoke(av, "readws", a[1]:sub(4)) if not d then return perr("scan: " .. tostring(e)) end data = d else data = readFile(a[1]) if not data then return perr("scan: " .. a[1] .. ": nao existe") end end local hits = component.invoke(av, "analyze", data) if #hits == 0 then cwrite(COL.ok or COL.exe, "Nenhum padrao suspeito encontrado.\n") cwrite(COL.dim, "Isso NAO prova que o codigo e seguro. Leia antes de rodar.\n") else cwrite(COL.err, "Padroes suspeitos (" .. #hits .. "):\n") for _, h in ipairs(hits) do twrite(" - " .. h .. "\n") end cwrite(COL.dim, "Nao rode esse codigo sem entender o que ele faz.\n") end end cmds.save = function(a) if not a[1] then return twrite("uso: save arquivo.lua (salva em Delta/Workspace/OpenComputers)\n") end local d = readFile(a[1]) if not d then return perr("save: " .. a[1] .. ": nao existe") end local ws = component.list("workspace")() if not ws then return perr("save: sem componente workspace") end local path, err = component.invoke(ws, "write", fs.name(a[1]), d) if not path then return perr("save: " .. tostring(err)) end cwrite(COL.exe, "salvo: " .. path .. " (" .. #d .. " bytes)\n") end cmds.boot = function(a) local list = {} for addr in component.list("filesystem") do if addr ~= computer.tmpAddress() and component.invoke(addr, "exists", "/init.lua") then list[#list + 1] = addr end end if a[1] then local sel = list[tonumber(a[1]) or 0] if not sel then return perr("boot: opcao invalida") end computer.setBootAddress(sel) return cwrite(COL.exe, "padrao do BIOS alterado. Use reboot.\n") end for i, addr in ipairs(list) do twrite(string.format("[%d] %s %s%s\n", i, addr:sub(1, 8), component.invoke(addr, "getLabel") or "", addr == computer.getBootAddress() and " (atual)" or "")) end cwrite(COL.dim, "boot define o padrao do BIOS\n") end local function resultsOut(r) if r.n > 1 then local t = {} for i = 2, r.n do t[#t + 1] = type(r[i]) == "table" and serialization.serialize(r[i]) or tostring(r[i]) end twrite(table.concat(t, "\t") .. "\n") end end cmds.lua = function(a) if a[1] then local f, e = loadfile(a[1]) if not f then return perr(e) end return f(table.unpack(a, 2)) end cwrite(COL.hi, "Lua 5.3 REPL ") cwrite(COL.dim, "(exit para sair)\n") local hist = {} while true do cwrite(COL.acc, "lua> ") local l = term.read({history = hist}) if l ~= nil then if l == "exit" or l == "os.exit()" then return end if l ~= "" then local f = load("return " .. l, "=stdin", "t", _G) local e if not f then f, e = load(l, "=stdin", "t", _G) end if not f then perr(e) else local r = table.pack(pcall(f)) if not r[1] then if not (type(r[2]) == "table" and r[2].exit) then perr(r[2]) end else resultsOut(r) end end end end end end cmds.help = function() local names = {} for k in pairs(cmds) do names[#names + 1] = k end table.sort(names) cwrite(COL.hi, "comandos: ") twrite(table.concat(names, " ") .. "\n") cwrite(COL.dim, "programas .lua em /bin, /usr/bin ou na pasta atual rodam pelo nome.\n") cwrite(COL.dim, "require() carrega de /lib e /usr/lib. Use edit/wget para criar scripts.\n") end local function complete(t) local head, tok = t:match("^(.*%s)(%S*)$") local first = false if not head then head, tok, first = "", t, true end local dir, base = tok:match("^(.*/)([^/]*)$") if not dir then dir, base = "", tok end local cands = {} local function add(n) if n:sub(1, #base) == base then cands[#cands + 1] = n end end local d = dir == "" and "." or dir if fs.isDirectory(d) then for n in fs.list(d) do add(n) end end if first and dir == "" then for k in pairs(cmds) do add(k) end end if #cands == 0 then return nil end table.sort(cands) local pre = cands[1] for _, c in ipairs(cands) do while c:sub(1, #pre) ~= pre do pre = pre:sub(1, -2) end end if #cands == 1 and pre:sub(-1) ~= "/" then pre = pre .. " " end if #pre <= #base then return nil end return head .. dir .. pre end ------------------------------------------------ inicio local host = computer.address():sub(1, 3) cwrite(COL.hi, "OpenOS-Lite 2.0") cwrite(COL.dim, " | OC Sim | Lua 5.3 (Luau)\n") cwrite(COL.dim, string.format("RAM %dk livres | boot %s | digite 'help'\n\n", math.floor(computer.freeMemory() / 1024), bootAddr:sub(1, 8))) local history = {} while true do cwrite(COL.usr, "root@" .. host) cwrite(COL.fg, ":") cwrite(COL.dir, fs.cwd) cwrite(COL.fg, "# ") local line = term.read({history = history, complete = complete}) if line and line ~= "" then shell.execute(line) end end ]==]) seed(dA, "/home/hello.lua", [==[ print("Ola do OpenOS-Lite!") local component = require("component") local gpu = component.gpu print("resolucao:", gpu.getResolution()) print("RAM livre:", require("computer").freeMemory()) ]==]) seed(dA, "/home/cor.lua", [==[ local gpu = require("component").gpu local term = require("term") for i = 0, 7 do gpu.setBackground(0x202020 + i * 0x203040) io.write(" cor " .. i .. " ") end gpu.setBackground(0x0B0E17) print() ]==]) seed(dA, "/etc/motd", "OpenOS-Lite 2.0\n") seed(dB, "/init.lua", [==[ -- MiniOS 0.2 (/init.lua do disco 2): GUI simples com area de trabalho -- Clique (touch) ou setas + Enter abrem apps. Esc fecha a janela. local gpu = component.proxy(component.list("gpu")()) gpu.bind(component.list("screen")()) local W, H = gpu.maxResolution() gpu.setResolution(W, H) local C = {bg = 0x1B1030, bar = 0x2A1B4A, txt = 0xFFFFFF, dim = 0x9A8CC8, sel = 0x7B4FD6, win = 0x33245A, ok = 0x77FFAA, err = 0xFF6B6B, title = 0xFFCC33} local function paint(bg, fg) if bg then gpu.setBackground(bg) end if fg then gpu.setForeground(fg) end end local log, line = {}, "" local function logLine(s, fg) table.insert(log, {tostring(s), fg or C.txt}) while #log > 200 do table.remove(log, 1) end end local function evalLine(src) logLine("> " .. src, C.dim) local f, err = load("return " .. src, "=mini") if not f then f, err = load(src, "=mini") end if not f then return logLine(err, C.err) end local r = table.pack(pcall(f)) if not r[1] then return logLine(r[2], C.err) end local parts = {} for i = 2, r.n do parts[#parts + 1] = tostring(r[i]) end if #parts > 0 then logLine(table.concat(parts, "\t"), C.ok) end end local apps local view, sel = "desk", 1 local function drawWindowFrame(title) paint(C.bar, C.title) gpu.fill(1, 1, W, 1, " ") gpu.set(2, 1, title) paint(nil, C.err) gpu.set(W - 2, 1, "[X]") paint(C.bg, C.txt) gpu.fill(1, 2, W, H - 1, " ") end local function drawTerminal() drawWindowFrame("Terminal") local top = H - 2 local rows = {} for i = #log, 1, -1 do table.insert(rows, 1, log[i]) if #rows >= top - 2 then break end end local y = 3 for _, r in ipairs(rows) do paint(nil, r[2]) gpu.set(2, y, r[1]:sub(1, W - 2)) y = y + 1 end paint(nil, C.ok) gpu.fill(1, H, W, 1, " ") gpu.set(2, H, "> " .. line:sub(-(W - 4))) end local function drawUptime() drawWindowFrame("Uptime") paint(nil, C.txt) gpu.set(3, 4, "Tempo ligado: " .. math.floor(computer.uptime()) .. " s") gpu.set(3, 5, "RAM livre: " .. computer.freeMemory() .. " bytes") gpu.set(3, 7, "Esc ou [X] fecha") end local function drawAbout() drawWindowFrame("Sobre") paint(nil, C.txt) gpu.set(3, 4, "MiniOS 0.2 - GUI de teste") gpu.set(3, 5, "Rodando no OpenComputers Sim") gpu.set(3, 7, "Feito em Lua 5.3 (Luau)") end -- Snake: setas mudam a direcao, R reinicia quando perde local snake = {} local function snakeFree(x, y) for _, b in ipairs(snake.body) do if b.x == x and b.y == y then return false end end return true end local function placeFood() for _ = 1, 500 do local x, y = math.random(2, W - 1), math.random(3, H - 1) if snakeFree(x, y) then snake.food = {x = x, y = y} return end end end local function startSnake() snake = {body = {{x = 10, y = 8}, {x = 9, y = 8}, {x = 8, y = 8}}, dx = 1, dy = 0, score = 0, over = false} placeFood() end local function stepSnake() if snake.over or not snake.body then return end local h = snake.body[1] local nx, ny = h.x + snake.dx, h.y + snake.dy if nx < 2 or nx > W - 1 or ny < 3 or ny > H - 1 or not snakeFree(nx, ny) then snake.over = true return end table.insert(snake.body, 1, {x = nx, y = ny}) if nx == snake.food.x and ny == snake.food.y then snake.score = snake.score + 1 placeFood() else table.remove(snake.body) end end local function keySnake(chr, code) if snake.over then if chr == 114 or chr == 82 then startSnake() end return end local nd = {[200] = {0, -1}, [208] = {0, 1}, [203] = {-1, 0}, [205] = {1, 0}} local d = nd[code] if d and not (d[1] == -snake.dx and d[2] == -snake.dy) then snake.dx, snake.dy = d[1], d[2] end end local function drawSnake() drawWindowFrame("Snake pontos: " .. (snake.score or 0)) if not snake.body then return end paint(nil, C.err) gpu.set(snake.food.x, snake.food.y, "*") paint(nil, C.ok) for _, b in ipairs(snake.body) do gpu.set(b.x, b.y, "#") end if snake.over then paint(nil, C.err) gpu.set(math.max(2, math.floor(W / 2) - 10), math.floor(H / 2), "GAME OVER - R reinicia") end end apps = { {name = "Terminal", draw = drawTerminal, open = function() line = "" end}, {name = "Snake", draw = drawSnake, open = startSnake, tick = stepSnake, key = keySnake}, {name = "Uptime", draw = drawUptime}, {name = "Sobre", draw = drawAbout}, } local current = nil local function drawDesk() paint(C.bg, C.txt) gpu.fill(1, 1, W, H, " ") for i, a in ipairs(apps) do local x, y = iconPos(i) paint(i == sel and C.sel or C.win, C.txt) gpu.fill(x, y, 10, 3, " ") gpu.set(x + 1, y + 1, a.name:sub(1, 8)) end paint(C.bar, C.dim) gpu.fill(1, H, W, 1, " ") gpu.set(2, H, "MiniOS 0.2 | clique ou setas + Enter | Esc fecha app") paint(C.bg, C.txt) end function iconPos(i) return 4 + ((i - 1) % 4) * 16, 4 + math.floor((i - 1) / 4) * 5 end local function redraw() if current then current.draw() else drawDesk() end end local function openApp(i) current = apps[i] if current.open then current.open() end redraw() end local function closeApp() current = nil redraw() end local function hitIcon(col, row) for i = 1, #apps do local x, y = iconPos(i) if col >= x and col < x + 10 and row >= y and row < y + 3 then return i end end end while true do redraw() local tickRate = (current and current.tick) and 0.15 or nil local e, _, a, b, c, d = computer.pullSignal(tickRate) if e == nil and current and current.tick then current.tick() elseif e == "touch" then local col, row = a, b if current then if row == 1 and col >= W - 3 then closeApp() end else local i = hitIcon(col, row) if i then sel = i openApp(i) end end elseif e == "key_down" then local chr, code = a, b if current then if code == 1 then closeApp() elseif current.key then current.key(chr, code) elseif current == apps[1] then if code == 28 then evalLine(line) line = "" elseif code == 14 then line = line:sub(1, -2) elseif chr and chr >= 32 then line = line .. utf8.char(chr) end end else if code == 203 then sel = math.max(1, sel - 1) elseif code == 205 then sel = math.min(#apps, sel + 1) elseif code == 200 then sel = math.max(1, sel - 4) elseif code == 208 then sel = math.min(#apps, sel + 4) elseif code == 28 then openApp(sel) end end end end ]==]) seed(dB, "/readme.txt", "Segundo disco com outro /init.lua.\n") do local hdd = mk("Frame", {Size = UDim2.new(0.8, 0, 0, 220), AnchorPoint = Vector2.new(0.5, 0.5), Position = UDim2.new(0.5, 0, 0.5, 0), BackgroundColor3 = T.panel, Visible = false, ZIndex = 40, BorderSizePixel = 0}, gui) mk("UISizeConstraint", {MaxSize = Vector2.new(360, 220)}, hdd) mk("UICorner", {CornerRadius = UDim.new(0, 12)}, hdd) mk("UIStroke", {Color = T.accent, Transparency = 0.4}, hdd) mk("TextLabel", {Position = UDim2.fromOffset(12, 8), Size = UDim2.new(1, -24, 0, 24), BackgroundTransparency = 1, Font = Enum.Font.GothamMedium, TextSize = 16, TextColor3 = T.text, TextXAlignment = Enum.TextXAlignment.Left, Text = "Qual sistema?", ZIndex = 41}, hdd) local hddMsg = mk("TextLabel", {Position = UDim2.fromOffset(12, 34), Size = UDim2.new(1, -24, 0, 0), BackgroundTransparency = 1, Font = Enum.Font.Code, TextSize = 13, TextColor3 = Color3.fromRGB(200, 205, 220), TextWrapped = true, TextXAlignment = Enum.TextXAlignment.Left, TextYAlignment = Enum.TextYAlignment.Top, Text = "", ZIndex = 41}, hdd) hddMsg.Size = UDim2.new(1, -24, 0, 60) local function hddClose() hdd.Visible = false end local function hddCreate(label, initSrc, restricted) if #comps >= CPU_MAX_COMPONENTS then hddClose() itemInfo.Text = "Limite de componentes da CPU Tier 3 (" .. CPU_MAX_COMPONENTS .. "). Nao da para adicionar outro disco." return end diskCount += 1 local addr = addDisk((restricted and "RESTRITO" or "HDD") .. diskCount, false, restricted) table.insert(userDisks, addr) seed(disks[addr], "/readme.txt", "Disco criado pelo Item (" .. label .. ").\n") seed(disks[addr], "/init.lua", initSrc) hddClose() itemInfo.Text = label .. " criado (" .. addr:sub(1, 8) .. "). Reinicie para escolher no BIOS." end local function initOf(addr) return disks[addr] and disks[addr].fs.root.c["init.lua"] and disks[addr].fs.root.c["init.lua"].data or "" end local function hddButton(text, y, color) return styled("TextButton", {Position = UDim2.fromOffset(12, y), Size = UDim2.new(1, -24, 0, 36), Text = text, Font = Enum.Font.GothamMedium, TextSize = 14, TextColor3 = T.text, BackgroundColor3 = color or T.btn, BorderSizePixel = 0, ZIndex = 41}, hdd) end local hb1 = hddButton("1 OpenOS-Lite", 96) local hb2 = hddButton("2 MiniOS", 138) local hb3 = hddButton("3 Outro sistema", 180) local hbOK = styled("TextButton", {Position = UDim2.new(1, -92, 1, -40), Size = UDim2.fromOffset(80, 30), Text = "OK", Font = Enum.Font.GothamMedium, TextSize = 14, TextColor3 = T.text, BackgroundColor3 = T.ok, BorderSizePixel = 0, Visible = false, ZIndex = 42}, hdd) local hbCancel = styled("TextButton", {Position = UDim2.new(0, 12, 1, -40), Size = UDim2.fromOffset(80, 30), Text = "Cancelar", Font = Enum.Font.GothamMedium, TextSize = 14, TextColor3 = T.text, BackgroundColor3 = T.bad, BorderSizePixel = 0, ZIndex = 41}, hdd) local function setWarn(on) hbOK.Visible = on hb1.Visible, hb2.Visible, hb3.Visible = not on, not on, not on end hddOpen = function() hddMsg.Text = "Escolha o sistema que vai no novo disco:" setWarn(false) hdd.Visible = true end hb1.MouseButton1Click:Connect(function() hddCreate("OpenOS-Lite", initOf(diskA)) end) hb2.MouseButton1Click:Connect(function() hddCreate("MiniOS", initOf(diskB)) end) hb3.MouseButton1Click:Connect(function() hddMsg.Text = "AVISO: sistemas de fora podem conter codigo malicioso (roubar conta, senha ou cookie). Este simulador NAO baixa nem roda nada da internet. Se quiser usar um sistema de outra pessoa, abra o codigo, leia tudo e copie com 'edit'. Nunca rode codigo que peca senha ou acesso ao Roblox." setWarn(true) end) hbOK.MouseButton1Click:Connect(function() hddCreate("Sistema nao oficial (restrito)", "-- Sistema nao oficial e RESTRITO: nao pode ser editado nem apagado pelo simulador.\nlocal gpu = component.proxy(component.list('gpu')())\ngpu.bind(component.list('screen')())\nlocal W, H = gpu.maxResolution()\ngpu.setResolution(W, H)\ngpu.fill(1, 1, W, H, ' ')\ngpu.set(2, 2, 'Sistema nao oficial (restrito)')\nwhile true do computer.pullSignal() end\n", true) setWarn(false) end) hbCancel.MouseButton1Click:Connect(hddClose) local pendingDel = false local itemDel = styled("TextButton", { Position = UDim2.new(1, -212, 1, -36), Size = UDim2.fromOffset(70, 30), Text = "Excluir HDD", Font = Enum.Font.GothamMedium, TextSize = 11, TextColor3 = T.text, BackgroundColor3 = T.bad, BorderSizePixel = 0, ZIndex = 31, }, itemPanel) itemInfo.Size = UDim2.new(1, -290, 0, 30) itemDel.MouseButton1Click:Connect(function() if M.state ~= "off" then pendingDel = false itemInfo.Text = "Desligue o computador antes de excluir um disco." return end if #userDisks == 0 then pendingDel = false itemInfo.Text = "Nenhum HDD criado pelo Item para excluir." return end if not pendingDel then pendingDel = true itemInfo.Text = "Toque em Excluir HDD de novo para confirmar (o ultimo HDD criado)." return end pendingDel = false local addr = table.remove(userDisks) for i, c in ipairs(comps) do if c.addr == addr then table.remove(comps, i) break end end byAddr[addr] = nil disks[addr] = nil itemInfo.Text = "HDD excluido (" .. addr:sub(1, 8) .. ")." refreshItems() end) local driveLabel = "Unidade de disco" local driveFloppy = nil -- endereco do disquete que esta dentro da unidade local lastEjected = nil -- ultimo disquete ejetado (pode ser colocado de volta) local floppyComp = {} -- addr -> registro do componente, guardado enquanto esta ejetado local floppyCount = 0 local function removeComp(addr) for i, c in ipairs(comps) do if c.addr == addr then table.remove(comps, i) byAddr[addr] = nil return c end end end local function restoreComp(c) table.insert(comps, c) byAddr[c.addr] = c end local driveM = { isEmpty = function() return driveFloppy == nil end, getLabel = function() return driveLabel end, setLabel = function(l) driveLabel = tostring(l) return driveLabel end, media = function() return driveFloppy end, eject = function() if not driveFloppy then return false, "unidade vazia" end local c = removeComp(driveFloppy) if c then floppyComp[driveFloppy] = c end lastEjected, driveFloppy = driveFloppy, nil return true end, insert = function() if driveFloppy then return false, "ja tem disquete" end local c = lastEjected and floppyComp[lastEjected] if not c then return false, "nenhum disquete para inserir" end if #comps >= CPU_MAX_COMPONENTS then return false, "limite de componentes" end restoreComp(c) driveFloppy, lastEjected = lastEjected, nil return true end, } local adapterLbl, adapterBB = nil, nil local adapterM = { getName = function() return "oc_sim_adapter" end, setLed = function(c) local v = math.floor(tonumber(c) or 0) % 0x1000000 setLed(Color3.fromRGB(math.floor(v / 65536) % 256, math.floor(v / 256) % 256, v % 256)) return true end, say = function(text) if not adapterBB then adapterBB = mk("BillboardGui", {Size = UDim2.fromOffset(240, 40), StudsOffset = Vector3.new(0, 3, 0), AlwaysOnTop = true}, case) adapterLbl = mk("TextLabel", {Size = UDim2.fromScale(1, 1), BackgroundTransparency = 0.3, BackgroundColor3 = Color3.new(0, 0, 0), Font = Enum.Font.Code, TextSize = 13, TextColor3 = T.text, TextWrapped = true}, adapterBB) end adapterLbl.Text = tostring(text):sub(1, 80) return true end, clear = function() if adapterBB then adapterBB:Destroy() adapterBB, adapterLbl = nil, nil end return true end, } installDrive = function(name) if isPresent("disk_drive") then itemInfo.Text = name .. " ja esta instalada." return end local ok, err = pcall(addComp, "disk_drive", driveM) itemInfo.Text = ok and (name .. " instalada no computador.") or tostring(err) end installAdapter = function(name) if isPresent("adapter") then itemInfo.Text = name .. " ja esta instalado." return end local ok, err = pcall(addComp, "adapter", adapterM) itemInfo.Text = ok and (name .. " instalado. Use component.adapter.say('oi').") or tostring(err) end makeFloppy = function() if not isPresent("disk_drive") then itemInfo.Text = "Instale a Unidade de disco primeiro." return end if driveFloppy then itemInfo.Text = "A unidade ja tem disquete. Ejete antes." return end floppyCount += 1 local ok, addr = pcall(addDisk, "FLOPPY" .. floppyCount, false, false) if not ok then itemInfo.Text = tostring(addr) return end driveFloppy = addr itemInfo.Text = "Disquete FLOPPY" .. floppyCount .. " colocado na unidade." end end local _, dGui = addDisk("GUIOS") seed(dGui, "/init.lua", [==[ -- GUIOS 1.0 (/init.lua do disco GUIOS): janelas, clique e teclado local gpu = component.proxy(component.list("gpu")()) gpu.bind(component.list("screen")()) local W, H = gpu.maxResolution() gpu.setResolution(W, H) local C = {bg = 0x1E2A3A, bar = 0x2F4A6B, bar2 = 0x3C6A99, win = 0x26354A, txt = 0xFFFFFF, dim = 0x9FB3CC, ok = 0x77FFAA, err = 0xFF6B6B, btn = 0x3A5577, key = 0xFFCC33} local function fill(x, y, w, h, bg) gpu.setBackground(bg) gpu.fill(x, y, w, h, " ") end local function txt(x, y, s, fg, bg) if bg then gpu.setBackground(bg) end gpu.setForeground(fg or C.txt) gpu.set(x, y, tostring(s)) end local windows = {} local focus = nil local function raise(win) for i, w in ipairs(windows) do if w == win then table.remove(windows, i) break end end table.insert(windows, win) focus = win end local function newWindow(title, x, y, w, h, app) local win = {title = title, x = x, y = y, w = w, h = h, app = app} table.insert(windows, win) raise(win) if app.init then app.init(win) end end local function closeWin(win) for i, w in ipairs(windows) do if w == win then table.remove(windows, i) break end end focus = windows[#windows] end ------------------------------------------------ APPS local notesApp = { init = function(win) win.lines = {""} end, draw = function(win) local maxRows = win.h - 2 local start = math.max(1, #win.lines - maxRows + 1) local row = 0 for i = start, #win.lines do row = row + 1 local s = win.lines[i] if i == #win.lines and win == focus then s = s .. "_" end txt(win.x + 1, win.y + row, s:sub(1, win.w - 2), C.txt, C.win) end end, key = function(win, chr, code) local L = win.lines if code == 28 then table.insert(L, "") elseif code == 14 then if #L[#L] > 0 then L[#L] = L[#L]:sub(1, -2) elseif #L > 1 then table.remove(L) end elseif chr and chr >= 32 then L[#L] = L[#L] .. utf8.char(chr) end end, } local CALC = {{"7", "8", "9", "/"}, {"4", "5", "6", "*"}, {"1", "2", "3", "-"}, {"0", ".", "=", "+"}} local function calcEval(win) if not win.op or not win.acc then return end local b = tonumber(win.disp) or 0 local a = win.acc local r if win.op == "+" then r = a + b elseif win.op == "-" then r = a - b elseif win.op == "*" then r = a * b else r = b ~= 0 and a / b or 0 end if r == math.floor(r) then win.disp = tostring(math.floor(r)) else win.disp = tostring(r) end win.acc, win.op = nil, nil end local function calcPress(win, k) if k == "C" then win.disp, win.acc, win.op, win.new = "0", nil, nil, true elseif k:match("%d") or k == "." then if win.new then win.disp = (k == ".") and "0." or k win.new = false elseif #win.disp < 12 then win.disp = win.disp .. k end elseif k == "=" then calcEval(win) win.new = true else if win.op then calcEval(win) end win.acc = tonumber(win.disp) or 0 win.op = k win.new = true end end local calcApp = { init = function(win) win.disp, win.new = "0", true end, draw = function(win) fill(win.x + 1, win.y + 1, win.w - 2, 1, C.bg) txt(win.x + 2, win.y + 1, win.disp:sub(-(win.w - 4)), C.ok, C.bg) for r, row in ipairs(CALC) do for c, label in ipairs(row) do local bx, by = win.x + 1 + (c - 1) * 5, win.y + 3 + (r - 1) * 2 fill(bx, by, 4, 1, C.btn) txt(bx + 1, by, label, C.txt, C.btn) end end local cy = win.y + 3 + 4 * 2 fill(win.x + 1, cy, win.w - 2, 1, C.err) txt(win.x + 2, cy, "C (limpar)", C.txt, C.err) end, touch = function(win, col, row) if row == win.y + 3 + 4 * 2 then return calcPress(win, "C") end for r, rowT in ipairs(CALC) do for c, label in ipairs(rowT) do local bx, by = win.x + 1 + (c - 1) * 5, win.y + 3 + (r - 1) * 2 if row == by and col >= bx and col < bx + 4 then return calcPress(win, label) end end end end, key = function(win, chr, code) local ch = chr and chr >= 32 and utf8.char(chr) or "" if code == 28 then calcPress(win, "=") elseif ch:match("%d") or ch == "." or ch == "+" or ch == "-" or ch == "*" or ch == "/" then calcPress(win, ch) elseif ch == "c" or ch == "C" then calcPress(win, "C") end end, } local aboutApp = { draw = function(win) txt(win.x + 2, win.y + 2, "GUIOS 1.0", C.key, C.win) txt(win.x + 2, win.y + 3, "Tempo ligado: " .. math.floor(computer.uptime()) .. " s", C.txt, C.win) txt(win.x + 2, win.y + 4, "Tab troca de janela", C.dim, C.win) txt(win.x + 2, win.y + 5, "Esc fecha a janela", C.dim, C.win) end, } local icons = { {name = "Notas", open = function() newWindow("Notas", 4, 4, 40, 14, notesApp) end}, {name = "Calculadora", open = function() newWindow("Calculadora", 30, 6, 24, 15, calcApp) end}, {name = "Sobre", open = function() newWindow("Sobre", 12, 12, 40, 7, aboutApp) end}, } local function iconPos(i) return 3 + (i - 1) * 14, 2 end ------------------------------------------------ DESENHO local function redraw() fill(1, 1, W, H, C.bg) for i, ic in ipairs(icons) do local x, y = iconPos(i) fill(x, y, 12, 3, C.btn) txt(x + 1, y + 1, ic.name:sub(1, 10), C.txt, C.btn) end for _, w in ipairs(windows) do local f = (w == focus) fill(w.x, w.y, w.w, w.h, C.win) fill(w.x, w.y, w.w, 1, f and C.bar2 or C.bar) txt(w.x + 1, w.y, w.title:sub(1, w.w - 6), C.txt, f and C.bar2 or C.bar) txt(w.x + w.w - 4, w.y, "[X]", C.err, f and C.bar2 or C.bar) if w.app.draw then w.app.draw(w) end end fill(1, H, W, 1, C.bar) txt(2, H, "GUIOS | clique para abrir | Tab: trocar | Esc: fechar", C.dim, C.bar) end ------------------------------------------------ ENTRADA local function onTouch(col, row) for i = #windows, 1, -1 do local w = windows[i] if col >= w.x and col <= w.x + w.w - 1 and row >= w.y and row <= w.y + w.h - 1 then if row == w.y and col >= w.x + w.w - 4 and col <= w.x + w.w - 2 then return closeWin(w) end raise(w) if row > w.y and w.app.touch then w.app.touch(w, col, row) end return end end for i, ic in ipairs(icons) do local x, y = iconPos(i) if col >= x and col < x + 12 and row >= y and row < y + 3 then return ic.open() end end end while true do redraw() local e, _, a, b = computer.pullSignal() if e == "touch" then onTouch(a, b) elseif e == "key_down" then local chr, code = a, b if code == 1 and focus then closeWin(focus) elseif code == 15 and #windows > 1 then raise(windows[1]) elseif focus and focus.app.key then focus.app.key(focus, chr, code) end end end ]==]) print("[OC Sim v4] pronto. Toque no gabinete ou em Power. Dois /init.lua = menu no BIOS.")