Upload System Image

This commit is contained in:
Bommels05 2025-10-21 00:40:14 +02:00
parent 16da0a1837
commit acf66baf57
56 changed files with 28248 additions and 61 deletions

221
LevelOS/Changelog.lua Normal file
View File

@ -0,0 +1,221 @@
if LevelOS and LevelOS.self and LevelOS.self.window then
LevelOS.self.window.winMode = "widget"
end
local oldlog = lUtils.asset.load("LevelOS/data/nativelog.lconf") or {}
local newlog = lUtils.asset.load("LevelOS/data/changelog.lconf")
if newlog then
fs.delete("LevelOS/data/nativelog.lconf")
fs.move("LevelOS/data/changelog.lconf","LevelOS/data/nativelog.lconf")
elseif oldlog then
newlog = oldlog
end
local run = false
for c=1,#newlog do
if not oldlog[c] then
newlog[c].new = true
run = true
end
end
local txt = term.setTextColor
local bg = term.setBackgroundColor
local function clr()
local w,h = term.getSize()
local x,y = term.getCursorPos()
term.setCursorPos(19,y)
term.write(string.rep(" ",w-21))
term.setCursorPos(x,y)
end
local function wr(text,color,mX,mY) --max x and y
if color then
txt(color)
end
local x,y = term.getCursorPos()
local cX = x
local cY = y
for word in text:gmatch("%S+") do
--[[if cX ~= x then
word = " "..word
end]]
if cX+#word <= mX then
term.write(word.." ")
cX = cX+#word+1
elseif cY < mY then
cX = x
cY = cY+1
term.setCursorPos(cX,cY)
clr()
term.write(word.." ")
cX = cX+#word+1
else
return (cY-y)+1
end
end
return (cY-y)+1
end
local function rm() -- reached max
local x,y = term.getCursorPos()
local w,h = term.getSize()
if y >= h then
return true
else
return false
end
end
function render(s)
local function cp(x,y)
term.setCursorPos(x,y+s)
end
bg(colors.cyan)
term.clear()
txt(colors.cyan)
bg(colors.white)
local w,h = term.getSize()
for t=0,h-s do
cp(14,4+t)
term.write("\149")
end
-- write with window height as max Y and width-4 as max X
local cY = 1
for k=#newlog,1,-1 do
local v = newlog[k]
cY = cY+2
-- the date
cp(2,cY+1)
bg(colors.cyan)
txt(colors.white)
term.write(v.date)
cp(13,cY)
-- cyan = 9, white = 0, lime=5
-- the dot
if k == #newlog then -- to check if its on top (for the line)
term.blit("\159\143\143","999","000")
else
term.blit("\159\133\143","999","000")
end
cp(13,cY+1)
if v.major then -- if major version make orange dot
term.blit("\149 \149","911","010")
else
term.blit("\149 \149","955","050")
end
cp(13,cY+2)
term.blit("\130\148\131","090","909")
-- the actual box
bg(colors.white)
txt(colors.cyan)
cp(19,cY)
clr()
--term.write("\151\129")
term.write("\129")
cp(w-3,cY)
term.write("\130")
--term.blit("\148","0","9")
--[[cY = cY+1
cp(19,cY)
clr()]]
cY = cY+1
cp(18,cY)
clr()
term.write("\145 ")
term.write("v"..v.version)
if v.new then
txt(colors.orange)
term.write(" New!")
end
cY = cY+1
cp(19,cY)
clr()
cY = cY+1
cp(20,cY)
clr()
if v.description then
cY = cY-1
cp(21,cY)
bg(colors.white)
txt(colors.black)
cY = cY+wr(v.description,nil,w-4,h)
cp(20,cY)
clr()
cY = cY+1
cp(20,cY)
clr()
end
if v.added and #v.added > 0 then
bg(colors.lime)
txt(colors.white)
term.write(" NEW ")
cY = cY+1
bg(colors.white)
cp(19,cY)
clr()
cY = cY+1
txt(colors.black)
for t=1,#v.added do
cp(21,cY)
clr()
term.write("\7 ")
cY = cY+wr(v.added[t],nil,w-4,h)
end
cp(20,cY)
clr()
end
if v.fixed and #v.fixed > 0 then
if v.added and #v.added > 0 then
cY = cY+1
cp(20,cY)
clr()
end
bg(colors.lightBlue)
txt(colors.white)
term.write(" FIXED ")
cY = cY+1
bg(colors.white)
cp(19,cY)
clr()
cY = cY+1
txt(colors.black)
for t=1,#v.fixed do
cp(21,cY)
clr()
term.write("\7 ")
cY = cY+wr(v.fixed[t],nil,w-4,h)
end
end
bg(colors.white)
txt(colors.cyan)
cp(19,cY)
clr()
cY = cY+1
cp(19,cY)
clr()
term.write("\144")
cp(w-3,cY)
term.blit("\159","0","9")
if rm() then break end
end
term.setCursorPos(1,1)
bg(colors.cyan)
txt(colors.white)
term.clearLine()
term.setCursorPos(2,1)
term.write("Changelog")
term.setCursorPos(w-2,1)
term.write("×")
end
render(0)
local scroll = 0
while true do
local e = {os.pullEvent()}
local w,h = term.getSize()
if e[1] == "term_resize" then
render(scroll)
elseif e[1] == "mouse_scroll" and scroll-e[2] <= 0 then
scroll = scroll-e[2]
render(scroll)
elseif e[1] == "mouse_up" and e[3] == w-2 and e[4] == 1 then
return
end
end

897
LevelOS/Clock.lua Normal file
View File

@ -0,0 +1,897 @@
local assets = {
[ "slider.lua" ] = {
id = 1,
content = "local s = shapescape.getSlide()\
if not s.var then s.var = {} end\
\
local set = \"LevelOS/data/settings.lconf\"\
\
if lOS.settings.rTime == nil then\
lOS.settings.rTime = false\
end\
\
local r = string.rep\
\
local rtime = lOS.settings.rTime\
\
local w,h = term.getSize()\
\
if rtime then\
term.setBackgroundColor(colors.green)\
term.setCursorPos(1,1)\
term.write(r(\" \",w-1))\
term.setBackgroundColor(colors.white)\
term.write(\" \")\
else\
term.setCursorPos(1,1)\
term.setBackgroundColor(colors.white)\
term.write(\" \")\
term.setBackgroundColor(colors.red)\
term.write(r(\" \",w-1))\
end\
\
while true do\
local w,h = term.getSize()\
if lOS.settings.rTime ~= rtime then\
rtime = lOS.settings.rTime\
local b1,b2,fg\
b1 = \"d\"\
b2 = \"e\"\
fg = \"0\"\
local a,b,c\
if rtime then\
a,b,c = 1,w,1\
else\
a,b,c = w,1,-1\
end\
for x=a,b,c do\
local d,e = x-1,w-x\
term.setCursorPos(1,1)\
term.blit(r(\" \",d)..\" \"..r(\" \",e),r(\"f\",w),r(b1,d)..fg..r(b2,e))\
os.sleep(0.05)\
end\
end\
e = {os.pullEvent()}\
end",
name = "slider.lua",
},
[ "switch_time.lua" ] = {
id = 2,
content = "lOS.settings.rTime = not lOS.settings.rTime",
name = "switch_time.lua",
},
[ "rendercalender.lua" ] = {
id = 7,
content = "local w,h = term.getSize()\
while h < 21 do\
os.pullEvent()\
w,h = term.getSize()\
end\
local epoch = os.epoch(\"local\")/1000\
local date = os.date(\"*t\",epoch)\
local targetmonth = date.month\
local targetyear = date.year\
local d = {}\
d.sec = 1\
d.min = d.sec*60\
d.hour = d.min*60\
d.day = d.hour*24\
local function dayadd()\
epoch = epoch+d.day\
date = os.date(\"*t\",epoch)\
end\
local function daysub()\
epoch = epoch-d.day\
date = os.date(\"*t\",epoch)\
end\
while date.year < targetyear or date.month < targetmonth do\
dayadd()\
end\
term.setBackgroundColor(colors.gray)\
term.setTextColor(colors.white)\
term.clear()\
term.setCursorPos(1,1)\
term.write(os.date(\"%B %Y\"))\
term.setCursorPos(1,3)\
days = {\"Mo\",\"Tu\",\"We\",\"Th\",\"Fr\",\"Sa\",\"Su\"}\
for t=1,7 do\
term.write(\" \"..days[t]..\" \")\
end\
local x = term.getCursorPos()\
term.setCursorPos(x-3,1)\
--LevelOS.setWin(x-1,24)\
term.write(\"\\30 \\31\")\
while date.day > 1 do\
daysub()\
end\
while date.wday ~= 2 do\
daysub()\
end\
local current = os.date(\"*t\")\
for w=1,6 do\
--term.setCursorPos(1,5+(w-1)*3)\
for t=1,7 do\
local x,y = 1+(t-1)*4,5+(w-1)*3\
local cur = false\
if current.day == date.day and current.month == date.month and current.year == date.year then\
term.setTextColor(colors.black)\
term.setBackgroundColor(colors.lightGray)\
lUtils.border(x,y-1,x+3,y+1)\
cur = true\
else\
term.setBackgroundColor(colors.gray)\
end\
if targetmonth == date.month then\
term.setTextColor(colors.white)\
elseif cur then\
term.setTextColor(colors.gray)\
else\
term.setTextColor(colors.lightGray)\
end\
term.setCursorPos(x+1,y)\
term.write(os.date(\"%d\",epoch))\
dayadd()\
end\
end\
while true do os.pullEvent() end",
name = "rendercalender.lua",
},
[ "offset.lua" ] = {
id = 3,
content = "if lOS.settings.timeOffset then\
local o = lOS.settings.timeOffset\
if o >= 0 then\
self.txt = \"+\"..o\
else\
self.txt = tostring(o)\
end\
end",
name = "offset.lua",
},
[ "offset_up.lua" ] = {
id = 5,
content = "lOS.settings.timeOffset = lOS.settings.timeOffset + 0.5",
name = "offset_up.lua",
},
[ "time.lua" ] = {
id = 0,
content = "if not lOS.settings.timeOffset then\
lOS.settings.timeOffset = 0\
end\
local t = os.date(\"*t\",os.epoch(\"utc\")/1000+lOS.settings.timeOffset*3600)\
term.setBackgroundColor(colors.gray)\
term.setTextColor(colors.white)\
term.setCursorPos(self.x1,self.y1)\
local function tz(n)\
return string.rep(\"0\",2-string.len(n))..n\
end\
if lOS.settings.rTime then\
bigfont.bigPrint(tz(t.hour)..\":\"..tz(t.min)..\":\"..tz(t.sec))\
else\
local nTime = (os.time()+lOS.settings.timeOffset)%24\
local nHour = math.floor(nTime)\
local nMinute = math.floor((nTime - nHour) * 60)\
bigfont.bigPrint(tz(nHour)..\":\"..tz(nMinute))\
end\
term.setTextColor(colors.lightGray)\
local days = {\"Sunday\",\"Monday\",\"Tuesday\",\"Wednesday\",\"Thursday\",\"Friday\",\"Saturday\"}\
local months = {\"Jan\",\"Feb\",\"Mar\",\"Apr\",\"May\",\"Jun\",\"Jul\",\"Aug\",\"Sep\",\"Oct\",\"Nov\",\"Dec\"}\
term.setCursorPos(self.x1,({term.getCursorPos()})[2])\
print(days[t.wday]..\", \"..months[t.month]..\" \"..t.day..\", \"..t.year)",
name = "time.lua",
},
[ "init.lua" ] = {
id = 4,
content = "local w,h = 27,13\
local tw,th = lOS.wAll.getSize()\
if th >= 40 then\
w,h = 32,36\
end\
LevelOS.setWin(w,h,\"widget\")\
LevelOS.self.window.win.reposition(tw-w,th-(h-1+lOS.tbSize))",
name = "init.lua",
},
[ "offset_down.lua" ] = {
id = 6,
content = "lOS.settings.timeOffset = lOS.settings.timeOffset - 0.5",
name = "offset_down.lua",
},
}
local nAssets = {}
for key,value in pairs(assets) do nAssets[key] = value nAssets[assets[key].id] = assets[key] end
assets = nAssets
nAssets = nil
local slides = {
{
y = 21,
x = 61,
h = 19,
w = 51,
objs = {
{
x2 = 51,
y2 = 19,
y1 = 1,
x1 = 1,
type = "rect",
event = {
mouse_up = {
[ 2 ] = -1,
},
mouse_click = {
[ 2 ] = -1,
},
Initialize = {
[ 2 ] = -1,
},
selected = {
[ 2 ] = -1,
},
update = {
[ 2 ] = -1,
},
Coroutine = {
[ 2 ] = 4,
},
},
ox2 = 0,
color = 128,
border = {
color = 256,
type = 1,
},
snap = {
Top = "Snap top",
Right = "Snap right",
Left = "Snap left",
Bottom = "Snap bottom",
},
oy2 = 0,
},
{
x2 = 26,
y2 = 4,
border = {
color = 128,
type = 1,
},
x1 = 3,
txt = "",
type = "text",
event = {
mouse_up = {
[ 2 ] = -1,
},
mouse_click = {
[ 2 ] = -1,
},
render = {
[ 2 ] = 0,
},
selected = {
[ 2 ] = -1,
},
update = {
[ 2 ] = -1,
},
Coroutine = {
[ 2 ] = -1,
},
},
txtcolor = 1,
color = 128,
snap = {
Top = "Snap top",
Right = "Snap left",
Left = "Snap left",
Bottom = "Snap top",
},
y1 = 2,
},
{
x2 = 50,
y2 = 8,
y1 = 7,
x1 = 2,
type = "rect",
event = {
mouse_up = {
[ 2 ] = -1,
},
mouse_click = {
[ 2 ] = -1,
},
Initialize = {
[ 2 ] = -1,
},
selected = {
[ 2 ] = -1,
},
update = {
[ 2 ] = -1,
},
Coroutine = {
[ 2 ] = -1,
},
},
ox2 = 1,
color = 128,
snap = {
Top = "Snap top",
Right = "Snap right",
Left = "Snap left",
Bottom = "Snap top",
},
border = {
color = 256,
type = 1,
},
},
{
x2 = 50,
y2 = 8,
y1 = 8,
x1 = 2,
type = "rect",
event = {
mouse_up = {
[ 2 ] = -1,
},
mouse_click = {
[ 2 ] = -1,
},
Initialize = {
[ 2 ] = -1,
},
selected = {
[ 2 ] = -1,
},
update = {
[ 2 ] = -1,
},
Coroutine = {
[ 2 ] = -1,
},
},
ox2 = 1,
color = 128,
snap = {
Top = "Snap top",
Right = "Snap right",
Left = "Snap left",
Bottom = "Snap top",
},
border = {
color = 0,
type = 1,
},
},
{
type = "rect",
color = 128,
y2 = 7,
y1 = 7,
x1 = 2,
x2 = 2,
border = {
color = 0,
type = 1,
},
snap = {
Top = "Snap top",
Right = "Snap left",
Left = "Snap left",
Bottom = "Snap top",
},
event = {
mouse_up = {
[ 2 ] = -1,
},
mouse_click = {
[ 2 ] = -1,
},
Initialize = {
[ 2 ] = -1,
},
selected = {
[ 2 ] = -1,
},
update = {
[ 2 ] = -1,
},
Coroutine = {
[ 2 ] = -1,
},
},
},
{
x2 = 50,
y2 = 7,
y1 = 7,
x1 = 50,
ox1 = 1,
type = "rect",
event = {
mouse_up = {
[ 2 ] = -1,
},
mouse_click = {
[ 2 ] = -1,
},
Initialize = {
[ 2 ] = -1,
},
selected = {
[ 2 ] = -1,
},
update = {
[ 2 ] = -1,
},
Coroutine = {
[ 2 ] = -1,
},
},
ox2 = 1,
color = 128,
snap = {
Top = "Snap top",
Right = "Snap right",
Left = "Snap right",
Bottom = "Snap top",
},
border = {
color = 0,
type = 1,
},
},
{
color = 128,
y2 = 8,
y1 = 8,
x1 = 11,
txt = "Use real time",
type = "text",
event = {
mouse_up = {
[ 2 ] = -1,
},
mouse_click = {
[ 2 ] = -1,
},
Initialize = {
[ 2 ] = -1,
},
selected = {
[ 2 ] = -1,
},
update = {
[ 2 ] = -1,
},
Coroutine = {
[ 2 ] = -1,
},
},
txtcolor = 1,
input = false,
x2 = 23,
border = {
color = 0,
type = 1,
},
},
{
color = 1,
y2 = 12,
y1 = 10,
x1 = 3,
txt = "+0",
type = "text",
event = {
mouse_up = {
[ 2 ] = -1,
},
mouse_click = {
[ 2 ] = -1,
},
Initialize = {
[ 2 ] = -1,
},
selected = {
[ 2 ] = -1,
},
update = {
[ 2 ] = 3,
},
Coroutine = {
[ 2 ] = -1,
},
},
txtcolor = 32768,
input = false,
x2 = 9,
border = {
color = 256,
type = 1,
},
},
{
x2 = 9,
y2 = 10,
y1 = 10,
x1 = 3,
txt = " ",
type = "text",
event = {
mouse_up = {
[ 2 ] = 5,
},
mouse_click = {
[ 2 ] = -1,
},
Initialize = {
[ 2 ] = -1,
},
selected = {
[ 2 ] = -1,
},
update = {
[ 2 ] = -1,
},
Coroutine = {
[ 2 ] = -1,
},
},
txtcolor = 1,
input = false,
color = 256,
snap = {
Top = "Snap top",
Right = "Snap left",
Left = "Snap left",
Bottom = "Snap top",
},
border = {
color = 0,
type = 1,
},
},
{
color = 256,
y2 = 12,
y1 = 12,
x1 = 3,
txt = " ",
type = "text",
event = {
mouse_up = {
[ 2 ] = 6,
},
mouse_click = {
[ 2 ] = -1,
},
Initialize = {
[ 2 ] = -1,
},
selected = {
[ 2 ] = -1,
},
update = {
[ 2 ] = -1,
},
Coroutine = {
[ 2 ] = -1,
},
},
txtcolor = 1,
input = false,
x2 = 9,
border = {
color = 0,
type = 1,
},
},
{
color = 128,
y2 = 11,
y1 = 11,
x1 = 11,
txt = "Offset (hours)",
type = "text",
event = {
mouse_up = {
[ 2 ] = -1,
},
mouse_click = {
[ 2 ] = -1,
},
Initialize = {
[ 2 ] = -1,
},
selected = {
[ 2 ] = -1,
},
update = {
[ 2 ] = -1,
},
Coroutine = {
[ 2 ] = -1,
},
},
txtcolor = 1,
input = false,
x2 = 26,
border = {
color = 0,
type = 1,
},
},
{
type = "window",
color = 32768,
y2 = 8,
border = {
color = 0,
type = 1,
},
x1 = 3,
y1 = 8,
x2 = 9,
snap = {
Top = "Snap top",
Right = "Snap left",
Left = "Snap left",
Bottom = "Snap top",
},
event = {
mouse_up = {
[ 2 ] = 2,
},
mouse_click = {
[ 2 ] = -1,
},
Initialize = {
[ 2 ] = -1,
},
selected = {
[ 2 ] = -1,
},
update = {
[ 2 ] = -1,
},
Coroutine = {
[ 2 ] = 1,
},
},
},
{
color = 128,
y2 = 15,
border = {
color = 256,
type = 1,
},
x1 = 2,
type = "rect",
event = {
mouse_up = {
[ 2 ] = -1,
},
mouse_click = {
[ 2 ] = -1,
},
Initialize = {
[ 2 ] = -1,
},
selected = {
[ 2 ] = -1,
},
update = {
[ 2 ] = -1,
},
Coroutine = {
[ 2 ] = -1,
},
},
ox2 = 1,
x2 = 50,
snap = {
Top = "Snap top",
Right = "Snap right",
Left = "Snap left",
Bottom = "Snap top",
},
y1 = 14,
},
{
type = "rect",
x2 = 2,
y2 = 14,
border = {
color = 0,
type = 1,
},
x1 = 2,
color = 128,
y1 = 14,
snap = {
Top = "Snap top",
Right = "Snap left",
Left = "Snap left",
Bottom = "Snap top",
},
event = {
mouse_up = {
[ 2 ] = -1,
},
mouse_click = {
[ 2 ] = -1,
},
Initialize = {
[ 2 ] = -1,
},
selected = {
[ 2 ] = -1,
},
update = {
[ 2 ] = -1,
},
Coroutine = {
[ 2 ] = -1,
},
},
},
{
color = 128,
y2 = 14,
border = {
color = 0,
type = 1,
},
x1 = 50,
ox1 = 1,
type = "rect",
event = {
mouse_up = {
[ 2 ] = -1,
},
mouse_click = {
[ 2 ] = -1,
},
Initialize = {
[ 2 ] = -1,
},
selected = {
[ 2 ] = -1,
},
update = {
[ 2 ] = -1,
},
Coroutine = {
[ 2 ] = -1,
},
},
ox2 = 1,
x2 = 50,
snap = {
Top = "Snap top",
Right = "Snap right",
Left = "Snap right",
Bottom = "Snap top",
},
y1 = 14,
},
{
color = 128,
y2 = 15,
border = {
color = 0,
type = 1,
},
x1 = 2,
type = "rect",
event = {
mouse_up = {
[ 2 ] = -1,
},
mouse_click = {
[ 2 ] = -1,
},
Initialize = {
[ 2 ] = -1,
},
selected = {
[ 2 ] = -1,
},
update = {
[ 2 ] = -1,
},
Coroutine = {
[ 2 ] = -1,
},
},
ox2 = 1,
x2 = 50,
snap = {
Top = "Snap top",
Right = "Snap right",
Left = "Snap left",
Bottom = "Snap top",
},
y1 = 15,
},
{
x2 = 49,
y2 = 18,
border = {
color = 0,
type = 1,
},
x1 = 3,
type = "window",
event = {
mouse_up = {
[ 2 ] = -1,
},
mouse_click = {
[ 2 ] = -1,
},
focus = {
[ 2 ] = -1,
},
render = {
[ 2 ] = -1,
},
update = {
[ 2 ] = -1,
},
Coroutine = {
[ 2 ] = 7,
},
},
ox2 = 2,
color = 32768,
y1 = 15,
snap = {
Top = "Snap top",
Right = "Snap right",
Left = "Snap left",
Bottom = "Snap bottom",
},
oy2 = 1,
},
},
c = 1,
},
{
y = 21,
x = 61,
h = 19,
w = 51,
objs = {},
c = 2,
},
}
for s=1,#slides do
local slide = slides[s]
for o=1,#slide.objs do
local obj = slide.objs[o]
for key,value in pairs(obj.event) do
if assets[ value[2] ] then
lUtils.shapescape.addScript(obj,value[2],key,assets,LevelOS,slides)
else
obj.event[key] = {function() end,-1}
end
end
end
end
local tArgs = {...}
if tArgs[1] and tArgs[1] == "load" then
return {assets=assets,slides=slides}
end
lUtils.shapescape.run(slides,...)

2063
LevelOS/Global_Login.lua Normal file

File diff suppressed because it is too large Load Diff

1734
LevelOS/Login_screen.sgui Normal file

File diff suppressed because it is too large Load Diff

124
LevelOS/Notification.lua Normal file
View File

@ -0,0 +1,124 @@
local tArgs = {...}
if not tArgs then return end
local sID = #lOS.notifWins+1
lOS.notifWins[sID] = LevelOS.self.window
local function count(tbl)
local c = 0
for k,v in pairs(tbl) do
c = c+1
end
return c
end
local nAmount = count(lOS.notifWins)
term.setBackgroundColor(colors.gray)
term.clear()
local x,y = 2,2
local icon
if type(tArgs[3]) == "string" and fs.exists(tArgs[3]) and lOS.getIcon then
icon = lOS.getIcon(tArgs[3])
end
if icon then
lUtils.renderImg(icon,x,y)
x = x+4
end
if type(tArgs[1]) == "string" then
term.setCursorPos(x,y)
term.setTextColor(colors.white)
local w,h = term.getSize()
local nw = w-x
local txt = lUtils.wordwrap(tArgs[1],nw-1)
if y+#txt > h then
local dif = y+#txt-h
local wX,wY = LevelOS.self.window.win.getPosition()
wY = wY-dif
h = h+dif
LevelOS.self.window.win.reposition(wX,wY,w,h)
end
for t=1,#txt do
term.setCursorPos(x,y)
term.write(txt[t])
y = y+1
end
end
if type(tArgs[2]) == "string" then
term.setCursorPos(x,y)
term.setTextColor(colors.lightGray)
local w,h = term.getSize()
local nw = w-x
local txt = lUtils.wordwrap(tArgs[2],nw)
if y+#txt > h then
local dif = y+#txt-h
local wX,wY = LevelOS.self.window.win.getPosition()
wY = wY-dif
h = h+dif
LevelOS.self.window.win.reposition(wX,wY,w,h)
end
for t=1,#txt do
term.setCursorPos(x,y)
term.write(txt[t])
y = y+1
end
end
local w,h = term.getSize()
term.setCursorPos(w-1,2)
term.setTextColor(colors.lightGray)
term.write("×")
local timer = 3
if type(tArgs[4]) == "string" and tonumber(tArgs[4]) then
timer = tonumber(tArgs[4])
end
local tID = os.startTimer(timer)
local tID2
local sel = false
while true do
local e = {os.pullEvent()}
if e[1] == "timer" and e[2] == tID then
break
elseif e[1]:find("mouse") and e[3] and e[4] then
if e[3] == w-1 and e[4] == 2 then
if e[1] == "mouse_hover" then
term.setCursorPos(w-1,2)
term.setTextColor(colors.white)
term.write("×")
sel = true
elseif e[1] == "mouse_click" then
term.setCursorPos(w-1,2)
term.setTextColor(colors.red)
term.write("×")
sel = true
elseif e[1] == "mouse_up" and sel then
break
end
end
if e[1] == "mouse_up" and sel then
term.setCursorPos(w-1,2)
term.setTextColor(colors.lightGray)
term.write("×")
sel = false
end
end
--if count(lOS.notifWins) ~= nAmount then
nAmount = count(lOS.notifWins)
local tW,tH = lOS.wAll.getSize()
local w,h = term.getSize()
local newY = tH-h-lOS.tbSize
local x,y = LevelOS.self.window.win.getPosition()
for k,v in pairs(lOS.notifWins) do
--if v ~= LevelOS.self.window then
local tx,ty = v.win.getPosition()
if ty-h-1 <= newY and ty > y then -- use actual height
newY = ty-h-1
end
--end
end
if newY > y then
if not tID2 then
tID2 = os.startTimer(0.3)
elseif tID2 and e[1] == "timer" and e[2] == tID2 then
LevelOS.self.window.win.reposition(x,newY)
tID2 = nil
end
end
--end
end
lOS.notifWins[sID] = nil

725
LevelOS/Notifications.lua Normal file
View File

