Skip to content

Instantly share code, notes, and snippets.

@nurpax
Last active July 29, 2019 22:10
Show Gist options
  • Star 0 You must be signed in to star a gist
  • Fork 0 You must be signed in to fork a gist
  • Save nurpax/ee11f06ed117031a784066d7850acb04 to your computer and use it in GitHub Desktop.
Save nurpax/ee11f06ed117031a784066d7850acb04 to your computer and use it in GitHub Desktop.
c64jasm content example in a gist
!let FALSE = 0
!let TRUE = 1
; Basic starter macro that needs to be the first emitted
; code in your main assembly source file.
!macro basic_start(addr) {
* = $801
!byte $0c
!byte $08
!byte $00
!byte $00
!byte $9e
!if (addr >= 10000) {
!byte $30 + (addr/10000)%10
}
!if (addr >= 1000) {
!byte $30 + (addr/1000)%10
}
!if (addr >= 100) {
!byte $30 + (addr/100)%10
}
!if (addr >= 10) {
!byte $30 + (addr/10)%10
}
!byte $30 + addr % 10
!byte 0, 0, 0
}
;------------------------------------------------------------------------
; IRQ setup macros
!macro setup_irq(irq_addr, irq_line) {
lda #$7f
sta $dc0d
sta $dd0d
lda #<irq_addr
ldx #>irq_addr
sta $fffe
stx $ffff
lda #$01
sta $d01a
lda #irq_line
sta $d012
!if (irq_line > 255) {
!error "this macro doesn't support setting the 9th bit of irq line"
}
lda $d011
and #$7f
sta $d011
asl $d019
bit $dc0d
bit $dd0d
}
!macro end_irq(next_irq_addr, next_irq_line, irq_line_hi) {
asl $d019
lda #<next_irq_addr
sta $fffe
lda #>next_irq_addr
sta $ffff
lda #next_irq_line
sta $d012
!if (irq_line_hi) {
lda $d011
ora #$80
sta $d011
} else {
lda $d011
and #$7f
sta $d011
}
}
!macro irq_start(end_lbl) {
sta end_lbl-6
stx end_lbl-4
sty end_lbl-2
}
!macro irq_end(next, line) {
+end_irq(next, line, FALSE)
lda #$00
ldx #$00
ldy #$00
rti
}
; C64jasm example program
;
; see https://github.com/nurpax/c64jasm for more
!include "macros.asm"
; Import plugins. These are just .js files. The path
; names are relative to the source file that !use's them.
!use "math" as math
!use "petscii" as petscii
!use "spd" as spd
!use "sid" as sid
; Load a PETSCII file exported into .json by Petmate.
; The petscii loader will RLE compress the screencodes
; and colors to save some RAM.
!let petscii_background = petscii.rlePetsciiJson("pipes-pet.json")
!let pacman_spd = spd("pacman.spd")
!let music = sid("Load_Line.sid")
!let irq_top_line = 10
!let SIN_LEN = 64
!let SINX_LEN = 256
!let debug_build = FALSE
!let zptmp0 = $20
+basic_start(entry)
;--------------------------------------------------------------
; Execution starts here
;--------------------------------------------------------------
entry: {
lda #0
jsr music.init
sei
lda #$35 ; Bank out kernal and basic
sta $01 ; $e000-$ffff
+setup_irq(irq_top, irq_top_line)
cli
; Decompress a PETSCII image on the display
lda #0
sta $d020
sta $d021
lda #<background_petscii_rle
ldx #>background_petscii_rle
jsr pet_rle::decode
frame_loop:
; wait for vsync by polling the framecount that's inc'd
; by the raster IRQ
lda framecount
vsync:
cmp framecount
beq vsync
!if (debug_build) {
inc $d020
}
jsr text_color_cycle
jsr animate_sprites
jsr set_sprite_regs
!if (debug_build) {
dec $d020
}
jmp frame_loop
}
animate_sprites: {
!let xanimptr = zptmp0 + 2
!let sidx = zptmp0 + 4
; sine animate sprites (y-coord)
lda #0
tay
sta zptmp0
anim_sprites:
lda framecount
clc
adc zptmp0
and #SIN_LEN-1
tax
lda sintab, x
clc
adc #142
sta sprite_ypos, y
lda zptmp0
clc
adc #5 ; no clc needed
sta zptmp0
iny
cpy #8
bne anim_sprites
; animate sprites (x-coord)
; just ping-pong motion which turned out
; to be a lot of code and RAM.. patches are welcome ;)
lda #0
sta sidx
sta zptmp0
anim_sprites_x:
lda framecount
clc
adc zptmp0
; xanimptr = (framecount+zptmp0)<<1
sta xanimptr
lda #0
sta xanimptr+1
lda xanimptr
asl
sta xanimptr+0
rol xanimptr+1
; xanimptr += xanim_tbl
clc
adc #<xanim_tbl
sta xanimptr+0
lda xanimptr+1
adc #>xanim_tbl
sta xanimptr+1
ldy #0
ldx sidx
lda (xanimptr), y
sta sprite_xpos+0, x
iny
lda (xanimptr), y
sta sprite_xpos+1, x
lda zptmp0
clc
adc #15
sta zptmp0
txa
clc
adc #2
sta sidx
cmp #8*2
bne anim_sprites_x
rts
}
; Set sprites to hardware
set_sprite_regs: {
!let xcoord = zptmp0
!let x9bit = zptmp0 + 2
!let sidx = zptmp0 + 4
lda #0
sta $d01d ; no double width
sta $d017 ; no double height
lda #%11111111 ; all 8 sprites multicolor
sta $d01c ; single color sprites
lda #sprite_data/64
ldx #sprite_data2/64
!for i in range(4) {
stx $07f8+i*2 ; sprite ptr
sta $07f8+i*2+1 ; sprite ptr
}
; Set the pacman multicolor sprite multicolor bits
lda #pacman_spd.multicol1
sta $d025
lda #pacman_spd.multicol2
sta $d026
lda #0
sta sidx
sta x9bit
xloop:
lda sidx
asl
tax
lda sprite_xpos + 0, x
sta xcoord
lda sprite_xpos + 1, x
sta xcoord+1
lda xcoord ; x coord
sta $d000, x
ldy sidx
lda sprite_ypos, y
sta $d001, x
lda sprite_color, y
sta $d027, y
; work out 9th bit of sprite x-coord
lda xcoord+1
and #1
beq lt256
ldx sidx
lda x9bit
ora shift_lut, x
sta x9bit
lt256:
inc sidx
cpy #7
bne xloop
; Enable all sprites
lda #%11111111
sta $d015
lda x9bit
sta $d010
rts
shift_lut:
!for i in range(8) {
!byte 1<<i
}
}
text_color_cycle: {
!let zx1 = zptmp0
!let zx2 = zptmp0+1
lda framecount
lsr
lsr
sta zx1
; rotate the bottom row in reverse direction
lda #0
sec
sbc zx1
sta zx2
ldx #0
cycle:
lda zx1
and #7
tay
lda colors1, y
sta $d800+40, x
lda zx2
and #7
tay
lda colors2, y
sta $d800+23*40, x
inc zx1
inc zx2
inx
cpx #40
bne cycle
rts
colors1: !byte 11, 12, 15, 1, 1, 15, 12, 11
colors2: !byte 6, 14, 3, 1, 1, 3, 14, 6
}
irq_top: {
+irq_start(end)
inc framecount
jsr music.play
+irq_end(irq_top, irq_top_line)
end:
}
framecount: !byte 0
sprite_xpos: !fill 8*2, 0 ; word
sprite_ypos: !fill 8, 0 ; byte
sprite_color: !byte 3, 10, 3, 9, 3, 2, 3, 14
!let sinvals = math.sintab(SIN_LEN, 30)
sintab:
!for v in sinvals {
!byte v
}
xanim_tbl:
!for v in range(128) { !word (v*2-128) + 344/2 }
!for v in range(128) { !word 344/2 - (v*2-128) }
* = music.startAddress ; most sids will go to $1000
sid_data: !byte music.data
* = $2000
sprite_data:
!byte pacman_spd.data[0] ; shape: data[num_sprites][64]
sprite_data2:
!byte pacman_spd.data[1] ; shape: data[num_sprites][64]
!include "pet_rle.asm"
; Expand the RLE compressed PETSCII bytes
background_petscii_rle: !byte petscii_background.interleaved
module.exports = {
sintab: ({}, len, scale) => {
const res = Array(len).fill(0).map((v,i) => Math.round(Math.sin(i/len * Math.PI * 2.0) * scale));
return res;
}
}
!filescope pet_rle
; Name some zero page addresses for use in the below decoder
!let z_src = $20
!let z_y = $22
!let z_scr_dst = $24
!let z_len = $26
!let z_scrdst = $28
!let z_coldst = $2a
; A = lo src
; X = hi src
decode: {
sta z_src
stx z_src+1
lda #25
sta z_y
lda #0
sta z_scrdst
sta z_coldst
lda #>$0400
sta z_scrdst+1
lda #>$d800
sta z_coldst+1
yloop:
ldy #0 ; RLE source index within line
lda z_scrdst
sta decode_line::dst-2
lda z_scrdst+1
sta decode_line::dst-1
jsr decode_line
lda z_coldst
sta decode_line::dst-2
lda z_coldst+1
sta decode_line::dst-1
jsr decode_line
tya
clc
adc z_src
sta z_src
lda z_src+1
adc #0
sta z_src+1
; advance screen dest ptr
lda z_scrdst ; no CLC needed
adc #40
sta z_scrdst
lda z_scrdst+1
adc #0
sta z_scrdst+1
lda z_coldst ; no CLC needed
adc #40
sta z_coldst
lda z_coldst+1
adc #0
sta z_coldst+1
dec z_y
bne yloop
rts
decode_line: {
ldx #0 ; dest index
xloop:
lda (z_src), y ; run-length
sta z_len
iny
lda (z_src), y ; screen code
iny
blit:
sta $1234, x ; $0400 screen
dst:
inx
dec z_len
bne blit
cpx #40
bne xloop
rts
}
}
function groupSame(values) {
let cur = undefined;
let out = [];
for (let v of values) {
// Start new run
if (cur !== v) {
cur = v;
out.push({code: cur, count: 1});
} else {
// Keep growing current group
out[out.length-1].count++;
}
}
return out;
}
module.exports = {
rlePetsciiJson: (ctx, filename) => {
const { readFileSync, resolveRelative } = ctx;
const json = JSON.parse(readFileSync(resolveRelative(filename)));
const fb = json.framebufs[0];
const { width, height } = fb;
const colors = [];
const screencodes = [];
const interleaved = [];
for (let y = 0; y < height; y++) {
const screen = groupSame(fb.screencodes.slice(y*width, (y+1)*width));
const rowScr = screen.flatMap(g => [g.count, g.code]);
// TODO pack colors to 8 bit two pix packets
const color = groupSame(fb.colors.slice(y*width, (y+1)*width));
const rowCol = color.flatMap(g => [g.count, g.code]);
screencodes.push(...rowScr);
colors.push(...rowCol);
interleaved.push(...rowScr);
interleaved.push(...rowCol);
}
return {
screencodes,
colors,
interleaved
}
}
}
/*
function test() {
const fs = require('fs')
const loader = fname => module.exports.rlePetsciiJson({readFileSync:fs.readFileSync, resolveRelative:(f) => f}, fname);
const r = loader('src/assets/phys-bg2.json');
console.log(JSON.stringify(r, null, 2));
}
test();
*/
{"version":1,"framebufs":[{"width":40,"height":25,"backgroundColor":0,"borderColor":11,"charset":"upper","name":"screen_002","screencodes":[32,32,32,32,32,32,32,32,32,32,32,32,32,32,32,32,32,32,32,32,32,32,32,32,32,32,32,32,32,32,32,32,32,32,32,32,32,32,32,32,32,32,32,32,32,32,32,32,32,32,32,32,32,32,32,32,32,32,32,32,32,32,32,32,32,32,32,32,32,32,32,32,32,32,32,32,32,32,32,32,32,32,32,32,32,32,32,32,32,32,32,32,32,32,32,32,32,32,32,32,32,32,32,32,32,32,32,32,32,32,32,32,32,32,32,32,32,32,32,32,32,32,32,32,32,32,32,32,32,32,32,32,32,32,32,32,32,32,32,32,32,32,32,32,32,32,32,32,32,32,32,32,32,32,32,32,32,32,32,32,32,32,32,32,32,32,32,32,32,32,32,32,32,32,32,32,32,32,32,32,32,32,32,32,32,32,32,32,32,32,32,32,32,32,32,32,32,32,32,32,32,32,32,32,32,32,32,32,32,160,160,160,160,32,32,32,32,32,32,32,32,32,32,32,32,32,32,160,160,160,160,32,32,32,32,32,32,32,32,32,32,32,32,32,32,32,32,160,160,160,160,160,160,160,160,32,32,32,32,32,32,32,32,32,32,160,160,160,160,160,160,160,160,32,32,32,32,32,32,32,32,32,32,32,32,32,160,160,160,160,160,160,160,160,160,160,32,32,32,32,32,32,32,32,160,160,160,160,160,160,160,160,160,160,32,32,32,32,32,32,32,32,32,32,32,160,160,160,160,160,160,160,160,160,160,160,160,32,32,32,32,32,32,160,160,160,160,160,160,160,160,160,160,160,160,32,32,32,32,32,32,32,32,32,32,160,160,160,160,160,160,160,160,160,160,160,160,32,32,32,32,32,32,160,160,160,160,160,160,160,160,160,160,160,160,32,32,32,32,32,32,32,32,32,32,160,160,160,160,160,160,160,160,160,160,160,160,32,32,32,32,32,32,160,160,160,160,160,160,160,160,160,160,160,160,32,32,32,32,32,32,32,32,32,160,160,160,160,160,160,160,160,160,160,160,160,160,160,32,32,32,32,160,160,160,160,160,160,160,160,160,160,160,160,160,160,32,32,32,32,32,32,32,32,160,160,160,160,160,160,160,160,160,160,160,160,160,160,32,32,32,32,160,160,160,160,160,160,160,160,160,160,160,160,160,160,32,32,32,32,32,32,32,32,160,160,160,160,160,160,160,160,160,160,160,160,160,160,32,32,32,32,160,160,160,160,160,160,160,160,160,160,160,160,160,160,32,32,32,32,32,32,32,32,160,160,160,160,160,160,160,160,160,160,160,160,160,160,32,32,32,32,160,160,160,160,160,160,160,160,160,160,160,160,160,160,32,32,32,32,32,32,32,32,160,160,160,160,160,160,160,160,160,160,160,160,160,160,32,32,32,32,160,160,160,160,160,160,160,160,160,160,160,160,160,160,32,32,32,32,32,32,32,32,160,160,160,160,160,160,160,160,160,160,160,160,160,160,32,32,32,32,160,160,160,160,160,160,160,160,160,160,160,160,160,160,32,32,32,32,32,32,32,32,160,160,32,160,160,160,32,32,160,160,160,32,160,160,32,32,32,32,160,160,32,160,160,160,32,32,160,160,160,32,160,160,32,32,32,32,32,32,32,32,160,32,32,32,160,160,32,32,160,160,32,32,32,160,32,32,32,32,160,32,32,32,160,160,32,32,160,160,32,32,32,160,32,32,32,32,32,32,32,32,32,32,32,32,32,32,32,32,32,32,32,32,32,32,32,32,32,32,32,32,32,32,32,32,32,32,32,32,32,32,32,32,32,32,32,32,32,32,32,32,32,32,32,32,32,32,32,32,32,32,32,32,32,32,32,32,32,32,32,32,32,32,32,32,32,32,32,32,32,32,32,32,32,32,32,32,32,32,32,32,32,32,32,32,32,32,32,32,32,32,32,32,32,32,32,32,32,32,32,32,32,32,32,32,32,32,32,32,32,32,32,32,32,32,32,32,32,32,32,32,32,32,32,32,32,32,32,32,32,32,32,32,32,32,32,32,32,32,32,32,32,32,32,32,32,32,32,32,32,32,32,32,32,32,32,32,32,32,32,32,32,32,32,32,32,32,32,32,32,32,32,32,32,32,32,32,32,32,32,32,32,32,32,32,32,32,32,32,32,32,32,32,32,32,32,32,32,32,32,32,32,32,32,32,32,32,32,32,32,32,32,32,32,32,32,32,32,32,32,32,32,32,32,32,32,32,32,32,32,32,32,32,32,32,32,32],"colors":[14,14,14,14,14,14,14,14,14,14,14,14,14,14,14,14,14,14,14,14,14,14,14,14,14,14,14,14,14,14,14,14,14,14,14,14,14,14,14,14,14,14,14,14,14,14,14,14,14,14,14,14,14,14,14,14,14,14,14,14,14,14,14,14,14,14,14,14,14,14,14,14,14,14,14,14,14,14,14,14,14,14,14,14,14,14,14,14,14,14,14,14,14,14,14,14,14,14,14,14,14,14,14,14,14,14,14,14,14,14,14,14,14,14,14,14,14,14,14,14,14,14,14,14,14,14,14,14,14,14,14,14,14,14,14,14,14,14,14,14,14,14,14,14,14,14,14,14,14,14,14,14,14,14,14,14,14,14,14,14,14,14,14,14,14,14,14,14,14,14,14,14,14,14,14,14,14,14,14,14,14,14,14,14,14,14,14,14,14,14,14,14,14,14,14,14,14,14,14,14,14,14,14,14,14,14,14,14,14,5,5,5,5,14,14,14,14,14,14,14,14,14,14,14,14,14,14,2,2,2,2,14,14,14,14,14,14,14,14,14,14,14,14,14,14,14,14,5,5,5,5,5,5,5,5,14,14,14,14,14,14,14,14,14,14,2,2,2,2,2,2,2,2,14,14,14,14,14,14,14,14,14,14,14,14,14,5,5,5,5,5,5,5,5,5,5,14,14,14,14,14,14,14,14,2,2,2,2,2,2,2,2,2,2,14,14,14,14,14,14,14,14,14,14,14,5,1,1,5,5,5,5,1,1,5,5,5,14,14,14,14,14,14,2,1,1,2,2,2,2,1,1,2,2,2,14,14,14,14,14,14,14,14,14,14,1,1,1,1,5,5,1,1,1,1,5,5,14,14,14,14,14,14,1,1,1,1,2,2,1,1,1,1,2,2,14,14,14,14,14,14,14,14,14,14,6,6,1,1,5,5,6,6,1,1,5,5,14,14,14,14,14,14,6,6,1,1,2,2,6,6,1,1,2,2,14,14,14,14,14,14,14,14,14,5,6,6,1,1,5,5,6,6,1,1,5,5,5,14,14,14,14,2,6,6,1,1,2,2,6,6,1,1,2,2,2,14,14,14,14,14,14,14,14,5,5,1,1,5,5,5,5,1,1,5,5,5,5,14,14,14,14,2,2,1,1,2,2,2,2,1,1,2,2,2,2,14,14,14,14,14,14,14,14,5,5,5,5,5,5,5,5,5,5,5,5,5,5,14,14,14,14,2,2,2,2,2,2,2,2,2,2,2,2,2,2,14,14,14,14,14,14,14,14,5,5,5,5,5,5,5,5,5,5,5,5,5,5,14,14,14,14,2,2,2,2,2,2,2,2,2,2,2,2,2,2,14,14,14,14,14,14,14,14,5,5,5,5,5,5,5,5,5,5,5,5,5,5,14,14,14,14,2,2,2,2,2,2,2,2,2,2,2,2,2,2,14,14,14,14,14,14,14,14,5,5,5,5,5,5,5,5,5,5,5,5,5,5,14,14,14,14,2,2,2,2,2,2,2,2,2,2,2,2,2,2,2,14,14,14,14,14,14,14,5,5,14,5,5,5,14,14,5,5,5,14,5,5,14,14,14,14,2,2,2,2,2,2,2,2,2,2,2,2,2,2,2,14,14,14,14,14,14,14,5,14,14,14,5,5,14,14,5,5,14,14,14,5,14,14,14,14,2,2,2,2,2,2,14,2,2,2,2,14,14,2,14,14,14,14,14,14,14,14,14,14,14,14,14,14,14,14,14,14,14,14,14,14,14,14,14,14,2,14,14,14,2,14,14,2,2,14,14,14,14,14,14,14,14,14,14,14,14,14,14,14,14,14,14,14,14,14,14,14,14,14,14,14,14,14,14,14,14,14,14,14,14,14,14,14,14,14,14,14,14,14,14,14,14,14,14,14,14,14,14,14,14,14,14,14,14,14,14,14,14,14,14,14,14,14,14,14,14,14,14,14,14,14,14,14,14,14,14,14,14,14,14,14,14,14,14,14,14,14,14,14,14,14,14,14,14,14,14,14,14,14,14,14,14,14,14,14,14,14,14,14,14,14,14,14,14,14,14,14,14,14,14,14,14,14,14,14,14,14,14,14,14,14,14,14,14,14,14,14,14,14,14,14,14,14,14,14,14,14,14,14,14,14,14,14,14,14,14,14,14,14,14,14,14,14,14,14,11,11,14,14,14,14,14,14,14,14,14,14,14,14,14,14,14,14,14,14,14,14,14,14,14,14,14,14,14,14,14,14,14,14,14,14,14,14]}]}
{"version":1,"framebufs":[{"width":40,"height":25,"backgroundColor":0,"borderColor":0,"charset":"upper","name":"screen_003","screencodes":[32,32,32,32,32,32,32,32,32,32,32,32,32,32,32,32,32,32,32,32,32,32,32,32,32,32,32,32,32,32,32,32,32,32,32,32,32,32,32,32,32,32,32,32,32,32,32,32,32,32,20,8,5,32,3,25,2,5,18,32,16,15,19,19,5,32,49,57,56,57,32,32,32,32,32,32,32,32,32,32,32,32,32,32,32,32,32,32,32,32,32,32,32,32,32,32,32,32,32,32,32,32,32,32,32,32,32,32,32,32,32,32,32,32,32,32,32,32,32,32,32,247,98,98,98,98,98,98,98,98,98,98,247,32,247,98,98,98,98,98,98,98,98,98,98,247,32,247,98,98,98,98,98,98,98,98,98,98,247,32,32,160,160,160,160,160,160,160,160,160,160,160,160,32,160,160,160,160,160,160,160,160,160,160,160,160,32,160,160,160,160,160,160,160,160,160,160,160,160,32,32,160,160,160,160,160,160,160,160,160,160,160,160,32,160,160,160,160,160,160,160,160,160,160,160,160,32,160,160,160,160,160,160,160,160,160,160,160,160,32,32,121,121,121,121,121,121,121,121,121,121,121,121,32,121,121,121,121,121,121,121,121,121,121,121,121,32,121,121,121,121,121,121,121,121,121,121,121,121,32,32,120,32,32,32,32,32,32,32,32,32,32,120,32,120,32,32,32,32,32,32,32,32,32,32,120,32,120,32,32,32,32,32,32,32,32,32,32,120,32,32,32,32,32,32,32,32,32,32,32,32,32,32,32,32,32,32,32,32,32,32,32,32,32,32,32,32,32,32,32,32,32,32,32,32,32,32,32,160,160,32,32,32,32,32,32,32,32,32,32,32,32,32,32,32,32,32,32,32,32,32,32,32,32,32,32,32,32,32,32,32,32,32,32,32,32,32,32,160,32,32,32,32,32,32,32,32,32,32,32,32,32,32,32,32,32,32,32,32,32,32,32,32,32,32,32,32,32,32,32,32,32,108,252,123,32,32,160,32,32,32,32,32,226,226,226,226,226,226,32,226,32,32,32,32,32,32,32,32,32,32,32,32,32,32,32,32,32,32,32,32,108,213,201,160,123,32,160,32,32,32,32,32,225,160,160,160,160,102,32,97,32,32,32,32,32,32,32,32,32,32,32,32,32,32,32,32,32,32,32,108,160,202,203,160,160,123,160,32,32,32,32,32,225,160,160,160,160,102,32,97,32,32,32,32,32,32,32,32,32,32,32,32,32,32,32,32,32,32,32,160,215,160,160,213,201,160,160,32,32,32,32,32,225,160,160,160,160,102,32,97,32,32,32,32,32,32,32,32,32,32,32,32,32,32,32,32,32,32,32,160,160,160,160,202,203,160,160,32,32,32,32,32,225,160,160,160,160,102,32,97,32,32,32,32,32,32,32,32,32,32,32,32,32,32,32,32,32,32,32,124,160,160,160,160,160,126,160,32,32,32,32,32,225,160,160,160,160,102,32,97,32,32,32,32,32,32,32,32,32,32,32,32,32,32,32,32,32,32,32,32,32,254,160,123,32,32,160,32,32,32,32,32,225,160,160,160,160,102,32,97,32,32,32,32,32,32,32,32,32,32,32,32,32,32,32,32,32,32,32,32,32,251,160,126,32,32,160,32,32,32,247,98,98,98,98,98,98,98,98,98,98,247,32,247,98,98,98,98,98,98,98,98,98,98,247,32,247,98,98,98,98,98,98,98,98,98,98,247,32,32,160,160,160,160,160,160,160,160,160,160,160,160,32,160,160,160,160,160,160,160,160,160,160,160,160,32,160,160,160,160,160,160,160,160,160,160,160,160,32,32,160,160,160,160,160,160,160,160,160,160,160,160,32,160,160,160,160,160,160,160,160,160,160,160,160,32,160,160,160,160,160,160,160,160,160,160,160,160,32,32,121,121,121,121,121,121,121,121,121,121,121,121,32,121,121,121,121,121,121,121,121,121,121,121,121,32,121,121,121,121,121,121,121,121,121,121,121,121,32,32,120,32,32,32,32,32,32,32,32,32,32,120,32,120,32,32,32,32,32,32,32,32,32,32,120,32,120,32,32,32,32,32,32,32,32,32,32,120,32,32,32,32,32,32,32,32,3,1,12,12,32,15,21,18,32,8,17,32,43,51,53,56,32,48,32,53,53,53,32,49,50,51,32,32,32,32,32,32,32,32,32,32,32,32,32,32,32,32,32,32,32,32,32,32,32,32,32,32,32,32,32,32,32,32,32,32,32,32,32,32,32,32,32,32,32,32,32,32,32],"colors":[14,14,14,14,14,14,14,14,14,14,14,14,14,14,14,14,14,14,14,14,14,14,14,14,14,14,14,14,14,14,14,14,14,14,14,14,14,14,14,14,14,14,14,14,14,14,14,14,14,14,1,12,11,11,1,12,11,11,11,11,1,12,11,11,11,11,1,12,11,11,14,14,14,14,14,14,14,14,14,14,14,14,14,14,14,14,14,14,14,14,14,14,14,14,14,14,14,14,14,14,14,14,14,14,14,14,14,14,14,14,14,14,14,14,14,14,14,14,14,14,14,14,14,14,14,14,14,14,14,14,14,14,14,14,14,14,14,14,14,14,14,14,14,14,14,14,14,14,14,14,14,14,14,14,14,14,14,14,14,14,14,1,1,1,1,1,1,1,1,1,1,1,1,14,1,1,1,1,1,1,1,1,1,1,1,1,14,1,1,1,1,1,1,1,1,1,1,1,1,14,14,1,14,14,14,14,14,14,14,14,14,14,1,14,1,14,14,14,14,14,14,14,14,14,14,1,14,1,14,14,14,14,14,14,14,14,14,14,1,14,14,6,6,6,6,6,6,6,6,6,6,6,6,14,6,6,6,6,6,6,6,6,6,6,6,6,14,6,6,6,6,6,6,6,6,6,6,6,6,14,14,6,14,14,14,14,14,14,14,14,14,14,6,14,6,14,14,14,14,14,14,14,14,14,14,6,14,6,14,14,14,14,14,14,14,14,14,14,6,14,14,14,14,14,14,14,14,14,14,14,14,14,14,14,14,14,14,14,14,14,14,14,14,14,14,14,14,14,14,14,14,14,14,14,14,14,14,14,0,0,14,14,14,14,14,14,14,14,14,2,2,14,14,14,14,14,14,14,14,14,14,14,14,2,14,14,14,14,14,14,14,14,14,14,14,14,14,14,0,14,14,14,14,14,14,14,14,14,14,14,14,14,14,14,14,14,14,14,14,14,14,14,2,2,14,14,14,14,14,14,14,14,10,10,10,2,2,0,2,14,14,14,14,5,13,1,13,5,5,14,5,14,14,14,14,14,14,14,14,14,14,14,14,14,14,14,14,14,14,14,14,10,10,10,10,2,14,0,14,14,14,14,14,5,13,1,13,5,5,14,5,14,14,14,14,14,14,14,14,14,14,14,14,14,14,14,14,14,14,14,10,10,10,10,10,2,2,0,14,14,14,14,6,5,13,1,13,5,5,14,5,14,14,14,14,14,14,14,14,14,14,14,14,14,14,14,14,14,14,14,10,10,10,10,2,2,2,0,14,14,14,14,14,5,13,1,13,5,5,14,5,14,14,14,14,14,14,14,14,14,14,14,14,14,14,14,14,14,14,14,10,10,10,2,2,2,2,0,14,14,14,14,14,5,13,1,13,5,5,14,5,14,14,14,14,14,14,14,14,14,14,14,14,14,14,14,14,14,14,14,10,2,2,2,2,2,2,0,14,14,14,14,14,5,13,1,13,5,5,14,5,14,14,14,14,14,14,14,14,14,14,14,14,14,14,14,14,14,14,14,14,14,1,15,15,14,14,0,14,14,14,14,14,5,13,1,13,5,5,14,5,14,14,14,14,14,14,14,14,14,14,14,14,14,14,14,14,14,14,14,14,14,1,1,15,14,14,0,14,14,14,14,14,14,14,14,14,14,14,14,14,14,14,14,14,14,14,14,14,14,14,14,14,14,14,14,14,14,14,14,14,14,14,14,14,14,14,14,14,14,14,1,1,1,1,1,1,1,1,1,1,1,1,14,1,1,1,1,1,1,1,1,1,1,1,1,14,1,1,1,1,1,1,1,1,1,1,1,1,14,14,1,14,14,14,14,14,14,14,14,14,14,1,14,1,14,14,14,14,14,14,14,14,14,14,1,14,1,14,14,14,14,14,14,14,14,14,14,1,14,14,6,6,6,6,6,6,6,6,6,6,6,6,14,6,6,6,6,6,6,6,6,6,6,6,6,14,6,6,6,6,6,6,6,6,6,6,6,6,14,14,6,14,14,14,14,14,14,14,14,14,14,6,14,6,14,14,14,14,14,14,14,14,14,14,6,14,6,14,14,14,14,14,14,14,14,14,14,6,14,14,14,14,14,14,14,14,1,3,14,14,14,1,3,14,14,1,3,14,1,3,14,14,14,1,14,1,3,14,14,1,3,14,14,14,14,14,14,14,14,14,14,14,14,14,14,14,14,14,14,14,14,14,14,14,14,14,14,14,14,14,14,14,14,14,14,14,14,14,14,14,14,14,14,14,14,14,14,14,14]}]}
function readWord(buf, offs) {
return buf.readUInt8(offs) + (buf.readUInt8(offs+1) << 8);
}
function readWordBE(buf, offs) {
return (buf.readUInt8(offs)<<8) + buf.readUInt8(offs+1);
}
module.exports = ({readFileSync, resolveRelative}, filename) => {
const buf = readFileSync(resolveRelative(filename));
const version = readWordBE(buf, 4);
const dataOffset = readWordBE(buf, 6);
const startAddress = readWord(buf, dataOffset);
const init = readWordBE(buf, 0x0a);
const play = readWordBE(buf, 0x0c);
const numSongs = readWord(buf, 0x0e);
const res = {
startAddress,
data: [...buf.slice(dataOffset+2)],
init: startAddress,
play: startAddress + 3
}
return res;
}
module.exports = ({readFileSync, resolveRelative}, filename) => {
const buf = readFileSync(resolveRelative(filename));
const numSprites = buf.readUInt8(4)+1;
const data = [];
for (let i = 0; i < numSprites; i++) {
const offs = i*64+9;
const bytes = [];
for (let j = 0; j < 64; j++) {
bytes.push(buf.readUInt8(offs + j));
}
data.push(bytes);
}
return {
numSprites,
enableMask: (1<<numSprites)-1,
bg: buf.readUInt8(6),
multicol1: buf.readUInt8(7),
multicol2: buf.readUInt8(8),
data
};
}
Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment