· 5 years ago · Jan 21, 2021, 06:14 AM
1-- TRASH by LDDestroier
2-- Syntax:
3-- > trash.lua [program] [arg1] [arg2] ...
4--
5-- Close the program or use LeftCTRL + LeftSHIFT + Backspace
6-- to throw it in the traaaaaaaaash
7
8local tArg = {...}
9
10local scr_x, scr_y = term.getSize()
11
12local images = {
13 handOpen = {
14 {" ","","","
"," "," "," ",},
15 {" 00ffff ","fffff000000","ffff0000000"," ff0000000"," f000 "," f000 "," 00 ",},
16 {" f00000 ","0000000000f","0000000000f"," 0000000ff"," 000f "," 00ff "," ff ",}
17 },
18 handClosed = {
19 {" "," "," ","
"," "," "},
20 {" fffff "," fff0000000"," ff00000000"," ff00000000"," 0fff000 "," 0000 "},
21 {" 00000 "," 000000000f"," 000000000f"," 0000000fff"," f00000f "," ffff "}
22 },
23 trashCan = {
24 {"","
"," "," "," "," "," ","
","
"},
25 {"888ffffffff888","f8877787778788","8878888788878 "," f88788788788 "," f8878878878 "," 8878878788 "," f887878788 "," 887787778 "," 88888888 "},
26 {"7788888888887f","8878887888788f"," 887887888788 "," 88788788788f "," 88788788788 "," 887878878f "," 887878788f "," f8887888f "," ffffffff ", }
27 },
28 trashLid = {
29 {" "," "," ","", },
30 {"fffffffffff","fffffffffff","ffffffffff8","f888877778888f"},
31 {"fffffffffff","fffffffffff","fff8888888f","88888888888888"}
32 }
33}
34
35for k,v in pairs(images) do
36 for y = 1, #v do
37 for x = 1, #v[y] do
38 images[k][y][x] = v[y][x]:gsub(" ", "f")
39 end
40 end
41end
42
43-- start up lddterm
44local lddterm = {}
45lddterm.alwaysRender = false -- renders after any and all screen-changing functions.
46lddterm.useColors = true -- normal computers do not allow color, but this variable doesn't do anything yet
47lddterm.baseTerm = term.current() -- will draw to this terminal
48lddterm.transformation = nil -- will modify the current buffer as an NFT image before rendering
49lddterm.cursorTransformation = nil -- will modify the cursor position
50lddterm.drawFunction = nil -- will draw using this function instead of basic NFT drawing
51lddterm.adjustX = 0 -- moves entire screen X
52lddterm.adjustY = 0 -- moves entire screen Y
53lddterm.selectedWindow = 1 -- determines which window controls the cursor
54lddterm.windows = {}
55
56-- converts hex colors to colors api, and back
57local to_colors, to_blit = {
58 [' '] = 0,
59 ['0'] = 1,
60 ['1'] = 2,
61 ['2'] = 4,
62 ['3'] = 8,
63 ['4'] = 16,
64 ['5'] = 32,
65 ['6'] = 64,
66 ['7'] = 128,
67 ['8'] = 256,
68 ['9'] = 512,
69 ['a'] = 1024,
70 ['b'] = 2048,
71 ['c'] = 4096,
72 ['d'] = 8192,
73 ['e'] = 16384,
74 ['f'] = 32768,
75}, {}
76for k,v in pairs(to_colors) do
77 to_blit[v] = k
78end
79
80-- separates string into table based on divider
81local explode = function(div, str, replstr, includeDiv)
82 if (div == '') then
83 return false
84 end
85 local pos, arr = 0, {}
86 for st, sp in function() return string.find(str, div, pos, false) end do
87 table.insert(arr, string.sub(replstr or str, pos, st - 1 + (includeDiv and #div or 0)))
88 pos = sp + 1
89 end
90 table.insert(arr, string.sub(replstr or str, pos))
91 return arr
92end
93
94-- determines the size of the terminal before rendering always
95local determineScreenSize = function()
96 scr_x, scr_y = lddterm.baseTerm.getSize()
97 lddterm.screenWidth = scr_x
98 lddterm.screenHeight = scr_y
99end
100
101determineScreenSize()
102
103-- takes two or more windows and checks if the first of them overlap the other(s)
104lddterm.checkWindowOverlap = function(window, ...)
105 if #lddterm.windows < 2 then
106 return false
107 end
108 local list, win = {...}
109 for i = 1, #list do
110 win = list[i]
111 if win ~= window then
112
113 if (
114 window.x < win.x + win.width and
115 win.x < window.x + window.width and
116 window.y < win.y + win.height and
117 win.y < window.y + window.height
118 ) then
119 return true
120 end
121
122 end
123 end
124 return false
125end
126
127local fixCursorPos = function()
128 local cx, cy
129 if lddterm.windows[lddterm.selectedWindow] then
130 if lddterm.cursorTransformation then
131 cx, cy = lddterm.cursorTransformation(
132 lddterm.windows[lddterm.selectedWindow].cursor[1],
133 lddterm.windows[lddterm.selectedWindow].cursor[2]
134 )
135 lddterm.baseTerm.setCursorPos(
136 cx + lddterm.windows[lddterm.selectedWindow].x - 1,
137 cy + lddterm.windows[lddterm.selectedWindow].y - 1
138 )
139 else
140 lddterm.baseTerm.setCursorPos(
141 -1 + lddterm.windows[lddterm.selectedWindow].cursor[1] + lddterm.windows[lddterm.selectedWindow].x,
142 lddterm.windows[lddterm.selectedWindow].cursor[2] + lddterm.windows[lddterm.selectedWindow].y - 1
143 )
144 end
145 lddterm.baseTerm.setCursorBlink(lddterm.windows[lddterm.selectedWindow].blink)
146 end
147end
148
149-- renders the screen with optional transformation function
150lddterm.render = function(transformation, drawFunction)
151 -- determine new screen size and change lddterm screen to fit
152 old_scr_x, old_scr_y = scr_x, scr_y
153 determineScreenSize()
154 if old_scr_x ~= scr_x or old_scr_y ~= scr_y then
155 lddterm.baseTerm.clear()
156 end
157 local image = lddterm.screenshot()
158 if type(transformation) == "function" then
159 image = transformation(image)
160 end
161 if drawFunction then
162 drawFunction(image, lddterm.baseTerm)
163 else
164 for y = 1, #image[1] do
165 lddterm.baseTerm.setCursorPos(1 + lddterm.adjustX, y + lddterm.adjustY)
166 lddterm.baseTerm.blit(image[1][y], image[2][y], image[3][y])
167 end
168 end
169 fixCursorPos()
170end
171
172lddterm.newWindow = function(width, height, x, y, meta)
173 meta = meta or {}
174 local window = {
175 width = math.floor(width),
176 height = math.floor(height),
177 blink = true,
178 cursor = meta.cursor or {1, 1},
179 colors = meta.colors or {"0", "f"},
180 clearChar = meta.clearChar or " ",
181 visible = meta.visible or true,
182 x = math.floor(x) or 1,
183 y = math.floor(y) or 1,
184 buffer = {{},{},{}},
185 }
186 for y = 1, height do
187 window.buffer[1][y] = {}
188 window.buffer[2][y] = {}
189 window.buffer[3][y] = {}
190 for x = 1, width do
191 window.buffer[1][y][x] = window.clearChar
192 window.buffer[2][y][x] = window.colors[1]
193 window.buffer[3][y][x] = window.colors[2]
194 end
195 end
196
197 window.handle = {}
198 window.handle.setCursorPos = function(x, y)
199 window.cursor = {x, y}
200 fixCursorPos()
201 end
202 window.handle.getCursorPos = function()
203 return window.cursor[1], window.cursor[2]
204 end
205 window.handle.setCursorBlink = function(blink)
206 window.blink = blink or false
207 end
208 window.handle.getCursorBlink = function()
209 return window.blink
210 end
211 window.handle.scroll = function(amount)
212 if amount > 0 then
213 for i = 1, amount do
214 for c = 1, 3 do
215 table.remove(window.buffer[c], 1)
216 window.buffer[c][window.height] = {}
217 for xx = 1, width do
218 window.buffer[c][window.height][xx] = (
219 c == 1 and window.clearChar or
220 c == 2 and window.colors[1] or
221 c == 3 and window.colors[2]
222 )
223 end
224 end
225 end
226 elseif amount < 0 then
227 for i = 1, -amount do
228 for c = 1, 3 do
229 window.buffer[c][window.height] = nil
230 table.insert(window.buffer[c], 1, {})
231 for xx = 1, width do
232 window.buffer[c][1][xx] = (
233 c == 1 and window.clearChar or
234 c == 2 and window.colors[1] or
235 c == 3 and window.colors[2]
236 )
237 end
238 end
239 end
240 end
241 if lddterm.alwaysRender then
242 lddterm.render(lddterm.transformation, lddterm.drawFunction)
243 end
244 end
245 window.handle.scrollX = function(amount)
246 if amount > 0 then
247 for i = 1, amount do
248 for c = 1, 3 do
249 for y = 1, window.height do
250 table.remove(window.buffer[c][y], 1)
251 window.buffer[c][y][window.width] = (
252 c == 1 and window.clearChar or
253 c == 2 and window.colors[1] or
254 c == 3 and window.colors[2]
255 )
256 end
257 end
258 end
259 elseif amount < 0 then
260 for i = 1, -amount do
261 for c = 1, 3 do
262 for y = 1, window.height do
263 window.buffer[c][y][window.width] = nil
264 table.insert(window.buffer[c][y], 1, (
265 c == 1 and window.clearChar or
266 c == 2 and window.colors[1] or
267 c == 3 and window.colors[2]
268 ))
269 end
270 end
271 end
272 end
273 if lddterm.alwaysRender then
274 lddterm.render(lddterm.transformation, lddterm.drawFunction)
275 end
276 end
277 window.handle.write = function(text, x, y, ignoreAlwaysRender)
278 assert(text ~= nil, "expected string 'text'")
279 text = tostring(text)
280 local cx = math.floor(tonumber(x) or window.cursor[1])
281 local cy = math.floor(tonumber(y) or window.cursor[2])
282 text = text:sub(math.max(0, -cx - 1))
283 for i = 1, #text do
284 if cx >= 1 and cx <= window.width and cy >= 1 and cy <= window.height then
285 window.buffer[1][cy][cx] = text:sub(i,i)
286 window.buffer[2][cy][cx] = window.colors[1]
287 window.buffer[3][cy][cx] = window.colors[2]
288 end
289 cx = math.min(cx + 1, window.width + 1)
290 end
291 window.cursor = {cx, cy}
292 if lddterm.alwaysRender and not ignoreAlwaysRender then
293 lddterm.render(lddterm.transformation, lddterm.drawFunction)
294 end
295 end
296 window.handle.writeWrap = function(text, x, y, ignoreAlwaysRender)
297 local words = explode(" ", text, nil, true)
298 local cx, cy = x or window.cursor[1], y or window.cursor[2]
299 for i = 1, #words do
300 if cx + #words[i] > window.width + 1 then
301 cx = 1
302 if cy >= window.height then
303 window.handle.scroll(1)
304 cy = window.height
305 else
306 cy = cy + 1
307 end
308 end
309 window.handle.write(words[i], cx, cy, true)
310 cx = cx + #words[i]
311 end
312 if lddterm.alwaysRender and not ignoreAlwaysRender then
313 lddterm.render(lddterm.transformation, lddterm.drawFunction)
314 end
315 end
316 window.handle.blit = function(char, textCol, backCol, x, y)
317 if type(char) == "number" then
318 char = tostring(char)
319 end
320 if type(textCol) == "number" then
321 textCol = tostring(textCol)
322 end
323 if type(backCol) == "number" then
324 backCol = tostring(backCol)
325 end
326 assert(char ~= nil, "expected string 'char'")
327 local cx = math.floor(tonumber(x) or window.cursor[1])
328 local cy = math.floor(tonumber(y) or window.cursor[2])
329 char = char:sub(math.max(0, -cx - 1))
330 for i = 1, #char do
331 if cx >= 1 and cx <= window.width and cy >= 1 and cy <= window.height then
332 window.buffer[1][cy][cx] = char:sub(i,i)
333 window.buffer[2][cy][cx] = textCol:sub(i,i)
334 window.buffer[3][cy][cx] = backCol:sub(i,i)
335 end
336 cx = cx + 1
337 end
338 window.cursor = {cx, cy}
339 if lddterm.alwaysRender and not ignoreAlwaysRender then
340 lddterm.render(lddterm.transformation, lddterm.drawFunction)
341 end
342 end
343 window.handle.print = function(text, x, y)
344 text = text and tostring(text)
345 window.handle.write(text, x, y, true)
346 window.cursor[1] = 1
347 if window.cursor[2] >= window.height then
348 window.handle.scroll(1)
349 else
350 window.cursor[2] = window.cursor[2] + 1
351 if lddterm.alwaysRender then
352 lddterm.render(lddterm.transformation, lddterm.drawFunction)
353 end
354 end
355 end
356 window.handle.clear = function(char, ignoreAlwaysRender)
357 local cx = 1
358 for y = 1, window.height do
359 for x = 1, window.width do
360 if char then
361 cx = (x % #char) + 1
362 end
363 window.buffer[1][y][x] = char and char:sub(cx, cx) or window.clearChar
364 window.buffer[2][y][x] = window.colors[1]
365 window.buffer[3][y][x] = window.colors[2]
366 end
367 end
368 if lddterm.alwaysRender and not ignoreAlwaysRender then
369 lddterm.render(lddterm.transformation, lddterm.drawFunction)
370 end
371 end
372 window.handle.clearLine = function(cy, char, ignoreAlwaysRender)
373 cy = math.floor(cy or window.cursor[2])
374 local cx = 1
375 for x = 1, window.width do
376 if char then
377 cx = (x % #char) + 1
378 end
379 window.buffer[1][cy or window.cursor[2]][x] = char and char:sub(cx, cx) or window.clearChar
380 window.buffer[2][cy or window.cursor[2]][x] = window.colors[1]
381 window.buffer[3][cy or window.cursor[2]][x] = window.colors[2]
382 end
383 if lddterm.alwaysRender and not ignoreAlwaysRender then
384 lddterm.render(lddterm.transformation, lddterm.drawFunction)
385 end
386 end
387 window.handle.clearColumn = function(cx, char, ignoreAlwaysRender)
388 cx = math.floor(cx)
389 char = char and char:sub(1,1)
390 for y = 1, window.height do
391 window.buffer[1][y][cx or window.cursor[1]] = char and char or window.clearChar
392 window.buffer[2][y][cx or window.cursor[1]] = window.colors[1]
393 window.buffer[3][y][cx or window.cursor[1]] = window.colors[2]
394 end
395 if lddterm.alwaysRender and not ignoreAlwaysRender then
396 lddterm.render(lddterm.transformation, lddterm.drawFunction)
397 end
398 end
399 window.handle.getSize = function()
400 return window.width, window.height
401 end
402 window.handle.isColor = function()
403 return lddterm.useColors
404 end
405 window.handle.isColour = window.handle.isColor
406 window.handle.setTextColor = function(color)
407 if to_blit[color] then
408 window.colors[1] = to_blit[color]
409 end
410 end
411 window.handle.setTextColour = window.handle.setTextColor
412 window.handle.setBackgroundColor = function(color)
413 if to_blit[color] then
414 window.colors[2] = to_blit[color]
415 end
416 end
417 window.handle.setBackgroundColour = window.handle.setBackgroundColor
418 window.handle.getTextColor = function()
419 return to_colors[window.colors[1]] or colors.white
420 end
421 window.handle.getTextColour = window.handle.getTextColor
422 window.handle.getBackgroundColor = function()
423 return to_colors[window.colors[2]] or colors.black
424 end
425 window.handle.getBackgroundColour = window.handle.getBackgroundColor
426 window.handle.reposition = function(x, y)
427 window.x = math.floor(x or window.x)
428 window.y = math.floor(y or window.y)
429 if lddterm.alwaysRender then
430 lddterm.render(lddterm.transformation, lddterm.drawFunction)
431 end
432 end
433 window.handle.setPaletteColor = function(...)
434 return lddterm.baseTerm.setPaletteColor(...)
435 end
436 window.handle.setPaletteColour = window.handle.setPaletteColor
437 window.handle.getPaletteColor = function(...)
438 return lddterm.baseTerm.getPaletteColor(...)
439 end
440 window.handle.getPaletteColour = window.handle.getPaletteColor
441 window.handle.getPosition = function()
442 return window.x, window.y
443 end
444 window.handle.restoreCursor = function()
445 lddterm.baseTerm.setCursorPos(
446 -1 + window.cursor[1] + window.x,
447 window.cursor[2] + window.y - 1
448 )
449 end
450 window.handle.setVisible = function(visible)
451 window.visible = visible or false
452 end
453
454 window.handle.redraw = lddterm.render
455 window.handle.current = window.handle
456
457 window.layer = #lddterm.windows + 1
458 lddterm.windows[window.layer] = window
459
460 return window, window.layer
461end
462
463lddterm.setLayer = function(window, _layer)
464 local layer = math.max(1, math.min(#lddterm.windows, _layer))
465
466 local win = window
467 table.remove(lddterm.windows, win.layer)
468 table.insert(lddterm.windows, layer, win)
469
470 if lddterm.alwaysRender then
471 lddterm.render(lddterm.transformation, lddterm.drawFunction)
472 end
473 return true
474end
475
476-- if the screen changes size, the effect is broken
477local old_scr_x, old_scr_y
478
479-- gets screenshot of whole lddterm desktop, OR a single window
480lddterm.screenshot = function(window)
481 local output = {{},{},{}}
482 local line
483 if window then
484 for y = 1, #window.buffer do
485 line = {"","",""}
486 for x = 1, #window.buffer do
487 line = {
488 line[1] .. window.buffer[1][y][x],
489 line[2] .. window.buffer[2][y][x],
490 line[3] .. window.buffer[3][y][x]
491 }
492 end
493 output[1][y] = line[1]
494 output[2][y] = line[2]
495 output[3][y] = line[3]
496 end
497 else
498 for y = 1, scr_y do
499 line = {"","",""}
500 for x = 1, scr_x do
501
502 c = "."
503 lt, lb = t, b
504 t, b = "0", "f"
505 for l = 1, #lddterm.windows do
506 if lddterm.windows[l].visible then
507 sx = 1 + x - lddterm.windows[l].x
508 sy = 1 + y - lddterm.windows[l].y
509 if lddterm.windows[l].buffer[1][sy] then
510 if lddterm.windows[l].buffer[1][sy][sx] then
511 c = lddterm.windows[l].buffer[1][sy][sx] or c
512 t = lddterm.windows[l].buffer[2][sy][sx] or t
513 b = lddterm.windows[l].buffer[3][sy][sx] or b
514 break
515 end
516 end
517 end
518 end
519 line = {
520 line[1] .. c,
521 line[2] .. t,
522 line[3] .. b
523 }
524 end
525 output[1][y] = line[1]
526 output[2][y] = line[2]
527 output[3][y] = line[3]
528 end
529 end
530 return output
531end
532
533-- load an abbridged NFTE API
534
535local nfte = {}
536
537local tchar = string.char(31) -- for text colors
538local bchar = string.char(30) -- for background colors
539local nchar = string.char(29) -- for differentiating multiple frames in ANFT
540
541local round = function(num)
542 return math.floor(num + 0.5)
543end
544
545local deepCopy
546deepCopy = function(tbl)
547 local output = {}
548 for k,v in pairs(tbl) do
549 if type(v) == "table" then
550 output[k] = deepCopy(v)
551 else
552 output[k] = v
553 end
554 end
555 return output
556end
557
558local function stringWrite(str,pos,ins,exc)
559 str, ins = tostring(str), tostring(ins)
560 local output, fn1, fn2 = str:sub(1,pos-1)..ins..str:sub(pos+#ins)
561 if exc then
562 repeat
563 fn1, fn2 = str:find(exc,fn2 and fn2+1 or 1)
564 if fn1 then
565 output = stringWrite(output,fn1,str:sub(fn1,fn2))
566 end
567 until not fn1
568 end
569 return output
570end
571
572local checkValid = function(image)
573 if type(image) == "table" then
574 if #image == 3 then
575 return (#image[1] == #image[2] and #image[2] == #image[3])
576 end
577 end
578 return false
579end
580
581local checkIfANFT = function(image)
582 if type(image) == "table" then
583 return type(image[1][1]) == "table"
584 elseif type(image) == "string" then
585 return image:find(nchar) and true or false
586 end
587end
588
589-- returns (x, y) size of a loaded NFT image
590nfte.getSize = function(image)
591 assert(checkValid(image), "Invalid image.")
592 local x, y = 0, #image[1]
593 for y = 1, #image[1] do
594 x = math.max(x, #image[1][y])
595 end
596 return x, y
597end
598
599local loadImageDataNFT = function(image, background) -- string image
600 local output = {{},{},{}} -- char, text, back
601 local y = 1
602 background = (background or " "):sub(1,1)
603 local text, back = " ", background
604 local doSkip, c1, c2 = false
605 local maxX = 0
606 local bx
607 for i = 1, #image do
608 if doSkip then
609 doSkip = false
610 else
611 output[1][y] = output[1][y] or ""
612 output[2][y] = output[2][y] or ""
613 output[3][y] = output[3][y] or ""
614 c1, c2 = image:sub(i,i), image:sub(i+1,i+1)
615 if c1 == tchar then
616 text = c2
617 doSkip = true
618 elseif c1 == bchar then
619 back = c2
620 doSkip = true
621 elseif c1 == "\n" then
622 maxX = math.max(maxX, #output[1][y])
623 y = y + 1
624 text, back = " ", background
625 else
626 output[1][y] = output[1][y]..c1
627 output[2][y] = output[2][y]..text
628 output[3][y] = output[3][y]..back
629 end
630 end
631 end
632 for y = 1, #output[1] do
633 output[1][y] = output[1][y] .. (" "):rep(maxX - #output[1][y])
634 output[2][y] = output[2][y] .. (" "):rep(maxX - #output[2][y])
635 output[3][y] = output[3][y] .. (background):rep(maxX - #output[3][y])
636 end
637 return output
638end
639
640local loadImageDataNFP = function(image, background)
641 local output = {}
642 local x, y = 1, 1
643 for i = 1, #image do
644 output[y] = output[y] or {}
645 if bl[image:sub(i,i)] then
646 output[y][x] = bl[image:sub(i,i)]
647 x = x + 1
648 elseif image:sub(i,i) == "\n" then
649 x, y = 1, y + 1
650 end
651 end
652 return output
653end
654
655-- takes a loaded image and returns a loaded NFT image
656nfte.convertFromNFP = function(image, background)
657 background = background or " "
658 local output = {{},{},{}}
659 if type(image) == "string" then
660 image = loadImageDataNFP(image)
661 end
662 local imageX, imageY = getSizeNFP(image)
663 local bx
664 for y = 1, imageY do
665 output[1][y] = ""
666 output[2][y] = ""
667 output[3][y] = ""
668 for x = 1, imageX do
669 if image[y][x] then
670 bx = (x % #background) + 1
671 output[1][y] = output[1][y]..lb[image[y][x] or background:sub(bx,bx)]
672 output[2][y] = output[2][y]..lb[image[y][x] or background:sub(bx,bx)]
673 output[3][y] = output[3][y]..lb[image[y][x] or background:sub(bx,bx)]
674 end
675 end
676 end
677 return output
678end
679
680-- loads the raw string NFT image data
681nfte.loadImageData = function(image, background)
682 assert(type(image) == "string", "NFT image data must be string.")
683 local output = {}
684 -- images can be ANFT, which means they have multiple layers
685 if checkIfANFT(image) then
686 local L, R = 1, 1
687 while L do
688 R = (image:find(nchar, L + 1) or 0)
689 output[#output+1] = loadImageDataNFT(image:sub(L, R - 1), background)
690 L = image:find(nchar, R + 1)
691 if L then L = L + 2 end
692 end
693 return output, "anft"
694 elseif image:find(tchar) or image:find(bchar) then
695 return loadImageDataNFT(image, background), "nft"
696 else
697 return convertFromNFP(image), "nfp"
698 end
699end
700
701-- loads an image file. will convert from NFP if necessary
702nfte.loadImage = function(path, background)
703 local file = io.open(path, "r")
704 if file then
705 io.input(file)
706 local output, format = loadImageData(io.read("*all"), background)
707 io.close()
708 return output, format
709 else
710 error("No such file exists, or is directory.")
711 end
712end
713
714local unloadImageNFT = function(image)
715 assert(checkValid(image), "Invalid image.")
716 local output = ""
717 local text, back = " ", " "
718 local c, t, b
719 for y = 1, #image[1] do
720 for x = 1, #image[1][y] do
721 c, t, b = image[1][y]:sub(x,x), image[2][y]:sub(x,x), image[3][y]:sub(x,x)
722 if (t ~= text) or (x == 1) then
723 output = output..tchar..t
724 text = t
725 end
726 if (b ~= back) or (x == 1) then
727 output = output..bchar..b
728 back = b
729 end
730 output = output..c
731 end
732 if y ~= #image[1] then
733 output = output.."\n"
734 text, back = " ", " "
735 end
736 end
737 return output
738end
739
740-- takes a loaded NFT image and converts it back into regular NFT (or ANFT)
741nfte.unloadImage = function(image)
742 assert(checkValid(image), "Invalid image.")
743 local output = ""
744 if checkIfANFT(image) then
745 for i = 1, #image do
746 output = output .. unloadImageNFT(image[i])
747 if i ~= #image then
748 output = output .. nchar .. "\n"
749 end
750 end
751 else
752 output = unloadImageNFT(image)
753 end
754 return output
755end
756
757-- draws an image with the topleft corner at (x, y)
758nfte.drawImage = function(image, x, y, terminal)
759 assert(checkValid(image), "Invalid image.")
760 assert(type(x) == "number", "x value must be number, got " .. type(x))
761 assert(type(y) == "number", "y value must be number, got " .. type(y))
762 terminal = terminal or term.current()
763 local cx, cy = terminal.getCursorPos()
764 for iy = 1, #image[1] do
765 terminal.setCursorPos(x, y + (iy - 1))
766 terminal.blit(image[1][iy], image[2][iy], image[3][iy])
767 end
768 terminal.setCursorPos(cx,cy)
769end
770
771-- draws an image with the topleft corner at (x, y), with transparency
772nfte.drawImageTransparent = function(image, x, y, terminal)
773 assert(checkValid(image), "Invalid image.")
774 assert(type(x) == "number", "x value must be number, got " .. type(x))
775 assert(type(y) == "number", "y value must be number, got " .. type(y))
776 terminal = terminal or term.current()
777 local cx, cy = terminal.getCursorPos()
778 local c, t, b
779 for iy = 1, #image[1] do
780 for ix = 1, #image[1][iy] do
781 c, t, b = image[1][iy]:sub(ix,ix), image[2][iy]:sub(ix,ix), image[3][iy]:sub(ix,ix)
782 if b ~= " " or c ~= " " then
783 terminal.setCursorPos(x + (ix - 1), y + (iy - 1))
784 terminal.blit(c, t, b)
785 end
786 end
787 end
788 terminal.setCursorPos(cx,cy)
789end
790
791-- draws an image centered at (x, y) or center screen
792nfte.drawImageCenter = function(image, x, y, terminal)
793 terminal = terminal or term.current()
794 local scr_x, scr_y = terminal.getSize()
795 local imageX, imageY = nfte.getSize(image)
796 return nfte.drawImage(
797 image,
798 round(0.5 + (x and x or (scr_x/2)) - imageX/2),
799 round(0.5 + (y and y or (scr_y/2)) - imageY/2),
800 terminal
801 ), round(0.5 + (x and x or (scr_x/2)) - imageX/2), round(0.5 + (y and y or (scr_y/2)) - imageY/2)
802end
803
804-- draws an image centered at (x, y) or center screen, with transparency
805nfte.drawImageCenterTransparent = function(image, x, y, terminal)
806 terminal = terminal or term.current()
807 local scr_x, scr_y = terminal.getSize()
808 local imageX, imageY = getSize(image)
809 return nfte.drawImageTransparent(
810 image,
811 round(0.5 + (x and x or (scr_x/2)) - imageX/2),
812 round(0.5 + (y and y or (scr_y/2)) - imageY/2),
813 terminal
814 )
815end
816
817-- stretches an image so that its new height and width are (sx, sy).
818-- if noRepeat, it will only draw one of each character for each pixel
819-- in the original image, so as to not mess up text in images.
820nfte.stretchImage = function(_image, sx, sy, noRepeat)
821 assert(checkValid(_image), "Invalid image.")
822 local output = {{},{},{}}
823 local image = deepCopy(_image)
824 if sx < 0 then image = flipX(image) end
825 if sy < 0 then image = flipY(image) end
826 sx, sy = math.abs(sx), math.abs(sy)
827 local imageX, imageY = nfte.getSize(image)
828 local tx, ty
829 if sx == 0 or sy == 0 then
830 for y = 1, math.max(sy, 1) do
831 output[1][y] = ""
832 output[2][y] = ""
833 output[3][y] = ""
834 end
835 return output
836 else
837 for y = 1, sy do
838 for x = 1, sx do
839 tx = round((x / sx) * imageX)
840 ty = math.ceil((y / sy) * imageY)
841 if not noRepeat then
842 output[1][y] = (output[1][y] or "")..image[1][ty]:sub(tx,tx)
843 else
844 output[1][y] = (output[1][y] or "").." "
845 end
846 output[2][y] = (output[2][y] or "")..image[2][ty]:sub(tx,tx)
847 output[3][y] = (output[3][y] or "")..image[3][ty]:sub(tx,tx)
848 end
849 end
850 if noRepeat then
851 for y = 1, imageY do
852 for x = 1, imageX do
853 if image[1][y]:sub(x,x) ~= " " then
854 tx = round(((x / imageX) * sx) - ((0.5 / imageX) * sx))
855 ty = round(((y / imageY) * sy) - ((0.5 / imageY) * sx))
856 output[1][ty] = stringWrite(output[1][ty], tx, image[1][y]:sub(x,x))
857 end
858 end
859 end
860 end
861 return output
862 end
863end
864
865local rotatePoint = function(x, y, angle, originX, originY)
866 return
867 round( (x-originX) * math.cos(angle) - (y-originY) * math.sin(angle) ) + originX,
868 round( (x-originX) * math.sin(angle) + (y-originY) * math.cos(angle) ) + originY
869end
870
871-- rotates an image around (originX, originY) or its center, by angle radians
872nfte.rotateImage = function(image, angle, originX, originY)
873 assert(checkValid(image), "Invalid image.")
874 if imageX == 0 or imageY == 0 then
875 return image
876 end
877 local output = {{},{},{}}
878 local realOutput = {{},{},{}}
879 local tx, ty, corners
880 local imageX, imageY = nfte.getSize(image)
881 local originX, originY = originX or math.floor(imageX / 2), originY or math.floor(imageY / 2)
882 corners = {
883 {rotatePoint(1, 1, angle, originX, originY)},
884 {rotatePoint(imageX, 1, angle, originX, originY)},
885 {rotatePoint(1, imageY, angle, originX, originY)},
886 {rotatePoint(imageX, imageY, angle, originX, originY)},
887 }
888 local minX = math.min(corners[1][1], corners[2][1], corners[3][1], corners[4][1])
889 local maxX = math.max(corners[1][1], corners[2][1], corners[3][1], corners[4][1])
890 local minY = math.min(corners[1][2], corners[2][2], corners[3][2], corners[4][2])
891 local maxY = math.max(corners[1][2], corners[2][2], corners[3][2], corners[4][2])
892
893 for y = 1, (maxY - minY) + 1 do
894 output[1][y] = {}
895 output[2][y] = {}
896 output[3][y] = {}
897 for x = 1, (maxX - minX) + 1 do
898 tx, ty = rotatePoint(x + minX - 1, y + minY - 1, -angle, originX, originY)
899 output[1][y][x] = "f"
900 output[2][y][x] = "f"
901 output[3][y][x] = "f"
902 if image[1][ty] then
903 if tx >= 1 and tx <= #image[1][ty] then
904 output[1][y][x] = image[1][ty]:sub(tx,tx)
905 output[2][y][x] = image[2][ty]:sub(tx,tx)
906 output[3][y][x] = image[3][ty]:sub(tx,tx)
907 end
908 end
909 end
910 end
911 for y = 1, #output[1] do
912 output[1][y] = table.concat(output[1][y])
913 output[2][y] = table.concat(output[2][y])
914 output[3][y] = table.concat(output[3][y])
915 end
916 return output, math.ceil(minX), math.ceil(minY)
917end
918
919local tWindow = lddterm.newWindow(scr_x, scr_y, 1, 1)
920tWindow.blink = false
921local tOriginal = term.redirect(tWindow.handle)
922
923local program = tArg[1] or "/rom/programs/shell.lua"
924
925local rendTimer = os.startTimer(0.05)
926table.remove(tArg, 1)
927parallel.waitForAny(function()
928 shell.run(program, table.unpack(tArg))
929end, function()
930 local evt
931 local keysDown = {}
932 while true do
933 evt = {os.pullEvent()}
934 if evt[1] == "timer" and evt[2] == rendTimer then
935 lddterm.render()
936 rendTimer = os.startTimer(0.05)
937 elseif evt[1] == "key" then
938 keysDown[evt[2]] = true
939 if keysDown[keys.leftCtrl] and keysDown[keys.leftShift] and evt[2] == keys.backspace then
940 return
941 end
942 elseif evt[1] == "key_up" then
943 keysDown[evt[2]] = false
944 end
945 end
946end)
947
948term.setCursorBlink(false)
949
950local fullScreenshot = lddterm.screenshot()
951local screenshot
952local screenshot_X, screenshot_Y = nfte.getSize(fullScreenshot)
953
954term.setBackgroundColor(colors.black)
955
956for i = screenshot_X, math.floor(math.sqrt(scr_x * 3)), -2 do
957 screenshot = nfte.stretchImage(fullScreenshot, i, i / (screenshot_X / screenshot_Y))
958 term.clear()
959 nfte.drawImageCenter(screenshot)
960 lddterm.render()
961 sleep(0.05)
962end
963
964local handX, handY = scr_x + 4, -5
965for x = handX, math.floor(scr_x / 2) + 1, -2 do
966 term.clear()
967 nfte.drawImageCenter(screenshot)
968 nfte.drawImageTransparent(images.handOpen, handX, handY)
969 lddterm.render()
970 sleep(0.05)
971 handX = handX - 2.0
972 handY = handY + (scr_y / scr_x) * 2
973end
974
975handX, handY = math.floor(handX), math.floor(handY)
976local anchorX, anchorY = handX, handY
977local scrollX, scrollY = 0, 0
978
979term.clear()
980local _, imageX, imageY = nfte.drawImageCenter(screenshot)
981nfte.drawImageTransparent(images.handClosed, handX, handY)
982lddterm.render()
983sleep(0.5)
984
985for i = 1, 10 do
986 handX = handX + 0.5
987 handY = handY + 0.4
988 term.clear()
989 nfte.drawImage(screenshot, imageX + (handX - anchorX), imageY + (handY - anchorY))
990 nfte.drawImageTransparent(images.handClosed, handX, handY)
991 lddterm.render()
992 sleep(0.05)
993end
994
995sleep(0.4)
996
997for i = 1, 10 do
998 handX = handX - (0.6 + (i / 8))
999 handY = handY - (0.1 + (i / 12))
1000 if i >= 2 then
1001 scrollX = scrollX + 1
1002 end
1003 term.clear()
1004 nfte.drawImage(screenshot, scrollX + imageX + (handX - anchorX), scrollY + imageY + (handY - anchorY))
1005 nfte.drawImageTransparent(images.handClosed, scrollX + handX, scrollY + handY)
1006 lddterm.render()
1007 sleep(0.05)
1008end
1009local imageYvel = -0.9
1010local imageRotate = 0
1011imageX = imageX + (handX - anchorX)
1012imageY = imageY + (handY - anchorY)
1013
1014local rImage, rX, rY
1015
1016for i = 1, 41 do
1017 if i <= 5 then
1018 handX = handX - 1
1019 handY = handY - 0.8
1020 end
1021 term.clear()
1022 rImage, rX, rY = nfte.rotateImage(screenshot, imageRotate)
1023 nfte.drawImage(rImage, scrollX + imageX, scrollY + imageY)
1024 nfte.drawImageTransparent(images.handOpen, scrollX + handX, scrollY + handY)
1025 nfte.drawImageTransparent(images.trashCan, (scr_x / 2) - (177 - scrollX), scrollY + 32 + (scr_y - 19) / 2 + (scr_x - 51) / 10)
1026 lddterm.render()
1027
1028 sleep(0.05)
1029
1030 imageRotate = imageRotate + 0.12
1031 scrollX = scrollX + 4
1032 if i < 20 then
1033 scrollY = scrollY - 0.25
1034 else
1035 scrollY = scrollY - 0.8
1036 end
1037 imageX = imageX - 4
1038 imageY = imageY + imageYvel
1039
1040 imageYvel = imageYvel + 0.07
1041end
1042
1043sleep(0.5)
1044
1045local scene = lddterm.screenshot()
1046
1047for i = 1, 6 do
1048 nfte.drawImage(scene, 1, 1)
1049 nfte.drawImageTransparent(images.trashLid, (scr_x / 2) - (179 - scrollX), ((scr_y - 19) / 4) + i - 3)
1050 lddterm.render()
1051 sleep(0.05)
1052end
1053
1054local lidAngle, rotLid = 0
1055
1056for i = 1, 10 do
1057 lidAngle = lidAngle + 0.0371
1058 rotLid = nfte.rotateImage(images.trashLid, lidAngle)
1059 nfte.drawImage(scene, 1, 1)
1060 nfte.drawImageTransparent(rotLid, (scr_x / 2) - (179 - scrollX), 1 + ((scr_y - 19) / 4))
1061 lddterm.render()
1062 sleep(0.05)
1063end
1064
1065sleep(0.5)
1066
1067term.redirect(tOriginal)
1068term.setCursorPos(1, scr_y)
1069