@ -0,0 +1,725 @@
local assets = {}
local nAssets = {}
for key,value in pairs(assets) do nAssets[key] = value nAssets[assets[key].id] = assets[key] end
assets = nAssets
nAssets = nil
local slides = {
{
y = 21,
x = 70,
w = 32,
h = 19,
objs = {
{
type = "rect",
color = 32768,
y2 = 19,
event = {
mouse_up = {
[ 2 ] = -1,
},
mouse_click = {
[ 2 ] = -1,
},
focus = {
[ 2 ] = -1,
},
render = {
[ 2 ] = -1,
},
update = {
[ 2 ] = -1,
},
Coroutine = {
[ 2 ] = -1,
},
},
x1 = 1,
x2 = 32,
border = {
color = 0,
type = 1,
},
y1 = 1,
},
{
type = "rect",
color = 128,
y2 = 6,
event = {
mouse_up = {
[ 2 ] = -1,
},
mouse_click = {
[ 2 ] = -1,
},
focus = {
[ 2 ] = -1,
},
render = {
[ 2 ] = -1,
},
Coroutine = {
[ 2 ] = -1,
},
update = {
[ 2 ] = -1,
},
},
x1 = 2,
y1 = 2,
border = {
color = 0,
type = 1,
},
x2 = 31,
},
{
x2 = 19,
y2 = 3,
border = {
color = 0,
type = 1,
},
x1 = 8,
txt = "Notification",
type = "text",
event = {
mouse_up = {
[ 2 ] = -1,
},
mouse_click = {
[ 2 ] = -1,
},
focus = {
[ 2 ] = -1,
},
render = {
[ 2 ] = -1,
},
Coroutine = {
[ 2 ] = -1,
},
update = {
[ 2 ] = -1,
},
},
txtcolor = 1,
input = false,
color = 0,
y1 = 3,
},
{
type = "rect",
color = 16384,
y2 = 5,
event = {
mouse_up = {
[ 2 ] = -1,
},
mouse_click = {
[ 2 ] = -1,
},
focus = {
[ 2 ] = -1,
},
render = {
[ 2 ] = -1,
},
Coroutine = {
[ 2 ] = -1,
},
update = {
[ 2 ] = -1,
},
},
x1 = 4,
y1 = 3,
border = {
color = 0,
type = 1,
},
x2 = 6,
},
{
x2 = 30,
y2 = 5,
border = {
color = 0,
type = 1,
},
x1 = 8,
txt = "This is a notification to tell you things yes.",
type = "text",
event = {
mouse_up = {
[ 2 ] = -1,
},
mouse_click = {
[ 2 ] = -1,
},
focus = {
[ 2 ] = -1,
},
render = {
[ 2 ] = -1,
},
Coroutine = {
[ 2 ] = -1,
},
update = {
[ 2 ] = -1,
},
},
txtcolor = 256,
input = false,
color = 0,
y1 = 4,
},
{
x2 = 30,
y2 = 3,
border = {
color = 0,
type = 1,
},
x1 = 30,
txt = "×",
type = "text",
event = {
mouse_up = {
[ 2 ] = -1,
},
mouse_click = {
[ 2 ] = -1,
},
focus = {
[ 2 ] = -1,
},
render = {
[ 2 ] = -1,
},
Coroutine = {
[ 2 ] = -1,
},
update = {
[ 2 ] = -1,
},
},
txtcolor = 256,
input = false,
color = 0,
y1 = 3,
},
},
c = 1,
},
{
y = 21,
x = 70,
c = 2,
objs = {
{
type = "rect",
color = 128,
y2 = 6,
event = {
render = {
[ 2 ] = -1,
},
mouse_click = {
[ 2 ] = -1,
},
focus = {
[ 2 ] = -1,
},
update = {
[ 2 ] = -1,
},
Coroutine = {
[ 2 ] = -1,
},
mouse_up = {
[ 2 ] = -1,
},
},
x1 = 2,
x2 = 31,
y1 = 2,
border = {
color = 0,
type = 1,
},
},
{
type = "rect",
color = 16384,
y2 = 5,
event = {
render = {
[ 2 ] = -1,
},
mouse_click = {
[ 2 ] = -1,
},
focus = {
[ 2 ] = -1,
},
update = {
[ 2 ] = -1,
},
Coroutine = {
[ 2 ] = -1,
},
mouse_up = {
[ 2 ] = -1,
},
},
x1 = 3,
x2 = 5,
y1 = 3,
border = {
color = 0,
type = 1,
},
},
{
color = 0,
y2 = 3,
y1 = 3,
x1 = 7,
txt = "Notification",
type = "text",
event = {
render = {
[ 2 ] = -1,
},
mouse_click = {
[ 2 ] = -1,
},
focus = {
[ 2 ] = -1,
},
update = {
[ 2 ] = -1,
},
Coroutine = {
[ 2 ] = -1,
},
mouse_up = {
[ 2 ] = -1,
},
},
txtcolor = 1,
input = false,
x2 = 18,
border = {
color = 0,
type = 1,
},
},
{
color = 0,
y2 = 5,
y1 = 4,
x1 = 7,
txt = "This is a notification to tell you things yes.",
type = "text",
event = {
render = {
[ 2 ] = -1,
},
mouse_click = {
[ 2 ] = -1,
},
focus = {
[ 2 ] = -1,
},
update = {
[ 2 ] = -1,
},
Coroutine = {
[ 2 ] = -1,
},
mouse_up = {
[ 2 ] = -1,
},
},
txtcolor = 256,
input = false,
x2 = 30,
border = {
color = 0,
type = 1,
},
},
{
color = 0,
y2 = 3,
y1 = 3,
x1 = 30,
txt = "×",
type = "text",
event = {
render = {
[ 2 ] = -1,
},
mouse_click = {
[ 2 ] = -1,
},
focus = {
[ 2 ] = -1,
},
update = {
[ 2 ] = -1,
},
Coroutine = {
[ 2 ] = -1,
},
mouse_up = {
[ 2 ] = -1,
},
},
txtcolor = 256,
input = false,
x2 = 30,
border = {
color = 0,
type = 1,
},
},
{
type = "rect",
color = 128,
y2 = 12,
event = {
render = {
[ 2 ] = -1,
},
mouse_click = {
[ 2 ] = -1,
},
focus = {
[ 2 ] = -1,
},
mouse_up = {
[ 2 ] = -1,
},
update = {
[ 2 ] = -1,
},
Coroutine = {
[ 2 ] = -1,
},
},
x1 = 2,
border = {
color = 0,
type = 1,
},
x2 = 31,
y1 = 8,
},
{
color = 0,
y2 = 9,
y1 = 9,
x1 = 3,
txt = "Notification",
type = "text",
event = {
render = {
[ 2 ] = -1,
},
mouse_click = {
[ 2 ] = -1,
},
focus = {
[ 2 ] = -1,
},
mouse_up = {
[ 2 ] = -1,
},
update = {
[ 2 ] = -1,
},
Coroutine = {
[ 2 ] = -1,
},
},
txtcolor = 1,
input = false,
x2 = 14,
border = {
color = 0,
type = 1,
},
},
{
x2 = 30,
y2 = 11,
border = {
color = 0,
type = 1,
},
x1 = 3,
txt = "This notification has no icon available.",
type = "text",
event = {
render = {
[ 2 ] = -1,
},
mouse_click = {
[ 2 ] = -1,
},
focus = {
[ 2 ] = -1,
},
mouse_up = {
[ 2 ] = -1,
},
update = {
[ 2 ] = -1,
},
Coroutine = {
[ 2 ] = -1,
},
},
txtcolor = 256,
input = false,
color = 0,
y1 = 10,
},
{
x2 = 30,
y2 = 9,
border = {
color = 0,
type = 1,
},
x1 = 30,
txt = "×",
type = "text",
event = {
render = {
[ 2 ] = -1,
},
mouse_click = {
[ 2 ] = -1,
},
focus = {
[ 2 ] = -1,
},
mouse_up = {
[ 2 ] = -1,
},
update = {
[ 2 ] = -1,
},
Coroutine = {
[ 2 ] = -1,
},
},
txtcolor = 256,
input = false,
color = 0,
y1 = 9,
},
{
type = "rect",
color = 128,
y2 = 19,
event = {
mouse_up = {
[ 2 ] = -1,
},
mouse_click = {
[ 2 ] = -1,
},
focus = {
[ 2 ] = -1,
},
Coroutine = {
[ 2 ] = -1,
},
update = {
[ 2 ] = -1,
},
render = {
[ 2 ] = -1,
},
},
x1 = 2,
border = {
color = 0,
type = 1,
},
y1 = 14,
x2 = 31,
},
{
type = "rect",
color = 16384,
y2 = 17,
event = {
render = {
[ 2 ] = -1,
},
mouse_click = {
[ 2 ] = -1,
},
focus = {
[ 2 ] = -1,
},
mouse_up = {
[ 2 ] = -1,
},
update = {
[ 2 ] = -1,
},
Coroutine = {
[ 2 ] = -1,
},
},
x1 = 3,
x2 = 5,
border = {
color = 0,
type = 1,
},
y1 = 15,
},
{
color = 0,
y2 = 15,
y1 = 15,
x1 = 7,
txt = "Notification",
type = "text",
event = {
render = {
[ 2 ] = -1,
},
mouse_click = {
[ 2 ] = -1,
},
focus = {
[ 2 ] = -1,
},
mouse_up = {
[ 2 ] = -1,
},
update = {
[ 2 ] = -1,
},
Coroutine = {
[ 2 ] = -1,
},
},
txtcolor = 1,
input = false,
x2 = 18,
border = {
color = 0,
type = 1,
},
},
{
color = 0,
y2 = 18,
y1 = 16,
x1 = 7,
txt = "This notification does not have enough space so it expands downwards.",
type = "text",
event = {
render = {
[ 2 ] = -1,
},
mouse_click = {
[ 2 ] = -1,
},
focus = {
[ 2 ] = -1,
},
mouse_up = {
[ 2 ] = -1,
},
update = {
[ 2 ] = -1,
},
Coroutine = {
[ 2 ] = -1,
},
},
txtcolor = 256,
input = false,
x2 = 30,
border = {
color = 0,
type = 1,
},
},
{
x2 = 30,
y2 = 15,
border = {
color = 0,
type = 1,
},
x1 = 30,
txt = "×",
type = "text",
event = {
mouse_up = {
[ 2 ] = -1,
},
mouse_click = {
[ 2 ] = -1,
},
focus = {
[ 2 ] = -1,
},
Coroutine = {
[ 2 ] = -1,
},
update = {
[ 2 ] = -1,
},
render = {
[ 2 ] = -1,
},
},
txtcolor = 256,
input = false,
color = 0,
y1 = 15,
},
},
w = 32,
h = 19,
},
}
for s=1,#slides do
local slide = slides[s]
for o=1,#slide.objs do
local obj = slide.objs[o]
for key,value in pairs(obj.event) do
if assets[ value[2] ] then
lUtils.shapescape.addScript(obj,value[2],key,assets,LevelOS,slides)
else
obj.event[key] = {function() end,-1}
end
end
end
end
local tArgs = {...}
if tArgs[1] and tArgs[1] == "load" then
return {assets=assets,slides=slides}
end
lUtils.shapescape.run(slides,...)

327
LevelOS/Start_Menu.sgui Normal file
View File

@ -0,0 +1,327 @@
local assets = {
[ "programs.lua" ] = {
id = 0,
content = "local scrollY = 0\
local programs = {}\
local found = fs.list(\"Program_Files\")\
local icons = lUtils.asset.load(\"LevelOS/assets/Compact_Icons.limg\")\
local A = string.byte(\"A\")\
local Z = string.byte(\"Z\")\
for f=1,#found do\
local l = string.byte(found[f]:sub(1,1):upper())\
local dest\
if l >= A and l <= Z then\
if not programs[l] then programs[l] = {} end\
dest = programs[l]\
else\
if not programs[A-1] then programs[A-1] = {} end\
dest = programs[A-1]\
end\
local program = {path=fs.combine(\"Program_Files\",found[f]),name=found[f]:sub(1,1):upper()..lUtils.getFileName(found[f]:sub(2))}\
--program.icon = whatever\
table.insert(dest,program)\
end\
local function render()\
local y = 2\
term.setBackgroundColor(colors.gray)\
term.setTextColor(colors.white)\
term.clear()\
for l=A-1,Z do\
if programs[l] then\
local letter\
if l == A-1 then\
letter = \"#\"\
else\
letter = string.char(l)\
end\
term.setCursorPos(1,y)\
term.write(letter)\
y = y+2\
for t=1,#programs[l] do\
lUtils.renderImg(icons[8],1,y)\
term.setCursorPos(5,y)\
term.setTextColor(colors.white)\
term.write(programs[l][t].name)\
y = y+1\
term.setTextColor(colors.lightGray)\
term.write( -- creator\
end\
end\
end",
name = "programs.lua",
},
}
local nAssets = {}
for key,value in pairs(assets) do nAssets[key] = value nAssets[assets[key].id] = assets[key] end
assets = nAssets
nAssets = nil
local slides = {
{
y = 21,
x = 61,
w = 51,
h = 19,
objs = {
{
color = 128,
y2 = 19,
border = {
color = 0,
type = 1,
},
x1 = 1,
type = "rect",
event = {
mouse_up = {
[ 2 ] = -1,
},
mouse_click = {
[ 2 ] = -1,
},
focus = {
[ 2 ] = -1,
},
render = {
[ 2 ] = -1,
},
update = {
[ 2 ] = -1,
},
Coroutine = {
[ 2 ] = -1,
},
},
x2 = 5,
y1 = 1,
snap = {
Top = "Snap top",
Right = "Snap left",
Left = "Snap left",
Bottom = "Snap bottom",
},
oy2 = 0,
},
{
color = 128,
y2 = 18,
border = {
color = 0,
type = 1,
},
x1 = 2,
image = {
{
"”•”",
"000",
"TTT",
},
{
"Œ…",
"000",
"TTT",
},
},
oy1 = 2,
type = "rect",
event = {
mouse_up = {
[ 2 ] = -1,
},
mouse_click = {
[ 2 ] = -1,
},
focus = {
[ 2 ] = -1,
},
render = {
[ 2 ] = -1,
},
update = {
[ 2 ] = -1,
},
Coroutine = {
[ 2 ] = -1,
},
},
oy2 = 1,
x2 = 4,
y1 = 17,
snap = {
Top = "Snap bottom",
Right = "Snap left",
Left = "Snap left",
Bottom = "Snap bottom",
},
},
{
color = 128,
y2 = 15,
border = {
color = 0,
type = 1,
},
x1 = 2,
image = {
{
"‡’",
"TT0",
"00T",
},
{
"‚‡€",
"00T",
"TTT",
},
},
oy1 = 5,
type = "rect",
event = {
mouse_up = {
[ 2 ] = -1,
},
mouse_click = {
[ 2 ] = -1,
},
focus = {
[ 2 ] = -1,
},
render = {
[ 2 ] = -1,
},
update = {
[ 2 ] = -1,
},
Coroutine = {
[ 2 ] = -1,
},
},
oy2 = 4,
x2 = 4,
y1 = 14,
snap = {
Top = "Snap bottom",
Right = "Snap left",
Left = "Snap left",
Bottom = "Snap bottom",
},
},
{
color = 128,
y2 = 12,
border = {
color = 0,
type = 1,
},
x1 = 2,
image = {
{
"‘€„",
"TT0",
"00T",
},
{
"ˆ€",
"00T",
"TTT",
},
},
oy1 = 8,
type = "rect",
event = {
mouse_up = {
[ 2 ] = -1,
},
mouse_click = {
[ 2 ] = -1,
},
focus = {
[ 2 ] = -1,
},
render = {
[ 2 ] = -1,
},
update = {
[ 2 ] = -1,
},
Coroutine = {
[ 2 ] = -1,
},
},
oy2 = 7,
x2 = 4,
y1 = 11,
snap = {
Top = "Snap bottom",
Right = "Snap left",
Left = "Snap left",
Bottom = "Snap bottom",
},
},
{
color = 128,
y2 = 19,
y1 = 1,
x1 = 6,
type = "window",
event = {
mouse_up = {
[ 2 ] = -1,
},
mouse_click = {
[ 2 ] = -1,
},
focus = {
[ 2 ] = -1,
},
render = {
[ 2 ] = -1,
},
update = {
[ 2 ] = -1,
},
Coroutine = {
[ 2 ] = -1,
},
},
ox2 = 0,
x2 = 51,
border = {
color = 0,
type = 1,
},
snap = {
Top = "Snap top",
Right = "Snap right",
Left = "Snap left",
Bottom = "Snap bottom",
},
oy2 = 0,
},
},
c = 1,
},
}
for s=1,#slides do
local slide = slides[s]
for o=1,#slide.objs do
local obj = slide.objs[o]
for key,value in pairs(obj.event) do
if assets[ value[2] ] then
lUtils.shapescape.addScript(obj,value[2],key,assets,LevelOS,slides)
else
obj.event[key] = {function() end,-1}
end
end
end
end
local tArgs = {...}
if tArgs[1] and tArgs[1] == "load" then
return {assets=assets,slides=slides}
end
lUtils.shapescape.run(slides,...)

1970
LevelOS/SystemUI.lua Normal file

File diff suppressed because it is too large Load Diff

451
LevelOS/Task_Manager.lua Normal file
View File

