Advertisement
BombBloke

Slide (RandomPeripherals)

Sep 26th, 2015
417
0
Never
Not a member of Pastebin yet? Sign Up, it unlocks many cool features!
Lua 27.59 KB | None | 0 0
  1. -- +--------------------------------------------------------+
  2. -- |                                                        |
  3. -- |                          Slide                         |
  4. -- |                                                        |
  5. -- +--------------------------------------------------------+
  6.  
  7. local version = "Version 1.0.0"
  8.  
  9. -- By Jeffrey Alexander, aka Bomb Bloke.
  10. -- A slide puzzle for the RandomPeripheral's Hologram Projector.
  11. -- http://www.computercraft.info/forums2/index.php?/topic/24764-slide-puzzle-randomperipherals/
  12. -- http://www.computercraft.info/forums2/index.php?/topic/20785-mc-1710cc-174-randomperipherals-read-nbt-data-from-every-item-and-more/
  13.  
  14. ---------------------------------------------
  15. ------------Variable Declarations------------
  16. ---------------------------------------------
  17.  
  18. if not fs.exists(shell.resolve("holo.pal")) then shell.run("pastebin get zszAghrq holo.pal") end
  19.  
  20. if not package then
  21.     if not (fs.exists("package") or fs.exists(shell.resolve("package"))) then
  22.         shell.run("pastebin get cUYTGbpb package")
  23.         os.loadAPI(shell.resolve("package"))
  24.     else os.loadAPI(fs.exists("package") and "package" or shell.resolve("package")) end
  25. end
  26.  
  27. if not GIF then
  28.     if not (fs.exists("GIF") or fs.exists(shell.resolve("GIF"))) then
  29.         shell.run("pastebin get 5uk9uRjC GIF")
  30.         os.loadAPI(shell.resolve("GIF"))
  31.     else os.loadAPI(fs.exists("GIF") and "GIF" or shell.resolve("GIF")) end
  32. end
  33.  
  34. local xSize, ySize, rotate, sideLengthX, sideLengthY, emptyTile, image, myEvent, tileWidth, tileHeight
  35. local tilesPerSide, tiles, pal, holo, grid, correct, redraw, blackText, scale, stretch, center = 4, 15, {}, {}, {}, 0, true, _CC_VERSION and colours.grey or colours.black, 0, 1, 2
  36. local cursor = {{">>  ","  <<"},{"> > "," < <"},{" >> "," << "},{"> > "," < <"}}
  37. local arrow = {{1,1,1,1,1,1,1,1},{1,2,2,3,2,2,2,1},{1,2,3,3,3,2,2,1},{1,3,2,3,2,3,2,1},{1,2,2,3,2,2,2,1},{1,2,2,3,2,2,2,1},{1,2,2,3,2,2,2,1},{1,1,1,1,1,1,1,1}}
  38. local alterOption = {function(x, y) return x, y - 1 end, function(x, y) return x, y + 1 end, function(x, y) return x - 1, y end, function(x, y) return x + 1, y end}
  39. local rotateOption = {function(x, y) return x, y end, function(x, y) return 7 - y, x end, function(x, y) return 7 - x, 7 - y end, function(x, y) return y, 7 - x end}
  40.  
  41. ---------------------------------------------
  42. ------------    Misc Functions   ------------
  43. ---------------------------------------------
  44.  
  45. local function clear(textCol, backCol)
  46.     if textCol then term.setTextColour(textCol) end
  47.     if backCol then term.setBackgroundColour(backCol) end
  48.     for i = 4, ySize - 3 do
  49.         term.setCursorPos(1, i)
  50.         term.clearLine()
  51.     end
  52. end
  53.  
  54. -- Returns whether a click was performed at a given location.
  55. -- If one parameter is passed, it checks to see if y is [1].
  56. -- If two parameters are passed, it checks to see if x is [1] and y is [2].
  57. -- If three parameters are passed, it checks to see if x is between [1]/[2] (non-inclusive) and y is [3].
  58. -- If four paramaters are passed, it checks to see if x is between [1]/[2] and y is between [3]/[4] (non-inclusive).
  59. local function clickedAt(...)
  60.     if myEvent[1] ~= "mouse_click" then return false end
  61.     if #arg == 1 then return (arg[1] == myEvent[4])
  62.     elseif #arg == 2 then return (myEvent[3] == arg[1] and myEvent[4] == arg[2])
  63.     elseif #arg == 3 then return (myEvent[3] > arg[1] and myEvent[3] < arg[2] and myEvent[4] == arg[3])
  64.     else return (myEvent[3] > arg[1] and myEvent[3] < arg[2] and myEvent[4] > arg[3] and myEvent[4] < arg[4]) end
  65. end
  66.  
  67. -- Returns whether one of a given set of keys was pressed.
  68. local function pressedKey(...)
  69.     if myEvent[1] ~= "key" then return false end
  70.     for i=1,#arg do if arg[i] == myEvent[2] then return true end end
  71.     return false
  72. end
  73.  
  74. local function writeAt(text, x, y, tCol, bCol)
  75.     if not (x and y) then
  76.         local curX, curY = term.getCursorPos()
  77.         x, y = x or curX, y or curY
  78.     end
  79.    
  80.     term.setCursorPos(x, y)
  81.     if tCol then term.setTextColour(tCol) end
  82.     if bCol then term.setBackgroundColour(bCol) end
  83.     term.write(text)
  84. end
  85.  
  86. local function loadImage(loadThis, resizeMode)
  87.     local GIFImage = GIF.loadGIF(loadThis, shell.resolve("holo.pal"))
  88.     if GIFImage.width ~= sideLengthX or GIFImage.height ~= sideLengthY then
  89.         for i = 2, #GIFImage do GIFImage[i] = nil end
  90.        
  91.         if resizeMode == scale then
  92.             if sideLengthX < math.floor(sideLengthY / GIFImage.height * GIFImage.width) then
  93.                 GIFImage = GIF.resizeGIF(GIFImage, sideLengthX)
  94.             else
  95.                 GIFImage = GIF.resizeGIF(GIFImage, nil, sideLengthY)
  96.             end
  97.         elseif resizeMode == stretch then
  98.             GIFImage = GIF.resizeGIF(GIFImage, sideLengthX, sideLengthY)
  99.         end
  100.     end
  101.    
  102.     image = {}
  103.     for y = 1, GIFImage.height do
  104.         image[y] = {}
  105.         for x = 1, GIFImage.width do image[y][x] = 0 end
  106.     end
  107.    
  108.     pal = {}
  109.     for i = 1, #GIFImage.pal do pal[i] = {GIFImage.pal[i][4], GIFImage.pal[i][5] or 0} end
  110.    
  111.     GIFImage = GIFImage[1]
  112.  
  113.     for y = 1, GIFImage.yend do
  114.         local x, GIFImageY, imageY = GIFImage.xstart + 1, GIFImage[y], image[y + GIFImage.ystart]
  115.         for i = 1, #GIFImageY do
  116.             local GIFImageYI = GIFImageY[i]
  117.             if type(GIFImageYI) == "number" then
  118.                 x = x + GIFImageYI
  119.             else
  120.                 for pixel = 1, #GIFImageYI do imageY[x + pixel - 1] = GIFImageYI[pixel] end
  121.                 x = x + #GIFImageYI
  122.             end
  123.         end
  124.     end
  125.    
  126.     if resizeMode == center and (#image[1] > sideLengthX or #image > sideLengthY) then
  127.         local xbump, ybump, newImage = math.max(math.floor((#image[1] - sideLengthX) / 2), 0), math.max(math.floor((#image - sideLengthY) / 2), 0), {}
  128.        
  129.         for y = 1, math.min(#image, sideLengthY) do
  130.             local newRow, oldRow = {}, image[y + ybump]
  131.             for x = 1, math.min(#image[1], sideLengthX) do newRow[x] = oldRow[x + xbump] end
  132.             newImage[y] = newRow
  133.         end
  134.        
  135.         image = newImage
  136.     end
  137. end
  138.  
  139. ---------------------------------------------
  140. ------------    GUI Functions    ------------
  141. ---------------------------------------------
  142.  
  143. local function fileBrowser()
  144.     local bump = math.floor((xSize - 49) / 2) + 1
  145.  
  146.     while true do
  147.         local displayList, lastPosition, animationTimer, curCount, gapTimer, lastProgress, position = {}, 0, os.startTimer(0), 1
  148.         if #shell.resolve(".") > 0 then displayList[1] = ".." end
  149.  
  150.         do
  151.             local fullList = fs.list(shell.resolve("."))
  152.             table.sort(fullList, function (a, b) return string.lower(a) < string.lower(b) end)
  153.             for i = 1, #fullList do if fs.isDir(shell.resolve(fullList[i])) then displayList[#displayList + 1] = fullList[i] end end
  154.             position = #displayList + 1
  155.             for i = 1, #fullList do if fullList[i]:sub(#fullList[i] - 3):lower() == ".gif" then displayList[#displayList + 1] = fs.getName(fullList[i]) end end
  156.             if position > #displayList then position = 1 end
  157.         end
  158.  
  159.         while true do
  160.             myEvent = {os.pullEvent()}
  161.  
  162.             -- Track animations (bouncing cursor + scrolling marquee).
  163.             if myEvent[1] == "timer" and myEvent[2] == animationTimer then
  164.                 curCount = curCount == 4 and 1 or (curCount + 1)
  165.                 animationTimer = os.startTimer(0.5)
  166.                 myEvent[1] = "cabbage"
  167.  
  168.             -- Bail.
  169.             elseif pressedKey(keys.backspace, keys.q, keys.x) or (myEvent[1] == "mouse_click" and myEvent[2] == 2) then
  170.                 return nil
  171.  
  172.             -- Move down the list.
  173.             elseif pressedKey(keys.down, keys.s) or (myEvent[1] == "mouse_scroll" and myEvent[2] == 1) then
  174.                 position = position == #displayList and 1 or (position + 1)
  175.  
  176.             -- Move up the list.
  177.             elseif pressedKey(keys.up, keys.w) or (myEvent[1] == "mouse_scroll" and myEvent[2] == -1) then
  178.                 position = position == 1 and #displayList or (position - 1)
  179.  
  180.             -- Select something.
  181.             elseif pressedKey(keys.enter, keys.space) or clickedAt(math.floor(ySize / 2) + 1) then
  182.                 if fs.isDir(shell.resolve(displayList[position])) then
  183.                     shell.setDir(shell.resolve(displayList[position]))
  184.                     break
  185.                 else return shell.resolve(displayList[position]) end
  186.            
  187.             -- User clicked somewhere on the file list; move that entry to the currently-selected position.
  188.             elseif clickedAt(0, xSize + 1, 3, ySize - 2) then
  189.                 position = position + myEvent[4] - math.floor(ySize / 2) - 1
  190.                 position = position > #displayList and #displayList or position
  191.                 position = position < 1 and 1 or position
  192.             end
  193.  
  194.             -- Update other screen stuff.
  195.             if myEvent[1] ~= "timer" then
  196.                 -- File list.
  197.                 term.setBackgroundColour(colours.black)
  198.                 for y = position == lastPosition and (math.floor(ySize / 2) + 1) or 4, position == lastPosition and (math.floor(ySize / 2) + 1) or (ySize - 3) do
  199.                     local thisLine = y + position - math.floor(ySize / 2) - 1
  200.  
  201.                     if displayList[thisLine] then
  202.                         local thisString = displayList[thisLine]
  203.                         thisString = fs.isDir(shell.resolve(thisString)) and "["..thisString.."]" or thisString:sub(1, #thisString-4)
  204.  
  205.                         if thisLine == position then
  206.                             term.setCursorPos(math.floor((xSize - #thisString - 8) / 2) + 1, y)
  207.                             term.clearLine()
  208.                             term.setTextColour(colours.red)
  209.                             term.write(cursor[curCount][1])
  210.                             term.setTextColour(colours.orange)
  211.                             term.write(thisString)
  212.                             term.setTextColour(colours.red)
  213.                             term.write(cursor[curCount][2])
  214.                         else
  215.                             term.setCursorPos(math.floor((xSize - #thisString) / 2) + 1, y)
  216.                             term.clearLine()
  217.  
  218.                             if y == 4 or y == ySize - 3 then term.setTextColour(blackText)
  219.                             elseif y == 5 or y == ySize - 4 then term.setTextColour(colours.grey)
  220.                             elseif y == 6 or y == ySize - 5 then term.setTextColour(colours.lightGrey)
  221.                             else term.setTextColour(colours.white) end
  222.  
  223.                             term.write(thisString)
  224.                         end
  225.                     else
  226.                         term.setCursorPos(1, y)
  227.                         term.clearLine()
  228.                     end
  229.                 end
  230.  
  231.                 lastPosition = position
  232.             end
  233.         end
  234.     end
  235. end
  236.  
  237. ---------------------------------------------
  238. ------------   Hologram Control  ------------
  239. ---------------------------------------------
  240.  
  241. local function clearHolo()
  242.     for row = 1, #holo do for col = 1, #holo[row] do
  243.         holo[row][col].setVelocity(0)
  244.         holo[row][col].setRotation(0)
  245.         holo[row][col].clear("minecraft:air", 0)
  246.     end end
  247. end
  248.  
  249. local function pset(x, y, col)
  250.     x, y = x - 1, y - 1
  251.     local subX, subY = rotate(bit.band(x, 7), bit.band(y, 7))
  252.     if col == 0 then
  253.         holo[bit.brshift(bit.band(y, 16777208), 3) + 1][bit.brshift(bit.band(x, 16777208), 3) + 1].setBlock(subX, 0, subY, "minecraft:air")
  254.     else
  255.         holo[bit.brshift(bit.band(y, 16777208), 3) + 1][bit.brshift(bit.band(x, 16777208), 3) + 1].setBlockMeta(subX, 0, subY, pal[col][1], pal[col][2])
  256.     end
  257. end
  258.  
  259. local function drawTile(x, y, bumpx, bumpy)
  260.     local tile = grid[y][x]
  261.     if not tile then return end
  262.     xbump, ybump = (x - 1) * tileWidth, (y - 1) * tileHeight
  263.    
  264.     if bumpx and bumpy then
  265.         if bumpx < 0 then for i = 1, tileHeight do pset(tileWidth + xbump + bumpx + 1, i + ybump + bumpy, 0) end
  266.         elseif bumpx > 0 then for i = 1, tileHeight do pset(xbump + bumpx, i + ybump + bumpy, 0) end
  267.         elseif bumpy < 0 then for i = 1, tileWidth do pset(i + xbump + bumpx, tileHeight + ybump + bumpy + 1, 0) end
  268.         elseif bumpy > 0 then for i = 1, tileWidth do pset(i + xbump + bumpx, ybump + bumpy, 0) end end
  269.     else bumpx, bumpy = 0, 0 end
  270.    
  271.     for y = 1, tileHeight do for x = 1, tileWidth do pset(x + xbump + bumpx, y + ybump + bumpy, tile[y][x]) end end
  272. end
  273.  
  274. local function displayImage()
  275.     local xbump, ybump = math.floor((sideLengthX - #image[1]) / 2), math.floor((sideLengthY - #image) / 2)
  276.     for y = 1, #image do for x = 1, #image[1] do pset(x + xbump, y + ybump, image[y][x]) end end
  277. end
  278.  
  279. ---------------------------------------------
  280. ------------      Game Funcs     ------------
  281. ---------------------------------------------
  282.  
  283. local function displayTimer()
  284.     local h, m, s = 0, 0, 0
  285.    
  286.     while true do
  287.         writeAt((h < 10 and "0" or "") .. tostring(h) .. ":" .. (m < 10 and "0" or "") .. tostring(m) .. ":" .. (s < 10 and "0" or "") .. tostring(s), 18, 9, colours.blue)
  288.        
  289.         s = s + 1
  290.         if s > 59 then
  291.             s = 0
  292.             m = m + 1
  293.             if m > 59 then
  294.                 m = 0
  295.                 h = h + 1
  296.             end
  297.         end
  298.        
  299.         sleep(1)
  300.     end
  301. end
  302.  
  303. local function doHint()
  304.     writeAt("Displaying hint!", 6, 6, colours.black)
  305.     displayImage()
  306.     sleep(5)
  307.     clearHolo()
  308.     for y = 1, tilesPerSide do for x = 1, tilesPerSide do drawTile(x, y) end end
  309.     writeAt("Game in progress", 6, 6, colours.black)
  310. end
  311.  
  312. local function puzzleLoop()
  313.     local hints, moves = 0, 0
  314.     writeAt(tostring(hints), 18, 11, colours.blue)
  315.     writeAt(tostring(moves), 18, 13)
  316.    
  317.     while correct ~= tiles do
  318.         myEvent = {os.pullEvent()}
  319.  
  320.         if myEvent[1] == "hologramTouch" then
  321.             myEvent[3], myEvent[5] = rotate(myEvent[3], myEvent[5])
  322.            
  323.             local touchx, touchy, alter = math.floor((myEvent[3] + holo[myEvent[7]][1] - 1) / tileWidth) + 1, math.floor((myEvent[5] + holo[myEvent[7]][2] - 1) / tileHeight) + 1
  324.  
  325.             if touchx == emptyTile.x and touchy == emptyTile.y + 1 then alter = alterOption[1]
  326.             elseif touchx == emptyTile.x and touchy == emptyTile.y - 1 then alter = alterOption[2]
  327.             elseif touchx == emptyTile.x + 1 and touchy == emptyTile.y then alter = alterOption[3]
  328.             elseif touchx == emptyTile.x - 1 and touchy == emptyTile.y then alter = alterOption[4] end
  329.  
  330.             if alter then
  331.                 moves = moves + 1
  332.                 writeAt(tostring(moves), 18, 13, colours.blue)
  333.                
  334.                 local tempx, tempy = 0, 0
  335.  
  336.                 for i = 1, touchx == emptyTile.x and tileHeight or tileWidth do
  337.                     tempx, tempy = alter(tempx, tempy)
  338.                     drawTile(touchx, touchy, tempx, tempy)
  339.                     sleep(0.05)
  340.                 end
  341.  
  342.                 tempx, tempy = touchx, touchy
  343.                 touchx, touchy = alter(touchx, touchy)
  344.                 grid[touchy][touchx] = grid[tempy][tempx]
  345.                 if grid[tempy][tempx].x == tempx and grid[tempy][tempx].y == tempy then correct = correct - 1 end
  346.                 if grid[touchy][touchx].x == touchx and grid[touchy][touchx].y == touchy then correct = correct + 1 end
  347.                 grid[tempy][tempx], emptyTile = nil, {["x"] = tempx, ["y"] = tempy}
  348.             end
  349.         elseif pressedKey(keys.h) or clickedAt(37, 48, 8) then
  350.             hints = hints + 1
  351.             writeAt(tostring(hints), 18, 11, colours.blue)
  352.             doHint()
  353.         elseif pressedKey(keys.x, keys.q) or clickedAt(39, 45, 13) then
  354.             return
  355.         end
  356.     end
  357. end
  358.  
  359. local function doPuzzle()
  360.     local getImage = fileBrowser()
  361.     if not getImage then return end
  362.    
  363.     clear(colours.black, colours.lightGrey)
  364.     writeAt("Loading image...", 6, 6)
  365.    
  366.     loadImage(getImage, stretch)
  367.    
  368.     local line = {}
  369.     for i = 1, tileWidth do line[i] = bit.band(i, 1) == 1 and 8 or 9 end
  370.    
  371.     for gridy = 1, tilesPerSide do
  372.         local ybump = (gridy - 1) * tileHeight
  373.         grid[gridy] = {}
  374.         for gridx = 1, tilesPerSide do
  375.             grid[gridy][gridx] = {["x"] = gridx, ["y"] = gridy}
  376.             local xbump = (gridx - 1) * tileWidth
  377.             for y = 1, tileHeight - 1 do
  378.                 grid[gridy][gridx][y] = {}
  379.                 for x = 1, tileWidth - 1 do grid[gridy][gridx][y][x] = image[ybump + y][xbump + x] end
  380.                 grid[gridy][gridx][y][tileWidth] = bit.band(y, 1) == 1 and 8 or 9
  381.             end
  382.             grid[gridy][gridx][tileHeight] = line
  383.         end
  384.     end
  385.  
  386.     local eX, eY = tilesPerSide, tilesPerSide
  387.     grid[eX][eY] = nil
  388.    
  389.     for i = 1, 1000 do
  390.         local cX, cY
  391.         repeat cX, cY = alterOption[math.random(4)](eX, eY) until cX > 0 and cY > 0 and cX <= tilesPerSide and cY <= tilesPerSide
  392.         grid[eY][eX] = grid[cY][cX]
  393.         grid[cY][cX] = nil
  394.         eX, eY = cX, cY
  395.     end
  396.  
  397.     for y = 1, tilesPerSide do for x = 1, tilesPerSide do if x ~= eX and y ~= eY and grid[y][x].x == x and grid[y][x].y == y then correct = correct + 1 end end end
  398.    
  399.     emptyTile = {["x"] = eX, ["y"] = eY}
  400.    
  401.     doHint()
  402.     writeAt("Time spent:", 6, 9, colours.grey)
  403.     writeAt("Hints used:", 6, 11)
  404.     writeAt("Moves used:", 6, 13)
  405.    
  406.  
  407.     writeAt(" Use Hint ", 38, 8, colours.lightGrey, colours.grey)
  408.     writeAt(" Exit ", 40, 13)
  409.     term.setBackgroundColour(colours.lightGrey)
  410.    
  411.     parallel.waitForAny(displayTimer, puzzleLoop)
  412.    
  413.     if correct == tiles then
  414.         writeAt("Puzzle complete!", 6, 6, colours.black)
  415.         writeAt("Press any key to continue...", 6, 15)
  416.         displayImage()
  417.         repeat local myEvent = os.pullEvent() until myEvent == "key" or myEvent == "mouse_click"
  418.     else clearHolo() end
  419. end
  420.  
  421.  
  422. ---------------------------------------------
  423. ------------     Viewer Funcs    ------------
  424. ---------------------------------------------
  425.  
  426. local function showImage()
  427.     local myEvent, par1, par2, imgName
  428.    
  429.     while true do
  430.         repeat myEvent, par1, par2 = os.pullEvent() until myEvent == "getImage" or myEvent == "showImage"
  431.        
  432.         if myEvent == "getImage" then
  433.             imgName = fs.getName(par1)
  434.             loadImage(par1, par2)
  435.             os.queueEvent("loaded")
  436.         else
  437.             clearHolo()
  438.             displayImage()
  439.             image = nil
  440.             term.setCursorPos(1, 7)
  441.             term.setBackgroundColour(colours.lightGrey)
  442.             term.clearLine()
  443.             writeAt(imgName, math.floor((51 - #imgName) / 2) + 1, 7, colours.blue)
  444.         end
  445.     end
  446. end
  447.  
  448. local function getIndex(thisVal, thisTable)
  449.     for i = 1, #thisTable do if thisTable[i] == thisVal then return i end end
  450. end
  451.  
  452. local function viewerLoop()
  453.     local loaded, reveal, fileList, myTimer = false, true, {}
  454.     local getImage, resizeMode, play, shuffle = fileBrowser(), scale, false, false
  455.     if not getImage then return end
  456.    
  457.     do
  458.         local fullList = fs.list(shell.resolve("."))
  459.         for i = 1, #fullList do if fullList[i]:sub(#fullList[i] - 3):lower() == ".gif" then fileList[#fileList + 1] = shell.resolve(fullList[i]) end end
  460.         table.sort(fileList, function (a, b) return string.lower(a) < string.lower(b) end)
  461.     end
  462.    
  463.     clearHolo()
  464.     clear(colours.black, colours.lightGrey)
  465.     writeAt("Image Viewer", 20, 5)
  466.     writeAt("Sizing:", 6, 9, colours.grey)
  467.     writeAt("Slideshow:", 6, 11)
  468.     writeAt("Ordering:", 6, 13)
  469.     writeAt(" Scale ", 17, 9, colours.lightGrey, colours.blue)
  470.     writeAt(" Pause ", 19, 11)
  471.     writeAt(" Sequence ", 17, 13)
  472.     writeAt(" Stretch ", 26, 9, colours.lightGrey, colours.grey)
  473.     writeAt(" Center ", 37, 9)
  474.     writeAt(" Play ", 34, 11)
  475.     writeAt(" Random ", 33, 13)
  476.     writeAt(" Exit ", 23, 15)
  477.    
  478.     os.queueEvent("getImage", getImage, resizeMode)
  479.     local curIndex = getIndex(getImage, fileList)
  480.    
  481.     while true do
  482.         myEvent = {os.pullEvent()}
  483.        
  484.         if myEvent[1] == "loaded" then
  485.             loaded = true
  486.         elseif myEvent[1] == "hologramTouch" or (myEvent[1] == "timer" and myEvent[2] == myTimer) then
  487.             if play then reveal = true end
  488.         elseif clickedAt(16, 24, 9) then
  489.             writeAt(" Scale ", 17, 9, colours.lightGrey, colours.blue)
  490.             writeAt(" Stretch ", 26, 9, colours.lightGrey, colours.grey)
  491.             writeAt(" Center ", 37, 9)
  492.             resizeMode = scale
  493.             os.queueEvent("getImage", getImage, resizeMode)
  494.             reveal = true
  495.         elseif clickedAt(25, 35, 9) then
  496.             writeAt(" Stretch ", 26, 9, colours.lightGrey, colours.blue)
  497.             writeAt(" Scale ", 17, 9, colours.lightGrey, colours.grey)
  498.             writeAt(" Center ", 37, 9)
  499.             resizeMode = stretch
  500.             os.queueEvent("getImage", getImage, resizeMode)
  501.             reveal = true
  502.         elseif clickedAt(36, 45, 9) then
  503.             writeAt(" Center ", 37, 9, colours.lightGrey, colours.blue)
  504.             writeAt(" Stretch ", 26, 9, colours.lightGrey, colours.grey)
  505.             writeAt(" Scale ", 17, 9)
  506.             resizeMode = center
  507.             os.queueEvent("getImage", getImage, resizeMode)
  508.             reveal = true
  509.         elseif clickedAt(18, 26, 11) then
  510.             writeAt(" Pause ", 19, 11, colours.lightGrey, colours.blue)
  511.             writeAt(" Play ", 34, 11, colours.lightGrey, colours.grey)
  512.             play = false
  513.         elseif clickedAt(33, 40, 11) then
  514.             writeAt(" Pause ", 19, 11, colours.lightGrey, colours.grey)
  515.             writeAt(" Play ", 34, 11, colours.lightGrey, colours.blue)
  516.             play = true
  517.             curIndex = shuffle and math.random(#fileList) or (curIndex == #fileList and 1 or curIndex + 1)
  518.             getImage = fileList[curIndex]
  519.             os.queueEvent("getImage", getImage, resizeMode)
  520.             myTimer = os.startTimer(10)
  521.         elseif clickedAt(16, 27, 13) then
  522.             writeAt(" Sequence ", 17, 13, colours.lightGrey, colours.blue)
  523.             writeAt(" Random ", 33, 13, colours.lightGrey, colours.grey)
  524.             shuffle = false
  525.         elseif clickedAt(32, 41, 13) then
  526.             writeAt(" Sequence ", 17, 13, colours.lightGrey, colours.grey)
  527.             writeAt(" Random ", 33, 13, colours.lightGrey, colours.blue)
  528.             shuffle = true
  529.         elseif pressedKey(keys.x, keys.q) or clickedAt(22, 29, 15) then
  530.             return
  531.         end
  532.        
  533.         if loaded and reveal then
  534.             loaded, reveal = false, false
  535.             os.queueEvent("showImage")
  536.             if play then
  537.                 curIndex = shuffle and math.random(#fileList) or (curIndex == #fileList and 1 or curIndex + 1)
  538.                 getImage = fileList[curIndex]
  539.                 os.queueEvent("getImage", getImage, resizeMode)
  540.                 myTimer = os.startTimer(10)
  541.             end
  542.         end
  543.     end
  544. end
  545.  
  546. ---------------------------------------------
  547. ------------     Config Funcs    ------------
  548. ---------------------------------------------
  549.  
  550. local function drawArrows()
  551.     for i = 1, #holo[1] do for y = 1, 8 do for x = 1, 8 do pset(x + (i - 1) * 8, y, arrow[y][x]) end end end
  552. end
  553.  
  554. local function doConfig()
  555.     clear(colours.black, colours.lightGrey)
  556.     writeAt("Calibration", 21, 6)
  557.    
  558.     local oldHolo = holo
  559.     holo = {{peripheral.find("hologram_projector", function(name, object) object.side = name return true end)}}
  560.    
  561.     if #holo[1] == 0 then error("Slide requires access to hologram projectors, from RandomPeripherals.") end
  562.    
  563.     clearHolo()
  564.    
  565.     writeAt(" Rotate ", 19, 12, colours.lightGrey, colours.grey)
  566.     writeAt(" Ok ", 29, 12)
  567.     if fs.exists(shell.resolve("slide.cfg")) then writeAt(" Cancel ", 22, 15, colours.lightGrey, colours.grey) end
  568.     writeAt("Align the arrows to point \"upwards\":", 8, 10, colours.grey, colours.lightGrey)
  569.    
  570.     local curRotate, oldRotate = 1, rotate
  571.     rotate = rotateOption[curRotate]
  572.     pal = {{"minecraft:stained_hardened_clay", 11}, {"minecraft:stained_hardened_clay", 3},  {"minecraft:stained_hardened_clay", 14}}
  573.     drawArrows()
  574.  
  575.     repeat
  576.         myEvent = {os.pullEvent("mouse_click")}
  577.        
  578.         if clickedAt(18, 27, 12) then
  579.             curRotate = curRotate == 4 and 1 or (curRotate + 1)
  580.             rotate = rotateOption[curRotate]
  581.             drawArrows()
  582.             rotate = oldRotate
  583.         elseif clickedAt(21, 30, 15) and fs.exists(shell.resolve("slide.cfg")) then
  584.             clearHolo()
  585.             holo = oldHolo
  586.             return
  587.         end
  588.     until clickedAt(28, 33, 12)
  589.    
  590.     term.setCursorPos(1, 10)
  591.     term.clearLine()
  592.     term.setCursorPos(1, 12)
  593.     term.clearLine()
  594.    
  595.     local rowLength = math.ceil(math.sqrt(#holo[1]))
  596.    
  597.     writeAt(" < ", 18, 12, colours.lightGrey, colours.grey)
  598.     writeAt(" > ", 26, 12)
  599.     writeAt(" Ok ", 31, 12)
  600.     writeAt("How many projectors per row?", 12, 10, colours.grey, colours.lightGrey)
  601.     local thisString = tostring(rowLength)
  602.     writeAt(thisString, 22 + math.floor((4 - #thisString) / 2), 12, colours.blue)
  603.    
  604.     repeat
  605.         myEvent = {os.pullEvent("mouse_click")}
  606.        
  607.         if clickedAt(17, 21, 12) then
  608.             rowLength = rowLength == 1 and #holo[1] or (rowLength - 1)
  609.         elseif clickedAt(25, 29, 12) then
  610.             rowLength = rowLength == #holo[1] and 1 or (rowLength + 1)
  611.         elseif clickedAt(21, 30, 15) and fs.exists(shell.resolve("slide.cfg")) then
  612.             clearHolo()
  613.             holo = oldHolo
  614.             return
  615.         end
  616.        
  617.         writeAt("   ", 22, 12)
  618.         thisString = tostring(rowLength)
  619.         writeAt(thisString, 22 + math.floor((4 - #thisString) / 2), 12)
  620.     until clickedAt(30, 35, 12) and #holo[1] % rowLength == 0
  621.    
  622.     local colLength = #holo[1] / rowLength
  623.    
  624.     term.setCursorPos(1, 10)
  625.     term.clearLine()
  626.     term.setCursorPos(1, 12)
  627.     term.clearLine()
  628.    
  629.     writeAt("Click each tile above the projector", 9, 8, colours.grey)
  630.     writeAt("in the snaking order shown below:", 10, 9)
  631.    
  632.     local map = {{0, 0}, {1, 0}, {2, 0}, {2, 1}, {1, 1}, {0, 1}, {0, 2}, {1, 2}, {2, 2}}
  633.     local outList, x, y, counter, myTimer = {{}}, 1, 1, -1, os.startTimer(0)
  634.     while true do
  635.         myEvent = {os.pullEvent()}
  636.        
  637.         if myEvent[1] == "hologramTouch" then
  638.             outList[y][x] = myEvent[7]
  639.             peripheral.call(myEvent[7], "clear", "minecraft:air", 0)
  640.             x = x + (bit.band(y, 1) == 1 and 1 or -1)
  641.             if x > rowLength or x < 1 then
  642.                 y = y + 1
  643.                 x = (bit.band(y, 1) == 1 and 1 or rowLength)
  644.                 if y > colLength then break end
  645.                 outList[y] = {}
  646.             end
  647.         elseif myEvent[1] == "timer" and myEvent[2] == myTimer then
  648.             counter = counter == 9 and 0 or (counter + 1)
  649.             myTimer = os.startTimer(1)
  650.             if counter == 0 then paintutils.drawFilledBox(25, 11, 27, 13, colours.grey) else writeAt(" ", 25 + map[counter][1], 11 + map[counter][2], nil, colours.lime) end
  651.         elseif clickedAt(21, 30, 15) and fs.exists(shell.resolve("slide.cfg")) then
  652.             clearHolo()
  653.             holo = oldHolo
  654.             return
  655.         end
  656.     end
  657.    
  658.     term.setCursorPos(1, 10)
  659.     term.clearLine()
  660.     term.setCursorPos(1, 11)
  661.     term.clearLine()
  662.    
  663.     holo = {}
  664.     for y = 1, colLength do
  665.         holo[y] = {}
  666.         for x = 1, rowLength do holo[y][x] = peripheral.wrap(outList[y][x]) end
  667.     end
  668.     sideLengthX, sideLengthY, tileWidth, tileHeight, rotate = rowLength * 8, colLength * 8, rowLength * 2, colLength * 2, rotateOption[curRotate]
  669.    
  670.     local file = fs.open(shell.resolve("slide.cfg"), "w")
  671.     file.writeLine(textutils.serialise({outList, curRotate}))
  672.     file.close()
  673.    
  674.     clear(colours.black, colours.lightGrey)
  675.     writeAt("Calibration", 21, 6)
  676.     writeAt("Settings saved.", 4, 10, colours.grey)
  677.     writeAt("Press any key to continue...", 6, 15)
  678.     repeat local myEvent = os.pullEvent() until myEvent == "key" or myEvent == "mouse_click"
  679. end
  680.  
  681. ---------------------------------------------
  682. ------------         Init        ------------
  683. ---------------------------------------------
  684.  
  685. if term.current().setTextScale then
  686.     local setTextScale = term.current().setTextScale
  687.    
  688.     setTextScale(0.5)
  689.     local scale = 5
  690.    
  691.     repeat
  692.         setTextScale(scale)
  693.         scale = scale - 0.5
  694.         local xSize, ySize = term.getSize()
  695.     until (xSize >= 50 and ySize >= 19) or scale == 0
  696. end
  697.  
  698. xSize, ySize = term.getSize()
  699.  
  700. if xSize < 50 or ySize < 19 or not term.isColour() then error("Sorry, a 50x19 colour display is required at minimum.") end
  701.  
  702. term.setTextColour(colours.black)
  703. term.setBackgroundColour(colours.orange)
  704.  
  705. for j = 0, 1 do for i = 1, 3 do
  706.     term.setCursorPos(1, i + (j * (ySize - 3)))
  707.     term.clearLine()
  708. end end
  709.  
  710. term.setCursorPos(5, 2)
  711. term.write("Slide", 5, 2)
  712.  
  713. paintutils.drawPixel(1, 1, colours.blue)
  714. paintutils.drawPixel(2, 1, colours.green)
  715. paintutils.drawPixel(3, 1, colours.yellow)
  716. paintutils.drawPixel(1, 2, colours.grey)
  717. paintutils.drawPixel(2, 2, colours.white)
  718. paintutils.drawPixel(3, 2, colours.lightBlue)
  719. paintutils.drawPixel(1, 3, colours.orange)
  720. paintutils.drawPixel(3, 3, colours.red)
  721. paintutils.drawPixel(2, 3, colours.lime)
  722.  
  723. if fs.exists(shell.resolve("slide.cfg")) then
  724.     local file = fs.open(shell.resolve("slide.cfg"), "r")
  725.     local input = textutils.unserialise(file.readAll())
  726.     file.close()
  727.    
  728.     holo, rotate = input[1], rotateOption[input[2]]
  729.     sideLengthX, sideLengthY = #holo[1], #holo
  730.    
  731.     for y = 1, sideLengthY do for x = 1, sideLengthX do
  732.         local key = holo[y][x]
  733.         holo[y][x] = peripheral.wrap(key)
  734.         if not holo[y][x] then error("Config file refers to missing projector \""..key.."\" at position "..tostring(x).."x"..tostring(y)..". Either connect it, or delete the file to enable reconfiguration (using \"rm slide.cfg\").") end
  735.         holo[key] = {(x - 1) * 8 + 1, (y - 1) * 8 + 1}
  736.     end end
  737.    
  738.     sideLengthX, sideLengthY = sideLengthX * 8, sideLengthY * 8
  739.     tileWidth, tileHeight = sideLengthX / 4, sideLengthY / 4
  740. else doConfig() end
  741.  
  742. clearHolo()
  743.  
  744. ---------------------------------------------
  745. ------------  Main Program Loop  ------------
  746. ---------------------------------------------
  747.  
  748. while true do
  749.     if redraw then
  750.         clear(colours.black, colours.lightGrey)
  751.         writeAt("What Do?", 22, 6)
  752.         writeAt(" Game ", 23, 8, colours.lightGrey, colours.grey)
  753.         writeAt(" Viewer ", 22, 10)
  754.         writeAt(" Calibrate ", 21, 12)
  755.         writeAt(" Quit ", 23, 14)
  756.     else redraw = true end
  757.    
  758.     repeat myEvent = {os.pullEvent()} until myEvent[1] == "key" or myEvent[1] == "mouse_click"
  759.    
  760.     if clickedAt(22, 29, 8) then
  761.         doPuzzle()
  762.     elseif clickedAt(21, 30, 10) then
  763.         parallel.waitForAny(showImage, viewerLoop)
  764.     elseif clickedAt(20, 32, 12) then
  765.         doConfig()
  766.     elseif pressedKey(keys.x, keys.q) or clickedAt(22, 29, 14) then
  767.         if myEvent[1] == "key" then os.pullEvent("char") end
  768.         break
  769.     else redraw = false end
  770. end
  771.  
  772. term.setTextColour(colours.white)
  773. term.setBackgroundColour(colours.black)
  774. term.clear()
  775. term.setCursorPos(1, 1)
  776. print("Thanks for playing!\n")
Advertisement
Add Comment
Please, Sign In to add comment
Advertisement