nonogamer9

Fire And Forget (The 1988 Game) Title Screen Craft-OS PC Port

Apr 18th, 2025 (edited)
141
0
Never
Not a member of Pastebin yet? Sign Up, it unlocks many cool features!
Lua 5.91 KB | Software | 0 0
  1. local pcmURL = "https://files.catbox.moe/5crejb.raw"
  2. local bmpURL = "https://files.catbox.moe/llki61.bmp"
  3. local bmpFilename = "image.bmp"
  4. local isUnsigned = false
  5. local inputSampleRate = 40000
  6. local outputSampleRate = 48000
  7. local volume = 0.1
  8. local graphicsMode = 2
  9.  
  10. local function downloadBMP(url, filename)
  11.   if not http then error("HTTP API not enabled!") end
  12.   local r = http.get(url, nil, true)
  13.   if not r then error("Failed to download image") end
  14.   local f = fs.open(filename, "wb")
  15.   local c = r.readAll()
  16.   for i = 1, #c, 8192 do f.write(c:sub(i, i + 8191)) end
  17.   f.close() r.close()
  18. end
  19.  
  20. local function readBMP(filename)
  21.   local file = fs.open(filename, "rb")
  22.   if not file then return nil, "Failed to open file" end
  23.   local header = file.read(54)
  24.   local width = string.byte(header, 19) + string.byte(header, 20) * 256
  25.   local height = string.byte(header, 23) + string.byte(header, 24) * 256
  26.   local pixels = {}
  27.   for y = height, 1, -1 do
  28.     pixels[y] = {}
  29.     for x = 1, width do
  30.       local b = file.read(1) local g = file.read(1) local r = file.read(1)
  31.       pixels[y][x] = {r = string.byte(r), g = string.byte(g), b = string.byte(b)}
  32.     end
  33.   end
  34.   file.close()
  35.   return {width = width, height = height, pixels = pixels}
  36. end
  37.  
  38. local function resizeImage(image, newWidth, newHeight)
  39.   local resized = {width = newWidth, height = newHeight, pixels = {}}
  40.   for y = 1, newHeight do
  41.     resized.pixels[y] = {}
  42.     for x = 1, newWidth do
  43.       local srcX = math.floor(x * image.width / newWidth)
  44.       local srcY = math.floor(y * image.height / newHeight)
  45.       resized.pixels[y][x] = image.pixels[srcY][srcX]
  46.     end
  47.   end
  48.   return resized
  49. end
  50.  
  51. local function displayBMPCraftOSPC(image, output, colorMode)
  52.   local screenWidth, screenHeight = output.getSize()
  53.   local imageWidth, imageHeight = image.width, image.height
  54.   local originalPalette = {}
  55.   for i = 0, 255 do originalPalette[i] = {term.getPaletteColor(i)} end
  56.   local originalGraphicsMode = term.getGraphicsMode()
  57.   term.setGraphicsMode(colorMode)
  58.   if colorMode == 2 then
  59.     local cubeSize = 5
  60.     for i = 16, 255 do
  61.       local index = i - 16
  62.       local rIndex = math.floor(index / (cubeSize * cubeSize))
  63.       local gIndex = math.floor((index % (cubeSize * cubeSize)) / cubeSize)
  64.       local bIndex = index % cubeSize
  65.       local r = math.floor(rIndex * 255 / (cubeSize - 1))
  66.       local g = math.floor(gIndex * 255 / (cubeSize - 1))
  67.       local b = math.floor(bIndex * 255 / (cubeSize - 1))
  68.       term.setPaletteColor(i, r / 255, g / 255, b / 255)
  69.     end
  70.   end
  71.   local function adjustBrightness(v) return math.min(255, math.max(0, math.floor(v * 1.2))) end
  72.   local function mapColor(r, g, b)
  73.     r, g, b = adjustBrightness(r), adjustBrightness(g), adjustBrightness(b)
  74.     if colorMode == 2 then
  75.       local cubeSize = 5
  76.       local rIndex = math.floor(r / (255 / (cubeSize - 1)))
  77.       local gIndex = math.floor(g / (255 / (cubeSize - 1)))
  78.       local bIndex = math.floor(b / (255 / (cubeSize - 1)))
  79.       return 16 + rIndex * cubeSize * cubeSize + gIndex * cubeSize + bIndex
  80.     else
  81.       return colors.white
  82.     end
  83.   end
  84.   for y = 0, screenHeight * 9 - 1 do
  85.     for x = 0, screenWidth * 6 - 1 do
  86.       local sourceX = math.floor(x * imageWidth / (screenWidth * 6))
  87.       local sourceY = math.floor(y * imageHeight / (screenHeight * 9))
  88.       local pixel = image.pixels[sourceY + 1][sourceX + 1]
  89.       local color = mapColor(pixel.r, pixel.g, pixel.b)
  90.       output.setPixel(x, y, color)
  91.     end
  92.   end
  93.   print("Image displayed. Press any key to continue.")
  94.   os.pullEvent("key")
  95.   term.setGraphicsMode(originalGraphicsMode)
  96.   for i = 0, 255 do term.setPaletteColor(i, table.unpack(originalPalette[i])) end
  97.   term.setBackgroundColor(colors.black) term.setTextColor(colors.white) term.clear() term.setCursorPos(1, 1)
  98. end
  99.  
  100. local function downloadAndResamplePCM(url, isUnsigned, inputRate, outputRate)
  101.   print("Downloading and resampling PCM audio...")
  102.   local response = http.get(url, nil, true)
  103.   if not response then error("Failed to download PCM file") end
  104.   local raw = response.readAll()
  105.   response.close()
  106.   local inSamples = {}
  107.   for i = 1, #raw do
  108.     local b = string.byte(raw, i)
  109.     if isUnsigned then b = b - 128 end
  110.     inSamples[#inSamples + 1] = b
  111.   end
  112.   local outSamples = {}
  113.   local ratio = inputRate / outputRate
  114.   for i = 1, math.floor(#inSamples / ratio) do
  115.     local src = (i - 1) * ratio + 1
  116.     local idx = math.floor(src)
  117.     local frac = src - idx
  118.     local s1 = inSamples[idx] or 0
  119.     local s2 = inSamples[idx + 1] or s1
  120.     outSamples[i] = s1 + (s2 - s1) * frac
  121.   end
  122.   return outSamples
  123. end
  124.  
  125. local function playPCMBufferLoop(speaker, buffer, volume)
  126.   local chunkSize = 16384
  127.   while true do
  128.     local played = 0
  129.     while played < #buffer do
  130.       local chunk = {}
  131.       for i = 1, chunkSize do
  132.         local idx = played + i
  133.         if idx > #buffer then break end
  134.         local sample = math.floor(buffer[idx] * volume + 0.5)
  135.         if sample > 127 then sample = 127 end
  136.         if sample < -128 then sample = -128 end
  137.         chunk[i] = sample
  138.       end
  139.       if #chunk == 0 then break end
  140.       while not speaker.playAudio(chunk) do
  141.         os.pullEvent("speaker_audio_empty")
  142.       end
  143.       played = played + #chunk
  144.     end
  145.   end
  146. end
  147.  
  148. local function audioTask()
  149.   local speaker = peripheral.find("speaker")
  150.   if not speaker then print("No speaker attached!") return end
  151.   local buffer = downloadAndResamplePCM(pcmURL, isUnsigned, inputSampleRate, outputSampleRate)
  152.   playPCMBufferLoop(speaker, buffer, volume)
  153. end
  154.  
  155. local function imageTask()
  156.   downloadBMP(bmpURL, bmpFilename)
  157.   local image, err = readBMP(bmpFilename)
  158.   if not image then print("BMP error:", err) return end
  159.   if term.setGraphicsMode then
  160.     displayBMPCraftOSPC(image, term, graphicsMode)
  161.   else
  162.     print("CraftOS-PC Graphics Mode not supported")
  163.   end
  164. end
  165.  
  166. parallel.waitForAny(audioTask, imageTask)
  167.  
Add Comment
Please, Sign In to add comment