@ -0,0 +1,451 @@
local scroll = 0
local procs = lOS.processes
local sel = {}
local pSel = {}
local expanded = {}
local cEnd = false
local scrollable = false
local display = 1
local function percentage(part,full)
if display == 1 then
local f = math.min(math.ceil((part/full)*1000)/10,100)
return f.."%"
else
return math.floor(part+0.5).." ms"
end
end
function _G.invWrite(txt)
local fg = lUtils.toBlit(term.getTextColor()):rep(#txt)
local bg = lUtils.toBlit(term.getBackgroundColor()):rep(#txt)
term.blit(txt,bg,fg)
end
local function drawProcs(x1,y1,x2,y2,e)
if e[1] == "mouse_scroll" then
if scroll+e[2] >= 0 and (e[2] <= -1 or scrollable) then
scroll = scroll+e[2]
end
end
term.setBackgroundColor(colors.yellow)
term.setTextColor(colors.lightGray)
--lOS.boxClear(x2-9,y1,x2,y2-2)
for y=y1,y2-2 do
term.setBackgroundColor(colors.white)
term.setCursorPos(x2-10,y)
invWrite("\149")
term.setBackgroundColor(colors.yellow)
term.write(string.rep(" ",10))
term.setBackgroundColor(colors.white)
term.write("\149")
end
scrollable = false
cY = y1-scroll
local pr = {}
local bg = {}
y2 = y2-2
for p=1,#procs do
if procs[p].path then
if procs[p].win and procs[p].winMode ~= "background" then
if not pr[procs[p].path] then
if expanded[procs[p].path] == nil then
expanded[procs[p].path] = false
end
pr[#pr+1] = {expanded=expanded[procs[p].path],path=procs[p].path,pr={procs[p]},yieldTime=procs[p].yieldTime}
pr[procs[p].path] = pr[#pr]
else
for t=1,#pr do
if pr[t].path == procs[p].path then
pr[t].pr[#pr[t].pr+1] = procs[p]
if procs[p].yieldTime then
pr[t].yieldTime = pr[t].yieldTime+procs[p].yieldTime
end
end
end
end
else
bg[#bg+1] = procs[p]
end
end
end
local clickmenu = {}
-- TEMP
if type(pSel) == "table" then
sel = pSel
elseif type(pSel) == "number" then
sel = pr[pSel]
else
sel = {}
end
--if pr[2] then
--pr[2].expanded = true
--end
if cY+1 >= y1 and cY+1 <= y2 then
term.setTextColor(colors.blue)
term.setBackgroundColor(colors.white)
term.setCursorPos(x1,cY+1)
term.write("Programs ("..#pr..")")
end
cY = cY+2
local previousColor1
local previousColor2
for p=1,#pr+1 do
local fg1
local bg1
local fg2
local bg2
local WARN = colors.yellow
if p <= #pr and pr[p].yieldTime then
local f = pr[p].yieldTime/lOS.yieldTime
if f > 0.7 then
WARN = colors.red
elseif f > 0.4 then
WARN = colors.orange
end
end
fg1 = previousColor1 or colors.white
fg2 = previousColor2 or colors.yellow
if p > #pr or sel ~= pr[p] then
bg1 = colors.white
bg2 = WARN
else
bg1 = colors.lightBlue
bg2 = colors.cyan
end
previousColor1 = bg1
previousColor2 = bg2
if cY >= y1 and cY <= y2 then
term.setTextColor(fg1)
term.setBackgroundColor(bg1)
term.setCursorPos(x1,cY)
term.write(string.rep("\131",x2-(x1-1)-11))
term.setTextColor(colors.lightGray)
term.setBackgroundColor(colors.white)
invWrite("\149")
term.setBackgroundColor(bg1)
term.setTextColor(fg2)
term.setBackgroundColor(bg2)
term.write(string.rep("\131",10))
end
term.setTextColor(fg1)
term.setBackgroundColor(bg1)
if p > #pr then
break
end
cY = cY+1
if cY >= y1 and cY <= y2 then
--term.setTextColor(colors.black)
clickmenu[cY] = p
term.setCursorPos(x1,cY)
term.write(string.rep(" ",x2-(x1-1)-11))
term.setTextColor(colors.lightGray)
term.setBackgroundColor(colors.white)
invWrite("\149")
term.setBackgroundColor(bg2)
term.write(string.rep(" ",10))
term.setCursorPos(x1+1,cY)
term.setBackgroundColor(bg1)
if not pr[p].expanded then
term.setTextColor(colors.lightGray)
term.write("\16 ")
else
term.setTextColor(colors.gray)
term.write("\31 ")
end
term.setTextColor(colors.black)
local path = pr[p].path
if fs.getName(path) == "main.lua" then
path = fs.getDir(path)
end
local t = lUtils.getFileName(path)
t = t:sub(1,1):upper()..t:sub(2)
term.write(t.." ("..#pr[p].pr..")")
local txt
if pr[p].yieldTime then
txt = percentage(pr[p].yieldTime,lOS.yieldTime)
else
txt = "???"
end
term.setCursorPos(x2-#txt,cY)
term.setBackgroundColor(bg2)
term.write(txt)
end
cY = cY+1
if pr[p].expanded then
for t=1,#pr[p].pr do
if cY >= y1 and cY <= y2 then
clickmenu[cY] = pr[p].pr[t]
local bg3
local bg4
if sel == pr[p].pr[t] or sel == pr[p] then
bg3 = colors.lightBlue
bg4 = colors.cyan
else
bg3 = colors.white
bg4 = WARN
end
term.setBackgroundColor(bg3)
if not (sel == pr[p]) then
term.setCursorPos(x1+3,cY)
term.write(string.rep(" ",(x2)-(x1+2)-11))
else
term.setCursorPos(x1,cY)
term.write(string.rep(" ",x2-(x1-1)-11))
end
term.setTextColor(colors.lightGray)
term.setBackgroundColor(colors.white)
invWrite("\149")
term.setBackgroundColor(bg4)
term.write(string.rep(" ",10))
term.setBackgroundColor(bg3)
term.setTextColor(colors.black)
term.setCursorPos(x1+4,cY)
term.write(pr[p].pr[t].title)
local txt
if pr[p].pr[t].yieldTime then
txt = percentage(pr[p].pr[t].yieldTime,lOS.yieldTime)
else
txt = "???"
end
term.setCursorPos(x2-#txt,cY)
term.setBackgroundColor(bg4)
term.write(txt)
end
cY = cY+1
end
end
end
-- draw bg processes (no extended)
if cY+1 >= y1 and cY+1 <= y2 then
term.setTextColor(colors.blue)
term.setBackgroundColor(colors.white)
term.setCursorPos(x1,cY+1)
term.write("Background Processes ("..#bg..")")
end
cY = cY+2
local previousColor1
local previousColor2
for p=1,#bg+1 do
local fg1
local bg1
local fg2
local bg2
local WARN = colors.yellow
if p <= #bg and bg[p].yieldTime then
local f = bg[p].yieldTime/lOS.yieldTime
if f > 0.7 then
WARN = colors.red
elseif f > 0.4 then
WARN = colors.orange
end
end
fg1 = previousColor1 or colors.white
fg2 = previousColor2 or colors.yellow
if p > #bg or sel ~= bg[p] then
bg1 = colors.white
bg2 = WARN
else
bg1 = colors.lightBlue
bg2 = colors.cyan
end
previousColor1 = bg1
previousColor2 = bg2
if cY >= y1 and cY <= y2 then
term.setTextColor(fg1)
term.setBackgroundColor(bg1)
term.setCursorPos(x1,cY)
term.write(string.rep("\131",x2-(x1-1)-11))
term.setTextColor(colors.lightGray)
term.setBackgroundColor(colors.white)
invWrite("\149")
term.setBackgroundColor(bg1)
term.setTextColor(fg2)
term.setBackgroundColor(bg2)
term.write(string.rep("\131",10))
end
term.setTextColor(fg1)
term.setBackgroundColor(bg1)
if p > #bg then
break
end
cY = cY+1
if cY >= y1 and cY <= y2 then
--term.setTextColor(colors.black)
clickmenu[cY] = bg[p]
term.setCursorPos(x1,cY)
term.write(string.rep(" ",x2-(x1-1)-11))
term.setTextColor(colors.lightGray)
term.setBackgroundColor(colors.white)
invWrite("\149")
term.setBackgroundColor(bg2)
term.write(string.rep(" ",10))
term.setCursorPos(x1+1,cY)
term.setBackgroundColor(bg1)
if sel ~= bg[p] then
term.setBackgroundColor(colors.white)
else
term.setBackgroundColor(colors.lightBlue)
end
term.write(" ")
term.setTextColor(colors.black)
local t = ""
if bg[p].title then
t = bg[p].title
else
t = bg[p].path
end
term.write(t)
local txt
if bg[p].yieldTime then
txt = percentage(bg[p].yieldTime,lOS.yieldTime)
else
txt = "???"
end
term.setCursorPos(x2-#txt,cY)
term.setBackgroundColor(bg2)
term.write(txt)
end
cY = cY+1
end
if cY > y2 then
scrollable = true
end
term.setCursorPos(1,y2+1)
term.setBackgroundColor(colors.white)
term.setTextColor(colors.gray)
local w,h = term.getSize()
term.write(string.rep("\131",w))
--term.setCursorPos(x1,y2+2)
local txt = "End Task"
term.setCursorPos(x2-(string.len(txt)),y2+2)
if sel.path then
if not cEnd then
term.setTextColor(colors.blue)
else
term.setTextColor(colors.lightBlue)
end
else
term.setTextColor(colors.lightGray)
end
term.write(txt)
if e[1] == "mouse_click" then
if e[3] >= x1 and e[3] <= x2 and e[4] >= y1 and e[4] <= y2 then
sel = {}
pSel = {}
end
if sel.path and e[4] == y2+2 and e[3] >= x2-string.len(txt) and e[3] <= x2-1 then
term.setCursorPos(x2-(string.len(txt)),y2+2)
term.setTextColor(colors.lightBlue)
term.write(txt)
cEnd = true
end
if clickmenu[e[4]] then
pSel = clickmenu[e[4]]
if type(pSel) == "number" and e[3] == x1+1 then
if expanded[pr[pSel].path] == false then
expanded[pr[pSel].path] = true
else
expanded[pr[pSel].path] = false
end
end
end
elseif e[1] == "mouse_up" then
cEnd = false
if sel.path and e[4] == y2+2 and e[3] >= x2-string.len(txt) and e[3] <= x2-1 then
local t = 1
while true do
if lOS.processes[t] == nil then break end
if type(sel[1]) == "thread" then
if lOS.processes[t] == sel then
for i=1,#lOS.wins do
if lOS.wins[i] == lOS.processes[t] then
table.remove(lOS.wins,i)
end
end
table.remove(lOS.processes,t)
break
else
t = t+1
end
else
if lOS.processes[t].path == sel.path then
for i=1,#lOS.wins do
if lOS.wins[i] == lOS.processes[t] then
table.remove(lOS.wins,i)
end
end
table.remove(lOS.processes,t)
else
t = t+1
end
end
end
sel = {}
pSel = {}
end
end
end
-- sel wont work since pr gets regenerated every time
-- it will work for subprocesses tho
local w,h = term.getSize()
term.setBackgroundColor(colors.white)
term.clear()
while true do
e = {os.pullEvent()}
term.setBackgroundColor(colors.white)
term.clear()
local w,h = term.getSize()
term.setCursorPos(2,3)
term.setTextColor(colors.blue)
term.write("Name")
term.setCursorPos(w-6,3)
term.write("Yield")
term.setTextColor(colors.black)
local txt
if lOS.yieldTime then
txt = math.ceil(lOS.yieldTime).." ms"
else
txt = "???"
end
term.setCursorPos((w-1)-#txt,2)
term.write(txt)
term.setCursorPos(1,4)
term.setTextColor(colors.lightGray)
term.setBackgroundColor(colors.white)
term.write(string.rep("\131",w))
for y=1,3 do
term.setCursorPos(w-11,y)
invWrite("\149")
term.setCursorPos(w,y)
term.write("\149")
end
term.setCursorPos(w-11,4)
invWrite("\148")
term.setBackgroundColor(colors.yellow)
term.write(string.rep("\131",10))
term.setBackgroundColor(colors.white)
term.setCursorPos(w,4)
term.write("\151")
drawProcs(2,5,w-1,h,e)
if e[1] == "key_up" and e[2] == keys.t and lUtils.isHolding(keys.leftShift) then
term.setBackgroundColor(colors.black)
term.clear()
term.setCursorPos(1,1)
term.setTextColor(colors.red)
print("Terminated")
return
elseif e[1] == "mouse_click" and e[2] == 2 and lUtils.isInside(e[3],e[4],{x1=w-10,y1=1,x2=w-1,y2=4}) then
if display == 1 then
lOS.contextmenu(e[3],e[4],0,{{txt="Switch to ms",action=function() display = 2 end}})
else
lOS.contextmenu(e[3],e[4],0,{{txt="Switch to %",action=function() display = 1 end}})
end
end
end

View File

@ -0,0 +1,37 @@
{
{
{
"‡€”‚",
"TT0Tb",
"bbbbT",
},
{
"€‰•",
"T000b",
"bbbbT",
},
{
"‹ˆŒŸ",
"b00bb",
"TbbTT",
},
},
{
{
"‡€€‚",
"TTTTb",
"bbbbT",
},
{
"€˜•",
"T000b",
"bbbbT",
},
{
"‹‚€Ÿ",
"b0Tbb",
"TbbTT",
},
},
type = "lImg",
}

View File

@ -0,0 +1,110 @@
{
{
{
"—‹",
"TT0",
"00T",
},
{
"Š…",
"000",
"TTT",
},
},
{
{
"‡‹",
"TT0",
"00T",
},
{
"ƒ‡",
"000",
"TTT",
},
},
{
{
"‡ƒ‹",
"TTT",
"000",
},
{
"›‡",
"000",
"TTT",
},
},
{
{
"‡‹ƒ",
"TTT",
"000",
},
{
"‹‡€",
"00T",
"TTT",
},
},
{
{
"ˆ€",
"00T",
"TTT",
},
{
"‚ˆ„",
"000",
"TTT",
},
},
{
{
"Ÿœ’",
"T00",
"0TT",
},
{
"‚",
"000",
"TTT",
},
},
{
{
"•ƒ•",
"TT0",
"00T",
},
{
"Š…",
"000",
"TTT",
},
},
{
{
"œ“ƒ",
"0TT",
"T00",
},
{
"Ž",
"000",
"TTT",
},
},
{
{
"€‘‹",
"TTT",
"T00",
},
{
"˜",
"000",
"TTT",
},
},
}

View File

@ -0,0 +1 @@
{{{"€•‹"," 9 ","9bb",},{"€€€"," ","999",},{"€€€"," ","999",},},{{"€•‹"," 9 ","9bb",},{"€€€"," ","999",},{"lua","000","bbb",},},{{""," ","777",},{"••€","8b ","b88",},{"ƒƒƒ","888"," ",},},{{"€•‹"," 8 ","877",},{"€€€"," ","888",},{"€€€"," ","888",},},{{"€•‹"," 8 ","877",},{"€€€"," ","888",},{"txt","000","777",},},{{"€•‹"," 8 ","877",},{"€€€"," ","888",},{"cfg","000","777",},},{{"€€•"," 4","44 ",},{"€€‚"," ","444",},{"€€€"," ","444",},},{{"€•‹"," e ","e11",},{"€€€"," ","eee",},{"gui","000","111",},},{{"€•‹"," 5 ","5dd",},{"€€€"," ","555",},{"sml","000","ddd",},},{{""," ","ccc",},{"•‹•","c43","3dc",},{"ƒƒƒ","ccc"," ",},},{{"","afa","faf",},{"ƒƒƒ","faf","afa",},{"","faf"," ",},},{{"˜ƒ›","bb "," b",},{"‰†","b b"," b ",},{"˜Œ›","bb "," b",},},{{""," ","888",},{"•€•","8 b","bb8",},{"Œ€Œ"," ","888",},},{{"Ÿ•‹","00 ","988",},{"ˆŒ„","999","000",},{"ŠŠ…","999","000",},},{{"€ƒ€"," "," b ",},{"€"," ","bbb",},{"‚","bbb"," ",},},{{"Ÿ‹€"," ","88 ",},{"Ÿ…","888"," ",},{"‚ƒ€","88 "," ",},},{{""," ","000",},{"•‡•","03d","3d0",},{"ƒƒƒ","000"," ",},},{{"€•”"," b"," b ",},{"€•Š"," b"," b ",},{"‘Ÿ€"," b ","b ",},},{{"Ÿ€"," 9","9 ",},{"•€•","9 "," 9",},{"‚€","9 9"," ",},},{{"Ÿ•","4b4","b4 ",},{"ƒ","bb9","494",},{"€€€"," ","444",},},{{"€€€"," "," ",},{"Š…","888","eee",},{"•Œ•","e78","88e",},},}

View File

@ -0,0 +1 @@
{{{"€€Ÿ€€•"," 000b b00 b 000b0","0bbb000bb000bbb0b",},{"€•ƒ”•Šƒ”‰†•ƒ”••"," b0bb00b0bbbb0bb0","00b00bb0b0000b00b",},{"€ŠŒŽŠ……ˆƒŒŽŠŒŽ••"," 00000000000000b0","0bbbbbbbbbbbbbb0b",},{"€›•‚–œˆ‚ˆ›˜ƒ€•"," 0bbbb0bbbbb0b0 0","0b0000b00000b0b0b",},{"€†–˜€Œ•Ÿ€€–ŒˆŒ€•"," b00 bb0 0b0b b0","00bbb00900b0b000b",},{"€“•‰••€™‹™–‘•"," 0b0bbb00 0bbbbb0","0b0b000990b00000b",},{"€ƒž™ŠŽŠ„€ž‰”•"," 0b00000b00 b0bb0","0b0bbbbb0bb00b00b",},{"€…ŠŽŸˆ™›ƒ‚†Œ‹Œ„•"," bbbb0b0b0bbb0bb0","00000b0b0b000b00b",},{"€—Œ“•‚Ž…œŽ”ŠŽˆ‰€•"," b0bbb00000000b 0","00b000bbbbbbbb00b",},{"€•…•Š–†‹Š–ŒŸ•"," bbbbb000bb0b0bb0","000000bbb00b0b00b",},{"€ƒƒƒ€€€ƒ‚ƒ€•"," bbbbb b bbbbb 0","0000000000000000b",},},{{"€€ŸŸ€€"," 000bb 00b b000b ","0bbb000bb000bbb00",},{"€•ƒ”•‚’•Šƒš…•ƒ”•€"," b0bb0bb0bbbb0bb ","00b00b00b0000b000",},{"€ŠŒŽ•ž•“‘œ”ŠŒŽ•€"," 000bbbbbbbb000b ","0bbb00000000bbb00",},{"€œƒ„‡›ƒ•Ÿ‡˜œ„€"," b00bbb0bb000bbb ","00bb000b00bbb0000",},{"€†›œ“Žž‘–Ž—Ž”ށ€"," bbbbb00b000000b ","000000bb0bbbbbb00",},{"€‚ž–Ž‘‚‡”Ž‹‘‡’€€"," bb0b00bb00bbb0 ","000b0bb00bb000b00",},{"€„Œœ›”–‡†š˜›‰€„€"," bbbbbb00bbbb0 b ","0000000bb0000bb00",},{"€Œ‰…ŒšŒŠŸ–‘ŸŒ‹’€€"," bbbbbb00b0bb0b ","0000000bb0b00b000",},{"€—Œ“•ƒŸ—•Œ’ŠŽˆ‘€"," b0bb0b0bb0000bb ","00b00b0b00bbbb000",},{"€•…•š—Ÿ…›’‚Œ‰Ÿ„€"," bbbbb0bb00b00bb ","000000b00bb0bb000",},{"€ƒƒƒ€€ƒƒ‚€€"," bbbbb bbbbbbb ","00000000000000000",},},}

View File

@ -0,0 +1,172 @@
{
{
{
"ŸŒ›€",
"T8TT",
"8T8T",
},
{
"•€€•",
"8TT8",
"TTTT",
},
{
"‚Œ†€",
"888T",
"TTTT",
},
},
{
{
"ŸŒ›€",
"T0TT",
"8T8T",
},
{
"•€€•",
"8TT8",
"TTTT",
},
{
"‚Œ†€",
"888T",
"TTTT",
},
},
{
{
"ŸŒ›€",
"T0TT",
"8T0T",
},
{
"•€€•",
"8TT8",
"TTTT",
},
{
"‚Œ†€",
"888T",
"TTTT",
},
},
{
{
"ŸŒ›€",
"T0TT",
"8T0T",
},
{
"•€€•",
"8TT0",
"TTTT",
},
{
"‚Œ†€",
"888T",
"TTTT",
},
},
{
{
"ŸŒ›€",
"T0TT",
"8T0T",
},
{
"•€€•",
"8TT0",
"TTTT",
},
{
"‚Œ†€",
"880T",
"TTTT",
},
},
{
{
"ŸŒ›€",
"T0TT",
"8T0T",
},
{
"•€€•",
"8TT0",
"TTTT",
},
{
"‚Œ†€",
"800T",
"TTTT",
},
},
{
{
"ŸŒ›€",
"T0TT",
"8T0T",
},
{
"•€€•",
"8TT0",
"TTTT",
},
{
"‚Œ†€",
"000T",
"TTTT",
},
},
{
{
"ŸŒ›€",
"T0TT",
"8T0T",
},
{
"•€€•",
"0TT0",
"TTTT",
},
{
"‚Œ†€",
"000T",
"TTTT",
},
},
{
{
"ŸŒ›€",
"T0TT",
"0T0T",
},
{
"•€€•",
"0TT0",
"TTTT",
},
{
"‚Œ†€",
"000T",
"TTTT",
},
},
{
{
"Ÿƒ‹€",
"TTTT",
"bbbT",
},
{
"€›†•",
"Tb0b",
"b0bT",
},
{
"‚‡€",
"bbbT",
"TTTT",
},
},
}

View File

@ -1,241 +1,241 @@
{
{
{
"-<2D>-ا-ا-ا",
"Ÿ€€€",
"TTTT",
"0TTT",
},
{
"-ْ-ا-ا-ا",
"•€€€",
"0TTT",
"TTTT",
},
{
"-ا-ا-ا-ا",
"€€€€",
"TTTT",
"TTTT",
},
},
{
{
"-ا-ل-ا-ا",
"€„€€",
"T0TT",
"TTTT",
},
{
"-ْ-ا-ا-ا",
"•€€€",
"0TTT",
"TTTT",
},
{
"-ا-ا-ا-ا",
"€€€€",
"TTTT",
"TTTT",
},
},
{
{
"-<2D>-ي-ا-ا",
"Ÿˆ€€",
"T0TT",
"0TTT",
},
{
"-<2D>-ا-ا-ا",
"”€€€",
"0TTT",
"TTTT",
},
{
"-ا-ا-ا-ا",
"€€€€",
"TTTT",
"TTTT",
},
},
{
{
"-ا-ل-ل-ا",
"€„„€",
"T00T",
"TTTT",
},
{
"-ـ-ا-ا-ا",
"…€€€",
"0TTT",
"TTTT",
},
{
"-ا-ا-ا-ا",
"€€€€",
"TTTT",
"TTTT",
},
},
{
{
"-<2D>-ي-<2D>-ا",
"ŸˆŸ€",
"T0TT",
"0T0T",
},
{
"-<2D>-ا-ا-ا",
"€€€",
"0TTT",
"TTTT",
},
{
"-ا-ا-ا-ا",
"€€€€",
"TTTT",
"TTTT",
},
},
{
{
"-<2D>-ي-<2D>-ا",
"ŸˆŸ€",
"T0TT",
"0T0T",
},
{
"-ا-ا-ا",
"€€€„",
"TTT0",
"TTTT",
},
{
"-ا-ا-ا-ا",
"€€€€",
"TTTT",
"TTTT",
},
},
{
{
"-ا-ل-ل-ا",
"€„„€",
"T00T",
"TTTT",
},
{
"-ا-ا-ا-<2D>",
"€€€",
"TTT0",
"TTTT",
},
{
"-ا-ا-ى-ا",
"€€‚€",
"TT0T",
"TTTT",
},
},
{
{
"-ا-ي-<2D>-ا",
"€ˆŸ€",
"T0TT",
"TT0T",
},
{
"-ا-ا-ا",
"€€€",
"TTT0",
"TTTT",
},
{
"-ا-ا-ل-ا",
"€€„€",
"TT0T",
"TTTT",
},
},
{
{
"-ا-ا-<2D>-ا",
"€€Ÿ€",
"TTTT",
"TT0T",
},
{
"-ا-ا-ا",
"€€€",
"TTT0",
"TTTT",
},
{
"-ى-ا-ل-ا",
"‚€„€",
"0T0T",
"TTTT",
},
},
{
{
"-ا-ا-ا-ا",
"€€€€",
"TTTT",
"TTTT",
},
{
"-ة-ا-ا",
"€€„",
"0TT0",
"TTTT",
},
{
"-ا-ل-ل-ا",
"€„„€",
"T00T",
"TTTT",
},
},
{
{
"-ا-ا-ا-ا",
"€€€€",
"TTTT",
"TTTT",
},
{
"-ل-ا-ا-ا",
"„€€€",
"0TTT",
"TTTT",
},
{
"-ى-ي-ى-ا",
"‚ˆ‚€",
"000T",
"TTTT",
},
},
{
{
"-ا-ا-ا-ا",
"€€€€",
"TTTT",
"TTTT",
},
{
"-ـ-ا-ا-ا",
"…€€€",
"0TTT",
"TTTT",
},
{
"-ى-ي-ا-ا",
"‚ˆ€€",
"00TT",
"TTTT",
},
},
{
{
"-ا-ا-ا-ا",
"€€€€",
"TTTT",
"TTTT",
},
{
"-ْ-ا-ا-ا",
"•€€€",
"0TTT",
"TTTT",
},
{
"-ا-ل-ا-ا",
"€„€€",
"T0TT",
"TTTT",
},
},
{
{
"-ا-ا-ا-ا",
"€€€€",
"TTTT",
"TTTT",
},
{
"-ْ-ا-ا-ا",
"•€€€",
"0TTT",
"TTTT",
},
{
"-ى-ا-ا-ا",
"‚€€€",
"0TTT",
"TTTT",
},
},
type = "lImg",
}
}

View File

@ -0,0 +1,40 @@
{
{
{
"€•€€€€€€",
"TeTTTTTT",
"eTTTTTTT",
},
{
"€•€€€€€€",
"TeTTTTTT",
"eTTTTTTT",
},
{
"€•€€€€€€",
"TdTTTTTT",
"dTTTTTTT",
},
{
"€•€€€€€€",
"TdTTTTTT",
"dTTTTTTT",
},
{
"€•€€€€€€",
"TeTTTTTT",
"eTTTTTTT",
},
{
"€•€€€€€€",
"TeTTTTTT",
"eTTTTTTT",
},
{
"€€•€€€€•",
"TTdTTTTd",
"ddeeeddT",
},
},
type = "lImg",
}

View File

@ -0,0 +1,40 @@
{
{
{
"€•€€€€€€",
"TeTTTTTT",
"eTTTTTTT",
},
{
"€•€€€€€€",
"TeTTTTTT",
"eTTTTTTT",
},
{
"€•€€€€€€",
"T1TTTTTT",
"1TTTTTTT",
},
{
"€•€€€€€€",
"T1TTTTTT",
"1TTTTTTT",
},
{
"€•€€€€€€",
"T4TTTTTT",
"4TTTTTTT",
},
{
"€•€€€€€€",
"T4TTTTTT",
"4TTTTTTT",
},
{
"€€•€€€€•",
"TTdTTTTa",
"ddbbbaaT",
},
},
type = "lImg",
}

71
LevelOS/assets/wifi.limg Normal file
View File

@ -0,0 +1,71 @@
{
{
{
"Œ›€",
"0TT",
"T0T",
},
{
"“”•",
"000",
"TTT",
},
{
"€€€",
"TTT",
"TTT",
},
},
{
{
"Œ›€",
"8TT",
"T8T",
},
{
"“”•",
"008",
"TTT",
},
{
"€€€",
"TTT",
"TTT",
},
},
{
{
"Œ›€",
"8TT",
"T8T",
},
{
"“”•",
"888",
"TTT",
},
{
"€€€",
"TTT",
"TTT",
},
},
{
{
"Œ›€",
"eTT",
"TeT",
},
{
"“”•",
"eee",
"TTT",
},
{
"€€€",
"TTT",
"TTT",
},
},
type = "lImg",
}

View File

@ -0,0 +1,324 @@
{
{
date = "01-06-2021",
version = "2.2.5",
description = "It's pride month! To show support, the LevelOS logo has been replaced by a rainbow variant throughout June.",
added = {
"Added changelog",
},
fixed = {
"lOS.execute now properly takes a window mode argument",
"Loading assets through lUtils no longer errors on invalid file path",
"lUtils.renderImg now handles transparency slightly better",
},
},
{
date = "01-06-2021",
version = "2.2.6",
fixed = {
"Modified changelog design and resizing",
"Fixed startup erroring after update",
},
},
{
date = "02-06-2021",
version = "2.2.7",
added = {
"Integrated global login into the LevelOS system",
},
},
{
date = "02-06-2021",
version = "2.2.8",
fixed = {
"Global login now only appears when LevelCloud is enabled, as was intended",
"Shapescape programs no longer crash on versions with mouse_move events",
},
},
{
date = "03-06-2021",
version = "2.2.9",
description = "The LevelOS search feature is currently disabled until input boxes are added.",
added = {
"LevelOS start menu is now an overlay and can be opened by both mouse buttons",
"Shapescape programs now clear their window when exited",
},
fixed = {
"Fixed LevelOS infinite-looping when booted without internet",
},
},
{
date = "03-06-2021",
version = "2.2.10",
description = "Mouse simulator will be added to LevelOS in the future",
added = {
"LevelOS can now run on classic computers when an external mouse simulator is used",
},
fixed = {
"Fixed the login screen getting stuck on boot until it received an event",
"Fixed the LevelCloud GUI showing an error when booted without internet",
},
},
{
date = "16-06-2021",
version = "2.2.11",
description = "This took too long but I finally fixed a bunch of issues in the OS. Input boxes coming soon.",
fixed = {
"Shutdown fade restored (broke in 2.2.9)",
"Fixed startup processes not being able to execute programs before their first yield",
"Fixed term_resize events being sent to every process instead of only the resizing one",
"Only the focused window has constant thread resuming now to improve performance",
"LevelOS now properly reports errors in System and SystemUI processes",
},
},
{
date = "19-06-2021",
version = "2.2.12",
description = "Some temporary fixes until the desktop and system are rewritten",
added = {
"New desktop icons for .lua files, files without extension, files with unknown extensions and LevelOS executables",
},
fixed = {
"LevelOS can now resize itself",
"Desktop no longer has weird dragging limits",
"Icon creation from the explorer and using lOS.genIco now works properly",
"Pigeon icon has been restored",
},
},
{
date = "22-11-2021",
version = "2.3.0",
description = "It's been a while, but LevelOS is back. And it's better than ever! Sorry for the long wait! The window manager has been rewritten entirely, and all sorts of cool functionality has been added. Desktop icons have been renewed but don't refresh automatically, so if you want those you have to delete desktop.lconf in LevelOS/data and hold ctrl + r.",
added = {
"The window manager now has animations on resizing, closing, opening and minimizing of windows",
"A tab menu (like Window's alt tab) has been added. Instead of alt, ctrl is used in LevelOS",
"Shell and Lua have new icons",
"Windows can now be in fullscreen mode by pressing f5",
"There's a new login screen and register screen, remember me can be toggled by logging out through the LevelCloud interface and pressing remember me in the prompt that comes up",
"Taskbar icons are now actual icons. Custom icons coming soon",
"When multiple windows of a certain program are open, they appear in the same taskbar icon",
"Taskbar icons can now be right clicked",
"Right click menu's are now overlays meaning they can go beyond their window's border",
"Bootup now displays what it's currently doing",
"The pride LevelOS icon is back due to popular demand",
},
fixed = {
"Desktop auto generation now works properly, may require deleting desktop.lconf in LevelOS/data and holding ctrl + r to work",
"The LevelOS start menu (opened by clicking the L in the bottom left corner) now appears on top of other windows",
},
major = true,
},
{
date = "26-12-2021",
version = "2.3.1",
description = "Merry Christmas! More changes are on the way for premium users.",
added = {
"Premium users now have an auto updater for dev builds",
"LevelOS now has an integrity check at startup",
"Replaced asterisks in login screen with circles",
},
fixed = {
"Minimizing widgets no longer causes a bluescreen",
"Clicks on the taskbar now also close widgets",
"Desktop shortcuts to program folders now execute properly",
"Start screen now properly resizes",
},
},
{
date = "22-05-2022",
version = "2.3.2",
description = "I seem to make a habit out of incredibly long delays between updates. Sorry about that. This update contains some very necessary bugfixes and some API rewrites, in wait of a bigger update with rewritten GUIs for several components in LevelOS. Stay tuned!",
added = {
"Redesigned and improved notifications",
"The clock now has a calendar as well",
"The window manager now uses a window_focus event",
"Shapescape now displays proper error messages when a script errors",
},
fixed = {
"Improved lUtils.renderImg transparency handling",
"Cursor no longer displays outside of window",
"The certificate error in the login screen has been fixed",
"Cursor no longer keeps blinking when a popup opens",
},
},
{
date = "22-05-2022",
version = "2.3.3",
description = "Wow! Two updates in one day!",
fixed = {
"Fixed another occurence of the certificate error in lUtils.login that I missed earlier",
},
},
{
major = true,
date = "04-08-2022",
version = "2.4.0",
description = "Version 2.4 is here! This version is all about the rewrites. LevelOS has gotten a completely new and rewritten desktop, which is now bound to the actual folder User/Desktop. There is also a completely new explorer, which together with the desktop supports a new shortcut system. Alongside with these big new changes, there have also been several fixes and other new features, and more will follow.",
added = {
"Rewrote the desktop, now has custom background support (right click any .nfp, .bimg or .limg image using explorer)",
"There is now a new shortcut system (right click any file or folder using explorer and click create shortcut)",
"Rewrote the explorer, now comes with a file tree, search function, icon view (icon in the bottom right) and more",
"Created the advanced lOS.contextmenu function, documentation will come soon",
"Made better taskbar icons",
"Changed the LevelOS file structure, LevelOS programs are now in Program_Files/LevelOS",
"Replaced openWith.lconf with formats.lconf, which has a better stucture",
"There is now a 'Yield' column in Task Manager",
"Added 'abort()' function to the LevelOS.close() callback function, to abort closing the program",
"Shutting down/rebooting now shows an interface to be able to save your work if apps have LevelOS.close() set",
"Added an early version of the Store",
"Replaced the lua repl with a custom version",
"Added 1 character icon support to the window manager",
"Added bimg support across LevelOS",
"Added a new program folder structure which is HIGHLY recommended you use for LevelOS programs as it allows setting custom icons: main.lua for file that gets executed when the program is ran, taskbar.bimg for the icon appearing on the taskbar (must be mostly white!) and icon.bimg for the icon appearing on desktop and more"
},
fixed = {
"Shapescape windows now resize properly",
"Fixed numerous bugs with CraftOS-PC",
"Solved some incompatibility issues with 1.12.2 (may not have caught all, please report if there are more)",
"Fixed some bugs in the login screen",
}
},
{
date = "08-08-2022",
version = "2.4.1",
description = "Thanks for the bug reports everyone! All bugs reported have been fixed, and the desktop got some necessary additions as well.",
added = {
"Right clicking an empty space on the desktop now opens a context menu for creating files and refreshing",
"Files can now be renamed directly from the desktop",
},
fixed = {
"Changed fs.combine into a vararg function on 1.12.2 to fix compatibility issues",
"Modified lUtils.wordwrap to account for the extra empty line that appears on CraftOS-PC",
"Prepared URLs for porting to a different server",
}
},
{
date = "11-08-2022",
version = "2.4.2",
added = {
"The text color of icons on the desktop can now be changed through the desktop context menu",
},
fixed = {
"Trying to perform operations on a shortcut of a deleted file no longer errors"
}
},
{
date = "01-09-2022",
version = "2.4.3",
description = "The new servers are finally here! Expect a lot of new features to follow soon that have become possible thanks to the migration.",
added = {
"Added 3x3 icons to some system folders",
"Migrated to new servers",
},
fixed = {
"Improved LevelCloud efficiency",
"Fixed a number of issues in the login screen",
}
},
{
date = "17-09-2022",
version = "2.4.4",
description = "Finally implemented some much needed LevelCloud features. Sync conflicts now have a proper interface and you can see the status of file synchronization in the LevelOS file explorer.",
added = {
"Explorer now shows synchronization status of cloud files",
"Sync conflicts in LevelCloud can now be resolved through the interface",
"Old context menus in LevelOS now have scrolling like the new ones",
}
},
{
date = "18-09-2022",
version = "2.4.5",
description = "It seems I broke something big last update. Sorry guys, fixed it now.",
fixed = {
"Fixed a recursion issue in the LevelOS Desktop generation that caused a crash on startup",
},
},
{
date = "12-02-2023",
version = "2.4.6",
description = "This update is all about bugfixes. The entire list of bugs has been worked through except for one, so thanks for all of the reports!",
fixed = {
"Explorer no longer crashes when the opened folder is deleted",
"LevelOS no longer displays a warning about LuaJIT when not using LuaJIT",
"LevelOS no longer crashes when being ran again after being terminated",
"Pressing space during a blue screen actually restarts now",
"The Lua REPL no longer crashes when documentation is not found",
"Icons no longer go under the taskbar",
},
added = {
"The store now displays icons of apps that use the recommended LevelOS program structure (a main.lua file with a 3x3 icon.bimg file in a folder)",
},
},
{
date = "25-11-2023",
version = "2.4.7",
description = "A small update to fix some things in the lUtils API. LevelOS 3 is in development and coming soon!",
fixed = {
"The lUtils text editor (used by the Lua REPL and Slime Text) now recognizes indenting as a change to be saved and undone",
"The lUtils.popup function now automatically sets width and/or height if not provided",
"The lUtils.popup function now uses a better word wrapping algorithm so text doesn't go outside of the box anymore",
"The start menu on the taskbar now opens instantly without having to receive another event",
},
},
{
date = "28-11-2023",
version = "2.4.8",
description = "Another small update with some bugfixes that were reported a while ago.",
fixed = {
"Resizing the entirety of LevelOS now works correctly",
"Trying to execute LevelOS within itself no longer causes a bluescreen",
},
},
{
date = "09-12-2023",
version = "2.4.9",
added = {
"You can now copy/paste text within the lUtils text editor using ctrl+c and ctrl+v outside of emulators as well, as long as you have some kind of text in your clipboard",
"Autocomplete in the lUtils text editor can now list nil values",
"Added lOS.getRunningProcess()",
}
},
{
date = "09-04-2024",
version = "2.5.0",
major = true,
description = "LevelOS 2 is finally completely compatible with CC: Tweaked 1.109! Apologies it took so long!",
added = {
"HTTP requests are now private to the programs sending them and can't conflict with eachother",
"The tabs and search in the store are now functional, and creator names are displayed below the program titles",
},
fixed = {
"LevelOS is now compatible with CC 1.109 and above",
"lOS.getRunningProcess() now returns the correct process at all times",
}
},
{
date = "11-04-2024",
version = "2.5.1",
fixed = {
"Restored compatibility with 1.12.2 versions of CC: Tweaked",
},
},
{
date = "18-04-2024",
version = "2.5.2",
fixed = {
"Added compatibility with the newest CraftOS-PC Accelerated",
},
},
{
date = "10-08-2024",
version = "2.5.3",
fixed = {
"Fixed the bluescreen upon closing the changelog on newer versions of ComputerCraft",
"Fixed a bug with UTF-8 decoding",
},
},
{
date = "11-08-2024",
version = "2.5.4",
fixed = {
"Resolved an error in the updater with the newer versions of ComputerCraft",
},
},
}

View File

@ -0,0 +1,3 @@
{
package = "Full",
}

1
LevelOS/data/version.txt Normal file
View File

@ -0,0 +1 @@
1723386918734

1608
LevelOS/desktop.lua Normal file

File diff suppressed because it is too large Load Diff

85
LevelOS/imageviewer.lua Normal file
View File

@ -0,0 +1,85 @@
local format
local function getLines(str)
local lines = {}
local w = 0
for potato in str:gmatch("[^\n]+") do
table.insert(lines,potato)
if #potato > w then
w = #potato
end
end
return lines,w
end
--[[local function render(spr)
term.setBackgroundColor(colors.black)
term.clear()
if format == "lImg" then
local sW,sH = #spr[1][1],#spr
local w,h = term.getSize()
for l=1,#spr do
term.setCursorPos(math.ceil(w/2)-math.floor(sW/2),math.ceil(h/2)-math.floor(sH/2)+(l-1))
local bl = {}
bl[1] = spr[l][1]
bl[2] = string.gsub(spr[l][2],"T",lUtils.toBlit(term.getBackgroundColor()))
bl[3] = string.gsub(spr[l][3],"T",lUtils.toBlit(term.getBackgroundColor()))
term.blit(unpack(bl))
end
elseif format == "nfp" or format == "nfg" then
local b,e = string.find(spr,"\n")
local sW,sH
local w,h = term.getSize()
local lines,sW = getLines(spr)
sH = #lines
for l=1,sH do
term.setCursorPos(math.ceil(w/2)-math.floor(sW/2),math.ceil(h/2)-math.floor(sH/2)+(l-1))
term.blit(string.rep(" ",#lines[l]),lines[l],lines[l])
end
end
end]]
local render = lUtils.renderImg
local tArgs = {...}
local filepath
if tArgs[1] ~= nil and fs.exists(tArgs[1]) then
filepath = tArgs[1]
end
while not filepath do
filepath = lUtils.explorer("User","SelFile false")
end
local sprite = {}
local ext = lUtils.getFileType(filepath)
if ext == ".nfp" then
format = "nfp"
sprite[1] = lUtils.fread(filepath)
elseif ext == ".nfg" then
format = "nfg"
sprite = lUtils.asset.load(filepath)
elseif ext == ".limg" or ext == ".bimg" then
format = "lImg"
sprite = lUtils.asset.load(filepath)
else
lUtils.popup("Error","This file type is not supported!",22,9,{"OK"})
return
end
local tID = os.startTimer(0.5)
render(sprite[1])
local spr = 1
while true do
local e = {os.pullEvent()}
if #sprite > 1 and e[1] == "timer" and e[2] == tID then
tID = os.startTimer(0.1)
spr = spr+1
if spr > #sprite then
spr = 1
end
term.clear()
render(sprite[spr])
elseif e[1] == "term_resize" then
term.clear()
render(sprite[spr])
end
end

258
LevelOS/lStore.lua Normal file
View File

@ -0,0 +1,258 @@
local cookie
if lOS and lOS.userID then
cookie = {Cookie=lOS.userID}
end
local function printUsage()
local programName = arg[0] or fs.getName(shell.getRunningProgram())
print("Usages:")
print(programName .. " put <path> <project name> [listing]")
print(programName .. " get <project name> <path>")
print(programName .. " run <project name> <arguments>")
end
local tArgs = { ... }
if #tArgs < 2 then
printUsage()
return
end
if not http then
printError("LevelStore requires the http API")
printError("Set http.enabled to true in CC: Tweaked's config")
return
end
local function fread(file)
local f = fs.open(file,"r")
local o = f.readAll()
f.close()
return o
end
local function fwrite(file,content)
local f = fs.open(file,"w")
f.write(content)
f.close()
return true
end
local hpost = http.post
local function getField(thing,fieldname)
if string.find(thing,"<"..fieldname..">",1,true) ~= nil and string.find(thing,"</"..fieldname..">",1,true) ~= nil then
begin = nil
ending = nil
trash,begin = string.find(thing,"<"..fieldname..">",1,true)
ending,ending2 = string.find(thing,"</"..fieldname..">",begin+1,true)
if begin ~= nil and ending ~= nil then
return string.sub(thing,begin+1,ending-1),string.sub(thing,1,trash-1)..string.sub(thing,ending2+1,string.len(thing))
end
end
return nil
end
local rType
local function download(name,pth,saveto,run)
local f = hpost("https://os.leveloper.cc/sGet.php","path="..textutils.urlEncode(pth).."&"..rType.."="..textutils.urlEncode(name),cookie).readAll()
if f and f ~= "409" and f ~= "403" and f ~= "401" then
if run then
return f
else
fwrite(saveto,f)
return true
end
else
return false
end
end
local function get(name)
write("Connecting to LevelStore... ")
rType = "code"
local response, err = http.post("https://os.leveloper.cc/sGet.php","path="..textutils.urlEncode("").."&code="..textutils.urlEncode(name),cookie)
if not response then
rType = "name"
response, err = http.post("https://os.leveloper.cc/sGet.php","path="..textutils.urlEncode("").."&name="..textutils.urlEncode(name),cookie)
end
if response then
local tree = {}
local folders = {}
local function searchFolder(folder)
--print("Searching folder root/"..folder)
local f = hpost("https://os.leveloper.cc/sGet.php","path="..textutils.urlEncode(folder).."&"..rType.."="..textutils.urlEncode(name),cookie).readAll()
--print(f)
local f2 = f
while true do
local file = nil
file,f = getField(f,"file")
if not file then
break
else
local name = getField(file,"name")
tree[#tree+1] = fs.combine(folder,name)
--print("Found "..fs.combine(folder,name))
end
end
f = f2
while true do
local file = nil
file,f = getField(f,"folder")
if not file then
break
else
local name = getField(file,"name")
--if not fs.exists(fs.combine(folder,name)) then
--fs.makeDir(fs.combine(folder,name))
--end
folders[#folders+1] = fs.combine(folder,name)
searchFolder(fs.combine(folder,name))
end
end
return true
end
searchFolder("")
print("Success.")
return tree,folders
else
printError("Failed.")
print(err)
end
end
local sCommand = tArgs[1]
if sCommand == "put" then
if #tArgs < 3 then
printUsage()
return
end
local listings = {"unlisted","public"}
for t=1,#listings do
listings[listings[t]] = true
end
local listing
if tArgs[4] then
if not listings[tArgs[4]] then
error(tArgs[4].." is not a valid listing. Choose one of the following: "..table.concat( listings, ", "),0)
else
listing = tArgs[4]
end
end
if not lOS.userID then
print("Not logged in")
print("Please have an active instance of LevelCloud running")
return
end
local sFile = tArgs[2]
local sPath = shell.resolve(fs.combine("User/Cloud",sFile))
if not fs.exists(sPath) or not string.find(sPath,"User/Cloud") then
print("Path not found")
print("Note: provide a relative path to a file or folder starting from cloud")
return
end
local sName = string.gsub(tArgs[3]," ","_")
local list = ""
if listing then
list = "&listing="..textutils.urlEncode(listing)
end
write("Connecting to LevelStore... ")
local response = http.post(
"https://os.leveloper.cc/sProject.php",
"path="..textutils.urlEncode(tArgs[2])..
"&title="..textutils.urlEncode(sName)..
"&timestamp="..textutils.urlEncode(tostring(os.epoch("utc")))..
"&direct="..textutils.urlEncode("false")..
list,
{
Cookie = lOS.userID
}
)
if response then
print("Success.")
local sResponse = response.readAll()
response.close()
print("Uploaded as " .. sResponse)
print("Run \"lStore get " .. sName .. "\" or \"lStore get " .. sResponse .. "\" to download anywhere")
else
printError("Failed.")
end
elseif sCommand == "get" then
if #tArgs < 3 then
printUsage()
return
end
-- Determine file to download
local sCode = tArgs[2]
local sFile = tArgs[3]
local sPath = shell.resolve(sFile)
if fs.exists(sPath) then
print("Path already exists")
return
end
local tree,folders = get(sCode)
if not tree then return end
term.write("Downloading... ")
local x,y = term.getCursorPos()
term.write("0%")
if #tree > 1 or #folders > 0 then
fs.makeDir(sPath)
for f=1,#folders do
fs.makeDir(fs.combine(sPath,folders[f]))
end
for f=1,#tree do
download(sCode,tree[f],fs.combine(sPath,tree[f]))
term.setCursorPos(x,y)
term.write(math.ceil((f/#tree)*100+0.5).."%")
end
else
download(sCode,tree[1],sPath)
end
term.setCursorPos(x,y)
print("100%")
print("Downloaded as " .. sFile)
elseif sCommand == "run" then
local sCode = tArgs[2]
local res
local tree,folders = get(sCode)
if not tree then return end
if #tree > 1 or #folders > 0 then
print("This project must be downloaded to run.")
return
else
--print(textutils.serialize(tree))
res = download(sCode,tree[1],"",true)
end
if res then
local func, err = load(res, sCode, "t", _ENV)
if not func then
printError(err)
return
end
local success, msg = pcall(func, select(3, ...))
if not success then
printError(msg)
end
end
else
printUsage()
return
end

396
LevelOS/login.lua Normal file
View File

@ -0,0 +1,396 @@
local bg = term.getBackgroundColor()
local fg = term.getTextColor()
if fs.exists("bigfont") then
os.loadAPI("bigfont")
end
local register = false
local rememberme = false
local w,h = term.getSize()
local userbox = lUtils.makeEditBox("username",w,1)
local pwbox = lUtils.makeEditBox("password",w,1)
local pwconfirm = lUtils.makeEditBox("pwconfirm",w,1)
if fs.exists("LevelOS/data/account.txt") then
userbox.lines[1] = lUtils.fread("LevelOS/data/account.txt")
end
if fs.exists("LevelOS/data/account2.txt") then
--pwbox.lines[1] = lUtils.fread("LevelOS/data/account2.txt")
token = lUtils.fread("LevelOS/data/account2.txt")
--rememberme = true
local res = http.post("https://www.old.leveloper.cc/auth.php","username="..userbox.lines[1].."&token="..token)
local str = res.readAll()
if str:find("Welcome") then
local userID = res.getResponseHeaders()["Set-Cookie"]
return userID,userbox.lines[1]
end
end
local trysub = false
local continue = true
local boxes = {}
local e = {}
local webresponse
local userID = ""
local pause = false
local function submit()
trysub = true
continue = true
os.sleep(0.5)
if continue == true then
saveuser = fs.open("LevelOS/data/account.txt","w")
saveuser.write(userbox.lines[1])
saveuser.close()
if rememberme then
--lUtils.fwrite("LevelOS/data/account2.txt",pwbox.lines[1])
else
fs.delete("LevelOS/data/account2.txt")
end
if register then
response = {http.post("https://www.old.leveloper.cc/register.php","username="..userbox.lines[1].."&password="..pwbox.lines[1])}
local webres = response[1].readAll()
if webres == "200" then
local xtra = ""
if rememberme then
xtra = "&rememberme=true"
end
response2 = {http.post("https://www.old.leveloper.cc/auth.php","username="..userbox.lines[1].."&password="..pwbox.lines[1]..xtra)}
userID = response2[1].getResponseHeaders()["Set-Cookie"]
webresponse = webres
if rememberme then
token = lUtils.getField(response2[1].readAll(),"token")
lUtils.fwrite("LevelOS/data/account2.txt",token)
end
end
else
local xtra = ""
if rememberme then
xtra = "&rememberme=true"
end
response = {http.post("https://www.old.leveloper.cc/auth.php","username="..userbox.lines[1].."&password="..pwbox.lines[1]..xtra)}
webresponse = response[1].readAll()
userID = response[1].getResponseHeaders()["Set-Cookie"]
if rememberme then
token = lUtils.getField(webresponse,"token")
lUtils.fwrite("LevelOS/data/account2.txt",token)
end
end
--print("username="..userbox.lines[1].."&password="..pwbox.lines[1])
-- check if things are present communicate with PHP
end
end
local regsel = false
local function draw()
boxes = {}
local cY = 1
local w,h = term.getSize()
term.setBackgroundColor(colors.white)
term.clear()
term.setBackgroundColor(colors.white)
if h < 19 then
-- absolutely fkin nothin
elseif h < 25 or w < 26 or not bigfont then
for t=0,2 do
term.setCursorPos(1,cY+t)
term.clearLine()
end
term.setCursorPos(2,cY+2)
term.setTextColor(colors.white)
term.setBackgroundColor(colors.lightGray)
term.write(string.rep("\143",w-2))
term.setTextColor(colors.blue)
term.setBackgroundColor(colors.white)
cY = cY+1
term.setCursorPos(1,cY)
if register then
lUtils.centerText("Register")
else
lUtils.centerText("Log in")
end
cY = cY+2
else
if h < 50 or w < 90 then
for t=0,4 do
term.setCursorPos(1,cY+t)
term.clearLine()
end
term.setCursorPos(2,cY+4)
else
for t=0,10 do
term.setCursorPos(1,cY+t)
term.clearLine()
end
term.setCursorPos(2,cY+10)
end
term.setTextColor(colors.white)
term.setBackgroundColor(colors.lightGray)
term.write(string.rep("\143",w-2))
term.setTextColor(colors.blue)
term.setBackgroundColor(colors.white)
cY = cY+1
local size = 1
--cY = cY+4
if h >= 50 and w >= 90 then
size = 2
cY = cY+10
else
cY = cY+4
end
if register then
bigfont.writeOn(term.current(),size,"Register",nil,2)
else
bigfont.writeOn(term.current(),size,"Log in",nil,2)
end
end
term.setBackgroundColor(colors.white)
for y=cY,h do
term.setCursorPos(1,y)
term.clearLine()
end
cY = cY+1
term.setTextColor(colors.lightGray)
local offset = math.ceil(w/30)
local spacing = 0
if h > 50 then
spacing = 5
elseif h > 45 then
spacing = 4
elseif h > 40 then
spacing = 3
elseif h > 35 then
spacing = 2
elseif h > 30 then
spacing = 1
end
cY = cY+spacing
if (register and trysub and userbox.lines[1] and userbox.lines[1] ~= "" and string.len(userbox.lines[1]) >= 3 and #userbox.lines[1] <= 15 and not string.find(userbox.lines[1],"[^a-zA-Z0-9]")) then -- also check for special characters
term.setTextColor(colors.lime)
elseif register and trysub then
term.setTextColor(colors.red)
term.setCursorPos(1,cY+3)
if #userbox.lines[1] < 3 or #userbox.lines[1] > 15 then
lUtils.centerText("Username must be between 3-15 characters.")
else
lUtils.centerText("Username can not contain special characters.")
end
continue = false
else
term.setTextColor(colors.lightGray)
end
lUtils.border(1+offset,cY,w-offset,cY+2)
userbox.x = 2+offset
userbox.y = cY+1
userbox.width = ((w-offset)-1)-(1+offset)
boxes[#boxes+1] = {x1=1+offset,y1=cY,x2=w-offset,y2=cY+2,func=function() lUtils.drawEditBox(userbox,nil,nil,nil,nil,nil,nil,true,false) end}
cY = cY+1
term.setCursorPos(2+offset,cY)
if userbox.lines[1] and userbox.lines[1] ~= "" then
term.setTextColor(colors.gray)
term.write(string.sub(userbox.lines[1],1,userbox.width))
else
term.write("Username")
end
cY = cY+3+spacing
if (register and trysub and pwbox.lines[1] and pwbox.lines[1] ~= "" and string.len(pwbox.lines[1]) >= 5) then
term.setTextColor(colors.lime)
elseif register and trysub then
term.setTextColor(colors.red)
continue = false
else
term.setTextColor(colors.lightGray)
end
lUtils.border(1+offset,cY,w-offset,cY+2)
pwbox.x = 2+offset
pwbox.y = cY+1
pwbox.width = ((w-offset)-1)-(1+offset)
boxes[#boxes+1] = {x1=1+offset,y1=cY,x2=w-offset,y2=cY+2,func=function() lUtils.drawEditBox(pwbox,nil,nil,nil,nil,nil,nil,true,false,"*") end}
cY = cY+1
term.setCursorPos(2+offset,cY)
if pwbox.lines[1] and pwbox.lines[1] ~= "" then
term.setTextColor(colors.gray)
term.write(string.rep("*",string.len(string.sub(pwbox.lines[1],1,pwbox.width))))
else
term.write("Password")
end
if register then
cY = cY+3+spacing
if (register and trysub and pwconfirm.lines[1] and pwconfirm.lines[1] ~= "" and string.len(pwconfirm.lines[1]) > 3 and pwconfirm.lines[1] == pwbox.lines[1]) then
term.setTextColor(colors.lime)
elseif register and trysub then
term.setTextColor(colors.red)
if spacing > 0 then
term.setCursorPos(1,cY+3)
lUtils.centerText("Passwords don't match.")
end
continue = false
else
term.setTextColor(colors.lightGray)
end
lUtils.border(1+offset,cY,w-offset,cY+2)
pwconfirm.x = 2+offset
pwconfirm.y = cY+1
pwconfirm.width = ((w-offset)-1)-(1+offset)
boxes[#boxes+1] = {x1=1+offset,y1=cY,x2=w-offset,y2=cY+2,func=function() lUtils.drawEditBox(pwconfirm,nil,nil,nil,nil,nil,nil,true,false,"*") end}
cY = cY+1
term.setCursorPos(2+offset,cY)
if pwconfirm.lines[1] and pwconfirm.lines[1] ~= "" then
term.setTextColor(colors.gray)
term.write(string.rep("*",string.len(string.sub(pwconfirm.lines[1],1,pwconfirm.width))))
else
term.write("Confirm Password")
end
end
cY = cY+3+spacing
term.setTextColor(colors.white)
if e[1] == "mouse_click" and e[3] >= 1+(offset+2) and e[4] >= cY and e[3] <= w-(offset+2) and e[4] <= cY+2 then
regsel = true
elseif e[1] == "mouse_up" then
regsel = false
end
if regsel or trysub then
term.setBackgroundColor(colors.lightBlue)
else
term.setBackgroundColor(colors.blue)
end
lUtils.border(1+(offset+2),cY,w-(offset+2),cY+2,"fill")
boxes[#boxes+1] = {x1=1+(offset+2),y1=cY,x2=w-(offset+2),y2=cY+2,func=submit}
cY = cY+1
term.setCursorPos(1,cY)
if register then
lUtils.centerText("Register")
term.setBackgroundColor(colors.white)
term.setTextColor(colors.lightBlue)
term.setCursorPos(1,cY-2)
local w,h = term.getSize()
if w < string.len("Already have an account? Log in.") then
lUtils.centerText("Log in")
else
lUtils.centerText("Already have an account? Log in.")
end
boxes[#boxes+1] = {x1=math.ceil(w/2)-16,x2=math.ceil(w/2)+16,y1=cY-2,y2=cY-2,func=function() register = false end}
else
lUtils.centerText("Log in")
term.setBackgroundColor(colors.white)
term.setTextColor(colors.lightBlue)
term.setCursorPos(1,cY+2)
local w,h = term.getSize()
if w < string.len("Don't have an account yet? Register.") then
lUtils.centerText("Register")
else
lUtils.centerText("Don't have an account yet? Register.")
end
boxes[#boxes+1] = {x1=math.ceil(w/2)-18,x2=math.ceil(w/2)+18,y1=cY+2,y2=cY+2,func=function() register = true end}
end
cY = cY+4
local bl = {
{
"Ÿ",
"00f",
"ff0",
},
{
"• •",
"0ff",
"f00",
},
{
"‚ƒ",
"fff",
"000",
},
}
if rememberme then
bl[2][1] = "•x•"
end
local txt = " Auto-login" -- 4 spaces for the box
local rX = math.ceil(w/2)-math.floor(#txt/2)
term.setCursorPos(rX,cY)
term.setBackgroundColor(colors.white)
term.setTextColor(colors.gray)
term.write(txt)
for b=1,#bl do
term.setCursorPos(rX,(cY-2)+b)
term.blit(unpack(bl[b]))
end
table.insert(boxes,{x1=rX,y1=cY,x2=rX+2,y2=cY,func=function() local f = function() rememberme = not rememberme end pause = true f() pause = false end})
end
local function textboxes()
while true do
local e = {os.pullEvent()}
term.setCursorPos(1,1)
term.setBackgroundColor(colors.white)
term.setTextColor(colors.black)
--term.write(table.concat(e,", "))
if e[1] == "mouse_up" and e[2] == 1 then
for b=1,#boxes do
local box = boxes[b]
if e[3] >= box.x1 and e[4] >= box.y1 and e[3] <= box.x2 and e[4] <= box.y2 then
trysub = false
box.func()
os.startTimer(0.1)
end
end
end
end
end
local txtbox = coroutine.create(textboxes)
if rememberme then submit() end
draw()
while true do
e = {os.pullEvent()}
local w,h = term.getSize()
local pW,pH
if w < 29 then
pW = 19
pH = 15
else
pW = 29
pH = 9
end
if not webresponse then
if not pause then
draw()
end
coroutine.resume(txtbox,table.unpack(e))
while pause do
local e = {os.pullEvent()}
coroutine.resume(txtbox,table.unpack(e))
end
else
if (register and webresponse ~= "200") or (not register and not string.find(webresponse,"Welcome")) then
lUtils.popup("LevelOS",lUtils.getField(webresponse,"msg"),pW,pH,{"OK"})
term.setTextColor(fg)
term.setBackgroundColor(bg)
if rememberme then
rememberme = false
fs.delete("LevelOS/data/account2.txt")
end
return false
elseif register then
lUtils.popup("LevelOS","You have successfully registered! You are now logged in.",pW,pH,{"OK"})
term.setTextColor(fg)
term.setBackgroundColor(bg)
return userID,userbox.lines[1]
else
term.setTextColor(fg)
term.setBackgroundColor(bg)
return userID,userbox.lines[1]
end
end
end

713
LevelOS/modules/lex.lua Normal file
View File

@ -0,0 +1,713 @@
-- Lex, by LoganDark
-- Can be loaded using os.loadAPI, has only a single function: lex.lex('code here')
-- If loaded using dofile(), it returns the lex function (for environments outside ComputerCraft)
-- It returns a list of lists, where each list is one line.
-- Each line contains tokens (in the order they are found), where each token is formatted like this:
-- {
-- type = one of the token types below,
-- data = the source code that makes up the token,
-- posFirst = the position (inclusive) within THAT LINE that the token starts
-- posLast = the position (inclusive) within THAT LINE that the token ends
-- }
-- Possible token types:
-- whitespace: Self-explanatory. Can match spaces, newlines, tabs, and carriage returns (although I don't know why anyone would use those... WINDOWS)
-- comment: Either multi-line or single-line comments.
-- string: A string. Usually the part of the string that is not an escape.
-- escape: Can only be found within strings (although they are separate tokens)
-- keyword: Keywords. Like "while", "end", "do", etc
-- value: Special values. Only true, false, and nil.
-- ident: Identifier. Variables, function names, etc..
-- number: Numbers!
-- symbol: Symbols, like brackets, parenthesis, ., .., ... etc
-- operator: Operators, like =, ==, >=, <=, ~=, etc
-- unidentified: Anything that isn't one of the above tokens. Consider them ERRORS.
local chars = {
whitespace = {
[' '] = true,
['\n'] = true,
['\t'] = true,
['\r'] = true
},
validEscapes = {
['a'] = true,
['b'] = true,
['f'] = true,
['n'] = true,
['r'] = true,
['t'] = true,
['v'] = true,
['"'] = true,
['\''] = true,
['\\'] = true,
['\n'] = true
},
ident = {
['a'] = true,
['b'] = true,
['c'] = true,
['d'] = true,
['e'] = true,
['f'] = true,
['g'] = true,
['h'] = true,
['i'] = true,
['j'] = true,
['k'] = true,
['l'] = true,
['m'] = true,
['n'] = true,
['o'] = true,
['p'] = true,
['q'] = true,
['r'] = true,
['s'] = true,
['t'] = true,
['u'] = true,
['v'] = true,
['w'] = true,
['x'] = true,
['y'] = true,
['z'] = true,
['A'] = true,
['B'] = true,
['C'] = true,
['D'] = true,
['E'] = true,
['F'] = true,
['G'] = true,
['H'] = true,
['I'] = true,
['J'] = true,
['K'] = true,
['L'] = true,
['M'] = true,
['N'] = true,
['O'] = true,
['P'] = true,
['Q'] = true,
['R'] = true,
['S'] = true,
['T'] = true,
['U'] = true,
['V'] = true,
['W'] = true,
['X'] = true,
['Y'] = true,
['Z'] = true,
['_'] = true,
['0'] = true,
['1'] = true,
['2'] = true,
['3'] = true,
['4'] = true,
['5'] = true,
['6'] = true,
['7'] = true,
['8'] = true,
['9'] = true,
start = {
['a'] = true,
['b'] = true,
['c'] = true,
['d'] = true,
['e'] = true,
['f'] = true,
['g'] = true,
['h'] = true,
['i'] = true,
['j'] = true,
['k'] = true,
['l'] = true,
['m'] = true,
['n'] = true,
['o'] = true,
['p'] = true,
['q'] = true,
['r'] = true,
['s'] = true,
['t'] = true,
['u'] = true,
['v'] = true,
['w'] = true,
['x'] = true,
['y'] = true,
['z'] = true,
['A'] = true,
['B'] = true,
['C'] = true,
['D'] = true,
['E'] = true,
['F'] = true,
['G'] = true,
['H'] = true,
['I'] = true,
['J'] = true,
['K'] = true,
['L'] = true,
['M'] = true,
['N'] = true,
['O'] = true,
['P'] = true,
['Q'] = true,
['R'] = true,
['S'] = true,
['T'] = true,
['U'] = true,
['V'] = true,
['W'] = true,
['X'] = true,
['Y'] = true,
['Z'] = true,
['_'] = true
},
},
digits = {
['0'] = true,
['1'] = true,
['2'] = true,
['3'] = true,
['4'] = true,
['5'] = true,
['6'] = true,
['7'] = true,
['8'] = true,
['9'] = true,
hex = {
['0'] = true,
['1'] = true,
['2'] = true,
['3'] = true,
['4'] = true,
['5'] = true,
['6'] = true,
['7'] = true,
['8'] = true,
['9'] = true,
['a'] = true,
['b'] = true,
['c'] = true,
['d'] = true,
['e'] = true,
['f'] = true,
['A'] = true,
['B'] = true,
['C'] = true,
['D'] = true,
['E'] = true,
['F'] = true
}
},
symbols = {
['+'] = true,
['-'] = true,
['*'] = true,
['/'] = true,
['^'] = true,
['%'] = true,
[','] = true,
['{'] = true,
['}'] = true,
['['] = true,
[']'] = true,
['('] = true,
[')'] = true,
[';'] = true,
['#'] = true,
['.'] = true,
[':'] = true,
equality = {
['~'] = true,
['='] = true,
['>'] = true,
['<'] = true
},
operators = {
['+'] = true,
['-'] = true,
['*'] = true,
['/'] = true,
['^'] = true,
['%'] = true,
['#'] = true
}
}
}
local keywords = {
structure = {
['and'] = true,
['break'] = true,
['do'] = true,
['else'] = true,
['elseif'] = true,
['end'] = true,
['for'] = true,
['function'] = true,
['goto'] = true,
['if'] = true,
['in'] = true,
['local'] = true,
['not'] = true,
['or'] = true,
['repeat'] = true,
['return'] = true,
['then'] = true,
['until'] = true,
['while'] = true
},
values = {
['true'] = true,
['false'] = true,
['nil'] = true,
['self'] = true,
}
}
function lex(text)
local pos = 1
local start = 1
local len = #text
local buffer = {}
local lines = {}
local function look(delta)
delta = pos + (delta or 0)
return text:sub(delta, delta)
end
local function get()
local char = text:sub(pos, pos)
pos = pos + 1
return char
end
local function getLevel()
local num = 0
while look(num) == '=' do
num = num + 1
end
if look(num) == '[' then
pos = pos + num
return num
else
return nil
end
end
local function getToken()
return text:sub(start, pos - 1)
end
local currentLineLength = 0
local lineoffset = 0
local function token(type, text)
local tk = buffer[#buffer]
if not tk or tk.type ~= type then
local tk = {
type = type,
data = text or getToken(),
posFirst = start - lineoffset,
posLast = pos - 1 - lineoffset
}
if tk.data ~= '' then
buffer[#buffer + 1] = tk
end
else
tk.data = tk.data .. (text or getToken())
tk.posLast = tk.posFirst + #tk.data - 1
--tk.posLast = getCol(pos - 1)
end
currentLineLength = currentLineLength + (text or getToken()):len()
start = pos
return tk
end
local function newline()
lines[#lines + 1] = buffer
buffer = {}
get()
token('newline')
buffer[1] = nil
lineoffset = lineoffset + currentLineLength
currentLineLength = 0
end
local function getData(level, type)
while true do
local char = get()
if char == '' then
return
elseif char == '\n' then
pos = pos - 1
token(type)
newline()
elseif char == ']' then
local valid = true
for i = 1, level do
if look() == '=' then
pos = pos + 1
else
valid = false
break
end
end
if valid and look() == ']' then
pos = pos + 1
return
end
end
end
end
while true do
while true do
local char = look()
if char == '\n' then
token('whitespace')
newline()
elseif chars.whitespace[char] then
pos = pos + 1
else
break
end
end
token('whitespace')
local char = get()
if char == '' then
break
elseif char == '-' and look() == '-' then
pos = pos + 1
if look() == '[' then
pos = pos + 1
local level = getLevel()
if level then
getData(level, 'comment')
else
while true do
local char2 = get()
if char2 == '' or char2 == '\n' then
pos = pos - 1
token('comment')
if char2 == '\n' then
newline()
end
break
end
end
end
else
while true do
local char2 = get()
if char2 == '' or char2 == '\n' then
pos = pos - 1
token('comment')
if char2 == '\n' then
newline()
end
break
end
end
end
token('comment')
elseif char == '\'' or char == '"' then
local cbuf = #buffer
while true do
if not buffer[cbuf] then
break
elseif buffer[cbuf].type == "whitespace" then
cbuf = cbuf-1
elseif buffer[cbuf].type == "ident" then
buffer[cbuf].type = "function"
break
else
break
end
end
while true do
local char2 = get()
if char2 == '\\' then
pos = pos - 1
token('string')
get()
local char3 = get()
if chars.digits[char3] then
for i = 1, 2 do
if chars.digits[look()] then
pos = pos + 1
end
end
elseif char3 == 'x' then
if chars.digits.hex[look()] and chars.digits.hex[look(1)] then
pos = pos + 2
else
token('unidentified')
end
elseif char3 == '\n' then
pos = pos - 1
token('escape')
newline()
elseif not chars.validEscapes[char3] then
token('unidentified')
end
token('escape')
elseif char2 == '\n' then
pos = pos - 1
token('string')
newline()
break
elseif char2 == char or char2 == '' then
break
end
end
token('string')
elseif chars.ident.start[char] then
while chars.ident[look()] do
pos = pos + 1
end
local word = getToken()
if word == 'self' or word == '_ENV' or word == "_G" then
token('arg')
elseif word == 'function' then
local findBracket = false
local c = 0
while true do
_G.debugstr = ""
local lChar = look(c)
_G.debugstr = debugstr..lChar
if lChar == " " or lChar == "\t" then
c = c+1
elseif lChar == "(" then
findBracket = true
break
else
break
end
end
if findBracket then
local cbuf = #buffer
local findEquals = false
while true do
--_G.debugstr = debugstr..buffer[cbuf].type
if not buffer[cbuf] then
break
elseif buffer[cbuf].type == "whitespace" then
cbuf = cbuf-1
elseif buffer[cbuf].data == "=" and not findEquals then
cbuf = cbuf-1
findEquals = true
elseif buffer[cbuf].type == "ident" and findEquals then
buffer[cbuf].type = "nfunction"
break
else
break
end
end
end
token('function')
elseif keywords.structure[word] then
token('keyword')
elseif keywords.values[word] then
token('value')
else
local findBracket = false
local c = 0
while true do
local lChar = look(c)
if lChar == " " or lChar == "\t" then
c = c+1
elseif lChar == "(" then
findBracket = true
break
else
break
end
end
if findBracket then
if buffer[#buffer-1] and buffer[#buffer-1].data == "function" and buffer[#buffer].type == "whitespace" then
token('nfunction')
else
token('function')
end
else
local b = #buffer
local isArg = true
local closedArgs = false
while true do
local buf = buffer[b]
if not buf then
isArg = false
break
elseif buf.data == "(" or buf.type == "whitespace" or buf.data == "," or buf.type == "arg" then
if buf.data == "(" then
closedArgs = true
end
b = b-1
elseif (buf.data == "function" or buf.type == "nfunction") and closedArgs then
token('arg')
break
else
isArg = false
break
end
end
if not isArg then
token('ident')
end
end
end
elseif chars.digits[char] or (char == '.' and chars.digits[look()]) then
if char == '0' and look() == 'x' then
pos = pos + 1
while chars.digits.hex[look()] do
pos = pos + 1
end
else
while chars.digits[look()] do
pos = pos + 1
end
if look() == '.' then
pos = pos + 1
while chars.digits[look()] do
pos = pos + 1
end
end
if look():lower() == 'e' then
pos = pos + 1
if look() == '-' then
pos = pos + 1
end
while chars.digits[look()] do
pos = pos + 1
end
end
end
token('number')
elseif char == '[' then
local level = getLevel()
if level then
local cbuf = #buffer
while true do
if not buffer[cbuf] then
break
elseif buffer[cbuf].type == "whitespace" then
cbuf = cbuf-1
elseif buffer[cbuf].type == "ident" then
buffer[cbuf].type = "function"
break
else
break
end
end
getData(level, 'string')
token('string')
else
token('symbol')
end
elseif char == '.' then
if look() == '.' then
pos = pos + 1
if look() == '.' then
pos = pos + 1
token('value')
else
token('operator')
end
else
token('symbol')
end
elseif chars.symbols.equality[char] then
if look() == '=' then
pos = pos + 1
else
end
token('operator')
elseif chars.symbols[char] then
if chars.symbols.operators[char] then
token('operator')
else
if char == "{" then
local cbuf = #buffer
while true do
if not buffer[cbuf] then
break
elseif buffer[cbuf].type == "whitespace" then
cbuf = cbuf-1
elseif buffer[cbuf].type == "ident" then
buffer[cbuf].type = "function"
break
else
break
end
end
end
token('symbol')
end
else
token('unidentified')
end
end
lines[#lines + 1] = buffer
return lines
end
return lex

View File

View File

@ -0,0 +1,147 @@
local class = {}
local tAPI = {} -- local class API for objects
local shapescape
class.init = function(api)
shapescape = api
setmetatable(tAPI, {__index=api.group})
api.generic.convertToClass = class.convertToClass
end
tAPI.initialize = function(obj)
local scape = obj:getScape()
local publicProperties = obj.publicProperties or {}
setmetatable(obj, {__index=tAPI})
obj.isClass = true
local str = ""
for k,v in pairs(publicProperties) do
if v == "" then
table.remove(publicProperties,k)
end
end
if not shapescape.utils.locateEntry(publicProperties, "properties") then
table.insert(publicProperties,"properties")
end
for i,p in ipairs(publicProperties) do
if p == "width" then
str = str.."instance:resize(width or instance.width)\n"
elseif p == "height" then
str = str.."instance:resize(nil, height or instance.height)\n"
elseif p == "x" then
str = str.."instance:move(x or instance.x)\n" -- "or instance.x1" is already done by API when provided with nil value
elseif p == "y" then
str = str.."instance:move(nil, y or instance.y)\n"
else
str = str.."instance."..p.." = "..p.." or instance."..p.."\n"
end
end
table.insert(publicProperties,1,"self")
local fStr = [[
return function(]]..table.concat(publicProperties,",")..[[)
local instance = shapescape.utils.instantiate(self)
if instance.name then
instance.class = instance.name
instance.name = nil
end
]]..str..[[
for k,v in pairs(properties or {}) do
instance[k] = v
end
instance.isClass = nil
return instance
end]]
local func,err = load(fStr,"@instantiate",nil,{shapescape=shapescape,pairs=pairs})
if func then
obj.instantiate = func()
else
_G.debugstr = fStr
error(err,0)
end
if obj.name then
scape.variables[obj.name] = obj
end
end
tAPI.instantiateTo = function(self, target, ...)
if not self.instantiate then
self:initialize()
end
return target:addObject(self:instantiate(...))
end
class.convertToClass = function(self, publicProperties, posProperties)
publicProperties = publicProperties or {}
if self.active then
error("Cannot convert active objects",2)
end
local sl = self:getSlide()
if sl then
-- remove obj from slide
self:destroy(false)
end
setmetatable(self, {__index=tAPI})
self.isClass = true
self.publicProperties = publicProperties
local coords = {}
if posProperties == 1 or posProperties == nil then -- if posProperties is false then no position
coords = {"x1","y1","x2","y2"}
elseif posProperties == 2 then
coords = {"x","y","width","height"}
elseif posProperties == 3 then
coords = {"x","y"}
elseif posProperties == 4 then
coords = {"width","height"}
end
for i,c in ipairs(coords) do
if not shapescape.utils.locateEntry(publicProperties, c) then
table.insert(publicProperties, i, c)
end
end
table.insert(self:getScape().classes,self)
if self:getScape().active then
self:initialize()
end
end
tAPI.convertToObject = function(self,slide)
self.publicProperties = nil
self.isClass = nil
for k,v in ipairs(self:getScape().classes) do
if v == self then
table.remove(self:getScape().classes,k)
end
end
slide:addObject(self)
end
tAPI.destroy = function(self)
-- remove from classes
for k,v in ipairs(scape.classes) do
if v == self then
table.remove(scape.classes,k)
end
end
shapescape.generic.destroy(self)
end
class.load = function(classObj)
setmetatable(classObj, {__index=tAPI})
if classObj.children then
for i,child in ipairs(classObj.children) do
shapescape.loadObject(child)
child.parent = classObj
child.id = i
end
end
end
return class

File diff suppressed because it is too large Load Diff

File diff suppressed because it is too large Load Diff

View File

121
LevelOS/settings.lua Normal file
View File

@ -0,0 +1,121 @@
--ccvs = mwm.newCvs() -- config canvas aka settings canvas
btns = {}
function _G.btn(x,y,width,lines)
btns[#btns+1] = {}
thebtn = btns[#btns]
thebtn.x = x
thebtn.y = y
thebtn.w = width
thebtn.h = #lines+2
function thebtn.render(px,py)
if px == nil then
px,py = thebtn.x,thebtn.y
end
thebtn.blit = {{"\151",tostring(lUtils.toBlit(colors.gray)),tostring(lUtils.toBlit(term.getBackgroundColor()))}}
for t=1,thebtn.w-2 do
thebtn.blit[1][1] = thebtn.blit[1][1].."\131"
thebtn.blit[1][2] = thebtn.blit[1][2]..lUtils.toBlit(colors.gray)
thebtn.blit[1][3] = thebtn.blit[1][3]..lUtils.toBlit(term.getBackgroundColor())
end
thebtn.blit[1][1] = thebtn.blit[1][1].."\148"
thebtn.blit[1][2] = thebtn.blit[1][2]..lUtils.toBlit(term.getBackgroundColor())
thebtn.blit[1][3] = thebtn.blit[1][3]..lUtils.toBlit(colors.gray)
for t=1,#lines do
thebtn.blit[t+1] = {"\149",tostring(lUtils.toBlit(colors.gray)),tostring(lUtils.toBlit(term.getBackgroundColor()))}
for w=1,width-2 do
thebtn.blit[t+1][1] = thebtn.blit[t+1][1].." "
if t == 1 then
thebtn.blit[t+1][2] = thebtn.blit[t+1][2]..lUtils.toBlit(term.getTextColor())
else
thebtn.blit[t+1][2] = thebtn.blit[t+1][2]..lUtils.toBlit(colors.lightGray)
end
thebtn.blit[t+1][3] = thebtn.blit[t+1][3]..lUtils.toBlit(term.getBackgroundColor())
end
local thetxt = ""
if string.len(lines[t]) > thebtn.w-2 then
thetxt = string.sub(lines[t],thebtn.w-2)
else
thetxt = lines[t]
end
thebtn.blit[t+1][1] = "\149"..thetxt..string.sub(thebtn.blit[t+1][1],2+string.len(thetxt),string.len(thebtn.blit[t+1][1]))
thebtn.blit[t+1][1] = thebtn.blit[t+1][1].."\149"
thebtn.blit[t+1][2] = thebtn.blit[t+1][2]..tostring(lUtils.toBlit(term.getBackgroundColor()))
thebtn.blit[t+1][3] = thebtn.blit[t+1][3]..lUtils.toBlit(colors.gray)
end
thebtn.blit[#thebtn.blit+1] = {"\138",tostring(lUtils.toBlit(term.getBackgroundColor())),tostring(lUtils.toBlit(colors.gray))}
local tempblit = thebtn.blit[#thebtn.blit]
for t=1,thebtn.w-2 do
tempblit[1] = tempblit[1].."\143"
tempblit[2] = tempblit[2]..lUtils.toBlit(term.getBackgroundColor())
tempblit[3] = tempblit[3]..lUtils.toBlit(colors.gray)
end
tempblit[1] = tempblit[1].."\133"
tempblit[2] = tempblit[2]..lUtils.toBlit(term.getBackgroundColor())
tempblit[3] = tempblit[3]..lUtils.toBlit(colors.gray)
for t=1,#thebtn.blit do
term.setCursorPos(px,py+(t-1))
term.blit(table.unpack(thebtn.blit[t]))
end
end
return thebtn
end
lSettings = {{"Peripherals","Monitors, Speakers,","Printers"},{"Personal Settings","Background, Welcome","Screen"},{"E","Fookin nonsense","aha"},{"Hello","How are you","Mr Valentine"},{"Hey","I am good thank",":)"}}
btnW = 21
btnH = 5
scrl = 0
function setrender(scr) -- settings render, scroll (Y)
if scr == nil then
scr = 0
end
term.setBackgroundColor(colors.black)
term.clear()
local w,h = term.getSize()
term.setCursorPos(math.ceil(w/2)-math.floor(string.len("Settings")/2),2-scr)
term.setTextColor(colors.white)
term.write("Settings")
local cX = math.ceil(w/2)+1
local cY = 4
while cX-(btnW+1) > 1 do
cX = cX-(btnW+1)
end
local OGcX = cX
btns = {}
for t=1,#lSettings do
--term.setCursorPos(cX,cY-scr)
btn(cX,cY-scr,btnW,lSettings[t]).render()
if cX+(btnW*2+2) <= w then
cX = cX+(btnW+1)
else
cX = OGcX
cY = cY+btnH+1
end
end
end
setrender()
local aw,ah = term.getSize()
local ow,oh = aw,ah
while true do
e = {os.pullEvent()}
if e[1] == "mouse_scroll" then
scrl = scrl+e[2]
setrender(scrl)
elseif e[1] == "mouse_click" then
for t=1,#btns do
if e[3] >= btns[t].x and e[4] >= btns[t].y and e[3] <= btns[t].x+(btns[t].w-1) and e[4] <= btns[t].y+(btns[t].h-1) then
term.setCursorPos(1,1)
print("Yey")
term.setBackgroundColor(colors.gray)
btns[t].render(btns[t].x,btns[t].y)
end
end
elseif e[1] == "mouse_up" then
term.setBackgroundColor(colors.black)
setrender(scrl)
end
aw,ah = term.getSize()
if aw ~= ow or ah ~= oh then
setrender(scrl)
ow,oh = aw,ah
end
end
os.sleep(3)

176
LevelOS/startup/MwMRender Normal file
View File

@ -0,0 +1,176 @@
if mwm == nil then _G.mwm = {} end
function tabletext(text)
local tTable = {}
for a=1,string.len(text) do
tTable[a] = string.sub(text,a,a)
end
return tTable
end
to_colors, to_blit = {}, {}
for i = 1, 16 do
to_blit[2^(i-1)] = ("0123456789abcdef"):sub(i, i)
to_colors[("0123456789abcdef"):sub(i, i)] = 2^(i-1)
end
function mwm.newCvs(tX,tY)
local cvs = {}
cvs.rCvs = {}
cvs.oCvs = {}
cvs.orCvs = {}
cvs.color = colors.white
if tX == nil or tY == nil then
tX,tY = term.getSize()
end
for x=1,tX do
cvs.rCvs[x] = {}
for y=1,tY do
cvs.rCvs[x][y] = {"",term.getBackgroundColor()} -- empty pixel = ""
end
end
cvs.width = tX
cvs.height = tY
local function genCvs()
cvs.rCvs = {}
local tX,tY = cvs.width,cvs.height
for x=1,tX do
cvs.rCvs[x] = {}
for y=1,tY do
cvs.rCvs[x][y] = {"",term.getBackgroundColor()} -- empty pixel = ""
end
end
end
function cvs.setColor(color)
cvs.color = color
end
function cvs.rect(x,y,w,h,text,txtcolor)
if tonumber(x) == nil or tonumber(y) == nil or tonumber(w) == nil or tonumber(h) == nil then
return
end
if text ~= nil then
if txtcolor == nil then
txtcolor = colors.white
end
if type(text) == "string" then
text = {text}
end
for t=1,#text do
if string.len(text[t]) > w then
string.sub(text[t],1,w)
end
end
end
cvs.oCvs[#cvs.oCvs+1] = {type="rect",x=x,y=y,width=w,height=h,color=cvs.color,txt=text,txtcolor=txtcolor,ref=#cvs.oCvs+1}
return cvs.oCvs[#cvs.oCvs],true
end
function cvs.print(text,x,y)
if text == nil or tonumber(x) == nil or tonumber(y) == nil then
return
end
cvs.oCvs[#cvs.oCvs+1] = {type="text",txt=text,x=x,y=y,color=cvs.color}
return cvs.oCvs[#cvs.oCvs],true
end
cvs.write = cvs.print
function cvs.sprite(file,x,y,w,h)
if fs.exists(file) == false then
return
end
opensprite = fs.open(file,"r")
local sprite = opensprite.readAll()
opensprite.close()
sprite = textutils.unserialize(sprite)
if sprite == nil then return end
cvs.oCvs[#cvs.oCvs+1] = {type="sprite",texture=sprite,x=x,y=y,width=w,height=h}
return cvs.oCvs[#cvs.oCvs]
end
-- Support circle rendering. This can be done by calculating with math.cos how many pixels it is from one side of one y coord to the other side of the same y coord and putting that in a string. repeat this for every y coord then draw
function cvs.clear()
cvs.oCvs = {}
end
function cvs.render(trans,x1,y1,x2,y2)
if x1 == nil then x1 = 1 end
if y1 == nil then y1 = 1 end
if x2 == nil then x2 = cvs.width end
if y2 == nil then y2 = cvs.height end
genCvs()
bgcolor = term.getBackgroundColor()
for a=1,#cvs.oCvs do
local o = cvs.oCvs[a]
cvs.oCvs[a].ref = a
o.x = math.floor(o.x+0.5)
o.y = math.floor(o.y+0.5)
if o.type == "rect" then
for b=1,o.height do
for c=1,o.width do
local tX,tY = term.getSize()
if o.x+(c-1) <= tX and o.y+(b-1) <= tY and o.x+(c-1) > 0 and o.y+(b-1) > 0 then
cvs.rCvs[o.x+(c-1)][o.y+(b-1)] = {" ",o.color}
end
end
end
if o.txt ~= nil and o.txtcolor ~= nil then
for b=1,o.height do
if o.txt[b] ~= nil then
dObj = tabletext(o.txt[b])
for c=1,string.len(o.txt[b]) do
cvs.rCvs[o.x+(c-1)][o.y+(b-1)] = {dObj[c],o.color,o.txtcolor}
end
end
end
end
elseif o.type == "sprite" then
for b=1,o.height do
for c=1,o.width do
if o.texture[c] ~= nil then
local tX,tY = term.getSize()
if o.x+(c-1) <= tX and o.y+(b-1) <= tY and o.x+(c-1) > 0 and o.y+(b-1) > 0 and o.texture[c][b] ~= nil then
cvs.rCvs[o.x+(c-1)][o.y+(b-1)] = o.texture[c][b]
end
end
end
end
elseif o.type == "text" then
dObj = tabletext(o.txt)
for b=1,#dObj do
local tX,tY = term.getSize()
if o.x+(b-1) <= tX and o.y <= tY and o.x+(b-1) > 0 and o.y > 0 then
cvs.rCvs[o.x+(b-1)][o.y][1] = dObj[b]
cvs.rCvs[o.x+(b-1)][o.y][3] = o.color
end
end
end
end
for y=y1,y2 do
bl1 = ""
bl2 = ""
bl3 = ""
for x=x1,x2 do
if not (cvs.orCvs[x] ~= nil and cvs.orCvs[x][y] == cvs.rCvs[x][y]) then
if cvs.rCvs[x][y][1] == "" then
if term.current().getLine and trans then
local theline = {term.current().getLine(y)}
bl1 = bl1..string.sub(theline[1],x,x)
bl2 = bl2..string.sub(theline[2],x,x)
bl3 = bl3..string.sub(theline[3],x,x)
else
bl1 = bl1.." "
bl2 = bl2..0
bl3 = bl3..to_blit[cvs.rCvs[x][y][2]]
end
else
if cvs.rCvs[x][y][3] ~= nil then
bl2 = bl2..to_blit[cvs.rCvs[x][y][3]]
else
bl2 = bl2..0
end
bl1 = bl1..tostring(cvs.rCvs[x][y][1])
bl3 = bl3..to_blit[cvs.rCvs[x][y][2]]
end
end
end
term.setCursorPos(x1,y)
term.blit(bl1,bl2,bl3)
end
cvs.orCvs = cvs.rCvs
term.setBackgroundColor(bgcolor)
end
return cvs
end

View File

@ -4384,9 +4384,9 @@ function lUtils.openWin(title,filepath,x,y,width,height,canresize,canmaximize)
end
term.setTextColor(colors.white)
if canmaximize == false then
term.write(" × ")
term.write(" × ")
else
term.write(" + × ")
term.write(" + × ")
end
term.setCursorPos(x+1,y)
term.write(title)
@ -4501,7 +4501,7 @@ function lUtils.openWin(title,filepath,x,y,width,height,canresize,canmaximize)
term.setTextColor(colors.white)
term.setBackgroundColor(colors.red)
term.setCursorPos(x+(width-3),y)
term.write(" × ")
term.write(" × ")
elseif e[1] == "mouse_up" then
stop = true
return false
@ -4618,7 +4618,7 @@ function lUtils.popup(title,msg,width,height,buttons,redrawscreen,colorScheme)
term.setCursorPos(math.ceil(w/2)-math.floor(width/2),math.ceil(h/2)-math.floor(height/2))
write(" "..title)
term.setCursorPos(math.ceil(w/2)-math.floor(width/2)+width-3,math.ceil(h/2)-math.floor(height/2))
write(" × ")
write(" × ")
-- The line below is unreadable now but it just makes the text box for the popup message and then prints it
term.setBackgroundColor(bg)
term.setCursorPos(math.ceil(w/2)-math.floor(width/2)+1,math.ceil(h/2)-math.floor(height/2)+1)
@ -4698,7 +4698,7 @@ function lUtils.popup(title,msg,width,height,buttons,redrawscreen,colorScheme)
term.setTextColor(colors.white)
term.setBackgroundColor(colors.red)
term.setCursorPos(math.ceil(w/2)-math.floor(width/2)+width-3,math.ceil(h/2)-math.floor(height/2))
write(" × ")
write(" × ")
elseif event == "mouse_up" then
if redrawscreen ~= nil and redrawscreen == true then
OGwin.render()
@ -4721,7 +4721,7 @@ function lUtils.popup(title,msg,width,height,buttons,redrawscreen,colorScheme)
term.setCursorPos(math.ceil(w/2)-math.floor(width/2),math.ceil(h/2)-math.floor(height/2))
write(" "..title)
term.setCursorPos(math.ceil(w/2)-math.floor(width/2)+width-3,math.ceil(h/2)-math.floor(height/2))
write(" × ")
write(" × ")
os.sleep(0.1)
term.setCursorPos(math.ceil(w/2)-math.floor(width/2),math.ceil(h/2)-math.floor(height/2))
term.setBackgroundColor(tbbg)
@ -4730,7 +4730,7 @@ function lUtils.popup(title,msg,width,height,buttons,redrawscreen,colorScheme)
term.setCursorPos(math.ceil(w/2)-math.floor(width/2),math.ceil(h/2)-math.floor(height/2))
write(" "..title)
term.setCursorPos(math.ceil(w/2)-math.floor(width/2)+width-3,math.ceil(h/2)-math.floor(height/2))
write(" × ")
write(" × ")
os.sleep(0.1)
end
end
@ -4772,7 +4772,7 @@ function lUtils.inputbox(title,msg,width,height,buttons)
term.setCursorPos(math.ceil(w/2)-math.floor(width/2),math.ceil(h/2)-math.floor(height/2))
write(" "..title)
term.setCursorPos(math.ceil(w/2)-math.floor(width/2)+width-3,math.ceil(h/2)-math.floor(height/2))
write(" × ")
write(" × ")
-- The line below is unreadable now but it just makes the text box for the popup message and then prints it
term.setBackgroundColor(colors.white)
term.setCursorPos(math.ceil(w/2)-math.floor(width/2)+1,math.ceil(h/2)-math.floor(height/2)+1)
@ -4871,7 +4871,7 @@ function lUtils.inputbox(title,msg,width,height,buttons)
term.setTextColor(colors.white)
term.setBackgroundColor(colors.red)
term.setCursorPos(math.ceil(w/2)-math.floor(width/2)+width-3,math.ceil(h/2)-math.floor(height/2))
write(" × ")
write(" × ")
elseif event == "mouse_up" then
return false,0,""
end
@ -4892,7 +4892,7 @@ function lUtils.inputbox(title,msg,width,height,buttons)
term.setCursorPos(math.ceil(w/2)-math.floor(width/2),math.ceil(h/2)-math.floor(height/2))
write(" "..title)
term.setCursorPos(math.ceil(w/2)-math.floor(width/2)+width-3,math.ceil(h/2)-math.floor(height/2))
write(" × ")
write(" × ")
os.sleep(0.1)
term.setCursorPos(math.ceil(w/2)-math.floor(width/2),math.ceil(h/2)-math.floor(height/2))
term.setBackgroundColor(colors.gray)
@ -4901,7 +4901,7 @@ function lUtils.inputbox(title,msg,width,height,buttons)
term.setCursorPos(math.ceil(w/2)-math.floor(width/2),math.ceil(h/2)-math.floor(height/2))
write(" "..title)
term.setCursorPos(math.ceil(w/2)-math.floor(width/2)+width-3,math.ceil(h/2)-math.floor(height/2))
write(" × ")
write(" × ")
os.sleep(0.1)
end
end
@ -5377,4 +5377,4 @@ function lUtils.isInside(x,y,object)
else
return false
end
end
end

1505
LevelOS/system.lua Normal file

File diff suppressed because it is too large Load Diff

View File

@ -0,0 +1,648 @@
------------------------------------------------ LevelOOPer Library 2.2.6 ------------------------------------------------
function _G.pairs(t)
local mt = getmetatable(t)
if mt and type(mt.__pairs) == "function" then
return mt.__pairs(t)
else
return next, t, nil
end
end
local function fread(file)
local f = fs.open(file,"r")
local txt = f.readAll()
f.close()
return txt
end
local env = _ENV
local oop = {}
local classCache = {}
local privCache = {}
local publicCache = {}
local objectCache = {}
local dir = fs.getDir(({...})[1] or shell.getRunningProgram())
local function typeRestriction(index, sType, value)
if not oop.isType(value, sType) then
return false, "cannot convert "..sType.." '"..index.."' to '"..oop.type(value, true).."'"
else
return true
end
end
local function getNumberType(number)
if number%1 == 0 then
return "int"
else
return "double"
end
end
oop.setEnv = function(newEnv)
env = newEnv
end
oop.setDir = function(newDir)
oop.expect(1, newDir, "string")
dir = newDir
end
oop.getDir = function()
return dir
end
local default = {
int = 0,
double = 0,
number = 0,
string = "",
["function"] = function() end,
table = {},
boolean = false,
}
local varTypes = {
int = "int",
double = "double",
num = "number",
str = "string",
func = "function",
tbl = "table",
bool = "boolean",
}
local newVar = {
var = function(name)
local tbl = {name=name}
setmetatable(tbl, {
__call = function(self, value)
self.value = value
return self
end
})
return tbl
end,
obj = function(class)
oop.expect(1, class, "class")
local var = {type=classCache[class].name}
setmetatable(var, {
__call = function(self, name)
self.name = name
setmetatable(var, {
__call = function(self, value)
local ok,err = typeRestriction(name, var.type, value)
if not ok then
error(err, 2)
else
self.value = value
return self
end
end,
})
return self
end,
})
return var
end,
}
local const = function(name)
if type(name) == "function" then
return function(realname)
local var = name(realname)
var.const = true
return var
end
elseif type(name) == "string" then
local var = {name=name, const=true}
setmetatable(var, {
__call = function(self, value)
self.value = value
return self
end,
})
return var
end
end
for k,v in pairs(varTypes) do
newVar[k] = function(name)
local tbl = {name=name, type=varTypes[k]}
setmetatable(tbl, {
__call = function(self, value)
local stat,err = typeRestriction(name, tbl.type, value)
if not stat then
error(err, 2)
else
self.value = value
return self
end
end,
})
return tbl
end
end
oop.injectEnv = function(env)
env.oop = oop
env.class = oop.class
env.const = const
env.import = oop.import
env.type = oop.type
env.getPublicObject = oop.getPublicObject
for k,v in pairs(newVar) do
env[k] = v
end
end
local metamethods = {
["__add"] = true,
["__sub"] = true,
["__mul"] = true,
["__div"] = true,
["__mod"] = true,
["__pow"] = true,
["__unm"] = true,
["__concat"] = true,
["__len"] = true,
["__eq"] = true,
["__lt"] = true,
["__le"] = true,
["__index"] = true,
["__newindex"] = true,
["__call"] = true,
["__tostring"] = true,
["__metatable"] = true,
["__pairs"] = true,
["__ipairs"] = true
}
local function sanitizeArgs(...)
local args = table.pack(...)
for k,v in pairs(args) do
if publicCache[v] then
args[k] = publicCache[v]
end
end
return table.unpack(args, nil, args.n)
end
local function instantiate(orig)
local function deepCopy(o, seen)
seen = seen or {}
if seen[o] then
return seen[o]
end
local copy
if type(o) == 'table' then
copy = {}
seen[o] = copy
for k,v in pairs(o) do
copy[deepCopy(k, seen)] = deepCopy(v, seen)
end
setmetatable(copy, deepCopy(getmetatable(o), seen))
else
copy = o
end
return copy
end
return deepCopy(orig)
end
local function makeClass(name, classTbl, inherit)
local class = {
static = {
},
private = {
},
public = {
},
properties = {
static = {
},
private = {
},
public = {
},
types = {
},
consts = {
},
},
metatable = {
public = {
},
private = {
},
},
name = name,
}
class.metatable.static = {
__index = class.static,
__newindex = function(tbl, k, v)
if class.properties.static[k] then
if class.properties.consts[k] then
error("cannot modify const '"..tostring(k).."'", 2)
elseif class.properties.types[k] then
local stat,err = typeRestriction(k, class.properties.types[k], v)
if not stat then
error(err, 2)
else
class.static[k] = v
end
end
elseif class.properties.private[k] then
error("cannot modify private property '"..tostring(k).."' outside of class", 2)
elseif class.properties.public[k] then
error("cannot modify public property '"..tostring(k).."' outside of object", 2)
end
end,
__call = function(self, ...)
local privObj = {}
local obj = {}
privCache[obj] = privObj
publicCache[privObj] = obj
local properties = {}
local privProperties = {}
setmetatable(properties, {__index=class.public})
setmetatable(privProperties, {
__index=function(t, k)
return properties[k] or class.private[k]
end
})
local mt = {
__index = function(t, k)
local p = properties
if t == privObj then
p = privProperties
end
local v = p[k]
if type(v) == "function" then
local tEnv = {self=privObj}
oop.injectEnv(tEnv)
setmetatable(tEnv, {__index=env})
setfenv(v, tEnv)
end
return v
end
}
local inConstructor = false
mt.__pairs = function(tbl)
local loopThroughTables = {properties, class.public, class.static}
if tbl == privObj then
table.insert(loopThroughTables, 2, class.private)
end
local cls = class
while cls.parent do -- this WONT WORK
cls = cls.parent
if tbl == privObj then
table.insert(loopThroughTables, cls.private)
end
table.insert(loopThroughTables, cls.public)
table.insert(loopThroughTables, cls.static)
end
local currentIndex = 1
local had = {}
local function customIterator(_, prevKey)
local key, value
while currentIndex <= #loopThroughTables do
key, value = next(loopThroughTables[currentIndex], prevKey)
while key ~= nil and had[key] do -- skip keys that were already found
key, value = next(loopThroughTables[currentIndex], key)
end
if key ~= nil then
had[key] = true
return key, tbl[key]
else
prevKey = nil
currentIndex = currentIndex + 1
end
end
return nil
end
return customIterator, tbl, nil
end
mt.__newindex = function(tbl, k, v)
if class.properties.consts[k] and not inConstructor then
error("cannot modify const '"..tostring(k).."'", 2)
end
if tbl ~= privObj and class.properties.private[k] then
error("cannot modify private property '"..tostring(k).."' outside of class", 2)
end
if class.properties.types[k] then
local stat,err = typeRestriction(k, class.properties.types[k], v)
if not stat then
error(err, 2)
end
end
if class.properties.static[k] then
-- change in whole class
class.static[k] = v
elseif class.properties.private[k] then
privProperties[k] = v
else
properties[k] = v
end
end
local mt2 = {}
for k,v in pairs(mt) do
mt2[k] = v
end
for k,v in pairs(class.metatable.public) do
mt[k] = function(...)
local tEnv = {self=privObj}
oop.injectEnv(tEnv)
setmetatable(tEnv, {__index=env})
setfenv(v, tEnv)
return v(sanitizeArgs(...))
end
end
for k,v in pairs(class.metatable.private) do
mt2[k] = function(...)
local tEnv = {self=privObj}
oop.injectEnv(tEnv)
setmetatable(tEnv, {__index=env})
setfenv(v, tEnv)
return v(sanitizeArgs(...))
end
end
setmetatable(obj, mt)
setmetatable(privObj, mt2)
local constructors = {class.constructor}
local cls = class
while cls.parent do
cls = cls.parent
if cls.constructor then
table.insert(constructors, 1, cls.constructor)
end
end
for t=1,#constructors do
inConstructor = true
local tEnv = {self=privCache[obj] or obj}
oop.injectEnv(tEnv)
setmetatable(tEnv, {__index=env})
setfenv(constructors[t], tEnv)
local status,tObj = pcall(constructors[t],sanitizeArgs(...))
if not status then
error(tObj, 2)
end
if tObj == false then
return false
elseif tObj then
obj = publicCache[tObj] or tObj
end
inConstructor = false
end
objectCache[obj] = class
objectCache[privObj] = class
for k,v in pairs(privObj) do
if type(v) == "table" and v == class.private[k] then
privObj[k] = instantiate(v)
end
end
return obj
end,
}
local iClass
if inherit then
iClass = classCache[inherit]
class.parent = iClass
setmetatable(class.static, {__index=iClass.static})
setmetatable(class.public, {
__index = function(tbl, key)
if iClass.public[key] ~= nil then
return iClass.public[key]
else
return class.static[key]
end
end,
})
setmetatable(class.private, {
__index = function(tbl, key)
if iClass.private[key] ~= nil then
return iClass.private[key]
else
return class.public[key]
end
end,
})
for k,v in pairs(class.properties) do
setmetatable(v, {__index=iClass.properties[k]})
end
setmetatable(class, {__index=iClass})
else
setmetatable(class.public, {__index=class.static})
setmetatable(class.private, {__index=class.public})
end
loopThrough = {"static","private","public"}
for i,l in ipairs(loopThrough) do
if classTbl[l] then
for k,v in pairs(classTbl[l]) do
if type(k) == "number" then
if type(v) == "table" and v.name then
if v.const then
class.properties.consts[v.name] = true
end
if v.type then
class.properties.types[v.name] = v.type
end
if v.value or v.type then
class[l][v.name] = v.value or default[v.type]
end
class.properties[l][v.name] = true -- now values can be generic typed starting with nil but still recognized
elseif type(v) == "string" then
class.properties[l][v] = true
end
elseif type(k) == "string" then
if l == "public" and k == name then -- constructor
if type(v) ~= "function" then
error("invalid constructor: expected function, got "..type(v),2)
end
class.constructor = v
elseif metamethods[k] then
class.metatable[l][k] = v
else
class[l][k] = v
class.properties[l][k] = true
end
end
end
end
end
local classObj = {}
classCache[classObj] = class
class.obj = classObj
setmetatable(classObj, class.metatable.static)
env[name] = classObj
end
function oop.class(name)
return function(class)
if classCache[class] then -- a class object was passed meaning we're gonna inherit
return function(realclass)
makeClass(name, realclass, class)
end
else
makeClass(name, class)
end
end
end
local oType = type
function oop.type(value, numberType)
if oType(value) == "table" then
if objectCache[value] then
return objectCache[value].name
elseif classCache[value] then
return "class"
else
return "table"
end
elseif numberType and oType(value) == "number" then
return getNumberType(value)
else
return oType(value)
end
end
function oop.getClassName(class)
oop.expect(1, class, "class")
return classCache[class].name
end
function oop.isType(value, ...)
local types = {oop.type(value), oType(value), oop.type(value, true)}
if types[1] ~= types[2] and types[3] ~= "class" then
types[3] = "object"
end
local allowedTypes = {...}
for i,t in ipairs(types) do
for i=1, #allowedTypes do
if allowedTypes[i] == t or (allowedTypes[i] == "double" and t == "number") then
return true
end
end
end
return false
end
function oop.expect(index, value, ...)
local level = 3
local allowedTypes = {...}
if type(allowedTypes[1]) == "number" then
level = allowedTypes[1]
table.remove(allowedTypes, 1)
end
if type(allowedTypes[1]) ~= "string" then
error("bad argument #3: expected string", 2)
end
if oop.isType(value, ...) then
return value
end
local expectlist
local numbertype = false
for t=1,#allowedTypes do
if allowedTypes[t] == "int" then
numbertype = true
end
end
if #allowedTypes > 1 then
local lastType = allowedTypes[#allowedTypes]
allowedTypes[#allowedTypes] = nil
expectlist = table.concat(allowedTypes, ", ").." or "..lastType
else
expectlist = allowedTypes[1]
end
local t = oop.type(value, numbertype)
error("bad argument #"..index..": expected "..expectlist.." got "..t.." ("..tostring(value)..")", level)
end
function oop.getPublicObject(privateObject)
return publicCache[privateObject] or privateObject
end
function oop.import(filepath)
oop.expect(1, filepath, "string")
local makePackage = require("cc.require")
local tEnv = setmetatable({shell=shell, multishell=multishell},{__index=env})
tEnv.require, tEnv.package = makePackage.make(tEnv, dir)
tEnv.oop = oop
oop.injectEnv(tEnv)
local pathlog = filepath
local filepath2 = filepath..".lua"
pathlog = pathlog.."\n"..filepath2
if filepath:sub(1,1) ~= "/" then
pathlog = pathlog.."\n"..fs.combine(dir, filepath)
pathlog = pathlog.."\n"..fs.combine(dir, filepath2)
if fs.exists(fs.combine(dir, filepath)) then
filepath = fs.combine(dir, filepath)
elseif fs.exists(fs.combine(dir, filepath2)) then
filepath = fs.combine(dir, filepath2)
end
end
if fs.exists(filepath2) and not fs.exists(filepath) then
filepath = filepath2
end
if not fs.exists(filepath) then
error("Could not find file:"..pathlog,2)
end
local f = fread(filepath)
local func, err = load(f, "@"..filepath, nil, tEnv)
if not func then
error(err, 2)
else
local ok,err = pcall(func)
if not ok then
error(err, 2)
end
end
end
return oop

View File

@ -0,0 +1,723 @@
local tokens = {
whitespace = {
["\t"] = true,
[" "] = true,
["\n"] = true,
[","] = true,
},
line = {
["\n"] = true,
[","] = true,
},
label = {
[":"] = true,
},
indexVar = {
["%"] = true,
},
operator = {},
op = {
add = {
["+"] = true,
},
subtract = {
["-"] = true,
},
multiply = {
["*"] = true,
},
modulo = {
["%"] = true,
},
power = {
["^"] = true,
},
divide = {
["/"] = true,
},
},
assign = {
["="] = true,
},
comparison = {},
comp = {
equals = {
["=="] = true,
},
notEquals = {
["~="] = true,
},
bigger = {
[">"] = true,
},
biggerOrEquals = {
[">="] = true,
},
smaller = {
["<"] = true,
},
smallerOrEquals = {
["<="] = true,
},
},
logic = {},
logicAnd = {
["and"] = true,
["&&"] = true,
},
logicOr = {
["or"] = true,
["||"] = true,
},
logicNot = {
["not"] = true,
["!"] = true,
},
keyword = {},
ifStatement = {
["if"] = true,
},
whileStatement = {
["while"] = true,
},
forStatement = {
["for"] = true,
},
elseStatement = {
["else"] = true,
},
localStatement = {
["local"] = true,
},
eof = {
["end"] = true,
["exit"] = true,
},
boolean = {},
boolTrue = {
["true"] = true,
},
boolFalse = {
["false"] = true,
},
ident = {
["_"] = true,
},
digits = {
},
string = {
["\""] = true,
["'"] = true,
},
symbol = {
["("] = true,
[")"] = true,
},
escape = {
["\\"] = true,
}
}
for c=("a"):byte(), ("z"):byte() do
tokens.ident[string.char(c)] = true
tokens.ident[string.char(c):upper()] = true
end
for c=("0"):byte(), ("9"):byte() do
tokens.ident[string.char(c)] = true
tokens.digits[string.char(c)] = true
end
local function addTo(root, ...)
if not root then error("invalid argument #1: expected table, got nil",2) end
local tbls = {...}
for i,t in ipairs(tbls) do
for k,v in pairs(t) do
root[k] = v
end
end
end
for k,v in pairs(tokens.comp) do
addTo(tokens.comparison, v)
end
for k,v in pairs(tokens.op) do
addTo(tokens.operator, v)
end
addTo(tokens.logic, tokens.logicAnd, tokens.logicOr, tokens.logicNot)
addTo(tokens.keyword, tokens.logic, tokens.ifStatement, tokens.whileStatement, tokens.forStatement, tokens.elseStatement, tokens.localStatement, tokens.eof)
addTo(tokens.boolean, tokens.boolTrue, tokens.boolFalse)
local statementValues = {
["string"] = true,
["number"] = true,
["variable"] = true,
["arg"] = true,
["value"] = true,
}
local validVarTypes = {
["function"] = true,
["arg"] = true,
["variable"] = true,
["escape"] = true,
}
local function lex(text)
local char = 1
local function get(p)
local tPos = p or char
return text:sub(tPos,tPos)
end
local beginline = true
local inStatement = false
local isLabel = false
local data = {{}}
local line = data[1]
local posOffset = 0
local function newline()
posOffset = char
table.insert(data,{})
line = data[#data]
end
local function addData(txt,type)
if not txt then error("no txt",2) end
if line[#line] and line[#line].type == type then
line[#line].data = line[#line].data..txt
line[#line].posLast = line[#line].posLast+#txt
else
table.insert(line,{data=txt,posFirst=(char-posOffset),posLast=(char-posOffset)+(#txt-1),type=type})
end
end
local function readWhitespace(acceptNewline)
local txt = get()
local oldchar = char
while tokens.whitespace[txt] and (acceptNewline or not tokens.line[txt]) do
char = char + 1
addData(txt,"whitespace")
isLabel = false
txt = get()
end
if oldchar == char then
return false
else
return true
end
end
while char <= #text do
local txt = get()
if tokens.whitespace[txt] and not tokens.line[txt] then
addData(txt,"whitespace")
isLabel = false
elseif tokens.escape[txt] then
addData(txt..text:sub(char+1,char+1),"escape")
char = char+1
if tokens.whitespace[get(char+1)] then
isLabel = false
beginline = false
end
elseif tokens.string[txt] then
local bchar = txt
local echar = bchar
local stype = "string"
if isLabel then
stype = "label"
elseif beginline then
stype = "function"
end
isLabel = false
beginline = false
addData(txt,stype)
char = char+1
while char <= #text do
local c = text:sub(char,char)
if tokens.escape[c] then
addData(c..get(char+1),"escape")
char = char+1
if tokens.digits[get()] then
char = char+1
for i=1,2 do
if tokens.digits[get()] then
addData(get(),"escape")
char = char+1
else
break
end
end
else
char = char+1
end
elseif tokens.indexVar[c] then
local b2,e2 = text:find("^%%[A-Za-z0-9_]+%%", char)
if b2 then
addData(text:sub(b2,e2), "variable")
char = e2
else
local b3,e3 = text:find("^%%[0-9]+", char)
if not b3 then
b3,e3 = text:find("^%%~[0-9]+", char)
end
if b3 then
addData(text:sub(b3,e3), "arg")
char = e3
else
addData(c, stype)
end
end
char = char+1
elseif c == echar then
addData(c, stype)
break
else
if c == "\n" then
newline()
else
addData(c, stype)
end
char = char+1
end
end
elseif tokens.indexVar[txt] then
if inStatement == 1 and line[#line] and line[#line].type == "whitespace" and line[#line-1] and statementValues[line[#line-1].type] then
inStatement = false
beginline = true
end
local b2,e2 = text:find("^%%[A-Za-z0-9_]+%%", char)
if b2 then
if isLabel and beginline then
addData(text:sub(b2,e2), "unidentified")
else
addData(text:sub(b2,e2), "variable")
end
char = e2
else
local b3,e3 = text:find("^%%[0-9]+", char)
if not b3 then
b3,e3 = text:find("^%%~[0-9]+", char)
end
if b3 then
if isLabel and beginline then
addData(text:sub(b3,e3), "unidentified")
else
addData(text:sub(b3,e3), "arg")
end
char = e3
elseif isLabel then
addData(txt, "label")
elseif beginline then
addData(txt, "function")
elseif not inStatement then
addData(txt, "string")
elseif tokens.operator[txt] then
addData(txt, "operator")
else
addData(txt, "unidentified")
end
end
if tokens.whitespace[get(char+1)] then
beginline = false
end
elseif tokens.ident[txt] or (not inStatement and not (tokens.line[txt] or tokens.label[txt] or tokens.assign[txt] or tokens.symbol[txt])) then
local b,e
if inStatement then
b,e = text:find("^[A-Za-z0-9_.]+", char)
else
b,e = char,char+1
local c = get(e)
while e <= #text and not (tokens.line[c] or tokens.label[c] or tokens.assign[c] or tokens.indexVar[c] or tokens.whitespace[c] or tokens.symbol[c] or tokens.escape[c]) do
e = e + 1
c = get(e)
end
e = e - 1
end
local token = text:sub(b,e)
local ltoken = token:lower()
local statementValue = false
if inStatement then
if line[#line] and line[#line].type == "whitespace" and line[#line-1] and statementValues[line[#line-1].type] then
if inStatement == 1 then
inStatement = 0
beginline = true
end
statementValue = true
end
end
char = e
if isLabel then
addData(token, "label")
if tokens.whitespace[get(char+1)] then
isLabel = false
beginline = false
end
elseif tokens.localStatement[ltoken] and not inStatement then
if not beginline then
addData(token, "string")
else
addData(token, "keyword")
end
elseif tokens.eof[ltoken] and (inStatement == 0 or not inStatement) then
addData(token, "keyword")
elseif (tokens.ifStatement[ltoken] or tokens.whileStatement[ltoken]) and (inStatement == 0 or not inStatement) then
addData(token, "keyword")
inStatement = 1
elseif (tokens.elseStatement[ltoken] or tokens.eof[ltoken]) and (inStatement == 0 or not inStatement) then
addData(token, "keyword")
elseif (tokens.logicAnd[ltoken] or tokens.logicOr[ltoken]) and statementValue then
addData(token, "logic")
if inStatement == 0 then
inStatement = 1
end
elseif tokens.logicNot[ltoken] and inStatement and not statementValue then
addData(token, "logic")
if inStatement == 0 then
inStatement = 1
end
elseif tokens.forStatement[ltoken] and (inStatement == 0 or not inStatement) then
-- other handling
elseif tokens.boolean[ltoken] and inStatement and not statementValue then
addData(token, "value")
elseif beginline and (inStatement == 0 or not inStatement) then
addData(token, "function")
if tokens.whitespace[get(char+1)] then
beginline = false
end
elseif tonumber(token) then
addData(token, "number")
if tokens.whitespace[get(char+1)] then
beginline = false
end
else
addData(token, "string")
end
if inStatement == 0 then
inStatement = false
end
elseif tokens.label[txt] then
if char+1 > #text or tokens.whitespace[get(char+1)] then
addData(txt, "string")
else
addData(txt, "label")
isLabel = true
end
elseif tokens.line[txt] then
beginline = true
inStatement = false
if txt ~= "\n" then
addData(txt, "symbol")
end
elseif tokens.symbol[txt] then
addData(txt, "symbol")
elseif txt:find("%p") then
local b,e = text:find("^%p+", char)
local token = text:sub(b,e)
char = e
if inStatement then
if tokens.operator[token] then
addData(token, "operator")
elseif tokens.comparison[token] then
addData(token, "comparison")
elseif tokens.logic[token] then
addData(token, "logic")
else
addData(token, "string")
end
else
if tokens.assign[token] then
local v = line[#line]
if v and v.type == "whitespace" then
v = line[#line-1]
end
if v and (validVarTypes[v.type]) then
local it = #line-1
while v and (validVarTypes[v.type]) do
if v.type == "function" then
v.type = "variable"
end
it = it-1
v = line[it]
end
addData(token, "assign")
inStatement = true
elseif beginline then
addData(token, "unidentified")
else
addData(token, "string")
end
elseif beginline then
addData(token, "unidentified")
else
addData(token, "string")
end
end
elseif txt ~= "\n" then
addData(txt, "unidentified")
end
if txt == "\n" then
newline()
end
char = char+1
end
return data
end
local function parse(data, filename)
filename = filename or "latch"
if type(data) == "string" then
data = lex(data)
end
local function err(lineNum, txt, txtafter)
local err = filename..": "..txt.." on line "..lineNum
if txtafter then
err = err.." ("..txtafter..")"
end
error(err, 0)
end
local function unexpectedToken(line, token, ...)
_G.debugtoken = token
local exp = {...}
local expstr
if #exp > 0 then
expstr = "expected "..table.concat(exp, ", ")
end
err(line, "unexpected token '"..tostring(token.data).."' ("..tostring(token.type)..")", expstr)
end
local function locateEntry(tbl, value)
for k,v in pairs(tbl) do
if v == value then
return true
end
end
return false
end
local function parseToken(line, i, allowed, stopAt)
local token = line[i]
local data = {}
stopAt = stopAt or {"whitespace"}
while true do
if locateEntry(allowed, token.type) then
if token.type == "number" then
table.insert(data, {type="number", data=token.data})
elseif token.type == "operator" then
table.insert(data, {type="operator", data=token.data})
elseif token.type == "variable" and token.data:sub(1,1) == "%" then
table.insert(data, {type="variable", data=token.data:sub(2,#token.data-1)})
elseif token.type == "variable" then
table.insert(data, {type="string", data=token.data})
elseif token.type == "arg" then
table.insert(data, {type="argument", data=token.data:sub(2)})
elseif token.type == "label" then
if tokens.string[token.data:sub(2,2)] then
table.insert(data, {type="label", data=token.data:sub(2):gsub(token.data:sub(2,2),"")})
else
table.insert(data, {type="label", data=token.data:sub(2)})
end
elseif tokens.string[token.data:sub(1,1)] then
table.insert(data, {type="string", data=token.data:gsub(token.data:sub(1,1),"")})
else
table.insert(data, {type="string", data=token.data})
end
elseif locateEntry(stopAt, token.type) then
i = i - 1
break
else
local expected = {}
addTo(expected, stopAt)
addTo(expected, allowed)
unexpectedToken(ln, token, unpack(expected))
end
i = i + 1
token = line[i]
if not token then break end
end
return data, i
end
local function parseExpression(line, i, whitespaceConcat) -- this is all wrong FUCK, value (x+5) > comparison (x+5 == 8) > expression(x+5 == 8 and %potato%)
-- expression structure
local token = line[i]
local conditions = {
{
{} -- current condition (value)
-- more AND conditions
}
-- more OR conditions
}
local condition = conditions[1][1]
local isValid = false
while true do
token = line[i]
if not token then break end
if token.type == "whitespace" then -- optional token
elseif token.type == "logic" and tokens.logicNot[token.data] then -- optional token
table.insert(condition, token)
isValid = false
elseif statementValues[token.type] then -- REQUIRED token, expression is invalid without it
table.insert(condition, token)
isValid = true
i = i + 1
token = line[i]
if not token then break end
if token.type == "whitespace" then
i = i + 1
token = line[i]
end
if not token then break end
if token.type == "logic" and tokens.logicAnd[token.data] then
condition = {}
table.insert(conditions[#conditions], condition)
isValid = false
elseif token.type == "logic" and tokens.logicOr[token.data] then
condition = {}
table.insert(conditions, {})
table.insert(conditions[#conditions], condition)
isValid = false
elseif token.type == "operator" then
table.insert(condition, token)
elseif whitespaceConcat then
i = i - 1
else
i = i - 1
break -- end of statement
end
else
unexpectedToken(i, token, "expression")
end
i = i + 1
end
if not isValid then
err(i, "invalid statement")
else
return conditions, i
end
end
local program = {
arguments = {},
env = {},
commands = {},
labels = {},
code = {},
}
local scope = program.code
for ln,line in ipairs(data) do
local token
local i = 1
local beginline = true
local function nextToken(includeWhitespace)
if line[i+1] and (includeWhitespace or line[i+1].type ~= "whitespace") then
return line[i+1]
elseif line[i+2] then
return line[i+2]
end
end
local function nextTokenType(includeWhitespace)
local nt = nextToken(includeWhitespace)
if nt then
return nt.type
end
end
while i <= #line do
token = line[i]
if beginline then
if token.type == "function" or token.type == "variable" or token.type == "arg" then
local data
data, i = parseToken(line, i, {"function", "variable", "arg", "escape"}, {"whitespace", "symbol", "assign"})
local l
if nextTokenType() == "assign" then
l = {type="assign", data=data, value={}}
while nextTokenType() == "assign" do
i = i + 1
end
i = i + 1
l.value, i = parseExpression(line, i, true)
else
l = {type="command", data=data, line=ln, params={}}
beginline = false
end
table.insert(scope, l)
elseif token.type == "label" then
program.labels[token.data] = {scope=scope, commandNum=#scope+1}
elseif token.type ~= "whitespace" then
--unexpectedToken(ln, token, "whitespace", "function", "variable", "arg")
end
else
if token.type == "label" then
if scope[#scope].type == "command" then
local data
data, i = parseToken(line, i, {"label", "variable", "arg", "escape"}, {"whitespace", "symbol"})
table.insert(scope[#scope].params, data)
else
unexpectedToken(ln, token)
end
elseif token.type == "string" or token.type == "number" then
if scope[#scope].type == "command" then
local data
data, i = parseToken(line, i, {"string", "number", "variable", "arg", "escape"}, {"whitespace", "symbol"})
table.insert(scope[#scope].params, data)
end
elseif token.type ~= "whitespace" then
end
end
i = i + 1
end
end
return program
end
return {lex=lex,parse=parse}

View File

@ -0,0 +1 @@
{{{"Ÿ€"," b ","b ",},{"ƒ","bb9"," 9 ",},{"€€€"," "," ",},},}

File diff suppressed because it is too large Load Diff

View File

@ -0,0 +1 @@
{{{"‡‹"," 0","00 ",},{"ƒ‡","000"," ",},},}

View File

@ -0,0 +1 @@
{{{"ƒ€€","1 ","444",},{"—Œ”","499","944",},{"€€€"," "," ",},},}

File diff suppressed because it is too large Load Diff

View File

@ -0,0 +1 @@
{{{"—‹"," 0","00 ",},{"Š…","000"," ",},},}

View File

@ -0,0 +1 @@
{{{"Ÿˆ"," b","bb ",},{"€‚•"," 0b","bb ",},{"‚ƒ€","bb "," ",},},}

View File

@ -0,0 +1,172 @@
local tArgs = {...}
if type(tArgs[1]) == "string" and fs.exists(tArgs[1]) then
lOS.execute(table.concat(tArgs," "))
return
end
if LevelOS then LevelOS.self.window.icon = {"\3","b"} end
local lex = "LevelOS/modules/lex.lua"
local docs = "Program_Files/Slime_Text/highlight/lua/docs.json"
local docstable
if not fs.exists(lex) then
-- oh no
end
if not fs.exists(docs) then
local webres = http.get("http://tweaked.cc/index.json")
if webres then
docstable = textutils.unserializeJSON(webres.readAll())
end
--[[if webres then
lUtils.fwrite(docs,webres.readAll())
end]]
end
if fs.exists(docs) then
docstable = textutils.unserializeJSON(lUtils.fread(docs))
end
local pretty = require "cc.pretty"
local tCommandHistory = {}
local hCur = 0
local bRunning = true
local tEnv = {
["exit"] = setmetatable({}, {
__tostring = function() return "Call exit() to exit." end,
__call = function() bRunning = false end,
__type = "function",
}),
["_echo"] = function(...)
return ...
end,
}
setmetatable(tEnv, { __index = _ENV })
term.setTextColor(colors.yellow)
print("LevelOS interactive Lua prompt.\nCall exit() to exit.")
term.setTextColor(colors.white)
while bRunning do
hCur = #tCommandHistory+1
write("lua> ")
local w,h = term.getSize()
local x,y = term.getCursorPos()
local self = lUtils.input(x,y,w,y)
self.opt.cursorColor = colors.white
self.opt.overflowY = "scroll"
self.scrollY = 0
self.opt.syntax = {
type="lua",
keyword=colors.yellow,
comment=colors.green,
string=colors.red,
number=colors.purple,
symbol=colors.white,
operator=colors.lightGray,
value=colors.purple,
ident=colors.white,
["function"]=colors.cyan,
nfunction=colors.lime,
arg=colors.orange,
lexer=lex,
whitespace=colors.lightGray,
}
self.opt.complete = {
docs = docstable,
env = tEnv,
overlay = true,
LevelOS = LevelOS,
}
self.opt.selectColor=colors.gray
self.opt.overflowY="stretch"
self.opt.overflowX="scroll"
_G.debugeditor = self
while true do
tCommandHistory[hCur] = self.txt
self.state = true
local doUpdate = true
local e = {os.pullEvent()}
if e[1] == "term_resize" then
local w,h = term.getSize()
self.x2 = w
elseif e[1] == "key" and (e[2] == keys.up or e[2] == keys.down) and not self.opt.complete.list then
doUpdate = false
local o = 1
if e[2] == keys.up then
o = -1
end
if tCommandHistory[hCur+o] then
hCur = hCur+o
self.txt = tCommandHistory[hCur]
self.cursor.x = #self.txt+1
self.cursor.a = #self.txt+1
end
self.update("term_resize")
elseif e[1] == "key" and e[2] == keys.enter and not lUtils.isHolding(keys.leftShift) then
if hCur < #tCommandHistory then
hCur = #tCommandHistory
tCommandHistory[hCur] = self.txt
end
doUpdate = false
term.setCursorBlink(false)
LevelOS.overlay = nil
print("")
local s = self.txt
local nForcePrint = 0
local func, e = load(s, "=lua", "t", tEnv)
local func2 = load("return _echo(" .. s .. ");", "=lua", "t", tEnv)
if not func then
if func2 then
func = func2
e = nil
nForcePrint = 1
end
else
if func2 then
func = func2
end
end
if func then
local tResults = table.pack(pcall(func))
if tResults[1] then
local n = 1
while n < tResults.n or n <= nForcePrint do
local value = tResults[n + 1]
local ok, serialised = pcall(pretty.pretty, value, {
function_args = settings.get("lua.function_args"),
function_source = settings.get("lua.function_source"),
})
if ok then
pretty.print(serialised)
else
print(tostring(value))
end
n = n + 1
end
else
printError(tResults[2])
end
else
printError(e)
end
break
elseif e[1] == "key" or e[1] == "char" or e[1] == "paste" then
if hCur < #tCommandHistory then
hCur = #tCommandHistory
tCommandHistory[hCur] = self.txt
end
end
if doUpdate then
self.update(unpack(e))
end
local w,h = term.getSize()
while self.y2 > h do
if self.y1 > 1 then
term.scroll(1)
self.y2 = self.y2-1
self.y1 = self.y1-1
else
self.y1 = 1
self.y2 = h
self.opt.overflowY = "scroll"
end
end
self.render()
end
end

View File

@ -0,0 +1 @@
{{{"Ÿœ’"," 00","0 ",},{"‚","000"," ",},},}

View File

@ -0,0 +1 @@
{{{"ŸŸ€"," ","77 ",},{"•","888","77 ",},{"ˆŒ•","778","88 ",},},}

View File

@ -0,0 +1,273 @@
local tArgs = {...}
local tFilepath = ""
if tArgs[1] ~= nil then
tFilepath = tArgs[1]
end
local isReadOnly = false
if tArgs[2] ~= nil and tArgs[2] == "true" then
isReadOnly = true
end
local tCol = {bg=colors.white,txt=colors.black,misc=colors.lightGray,misc2=colors.gray}
local btns = {{"File",{{"New","New window","Open...","Save","Save as..."},"Print","Quit"}},{"Edit",{"Undo",{"Search","Replace"},{"Time"}}},{"View",{"Dark Mode"}}}
local function topbar()
local w,h = term.getSize()
theline = ""
for t=1,w-1 do
theline = theline.."\131"
end
term.setCursorPos(1,1)
term.setBackgroundColor(tCol.bg)
term.setTextColor(tCol.misc)
term.clearLine()
term.setCursorPos(1,2)
term.write(theline)
term.setCursorPos(1,1)
term.setTextColor(tCol.txt)
for t=1,#btns do
btns[t].x = ({term.getCursorPos()})[1]
btns[t].w = string.len(btns[t][1])+2
term.write(" "..btns[t][1].." ")
end
end
local w,h = term.getSize()
local a = {}
local function txt()
a = {{width=w-1,height=h-4,sTable={},filepath="",lines={""},changed=false},0,0,1,1}
if tFilepath ~= "" then
if fs.exists(tFilepath) == true then
local openfile = fs.open(tFilepath,"r")
a[1].lines = {}
for line in openfile.readLine do
a[1].lines[#a[1].lines+1] = line
end
openfile.close()
if a[1].lines[1] == nil then
a[1].lines[1] = ""
end
end
end
while true do
local w,h = term.getSize()
a[1].width = w-1
a[1].height = h-4
a[1].sTable = {background={tCol.bg},text={tCol.txt},cursor={colors.red}}
term.setCursorPos(1,5)
term.setBackgroundColor(colors.white)
term.setTextColor(colors.black)
--print("I am present.")
local changesAllowed = true
if isReadOnly == true or (tFilepath ~= "" and fs.isReadOnly(tFilepath) == true) then
changesAllowed = false
end
a = {lUtils.drawEditBox(a[1],1,3,a[2],a[3],a[4],a[5],true,true,nil,changesAllowed)}
--term.setCursorPos(1,3)
--term.clearLine()
--term.write("HIII: ")
--term.write(textutils.serialize(a))
os.sleep(0)
end
end
_G.thetxtfunction = txt
local function save()
if tFilepath == "" then
while true do
local i = {lUtils.inputbox("Filepath","Please enter a new filepath:",29,10,{"Done","Cancel"})}
if i[2] == false or i[4] == "Cancel" then
return false
end
if fs.exists(i[1]) == true then
lUtils.popup("Error","This path already exists!",29,9,{"OK"})
else
tFilepath = i[1]
break
end
end
end
local savefile = fs.open(tFilepath,"w")
for t=1,#a[1].lines do
savefile.writeLine(a[1].lines[t])
end
savefile.close()
return true
end
function uwansave()
local name = ""
if tFilepath == "" then
name = "Untitled"
else
name = fs.getName(tFilepath)
end
local c = {lUtils.popup("Notepad","Do you want to save your changes in "..name.."?",30,8,{"Save","Don't save","Cancel"})}
if c[1] == false then return false
elseif c[3] == "Save" then
if tFilepath == "" then
-- select file path with explorer asap
return false
end
local ayyy = fs.open(tFilepath,"w")
for t=1,#a[1].lines do
ayyy.writeLine(a[1].lines[t])
end
end
if c[3] ~= "Cancel" then
return true
end
end
local function scrollbars()
local w,h = term.getSize()
term.setCursorPos(1,h-1)
term.setBackgroundColor(tCol.misc)
term.setTextColor(tCol.misc2)
term.clearLine()
term.setCursorPos(1,h-1)
term.write("\17")
term.setCursorPos(w-1,h-1)
term.write("\16")
for t=2,h-2 do
term.setCursorPos(w,t)
if t == 3 then
term.write("\30")
elseif t == h-2 then
term.write("\31")
else
term.write(" ")
end
end
term.setCursorPos(1,h)
for t=1,w do
term.write("\131")
end
end
function LevelOS.close()
local u = true
if a[1].changed == true then
u = uwansave()
end
if u == true then
return
else
regevents()
end
end
function regevents()
scrollbars()
local txtcor = coroutine.create(txt)
topbar()
coroutine.resume(txtcor)
while true do
e = {os.pullEvent()}
scrollbars()
if not ((e[1] == "mouse_click" or e[1] == "mouse_up") and e[4] == 1) then
coroutine.resume(txtcor,table.unpack(e))
end
--term.setCursorPos(1,3)
--term.setBackgroundColor(colors.white)
--term.setTextColor(colors.black)
--term.clearLine()
--term.setCursorPos(1,3)
--term.write(coroutine.status(txtcor).." "..textutils.serialize(a[1]))
if e[1] == "term_resize" then
topbar()
scrollbars()
coroutine.resume(txtcor,"mouse_click",1,1,1)
elseif e[1] == "mouse_click" then
if e[4] == 1 then
topbar()
term.setCursorBlink(false)
local oldcursorpos = {term.getCursorPos()}
for t=1,#btns do
if e[3] >= btns[t].x and e[3] <= btns[t].x+btns[t].w-1 then
-- open menu and color button light blue
term.setCursorPos(btns[t].x,1)
term.setBackgroundColor(colors.blue)
term.write(" "..btns[t][1].." ")
local disabled = {}
if btns[t][1] == "File" then
if a[1].changed == false then
disabled = {"Save","Save as..."}
end
end
local b = {lUtils.clickmenu(btns[t].x,2,20,btns[t][2],true,disabled)}
if b[1] ~= false then
if b[3] == "New" then
local d = true
if a[1].changed == true then
d = uwansave()
end
if d == true then
tFilepath = ""
txtcor = coroutine.create(txt)
os.startTimer(0.1)
end
elseif b[3] == "New window" then
lOS.execute(LevelOS.path)
elseif b[3] == "Open..." then
local u = true
if a[1].changed == true then
u = uwansave()
end
if u == true then
local d = {lUtils.explorer("/","SelFile false")}
if d[1] ~= nil then
if fs.exists(d[1]) == true then
a = {}
txtcor = coroutine.create(txt)
coroutine.resume(txtcor)
tFilepath = d[1]
local openfile = fs.open(tFilepath,"r")
a[1].lines = {}
for line in openfile.readLine do
a[1].lines[#a[1].lines+1] = line
end
openfile.close()
if a[1].lines[1] == nil then
a[1].lines[1] = ""
end
end
end
end
elseif b[3] == "Save" then
if save() == true then
a[1].changed = false
end
elseif b[3] == "Save as..." then
local oldF = tFilepath
tFilepath = ""
if save() == false then
tFilepath = oldF
else
a[1].changed = false
end
elseif b[3] == "Quit" then
local u = true
if a[1].changed == true then
u = uwansave()
end
if u == true then
return
end
elseif b[3] == "Dark Mode" then
tCol = {bg=colors.black,txt=colors.white,misc=colors.gray,misc2=colors.lightGray}
topbar()
scrollbars()
coroutine.resume(txtcor,"mouse_click",1,1,1)
btns[3][2][1] = "Light Mode"
elseif b[3] == "Light Mode" then
tCol = {bg=colors.white,txt=colors.black,misc=colors.lightGray,misc2=colors.gray}
topbar()
scrollbars()
coroutine.resume(txtcor,"mouse_click",1,1,1)
btns[3][2][1] = "Dark Mode"
end
end
end
end
topbar()
term.setCursorPos(table.unpack(oldcursorpos))
term.setTextColor(colors.red)
term.setCursorBlink(true)
end
end
end
end
regevents()

View File

@ -0,0 +1 @@
{{{"•ƒ•"," 0","00 ",},{"Š…","000"," ",},},}

View File

@ -0,0 +1 @@
{{{"‡Œ‹"," ","999",},{"€Š€"," 9 ","909",},{"","999"," ",},},}

File diff suppressed because it is too large Load Diff

View File

@ -0,0 +1 @@
{{{"—Œ”"," 0","00 ",},{"Š…","000"," ",},},}

12
bigfont

File diff suppressed because one or more lines are too long

743
blittle Normal file
View File

@ -0,0 +1,743 @@
-- +--------------------------------------------------------+
-- | |
-- | BLittle |
-- | |
-- +--------------------------------------------------------+
local version = "Version 1.1.6beta"
-- By Jeffrey Alexander, aka Bomb Bloke.
-- Convenience functions to make use of ComputerCraft 1.76's new "drawing" characters.
-- http://www.computercraft.info/forums2/index.php?/topic/25354-cc-176-blittle-api/
-------------------------------------------------------------
if shell then
local arg = {...}
if #arg == 0 then
print("Usage:")
print("blittle <scriptName> [args]")
return
end
if not blittle then os.loadAPI(shell.getRunningProgram()) end
local oldTerm = term.redirect(blittle.createWindow())
shell.run(unpack(arg))
term.redirect(oldTerm)
return
end
local relations = {[0] = {8, 4, 3, 6, 5}, {4, 14, 8, 7}, {6, 10, 8, 7}, {9, 11, 8, 0}, {1, 14, 8, 0}, {13, 12, 8, 0}, {2, 10, 8, 0}, {15, 8, 10, 11, 12, 14},
{0, 7, 1, 9, 2, 13}, {3, 11, 8, 7}, {2, 6, 7, 15}, {9, 3, 7, 15}, {13, 5, 7, 15}, {5, 12, 8, 7}, {1, 4, 7, 15}, {7, 10, 11, 12, 14}}
local colourNum, exponents, colourChar = {}, {}, {}
for i = 0, 15 do exponents[2^i] = i end
do
local hex = "0123456789abcdef"
for i = 1, 16 do
colourNum[hex:sub(i, i)] = i - 1
colourNum[i - 1] = hex:sub(i, i)
colourChar[hex:sub(i, i)] = 2 ^ (i - 1)
colourChar[2 ^ (i - 1)] = hex:sub(i, i)
local thisRel = relations[i - 1]
for i = 1, #thisRel do thisRel[i] = 2 ^ thisRel[i] end
end
end
local function getBestColourMatch(usage)
local lastCol = relations[exponents[usage[#usage][1]]]
for j = 1, #lastCol do
local thisRelation = lastCol[j]
for i = 1, #usage - 1 do if usage[i][1] == thisRelation then return i end end
end
return 1
end
local function colsToChar(pattern, totals)
if not totals then
local newPattern = {}
totals = {}
for i = 1, 6 do
local thisVal = pattern[i]
local thisTot = totals[thisVal]
totals[thisVal], newPattern[i] = thisTot and (thisTot + 1) or 1, thisVal
end
pattern = newPattern
end
local usage = {}
for key, value in pairs(totals) do usage[#usage + 1] = {key, value} end
if #usage > 1 then
-- Reduce the chunk to two colours:
while #usage > 2 do
table.sort(usage, function (a, b) return a[2] > b[2] end)
local matchToInd, usageLen = getBestColourMatch(usage), #usage
local matchFrom, matchTo = usage[usageLen][1], usage[matchToInd][1]
for i = 1, 6 do if pattern[i] == matchFrom then
pattern[i] = matchTo
usage[matchToInd][2] = usage[matchToInd][2] + 1
end end
usage[usageLen] = nil
end
-- Convert to character. Adapted from oli414's function:
-- http://www.computercraft.info/forums2/index.php?/topic/25340-cc-176-easy-drawing-characters/
local data = 128
for i = 1, #pattern - 1 do if pattern[i] ~= pattern[6] then data = data + 2^(i-1) end end
return string.char(data), colourChar[usage[1][1] == pattern[6] and usage[2][1] or usage[1][1]], colourChar[pattern[6]]
else
-- Solid colour character:
return "\128", colourChar[pattern[1]], colourChar[pattern[1]]
end
end
local function snooze()
local myEvent = tostring({})
os.queueEvent(myEvent)
os.pullEvent(myEvent)
end
function shrink(image, bgCol)
local results, width, height, bgCol = {{}, {}, {}}, 0, #image + #image % 3, bgCol or colours.black
for i = 1, #image do if #image[i] > width then width = #image[i] end end
for y = 0, height - 1, 3 do
local cRow, tRow, bRow, counter = {}, {}, {}, 1
for x = 0, width - 1, 2 do
-- Grab a 2x3 chunk:
local pattern, totals = {}, {}
for yy = 1, 3 do for xx = 1, 2 do
pattern[#pattern + 1] = (image[y + yy] and image[y + yy][x + xx]) and (image[y + yy][x + xx] == 0 and bgCol or image[y + yy][x + xx]) or bgCol
totals[pattern[#pattern]] = totals[pattern[#pattern]] and (totals[pattern[#pattern]] + 1) or 1
end end
cRow[counter], tRow[counter], bRow[counter] = colsToChar(pattern, totals)
counter = counter + 1
end
results[1][#results[1] + 1], results[2][#results[2] + 1], results[3][#results[3] + 1] = table.concat(cRow), table.concat(tRow), table.concat(bRow)
end
results.width, results.height = #results[1][1], #results[1]
return results
end
function shrinkGIF(image, bgCol)
if not GIF and not os.loadAPI("GIF") then error("blittle.shrinkGIF: Load GIF API first.", 2) end
image = GIF.flattenGIF(image)
snooze()
local prev = GIF.toPaintutils(image[1])
snooze()
prev = blittle.shrink(prev, bgCol)
prev.delay = image[1].delay
image[1] = prev
snooze()
image.width, image.height = prev.width, prev.height
for i = 2, #image do
local temp = GIF.toPaintutils(image[i])
snooze()
temp = blittle.shrink(temp, bgCol)
snooze()
local newImage = {{}, {}, {}, ["delay"] = image[i].delay, ["width"] = temp.width, ["height"] = 0}
local a, b, c, pa, pb, pc = temp[1], temp[2], temp[3], prev[1], prev[2], prev[3]
for i = 1, temp.height do
local a1, b1, c1, pa1, pb1, pc1 = a[i], b[i], c[i], pa[i], pb[i], pc[i]
if a1 ~= pa1 or b1 ~= pb1 or c1 ~= pc1 then
local min, max = 1, #a1
local a2, b2, c2, pa2, pb2, pc2 = {a1:byte(1, max)}, {b1:byte(1, max)}, {c1:byte(1, max)}, {pa1:byte(1, max)}, {pb1:byte(1, max)}, {pc1:byte(1, max)}
for j = 1, max do if a2[j] ~= pa2[j] or b2[j] ~= pb2[j] or c2[j] ~= pc2[j] then
min = j
break
end end
for j = max, min, -1 do if a2[j] ~= pa2[j] or b2[j] ~= pb2[j] or c2[j] ~= pc2[j] then
max = j
break
end end
newImage[1][i], newImage[2][i], newImage[3][i], newImage.height = min > 1 and {min - 1, a1:sub(min, max)} or a1:sub(min, max), b1:sub(min, max), c1:sub(min, max), i
end
snooze()
end
image[i], prev = newImage, temp
for j = 1, i - 1 do
local oldImage = image[j]
if type(oldImage[1]) == "table" and oldImage.height == newImage.height then
local same = true
for k = 1, oldImage.height do
local comp1, comp2 = oldImage[1][k], newImage[1][k]
if type(comp1) ~= type(comp2) or
(type(comp1) == "string" and comp1 ~= comp2) or
(type(comp1) == "table" and (comp1[1] ~= comp2[1] or comp1[2] ~= comp2[2])) or
oldImage[2][k] ~= newImage[2][k] or
oldImage[3][k] ~= newImage[3][k] then
same = false
break
end
end
if same then
newImage[1], newImage[2], newImage[3] = j
break
end
end
snooze()
end
end
return image
end
local function newLine(width, bCol)
local line = {}
for i = 1, width do line[i] = {bCol, bCol, bCol, bCol, bCol, bCol} end
return line
end
function createWindow(parent, x, y, width, height, visible)
if parent == term or not parent then
parent = term.current()
elseif type(parent) ~= "table" or not parent.write then
error("blittle.newWindow: \"parent\" does not appear to be a terminal object.", 2)
end
local workBuffer, backBuffer, frontBuffer, window, tCol, bCol, curX, curY, blink, cWidth, cHeight, pal = {}, {}, {}, {}, colours.white, colours.black, 1, 1, false
if type(visible) ~= "boolean" then visible = true end
x, y = x and math.floor(x) or 1, y and math.floor(y) or 1
do
local xSize, ySize = parent.getSize()
cWidth, cHeight = (width or xSize), (height or ySize)
width, height = cWidth * 2, cHeight * 3
end
if parent.setPaletteColour then
pal = {}
local counter = 1
for i = 1, 16 do
pal[counter] = {parent.getPaletteColour(counter)}
counter = counter * 2
end
window.getPaletteColour = function(colour)
return unpack(pal[colour])
end
window.setPaletteColour = function(colour, r, g, b)
pal[colour] = {r, g, b}
if visible then return parent.setPaletteColour(colour, r, g, b) end
end
window.getPaletteColor, window.setPaletteColor = window.getPaletteColour, window.setPaletteColour
end
window.blit = function(_, _, bC)
local bClen = #bC
if curX > width or curX + bClen < 2 or curY < 1 or curY > height then
curX = curX + bClen
return
end
if curX < 1 then
bC = bC:sub(2 - curX)
curX, bClen = 1, #bC
end
if curX + bClen - 1 > width then bC, bClen = bC:sub(1, width - curX + 1), width - curX + 1 end
local colNum, rowNum, thisX, yBump = math.floor((curX - 1) / 2) + 1, math.floor((curY - 1) / 3) + 1, (curX - 1) % 2, ((curY - 1) % 3) * 2
local firstColNum, lastColNum, thisRow = colNum, math.floor((curX + bClen) / 2), backBuffer[rowNum]
local thisChar = thisRow[colNum]
for i = 1, bClen do
thisChar[thisX + yBump + 1] = colourChar[bC:sub(i, i)]
if thisX == 1 then
thisX, colNum = 0, colNum + 1
thisChar = thisRow[colNum]
if not thisChar then break end
else thisX = 1 end
end
if visible then
local chars1, chars2, chars3, count = {}, {}, {}, 1
for i = firstColNum, lastColNum do
chars1[count], chars2[count], chars3[count] = colsToChar(thisRow[i])
count = count + 1
end
chars1, chars2, chars3 = table.concat(chars1), table.concat(chars2), table.concat(chars3)
parent.setCursorPos(x + math.floor((curX - 1) / 2), y + math.floor((curY - 1) / 3))
parent.blit(chars1, chars2, chars3)
local thisRow = frontBuffer[rowNum]
frontBuffer[rowNum] = {thisRow[1]:sub(1, firstColNum - 1) .. chars1 .. thisRow[1]:sub(lastColNum + 1), thisRow[2]:sub(1, firstColNum - 1) .. chars2 .. thisRow[2]:sub(lastColNum + 1), thisRow[3]:sub(1, firstColNum - 1) .. chars3 .. thisRow[3]:sub(lastColNum + 1)}
else
local thisRow = workBuffer[rowNum]
if (not thisRow[firstColNum]) or thisRow[firstColNum] < lastColNum then
local x, newLastColNum = 1, lastColNum
while x <= lastColNum + 1 do
local thisSpot = thisRow[x]
if thisSpot then
if thisSpot >= firstColNum - 1 then
if x < firstColNum then firstColNum = x else thisRow[x] = nil end
if thisSpot > newLastColNum then newLastColNum = thisSpot end
end
x = thisSpot + 1
else x = x + 1 end
end
thisRow[firstColNum] = newLastColNum
if thisRow.max <= newLastColNum then thisRow.max = firstColNum end
end
end
curX = curX + bClen
end
window.write = function(text)
window.blit(nil, nil, string.rep(colourChar[bCol], #tostring(text)))
end
window.clearLine = function()
local oldX = curX
curX = 1
window.blit(nil, nil, string.rep(colourChar[bCol], width))
curX = oldX
end
window.clear = function()
local t, fC, bC = string.rep("\128", cWidth), string.rep(colourChar[tCol], cWidth), string.rep(colourChar[bCol], cWidth)
for y = 1, cHeight do workBuffer[y], backBuffer[y], frontBuffer[y] = {["max"] = 0}, newLine(cWidth, bCol), {t, fC, bC} end
window.redraw()
end
window.getCursorPos = function()
return curX, curY
end
window.setCursorPos = function(newX, newY)
curX, curY = math.floor(newX), math.floor(newY)
if visible and blink then window.restoreCursor() end
end
window.restoreCursor = function() end
window.setCursorBlink = window.restoreCursor
window.isColour = function()
return parent.isColour()
end
window.isColor = window.isColour
window.getSize = function()
return width, height
end
window.scroll = function(lines)
lines = math.floor(lines)
if lines ~= 0 then
if lines % 3 == 0 then
local newWB, newBB, newFB, line1, line2, line3 = {}, {}, {}, string.rep("\128", cWidth), string.rep(colourChar[tCol], cWidth), string.rep(colourChar[bCol], cWidth)
for y = 1, cHeight do newWB[y], newBB[y], newFB[y] = workBuffer[y + lines] or {["max"] = 0}, backBuffer[y + lines] or newLine(cWidth, bCol), frontBuffer[y + lines] or {line1, line2, line3} end
workBuffer, backBuffer, frontBuffer = newWB, newBB, newFB
else
local newBB, tRowNum, tBump, sRowNum, sBump = {}, 1, 0, math.floor(lines / 3) + 1, (lines % 3) * 2
local sRow, tRow = backBuffer[sRowNum], {}
for x = 1, cWidth do tRow[x] = {} end
for y = 1, height do
if sRow then
for x = 1, cWidth do
local tChar, sChar = tRow[x], sRow[x]
tChar[tBump + 1], tChar[tBump + 2] = sChar[sBump + 1], sChar[sBump + 2]
end
else
for x = 1, cWidth do
local tChar = tRow[x]
tChar[tBump + 1], tChar[tBump + 2] = bCol, bCol
end
end
tBump, sBump = tBump + 2, sBump + 2
if tBump > 4 then
tBump, newBB[tRowNum] = 0, tRow
tRowNum, tRow = tRowNum + 1, {}
for x = 1, cWidth do tRow[x] = {} end
end
if sBump > 4 then
sRowNum, sBump = sRowNum + 1, 0
sRow = backBuffer[sRowNum]
end
end
for y = 1, cHeight do workBuffer[y] = {["max"] = 1, cWidth} end
backBuffer = newBB
end
window.redraw()
end
end
window.setTextColour = function(newCol)
tCol = newCol
end
window.setTextColor = window.setTextColour
window.setBackgroundColour = function(newCol)
bCol = newCol
end
window.setBackgroundColor = window.setBackgroundColour
window.getTextColour = function()
return tCol
end
window.getTextColor = window.getTextColour
window.getBackgroundColour = function()
return bCol
end
window.getBackgroundColor = window.getBackgroundColour
window.redraw = function()
if visible then
for i = 1, cHeight do
local work, front = workBuffer[i], frontBuffer[i]
local front1, front2, front3 = front[1], front[2], front[3]
if work.max > 0 then
local line1, line2, line3, lineLen, skip, back, count = {}, {}, {}, 1, 0, backBuffer[i], 1
while count <= work.max do if work[count] then
if skip > 0 then
line1[lineLen], line2[lineLen], line3[lineLen] = front1:sub(count - skip, count - 1), front2:sub(count - skip, count - 1), front3:sub(count - skip, count - 1)
skip, lineLen = 0, lineLen + 1
end
for i = count, work[count] do
line1[lineLen], line2[lineLen], line3[lineLen] = colsToChar(back[i])
lineLen = lineLen + 1
end
count = work[count] + 1
else skip, count = skip + 1, count + 1 end end
if count < cWidth + 1 then line1[lineLen], line2[lineLen], line3[lineLen] = front1:sub(count), front2:sub(count), front3:sub(count) end
front1, front2, front3 = table.concat(line1), table.concat(line2), table.concat(line3)
frontBuffer[i], workBuffer[i] = {front1, front2, front3}, {["max"] = 0}
end
parent.setCursorPos(x, y + i - 1)
parent.blit(front1, front2, front3)
end
if pal then
local counter = 1
for i = 1, 16 do
parent.setPaletteColour(counter, unpack(pal[counter]))
counter = counter * 2
end
end
end
end
window.setVisible = function(newVis)
newVis = newVis and true or false
if newVis and not visible then
visible = true
window.redraw()
else visible = newVis end
end
window.getPosition = function()
return x, y
end
window.reposition = function(newX, newY, newWidth, newHeight)
x, y = type(newX) == "number" and math.floor(newX) or x, type(newY) == "number" and math.floor(newY) or y
if type(newWidth) == "number" then
newWidth = math.floor(newWidth)
if newWidth > cWidth then
local line1, line2, line3 = string.rep("\128", newWidth - cWidth), string.rep(colourChar[tCol], newWidth - cWidth), string.rep(colourChar[bCol], newWidth - cWidth)
for y = 1, cHeight do
local bRow, fRow = backBuffer[y], frontBuffer[y]
for x = cWidth + 1, newWidth do bRow[x] = {bCol, bCol, bCol, bCol, bCol, bCol} end
frontBuffer[y] = {fRow[1] .. line3, fRow[2] .. line2, fRow[3] .. line3}
end
elseif newWidth < cWidth then
for y = 1, cHeight do
local wRow, bRow, fRow = workBuffer[y], backBuffer[y], frontBuffer[y]
for x = newWidth + 1, cWidth do bRow[x] = nil end
frontBuffer[y] = {fRow[1]:sub(1, newWidth), fRow[2]:sub(1, newWidth), fRow[3]:sub(1, newWidth)}
while wRow[wRow.max] and wRow[wRow.max] > newWidth do
wRow[wRow.max] = nil
wRow.max = table.maxn(wRow)
end
end
end
width, cWidth = newWidth * 2, newWidth
end
if type(newHeight) == "number" then
newHeight = math.floor(newHeight)
if newHeight > cHeight then
local line1, line2, line3 = string.rep("\128", cWidth), string.rep(colourChar[tCol], cWidth), string.rep(colourChar[bCol], cWidth)
for y = cHeight + 1, newHeight do workBuffer[y], backBuffer[y], frontBuffer[y] = {["max"] = 0}, newLine(cWidth, bCol), {line1, line2, line3} end
elseif newHeight < cHeight then
for y = newHeight + 1, cHeight do workBuffer[y], backBuffer[y], frontBuffer[y] = nil, nil, nil end
end
height, cHeight = newHeight * 3, newHeight
end
window.redraw()
end
window.clear()
return window
end
function draw(image, x, y, terminal)
local t, tC, bC = image[1], image[2], image[3]
x, y, terminal = x or 1, y or 1, terminal or term.current()
for i = 1, image.height do
local tI = t[i]
if type(tI) == "string" then
terminal.setCursorPos(x, y + i - 1)
terminal.blit(tI, tC[i], bC[i])
elseif type(tI) == "table" then
terminal.setCursorPos(x + tI[1], y + i - 1)
terminal.blit(tI[2], tC[i], bC[i])
end
end
end
function save(image, filename)
local output = fs.open(filename, "wb")
if not output then error("Can't open "..filename.." for output.") end
local writeByte = output.write
local function writeInt(num)
writeByte(bit.band(num, 255))
writeByte(bit.brshift(num, 8))
end
writeByte(66) -- B
writeByte(76) -- L
writeByte(84) -- T
local animated = image[1].delay ~= nil
writeByte(animated and 1 or 0)
if animated then
writeInt(#image)
else
local tempImage = {image[1], image[2], image[3]}
image[1], image[2], image[3] = tempImage, nil, nil
end
local width, height = image.width, image.height
writeInt(width)
writeInt(height)
for k = 1, #image do
local thisImage = image[k]
if type(thisImage[1]) == "number" then
writeByte(3)
writeInt(thisImage[1])
else
for i = 1, height do
if thisImage[1][i] then
local rowType, len, thisRow = type(thisImage[1][i])
if rowType == "string" then
writeByte(1)
len = #thisImage[1][i]
writeInt(len)
thisRow = {thisImage[1][i]:byte(1, len)}
elseif rowType == "table" then
writeByte(2)
len = #thisImage[1][i][2]
writeInt(len)
writeInt(thisImage[1][i][1])
thisRow = {thisImage[1][i][2]:byte(1, len)}
else
error("Malformed row record #"..i.." in frame #"..k.." when attempting to save \""..filename.."\", type is "..rowType..".")
end
for x = 1, len do writeByte(thisRow[x]) end
local txt, bg = thisImage[2][i], thisImage[3][i]
for x = 1, len do writeByte(colourNum[txt:sub(x, x)] + colourNum[bg:sub(x, x)] * 16) end
else writeByte(0) end
end
end
if animated then writeInt(thisImage.delay * 20) end
snooze()
end
if image.pal then
writeByte(#image.pal)
for i = 0, #image.pal do for j = 1, 3 do writeByte(image.pal[i][j]) end end
end
if not animated then
image[2], image[3] = image[1][2], image[1][3]
image[1] = image[1][1]
end
output.close()
end
function load(filename)
local input = fs.open(filename, "rb")
if not input then error("Can't open "..filename.." for input.") end
local read = input.read
local function readInt()
local result = read()
return result + bit.blshift(read(), 8)
end
if string.char(read(), read(), read()) ~= "BLT" then
-- Assume legacy format.
input.close()
input = fs.open(filename, "rb")
read = input.read
function readInt()
local result = input.read()
return result + bit.blshift(input.read(), 8)
end
local image = {}
image.width, image.height = readInt(), readInt()
for i = 1, 3 do
local thisSet = {}
for y = 1, image.height do
local thisRow = {}
for x = 1, image.width do thisRow[x] = string.char(input.read()) end
thisSet[y] = table.concat(thisRow)
end
image[i] = thisSet
end
input.close()
return image
end
local image, animated, frames = {}, read() == 1
if animated then frames = readInt() else frames = 1 end
local width, height = readInt(), readInt()
image.width, image.height = width, height
for k = 1, frames do
local thisImage = {["width"] = width, ["height"] = 0}
local chr, txt, bg = {}, {}, {}
for i = 1, height do
local lineType = read()
if lineType == 3 then
chr, txt, bg = readInt()
break
elseif lineType > 0 then
local l1, l2, len, bump = {}, {}, readInt()
if lineType == 2 then bump = readInt() end
for x = 1, len do l1[x] = read() end
chr[i] = string.char(unpack(l1))
if lineType == 2 then chr[i] = {bump, chr[i]} end
for x = 1, len do
local thisVal = read()
l1[x], l2[x] = colourNum[bit.band(thisVal, 15)], colourNum[bit.brshift(thisVal, 4)]
end
txt[i], bg[i], thisImage.height = table.concat(l1), table.concat(l2), i
end
end
if animated then thisImage["delay"] = readInt() / 20 end
thisImage[1], thisImage[2], thisImage[3] = chr, txt, bg
image[k] = thisImage
snooze()
end
local palLength = read()
if palLength and palLength > 0 then
image.pal = {}
for i = 0, palLength do image.pal[i] = {read(), read(), read()} end
end
if not animated then
image[2], image[3] = image[1][2], image[1][3]
image[1] = image[1][1]
end
input.close()
return image
end
if term.setPaletteColour then
function applyPalette(image, terminal)
terminal = terminal or term
local col, pal = 1, image.pal
for i = 0, #pal do
local thisCol = pal[i]
terminal.setPaletteColour(col, thisCol[1] / 255, thisCol[2] / 255, thisCol[3] / 255)
col = col * 2
end
end
end

847
real_startup.lua Normal file
View File

@ -0,0 +1,847 @@
-- LevelOS
term.clear()
term.setCursorPos(1,1)
if not fs.exists("LevelOS") then
--Let the bios know the system is broken
fs.delete("/real_startup.lua")
os.reboot()
return
end
for k,v in pairs(colors) do
if type(v) == "number" then
term.setPaletteColor(v,term.native().getPaletteColor(v))
end
end
if lOS then
error("LevelOS is already running, silly!")
end
_G.lOS = {}
lOS.path = shell.getRunningProgram()
local chunkSize = 32768
if jit then
chunkSize = 4092
end
local function encodeUTF8(asciiText)
local utf8Text = ""
for i=1, #asciiText, chunkSize do
utf8Text = utf8Text..utf8.char(string.byte(asciiText, i, math.min(i + (chunkSize-1), #asciiText)))
end
return utf8Text
end
local function decodeUTF8(utf8Text)
local asciiText = ""
local ok, t = pcall(function()
return string.char(utf8.codepoint(utf8Text, 1, #utf8Text))
end)
if ok then
asciiText = t
else
local ok2, err = pcall(function()
for _, codepoint in utf8.codes(utf8Text) do
if codepoint < 256 then
asciiText = asciiText .. string.char(codepoint)
else
asciiText = asciiText .. "?"
end
end
end)
if not ok2 then
_G.debugCurrentText = asciiText
_G.debugTextInput = utf8Text
error(err, 2)
end
end
return asciiText
end
local function encodeAll(...)
local tbl = table.pack(...)
for k,v in pairs(tbl) do
if type(v) == "string" and not utf8.len(v) then
tbl[k] = encodeUTF8(v)
end
end
return table.unpack(tbl, 1, tbl.n)
end
local function decodeAll(...)
local tbl = table.pack(...)
for k,v in pairs(tbl) do
if type(v) == "string" then
tbl[k] = decodeUTF8(v)
end
end
return table.unpack(tbl, 1, tbl.n)
end
lOS.utf8 = {
decode = decodeUTF8,
encode = encodeUTF8,
decodeAll = decodeAll,
encodeAll = encodeAll,
}
local function extractVersion(str)
local version = str:match("ComputerCraft (%d+%.%d+%.%d+)")
return version
end
local function isVersionAbove(version1, version2)
local function splitVersion(version)
local parts = {}
for part in version:gmatch("(%d+)") do
table.insert(parts, tonumber(part))
end
return parts
end
local v1Parts = splitVersion(version1)
local v2Parts = splitVersion(version2)
for i = 1, math.max(#v1Parts, #v2Parts) do
local v1 = v1Parts[i] or 0
local v2 = v2Parts[i] or 0
if v1 > v2 then
return true
elseif v1 < v2 then
return false
end
end
return true -- They are equal if all parts are equal
end
if isVersionAbove(extractVersion(_HOST), "1.109") then
local fopen = fs.open
function fs.open(path, mode)
local f = fopen(path, mode)
if not f then return nil end
local customHandle = {}
for k,v in pairs(f) do
if mode:find("b") then
customHandle[k] = function(...) return v(...) end
else
customHandle[k] = function(...) return decodeAll(v(encodeAll(...))) end
end
end
return customHandle
end
end
--enable mouse if no color
if not rtype then
_G.rtype = type
_G.type = function(obj)
local mt = getmetatable(obj)
if rtype(mt) == "table" and mt.__type then
if rtype(mt.__type) == "string" then
return mt.__type
elseif rtype(mt.__type) == "function" then
return mt.__type(obj)
end
else
return rtype(obj)
end
end
end
function _G.pairs(t)
local mt = getmetatable(t)
if mt and type(mt.__pairs) == "function" then
return mt.__pairs(t)
else
return next, t, nil
end
end
if not hardreboot then
_G.hardreboot = os.reboot
end
if fs.combine("a","b","c") == fs.combine("a","b") then
local ocombine = fs.combine
function fs.combine(path,...)
local parts = {...}
for p=1,#parts do
path = ocombine(path,parts[p])
end
return path
end
end
local w,h = term.getSize()
if h < 19 then return end
local newwin = false
local therealOGterm = term.current()
local function tokenise( ... )
local sLine = table.concat( { ... }, " " )
local tWords = {}
local bQuoted = false
for match in string.gmatch( sLine .. "\"", "(.-)\"" ) do
if bQuoted then
table.insert( tWords, match )
else
for m in string.gmatch( match, "[^ \t]+" ) do
table.insert( tWords, m )
end
end
bQuoted = not bQuoted
end
return tWords
end
if fs.exists("AppData") == false then
fs.makeDir("AppData")
end
if fs.exists("User") == false then
fs.makeDir("User")
fs.makeDir("User/Documents")
fs.makeDir("User/Images")
fs.makeDir("User/Scripts")
fs.makeDir("User/Downloads")
end
if not fs.exists("bigfont") then
--Let the bios know the system is broken
fs.delete("/real_startup.lua")
os.reboot()
return
end
local to_colors, to_blit = {}, {}
for i = 1, 16 do
to_blit[2^(i-1)] = ("0123456789abcdef"):sub(i, i)
to_colors[("0123456789abcdef"):sub(i, i)] = 2^(i-1)
end
local function toColor(theblit)
return to_colors[theblit] or nil
end
local function toBlit(thecolor)
return to_blit[thecolor] or nil
end
local function render(spr,x,y)
local format = "lImg"
if format == "lImg" then
local sW,sH = #spr[1][1],#spr
local w,h = term.getSize()
for l=1,#spr do
if not y then
term.setCursorPos(math.ceil(w/2)-math.floor(sW/2),(math.ceil(h/2)-math.floor(sH/2)+(l-1))+x)
else
term.setCursorPos(x,y+(l-1))
end
local bl = {}
bl[1] = spr[l][1]
bl[2] = string.gsub(spr[l][2],"T",toBlit(term.getBackgroundColor()))
bl[3] = string.gsub(spr[l][3],"T",toBlit(term.getBackgroundColor()))
term.blit(unpack(bl))
end
elseif format == "nfp" or format == "nfg" then
local b,e = string.find(spr,"\n")
local sW,sH
local w,h = term.getSize()
local lines,sW = getLines(spr)
sH = #lines
for l=1,sH do
term.setCursorPos(math.ceil(w/2)-math.floor(sW/2),math.ceil(h/2)-math.floor(sH/2)+(l-1))
term.blit(string.rep(" ",#lines[l]),lines[l],lines[l])
end
end
end
local function fread(file)
local f = fs.open(file,"r")
local o = f.readAll()
f.close()
return o
end
local function fwrite(file,content)
local f = fs.open(file,"w")
f.write(content)
f.close()
return true
end
local loadingico = textutils.unserialize(fread("LevelOS/assets/loading.limg"))
_G.bigfont = loadfile("bigfont",_ENV)()
local progress = 0
local function centerText(text,customY,customLen) -- i tried to put indentation but pastebin is being stupid for some reason
local x,y = term.getSize()
local x2,y2 = term.getCursorPos()
if customY then y2 = customY end
local len = customLen or text:len()
term.setCursorPos((math.ceil(x / 2) - math.floor(len / 2)), y2)
term.write(text)
term.setCursorPos(x2,y2+1)
end
local doUpdate
local bootText = "Initializing"
local dots = 1
local frame = 1
local function bootscreen()
term.setBackgroundColor(colors.black)
term.setTextColor(colors.cyan)
term.clear()
local w,h = term.getSize()
if h > 19 then
if fs.exists("LevelOS/assets/logo_christmas.limg") and os.date("%m") == "12" then
render(textutils.unserialize(fread("LevelOS/assets/logo_christmas.limg"))[1],math.ceil(w/2)-4,h/2-8)
elseif fs.exists("LevelOS/assets/logo_pride.limg") then
render(textutils.unserialize(fread("LevelOS/assets/logo_pride.limg"))[1],math.ceil(w/2)-4,h/2-8)
else
bigfont.writeOn(term.current(),2,"L",nil,h/2-8)
end
else
if fs.exists("LevelOS/assets/logo_christmas.limg") and os.date("%m") == "12" then
render(textutils.unserialize(fread("LevelOS/assets/logo_christmas.limg"))[1],math.ceil(w/2)-4,h/2-5)
elseif fs.exists("LevelOS/assets/logo_pride.limg") then
render(textutils.unserialize(fread("LevelOS/assets/logo_pride.limg"))[1],math.ceil(w/2)-4,h/2-5)
else
bigfont.writeOn(term.current(),2,"L",nil,h/2-5)
end
end
while true do
if doUpdate then
term.setBackgroundColor(colors.blue)
term.setTextColor(colors.white)
term.clear()
local w,h = term.getSize()
term.setCursorPos(1,math.ceil(h/2))
centerText("Getting ready for updates")
centerText("Do not turn off your computer")
local init = false
while true do
render(loadingico[frame],-5)
if progress > 0 then
if not init then
term.setBackgroundColor(colors.blue)
term.setTextColor(colors.white)
term.clear()
render(loadingico[frame],-5)
init = true
end
term.setCursorPos(1,math.ceil(h/2))
centerText("Working on updates")
centerText(math.floor(progress + 0.5).."% complete")
centerText("Do not turn off your computer")
end
frame = frame+1
if frame > #loadingico then
frame = 1
end
os.sleep(0.1)
end
end
if h > 19 then
render(loadingico[frame],10)
if bootText then
centerText(" "..bootText..string.rep(".",dots).." ",h/2+14,#(" "..bootText.." "))
end
else
render(loadingico[frame],7)
end
os.pullEvent()
end
end
local function loadIco()
while true do
frame = frame+1
if frame > #loadingico then
frame = 1
end
dots = dots+0.5
if dots > 3 then dots = 0 end
os.sleep(0.1)
end
end
local hpost = function(...)
while true do
local ret = table.pack(http.post(...))
if not ret[1] then
os.sleep(0.5)
else
badConn = false
return table.unpack(ret, 1, ret.n)
end
end
end
local function getField(thing,fieldname)
if string.find(thing,"<"..fieldname..">",1,true) ~= nil and string.find(thing,"</"..fieldname..">",1,true) ~= nil then
local begin = nil
local ending = nil
local trash,begin = string.find(thing,"<"..fieldname..">",1,true)
local ending,ending2 = string.find(thing,"</"..fieldname..">",begin+1,true)
if begin ~= nil and ending ~= nil then
return string.sub(thing,begin+1,ending-1),string.sub(thing,1,trash-1)..string.sub(thing,ending2+1,string.len(thing))
end
end
return nil
end
local function download(pth)
local f = hpost("https://os.leveloper.cc/sGet.php","path="..textutils.urlEncode(pth).."&code="..textutils.urlEncode("lSlb8kZq"),{Cookie=userID}).readAll()
if f ~= "409" and f ~= "403" and f ~= "401" then
if pth == "startup.lua" and f ~= fread(shell.getRunningProgram()) then
fwrite(shell.getRunningProgram(),f)
os.sleep(1)
os.reboot()
end
if pth ~= "startup.lua" then
fwrite(pth,f)
end
return true
else
return false
end
end
local step = 0.05
local function update()
bootText = "Connecting to server"
os.sleep(step)
local opost = http.post
local ping = http.get("https://os.leveloper.cc/ping.php")
if not ping then
bootText = "Trying HTTP"
os.sleep(step)
local ping2 = http.get("http://os.leveloper.cc/ping.php")
if not ping2 then
bootText = "Starting in offline"
os.sleep(step)
-- no internet
return
end
function http.post(...)
local args = table.pack(...)
local r = table.pack(opost(...))
if not r[1] and string.find(args[1],"https://",nil,true) == 1 then
args[1] = "http"..string.sub(args[1],6,#args[1])
return opost(table.unpack(args))
else
return table.unpack(r)
end
end
local oget = http.get
function http.get(...)
local args = table.pack(...)
local r = table.pack(oget(...))
if not r[1] and string.find(args[1],"https://",nil,true) == 1 then
args[1] = "http"..string.sub(args[1],6,#args[1])
return oget(table.unpack(args))
else
return table.unpack(r)
end
end
hpost = http.post
end
bootText = "Checking client version"
os.sleep(step)
local servertimestamp
local clienttimestamp
if fs.exists("LevelOS/data/version.txt") then
clienttimestamp = tonumber(fread("LevelOS/data/version.txt"))
end
if not clienttimestamp then
clienttimestamp = 0
end
bootText = "Looking for updates"
os.sleep(step)
local response,err = hpost("https://os.leveloper.cc/sGet.php","path="..textutils.urlEncode("").."&code="..textutils.urlEncode("lSlb8kZq"))
local res2,err2
if fs.exists("LevelOS/startup/LevelCloud.lua") then
res2,err2 = hpost("https://os.leveloper.cc/sGet.php","path="..textutils.urlEncode("").."&code="..textutils.urlEncode("Sm0f1bwQ"))
end
if res2 then
bootText = "Updating LevelCloud"
os.sleep(step)
local f = res2.readAll()
local sTS = tonumber((getField(f,"version"))) or math.huge
local cTS = fs.attributes("LevelOS/startup/LevelCloud.lua").modification or fs.attributes("LevelOS/startup/LevelCloud.lua").modified or 0
if sTS > cTS then
local f = hpost("https://os.leveloper.cc/sGet.php","path="..textutils.urlEncode("LevelCloud.lua").."&code="..textutils.urlEncode("Sm0f1bwQ"))
if f then
fwrite("LevelOS/startup/LevelCloud.lua",f.readAll())
end
end
end
bootText = "Processing"
os.sleep(step)
if not response then
-- could not connect
--os.sleep(0.5)
-- put "starting in offline mode"
return
end
local f = response.readAll()
servertimestamp = tonumber((getField(f,"version")))
local tFiles = 0
local pack = "Full"
if fs.exists("LevelOS/data/settings.lconf") then
local set = textutils.unserialize(fread("LevelOS/data/settings.lconf"))
if set.package then
pack = set.package
end
end
local tree = {}
local folders = {}
local function searchFolder(folder)
--print("Searching folder root/"..folder)
local f = hpost("https://os.leveloper.cc/sGet.php","path="..textutils.urlEncode(folder).."&code="..textutils.urlEncode("lSlb8kZq")).readAll()
--print(f)
local f2 = f
while true do
local file = nil
file,f = getField(f,"file")
if not file then
break
else
local name = getField(file,"name")
local timestamp = getField(file,"timestamp")
timestamp = tonumber(timestamp)
if pack == "Full" or fs.exists(fs.combine(folder,name)) or folder == "LevelOS/assets" or fs.combine(folder,name) == "startup.lua" then
tree[fs.combine(folder,name)] = {timestamp=timestamp}
tFiles = tFiles+1
end
--print("Found "..fs.combine(folder,name))
end
end
f = f2
while true do
local file = nil
file,f = getField(f,"folder")
if not file then
break
else
local name = getField(file,"name")
if not fs.exists(fs.combine(folder,name)) then
fs.makeDir(fs.combine(folder,name))
end
folders[fs.combine(folder,name)] = ""
searchFolder(fs.combine(folder,name))
end
end
return true
end
if servertimestamp > clienttimestamp then
doUpdate = true
local deleteFiles = {
"LevelOS/explorer.lua",
"LevelOS/Pigeon.lua",
"LevelOS/LevelCloud.lua",
"LevelOS/notepad.lua",
"LevelOS/Register.lua",
}
if fs.exists("LevelOS/data/nativelog.txt") then
fs.move("LevelOS/data/nativelog.txt","LevelOS/data/nativelog.lconf")
end
for f=1,#deleteFiles do
if fs.exists(deleteFiles[f]) then
fs.delete(deleteFiles[f])
end
end
else
bootText = "Checking file integrity"
os.sleep(step)
local icheck = {
--"startup.lua",
"bigfont",
"blittle",
"LevelOS",
"LevelOS/system.lua",
"LevelOS/startup",
"LevelOS/startup/lUtils.lua",
"LevelOS/assets",
"LevelOS/assets/Circle_Symbols.limg",
"LevelOS/assets/circProgress.limg",
"LevelOS/assets/Compact_Icons.limg",
"LevelOS/assets/Desktop_Icons.limg",
"LevelOS/assets/loading.limg",
"LevelOS/assets/logo_pride.limg",
"LevelOS/assets/QR_Code.limg",
"LevelOS/assets/wifi.limg",
"LevelOS/login.lua",
"LevelOS/Changelog.lua",
"LevelOS/lStore.lua",
"LevelOS/SystemUI.lua",
"LevelOS/Task_Manager.lua",
}
local aFiles = {} -- absent files
for f=1,#icheck do
if not fs.exists(icheck[f]) then
table.insert(aFiles,icheck[f])
end
end
if #aFiles > 0 then
bootText = "Integrity compromised"
os.sleep(0.5)
bootText = "Restoring files"
if not searchFolder("") then return false end
for f=1,#aFiles do
while not download(aFiles[f]) do
end
end
bootText = "Restarting"
os.sleep(1)
os.reboot()
end
end
if doUpdate then
if not searchFolder("") then return false end
if tree["startup.lua"] then
download("startup.lua")
end
for k,v in pairs(tree) do
if download(k,root,v.timestamp) == true then
progress = progress+(100/tFiles)
end
end
fwrite("LevelOS/data/version.txt",tostring(servertimestamp))
os.sleep(1)
os.reboot()
end
if not fs.exists("LevelOS/assets/wifi.limg") then
folders["LevelOS/assets"] = ""
if not searchFolder("LevelOS/assets") then return false end
for k,v in pairs(tree) do
if download(k) == true then
end
end
end
bootText = "Loading system"
os.sleep(step)
end
parallel.waitForAny(update,bootscreen,loadIco)
local expect = require "cc.expect".expect
local function wrap(txt,width)
local lines = {}
for line in txt:gmatch("([^\n]*)\n?") do
table.insert(lines,"")
for word in line:gmatch("%S*%s?") do
if #lines[#lines]+#word > width and #lines[#lines] > 0 then
lines[#lines+1] = ""
end
if #lines[#lines]+#word > width then
local tWord = word
while #lines[#lines]+#tWord > width do
print(tWord:sub(1,width))
lines[#lines] = tWord:sub(1,width)
table.insert(lines,"")
tWord = tWord:sub(width+1)
end
lines[#lines] = tWord
else
lines[#lines] = lines[#lines]..word
end
end
end
if txt:sub(#txt) == "\n" then
table.insert(lines,"")
end
return lines
end
local function bPrint(txt)
local x,y = term.getCursorPos()
local w,h = term.getSize()
local text = wrap(txt,w-(x-1))
for t=1,#text do
term.write(text[t])
term.setCursorPos(x,y+t)
end
end
local function wordwrap(str)
local x,y = term.getCursorPos()
local tW,tH = term.getSize()
for w in str:gmatch("%S+") do
local x1,y1 = term.getCursorPos()
if x1+(#w*3) >= tW then
bigfont.bigPrint(" ")
local x2,y2 = term.getCursorPos()
term.setCursorPos(x,y2)
end
bigfont.bigWrite(w.." ")
end
end
if fs.exists("LevelOS/lStore.lua") then
shell.setAlias("lStore","LevelOS/lStore.lua")
local completion = require "cc.shell.completion"
local function completelStorePut(shell, text, previous)
if previous[2] == "put" then
return fs.complete(text, "User/Cloud", true, false)
end
end
shell.setCompletionFunction("LevelOS/lStore.lua", completion.build(
{ completion.choice, { "put ", "get ", "run " } },
completelStorePut
))
end
if jit then
shell.run("lStore get JITAlert LevelOS/startup/JITAlert2.lua")
if fs.exists("LevelOS/startup/JITAlert2.lua") then
if fs.exists("LevelOS/startup/JITAlert.lua") then
fs.delete("LevelOS/startup/JITAlert.lua")
end
fs.move("LevelOS/startup/JITAlert2.lua","LevelOS/startup/JITAlert.lua")
end
elseif fs.exists("LevelOS/startup/JITAlert.lua") then
fs.delete("LevelOS/startup/JITAlert.lua")
end
local u
local u = {pcall(loadfile("LevelOS/system.lua",_ENV))}
_G.whatitreturn = u
local link
local copied = false
local crashwin
function bsodRender()
term.redirect(therealOGterm)
term.setPaletteColor(colors.blue,0,120/255,215/255)
term.setPaletteColor(colors.white,1,1,1)
term.setCursorPos(4,4)
term.setBackgroundColor(colors.blue)
term.clear()
local w,h = term.getSize()
if w > 140 then
crashwin = window.create(therealOGterm,12,8,w/2+10,h-12)
bigfont.writeOn(therealOGterm,3,"L",w-40,math.ceil(h/2)-10)
else
crashwin = window.create(therealOGterm,4,5,w-8,h-5)
end
term.redirect(crashwin)
term.setBackgroundColor(colors.blue)
term.clear()
if w > 110 and h > 40 and fs.exists("LevelOS/assets/QR_Code.limg") then
local qrcode = textutils.unserialize(fread("LevelOS/assets/QR_Code.limg"))
bigfont.hugePrint(":(")
wordwrap("Your PC ran into a problem and needs to restart. Please press space to continue.")
print("\n\n\n\n\n\n")
local x,y = term.getCursorPos()
render(qrcode[1],x,y)
term.setCursorPos(x+22,y)
bPrint("For more information about this issue and possible fixes, visit ")
local txt = "https://discord.gg/vBsjGqy99U"
if copied then
txt = txt.." (copied to clipboard!)"
end
local tx,ty = term.getCursorPos()
local tw,th = term.getSize()
if tx+(#txt-1) > tw then
ty = ty+1
tx = x+22
end
if ccemux and ccemux.setClipboard then
link = {x=tx,y=ty,w=#txt,h=1,txt="https://discord.gg/vBsjGqy99U"}
if copied then
term.setTextColor(colors.cyan)
else
term.setTextColor(colors.lightBlue)
term.setCursorPos(link.x,link.y+1)
term.write(string.rep("\131",link.w))
end
end
term.setCursorPos(tx,ty)
term.write(txt)
term.setTextColor(colors.white)
term.setCursorPos(x+22,y+(#qrcode[1]-3))
bPrint("If you contact support, give them this info:")
term.setCursorPos(x+22,y+(#qrcode[1]-1))
bPrint(u[2])
else
bigfont.bigPrint(":(")
print("\nYour PC ran into a problem and needs to restart. Please press space to continue.")
print("\nError:")
print(u[2])
end
end
bsodRender()
os.sleep(1)
while true do
local e = {os.pullEventRaw()}
if e[1] == "mouse_click" then
local x,y = crashwin.getPosition()
e[3] = e[3]-(x-1)
e[4] = e[4]-(y-1)
end
if e[1] == "key" and e[2] == keys.space then
hardreboot()
elseif e[1] == "term_resize" then
bsodRender()
elseif link and e[1] == "mouse_click" and e[3] >= link.x and e[4] == link.y and e[3] <= link.x+(link.w-1) then
ccemux.setClipboard(link.txt)
copied = true
bsodRender()
elseif link and e[1] == "mouse_click" then
--[[term.setCursorPos(1,1)
print(textutils.serialize(link))
print(textutils.serialize(e))]]
elseif e[1] == "terminate" then
term.redirect(therealOGterm)
break
end
end
-- TEMP FOR DEBUGGING
term.setBackgroundColor(colors.black) term.clear() term.setCursorPos(1,1)
shell.run("shell")