nonogamer9

IBM i486 Demo! Made by nonogamer9 [ComputerCraft demoscene]

Jun 4th, 2025
166
0
Never
Not a member of Pastebin yet? Sign Up, it unlocks many cool features!
Lua 20.56 KB | Software | 0 0
  1. local ASSET_DIR = "assets"
  2. local FLOOR_BMP_FILE = ASSET_DIR .. "/floor.bmp"
  3. local SPRITE_BMP_FILE = ASSET_DIR .. "/sprite.bmp"
  4. local PCM1_FILE = ASSET_DIR .. "/music1.raw"
  5. local PCM2_FILE = ASSET_DIR .. "/music2.raw"
  6. local FONT_BMP_FILE = ASSET_DIR .. "/font.bmp"
  7. local FLOOR_BMP_URL = "https://files.catbox.moe/ipwa9x.bmp"
  8. local SPRITE_BMP_URL = "https://files.catbox.moe/pemxbh.bmp"
  9. local PCM1_URL = "https://files.catbox.moe/t1cnnf.raw"
  10. local PCM2_URL = "https://files.catbox.moe/k3wxw5.raw"
  11. local FONT_BMP_URL = "https://files.catbox.moe/zkdsi9.bmp"
  12. local PCM_SAMPLE_RATE = 32000
  13. local PCM_UNSIGNED = true
  14. local VOLUME_BOOST = 2.5
  15. local SPRITE_SCALE = 0.5
  16. local CHUNK_HEIGHT = 4
  17. local SCANIMATE_PHASE = 0.15
  18. local SINE_AMPLITUDE = 16
  19. local FAST_PERIOD = 36
  20. local SWITCH_PERIOD = 5
  21. local FPS = 30
  22. local FONT_CELL_W, FONT_CELL_H = 20, 20
  23. local FONT_OUT_W, FONT_OUT_H = 10, 10
  24. local FONT_COLS = 15
  25. local FONT_TRANSPARENT = { r=34, g=177, b=76 }
  26. local math_floor, math_min, math_max, math_sin, math_cos, math_pi, math_abs = math.floor, math.min, math.max, math.sin, math.cos, math.pi, math.abs
  27. local table_unpack = table.unpack
  28. local os_pullEvent, os_queueEvent = os.pullEvent, os.queueEvent
  29. local term_setPaletteColor, term_getPaletteColor = term.setPaletteColor, term.getPaletteColor
  30. local term_setGraphicsMode, term_getGraphicsMode = term.setGraphicsMode, term.getGraphicsMode
  31. local term_setBackgroundColor, term_getBackgroundColor = term.setBackgroundColor, term.getBackgroundColor
  32. local term_setTextColor, term_getTextColor = term.setTextColor, term.getTextColor
  33. local term_clear, term_setCursorPos = term.clear, term.setCursorPos
  34.  
  35. term_clear()
  36. term_setCursorPos(1, 1)
  37. print([[
  38.                                
  39.   &$$$&.X&$$$$$  :&$$&   .&$$&  
  40.   &&&&&x&&&&&&&&&+&&$&x  &$&&&  
  41.     $$    $$   &&  $xX& x$+$    
  42.     xX    xx&&$x   X: xxx.:x    
  43.     +x    ++   X$  xx  $& x+    
  44.   &&&&&X&&&&&&&&&;&&&; &+ &&&&  
  45.   &&&&&:X&&&&&&  .&&&+    &&&&
  46.  
  47. I486 Demo by nonogamer9!
  48. Loading demo's assets if missing...
  49. ]])
  50. os.sleep(1)
  51.  
  52. if not fs.exists(ASSET_DIR) then fs.makeDir(ASSET_DIR) end
  53. local function downloadContent(url, filename, contentType)
  54.  print("Downloading " .. contentType .. "...")
  55.  local response = http.get(url, nil, true)
  56.  if not response then error("Failed to download " .. contentType .. ": " .. url) end
  57.  local file = fs.open(filename, "wb")
  58.  local content = response.readAll()
  59.  for i = 1, #content, 8192 do
  60.    file.write(content:sub(i, i + 8191))
  61.    os_queueEvent("yield")
  62.    os_pullEvent("yield")
  63.  end
  64.  file.close()
  65.  response.close()
  66.  print("Downloaded " .. contentType .. ".")
  67. end
  68. local function readBMP(filename)
  69.  local file = fs.open(filename, "rb")
  70.  if not file then return nil, "Failed to open file" end
  71.  local header = file.read(54)
  72.  local width = string.byte(header, 19) + string.byte(header, 20) * 256
  73.  local height = string.byte(header, 23) + string.byte(header, 24) * 256
  74.  local rowSize = math_floor((width * 3 + 3) / 4) * 4
  75.  local padding = rowSize - width * 3
  76.  local pixels = {}
  77.  for y = height, 1, -1 do
  78.    local row = {}
  79.    for x = 1, width do
  80.      local b = file.read(1)
  81.      local g = file.read(1)
  82.      local r = file.read(1)
  83.      row[x] = {r = string.byte(r), g = string.byte(g), b = string.byte(b)}
  84.    end
  85.    if padding > 0 then file.read(padding) end
  86.    pixels[y] = row
  87.    if y % 10 == 0 then os_queueEvent("yield") os_pullEvent("yield") end
  88.  end
  89.  file.close()
  90.  return {width = width, height = height, pixels = pixels}
  91. end
  92. local function scaleSprite(sprite, scale)
  93.  local srcW, srcH = sprite.width, sprite.height
  94.  local dstW, dstH = math_max(1, math_floor(srcW * scale + 0.5)), math_max(1, math_floor(srcH * scale + 0.5))
  95.  local srcPixels, dst = sprite.pixels, {}
  96.  for y = 1, dstH do
  97.    local row, srcY = {}, math_min(srcH, math_max(1, math_floor((y-1)/scale+1)))
  98.    local srcRow = srcPixels[srcY]
  99.    for x = 1, dstW do
  100.      local srcX = math_min(srcW, math_max(1, math_floor((x-1)/scale+1)))
  101.      row[x] = srcRow[srcX]
  102.    end
  103.    dst[y] = row
  104.  end
  105.  return {width = dstW, height = dstH, pixels = dst}
  106. end
  107. local function mapColor256(r, g, b)
  108.  local cubeSize = 6
  109.  local rIndex = math_floor(r / (255 / (cubeSize - 1)))
  110.  local gIndex = math_floor(g / (255 / (cubeSize - 1)))
  111.  local bIndex = math_floor(b / (255 / (cubeSize - 1)))
  112.  return 16 + rIndex * cubeSize * cubeSize + gIndex * cubeSize + bIndex
  113. end
  114. local function set256Palette()
  115.  local cubeSize = 6
  116.  for i = 16, 231 do
  117.    local index = i - 16
  118.    local rIndex = math_floor(index / (cubeSize * cubeSize))
  119.    local gIndex = math_floor((index % (cubeSize * cubeSize)) / cubeSize)
  120.    local bIndex = index % cubeSize
  121.    local r = math_floor(rIndex * 255 / (cubeSize - 1))
  122.    local g = math_floor(gIndex * 255 / (cubeSize - 1))
  123.    local b = math_floor(bIndex * 255 / (cubeSize - 1))
  124.    term_setPaletteColor(i, r / 255, g / 255, b / 255)
  125.  end
  126.  for i = 232, 255 do
  127.    local gray = math_floor((i - 232) * 255 / 23)
  128.    term_setPaletteColor(i, gray / 255, gray / 255, gray / 255)
  129.  end
  130. end
  131. local function savePalette()
  132.  local t = {}
  133.  for i = 0, 255 do t[i] = {term_getPaletteColor(i)} end
  134.  return t
  135. end
  136. local function restorePalette(t)
  137.  for i = 0, 255 do term_setPaletteColor(i, table_unpack(t[i])) end
  138. end
  139. local function makeBuffer(width, height)
  140.  local buf = {}
  141.  for y = 0, height-1 do
  142.    local row = {}
  143.    for x = 0, width-1 do row[x] = 0 end
  144.    buf[y] = row
  145.  end
  146.  return buf
  147. end
  148. local function swapBuffers(a, b) return b, a end
  149. local function blitBuffer(buf, output)
  150.  for y = 0, #buf do
  151.    local row = buf[y]
  152.    for x = 0, #(row) do
  153.      output.setPixel(x, y, row[x])
  154.    end
  155.  end
  156. end
  157. local function playPCMOnce(filename, inputSampleRate, isUnsigned, volume)
  158.  local speaker = peripheral.find("speaker")
  159.  if not speaker then return end
  160.  local file = fs.open(filename, "rb")
  161.  if not file then return end
  162.  local samples, sum, count = {}, 0, 0
  163.  while true do
  164.    local byte = file.read()
  165.    if not byte then break end
  166.    if isUnsigned then byte = byte - 128 end
  167.    samples[#samples + 1] = byte
  168.    sum = sum + byte
  169.    count = count + 1
  170.  end
  171.  file.close()
  172.  if #samples == 0 then return end
  173.  local avg = sum / count
  174.  for i = 1, #samples do samples[i] = samples[i] - avg end
  175.  local outputSampleRate = 48000
  176.  if inputSampleRate ~= outputSampleRate then
  177.    local resampled, ratio = {}, inputSampleRate / outputSampleRate
  178.    for i = 1, math_floor(#samples / ratio) do
  179.      local src = (i - 1) * ratio + 1
  180.      local idx = math_floor(src)
  181.      local frac = src - idx
  182.      local s1, s2 = samples[idx] or 0, samples[idx + 1] or samples[idx] or 0
  183.      resampled[i] = s1 + (s2 - s1) * frac
  184.    end
  185.    samples = resampled
  186.  end
  187.  local chunkSize, totalSamples = 128 * 1024, #samples
  188.  local playedSamples = 0
  189.  while playedSamples < totalSamples do
  190.    local chunk = {}
  191.    for i = 1, chunkSize do
  192.      local idx = playedSamples + i
  193.      if idx > totalSamples then break end
  194.      local sample = math_floor(samples[idx] * volume * VOLUME_BOOST + 0.5)
  195.      if sample > 127 then sample = 127 end
  196.      if sample < -128 then sample = -128 end
  197.      chunk[i] = sample
  198.    end
  199.    if #chunk == 0 then break end
  200.    while not speaker.playAudio(chunk) do
  201.      os_pullEvent("speaker_audio_empty")
  202.    end
  203.    playedSamples = playedSamples + #chunk
  204.  end
  205. end
  206. local function playPCMsAlternating()
  207.  while true do
  208.    playPCMOnce(PCM1_FILE, PCM_SAMPLE_RATE, PCM_UNSIGNED, 0.2)
  209.    playPCMOnce(PCM2_FILE, PCM_SAMPLE_RATE, PCM_UNSIGNED, 0.2)
  210.  end
  211. end
  212. local function mode7_floor()
  213.  return function(frame, sw, sh, iw, ih)
  214.    local cam_x, cam_y = iw/2, ih/2
  215.    local cam_angle = frame/60
  216.    local cam_height, focal_length = 120, 170
  217.    local pxw, pxh = sw*6, sh*9
  218.    local horizon = math_floor(pxh * 0.45)
  219.    return {
  220.      a=1, b=0, c=0, d=1, x0=0, y0=0, u0=0, v0=0,
  221.      scanline=function(sy,a,b,c,d,frame) return a,b,c,d end,
  222.      floor=function(sx,sy)
  223.        if sy < horizon then return nil,nil end
  224.        local dx, dy = sx - pxw/2, sy - horizon
  225.        local angle = cam_angle
  226.        local distance = cam_height * focal_length / (dy+1)
  227.        local world_x = cam_x + math.cos(angle)*distance + math.sin(angle)*dx*distance/focal_length
  228.        local world_y = cam_y + math.sin(angle)*distance - math.cos(angle)*dx*distance/focal_length
  229.        local tx = ((math_floor(world_x)-1) % iw) + 1
  230.        local ty = ((math_floor(world_y)-1) % ih) + 1
  231.        return tx, ty
  232.      end,
  233.      horizon = horizon
  234.    }
  235.  end
  236. end
  237. local SCANIMATE_EFFECTS = {
  238.  function(chunk, y, x, frame)
  239.    local phase = frame / FAST_PERIOD * 2 * math_pi + chunk * SCANIMATE_PHASE
  240.    return 0, math_floor(math_sin(phase) * SINE_AMPLITUDE + 0.5)
  241.  end,
  242.  function(chunk, y, x, frame)
  243.    local phase = frame / FAST_PERIOD * 2 * math_pi + chunk * SCANIMATE_PHASE
  244.    return math_floor(math_sin(phase) * SINE_AMPLITUDE + 0.5), 0
  245.  end,
  246.  function(chunk, y, x, frame)
  247.    local phase = frame / FAST_PERIOD * 2 * math_pi + chunk * SCANIMATE_PHASE
  248.    return math_floor(math_cos(phase) * SINE_AMPLITUDE * 0.7 + 0.5), math_floor(math_sin(phase) * SINE_AMPLITUDE + 0.5)
  249.  end,
  250.  function(chunk, y, x, frame)
  251.    local phase = frame / FAST_PERIOD * 2 * math_pi + chunk * SCANIMATE_PHASE
  252.    return math_floor(math_sin(phase) * SINE_AMPLITUDE * 0.7 + 0.5),
  253.           math_floor(math_sin(phase*2) * SINE_AMPLITUDE * 0.5 + 0.5)
  254.  end,
  255.  function(chunk, y, x, frame)
  256.    local phase = frame / (FAST_PERIOD*0.5) * 2 * math_pi
  257.    local sign = (chunk % 2 == 0) and 1 or -1
  258.    return 0, math_floor(math_sin(phase + chunk * SCANIMATE_PHASE) * SINE_AMPLITUDE * sign + 0.5)
  259.  end,
  260.  function(chunk, y, x, frame)
  261.    local phase = frame / FAST_PERIOD * 2 * math_pi + chunk * SCANIMATE_PHASE
  262.    local angle = phase
  263.    local r = SINE_AMPLITUDE * 0.7
  264.    return math_floor(math_cos(angle) * r + 0.5), math_floor(math_sin(angle) * r + 0.5)
  265.  end,
  266.  function(chunk, y, x, frame)
  267.    local phase = frame / FAST_PERIOD * 2 * math_pi + chunk * SCANIMATE_PHASE
  268.    local scale = 1 + 0.5 * math_sin(phase)
  269.    local ycenter = (chunk * CHUNK_HEIGHT + CHUNK_HEIGHT/2)
  270.    local yoff = math_floor((y - ycenter) * (scale - 1) + 0.5)
  271.    return 0, yoff
  272.  end,
  273.  function(chunk, y, x, frame)
  274.    local phase = frame / FAST_PERIOD * 2 * math_pi + chunk * SCANIMATE_PHASE + y * 0.08
  275.    return math_floor(math_sin(phase) * SINE_AMPLITUDE * (0.3 + 0.7 * (y / (chunk * CHUNK_HEIGHT + 1))) + 0.5), 0
  276.  end,
  277.  function(chunk, y, x, frame)
  278.    local phase = frame / FAST_PERIOD * 2 * math_pi
  279.    local bulge = math_sin(phase + chunk * SCANIMATE_PHASE)
  280.    local ycenter = (chunk * CHUNK_HEIGHT + CHUNK_HEIGHT/2)
  281.    local dist = math_abs(y - ycenter)
  282.    local amt = (1 - dist / (CHUNK_HEIGHT/2 + 1)) * SINE_AMPLITUDE
  283.    return 0, math_floor(bulge * amt + 0.5)
  284.  end,
  285.  function(chunk, y, x, frame)
  286.    local phase = frame / FAST_PERIOD * 2 * math_pi
  287.    local t = (chunk * CHUNK_HEIGHT + y) / (CHUNK_HEIGHT * 8)
  288.    local squish = 1 + 0.7 * math_sin(phase)
  289.    local yoff = math_floor((t - 0.5) * squish * SINE_AMPLITUDE)
  290.    return 0, yoff
  291.  end,
  292.  function(chunk, y, x, frame)
  293.    local phase = frame / FAST_PERIOD * 2 * math_pi
  294.    local ripple = math_sin(phase + y * 0.15)
  295.    return math_floor(ripple * SINE_AMPLITUDE * 0.5 + 0.5), 0
  296.  end,
  297.  function(chunk, y, x, frame)
  298.    local phase = frame / FAST_PERIOD * 2 * math_pi
  299.    local twist = math_sin(phase + y * 0.20)
  300.    return math_floor(twist * SINE_AMPLITUDE * 0.7 + 0.5), math_floor(twist * SINE_AMPLITUDE * 0.2 + 0.5)
  301.  end,
  302.  function(chunk, y, x, frame)
  303.    local phase = frame / FAST_PERIOD * 2 * math_pi
  304.    local t = (chunk * CHUNK_HEIGHT + y) / (CHUNK_HEIGHT * 8)
  305.    local bend = math_sin(phase)
  306.    return math_floor(bend * SINE_AMPLITUDE * t + 0.5), 0
  307.  end,
  308.  function(chunk, y, x, frame)
  309.    local phase1 = frame / FAST_PERIOD * 2 * math_pi + chunk * SCANIMATE_PHASE
  310.    local phase2 = frame / (FAST_PERIOD*0.5) * 2 * math_pi + chunk * SCANIMATE_PHASE * 2
  311.    return math_floor(math_sin(phase1) * SINE_AMPLITUDE * 0.6 + math_sin(phase2) * SINE_AMPLITUDE * 0.4 + 0.5), 0
  312.  end,
  313.  function(chunk, y, x, frame)
  314.    local phase = frame / FAST_PERIOD * 2 * math_pi + chunk * SCANIMATE_PHASE
  315.    local scale = 1 + 0.3 * math_sin(phase)
  316.    local ycenter = (chunk * CHUNK_HEIGHT + CHUNK_HEIGHT/2)
  317.    local xcenter = (x - 1) - 32
  318.    local yoff = math_floor((y - ycenter) * (scale - 1) + 0.5)
  319.    local xoff = math_floor(xcenter * 0.15 * math_sin(phase) + 0.5)
  320.    return xoff, yoff
  321.  end,
  322.  function(chunk, y, x, frame)
  323.    local phase = frame / (FAST_PERIOD*0.8) * 2 * math_pi
  324.    local scale = 1 + 0.6 * math_sin(phase)
  325.    local ycenter = (chunk * CHUNK_HEIGHT + CHUNK_HEIGHT/2)
  326.    local yoff = math_floor((y - ycenter) * (scale - 1) + 0.5)
  327.    return 0, yoff
  328.  end,
  329.  function(chunk, y, x, frame)
  330.    local t = ((frame + chunk*8) % FAST_PERIOD) / FAST_PERIOD
  331.    return 0, math_floor((t - 0.5) * 2 * SINE_AMPLITUDE)
  332.  end,
  333.  function(chunk, y, x, frame)
  334.    local seed = (frame + chunk*13) % 97
  335.    local jitter = ((seed * 37) % 7) - 3
  336.    return 0, jitter
  337.  end,
  338.  function(chunk, y, x, frame)
  339.    local phase = frame / FAST_PERIOD * 2 * math_pi + (chunk + x) * SCANIMATE_PHASE
  340.    local sign = ((chunk + x) % 2 == 0) and 1 or -1
  341.    return 0, math_floor(math_sin(phase) * SINE_AMPLITUDE * sign * 0.5)
  342.  end,
  343. }
  344. local function blitSpriteScanimate(buf, sprite, px, py, frame, effectFn)
  345.  local s_pixels, s_width, s_height = sprite.pixels, sprite.width, sprite.height
  346.  local chunkHeight, numChunks = CHUNK_HEIGHT, math.ceil(s_height / CHUNK_HEIGHT)
  347.  for chunk = 0, numChunks-1 do
  348.    local yStart = chunk * chunkHeight + 1
  349.    local yEnd = math_min(s_height, yStart + chunkHeight - 1)
  350.    for y = yStart, yEnd do
  351.      local srcRow = s_pixels[y]
  352.      for x = 1, s_width do
  353.        local pixel = srcRow[x]
  354.        if not (pixel.r == 255 and pixel.g == 0 and pixel.b == 255) then
  355.          local dx, dy = effectFn(chunk, y, x, frame)
  356.          local sx = px + x - 1 + dx
  357.          local sy = py + y - 1 + dy
  358.          local row = buf[sy]
  359.          if row and row[sx] ~= nil then
  360.            row[sx] = mapColor256(pixel.r, pixel.g, pixel.b)
  361.          end
  362.        end
  363.      end
  364.    end
  365.  end
  366. end
  367. local function drawTextHalfResWave(buf, font, str, px, py, frame, amplitude, period, phaseStep, scale)
  368.  scale = scale or 1
  369.  for i = 1, #str do
  370.    local c = string.byte(str, i) - 32
  371.    if c >= 0 and c < 120 then
  372.      local sx = (c % FONT_COLS) * FONT_CELL_W
  373.      local sy = math_floor(c / FONT_COLS) * FONT_CELL_H
  374.      local phase = (frame / period) * 2 * math_pi + (i - 1) * phaseStep
  375.      local yoff = math_floor(math_sin(phase) * amplitude + 0.5)
  376.      local baseX = px + (i - 1) * FONT_OUT_W * scale
  377.      local baseY = py + yoff
  378.      for dy = 0, FONT_OUT_H - 1 do
  379.        for dx = 0, FONT_OUT_W - 1 do
  380.          local p = font.pixels[sy + dy * 2 + 1][sx + dx * 2 + 1]
  381.          if not (p.r == FONT_TRANSPARENT.r and p.g == FONT_TRANSPARENT.g and p.b == FONT_TRANSPARENT.b) then
  382.            if scale == 1 then
  383.              local by = baseY + dy
  384.              local bx = baseX + dx
  385.              if buf[by] and buf[by][bx] then
  386.                buf[by][bx] = mapColor256(p.r, p.g, p.b)
  387.              end
  388.            else
  389.              for syy = 0, scale - 1 do
  390.                for sxx = 0, scale - 1 do
  391.                  local by = baseY + dy * scale + syy
  392.                  local bx = baseX + dx * scale + sxx
  393.                  if buf[by] and buf[by][bx] then
  394.                    buf[by][bx] = mapColor256(p.r, p.g, p.b)
  395.                  end
  396.                end
  397.              end
  398.            end
  399.          end
  400.        end
  401.      end
  402.    end
  403.  end
  404. end
  405. local function displayMode7WithSpriteForever(floorImage, spriteImage, fontImage, output, paramFunc)
  406.  local screenWidth, screenHeight = output.getSize()
  407.  local pxw, pxh = screenWidth * 6, screenHeight * 9
  408.  local imageWidth, imageHeight = floorImage.width, floorImage.height
  409.  local savePal, getGM, setGM = savePalette, term_getGraphicsMode, term_setGraphicsMode
  410.  local origPalette, origGM = savePal(), getGM()
  411.  local origBG, origFG = term_getBackgroundColor(), term_getTextColor()
  412.  setGM(2)
  413.  set256Palette()
  414.  local bufA, bufB = makeBuffer(pxw, pxh), makeBuffer(pxw, pxh)
  415.  local front, back, frame = bufA, bufB, 0
  416.  local stop = false
  417.  local function waitForEnter()
  418.    while true do
  419.      local ev, key = os_pullEvent("key")
  420.      if key == keys.enter then stop = true break end
  421.    end
  422.  end
  423.  local numEffects = #SCANIMATE_EFFECTS
  424.  parallel.waitForAny(
  425.    function()
  426.      while not stop do
  427.        frame = frame + 1
  428.        local params = paramFunc(frame, screenWidth, screenHeight, imageWidth, imageHeight)
  429.        local a, b, c, d = params.a, params.b, params.c, params.d
  430.        local x0, y0, u0, v0 = params.x0, params.y0, params.u0, params.v0
  431.        local floorFunc, horizon = params.floor, params.horizon or 0
  432.        for sy = 0, pxh-1 do
  433.          local row = back[sy]
  434.          for sx = 0, pxw-1 do
  435.            local color = 0
  436.            if floorFunc then
  437.              local tx, ty = floorFunc(sx, sy)
  438.              if tx and ty and tx >= 1 and tx <= imageWidth and ty >= 1 and ty <= imageHeight then
  439.                local pixel = floorImage.pixels[ty][tx]
  440.                color = mapColor256(pixel.r, pixel.g, pixel.b)
  441.              end
  442.            else
  443.              local dx, dy = sx - x0, sy - y0
  444.              local u = a * dx + b * dy + u0
  445.              local v = c * dx + d * dy + v0
  446.              local srcX, srcY = math_floor(u + 0.5), math_floor(v + 0.5)
  447.              if srcX >= 1 and srcX <= imageWidth and srcY >= 1 and srcY <= imageHeight then
  448.                local pixel = floorImage.pixels[srcY][srcX]
  449.                color = mapColor256(pixel.r, pixel.g, pixel.b)
  450.              end
  451.            end
  452.            row[sx] = color
  453.          end
  454.          if sy % 10 == 0 then os_queueEvent("yield") os_pullEvent("yield") end
  455.        end
  456.        local effectIdx = math_floor((frame / (SWITCH_PERIOD * FPS)) % numEffects) + 1
  457.        local effectFn = SCANIMATE_EFFECTS[effectIdx]
  458.        local spriteX = math_floor(pxw / 2 - spriteImage.width / 2)
  459.        local baseY = math_floor(pxh * 0.45 - spriteImage.height / 2)
  460.        blitSpriteScanimate(back, spriteImage, spriteX, baseY, frame, effectFn)
  461.        local text1 = "this is possible on CC"
  462.        local text2 = "thanks to nonogamer9"
  463.        local framePeriod = 18
  464.        local amplitude1 = 4
  465.        local amplitude2 = 2
  466.        local phaseStep1 = 0.3
  467.        local phaseStep2 = 0.5
  468.        local scale1 = 1
  469.        local scale2 = 1
  470.        local text1width = #text1 * FONT_OUT_W * scale1
  471.        local text2width = #text2 * FONT_OUT_W * scale2
  472.        local text1x = math_floor((pxw - text1width) / 2)
  473.        local text2x = math_floor((pxw - text2width) / 2)
  474.        local text1y = math_floor(pxh * 0.75)
  475.        local text2y = text1y + FONT_OUT_H * scale1 + 2
  476.        drawTextHalfResWave(back, fontImage, text1, text1x, text1y, frame, amplitude1, framePeriod, phaseStep1, scale1)
  477.        drawTextHalfResWave(back, fontImage, text2, text2x, text2y, frame, amplitude2, framePeriod, phaseStep2, scale2)
  478.        front, back = swapBuffers(front, back)
  479.        blitBuffer(front, output)
  480.        os_queueEvent("yield")
  481.        os_pullEvent("yield")
  482.      end
  483.    end,
  484.    waitForEnter
  485.  )
  486.  setGM(origGM)
  487.  restorePalette(origPalette)
  488.  term_setBackgroundColor(origBG)
  489.  term_setTextColor(origFG)
  490.  term_clear()
  491.  term_setCursorPos(1, 1)
  492. end
  493. if not fs.exists(FLOOR_BMP_FILE) then downloadContent(FLOOR_BMP_URL, FLOOR_BMP_FILE, "floor image") end
  494. if not fs.exists(SPRITE_BMP_FILE) then downloadContent(SPRITE_BMP_URL, SPRITE_BMP_FILE, "sprite image") end
  495. if not fs.exists(PCM1_FILE) then downloadContent(PCM1_URL, PCM1_FILE, "music1 audio") end
  496. if not fs.exists(PCM2_FILE) then downloadContent(PCM2_URL, PCM2_FILE, "music2 audio") end
  497. if not fs.exists(FONT_BMP_FILE) then downloadContent(FONT_BMP_URL, FONT_BMP_FILE, "font image") end
  498. local floorImage, err1 = readBMP(FLOOR_BMP_FILE)
  499. if not floorImage then print("Error reading floor BMP:", err1) return end
  500. local spriteImage, err2 = readBMP(SPRITE_BMP_FILE)
  501. if not spriteImage then print("Error reading sprite BMP:", err2) return end
  502. local fontImage, fontErr = readBMP(FONT_BMP_FILE)
  503. if not fontImage then print("Error reading font BMP:", fontErr) return end
  504. local scaledSprite = scaleSprite(spriteImage, SPRITE_SCALE)
  505. parallel.waitForAny(
  506.  playPCMsAlternating,
  507.  function() displayMode7WithSpriteForever(floorImage, scaledSprite, fontImage, term, mode7_floor()) end
  508. )
  509.  
Add Comment
Please, Sign In to add comment