0,]']±>Sï}WÿÍu§ðp8·d%qy)6o;]ÉA¦ösï÷ôôô”°ÂVl†3= 60 then limiter.elapsed = 0 return false end limiter.elapsed = limiter.elapsed + timer.delta if limiter.elapsed < 1 / fps then return true end limiter.elapsed = 0 return false end -- title: core_pcx -- author: Olympian / Spectrox -- desc: n/a -- site: https://github.com/olymp14n -- license: CC0 1.0 Universal -- version: 1.0 -- script: lua -- references: -- [1] https://www.fileformat.info/format/pcx/egff.htm -- [2] https://moddingwiki.shikadi.net/wiki/PCX_Format ------------------------------------------------------------------------------- --- PCX ------------------------------------------------------------------------------- --- Decode PCX data. --- @param data PCX data. Must have 4 bits per pixel for a maximum of 16 colors. --- @return table function core_pcx_decode(data) local id = data[1] if id ~= 0xa then error("Invalid PCX data!") end local bpp = data[4] if bpp ~= 4 then error("PCX data must have 4 bits per pixel!") end local w = data[10] << 8 | data[9] + 1 local h = data[12] << 8 | data[11] + 1 local bpl = data[68] << 8 | data[67] -- Number of undecoded bytes per line. -- Read palette. local pal = {} -- Start at byte 17 for a total length of 48 bytes. for i = 17, 64 do table.insert(pal, data[i]) end -- Read pixel data. local tmp = {} -- Decoded pixel data. Still contains potential line padding. local i = 129 -- Start of pixel data. while i <= #data do local count = 0 local value = 0 if ((data[i] & 0xc0) == 0xc0) then count = data[i] & 0x3f i = i + 1 value = data[i] else count = 1 value = data[i] end for j = 1, count do table.insert(tmp, value >> 4) table.insert(tmp, value & 0xf) end i = i + 1 end -- Final decoded pixel data. local decoded = {} -- Transfer pixel data to final buffer while skipping padding bytes. -- `bpl` is the number of undecoded bytes. Every byte contains two color indexes. for j = 1, #tmp, 2 * bpl do for k = 0, 2 * bpl do if k < w then table.insert(decoded, tmp[j + k]) end end end return { width = w, height = h, width_1 = w - 1, height_1 = h - 1, width_half = w // 2, height_half = h // 2, palette = pal, pixels = decoded } end -- title: core_pal -- author: Olympian / Spectrox -- desc: n/a -- site: https://github.com/olymp14n -- license: CC0 1.0 Universal -- version: 1.0 -- script: lua -- references: -- [1] https://github.com/nesbox/TIC-80/wiki/palette -- [2] https://github.com/nesbox/TIC-80/wiki/Sample-RGB-Color-RAM-Address ------------------------------------------------------------------------------- --- PAL ------------------------------------------------------------------------------- local ADR_PALETTE = 0x3FC0 local ADR_PALETTE_MAP = 0x3FF0 local ADR_PALETTE_MAP_2 = ADR_PALETTE_MAP * 2 --- Apply color palette. --- @param pal Palette of 16 colors. Array of 48 bytes in RGB layout. function core_pal_apply(pal) for i = 1, #pal do poke(ADR_PALETTE + i - 1, pal[i]) end end function core_pal_grab() local pal = {} for i = 1, 48 do pal[i] = peek(ADR_PALETTE + i - 1) end return pal end function core_pal_apply_color(index, r, g, b) local off = ADR_PALETTE + index * 3 poke(off, r) poke(off + 1, g) poke(off + 2, b) end function core_pal_set_color(pal, index, r, g, b) local i = (index - 1) * 3 + 1 pal[i] = r pal[i + 1] = g pal[i + 2] = b end function core_pal_swap(index, color) poke4(ADR_PALETTE_MAP_2 + index, color) end function core_pal_mix(srcPal1, srcPal2, dstPal, p) for i = 1, #srcPal1 do dstPal[i] = srcPal1[i] + p * (srcPal2[i] - srcPal1[i]) end end function core_pal_apply_mix(srcPal1, srcPal2, p) p = p < 0 and 0 or p p = p > 1 and 1 or p local dstPal = {} core_pal_mix(srcPal1, srcPal2, dstPal, p) core_pal_apply(dstPal) end function core_pal_apply_white_fade(srcPal, p) p = p < 0 and 0 or p p = p > 1 and 1 or p local dstPal = {} for i = 1, #srcPal do dstPal[i] = srcPal[i] + p * (255 - srcPal[i]) end core_pal_apply(dstPal) end function core_pal_apply_black_fade(srcPal, p) p = p < 0 and 0 or p p = p > 1 and 1 or p local dstPal = {} for i = 1, #srcPal do dstPal[i] = srcPal[i] * (1 - p) end core_pal_apply(dstPal) end -- title: core_image -- author: Olympian / Spectrox -- desc: n/a -- site: https://github.com/olymp14n -- license: CC0 1.0 Universal -- version: 1.0 -- script: lua ------------------------------------------------------------------------------- --- IMAGE ------------------------------------------------------------------------------- function core_image_new(w, h, palette, pixels) return { width = w, height = h, width_1 = w - 1, height_1 = h - 1, width_half = w // 2, height_half = h // 2, palette = palette, pixels = pixels } end function core_image_crop(image, x, y, w, h) local pixels = {} for iy = y, y + h - 1 do for ix = x, x + w - 1 do table.insert(pixels, image.pixels[ix + iy * image.width + 1]) end end return core_image_new(w, h, image.palette, pixels) end function core_image_scale(image, s) local pixels = {} local sw = (image.width * s) // 1 local sh = (image.height * s) // 1 local sf = 1 / s for iy = 0, sh - 1 do local my = (sf * iy) // 1 local stride = my * image.width + 1 for ix = 0, sw - 1 do local mx = (sf * ix) // 1 pixels[ix + iy * sw + 1] = image.pixels[stride + mx] end end return core_image_new(sw, sh, image.palette, pixels) end function core_image_get(image, x, y) return image.pixels[x + y * image.width + 1] end function core_image_from_canvas(x, y, w, h) local pixels = {} for iy = y, y + h - 1 do for ix = x, x + w - 1 do table.insert(pixels, pix(ix, iy)) end end return core_image_new(w, h, nil, pixels) end -- title: core_sprite -- author: Olympian / Spectrox -- desc: n/a -- site: https://github.com/olymp14n -- license: CC0 1.0 Universal -- version: 1.0 -- script: lua ------------------------------------------------------------------------------- --- SPRITE ------------------------------------------------------------------------------- --- Define a sprite in a TIC-80 sprite sheet. --- @param page any 0 or 1. --- @param col any 0-based. --- @param row any 0-based. --- @param sprW any Composite sprite: number of horizontal 8x8 sprites. --- @param sprH any Composite sprite: number of vertical 8x8 sprites. --- @param colorTransparent any --- @param imgW any Total height of (composite) sprites in pixels. --- @param imgH any Total width of (composite) sprite in pixels. --- @return table function core_sprite_def(page, col, row, sprW, sprH, colorTransparent, imgW, imgH) return { idx = col + row * 16 + page * 256, col = col, row = row, sprW = sprW, sprH = sprH, bgCol = colorTransparent, imgW = imgW, imgH = imgH, imgW_1 = imgW - 1, imgH_1 = imgH - 1, imgW_half = imgW // 2, imgH_half = imgH // 2 } end --- Transfer a 128x128 image to a sprite sheet page. --- @param img any Image data. --- @param page any Sprite sheet page (0 or 1). function core_sprite_transfer_sheet(img, page) if img.width ~= 128 or img.height ~= 128 then error("Spritesheet dimension must be 128x128!") end local off = 256 * page for iy = 0, 15 do for ix = 0, 15 do core_sprite_transfer(img, ix * 8, iy * 8, off + ix + iy * 16) -- 16 is the number of sprites per row in TIC-80 memory. end end end function core_sprite_transfer(img, x, y, sprIdx) -- One sprite is 8x8 pixels. Every pixel is half a byte. So 8x8/2 = 32 = << 5. local sprAdr = 0x4000 + (sprIdx << 5) local off = 0 local cl, cr for iy = y, y + 7 do for ix = x, x + 7, 2 do cl = core_image_get(img, ix, iy) cr = core_image_get(img, ix + 1, iy) poke(sprAdr + off, cr << 4 | cl) off = off + 1 end end end --- Set a pixel in a 8x8 sprite. --- There are 16x16 sprites on one sheet. --- @param sprIdx any Sprite index. There are 8 sprites in the first row (indexes 0..15). The first sprite on the second sheet has index 16*16+0 = 256. --- @param x any Relative X position within the sprite, so from 0..7 --- @param y any Relative Y position within the sprite, so from 0..7 --- @param color any Pixel color to set. function core_sprite_pix(sprIdx, x, y, color) local sprAdr = 0x4000 + (sprIdx << 5) + (x >> 1) + (y << 2) local old = peek(sprAdr) poke(sprAdr, x & 1 == 0 and (old & 0xf0) | color or (old & 0x0f) | color << 4) end -- title: core_anim -- author: Olympian / Spectrox -- desc: n/a -- site: https://github.com/olymp14n -- license: CC0 1.0 Universal -- version: 1.0 -- script: lua ------------------------------------------------------------------------------- --- ANIM ------------------------------------------------------------------------------- local CoreAnimState = { INITIALIZED = 0, RUNNING = 1, COMPLETED = 2, } local CoreAnimKeyframeType = { TWEEN = 0, FIRE_ONCE = 1, NOP = 2, } function core_anim_process_keyframe_nop(keyframe, timeOffset, timer) local keyTimeStart = keyframe.timeStart + timeOffset if not keyframe.isCompleted and timer.elapsed >= keyTimeStart then keyframe.isCompleted = true end end function core_anim_process_keyframe_fire_once(keyframe, timeOffset, timer) local keyTimeStart = keyframe.timeStart + timeOffset if not keyframe.isCompleted and timer.elapsed >= keyTimeStart then keyframe.isCompleted = true keyframe.started_proc(timer) end end function core_anim_process_keyframe_tween(keyframe, timeOffset, timer) local keyTimeStart = keyframe.timeStart + timeOffset local keyTimeEnd = keyframe.timeEnd + timeOffset if (timer.elapsed >= keyTimeEnd) then for j = 1, #keyframe.value do keyframe.value[j] = keyframe.to[j] end keyframe.isCompleted = true goto continue end if (timer.elapsed >= keyTimeStart and timer.elapsed < keyTimeEnd) then local p = (timer.elapsed - keyTimeStart) / (keyTimeEnd - keyTimeStart) p = keyframe.easing_func(p) for j = 1, #keyframe.value do keyframe.value[j] = keyframe.from[j] + p * (keyframe.to[j] - keyframe.from[j]) end end ::continue:: end function core_anim_process_keyframes(keyframes, timeOffset, timer) for i = 1, #keyframes do if keyframes[i].isCompleted then goto continue end if keyframes[i].type == CoreAnimKeyframeType.TWEEN then core_anim_process_keyframe_tween(keyframes[i], timeOffset, timer) elseif keyframes[i].type == CoreAnimKeyframeType.FIRE_ONCE then core_anim_process_keyframe_fire_once(keyframes[i], timeOffset, timer) else core_anim_process_keyframe_nop(keyframes[i], timeOffset, timer) end ::continue:: end end function core_anim_reset_keyframes(keyframes) for i = 1, #keyframes do keyframes[i].isCompleted = false end end function core_anim_start(anim, timer) core_anim_reset_keyframes(anim.keyframes) anim.state = CoreAnimState.RUNNING anim.timeStartedAt = timer.elapsed if anim.started_proc then anim.started_proc(anim, timer) end end function core_anim_process(anim, timer) if (anim.isAutostart and anim.state == CoreAnimState.INITIALIZED) then core_anim_start(anim, timer) end if (anim.state ~= CoreAnimState.RUNNING) then return end core_anim_process_keyframes(anim.keyframes, anim.timeStartedAt, timer) end function core_anim_is_completed(anim) for i = 1, #anim.keyframes do if not anim.keyframes[i].isCompleted then return false end end return true end function core_anim_handle_completed(anim, timer) if (anim.state == CoreAnimState.RUNNING and core_anim_is_completed(anim)) then anim.state = CoreAnimState.COMPLETED if anim.completed_proc then anim.completed_proc(anim, timer) end end end function core_anim_process_schedule(schedule, timer) for i = 1, #schedule.anims do core_anim_process(schedule.anims[i], timer) core_anim_handle_completed(schedule.anims[i], timer) end -- Make sure anims are being processed that have been started by an end listener in a previous anim. for i = 1, #schedule.anims do core_anim_process(schedule.anims[i], timer) end end function core_anim_new_keyframe_tween(timeStart, timeEnd, from, to, easing_func, value) return { type = CoreAnimKeyframeType.TWEEN, timeStart = timeStart, timeEnd = timeEnd, from = from, to = to, easing_func = easing_func, value = value, } end function core_anim_new_keyframe_fire_once(timeStart, started_proc) return { type = CoreAnimKeyframeType.FIRE_ONCE, timeStart = timeStart, started_proc = started_proc, } end function core_anim_new_keyframe_nop(timeStart, started_proc) return { type = CoreAnimKeyframeType.NOP, timeStart = timeStart, started_proc = started_proc, } end function core_anim_new(isAutostart, keyframes, started_proc, completed_proc) return { isAutostart = isAutostart, keyframes = keyframes, state = CoreAnimState.INITIALIZED, started_proc = started_proc, completed_proc = completed_proc, } end function core_anim_new_schedule() return { anims = {} } end --- Adds a new anim to the schedule. --- @param name Must be a integer value. Must result in sequential numeric indices starting at 1. function core_anim_add_anim(name, schedule, anim) schedule.anims[name] = anim end function core_anim_is_running(schedule, animName) return schedule.anims[animName].state == CoreAnimState.RUNNING end function core_anim_update_local_timer(schedule, animName, localTimer, globalTimer) localTimer.startMillis = globalTimer.startMillis localTimer.currentMillis = globalTimer.currentMillis localTimer.delta = globalTimer.delta localTimer.previousMillis = globalTimer.previousMillis localTimer.elapsed = globalTimer.elapsed - schedule.anims[animName].timeStartedAt end -- title: core_easing -- author: Olympian / Spectrox -- desc: n/a -- site: https://github.com/olymp14n -- license: CC0 1.0 Universal -- version: 1.0 -- script: lua -- references: -- [1] https://github.com/warrenm/AHEasing ------------------------------------------------------------------------------- --- EASING ------------------------------------------------------------------------------- local sin = math.sin local cos = math.cos local pow = math.pow --- Modeled after the line y = x function core_easing_lerp(p) return p end --- Modeled after the parabola y = x^2. function core_easing_quadratic_in(p) return p * p end --- Modeled after the parabola y = -x^2 + 2x. function core_easing_quadratic_out(p) return -(p * (p - 2)) end --- Modeled after the piecewise quadratic --- y = (1/2)((2x)^2) ; [0, 0.5) --- y = -(1/2)((2x-1)*(2x-3) - 1) ; [0.5, 1] function core_easing_quadratic_in_out(p) if p < .5 then return 2 * p * p else return (-2 * p * p) + (4 * p) - 1 end end --- Modeled after the overshooting cubic y = x^3-x*sin(x*pi) function core_easing_back_in(p) return p * p * p - p * sin(p * M_PI) end --- Modeled after overshooting cubic y = 1-((1-x)^3-(1-x)*sin((1-x)*pi)) function core_easing_back_out(p) local f = (1 - p) return 1 - (f * f * f - f * sin(f * M_PI)) end --- Modeled after the piecewise overshooting cubic function: --- y = (1/2)*((2x)^3-(2x)*sin(2*x*pi)) ; [0, 0.5) --- y = (1/2)*(1-((1-x)^3-(1-x)*sin((1-x)*pi))+1) ; [0.5, 1] function core_easing_back_in_out(p) if p < .5 then local f = 2 * p return .5 * (f * f * f - f * sin(f * M_PI)) else f = (1 - (2 * p - 1)); return .5 * (1 - (f * f * f - f * sin(f * M_PI))) + .5 end end function core_easing_bounce_in(p) return 1 - core_easing_bounce_out(1 - p) end function core_easing_bounce_out(p) if p < 4 / 11 then return (121 * p * p) / 16 elseif p < 8 / 11 then return (363 / 40 * p * p) - (99 / 10 * p) + 17 / 5 elseif p < 9 / 10 then return (4356 / 361 * p * p) - (35442 / 1805 * p) + 16061 / 1805 else return (54 / 5.0 * p * p) - (513 / 25 * p) + 268 / 25 end end --- Bounce only once. function core_easing_bounce_once_out(p) if p < 4 / 11 then return (121 * p * p) / 16 elseif p < 8 / 11 then return (363 / 40 * p * p) - (99 / 10 * p) + 17 / 5 else return 1 end end function core_easing_bounce_in_out(p) if p < .5 then return .5 * core_easing_bounce_in(p * 2) else return .5 * core_easing_bounce_out(p * 2 - 1) + .5 end end --- Modeled after the damped sine wave y = sin(13pi/2*x)*pow(2, 10 * (x - 1)) function core_easing_elastic_in(p) return sin(13 * M_PI_2 * p) * pow(2, 10 * (p - 1)) end --- Modeled after the damped sine wave y = sin(-13pi/2*(x + 1))*pow(2, -10x) + 1 function core_easing_elastic_out(p) return sin(-13 * M_PI_2 * (p + 1)) * pow(2, -10 * p) + 1 end --- Modeled after the piecewise exponentially-damped sine wave: --- y = (1/2)*sin(13pi/2*(2*x))*pow(2, 10 * ((2*x) - 1)) ; [0,0.5) --- y = (1/2)*(sin(-13pi/2*((2x-1)+1))*pow(2,-10(2*x-1)) + 2) ; [0.5, 1] function core_easing_elastic_in_out(p) if p < .5 then return .5 * sin(13 * M_PI_2 * (2 * p)) * pow(2, 10 * ((2 * p) - 1)) else return .5 * (sin(-13 * M_PI_2 * ((2 * p - 1) + 1)) * pow(2, -10 * (2 * p - 1)) + 2) end end --- Modeled after quarter-cycle of sine wave function core_easing_sine_in(p) return sin((p - 1) * M_PI_2) + 1 end --- Modeled after quarter-cycle of sine wave (different phase) function core_easing_sine_out(p) return sin(p * M_PI_2) end --- Modeled after half sine wave function core_easing_sine_in_out(p) return 0.5 * (1 - cos(p * M_PI)) end --- Modeled after the cubic y = x^3 function core_easing_cubic_in(p) return p * p * p end --- Modeled after the cubic y = (x - 1)^3 + 1 function core_easing_cubic_out(p) local f = (p - 1) return f * f * f + 1 end --- Modeled after the piecewise cubic --- y = (1/2)((2x)^3) ; [0, 0.5) --- y = (1/2)((2x-2)^3 + 2) ; [0.5, 1] function core_easing_cubic_in_out(p) if p < 0.5 then return 4 * p * p * p else local f = ((2 * p) - 2) return 0.5 * f * f * f + 1 end end --- Modeled after the exponential function y = 2^(10(x - 1)) function core_easing_exponential_in(p) return (p == 0) and p or pow(2, 10 * (p - 1)) end --- Modeled after the exponential function y = -2^(-10x) + 1 function core_easing_exponential_out(p) return (p == 1) and p or 1 - pow(2, -10 * p) end --- Modeled after the piecewise exponential --- y = (1/2)2^(10(2x - 1)) ; [0,0.5) --- y = -(1/2)*2^(-10(2x - 1))) + 1 ; [0.5,1] function core_easing_exponential_in_out(p) if p == 0 or p == 1 then return p end if p < .5 then return 0.5 * pow(2, (20 * p) - 10) else return -0.5 * pow(2, (-20 * p) + 10) + 1; end end -- title: core_sound -- author: Olympian / Spectrox -- desc: n/a -- site: https://github.com/olymp14n -- license: CC0 1.0 Universal -- version: 1.0 -- script: lua -- references: -- [1] "Sound State" in https://github.com/nesbox/TIC-80/wiki/RAM ------------------------------------------------------------------------------- --- SOUND ------------------------------------------------------------------------------- local ADR_SOUND_STATE_TRACK = 0x13FFC local ADR_SOUND_STATE_PATTERN = 0x13FFD local ADR_SOUND_STATE_ROW = 0x13FFE function core_sound_create_soundstate() return { track = -1, pattern = -1, row = -1, rowFired = -1 } end function core_sound_update(soundState) soundState.track = peek(ADR_SOUND_STATE_TRACK) soundState.pattern = peek(ADR_SOUND_STATE_PATTERN) soundState.row = peek(ADR_SOUND_STATE_ROW) end --- The same row is active for multiple frames. --- Make sure to only trigger actions once per row. function core_sound_fire(soundState) soundState.rowFired = soundState.row end function core_sound_not_fired(soundState) return soundState.rowFired ~= soundState.row end --- Sets up the track list to be played. ---@param tracks any List of tracks to be played in order. --- STRUCTURE: --- bank: The bank number starting at 0 --- track: The track number starting at 0 --- pattern: Number of the pattern to play. -1 for first pattern. --- row: Number of the row to play. -1 for first row. --- lastPattern: This is the last pattern of the track. -1 for default. --- lastRow: This is the last row of the lastPattern of the track. After this the track will be changed. -1 for default. --- EXAMPLE: --- {bank = 0, track = 1, pattern = -1, row = -1, lastPattern = -1, lastRow = -1} ---@return table function core_sound_create_tracklist(tracks) return { current = 0, tracks = tracks } end function core_sound_play(tracklist, isLooped) -- See "Sound State" in https://github.com/nesbox/TIC-80/wiki/RAM if peek(ADR_SOUND_STATE_TRACK) == 255 or ( peek(ADR_SOUND_STATE_PATTERN) == tracklist.tracks[tracklist.current].lastPattern and peek(ADR_SOUND_STATE_ROW) > tracklist.tracks[tracklist.current].lastRow ) then -- No track is playing (255) at the moment. -- Look up if a new track has to be started in the tracklist. if isLooped then tracklist.current = tracklist.current % #tracklist.tracks + 1 sync(16, tracklist.tracks[tracklist.current].bank) music(tracklist.tracks[tracklist.current].track, tracklist.tracks[tracklist.current].pattern, tracklist.tracks[tracklist.current].row, false) else tracklist.current = tracklist.current + 1 if (tracklist.current <= #tracklist.tracks) then sync(16, tracklist.tracks[tracklist.current].bank) music(tracklist.tracks[tracklist.current].track, tracklist.tracks[tracklist.current].pattern, tracklist.tracks[tracklist.current].row, false) end end end end function core_sound_stop() music() end RES_PCX_FONT = { 10,5,1,4,0,0,0,0,127,0,127,0,0,0,0,0, 0,0,0,255,0,255,255,0,255,255,0,255,255,0,255,255, 0,255,255,0,255,255,0,255,255,0,255,255,0,255,255,0, 255,255,0,255,255,0,255,255,0,255,255,0,255,255,0,255, 0,1,64,0,1,0,0,0,0,0,0,0,0,0,0,0, 0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0, 0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0, 0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0, 255,0,0,255,0,0,255,0,0,255,0,0,255,0,0,255, 0,0,255,0,0,255,0,0,255,0,0,255,0,0,255,0, 0,255,0,0,255,0,0,255,0,0,255,0,0,255,0,0, 196,0,193,255,204,0,194,240,194,0,194,240,194,0,193,255, 194,0,193,255,195,0,15,196,0,193,240,216,0,15,0,196, 0,193,255,203,0,195,15,0,15,194,255,0,15,193,255,193, 240,0,15,195,0,193,240,196,0,15,216,0,193,255,0,196, 0,193,255,203,0,15,0,15,0,15,194,255,0,15,193,255, 193,240,197,0,193,240,196,0,15,195,0,15,203,0,193,255, 193,240,198,0,15,193,240,0,209,0,194,240,194,0,193,255, 193,240,194,0,193,255,198,0,193,240,196,0,15,215,0,193, 255,194,0,196,0,193,255,204,0,15,195,0,15,202,0,15, 196,0,193,240,202,0,193,240,199,0,193,240,196,0,193,240, 194,0,240,0,193,240,207,0,255,0,0,255,0,0,195,255, 193,240,15,193,255,194,0,195,255,193,240,195,255,194,240,194, 0,193,240,195,255,193,240,195,255,193,240,195,255,193,240,195, 255,193,240,195,255,193,240,212,0,15,194,255,193,240,193,240, 194,0,193,240,0,15,197,0,193,240,195,0,194,240,194,0, 194,240,195,0,193,240,198,0,194,240,194,0,194,240,194,0, 193,240,0,15,193,240,209,0,15,194,0,193,240,193,240,194, 0,193,240,0,15,194,0,195,255,193,240,15,194,255,193,240, 195,255,193,240,195,255,193,240,195,255,193,240,195,0,193,240, 195,255,193,240,195,255,193,240,213,0,15,193,255,193,240,193, 240,194,0,193,240,0,15,194,0,193,240,198,0,193,240,195, 0,193,240,195,0,194,240,194,0,193,240,195,0,194,240,194, 0,193,240,195,0,193,240,0,15,193,240,210,0,15,194,0, 195,255,193,240,195,255,193,240,195,255,193,240,195,255,193,240, 195,0,193,240,195,255,193,240,195,255,193,240,195,0,193,240, 195,255,193,240,195,255,193,240,216,0,253,0,15,194,0,255, 0,0,255,0,0,196,0,195,255,193,240,195,255,0,195,255, 0,195,255,0,195,255,0,195,255,193,240,195,255,0,193,255, 0,15,193,240,193,255,197,0,15,193,240,193,255,0,193,255, 0,193,255,195,0,195,255,193,240,195,255,193,240,195,255,193, 240,0,15,193,240,0,193,255,0,15,193,240,193,255,0,193, 255,0,193,255,195,0,193,255,0,15,193,240,193,255,195,0, 193,255,195,0,193,255,195,0,193,255,0,15,193,240,193,255, 197,0,15,193,240,193,255,0,193,255,0,193,255,195,0,193, 255,194,15,193,240,193,255,0,15,193,240,193,255,0,15,193, 240,0,15,193,240,0,195,255,193,240,195,255,193,240,193,255, 195,0,193,255,0,15,193,240,194,255,193,240,0,194,255,193, 240,0,193,255,15,193,255,193,240,195,255,193,240,193,255,195, 0,193,255,0,15,193,240,195,255,193,240,193,255,195,0,193, 255,194,15,193,240,193,255,0,15,193,240,193,255,0,15,193, 240,196,0,193,255,0,15,193,240,193,255,0,15,193,240,193, 255,195,0,193,255,0,15,193,240,193,255,195,0,193,255,195, 0,193,255,0,15,193,240,193,255,0,15,193,240,193,255,195, 0,193,255,0,15,193,240,193,255,0,15,193,240,193,255,195, 0,193,255,0,15,193,240,193,255,0,15,193,240,193,255,0, 15,193,240,196,0,193,255,0,15,193,240,195,255,193,240,195, 255,193,240,195,255,193,240,195,255,193,240,193,255,195,0,195, 255,193,240,193,255,0,15,193,240,193,255,195,0,195,255,193, 240,193,255,0,15,193,240,195,255,193,240,193,255,0,15,193, 240,193,255,0,15,193,240,195,255,193,240,255,0,0,255,0, 0,255,0,0,195,255,193,240,195,255,193,240,195,255,0,195, 255,0,195,255,0,193,255,0,15,193,240,193,255,0,15,193, 240,193,255,0,15,193,240,193,255,0,15,193,240,193,255,0, 15,193,240,15,194,255,193,240,212,0,193,255,0,15,193,240, 193,255,0,15,193,240,193,255,0,193,255,0,193,255,196,0, 193,255,194,0,193,255,0,15,193,240,193,255,0,15,193,240, 193,255,0,15,193,240,193,255,0,15,193,240,193,255,0,15, 193,240,194,0,15,193,240,212,0,195,255,193,240,193,255,0, 15,193,240,195,255,193,240,195,255,193,240,0,193,255,194,0, 193,255,0,15,193,240,193,255,0,15,193,240,193,255,194,15, 193,240,15,194,255,0,195,255,193,240,195,255,193,240,212,0, 193,255,195,0,193,255,194,15,193,240,193,255,0,15,193,240, 194,0,15,193,240,0,193,255,194,0,193,255,0,15,193,240, 193,255,0,15,193,240,193,255,194,15,193,240,193,255,0,15, 193,240,194,0,15,193,240,193,255,215,0,193,255,195,0,195, 255,193,240,193,255,0,15,193,240,195,255,193,240,0,193,255, 194,0,195,255,193,240,195,255,0,195,255,193,240,193,255,0, 15,193,240,15,194,255,193,240,195,255,193,240,212,0,255,0, 0,255,0,0,255,0,0,196,0,195,255,193,240,195,255,193, 240,195,255,193,240,195,255,193,240,195,255,193,240,195,255,193, 240,195,255,194,240,194,0,193,240,195,255,193,240,195,0,194, 240,0,15,0,193,240,195,0,195,255,193,240,195,255,193,240, 195,255,193,240,196,0,193,240,194,0,194,240,194,0,194,240, 195,0,193,240,194,0,194,240,195,0,193,240,195,0,193,240, 195,0,193,240,194,0,193,240,0,15,197,0,194,240,0,15, 0,193,240,195,0,193,240,15,0,194,240,194,0,194,240,194, 0,193,240,196,0,195,255,193,240,195,255,0,193,240,195,0, 193,240,194,0,193,240,194,255,193,240,0,194,255,193,240,0, 193,240,194,255,193,240,195,255,193,240,0,15,197,0,193,240, 195,255,194,240,195,0,193,240,15,0,194,240,194,0,194,240, 194,0,193,240,196,0,193,240,194,0,194,240,194,0,194,240, 195,0,193,240,194,0,194,240,195,0,193,240,195,0,193,240, 194,0,194,240,194,0,193,240,0,15,194,0,193,240,194,0, 194,240,194,0,194,240,195,0,193,240,15,0,194,240,194,0, 194,240,194,0,193,240,196,0,193,240,194,0,193,240,195,255, 193,240,195,255,193,240,195,255,0,195,255,194,240,195,0,195, 255,194,240,194,0,193,240,195,255,193,240,195,255,194,240,194, 0,193,240,195,255,194,240,194,0,194,240,194,0,193,240,195, 255,193,240,255,0,0,255,0,0,255,0,0,195,255,193,240, 195,255,193,240,195,255,193,240,195,255,193,240,195,255,194,240, 194,0,194,240,194,0,194,240,194,0,193,240,15,0,15,0, 193,240,194,0,193,240,195,255,193,240,212,0,193,240,194,0, 194,240,194,0,194,240,194,0,194,240,196,0,15,194,0,193, 240,194,0,194,240,194,0,194,240,15,0,193,240,15,0,15, 0,193,240,194,0,193,240,195,0,193,240,212,0,195,255,194, 240,194,0,193,240,195,255,0,195,255,193,240,0,15,194,0, 193,240,194,0,194,240,194,0,194,240,15,0,193,240,195,255, 193,240,195,255,193,240,195,255,193,240,212,0,193,240,195,0, 193,240,0,195,240,194,0,193,240,195,0,193,240,0,15,194, 0,193,240,194,0,194,240,194,0,194,240,15,0,194,240,194, 0,193,240,0,15,194,0,193,240,215,0,193,240,195,0,195, 255,194,240,194,0,193,240,195,255,193,240,0,15,194,0,195, 255,193,240,195,255,0,195,255,194,240,194,0,193,240,0,15, 194,0,195,255,193,240,212,0,255,0,0,255,0,0,255,0, 0,255,0,0,255,0,0,255,0,0,255,0,0,255,0,0, 255,0,0,255,0,0,255,0,0,255,0,0,255,0,0,255, 0,0,255,0,0,255,0,0,255,0,0,255,0,0,255,0, 0,255,0,0,255,0,0,255,0,0,255,0,0,255,0,0, 255,0,0,255,0,0,255,0,0,255,0,0,255,0,0,255, 0,0,255,0,0,255,0,0,255,0,0,255,0,0,255,0, 0,255,0,0,255,0,0,255,0,0,255,0,0,255,0,0, 255,0,0,255,0,0,255,0,0,255,0,0,255,0,0,255, 0,0,255,0,0,255,0,0,255,0,0,255,0,0,255,0, 0,255,0,0,255,0,0,255,0,0,255,0,0,255,0,0, 255,0,0,255,0,0,255,0,0,255,0,0,255,0,0,255, 0,0,255,0,0,255,0,0,255,0,0,255,0,0,255,0, 0 } ------------------------------------------------------------------------------- --- VARIABLES ------------------------------------------------------------------------------- local _timer = core_timer_create() local _localTimer = {} local _tracklist = core_sound_create_tracklist({ { bank = 0, track = 1, pattern = -1, row = -1, lastPattern = -1, lastRow = -1 }, { bank = 0, track = 0, pattern = -1, row = -1, lastPattern = -1, lastRow = -1 }, { bank = 0, track = 2, pattern = -1, row = -1, lastPattern = -1, lastRow = -1 }, { bank = 0, track = 3, pattern = -1, row = -1, lastPattern = -1, lastRow = -1 }, { bank = 1, track = 0, pattern = -1, row = -1, lastPattern = -1, lastRow = -1 }, }) local _soundState = core_sound_create_soundstate() local _musicStarted = false local _imgFont ------------------------------------------------------------------------------- --- ANIM ------------------------------------------------------------------------------- -- Must be sequential numeric indices starting at 1. local AnimNames = { MAIN = 1, } local _schedule = core_anim_new_schedule() ------------------------------------------------------------------------------- --- MAIN ANIM _progressBarWidth = { 0 } function mainSceneStarted() _musicStarted = true end function mainSceneCompleted() exit() end core_anim_add_anim(AnimNames.MAIN, _schedule, core_anim_new(false, { core_anim_new_keyframe_tween(0, 6 * 60 + 3, { 0 }, { 240 }, core_easing_lerp, _progressBarWidth), }, mainSceneStarted, mainSceneCompleted )) ------------------------------------------------------------------------------- ------------------------------------------------------------------------------- --- INIT ------------------------------------------------------------------------------- function initFont() _imgFont = core_pcx_decode(RES_PCX_FONT) core_sprite_transfer_sheet(_imgFont, 1) end ------------------------------------------------------------------------------- --- EXECUTE ------------------------------------------------------------------------------- --- MAIN EXECUTE function renderText(x, y, col1, col2) core_pal_swap(15, col1) font("prelude to neobyte", x, y, 0, 10, 8, false, 1) core_pal_swap(15, col2) font("original soundtrack", x, y + 15, 0, 4, 8, false, 1) font("2025 by . . . . . . virgill", x, y + 25, 0, 4, 8, false, 1) core_pal_swap(15, 15) end function renderProgressbar() rect(0, 45, _progressBarWidth[1], 15, 1) rect(0, 46, _progressBarWidth[1], 1, 0) rect(0, 60, _progressBarWidth[1], 26, 9) rect(0, 62, _progressBarWidth[1], 1, 1) rect(0, 82, _progressBarWidth[1], 1, 8) rect(0, 84, _progressBarWidth[1], 1, 8) end function renderMainScene(t) cls(0) renderProgressbar() line(0, 59, 240, 59, 12) line(0, 60, 240, 60, 0) renderText(47, 51, 0, 0) renderText(46, 50, 12, 12) end ------------------------------------------------------------------------------- --- TIC FUNCTIONS ------------------------------------------------------------------------------- function BOOT() -- Hide mouse. -- poke(0x7FC3F, 1, 1) -- Border color poke(0x3FF8, 0) initFont() end -- Initial anim. _START_AT = AnimNames.MAIN _schedule.anims[_START_AT].isAutostart = true function TIC() core_timer_start(_timer) core_timer_update(_timer) core_anim_process_schedule(_schedule, _timer) if _musicStarted then core_sound_play(_tracklist, false) core_sound_update(_soundState) end if core_anim_is_running(_schedule, AnimNames.MAIN) then core_anim_update_local_timer(_schedule, AnimNames.MAIN, _localTimer, _timer) renderMainScene(_localTimer) end core_timer_update_global_frame_counter() end