Skip to content

Instantly share code, notes, and snippets.

@SelvinPL
Created September 16, 2024 21:58
Show Gist options
  • Select an option

  • Save SelvinPL/0c418956154f06573a00fc23e499ba72 to your computer and use it in GitHub Desktop.

Select an option

Save SelvinPL/0c418956154f06573a00fc23e499ba72 to your computer and use it in GitHub Desktop.
hike-gb
include "hardware.inc"
include "global.inc"
section "autotiler", ROM0
;;
; Draws a half-column in vicinity to the screen
; @param A column to draw (0-31)
blit_one_col_new::
local hThisColumnXAddr
local hAdjacentColumnXAddr
local hMtDefsLo
local hMtDefsHi
; register variables:
; DE = VRAM destination address
; C = vicinity row address
; Find the column being drawn
and SCRN_VX_B-1
ld e, a
ld d, high(_SCRN0)
rra
and MAP_VICINITY_WIDTH_MT-1
add high(wMapVicinity)
ldh [.hThisColumnXAddr], a
; Find the adjacent column for autotiling comparison.
; If the left half of the leftmost column is being drawn,
; use self. Otherwise, use the column to the left.
ld a, [wMapVicinityLeft]
or e
jr z, .haveAdjacentColumnWrappedX
ld a, e
rra
; decrease by 1 if NC or increase by 1 if C
dec a
jr nc, .adjacentColumnIsPrevious
add 2
.adjacentColumnIsPrevious:
and MAP_VICINITY_WIDTH_MT-1
.haveAdjacentColumnWrappedX:
add high(wMapVicinity)
ldh [.hAdjacentColumnXAddr], a
; Choose definitions of the left or right half of a metatile
; in order:
; $00 top left attribute, edge
; $01 bottom left attribute, edge
; $02 top left tile number, edge
; $03 bottom left tile number, edge
; $04 top left attribute, interior
; $05 bottom left attribute, interior
; $06 top left tile number, interior
; $07 bottom left tile number, interior
; $08 top right attribute, edge
; $09 bottom right attribute, edge
; $0A top right tile number, edge
; $0B bottom right tile number, edge
; $0C top right attribute, interior
; $0D bottom right attribute, interior
; $0E top right tile number, interior
; $0F bottom right tile number, interior
ld a, e
rra
sbc a ; 00: left, FF: right
and $08
add low(metatiles_defs)
ldh [.hMtDefsLo], a
ld a, 0
adc high(metatiles_defs)
ldh [.hMtDefsHi], a
ld c, low(wMapVicinity)
.blkloop:
; look up metatile number in vicinity
ldh a, [.hThisColumnXAddr]
ld b, a
ld a, [bc]
ld l, a
; Choose interior or edge variant of this metatile
ldh a, [.hAdjacentColumnXAddr]
ld b, a
ld a, [bc]
xor l ; A=$00: interior; nonzero: edge
; Translate metatile number to offset from metatile table start
ld h, 0
add hl, hl ; start at whatever left or right half is baked
; into hMtDefsLo
cp 1 ; CF=1: interior; CF=0: edge
rl l
rl h
add hl, hl ; start at top (vs. bottom)
add hl, hl ; start at attribute (vs. tile)
; Translate the offset into an address
ldh a, [.hMtDefsLo]
add l
ld l, a
ldh a, [.hMtDefsHi]
adc h
ld h, a
ld a, 1
ldh [rVBK], a ; prepare to write attribute
; wait for mode 0 or 1
.stat01loop_attr:
ldh a, [rSTAT]
and STATF_BUSY
jr nz, .stat01loop_attr
; write attributes (10 cycles hblank open)
ld a, [hl+]
ld [de], a
set 5, e
ld a, [hl+]
ld [de], a
res 5, e
inc c ; go to next row of vicinity
xor a
ldh [rVBK], a ; prepare to write tile number
; wait for mode 0 or 1
.stat01loop_tilenum:
ldh a, [rSTAT]
and STATF_BUSY
jr nz, .stat01loop_tilenum
; write tile numbers
ld a, [hl+]
ld [de], a
set 5, e
ld a, [hl+]
ld [de], a
; move destination address to next row
ld a, e
add SCRN_VX_B
ld e, a
adc d
sub e
ld d, a
cp high(_SCRN0 + MAP_COLUMN_HEIGHT_MT * MT_HEIGHT_CHARS * SCRN_VY_B)
jr c, .blkloop
ret
db $00,$3c,$3c,$42,$7e,$bb,$dd,$ff,$a1,$e0,$99,$7e,$42,$3c,$3c,$00,$18,$18,$24,$3c,$4a,$7e,$7e,$52,$c0,$4a,$7e,$24,$3c,$18,$18,$dc,$00,$18,$00,$cd,$00,$18,$18,$c0,$24,$3c,$5a,$7e,$7e,$5a,$80,$7a,$5a,$7e,$2c,$3c,$18,$18,$00,$3c,$3c,$42,$7e,$bf,$d9,$ff,$bd,$a0,$ed,$a5,$7e,$5a,$3c,$3c
db $00,$80,$80,$c0,$c0,$e0,$a0,$f0,$90,$00,$f8,$98,$f0,$d0,$b8,$a8,$18,$18,$00,$80,$80,$c0,$c0,$e0,$e0,$f0,$f0,$00,$f8,$f8,$f0,$f0,$b8,$b8,$18,$18,$3f,$00,$00,$ff,$ff,$ff
; Generated by vwfbuild
section "vwfChrData",ROM0,align[3] ; log2(glyph height) = 3
vwfChrData::
db 0, 0, 0, 0, 0, 0, 0, 0, 0,128,128,128,128, 0,128, 0
db 0,160,160, 0, 0, 0, 0, 0, 0, 80,248, 80,248, 80, 0, 0
db 0, 32,112,160, 96, 80,224, 64, 0,232,176,208, 44, 52, 92, 0
db 0, 32, 80, 96,152,144,104, 0, 0,128,128, 0, 0, 0, 0, 0
db 0, 64,128,128,128,128,128, 64, 0,128, 64, 64, 64, 64, 64,128
db 0, 32,168,112,168, 32, 0, 0, 0, 0, 32, 32,248, 32, 32, 0
db 0, 0, 0, 0, 0, 0,128,128, 0, 0, 0, 0,240, 0, 0, 0
db 0, 0, 0, 0, 0, 0,128, 0, 0, 16, 32, 32, 64, 64,128, 0
db 0, 96,144,144,144,144, 96, 0, 0, 96, 32, 32, 32, 32, 32, 0
db 0, 96,144, 16, 32, 64,240, 0, 0, 96,144, 32, 16,144, 96, 0
db 0, 16, 48, 80,144,248, 16, 0, 0,112,128,224, 16,144, 96, 0
db 0, 32, 64,224,144,144, 96, 0, 0,240, 16, 32, 32, 64, 64, 0
db 0, 96,144, 96,144,144, 96, 0, 0, 96,144,144,112, 32, 64, 0
db 0, 0, 0,128, 0, 0,128, 0, 0, 0, 0,128, 0, 0,128,128
db 0, 0, 16, 96,128, 96, 16, 0, 0, 0,240, 0, 0,240, 0, 0
db 0, 0,128, 96, 16, 96,128, 0, 0,224, 16, 96, 64, 0, 64, 0
db 0, 56, 68,154,170,170,158, 64, 0, 32, 80, 80, 80,248,136, 0
db 0,224,144,240,136,136,240, 0, 0,112,136,128,128,136,112, 0
db 0,240,136,136,136,136,240, 0, 0,240,128,240,128,128,240, 0
db 0,240,128,240,128,128,128, 0, 0,112,136,128,152,136,112, 0
db 0,136,136,248,136,136,136, 0, 0,224, 64, 64, 64, 64,224, 0
db 0, 16, 16, 16, 16,144, 96, 0, 0,136,144,160,224,144,136, 0
db 0,128,128,128,128,128,248, 0, 0, 68, 68,170,170,146,146, 0
db 0,136,200,168,168,152,136, 0, 0,112,136,136,136,136,112, 0
db 0,240,136,136,240,128,128, 0, 0,112,136,136,136,144,104, 0
db 0,240,136,136,240,144,136, 0, 0,112,136, 96, 16,136,112, 0
db 0,248, 32, 32, 32, 32, 32, 0, 0,136,136,136,136,136,112, 0
db 0,136,136, 80, 80, 32, 32, 0, 0,146,146,170,170, 68, 68, 0
db 0,136, 80, 32, 80,136,136, 0, 0,136, 80, 32, 32, 32, 32, 0
db 0,248, 16, 32, 64,128,248, 0, 0,192,128,128,128,128,128,192
db 0,128, 64, 64, 32, 32, 16, 0, 0,192, 64, 64, 64, 64, 64,192
db 0, 32, 80,136, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0,248
db 0,128, 64, 0, 0, 0, 0, 0, 0, 0,112,144,144,144,112, 0
db 0,128,224,144,144,144,224, 0, 0, 0, 96,144,128,128,112, 0
db 0, 16,112,144,144,144,112, 0, 0, 0, 96,144,240,128,112, 0
db 0, 32, 64,224, 64, 64, 64, 0, 0, 0,112,144,144,112, 16, 96
db 0,128,224,144,144,144,144, 0, 0,128, 0,128,128,128,128, 0
db 0,128, 0,128,128,128,128,128, 0,128,144,160,192,160,144, 0
db 0,128,128,128,128,128,128, 0, 0, 0,208,168,168,168,168, 0
db 0, 0,224,144,144,144,144, 0, 0, 0, 96,144,144,144, 96, 0
db 0, 0,224,144,144,224,128,128, 0, 0,112,144,144,112, 16, 16
db 0, 0,224,128,128,128,128, 0, 0, 0,112,128, 96, 16,224, 0
db 0, 64,224, 64, 64, 64, 64, 0, 0, 0,144,144,144,144, 96, 0
db 0, 0,144,144,144, 96, 96, 0, 0, 0,136,168,168, 80, 80, 0
db 0, 0,144,144, 96,144,144, 0, 0, 0,144,144, 96, 32, 64, 64
db 0, 0,240, 32, 64,128,240, 0, 0, 96, 64, 64,128, 64, 64, 96
db 0,128,128,128,128,128,128,128, 0,192, 64, 64, 32, 64, 64,192
db 0, 80,160, 0, 0, 0, 0, 0, 0, 0, 32, 80,136,136,248, 0
vwfChrWidths::
db 3, 2, 4, 6, 5, 7, 6, 2, 3, 3, 6, 5, 2, 5, 2, 5
db 5, 5, 5, 5, 5, 5, 5, 5, 5, 5, 2, 2, 5, 5, 5, 5
db 8, 6, 6, 6, 6, 5, 5, 6, 6, 4, 5, 6, 6, 8, 6, 6
db 6, 6, 6, 6, 6, 6, 6, 8, 6, 6, 6, 3, 5, 3, 6, 5
db 3, 5, 5, 5, 5, 5, 4, 5, 5, 2, 2, 5, 2, 6, 5, 5
db 5, 5, 4, 5, 4, 5, 5, 6, 5, 5, 5, 4, 2, 4, 5, 6
IF !DEF(GLOBAL_INC)
DEF GLOBAL_INC EQU 1
; call graph annotation ;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;
macro fallthrough
assert (\1) == @
endm
macro calls
endm
macro tailcalls
endm
macro jumptable
endm
macro local
endm
; for things still noet yet ported to SAVE
; http://gbdev.gg8.se/forums/viewtopic.php?pid=3176#p3176
DEF hLocals EQU $FF80
DEF locals_size EQU 16
; the width of the area that can affect autotiling of onscreen tiles
def MAP_VICINITY_WIDTH_MT equ 16
def MAP_COLUMN_HEIGHT_MT equ 16
def MT_WIDTH_CHARS equ 2
def MT_HEIGHT_CHARS equ 2
def TEXTWINDOW_ROWS equ 5
;;
; Syntax: drgb $FF9966 for color #FF9966
; Divides each hex tuplet by 8 and rounds down, forming an RGB555
; color word suitable for SNES/SGB or GBC/GBA/DS.
macro drgb
REPT _NARG
dw (\1 & $F80000) >> 19 | (\1 & $00F800) >> 6 | (\1 & $0000F8) << 7
shift 1
ENDR
endm
;;
; Syntax: lb rp, hivalue, lovalue
; Loads hivalue into the upper register of a pair (B, D, or H)
; and lovalue into the lower register of the same pair (C, E, or L).
macro lb
ld \1, low(\2) << 8 | low(\3)
endm
ENDC
include "hardware.inc"
include "global.inc"
section "stack", WRAM0, ALIGN[1]
wStackTop: ds 64
wStackStart:
section "header", ROM0[$100]
nop
jp init
ds 76, $00
init:
di
ld sp, wStackStart
xor $11
cp 1 ; Carry true if GBC or GBA, false for mono or SGB
sbc a
and $80
ldh [hCapability], a
call clear_gbc_attr
ld a, $FF
ldh [hCurKeys], a
ld hl, hramcode_LOAD
ld de, hramcode_RUN
call memcpy_pascal16
xor a
ldh [hVblanks], a
ld hl, wShadowOAM
ld c, 160
rst memset_tiny
call run_dma
jp main
section "memset_tiny",ROM0[$08]
;;
; Writes C bytes of value A starting at HL.
memset_tiny::
ld [hl+],a
dec c
jr nz,memset_tiny
ret
section "memset_inc",ROM0
;;
; Writes C bytes of value A, A+1, ..., A+C-1 starting at HL.
memset_inc::
ld [hl+],a
inc a
dec c
jr nz,memset_inc
ret
section "memcpy", ROM0
;;
; Copy a string preceded by a 2-byte length from HL to DE.
; @param HL source address
; @param DE destination address
memcpy_pascal16::
ld a, [hl+]
ld c, a
ld a, [hl+]
ld b, a
fallthrough memcpy
;;
; Copies BC bytes from HL to DE.
; @return A: last byte copied; HL at end of source;
; DE at end of destination; B=C=0
memcpy::
; Increment B if C is nonzero
dec bc
inc b
inc c
.loop:
ld a, [hl+]
ld [de],a
inc de
dec c
jr nz,.loop
dec b
jr nz,.loop
ret
section "HRAMCODE_src", ROM0
;;
; While OAM DMA is running, the CPU keeps fetching instructions
; while ROM and WRAM are inaccessible. A program needs to jump to
; HRAM and busy-wait 160 cycles until OAM DMA finishes.
hramcode_LOAD:
dw hramcode_RUN_end-hramcode_RUN
load "HRAMCODE", HRAM
hramcode_RUN:
;;
; Copy a display list from shadow OAM to OAM
; @param HL address to read once while copying is in progress
; @return A = value read from [HL]
run_dma::
ld a, wShadowOAM >> 8
ldh [rDMA],a
ld b, 40
.loop:
dec b
jr nz,.loop
ret
hramcode_RUN_end:
endl
include "hardware.inc"
include "global.inc"
def COINCELS_BASE_TILE equ $7B
; This number is added to wGlobalSubpixel every frame. It must be
; odd and should be close to 256 divided by a highly irrational
; number (lots of small terms in continued fraction representation)
; to mask repetition. Here we use 256 divided by the golden ratio,
; which is the most irrational number (see numberphile video).
def GLOBAL_SUBPIXEL_ADD equ 159
def STARTING_CURSOR_Y equ 64
def STARTING_CURSOR_X equ 64
def NUM_HIDDEN_OBJS equ 10
def PAGE_MINDY equ 9
def PAGE_FOUND_THEM_ALL equ 10
def PAGE_INSTRUCTIONS equ 11
export PAGE_INSTRUCTIONS
section "tilemapcol", WRAM0
wMapCol: ds MAP_COLUMN_HEIGHT_MT
section "mapdecodestate", WRAM0, ALIGN[1]
; A map consists of a bitmap and contents. The bitmap is an array
; of up to 256 u16 values, each representing one column, where a
; 1 bit in a particular position means the metatile there differs
; from the predicted metatile. The contents represent the (nonzero)
; metatile that replaces each predicted metatile.
wCameraY:: ds 1
wCameraX:: ds 2 ; pixel position (1/16 column) of camera
wMapVicinityLeft:: ds 1 ; left column of valid area of sliding window
wMapFetchedX: ds 1 ; Column corresponding to wMapCol
wMapDecodeX: ds 1 ; Column corresponding to wMapContentsPtr
wMapBitmapBase: ds 2 ; Pointer to the base of a map's bitmap
wMapContentsPtr: ds 2 ; Pointer to contents at column wMapDecodeX
wGlobalSubpixel: ds 1
wCursorY: ds 1
wCursorX: ds 2
wCursorYAdd: ds 1
wCursorXAdd: ds 1
wCursorItem: ds 1
section "seenpages", WRAM0
wSeenPages: ds NUM_HIDDEN_OBJS
def TEST_REWIND_COLUMN equ 4
section "main", ROM0
main::
call show_title
call clear_gbc_attr
ld de, static_tiles
call pb16_unpack_dest_length_block
call pb16_unpack_dest_length_block
call pb16_unpack_dest_length_block
; Set up initial map pointer
ld hl, wCameraY
ld a, 28
ld [hl+], a
assert wCameraX == wCameraY + 1
ld a, 10
ld [hl+], a
xor a
ld [hl+], a
assert wMapVicinityLeft == wCameraX + 2
ld [hl], a
ld hl, wMapDecodeX
ld [hl+], a
assert wMapBitmapBase == wMapDecodeX + 1
ld a, low(level1Bitmap)
ld [hl+], a
ld a, high(level1Bitmap)
ld [hl+], a
assert wMapContentsPtr == wMapBitmapBase + 2
ld a, low(level1Contents)
ld [hl+], a
ld a, high(level1Contents)
ld [hl+], a
assert wGlobalSubpixel == wMapContentsPtr + 2
xor a
ld [hl+], a
assert wCursorY == wGlobalSubpixel + 1
ld a, STARTING_CURSOR_Y
ld [hl+], a
assert wCursorX == wCursorY + 1
ld a, low(STARTING_CURSOR_X)
ld [hl+], a
ld a, high(STARTING_CURSOR_X)
ld [hl+], a
xor a
assert wCursorYAdd == wCursorX + 2
ld [hl+], a
ld [hl+], a
ld hl, wSeenPages
ld c, NUM_HIDDEN_OBJS
rst memset_tiny
call mindy_init
call textwindow_init
ld hl, wMapVicinity
call redraw_whole_screen
xor a
ldh [rIF], a
ld a, IEF_VBLANK
ldh [rIE], a
ei
ld a, 7
ldh [rWX], a
ld a, FRAME_Mindy_walk1
call mindy_set_cel_A
ld a, %11100100
ldh [rBGP], a
ld hl, metatiles_palettes
lb bc, MT_NUM_PALETTES * 8, low(rBCPS)
ld a, $80
call set_gbc_palette
.forever:
ld hl, wGlobalSubpixel
ld a, GLOBAL_SUBPIXEL_ADD
add [hl]
ld [hl], a
call read_pad
call move_cursor
call move_camera
call textwindow_update
xor a
ld [wOAMUsed], a
call draw_cursor
call draw_coins
call mindy_draw_current_cel
call lcd_clear_oam
ld a, LCDCF_ON|LCDCF_BGON|LCDCF_WINON|LCDCF_OBJON|LCDCF_WIN9C00|LCDCF_BG9800|LCDCF_BG8800
ldh [rLCDC], a
halt
call run_dma
ld a, %11100100
call set_obp1
ld a, [hVblanks]
rra
sbc a
and %00010000
or %10000000
call set_obp0
ld a, [wCameraX]
ldh [rSCX], a
ld a, [wCameraY]
ldh [rSCY], a
ld a, [wWindowProgress]
sub TEXTWINDOW_ROWS
add a ; CF true to hide window
sbc a
or SCRN_Y-TEXTWINDOW_ROWS * 8
ld [rWY], a
jr .forever
; Selection control ;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;
def CURSOR_TILE_NO_MATCH equ $70
def CURSOR_PIXELS_PER_PRESS equ 8
def MINDY_HITBOX_WIDTH equ 20
move_cursor:
ld a, $FF
ld [wCursorItem], a
; 1. control what to add
ld b, PADF_UP|PADF_DOWN|PADF_LEFT|PADF_RIGHT
call autorepeat
ldh a, [hNewKeys]
ld b, a
and PADF_UP|PADF_DOWN|PADF_LEFT|PADF_RIGHT
jr z, .no_cursor_movement
; check for individual directions
ld a, [wCursorYAdd]
bit PADB_DOWN, b
jr z, .notDown
add CURSOR_PIXELS_PER_PRESS
.notDown:
bit PADB_UP, b
jr z, .notUp
sub CURSOR_PIXELS_PER_PRESS
.notUp:
ld [wCursorYAdd], a
ld a, [wCursorXAdd]
bit PADB_RIGHT, b
jr z, .notRight
add CURSOR_PIXELS_PER_PRESS
.notRight:
bit PADB_LEFT, b
jr z, .notLeft
sub CURSOR_PIXELS_PER_PRESS
.notLeft:
ld [wCursorXAdd], a
; Moving the cursor shows the win notice if won;
; otherwise it closes the window.
ld hl, wSeenPages
.seenloop:
ld a, [hl+]
or a
jr z, .not_won_msg
ld a, l
xor low(wSeenPages + NUM_HIDDEN_OBJS)
jr nz, .seenloop
ld a, PAGE_FOUND_THEM_ALL
call textwindow_start_page
jr .no_cursor_movement
.not_won_msg:
ld a, $FF
ld [wWindowProgress], a
.no_cursor_movement:
ldh a, [hNewKeys]
bit PADB_SELECT, a
call nz, mindy_set_next_cel
; 2. move the cursor itself
ld hl, wCursorYAdd
ld b, [hl]
call divide_B_by_damping
ld c, a ; C: distance to move cursor
ld a, [hl] ; log these pixels as being used up
sub c
ld [hl], a
ld hl, wCursorY
ld a, [hl]
ld b, a ; B: previous position
add c
ld d, a ; D: new position
; check for wraparound based on carry from D-B
sub b ; CF: 1 if D>=B
rra ; A bit 7: 1 if D >= B
xor c ; A bit 7: 1 if wrapped
add a
jr nc, .have_Y_in_D
ld a, b
add a ; CF: sign of old position
sbc a ; A: 0 if was in top half or FF in bottom half
and 255 - 255 % CURSOR_PIXELS_PER_PRESS
ld d, a
.have_Y_in_D:
ld [hl], d
ld hl, wCursorXAdd
ld b, [hl]
call divide_B_by_damping
ld c, a
add a
sbc a
ld b, a ; BC: 16-bit distance to move cursor
ld a, [hl] ; log these pixels as being used up
sub c
ld [hl], a
ld hl, wCursorX
ld a, c
add [hl]
ld [hl+], a
ld a, b
adc [hl]
cp MAP_WIDTH_MT / 16
jr c, .have_X_hi_in_A
; bit 7 set if off left, or clear if off right
add a
ccf ; CF clear if at left, or set if off right
sbc a
ld b, a ; B = $FF at right, 0 at left
xor a
ld [wCursorXAdd], a
dec hl
ld a, 255 - 255 % CURSOR_PIXELS_PER_PRESS - CURSOR_PIXELS_PER_PRESS
and b
add CURSOR_PIXELS_PER_PRESS
ld [hl+], a
ld a, MAP_WIDTH_MT / 16 - 1
and b
.have_X_hi_in_A:
ld [hl], a
; now detect collision with coins and signs
ld a, [wCursorY]
and $F0
swap a
ld e, a ; E = Y coordinate in metatiles
ld a, [wCursorX]
ld d, a
ld a, [wCursorX+1]
xor d
and $0F ; keep low nibble of high byte and high nibble of low byte
xor d
swap a
ld d, a ; D = X coordinate in metatiles
ld hl, coin_pos
.coin_sign_loop:
ld a, [hl+] ; fetch X coordinate
cp d
jr nz, .not_this_coin_or_sign
ld a, [hl] ; fetch Y coordinate
and $0F ; skip priority bits
cp e
jr nz, .not_this_coin_or_sign
ld a, l
sub low(coin_pos)
srl a
jr .is_over_item_a
.not_this_coin_or_sign:
inc hl
ld a, l
xor low(coin_pos + 2 * (NUM_DEFINED_COINS + NUM_DEFINED_SIGNS))
jr nz, .coin_sign_loop
ld a, [wCursorX]
sub low(MINDY_X)
ld c, a
ld a, [wCursorX+1]
sbc high(MINDY_X)
ld b, a
sbc a
and OAMF_XFLIP
ld [wMindyFacing], a
; Face cursor
ld a, [wCursorY]
sub MINDY_Y
cp -24
jr c, .notOverMindy
ld a, MINDY_HITBOX_WIDTH/2
add c
ld c, a
adc b
sub c
jr nz, .notOverMindy
ld a, c
cp MINDY_HITBOX_WIDTH
jr nc, .notOverMindy
ld a, PAGE_MINDY
.is_over_item_a:
ld [wCursorItem], a
ld hl, hNewKeys
bit PADB_A, [hl]
ret z
; mark thing as seen
push af
ld hl, wSeenPages
add l
ld l, a
adc h
sub l
ld h, a
ld [hl], 1
pop af
jp textwindow_start_page
.notOverMindy:
ret
def CURSOR_DAMPING equ 2
;;
; Divides A by 2^CURSOR_DAMPING, rounding per wGlobalSubpixel
; @return A: rounded quotient; B: quotient rounded toward 0;
; C: wGlobalSubpixel
; DEHL unchanged
divide_by_damping:
ld b, a
fallthrough divide_B_by_damping
divide_B_by_damping:
ld a, [wGlobalSubpixel]
ld c, a
xor a
rept CURSOR_DAMPING
sra b
rra
endr
; BA: 1/256 pixels to add
add c
ld a, 0
adc b
ret
; Camera control ;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;
def CURSOR_MOVE_MAX equ 8 << CURSOR_DAMPING
move_camera:
; calculate vertical displacement
ld a, [wCursorY]
sub SCRN_Y/2
jr nc, .noYTopClip
xor a
.noYTopClip:
cp MAP_COLUMN_HEIGHT_MT * 16 - SCRN_Y
jr c, .noYBottomClip
ld a, MAP_COLUMN_HEIGHT_MT * 16 - SCRN_Y
.noYBottomClip:
ld hl, wCameraY
sub [hl]
; scroll by that amount
call divide_by_damping
add [hl]
ld [hl], a
; Don't update horizontally if window is being drawn
ld a, [wWindowProgress]
cp TEXTWINDOW_ROWS
ret c
; calculate horizontal displacement
ld hl, wCursorX
ld a, [hl+]
sub SCRN_X/2
ld c, a
ld a, [hl]
sbc 0
jr nc, .noXLeftClip
xor a
ld c, a
.noXLeftClip:
ld b, a
ld hl, wCameraX
ld a, c
sub [hl]
ld e, a
ld a, b
inc hl
sbc [hl] ; AE = displacement
dec hl
; clamp displacement to maximum
jr c, .clamp_x_neg
jr nz, .displacement_is_max_pos
ld a, e
cp CURSOR_MOVE_MAX
jr c, .have_x_dist
.displacement_is_max_pos:
ld a, CURSOR_MOVE_MAX
jr .have_x_dist
.clamp_x_neg:
inc a
jr nz, .displacement_is_max_neg
ld a, e
cp -CURSOR_MOVE_MAX
jr nc, .have_x_dist
.displacement_is_max_neg:
ld a, -CURSOR_MOVE_MAX
.have_x_dist:
; scroll by a fraction of that amount
call divide_by_damping
ld c, a
add a
sbc a
ld b, a ; BC = signed displacement
ld a, c
add [hl]
ld [hl+], a
ld a, b
adc [hl]
ld [hl], a
; Move map vicinity toward camera X
ld hl, wCameraX
ld a, [hl+]
ld h, [hl]
ld l, a
add hl, hl
add hl, hl
add hl, hl
add hl, hl ; H = camera X in map columns
ld a, h ; A = camera X in map columns
ld hl, wMapVicinityLeft
sub [hl]
; A is distance in whole metatiles from left edge of vicinity to
; left edge of camera
; [HL] is current left edge of camera
; <0 (CF=1): go left now
; 0: go left unless already 0
; 1: prepare to go left unless already 0
; >=MAP_VICINITY_WIDTH_MT-SCRN_X/16-1: go right unless at 240
; already 256-MAP_VICINITY_WIDTH_MT
jr c, .decode_to_left
jr z, .decode_to_left
cp 1
jr nz, .no_seek_toward_left
; if camera near left side of vicinity, prepare for decoding to left
ld a, [hl]
jp map_seek_column_a
.decode_to_left:
ld a, [hl]
or a
ret z ; do nothing if already at left side
call map_seek_column_a
call map_fetch_prev_bitmap_column
call map_fetch_col_backward
call map_decode_markov
call map_stash_decoded_col
; and draw them to the tilemap
ld hl, wMapFetchedX
ld a, [hl]
ld [wMapVicinityLeft], a
; draw columns 1 and 2, and draw column 0 if at far left
cp 1 ; CF=1 if at far left
ld a, 1
adc a
ld c, a ; 3 columns at far left, 2 columns elsewhere
rra
ccf ; CF=0 if at far left
ld a, [hl]
adc a
ld b, a
jp blit_c_columns
.no_seek_toward_left:
; A is still distance in MTs from vicinity left to camera left
cp MAP_VICINITY_WIDTH_MT-SCRN_X/16-2
jr z, .seek_toward_right
ret c
; Decode to right
ld a, [hl]
add MAP_VICINITY_WIDTH_MT
ret c ; do nothing if already at right side
inc [hl]
call map_seek_column_a
call map_fetch_bitmap_column
call map_fetch_col_forward
call map_decode_markov
call map_stash_decoded_col
; and draw them to the tilemap
ld hl, wMapFetchedX
ld a, 255
cp [hl] ; CF=1 if at far right
ld a, 1
adc a
ld c, a ; 3 columns at far right, 2 columns elsewhere
ld a, [hl]
add a
dec a ; Draw starting at right half of column to left of decoded
ld b, a
jp blit_c_columns
.seek_toward_right:
; if camera near right side of vicinity, prepare for decoding to right
ld a, [hl]
add MAP_VICINITY_WIDTH_MT
ret c
jp map_seek_column_a
if 0
debug_print_de:
ld d, d
jr .txtend
dw $6464
dw $0000
db "DE=%DE%;CF=%CARRY%"
.txtend:
ret
endc
redraw_whole_screen:
ld a, [wMapVicinityLeft]
call map_seek_column_a
ld b, MAP_VICINITY_WIDTH_MT
.decodeloop:
push bc
call map_fetch_bitmap_column
call map_fetch_col_forward
call map_decode_markov
call map_stash_decoded_col
pop bc
dec b
jr nz, .decodeloop
; The leftmost column is valid only if camera is at the far left.
ld a, [wMapVicinityLeft]
cp 1 ; CF = 1: at far left; 0: at next column
ld a, MAP_VICINITY_WIDTH_MT - 1
adc a
ld c, a ; C = number of columns to draw
rra
ccf ; CF = 0: at far left; 1: at next column
ld a, [wMapVicinityLeft]
adc a
ld b, a ; B = starting column
fallthrough blit_c_columns
;;
; Draws tile columns from vicinity to the screen.
; @param C count of tilemap columns (half vicinity columns)
; @param B first tilemap column to draw (0-31)
blit_c_columns:
.drawloop:
push bc
ld a, b
call blit_one_col_new
pop bc
inc b
dec c
jr nz, .drawloop
ret
; map decoding ;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;
;;
; Seeks to a column of the map.
; @param wMapDecodeX current column number
; @param A target column number
; @return wMapDecodeX equal to initial A; wMapContentsPtr adjusted
; by the size of skipped contents
map_seek_column_a:
ld hl, wMapDecodeX
sub [hl]
; A = number of forward steps to take modulo 256
; CF = true if negative
ret z
push af
call map_fetch_bitmap_column
ld a, [wMapContentsPtr+0]
ld e, a
ld a, [wMapContentsPtr+1]
ld d, a
; HL points to bitmap column; DE points to contents
pop af
ld b, a
jr c, .seek_backward
.seek_forward:
ld a, [wMapDecodeX]
add b
ld [wMapDecodeX], a
.seek_forward_loop:
; take B steps forward
ld a, [hl+]
call add_de_popcnt_a
ld a, [hl+]
call add_de_popcnt_a
dec b
jr nz, .seek_forward_loop
.writeback_de:
ld a, e
ld [wMapContentsPtr+0], a
ld a, d
ld [wMapContentsPtr+1], a
ret
.seek_backward:
ld a, [wMapDecodeX]
add b
ld [wMapDecodeX], a
.seek_backward_loop:
; take 256-B steps backward
dec hl
ld a, [hl-]
call sub_de_popcnt_a
ld a, [hl]
call sub_de_popcnt_a
inc b
jr nz, .seek_backward_loop
jr .writeback_de
add_de_popcnt_a:
add a
jr nc, .no_add
inc de
or a
.no_add:
jr nz, add_de_popcnt_a
ret
sub_de_popcnt_a:
add a
jr nc, .no_add
dec de
or a
.no_add:
jr nz, sub_de_popcnt_a
ret
;;
; Fetches a column from the overrides bitmap at X = wMapDecodeX
; @param wMapDecodeX index into wMapBitmapBase
; @return BC: list of bits to replace; HL: pointer to bitmap column
map_fetch_bitmap_column:
ld hl, wMapDecodeX
ld a, [hl+]
.have_col_a:
ld e, a
ld d, 0 ; DE = map decode X position
assert wMapBitmapBase == wMapDecodeX + 1
ld a, [hl+]
ld h, [hl]
ld l, a ; HL = base of map's Markov overrides bitmap
add hl, de
add hl, de ; HL = address of current column of overrides bitmap
ld a, [hl+]
ld c, a
ld a, [hl-]
ld b, a ; BC = column of overrides bitmap
ret
;;
; Fetches a column from the overrides bitmap at X = wMapDecodeX-1
map_fetch_prev_bitmap_column:
ld hl, wMapDecodeX
ld a, [hl+]
dec a
jr map_fetch_bitmap_column.have_col_a
;;
; Decodes one column of map metatile overrides from wMapContentsPtr
; to wMapCol. If wMapDecodeX isn't already $FF, it is incremented
; and the end address is written back to wMapContentsPtr.
; @param BC bitmap column
map_fetch_col_forward:
ld hl, wMapContentsPtr
ld a, [hl+]
ld h, [hl]
ld l, a
ld de, wMapCol
.fetchloop:
xor a
sla c
rl b
jr nc, .skip_map_fetch
ld a, [hl+]
.skip_map_fetch:
ld [de], a
inc de
ld a, e
xor low(wMapCol + MAP_COLUMN_HEIGHT_MT)
jr nz, .fetchloop
ld a, [wMapDecodeX]
ld [wMapFetchedX], a
inc a
ret z
ld [wMapDecodeX], a
ld a, l
ld [wMapContentsPtr+0], a
ld a, h
ld [wMapContentsPtr+1], a
ret
map_fetch_col_backward:
ld a, [wMapDecodeX]
dec a
ld [wMapFetchedX], a
ld [wMapDecodeX], a
ld hl, wMapContentsPtr
ld a, [hl+]
ld h, [hl]
ld l, a
dec hl
ld de, wMapCol + MAP_COLUMN_HEIGHT_MT - 1
.fetchloop:
xor a
srl b
rr c
jr nc, .skip_map_fetch
ld a, [hl-]
.skip_map_fetch:
ld [de], a
dec de
ld a, e
xor low(wMapCol - 1)
jr nz, .fetchloop
inc hl
ld a, l
ld [wMapContentsPtr+0], a
ld a, h
ld [wMapContentsPtr+1], a
ret
map_decode_markov:
ld hl, wMapCol
ld b, 16
.markovloop:
ld a, [hl]
or a
jr nz, .skip_markov
ld a, c
add low(metatiles_chains)
ld e, a
adc high(metatiles_chains)
sub e
ld d, a
ld a, [de]
.skip_markov:
ld [hl+], a
ld c, a
dec b
jr nz, .markovloop
ret
map_stash_decoded_col:
ld a, [wMapFetchedX]
and $0F
ld de, wMapVicinity
add d
ld d, a
ld hl, wMapCol
ld bc, MAP_COLUMN_HEIGHT_MT
jp memcpy
; Test level data ;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;
; stage 1
section "leveldata", ROM0
level1Bitmap:
dw %0000000010000000
dw %0000000010000000
dw %0000000010000000
dw %0000000010000000
dw %0000000010000000
dw %0000000010000000
dw %0001000100000000
dw %0001000010000000 ; Gravity barrier
dw %0001000000100000
dw %0000000000100000
dw %0000000001000000
dw %0000000000100000
dw %0000000001000000
dw %0000000000100000
dw %0000000001000000
dw %0000000000100000
dw %0000000001000000
dw %0000000010000000
dw %0000000001000000
dw %0000000100000000
dw %0000000100000000
dw %0000000001000000
dw %0000000001000000
dw %0000000010000000
dw %0000000001000000
dw %0000001001000000
dw %0000001001000000
dw %0000011001000000
dw %0000011001000000
dw %0000011001000000
dw %0000011010000000
dw %0000010001000000
dw %0000010000000000
dw %0000011000000000
dw %0000010000000000
dw %0001000000000000
dw %0110010010001000
dw %0110010010001000
dw %0000010010001000
dw %0000010010001000
dw %0000000000001000
dw %0000000000001000
dw %0000000000000000
dw %0000000000000000
dw %0000000000000000
dw %0000000000000000
dw %0000000000000000
dw %0000000000000000
dw %0000000000000000
dw %0000000000000000
dw %0000000000000000
dw %0000000000000000
dw %0000000010000000
dw %0000000010000000
dw %0000000010000000
dw %0000000010000000
dw %0000000010000000
dw %0000000010000000
dw %0000000010000000
dw %0000000010000000
dw %0000001000000000
dw %0000001000000000
dw %0000001000000000
dw %0000001000000000
def MAP_WIDTH_MT equ (@-level1Bitmap)/2
level1Contents:
db MT_GROUND
db MT_GROUND
db MT_GROUND
db MT_GROUND
db MT_GROUND
db MT_GROUND
db MT_CLOUD, MT_SIGN
db MT_CLOUD, MT_GROUND
db MT_CLOUD, MT_GROUND
db MT_GROUND
db MT_FLOWER1
db MT_GROUND
db MT_FLOWER2
db MT_GROUND
db MT_SIGN
db MT_GROUND
db MT_GROUND
db MT_SMBUSH
db MT_GROUND
db MT_BUSH
db MT_BUSH
db MT_GROUND
db MT_GROUND
db MT_FLOWER3
db MT_GROUND
db MT_LADDER, MT_GROUND
db MT_GROUND_0HT, MT_GROUND
db MT_BUSH, MT_GROUND_0HT, MT_GROUND
db MT_BUSH, MT_GROUND_0HT, MT_GROUND
db MT_SIGN, MT_GROUND_0HT, MT_GROUND
db MT_BRIDGE_RAIL, MT_BRIDGE_BRACE_L, MT_WARNING_SIGN
db MT_BRIDGE_RAIL, MT_GROUND
db MT_BRIDGE_RAIL
db MT_BRIDGE_RAIL, MT_BRIDGE_BRACE_R
db MT_GROUND
db MT_TALL_FLOWER
db MT_BUSH, MT_TREE, MT_GROUND, MT_CAVE, MT_GROUND
db MT_BUSH, MT_TREE, MT_GROUND, MT_CAVE, MT_GROUND
db MT_GROUND, MT_CAVE, MT_GROUND
db MT_GROUND, MT_CAVE, MT_GROUND
db MT_GROUND
db MT_GROUND
; none
; none
; none
; none
; none
; none
; none
; none
; none
; none
db MT_GROUND
db MT_GROUND
db MT_GROUND
db MT_GROUND
db MT_GROUND
db MT_GROUND
db MT_GROUND
db MT_GROUND
db MT_GROUND
db MT_GROUND
db MT_GROUND
db MT_GROUND
coin_pos:
db 15, 9
db 24, 8
db 27, 5|$80 ; coin half behind bush
db 38, 4
db 36, 11
def NUM_DEFINED_COINS equ (@-coin_pos)/2
sign_pos:
db 6, 7
db 14, 9
db 30, 8
db 29, 5
def NUM_DEFINED_SIGNS equ (@-sign_pos)/2
section "bgchr", ROMX, BANK[1]
static_tiles:
dw $9000
db 80
include "parkmetatiles.2b.pb16.inc"
dw $8000 + 16 * COINCELS_BASE_TILE
db 5
include "coincels.2b.pb16.inc"
dw $8000 + 16 * CURSOR_TILE_NO_MATCH
db 4
include "cursor.2b.pb16.inc"
; Static sprite drawing ;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;
def COINS_ATTR equ $11 ; no flip, DMG and GBC palette 1
section "draw_objs", ROM0
draw_coins:
ld bc, coin_pos
ld de, wOAMUsed
ld a, [de]
ld e, a
.coinloop:
ld a, [bc]
inc bc
push bc
; calculate X coordinate of coin
ld hl, wCameraX
ld c, [hl]
inc hl
ld b, [hl]
ld l, a
ld h, 0
add hl, hl
; add 12 (GB sprite offset 8 plus 4 from left) to center object
; in metatile
inc l
add hl, hl
inc l
add hl, hl
add hl, hl
ld a, l
sub c
ld l, a
ld a, h
sbc b
pop bc
jr nz, .not_this_coin
ld a, l
cp SCRN_X+8
jr nc, .not_this_coin
; calculate Y coordinate of coin
ld a, [wCameraY]
ld h, a
ld a, [bc]
inc a ; draw coin at top of metatile (offset 16)
add a
add a
add a
add a
sub h
jr c, .not_this_coin
cp SCRN_Y+16
jr nc, .not_this_coin
ld [de], a
inc e
ld a, l
ld [de], a
inc e
ldh a, [hVblanks]
and $38
rra
rra
rra
cp 5
jr c, .coin_not_reverse
cpl
add 8+1
.coin_not_reverse:
add COINCELS_BASE_TILE
ld [de], a
inc e
ld a, [bc]
and $80 ; priority
or COINS_ATTR
ld [de], a
inc e
.not_this_coin:
inc bc
ld a, c
xor low(coin_pos + NUM_DEFINED_COINS * 2)
jr nz, .coinloop
ld a, e
ld [wOAMUsed], a
ret
draw_cursor:
ld hl, wOAMUsed
ld l, [hl]
ld a, [wCameraY]
ld b, a
ld a, [wCursorY]
sub b
add 16-1
ld [hl+], a
ld a, [wCameraX]
ld b, a
ld a, [wCursorX]
sub b
add 8-1
ld [hl+], a
ld a, [wCursorItem]
rlca
and $01
xor CURSOR_TILE_NO_MATCH|1
ld [hl+], a
rrca
sbc a
and $11 ; attribute
ld [hl+], a
ld a, l
ld [wOAMUsed], a
ret
; Title screen ;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;
section "title", ROMX,BANK[1]
show_title:
call lcd_off
ld hl, title_2b
ld de, $8800
call memcpy_pascal16
ld de, _SCRN0
call load_full_nam
xor a
ldh [rIF], a
ldh [rSCX], a
ldh [rSCY], a
ld a, IEF_VBLANK
ldh [rIE], a
ei
ld a, %11100100
call set_bgp
ld a, LCDCF_ON|LCDCF_BGON|LCDCF_BG9800|LCDCF_BG8800
ldh [rLCDC], a
.loop:
halt
call read_pad
ldh a, [hNewKeys]
and PADF_START|PADF_A
jr z, .loop
ret
title_2b:
dw .end-.start
.start:
include "title.2b.inc"
.end:
include "title.nam.inc"
; shelf c0c0-cfff
; +wMapVicinity--++wActors-----------------------+................
; |..............||..............................|................
; |..............||..............................|................
; |..............||..............................|................
; |..............||..............................|................
; |..............||..............................|................
; |..............||..............................|................
; |..............||..............................|................
; |..............||..............................|................
; |..............||..............................|................
; |..............||..............................|................
; |..............|+------------------------------+................
; |..............|................................................
; |..............|................................................
; |..............|................................................
; +--------------+................................................
SECTION "wMapVicinity_row00", WRAM0[$c0c0]
wMapVicinity::
ds 16
SECTION "wMapVicinity_row01", WRAM0[$c1c0]
ds 16
SECTION "wMapVicinity_row02", WRAM0[$c2c0]
ds 16
SECTION "wMapVicinity_row03", WRAM0[$c3c0]
ds 16
SECTION "wMapVicinity_row04", WRAM0[$c4c0]
ds 16
SECTION "wMapVicinity_row05", WRAM0[$c5c0]
ds 16
SECTION "wMapVicinity_row06", WRAM0[$c6c0]
ds 16
SECTION "wMapVicinity_row07", WRAM0[$c7c0]
ds 16
SECTION "wMapVicinity_row08", WRAM0[$c8c0]
ds 16
SECTION "wMapVicinity_row09", WRAM0[$c9c0]
ds 16
SECTION "wMapVicinity_row0a", WRAM0[$cac0]
ds 16
SECTION "wMapVicinity_row0b", WRAM0[$cbc0]
ds 16
SECTION "wMapVicinity_row0c", WRAM0[$ccc0]
ds 16
SECTION "wMapVicinity_row0d", WRAM0[$cdc0]
ds 16
SECTION "wMapVicinity_row0e", WRAM0[$cec0]
ds 16
SECTION "wMapVicinity_row0f", WRAM0[$cfc0]
ds 16
SECTION "wActors_row00", WRAM0[$c0d0]
wActors::
ds 32
SECTION "wActors_row01", WRAM0[$c1d0]
ds 32
SECTION "wActors_row02", WRAM0[$c2d0]
ds 32
SECTION "wActors_row03", WRAM0[$c3d0]
ds 32
SECTION "wActors_row04", WRAM0[$c4d0]
ds 32
SECTION "wActors_row05", WRAM0[$c5d0]
ds 32
SECTION "wActors_row06", WRAM0[$c6d0]
ds 32
SECTION "wActors_row07", WRAM0[$c7d0]
ds 32
SECTION "wActors_row08", WRAM0[$c8d0]
ds 32
SECTION "wActors_row09", WRAM0[$c9d0]
ds 32
SECTION "wActors_row0a", WRAM0[$cad0]
ds 32
SECTION "wActors_row0b", WRAM0[$cbd0]
ds 32
db $ff,$ff,$7f,$ff,$ff,$3f,$00,$ff,$ff,$7f,$ff,$ff,$15,$00,$00,$03,$0c,$30,$77,$40,$80,$57,$3f,$c0,$00,$ff,$57,$fc,$03,$00,$ff,$d5,$c0,$30,$0c,$77,$02,$01,$42,$ff,$7f,$80,$00,$ff,$30,$00,$20,$10,$3f,$00,$00,$3f,$20,$10,$02,$ff,$00,$fe,$01,$00,$ff,$0c,$00,$04,$08,$fc,$00,$00,$fc,$04,$08,$00,$03,$00,$00,$03,$7f,$00,$40,$3f,$00,$5f,$20,$51,$2e,$2f,$10,$2c,$13,$10,$00,$00,$fc,$04,$f8,$74,$88,$00,$94,$68,$fa,$04,$8a,$74,$e2,$1c,$14,$7b,$7f,$7f,$74,$3c,$3f,$1c,$0e,$1f,$1f,$0f,$0f,$3f,$ff,$ff,$c0,$3f,$bf,$df,$df,$c4,$c4,$3f,$ff,$ff,$00,$bf,$bf,$bb,$bb,$7b,$7b,$37,$37,$0c,$fc,$fc,$fe,$fe,$fc,$fc,$cc,$f8,$f8,$f0,$f0,$38,$00,$00,$01,$04,$03,$00,$06,$01,$46,$0f,$61,$1e,$25,$1a,$00,$00,$99,$0d,$f2,$1d,$e2,$dd,$27,$02,$da,$3d,$e6,$99,$f6,$49,$3f,$01,$00,$19,$0c,$bd,$7c,$ff,$4f,$55,$44,$c1,$75,$9f,$30,$00,$00,$80,$80,$c0,$c0,$00,$d8,$d8,$b0,$f0,$9a,$fa,$1e,$fe,$15,$80,$00,$c0,$40,$70,$55,$3c,$0f,$03,$00,$ff,$d5,$c0,$ff,$3f,$7f,$00,$d5,$03,$ff,$fc,$55,$01,$03,$02,$0e,$55,$3c,$f0,$c0,$00,$00,$20,$10,$3f,$00,$00,$3f,$20,$10,$c0,$3f,$00,$00,$3f,$20,$10,$00,$04,$08,$fc,$00,$00,$fc,$04,$08,$c0,$fc,$00,$00,$fc,$04,$08,$02,$23,$1c,$3f,$00,$00,$3f,$00,$ff,$00,$7e,$80,$80,$7e,$00,$c0,$40,$80,$3c,$80,$40,$00,$c0,$ae,$03,$01,$00,$ff,$b0,$e0,$40,$b0,$00,$f8,$08,$10,$ec,$08,$76,$77,$00,$7f,$a8,$03,$07,$0f,$04,$1b,$00,$18,$26,$10,$6e,$20,$de,$00,$fc,$ab,$c0,$80,$00,$ff,$00,$2d,$32,$1d,$63,$1c,$7b,$dc,$27,$00,$d8,$a7,$5b,$ac,$73,$4e,$31,$7f,$00,$cd,$32,$ec,$d3,$6f,$97,$ff,$cf,$05,$3b,$f7,$91,$7f,$b9,$ed,$15,$12,$ff,$d3,$7f,$1e,$55,$9e,$bc,$37,$e7,$04,$7c,$fc,$fe,$fe,$e6,$74,$ff,$73,$ff,$fe,$fe,$00,$f4,$0b,$f6,$09,$e6,$19,$00,$ff,$c0,$01,$c0,$63,$80,$36,$41,$30,$f6,$09,$e4,$1b,$00,$ff,$c2,$80,$60,$00,$c0,$80,$00,$f4,$0b,$f6,$09,$e6,$19,$00,$ff,$c2,$01,$06,$00,$03,$01,$30,$f6,$09,$e4,$1b,$00,$ff,$c0,$80,$03,$c6,$01,$6c,$82,$00,$0b,$0a,$1b,$1b,$55,$5d,$6a,$56,$00,$37,$3f,$fe,$bf,$fd,$de,$7e,$77,$00,$10,$30,$a8,$58,$d8,$f8,$f4,$f4,$01,$f6,$d6,$fe,$de,$7c,$fc,$fc,$02,$03,$00,$02,$01,$04,$02,$03,$00,$0a,$05,$0e,$01,$10,$09,$18,$00,$50,$00,$80,$40,$80,$20,$c0,$00,$60,$80,$10,$a0,$28,$90,$08,$10,$10,$18,$00,$5a,$24,$18,$db,$3c,$c1,$24,$18,$5a,$00,$18,$0c,$10,$2f,$11,$2e,$01,$3e,$33,$04,$3b,$00,$3f,$03,$20,$dc,$28,$d4,$08,$f4,$33,$00,$fc,$10,$ec,$08,$24,$42,$18,$67,$e7,$08,$f7,$10,$10,$ff,$89,$56,$6e,$38,$38,$17,$fb,$ff,$e3,$26,$07,$7e,$7f,$e7,$ff,$f3,$55,$cf,$ff,$3d,$7e,$55,$f7,$a7,$cf,$9f,$55,$e6,$de,$ff,$7f,$57,$77,$ef,$ff,$04,$7c,$fc,$fe,$fe,$e6,$74,$ff,$73,$ff,$fe,$fe,$00,$14,$2b,$00,$1e,$30,$0c,$60,$18,$02,$c0,$30,$80,$60,$00,$c0,$80,$08,$ff,$00,$00,$ff,$18,$10,$08,$ff,$30,$f6,$09,$e4,$1b,$00,$ff,$ef,$00,$00,$28,$d4,$00,$78,$0c,$30,$06,$18,$02,$03,$0c,$01,$06,$00,$03,$01,$00,$3f,$3f,$ef,$bf,$d7,$ef,$ef,$ff,$0c,$7f,$7f,$3f,$3f,$1f,$1f,$30,$fe,$fe,$ef,$ff,$d7,$ef,$00,$ee,$fe,$fc,$fc,$fe,$fe,$f0,$f0,$21,$20,$11,$1f,$3f,$00,$00,$ff,$00,$24,$98,$1c,$e0,$c0,$00,$00,$c0,$3c,$80,$40,$00,$c0,$00,$c8,$88,$eb,$c9,$6f,$6f,$7e,$7e,$03,$38,$38,$18,$18,$10,$10,$3b,$00,$3f,$7f,$30,$11,$6e,$21,$de,$20,$df,$3b,$00,$fc,$fe,$c0,$08,$f6,$04,$fb,$00,$ff,$00,$13,$11,$d7,$93,$f6,$f6,$7e,$7e,$03,$1c,$1c,$18,$18,$08,$08,$3f,$e7,$00,$ff,$ff,$ff,$ff,$ff,$ff,$ff,$ff,$ff,$ff,$ff,$00,$00,$38,$10,$6c,$38,$d6,$10,$ee,$00,$82,$fe,$44,$7c,$38,$38,$30,$30,$00,$18,$00,$28,$10,$f2,$1c,$9e,$70,$08,$ee,$d6,$38,$08,$38,$10,$10,$3f,$9f,$ff,$ff,$55,$c0,$80,$c0,$80,$55,$c0,$80,$c0,$80,$55,$03,$01,$03,$01,$55,$03,$01,$03,$01,$7f,$f9,$ff,$00,$25,$3b,$46,$79,$9e,$e5,$9b,$e4,$07,$d3,$ee,$d0,$ff,$bb,$00,$b4,$fb,$45,$ba,$4d,$b2,$6f,$d5,$05,$2a,$f7,$48,$ff,$4a,$de,$00,$a5,$db,$66,$99,$6e,$95,$eb,$34,$07,$c3,$be,$90,$ff,$bb,$00,$b4,$fc,$42,$be,$49,$b7,$69,$d7,$05,$2b,$f7,$4b,$ff,$4d,$dd
; Generated with savescan.py - Static Automatic Variable Earmarker
; for RGBASM 0.6.2 or later
section "hSAVE_locals",HRAM
union
vwfPutTile_shifter.hShifterMask:: ds 1
vwfPutTile_shifter.hDestAddrLo:: ds 1
nextu
draw_metasprite.hYLo:: ds 1
draw_metasprite.hYHi:: ds 1
draw_metasprite.hXLo:: ds 1
draw_metasprite.hXHi:: ds 1
draw_metasprite.hAttr:: ds 1
draw_metasprite.hSheetID:: ds 1
draw_metasprite.hFrame:: ds 1
draw_metasprite.hBaseTile:: ds 1
draw_metasprite.hXAdd:: ds 1
draw_metasprite.hStripY:: ds 1
draw_metasprite.hStripXLo:: ds 1
draw_metasprite.hStripXHi:: ds 1
nextu
blit_one_col_new.hThisColumnXAddr:: ds 1
blit_one_col_new.hAdjacentColumnXAddr:: ds 1
blit_one_col_new.hMtDefsLo:: ds 1
blit_one_col_new.hMtDefsHi:: ds 1
nextu
pb16_unpack_packet.hByte0:: ds 1
endu
; maximum size of live local variables: 12 bytes
db $88,$00,$70,$00,$04,$04,$0c,$dc,$0a,$de,$c2,$fe,$84,$fc,$f8,$f8,$60,$00,$f0,$00,$f0,$00,$04,$64,$40,$7e,$3c,$3c,$00,$00,$00,$00,$38,$38,$27,$3f,$2f,$3c,$3d,$38,$7e,$58,$7f,$48,$7c,$5c,$7c,$5c,$00,$00,$e0,$e0,$f0,$10,$d8,$08,$38,$18,$e8,$68,$80,$80,$80,$80,$74,$74,$50,$50,$10,$10,$00,$02,$00,$04,$00,$04,$06,$06,$0a,$0e,$00,$00,$00,$00,$00,$00,$00,$40,$00,$20,$00,$20,$60,$60,$00,$00,$11,$1f,$20,$3f,$20,$3f,$40,$7f,$70,$7f,$7f,$7f,$1f,$1f,$07,$04,$08,$08,$f4,$fc,$04,$fc,$02,$fe,$0e,$fe,$fe,$fe,$f8,$f8,$e0,$20,$00,$00,$04,$00,$03,$00,$00,$02,$02,$17,$02,$1f,$08,$0f,$05,$07,$03,$03,$02,$00,$0b,$00,$1b,$00,$08,$10,$00,$18,$10,$18,$00,$00,$24,$e7,$7e,$ff,$ff,$c3,$bd,$81,$c3,$81,$db,$db,$81,$81,$00,$00,$00,$00,$00,$00,$00,$00,$18,$5a,$00,$42,$00,$42,$7e,$7e,$00,$7e,$00,$07,$38,$3f,$20,$3f,$40,$7f,$70,$7f,$7f,$7f,$1f,$1f,$0f,$09,$38,$38,$27,$3f,$2f,$3c,$3d,$38,$3e,$38,$3f,$28,$3c,$2c,$3c,$2c,$00,$00,$e0,$e0,$f0,$10,$d8,$08,$3c,$1c,$e4,$64,$80,$80,$80,$80,$3c,$3c,$28,$28,$08,$08,$00,$02,$00,$04,$00,$04,$06,$06,$0a,$0e,$09,$0f,$10,$1f,$10,$1f,$20,$3f,$20,$3f,$3f,$3f,$3f,$3f,$07,$04,$0c,$0c,$f2,$fe,$01,$ff,$01,$ff,$0f,$ff,$fe,$fe,$f8,$f8,$e0,$20,$60,$00,$f0,$00,$70,$00,$04,$64,$40,$7e,$3c,$3c,$00,$00,$00,$00,$38,$38,$27,$3f,$2f,$3c,$3d,$38,$1e,$18,$1f,$10,$1c,$14,$1c,$14,$00,$00,$e0,$e0,$f8,$18,$dc,$0c,$3a,$1a,$e0,$60,$80,$80,$80,$80,$1c,$1c,$14,$14,$04,$04,$00,$02,$00,$04,$00,$06,$06,$06,$0a,$0e,$00,$00,$00,$00,$00,$00,$00,$40,$00,$20,$00,$20,$60,$60,$04,$04,$24,$3c,$23,$3f,$20,$3f,$40,$7f,$40,$7f,$7f,$7f,$7f,$7f,$1f,$10,$28,$38,$c4,$fc,$02,$fe,$06,$fe,$1c,$fc,$f8,$f8,$e0,$e0,$80,$80,$01,$00,$05,$00,$04,$00,$00,$00,$00,$00,$00,$00,$00,$00,$00,$00,$80,$00,$c0,$00,$e4,$04,$00,$7e,$3c,$3c,$00,$00,$00,$00,$00,$00,$38,$38,$27,$3f,$2f,$3c,$7d,$78,$fe,$98,$ef,$a8,$ec,$ac,$ec,$ec,$a4,$a4,$20,$20,$00,$00,$00,$02,$00,$02,$00,$03,$0f,$0f,$30,$3f,$00,$00,$00,$00,$00,$00,$00,$40,$00,$20,$18,$18,$80,$80,$c2,$c2,$20,$3f,$40,$7f,$80,$ff,$c0,$ff,$70,$7f,$3f,$3f,$3f,$27,$00,$00,$18,$f8,$08,$f8,$08,$f8,$04,$fc,$04,$fc,$fe,$fe,$ff,$f9,$00,$00,$74,$74,$50,$50,$10,$10,$00,$02,$00,$04,$00,$04,$06,$06,$1a,$1e,$21,$3f,$40,$7f,$80,$ff,$80,$ff,$f0,$ff,$7f,$7f,$1f,$1f,$07,$04,$08,$08,$f8,$f8,$08,$f8,$04,$fc,$04,$fc,$fc,$fc,$fc,$fc,$e0,$20,$01,$00,$03,$00,$07,$00,$00,$06,$04,$07,$03,$03,$00,$00,$00,$00,$80,$00,$a0,$00,$24,$04,$1e,$1e,$4c,$4c,$00,$e0,$c0,$c0,$00,$00,$a4,$a4,$20,$20,$00,$00,$00,$02,$00,$04,$00,$00,$01,$01,$08,$08,$00,$00,$00,$00,$00,$00,$00,$40,$00,$40,$18,$d8,$20,$e0,$b2,$b2,$14,$1c,$23,$3f,$20,$3f,$40,$7f,$70,$7f,$7f,$7f,$7f,$4f,$00,$00,$0c,$1c,$24,$3c,$c4,$fc,$02,$fe,$0e,$fe,$fe,$fe,$fe,$f2,$00,$00,$a4,$a4,$20,$20,$00,$00,$00,$02,$00,$02,$00,$03,$07,$07,$08,$0f,$10,$1f,$20,$3f,$20,$3f,$40,$7f,$70,$7f,$7f,$7f,$7f,$4f,$00,$00,$3c,$fc,$04,$fc,$04,$fc,$02,$fe,$0e,$fe,$fe,$fe,$fe,$f2,$00,$00,$40,$00,$24,$00,$18,$00,$02,$62,$06,$6e,$ca,$fe,$82,$fe,$e4,$fc,$f8,$18,$f0,$00,$04,$64,$40,$7e,$3c,$3c,$00,$00,$00,$00,$00,$00,$0e,$0e,$09,$0f,$0b,$0f,$3f,$3e,$3e,$2c,$7f,$4c,$7f,$5c,$7e,$5e,$00,$00,$00,$00,$c0,$c0,$f0,$30,$f8,$08,$6c,$04,$9c,$0c,$74,$74,$76,$76,$54,$54,$10,$10,$00,$00,$00,$04,$00,$04,$06,$06,$08,$0e,$40,$40,$00,$00,$00,$00,$00,$00,$00,$00,$00,$20,$60,$60,$00,$00,$74,$74,$50,$50,$10,$10,$00,$02,$00,$04,$00,$04,$18,$1e,$20,$3e,$00,$00,$00,$00,$00,$00,$00,$40,$00,$20,$00,$20,$68,$68,$04,$04,$41,$7f,$40,$7f,$70,$7f,$7f,$7f,$1f,$1f,$07,$04,$00,$00,$00,$00,$0a,$0e,$f2,$fe,$0e,$fe,$fe,$fe,$f8,$f8,$e0,$20,$00,$00,$00,$00,$60,$00,$f0,$00,$84,$64,$40,$7c,$3c,$3e,$00,$00,$00,$00,$00,$00,$38,$38,$27,$3f,$2f,$3c,$7d,$78,$fe,$98,$ff,$98,$fc,$bc,$ec,$ec,$e0,$e0,$f0,$10,$f8,$08,$d8,$18,$38,$18,$e0,$60,$80,$80,$80,$80,$a4,$a4,$20,$20,$00,$00,$00,$02,$00,$04,$38,$3c,$40,$7e,$41,$7f,$00,$00,$00,$00,$00,$00,$00,$40,$00,$20,$6c,$6c,$02,$0e,$06,$06,$70,$7f,$7f,$7f,$1f,$1f,$00,$00,$00,$00,$00,$00,$00,$00,$00,$00,$fe,$fe,$fe,$fe,$f8,$f8,$00,$00,$00,$00,$00,$00,$00,$00,$00,$00,$e0,$00,$90,$60,$40,$70,$30,$3c,$0c,$0c,$00,$00,$00,$00,$00,$00,$a4,$a4,$20,$20,$00,$00,$00,$04,$3c,$3c,$60,$7e,$71,$7f,$7f,$7f,$00,$00,$00,$00,$00,$00,$38,$78,$04,$3c,$06,$3e,$0e,$0e,$ce,$ce,$f0,$00,$e0,$00,$00,$70,$60,$7c,$38,$3c,$00,$00,$00,$00,$00,$00,$38,$38,$27,$3f,$2f,$3c,$7d,$78,$7e,$58,$7f,$48,$7c,$5c,$7c,$5c,$74,$74,$50,$50,$10,$10,$00,$04,$00,$04,$1e,$1e,$70,$7e,$7f,$7f,$00,$00,$00,$00,$00,$00,$00,$20,$78,$78,$04,$3c,$02,$0e,$0e,$0e,$40,$00,$24,$00,$18,$00,$02,$62,$06,$6e,$65,$6f,$81,$ff,$e2,$fe,$fc,$1c,$c0,$00,$40,$70,$20,$3c,$18,$1e,$00,$00,$00,$00,$00,$00,$1c,$1c,$13,$1f,$17,$1e,$3e,$3c,$3f,$2c,$3b,$20,$3a,$2a,$72,$52,$00,$00,$80,$80,$f0,$70,$f8,$08,$6c,$04,$9c,$0c,$74,$34,$40,$40,$72,$72,$50,$50,$10,$10,$00,$04,$00,$08,$3e,$3e,$e0,$ff,$ff,$ff,$40,$40,$00,$00,$00,$00,$00,$00,$f0,$f0,$08,$38,$04,$0c,$84,$84,$d8,$18,$80,$f0,$60,$7c,$0c,$0f,$00,$00,$00,$00,$00,$00,$00,$00,$0e,$0e,$09,$0f,$1b,$1f,$3f,$2e,$3e,$24,$7f,$5c,$77,$54,$76,$76,$15,$15,$05,$05,$00,$02,$00,$04,$00,$04,$3f,$3f,$e0,$ff,$ff,$ff,$90,$90,$00,$00,$00,$00,$00,$00,$20,$20,$08,$08,$00,$80,$f0,$f0,$0e,$0e,$09,$0f,$0b,$0f,$1f,$1e,$1e,$14,$1f,$14,$1f,$14,$1e,$16,$07,$07,$07,$07,$02,$02,$00,$04,$00,$04,$3f,$3f,$e0,$ff,$ff,$ff,$1c,$1c,$13,$1f,$17,$1e,$3e,$3c,$3f,$2c,$3f,$2c,$3e,$2e,$1e,$16,$00,$00,$80,$80,$f0,$70,$f8,$08,$6c,$04,$9e,$0e,$72,$32,$40,$40,$1e,$16,$1c,$1c,$0c,$0c,$00,$04,$00,$08,$3e,$3e,$e0,$ff,$ff,$ff,$1c,$1c,$13,$1f,$17,$1e,$3e,$3c,$3f,$2c,$3f,$24,$3e,$2e,$1e,$16,$00,$00,$f0,$f0,$f8,$08,$ec,$04,$1e,$0e,$f2,$32,$40,$40,$40,$40,$1e,$1e,$0a,$0a,$08,$08,$00,$02,$00,$02,$0f,$0f,$38,$3f,$3f,$3f,$00,$00,$00,$00,$00,$00,$00,$10,$3c,$3c,$02,$1e,$01,$07,$87,$87,$04,$00,$88,$00,$72,$02,$06,$06,$05,$6f,$01,$6f,$61,$7f,$46,$7e,$78,$78,$60,$1e,$4c,$3c,$00,$00,$00,$00,$00,$00,$00,$00,$00,$00,$00,$00,$7b,$7b,$4f,$7c,$5b,$70,$7c,$78,$7f,$58,$7c,$4c,$7c,$5c,$00,$00,$e0,$e0,$d0,$10,$b8,$18,$68,$28,$c0,$40,$80,$80,$80,$80,$74,$54,$70,$70,$50,$50,$10,$14,$00,$04,$1f,$1f,$70,$7f,$7f,$7f,$00,$00,$00,$00,$00,$00,$00,$00,$18,$18,$e4,$fc,$02,$fe,$fe,$fe,$60,$00,$c0,$3c,$bc,$7c,$00,$00,$00,$00,$00,$00,$00,$00,$00,$00,$74,$74,$50,$50,$10,$10,$00,$02,$00,$04,$00,$04,$0f,$0f,$3c,$3f,$00,$00,$00,$00,$00,$00,$00,$40,$00,$00,$00,$00,$f8,$f8,$04,$fc,$60,$7f,$7f,$7f,$00,$00,$00,$00,$00,$00,$00,$00,$00,$00,$00,$00,$88,$00,$70,$00,$00,$00,$0c,$dc,$0a,$de,$c2,$fe,$84,$fc,$f8,$f8,$60,$00,$f0,$00,$80,$70,$60,$7c,$18,$18,$00,$00,$00,$00,$00,$00,$00,$00,$80,$80,$f0,$70,$d8,$08,$38,$18,$f8,$78,$88,$88,$80,$80,$3c,$2c,$38,$38,$28,$28,$08,$0a,$00,$04,$00,$04,$06,$06,$09,$0f,$00,$00,$00,$00,$00,$00,$00,$40,$00,$20,$00,$20,$00,$00,$90,$90,$10,$1f,$20,$3f,$20,$3f,$7f,$7f,$7f,$7f,$00,$00,$00,$00,$00,$00,$68,$f8,$04,$fc,$04,$fc,$fe,$fe,$fe,$fe,$00,$00,$00,$00,$00,$00,$3c,$2c,$38,$38,$28,$28,$08,$0a,$00,$04,$00,$04,$06,$06,$08,$0e,$11,$1f,$10,$1f,$20,$3f,$20,$3f,$20,$3f,$70,$7f,$7f,$7f,$1f,$1f,$08,$08,$f8,$f8,$04,$fc,$04,$fc,$04,$fc,$0e,$fe,$fe,$fe,$f8,$f8,$08,$00,$90,$00,$64,$04,$0c,$0c,$0a,$de,$02,$de,$c2,$fe,$8c,$fd,$f4,$f3,$3d,$03,$7a,$02,$70,$00,$00,$00,$00,$00,$00,$00,$00,$00,$00,$60,$20,$e0,$40,$c0,$80,$80,$00,$00,$00,$00,$00,$00,$00,$00,$3c,$2c,$38,$38,$28,$28,$08,$09,$00,$02,$00,$02,$07,$07,$18,$1f,$00,$00,$00,$00,$00,$00,$00,$00,$00,$10,$00,$30,$e0,$e0,$10,$f0,$20,$3f,$40,$7f,$80,$ff,$80,$ff,$f0,$ff,$7f,$7f,$0f,$0f,$07,$04,$10,$f0,$08,$f8,$08,$f8,$04,$fc,$04,$fc,$fc,$fc,$fc,$fc,$e0,$20,$88,$00,$70,$00,$04,$04,$0c,$dc,$0a,$df,$c0,$ff,$85,$fb,$fe,$e2,$78,$00,$e0,$00,$f0,$00,$00,$00,$00,$00,$00,$00,$00,$00,$00,$00,$a4,$a4,$20,$20,$00,$00,$00,$02,$00,$04,$00,$04,$1f,$1f,$60,$7f,$00,$00,$00,$00,$00,$00,$00,$10,$00,$70,$00,$20,$f0,$f0,$08,$f8,$80,$ff,$80,$ff,$f0,$ff,$ff,$ff,$1f,$1f,$07,$04,$00,$00,$00,$00,$04,$fc,$04,$fc,$1c,$fc,$fc,$fc,$fc,$fc,$e0,$20,$00,$00,$00,$00,$88,$00,$70,$00,$04,$05,$0c,$df,$0e,$d9,$cf,$f1,$9c,$e0,$f8,$c0,$00,$c0,$40,$c0,$00,$80,$80,$80,$00,$00,$00,$00,$00,$00,$00,$00,$70,$00,$e0,$00,$f0,$00,$00,$00,$00,$00,$00,$00,$00,$00,$00,$00,$a4,$a4,$20,$20,$00,$00,$00,$02,$00,$04,$78,$7c,$87,$ff,$80,$ff,$00,$00,$00,$00,$00,$00,$00,$00,$00,$60,$18,$38,$e4,$fc,$04,$fc,$f0,$ff,$ff,$ff,$1f,$1f,$00,$00,$00,$00,$00,$00,$00,$00,$00,$00,$0c,$fc,$fc,$fc,$fc,$fc,$00,$00,$00,$00,$00,$00,$00,$00,$00,$00,$80,$00,$78,$00,$00,$00,$06,$6e,$05,$6f,$60,$7f,$42,$7d,$7f,$71,$00,$00,$00,$00,$00,$60,$20,$60,$00,$c0,$40,$c0,$80,$80,$00,$00,$00,$00,$73,$73,$4f,$7c,$5b,$70,$fc,$f8,$ff,$b8,$ec,$8c,$ec,$ac,$00,$00,$80,$80,$f0,$70,$f8,$08,$38,$18,$f8,$78,$88,$88,$80,$80,$e4,$a4,$e0,$e0,$a0,$a0,$20,$22,$00,$04,$00,$04,$07,$07,$18,$1f,$00,$00,$00,$00,$00,$00,$00,$10,$00,$70,$00,$20,$e0,$e0,$10,$f0,$00,$00,$73,$73,$4f,$7c,$5d,$70,$fe,$f8,$ff,$b8,$ec,$8c,$ec,$ac,$e4,$a4,$e0,$e0,$a0,$a0,$20,$21,$00,$02,$00,$02,$07,$07,$08,$0f,$10,$1f,$20,$3f,$20,$3f,$40,$7f,$40,$7f,$e0,$ff,$ff,$ff,$1f,$1f,$10,$f0,$08,$f8,$08,$f8,$04,$fc,$04,$fc,$0c,$fc,$fc,$fc,$fc,$fc,$08,$00,$90,$00,$64,$04,$0c,$0c,$0a,$de,$02,$de,$c2,$fe,$8c,$fc,$f0,$f0,$30,$00,$78,$03,$7d,$03,$3e,$02,$00,$00,$00,$00,$00,$00,$00,$00,$00,$00,$00,$c0,$c0,$c0,$00,$00,$00,$00,$00,$00,$00,$00,$00,$00,$00,$00,$00,$00,$00,$20,$00,$10,$00,$00,$00,$00,$f8,$f8,$20,$3f,$40,$7f,$80,$ff,$80,$ff,$c0,$ff,$70,$7f,$3f,$3f,$0f,$0f,$08,$f8,$08,$f8,$08,$f8,$04,$fc,$04,$fc,$04,$fc,$fc,$fc,$fc,$fc,$f0,$f0,$30,$00,$78,$00,$78,$00,$3c,$00,$1c,$03,$06,$07,$01,$01,$00,$00,$00,$00,$00,$00,$00,$20,$00,$10,$00,$10,$00,$00,$80,$80,$20,$3f,$41,$7f,$80,$ff,$80,$ff,$f0,$ff,$7f,$7f,$0f,$0f,$00,$00,$e0,$e0,$98,$f8,$04,$fc,$04,$fc,$3c,$fc,$fc,$fc,$c0,$c0,$00,$00,$38,$38,$18,$00,$3c,$00,$3c,$00,$1e,$00,$0e,$00,$04,$02,$00,$03,$00,$06,$04,$06,$00,$03,$03,$03,$00,$00,$00,$00,$00,$00,$00,$00,$00,$00,$1c,$1c,$13,$1f,$16,$1c,$3f,$3e,$3f,$2e,$3b,$23,$3b,$2b,$00,$00,$f8,$f8,$f4,$04,$ee,$06,$1a,$0a,$f0,$10,$20,$20,$20,$20,$39,$29,$38,$38,$28,$28,$08,$08,$00,$00,$00,$00,$01,$01,$02,$03,$00,$00,$00,$00,$00,$00,$00,$48,$00,$84,$00,$84,$c0,$c0,$20,$e0,$08,$0f,$10,$1f,$20,$3f,$20,$3f,$3f,$3f,$1f,$1f,$00,$00,$00,$00,$e4,$e4,$12,$f2,$13,$f3,$13,$f3,$f8,$f8,$e0,$e0,$00,$00,$00,$00,$60,$00,$f0,$00,$f0,$00,$70,$00,$00,$60,$00,$70,$00,$30,$00,$00,$1c,$1c,$13,$1f,$17,$1e,$3e,$3c,$7f,$4c,$77,$54,$76,$56,$76,$76,$00,$00,$f0,$f0,$f8,$08,$ec,$04,$1c,$0c,$f4,$34,$40,$40,$40,$40,$52,$52,$10,$10,$00,$00,$00,$01,$00,$02,$06,$06,$19,$1f,$21,$3f,$00,$00,$00,$00,$00,$00,$00,$20,$00,$10,$18,$18,$04,$1c,$26,$3e,$41,$7f,$40,$7f,$7f,$7f,$3f,$3f,$00,$00,$00,$00,$00,$00,$00,$00,$1e,$1e,$9c,$9c,$9c,$94,$80,$80,$00,$00,$00,$00,$00,$00,$00,$00,$18,$00,$3c,$00,$38,$00,$70,$00,$00,$60,$00,$e0,$00,$c0,$00,$00,$52,$52,$10,$10,$00,$00,$00,$01,$00,$02,$06,$06,$1c,$1c,$24,$3c,$00,$00,$00,$00,$00,$00,$00,$20,$00,$10,$38,$38,$44,$7c,$86,$fe,$40,$78,$41,$79,$79,$79,$39,$39,$00,$00,$00,$00,$00,$00,$00,$00,$8e,$fe,$fc,$fc,$fc,$f4,$80,$80,$00,$00,$00,$00,$00,$00,$00,$00,$18,$00,$3c,$00,$70,$00,$20,$c0,$00,$c0,$00,$c0,$c0,$c0,$00,$00,$74,$74,$50,$50,$10,$10,$00,$02,$00,$04,$00,$08,$11,$11,$22,$33,$00,$00,$00,$00,$00,$00,$00,$40,$00,$20,$f0,$f0,$08,$f8,$04,$fc,$42,$73,$42,$73,$7f,$7f,$7f,$7f,$00,$00,$00,$00,$00,$00,$00,$00,$06,$fe,$7e,$fe,$fc,$fc,$f0,$90,$00,$00,$00,$00,$00,$00,$00,$00,$60,$00,$f0,$00,$e0,$00,$00,$70,$60,$7c,$38,$3c,$00,$00,$00,$00,$74,$74,$50,$50,$10,$10,$00,$02,$00,$04,$04,$04,$0a,$0e,$12,$1e,$00,$00,$00,$00,$00,$00,$00,$40,$00,$20,$70,$70,$08,$38,$04,$0c,$21,$3f,$20,$3f,$7f,$7f,$7f,$7f,$00,$00,$00,$00,$00,$00,$00,$00,$04,$0c,$fe,$fe,$fe,$fe,$f0,$f0,$00,$00,$00,$00,$00,$00,$00,$00
dw mspr_Mindy_stand
dw mspr_Mindy_turn
dw mspr_Mindy_stop1
dw mspr_Mindy_stop2
dw mspr_Mindy_stop_last
dw mspr_Mindy_start1
dw mspr_Mindy_start2
dw mspr_Mindy_walk1
dw mspr_Mindy_walk2
dw mspr_Mindy_walk3
dw mspr_Mindy_walk4
dw mspr_Mindy_walk5
dw mspr_Mindy_walk6
dw mspr_Mindy_walk7
dw mspr_Mindy_walk8
dw mspr_Mindy_crouch1
dw mspr_Mindy_crouch2
dw mspr_Mindy_crouch3
dw mspr_Mindy_crouch4
dw mspr_Mindy_crouch_last
dw mspr_Mindy_crouch_lean1
dw mspr_Mindy_crouch_lean2
dw mspr_Mindy_crouch_lean
dw mspr_Mindy_crouch_leanout1
dw mspr_Mindy_crouch_leanout_last
dw mspr_Mindy_uncrouch_1
dw mspr_Mindy_uncrouch_2
dw mspr_Mindy_uncrouch_3
dw mspr_Mindy_uncrouch_last
dw mspr_Mindy_hoist_leap_1
dw mspr_Mindy_hoist_leap_2
dw mspr_Mindy_hoist_leap_3
dw mspr_Mindy_hoist_leap_4
dw mspr_Mindy_hoist_leap_last
dw mspr_Mindy_hoist_climb_1
dw mspr_Mindy_hoist_climb_2
dw mspr_Mindy_hoist_climb_3
dw mspr_Mindy_hoist_climb_4
dw mspr_Mindy_hoist_climb_5
dw mspr_Mindy_hoist_climb_6
dw mspr_Mindy_hoist_climb_last
mspr_Mindy_stand:
mspr_Mindy_walk3:
mspr_Mindy_walk4:
mspr_Mindy_walk7:
mspr_Mindy_walk8:
db $08,$00,$01,$02,$03,$04,$05,$06,$07
db $6b,$7e,$06,$00
db $73,$7e,$06,$01
db $68,$78,$37,$02,$03
db $70,$78,$37,$04,$05
db $78,$78,$37,$06,$07
db $00
mspr_Mindy_turn:
db $05,$08,$09,$0a,$0b,$0c
db $6a,$78,$26,$00,$40
db $72,$78,$26,$01,$41
db $68,$7c,$17,$02
db $70,$7c,$17,$03
db $78,$78,$37,$04,$44
db $00
mspr_Mindy_stop1:
mspr_Mindy_stop_last:
db $08,$00,$01,$05,$0d,$0e,$0f,$10,$11
db $6b,$7e,$06,$00
db $73,$7e,$06,$01
db $68,$78,$37,$03,$04
db $70,$78,$37,$05,$02
db $78,$78,$37,$06,$07
db $00
mspr_Mindy_stop2:
db $08,$00,$12,$13,$14,$15,$16,$17,$18
db $6b,$7e,$06,$00
db $73,$7e,$06,$01
db $68,$78,$37,$02,$03
db $70,$78,$37,$04,$05
db $78,$7a,$37,$06,$07
db $00
mspr_Mindy_start1:
db $09,$00,$03,$19,$1a,$1b,$1c,$1d,$1e,$1f
db $6c,$7e,$06,$00
db $74,$78,$26,$02,$03
db $69,$78,$37,$04,$01
db $71,$78,$37,$05,$06
db $79,$77,$37,$07,$08
db $00
mspr_Mindy_start2:
db $08,$00,$01,$02,$03,$05,$20,$21,$22
db $6b,$7e,$06,$00
db $73,$7e,$06,$01
db $68,$78,$37,$02,$03
db $70,$78,$37,$05,$04
db $78,$78,$37,$06,$07
db $00
mspr_Mindy_walk1:
mspr_Mindy_walk2:
db $09,$00,$03,$1b,$23,$24,$25,$26,$27,$28
db $6c,$7e,$06,$00
db $74,$78,$26,$03,$04
db $69,$78,$37,$02,$01
db $71,$78,$37,$05,$06
db $79,$78,$37,$07,$08
db $00
mspr_Mindy_walk5:
mspr_Mindy_walk6:
db $09,$00,$03,$19,$1a,$1b,$1d,$29,$2a,$2b
db $6c,$7e,$06,$00
db $74,$78,$26,$02,$03
db $69,$78,$37,$04,$01
db $71,$78,$37,$06,$05
db $79,$78,$37,$07,$08
db $00
mspr_Mindy_crouch1:
db $08,$06,$07,$2c,$2d,$2e,$2f,$30,$31
db $6c,$7e,$06,$02
db $74,$7e,$06,$03
db $68,$78,$37,$04,$05
db $70,$78,$37,$06,$07
db $78,$78,$37,$00,$01
db $00
mspr_Mindy_crouch2:
db $08,$00,$01,$02,$03,$32,$33,$34,$35
db $6d,$7e,$06,$00
db $75,$7e,$06,$01
db $6a,$78,$37,$02,$03
db $72,$78,$37,$04,$05
db $7a,$78,$37,$06,$07
db $00
mspr_Mindy_crouch3:
db $08,$00,$36,$37,$38,$39,$3a,$3b,$3c
db $70,$7e,$06,$00
db $78,$7e,$06,$01
db $6d,$78,$37,$02,$03
db $75,$78,$37,$04,$05
db $7d,$78,$37,$06,$07
db $00
mspr_Mindy_crouch4:
db $06,$00,$37,$38,$3d,$3e,$3f
db $73,$7e,$06,$00
db $7b,$7e,$06,$03
db $70,$78,$37,$01,$02
db $78,$78,$37,$04,$05
db $00
mspr_Mindy_crouch_last:
db $06,$00,$03,$40,$41,$42,$43
db $73,$7e,$06,$00
db $7b,$7e,$06,$02
db $70,$78,$37,$03,$01
db $78,$78,$37,$04,$05
db $00
mspr_Mindy_crouch_lean1:
db $06,$44,$45,$46,$47,$48,$49
db $73,$7f,$06,$00
db $7b,$7f,$06,$01
db $70,$79,$37,$02,$03
db $78,$79,$37,$04,$05
db $00
mspr_Mindy_crouch_lean2:
db $06,$2c,$2f,$4a,$4b,$4c,$4d
db $74,$81,$06,$00
db $7c,$81,$06,$02
db $70,$7b,$37,$03,$01
db $78,$79,$37,$04,$05
db $00
mspr_Mindy_crouch_lean:
db $06,$2c,$2f,$4a,$4d,$4e,$4f
db $74,$81,$06,$00
db $7c,$81,$06,$02
db $70,$7b,$37,$04,$01
db $78,$79,$37,$05,$03
db $00
mspr_Mindy_crouch_leanout1:
db $06,$44,$45,$49,$50,$51,$52
db $73,$7f,$06,$00
db $7b,$7f,$06,$01
db $70,$79,$37,$03,$04
db $78,$79,$37,$05,$02
db $00
mspr_Mindy_crouch_leanout_last:
db $06,$00,$40,$53,$54,$55,$56
db $73,$7e,$06,$00
db $7b,$7e,$06,$01
db $70,$77,$37,$02,$03
db $78,$77,$37,$04,$05
db $00
mspr_Mindy_uncrouch_1:
db $06,$57,$58,$59,$5a,$5b,$5c
db $72,$7d,$06,$00
db $7a,$7d,$06,$01
db $70,$78,$37,$02,$03
db $78,$78,$37,$04,$05
db $00
mspr_Mindy_uncrouch_2:
db $07,$00,$03,$41,$5d,$5e,$5f,$60
db $71,$7e,$06,$00
db $79,$7e,$06,$03
db $6e,$78,$37,$02,$01
db $76,$78,$37,$04,$05
db $7e,$78,$37,$06,$46
db $00
mspr_Mindy_uncrouch_3:
db $08,$0d,$61,$62,$63,$64,$65,$66,$67
db $6e,$7e,$06,$01
db $76,$7e,$06,$02
db $6b,$78,$37,$00,$03
db $73,$78,$37,$04,$05
db $7b,$78,$37,$06,$07
db $00
mspr_Mindy_uncrouch_last:
db $08,$01,$05,$0d,$61,$63,$68,$69,$6a
db $6b,$7e,$06,$03
db $73,$7e,$06,$00
db $68,$78,$37,$02,$04
db $70,$78,$37,$05,$01
db $78,$78,$37,$06,$07
db $00
mspr_Mindy_hoist_leap_1:
db $09,$0d,$5a,$6b,$6c,$6d,$6e,$6f,$70,$71
db $6a,$7e,$06,$02
db $72,$7e,$06,$03
db $70,$85,$06,$04
db $68,$78,$37,$00,$01
db $70,$78,$37,$05,$06
db $78,$78,$37,$07,$08
db $00
mspr_Mindy_hoist_leap_2:
db $09,$37,$38,$6d,$72,$73,$74,$75,$76,$77
db $6d,$7e,$06,$03
db $75,$7e,$06,$04
db $70,$85,$06,$02
db $6a,$78,$37,$00,$01
db $72,$78,$37,$05,$06
db $7a,$78,$37,$07,$08
db $00
mspr_Mindy_hoist_leap_3:
db $09,$37,$38,$78,$79,$7a,$7b,$7c,$7d,$7e
db $70,$7e,$26,$02,$03
db $78,$7e,$06,$04
db $6d,$78,$37,$00,$01
db $75,$78,$37,$05,$06
db $7d,$78,$37,$07,$08
db $00
mspr_Mindy_hoist_leap_4:
db $08,$66,$73,$7f,$80,$81,$82,$83,$84
db $6e,$7d,$26,$02,$03
db $76,$7e,$06,$01
db $6b,$78,$37,$04,$05
db $73,$78,$37,$06,$07
db $7b,$77,$37,$00,$40
db $00
mspr_Mindy_hoist_leap_last:
db $09,$5a,$6b,$6c,$6d,$6f,$85,$86,$87,$88
db $6a,$7e,$06,$01
db $72,$7e,$06,$02
db $70,$85,$06,$03
db $68,$78,$37,$05,$00
db $70,$78,$37,$06,$04
db $78,$78,$37,$07,$08
db $00
mspr_Mindy_hoist_climb_1:
db $09,$0d,$5a,$6e,$89,$8a,$8b,$8c,$8d,$8e
db $6a,$7e,$06,$03
db $72,$7e,$26,$04,$05
db $68,$78,$37,$00,$01
db $70,$78,$37,$02,$06
db $78,$78,$37,$07,$08
db $00
mspr_Mindy_hoist_climb_2:
db $09,$0d,$5a,$6e,$89,$8b,$8f,$90,$91,$92
db $6a,$7e,$06,$03
db $72,$7e,$06,$05
db $76,$86,$06,$04
db $68,$78,$37,$00,$01
db $70,$78,$37,$02,$06
db $78,$78,$37,$07,$08
db $00
mspr_Mindy_hoist_climb_3:
db $09,$57,$93,$94,$95,$96,$97,$98,$99,$9a
db $6a,$7f,$06,$00
db $72,$7f,$06,$01
db $7a,$80,$06,$02
db $68,$78,$37,$03,$04
db $70,$78,$37,$05,$06
db $78,$79,$37,$07,$08
db $00
mspr_Mindy_hoist_climb_4:
db $09,$00,$8b,$9b,$9c,$9d,$9e,$9f,$a0,$a1
db $6f,$81,$06,$00
db $77,$81,$06,$02
db $7c,$83,$06,$01
db $6c,$7a,$37,$03,$04
db $74,$7a,$37,$05,$06
db $7c,$7a,$37,$07,$08
db $00
mspr_Mindy_hoist_climb_5:
db $09,$00,$8b,$9c,$9d,$a2,$a3,$a4,$a5,$a6
db $6f,$81,$06,$00
db $77,$7f,$06,$04
db $7c,$7f,$06,$01
db $6c,$7a,$37,$02,$03
db $74,$7a,$37,$05,$06
db $7c,$7a,$37,$07,$08
db $00
mspr_Mindy_hoist_climb_6:
db $08,$00,$03,$41,$a7,$a8,$a9,$aa,$ab
db $6f,$81,$06,$00
db $77,$7f,$06,$03
db $6c,$7b,$37,$02,$01
db $74,$7b,$37,$04,$05
db $7c,$7b,$37,$06,$07
db $00
mspr_Mindy_hoist_climb_last:
db $08,$00,$03,$41,$ac,$ad,$ae,$af,$b0
db $6f,$7e,$06,$00
db $77,$7e,$06,$03
db $6c,$78,$37,$02,$01
db $74,$78,$37,$04,$05
db $7c,$78,$37,$06,$07
db $00
def FRAME_Mindy_stand equ 0
def FRAME_Mindy_turn equ 1
def FRAME_Mindy_stop1 equ 2
def FRAME_Mindy_stop2 equ 3
def FRAME_Mindy_stop_last equ 4
def FRAME_Mindy_start1 equ 5
def FRAME_Mindy_start2 equ 6
def FRAME_Mindy_walk1 equ 7
def FRAME_Mindy_walk2 equ 8
def FRAME_Mindy_walk3 equ 9
def FRAME_Mindy_walk4 equ 10
def FRAME_Mindy_walk5 equ 11
def FRAME_Mindy_walk6 equ 12
def FRAME_Mindy_walk7 equ 13
def FRAME_Mindy_walk8 equ 14
def FRAME_Mindy_crouch1 equ 15
def FRAME_Mindy_crouch2 equ 16
def FRAME_Mindy_crouch3 equ 17
def FRAME_Mindy_crouch4 equ 18
def FRAME_Mindy_crouch_last equ 19
def FRAME_Mindy_crouch_lean1 equ 20
def FRAME_Mindy_crouch_lean2 equ 21
def FRAME_Mindy_crouch_lean equ 22
def FRAME_Mindy_crouch_leanout1 equ 23
def FRAME_Mindy_crouch_leanout_last equ 24
def FRAME_Mindy_uncrouch_1 equ 25
def FRAME_Mindy_uncrouch_2 equ 26
def FRAME_Mindy_uncrouch_3 equ 27
def FRAME_Mindy_uncrouch_last equ 28
def FRAME_Mindy_hoist_leap_1 equ 29
def FRAME_Mindy_hoist_leap_2 equ 30
def FRAME_Mindy_hoist_leap_3 equ 31
def FRAME_Mindy_hoist_leap_4 equ 32
def FRAME_Mindy_hoist_leap_last equ 33
def FRAME_Mindy_hoist_climb_1 equ 34
def FRAME_Mindy_hoist_climb_2 equ 35
def FRAME_Mindy_hoist_climb_3 equ 36
def FRAME_Mindy_hoist_climb_4 equ 37
def FRAME_Mindy_hoist_climb_5 equ 38
def FRAME_Mindy_hoist_climb_6 equ 39
def FRAME_Mindy_hoist_climb_last equ 40
export FRAME_Mindy_stand
export FRAME_Mindy_turn
export FRAME_Mindy_stop1
export FRAME_Mindy_stop2
export FRAME_Mindy_stop_last
export FRAME_Mindy_start1
export FRAME_Mindy_start2
export FRAME_Mindy_walk1
export FRAME_Mindy_walk2
export FRAME_Mindy_walk3
export FRAME_Mindy_walk4
export FRAME_Mindy_walk5
export FRAME_Mindy_walk6
export FRAME_Mindy_walk7
export FRAME_Mindy_walk8
export FRAME_Mindy_crouch1
export FRAME_Mindy_crouch2
export FRAME_Mindy_crouch3
export FRAME_Mindy_crouch4
export FRAME_Mindy_crouch_last
export FRAME_Mindy_crouch_lean1
export FRAME_Mindy_crouch_lean2
export FRAME_Mindy_crouch_lean
export FRAME_Mindy_crouch_leanout1
export FRAME_Mindy_crouch_leanout_last
export FRAME_Mindy_uncrouch_1
export FRAME_Mindy_uncrouch_2
export FRAME_Mindy_uncrouch_3
export FRAME_Mindy_uncrouch_last
export FRAME_Mindy_hoist_leap_1
export FRAME_Mindy_hoist_leap_2
export FRAME_Mindy_hoist_leap_3
export FRAME_Mindy_hoist_leap_4
export FRAME_Mindy_hoist_leap_last
export FRAME_Mindy_hoist_climb_1
export FRAME_Mindy_hoist_climb_2
export FRAME_Mindy_hoist_climb_3
export FRAME_Mindy_hoist_climb_4
export FRAME_Mindy_hoist_climb_5
export FRAME_Mindy_hoist_climb_6
export FRAME_Mindy_hoist_climb_last
; Maximum tiles per frame: 9
;
; Controller reading for Game Boy and Super Game Boy
;
; Copyright 2018, 2020 Damian Yerrick
;
; This software is provided 'as-is', without any express or implied
; warranty. In no event will the authors be held liable for any damages
; arising from the use of this software.
;
; Permission is granted to anyone to use this software for any purpose,
; including commercial applications, and to alter it and redistribute it
; freely, subject to the following restrictions:
;
; 1. The origin of this software must not be misrepresented; you must not
; claim that you wrote the original software. If you use this software
; in a product, an acknowledgment in the product documentation would be
; appreciated but is not required.
; 2. Altered source versions must be plainly marked as such, and must not be
; misrepresented as being the original software.
; 3. This notice may not be removed or altered from any source distribution.
;
include "hardware.inc"
def DAS_DELAY equ 15
def DAS_SPEED equ 3
SECTION "hram_pads", HRAM
hCurKeys:: ds 1
hNewKeys:: ds 1
hLastKeyLY:: ds 1
SECTION "ram_pads", WRAM0
das_keys:: ds 1
das_timer:: ds 1
wJoyIRQCapability:: ds 1
SECTION "rom_pads", ROM0
; Controller reading ;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;
; This controller reading routine is optimized for size.
; It stores currently pressed keys in hCurKeys (1=pressed) and
; keys newly pressed since last read in hNewKeys, with the same
; nibble ordering as the Game Boy Advance.
; 76543210
; |||||||+- A
; ||||||+-- B
; |||||+--- Select
; ||||+---- Start
; |||+----- Right
; ||+------ Left
; |+------- Up
; +-------- Down
; R
; L (just kidding)
read_pad::
; Poll half the controller
ld a,P1F_GET_BTN
call .onenibble
ld b,a ; B7-4 = 1; B3-0 = unpressed buttons
; Poll the other half
ld a,P1F_GET_DPAD
call .onenibble
swap a ; A3-0 = unpressed directions; A7-4 = 1
xor b ; A = pressed buttons + directions
ld b,a ; B = pressed buttons + directions
; And release the controller
ld a,P1F_GET_NONE
ldh [rP1],a
; Combine with previous hCurKeys to make hNewKeys
ldh a,[hCurKeys]
xor b ; A = keys that changed state
and b ; A = keys that changed to pressed
ldh [hNewKeys],a
ld a,b
ldh [hCurKeys],a
ret
.onenibble:
ldh [rP1],a ; switch the key matrix
call .knownret ; burn 10 cycles calling a known ret
ldh a,[rP1] ; ignore value while waiting for the key matrix to settle
ldh a,[rP1]
ldh a,[rP1] ; this read counts
or $F0 ; A7-4 = 1; A3-0 = unpressed keys
.knownret:
ret
;;
; Adds held keys to hNewKeys, DAS_DELAY frames after press and
; every DAS_SPEED frames thereafter
; @param B which keys are eligible for autorepeat
autorepeat::
; If no eligible keys are held, skip all autorepeat processing
ldh a,[hCurKeys]
and b
ret z
ld c,a ; C: Currently held
; If any keys were newly pressed, set the eligible keys among them
; as the autorepeating set. For example, changing from Up to
; Up+Right sets Right as the new autorepeating set.
ldh a,[hNewKeys]
ld d,a ; D: hNewKeys
or a
jr z,.no_restart_das
and b
ld [das_keys],a
ld a,DAS_DELAY
jr .have_das_timer
.no_restart_das:
; If time has expired, merge in the autorepeating set
ld a,[das_timer]
dec a
jr nz,.have_das_timer
ld a,[das_keys]
and c
or d
ldh [hNewKeys],a
ld a,DAS_SPEED
.have_das_timer:
ld [das_timer],a
ret
SECTION "rst60", ROM0[$0060]
push af
ldh a, [rLY]
ldh [hLastKeyLY], a
pop af
reti ; jp joypad_handler
db $ff,$ff,$00,$25,$3b,$46,$79,$9e,$e5,$9b,$e4,$07,$d3,$ee,$d0,$ff,$bb,$7f,$9f,$ff,$00,$b4,$fb,$45,$ba,$4d,$b2,$6f,$d5,$05,$2a,$f7,$48,$ff,$4a,$de,$7f,$ff,$ff,$00,$a5,$db,$66,$99,$6e,$95,$eb,$34,$07,$c3,$be,$90,$ff,$bb,$00,$b4,$fc,$42,$be,$49,$b7,$69,$d7,$05,$2b,$f7,$4b,$ff,$4d,$dd,$7f,$f9,$ff,$02,$ff,$00,$7f,$80,$00,$ff,$30,$00,$20,$10,$3f,$00,$00,$3f,$20,$10,$c0,$3f,$00,$00,$3f,$20,$10,$c0,$3f,$00,$00,$3f,$20,$10,$02,$ff,$00,$fe,$01,$00,$ff,$0c,$00,$04,$08,$fc,$00,$00,$fc,$04,$08,$c0,$fc,$00,$00,$fc,$04,$08,$c0,$fc,$00,$00,$fc,$04,$08,$00,$25,$3b,$46,$79,$9e,$e5,$9b,$e4,$03,$d3,$ee,$d0,$ff,$bb,$e4,$15,$c0,$ff,$a0,$c0,$a0,$55,$c0,$a0,$c0,$a0,$00,$b4,$fb,$45,$ba,$4d,$b2,$6f,$d5,$05,$2a,$f7,$a2,$ff,$90,$00,$3f,$ff,$00,$ff,$00,$a5,$db,$66,$99,$6e,$95,$ef,$34,$00,$e7,$be,$14,$ef,$9b,$64,$bb,$44,$3f,$00,$ff,$ff,$00,$b4,$fc,$42,$be,$49,$b7,$69,$d7,$05,$2b,$f7,$ab,$ff,$95,$05,$15,$fb,$07,$f9,$fb,$f9,$55,$fb,$f9,$fb,$f9,$00,$03,$00,$00,$03,$7f,$00,$40,$3f,$00,$5f,$20,$51,$2e,$2f,$10,$2c,$13,$02,$23,$1c,$3f,$00,$00,$3f,$00,$ff,$d0,$fc,$04,$f8,$74,$88,$00,$94,$68,$fa,$04,$8a,$74,$e2,$1c,$00,$7e,$80,$80,$7e,$00,$c0,$40,$80,$3c,$80,$40,$00,$c0,$01,$03,$00,$02,$01,$05,$03,$04,$00,$0a,$05,$0e,$01,$16,$0f,$1f,$07,$11,$2e,$1f,$20,$3f,$00,$00,$ff,$d0,$80,$40,$80,$20,$c0,$00,$60,$80,$50,$e0,$68,$d0,$e8,$f0,$00,$64,$d8,$1c,$e0,$c0,$00,$00,$c0,$3c,$80,$40,$00,$c0,$b8,$00,$01,$04,$03,$00,$06,$01,$46,$0f,$61,$1e,$25,$1a,$00,$2d,$32,$1d,$63,$1c,$7b,$dc,$27,$00,$d8,$a7,$5b,$ac,$73,$4e,$31,$7f,$00,$00,$99,$0d,$f2,$1d,$e2,$dd,$27,$02,$da,$3d,$e6,$99,$f6,$49,$3f,$00,$cd,$32,$ec,$d3,$6f,$97,$ff,$cf,$05,$3b,$f7,$91,$7f,$b9,$ed,$01,$00,$19,$0c,$bd,$7c,$ff,$4f,$55,$44,$c1,$75,$9f,$55,$12,$d3,$7f,$1e,$55,$9e,$bc,$37,$e7,$30,$00,$00,$80,$80,$c0,$c0,$00,$d8,$d8,$b0,$f0,$9a,$fa,$1e,$fe,$04,$7c,$fc,$fe,$fe,$e6,$74,$ff,$73,$ff,$fe,$fe,$17,$fb,$ff,$e3,$26,$07,$7e,$7f,$e7,$ff,$f3,$14,$7b,$7f,$7f,$74,$3c,$3f,$1c,$0e,$1f,$1f,$0f,$0f,$15,$cf,$ff,$ff,$3d,$7e,$55,$f7,$a7,$cf,$9f,$55,$e6,$de,$ff,$7f,$57,$77,$ef,$ff,$0c,$fc,$fc,$fe,$fe,$fc,$fc,$cc,$f8,$f8,$f0,$f0,$3f,$ff,$ff,$c0,$3f,$bf,$df,$df,$c4,$c4,$3f,$ff,$ff,$00,$bf,$bf,$bb,$bb,$7b,$7b,$37,$37,$2e,$00,$03,$01,$00,$ff,$b0,$e0,$40,$b0,$00,$f8,$08,$10,$ec,$08,$76,$77,$00,$7f,$0c,$10,$2f,$11,$2e,$01,$3e,$33,$04,$3b,$00,$3f,$a8,$03,$07,$0f,$04,$1b,$00,$18,$26,$10,$6e,$20,$de,$00,$fc,$03,$20,$dc,$28,$d4,$08,$f4,$33,$00,$fc,$10,$ec,$2b,$00,$c0,$80,$00,$ff,$bb,$3f,$7f,$30,$11,$6e,$21,$de,$20,$df,$3b,$00,$fc,$fe,$c0,$08,$f6,$04,$fb,$00,$ff,$15,$df,$e0,$9f,$df,$9f,$55,$df,$9f,$df,$9f,$15,$03,$ff,$05,$03,$05,$55,$03,$05,$03,$05,$20,$00,$00,$03,$03,$0c,$0f,$30,$33,$3f,$40,$7f,$80,$c8,$3f,$c0,$40,$0f,$70,$0a,$03,$3c,$00,$0f,$03,$00,$83,$3f,$3f,$c0,$ff,$00,$ff,$ff,$c2,$3f,$c0,$00,$ff,$3f,$83,$fc,$fc,$03,$ff,$00,$ff,$ff,$c2,$fc,$03,$00,$ff,$fc,$a0,$00,$c0,$c0,$30,$f0,$0c,$33,$fc,$02,$fe,$01,$c8,$fc,$03,$02,$f0,$0e,$0a,$c0,$3c,$00,$f0,$c0,$00,$00,$0b,$0a,$1b,$1b,$55,$5d,$6a,$56,$00,$37,$3f,$fe,$bf,$fd,$de,$7e,$77,$00,$3f,$3f,$ef,$af,$d7,$c7,$ef,$ef,$0c,$7f,$7f,$3f,$3f,$1f,$1f,$00,$10,$10,$a8,$08,$d8,$d8,$f4,$f4,$00,$f6,$d6,$fe,$de,$7c,$7c,$fc,$fc,$30,$fe,$fe,$ef,$ef,$d7,$c7,$00,$ee,$ee,$fc,$fc,$fe,$fe,$f0,$f0,$00,$00,$38,$10,$6c,$38,$d6,$10,$ee,$00,$82,$fe,$44,$7c,$38,$38,$30,$30,$00,$13,$11,$d7,$93,$f6,$f6,$7e,$7e,$03,$1c,$1c,$18,$18,$08,$08,$00,$18,$00,$28,$10,$f2,$1c,$9e,$70,$08,$ee,$d6,$38,$08,$38,$10,$10,$08,$24,$42,$18,$67,$e7,$08,$f7,$10,$10,$ff,$89,$56,$6e,$38,$38,$10,$18,$00,$5a,$24,$18,$db,$3c,$c1,$24,$18,$5a,$00,$18,$00,$c8,$88,$eb,$c9,$6f,$6f,$7e,$7e,$03,$38,$38,$18,$18,$10,$10,$08,$ff,$00,$00,$ff,$66,$44,$22,$ff,$00,$f4,$0b,$f6,$09,$e6,$19,$00,$ff,$c0,$01,$c0,$63,$80,$36,$41,$00,$14,$2b,$00,$1e,$30,$0c,$60,$18,$02,$c0,$30,$80,$60,$00,$c0,$80,$30,$f6,$09,$e4,$1b,$00,$ff,$c2,$80,$60,$00,$c0,$80,$00,$f4,$0b,$f6,$09,$e6,$19,$00,$ff,$ef,$00,$30,$f6,$09,$e4,$1b,$00,$ff,$ef,$00,$00,$f4,$0b,$f6,$09,$e6,$19,$00,$ff,$c2,$01,$06,$00,$03,$01,$30,$f6,$09,$e4,$1b,$00,$ff,$c0,$80,$03,$c6,$01,$6c,$82,$00,$28,$d4,$00,$78,$0c,$30,$06,$18,$02,$03,$0c,$01,$06,$00,$03,$01
; generated with mtset.py
section "metatiles",ROMX
metatiles_defs::
db $00,$00,$00,$00,$00,$00,$00,$00,$00,$00,$00,$00,$00,$00,$00,$00 ; 00: SKY
db $00,$00,$01,$02,$00,$00,$05,$04,$00,$00,$06,$07,$00,$00,$03,$04 ; 01: GROUND
db $00,$00,$02,$02,$00,$00,$04,$04,$00,$00,$07,$07,$00,$00,$04,$04 ; 02: GROUND_02
db $03,$03,$08,$09,$03,$03,$08,$09,$03,$03,$0a,$0b,$03,$03,$0a,$0b ; 03: LADDER
db $03,$03,$09,$09,$03,$03,$09,$09,$03,$03,$0b,$0b,$03,$03,$0b,$0b ; 04: LADDER_04
db $00,$00,$0c,$0d,$00,$00,$10,$11,$00,$00,$12,$13,$00,$00,$0e,$0f ; 05: GROUND_0HT
db $03,$03,$14,$15,$03,$03,$14,$15,$03,$03,$16,$17,$03,$03,$16,$17 ; 06: SIGN
db $03,$03,$18,$19,$03,$03,$18,$19,$03,$03,$1a,$1b,$03,$03,$1a,$1b ; 07: WARNING_SIGN
db $00,$00,$1c,$1d,$00,$00,$20,$21,$00,$00,$22,$23,$00,$00,$1e,$1f ; 08: BUSH
db $00,$00,$24,$25,$00,$00,$27,$04,$00,$00,$23,$28,$00,$00,$26,$04 ; 09: BUSH_09
db $00,$00,$24,$25,$00,$00,$27,$2a,$00,$00,$23,$28,$00,$00,$26,$29 ; 0a: TREE
db $03,$00,$2b,$00,$03,$03,$2e,$2f,$03,$00,$30,$00,$03,$03,$2c,$2d ; 0b: TREE_0B
db $00,$00,$00,$00,$03,$03,$2f,$32,$00,$00,$00,$00,$03,$03,$2d,$31 ; 0c: TREE_0C
db $00,$00,$33,$0d,$00,$00,$0f,$11,$00,$00,$34,$13,$00,$00,$11,$0f ; 0d: CAVE
db $01,$01,$35,$36,$01,$01,$39,$3a,$01,$01,$3b,$3c,$01,$01,$37,$38 ; 0e: CLOUD
db $02,$00,$3d,$3e,$02,$00,$3d,$3e,$00,$00,$3f,$40,$00,$00,$3f,$40 ; 0f: SMBUSH
db $00,$00,$00,$00,$00,$00,$00,$00,$02,$00,$41,$42,$02,$00,$41,$42 ; 10: FLOWER1
db $00,$00,$00,$00,$00,$00,$00,$00,$02,$00,$43,$42,$02,$00,$43,$42 ; 11: FLOWER2
db $00,$00,$00,$00,$00,$00,$00,$00,$02,$00,$44,$42,$02,$00,$44,$42 ; 12: FLOWER3
db $00,$00,$00,$00,$00,$00,$00,$00,$02,$00,$45,$42,$02,$00,$45,$42 ; 13: TALL_FLOWER
db $00,$00,$00,$00,$00,$00,$00,$00,$00,$00,$46,$42,$00,$00,$46,$42 ; 14: TALL_FLOWER_14
db $00,$00,$00,$00,$00,$00,$00,$00,$00,$00,$00,$00,$00,$00,$00,$00 ; 15: --
db $00,$03,$00,$47,$00,$03,$00,$47,$00,$03,$00,$47,$00,$03,$00,$47 ; 16: BRIDGE_RAIL
db $00,$00,$00,$00,$00,$00,$00,$00,$00,$00,$00,$00,$00,$00,$00,$00 ; 17: --
db $00,$00,$00,$00,$00,$00,$00,$00,$00,$00,$00,$00,$00,$00,$00,$00 ; 18: --
db $00,$00,$00,$00,$00,$00,$00,$00,$00,$00,$00,$00,$00,$00,$00,$00 ; 19: --
db $00,$00,$00,$00,$00,$00,$00,$00,$00,$00,$00,$00,$00,$00,$00,$00 ; 1a: --
db $00,$00,$00,$00,$00,$00,$00,$00,$00,$00,$00,$00,$00,$00,$00,$00 ; 1b: --
db $00,$00,$00,$00,$00,$00,$00,$00,$00,$00,$00,$00,$00,$00,$00,$00 ; 1c: --
db $03,$03,$48,$49,$03,$03,$48,$49,$03,$00,$4a,$00,$03,$00,$4a,$00 ; 1d: BRIDGE_BRACE_L
db $03,$00,$4b,$00,$03,$00,$4b,$00,$03,$00,$4c,$00,$03,$00,$4c,$00 ; 1e: BRIDGE_CENTER
db $03,$00,$4d,$00,$03,$00,$4d,$00,$03,$03,$4e,$4f,$03,$03,$4e,$4f ; 1f: BRIDGE_BRACE_R
metatiles_chains::
db 0,2,2,4,4,13,1,1,9,1,11,12,1,13,0,1
db 1,1,1,20,1,0,30,0,0,0,0,0,0,0,0,0
metatiles_palettes::
dw 32437,1002,682,320
dw 32437,32767,22197,0
dw 32437,1023,21535,10
dw 32437,703,341,1023
export MT_SKY
export MT_GROUND
export MT_GROUND_02
export MT_LADDER
export MT_LADDER_04
export MT_GROUND_0HT
export MT_SIGN
export MT_WARNING_SIGN
export MT_BUSH
export MT_BUSH_09
export MT_TREE
export MT_TREE_0B
export MT_TREE_0C
export MT_CAVE
export MT_CLOUD
export MT_SMBUSH
export MT_FLOWER1
export MT_FLOWER2
export MT_FLOWER3
export MT_TALL_FLOWER
export MT_TALL_FLOWER_14
export MT_BRIDGE_RAIL
export MT_BRIDGE_BRACE_L
export MT_BRIDGE_CENTER
export MT_BRIDGE_BRACE_R
export MT_LAST_VALUE
export MT_NUM_PALETTES
def MT_SKY equ 0
def MT_GROUND equ 1
def MT_GROUND_02 equ 2
def MT_LADDER equ 3
def MT_LADDER_04 equ 4
def MT_GROUND_0HT equ 5
def MT_SIGN equ 6
def MT_WARNING_SIGN equ 7
def MT_BUSH equ 8
def MT_BUSH_09 equ 9
def MT_TREE equ 10
def MT_TREE_0B equ 11
def MT_TREE_0C equ 12
def MT_CAVE equ 13
def MT_CLOUD equ 14
def MT_SMBUSH equ 15
def MT_FLOWER1 equ 16
def MT_FLOWER2 equ 17
def MT_FLOWER3 equ 18
def MT_TALL_FLOWER equ 19
def MT_TALL_FLOWER_14 equ 20
def MT_BRIDGE_RAIL equ 22
def MT_BRIDGE_BRACE_L equ 29
def MT_BRIDGE_CENTER equ 30
def MT_BRIDGE_BRACE_R equ 31
def MT_LAST_VALUE equ 31
def MT_NUM_PALETTES equ 4
include "hardware.inc"
include "global.inc"
def MINDY_MAX_TILES_PER_CEL equ 9
def MINDY_EST_LINES_PER_TILE equ 5
def MINDY_X equ 288
def MINDY_Y equ 144
def MINDY_NUM_FRAMES equ 41
export MINDY_X, MINDY_Y
section "Mindy_state", WRAM0
wMindyLoadedCel: ds 1
wMindyDisplayCelBase: ds 1
wMindyFacing:: ds 1
section "Mindy", ROMX,BANK[1]
mindy_init::
xor a
ld [wMindyDisplayCelBase], a
dec a
ld [wMindyLoadedCel], a
ld hl, Mindy_palette
lb bc, Mindy_palette.end - Mindy_palette, low(rOCPS)
ld a, $B0
jp set_gbc_palette
mindy_set_next_cel::
ld a, [wMindyLoadedCel]
inc a
cp MINDY_NUM_FRAMES
jr c, .noFrameWrap
xor a
.noFrameWrap:
fallthrough mindy_set_cel_A
mindy_set_cel_A::
; don't load it if it's already loaded
ld hl, wMindyLoadedCel
cp [hl]
ret z
ld [hl], a
add a
add low(Mindy_mspr)
ld l, a
adc high(Mindy_mspr)
sub l
ld h, a
ld a, [hl+]
ld d, [hl]
ld e, a
; DE points at a cel definition:
; number of distinct tiles, tile IDs, and horizontal strips
ld a, [de]
inc de
or a
ret z ; blank cel
ld c, a ; C: tile count
; Find the destination address in CHR RAM
ld a, [wMindyDisplayCelBase]
cp 1
sbc a
and MINDY_MAX_TILES_PER_CEL
ld [wMindyDisplayCelBase], a
ld h, $8000 >> 12
ld l, a
rept 4
add hl, hl
endr
.tileloop:
; Grab one tile ID from the cel definition
ld a, [de]
inc de
push de
; Calculate ROM address of this tile
ld d, 0
rept 4
add a
rl d
endr
add low(Mindy_chr)
ld e, a
ld a, d
adc high(Mindy_chr)
ld d, a
; Copy it
ld b, 16/4
call hblankcopy
pop de
dec c
jr nz, .tileloop
ret
mindy_draw_current_cel::
ld hl, wCameraY
ld a, low(MINDY_Y)
sub [hl]
ldh [draw_metasprite.hYLo], a
ld a, high(MINDY_Y)
sbc 0
ldh [draw_metasprite.hYHi], a
ld hl, wCameraX
ld a, low(MINDY_X)
sub [hl]
inc hl
ldh [draw_metasprite.hXLo], a
ld a, high(MINDY_X)
sbc [hl]
ldh [draw_metasprite.hXHi], a
ld a, [wMindyFacing]
ldh [draw_metasprite.hAttr], a
ld a, [wMindyDisplayCelBase]
ld [draw_metasprite.hBaseTile], a
; lookup the metatile
ld a, [wMindyLoadedCel]
add a
add low(Mindy_mspr)
ld l, a
adc high(Mindy_mspr)
sub l
ld h, a ; HL: pointer to pointer to cel
ld a, [hl+]
ld h, [hl]
ld l, a ; HL: pointer to cel's tile count
ld a, [hl+]
add l
ld l, a
adc h
sub l
ld h, a ; HL: pointer to cel's rectangles
jp draw_metasprite
def TMARGIN equ 16
def LMARGIN equ 8
def SPRITEHT equ 8 ; or 16?
def SPRITEWID equ 8
section "metasprite", ROM0
;;
; Draws to shadow OAM a list of sprites forming one cel.
;
; The cel data is of the form
; (Y, X, attributes, tile+)+, $00
; where:
; Y is excess-128 offset of sprite top down from hotspot (128 is center)
; X is excess-128 offset to right of hotspot (128 is center)
; attributes is a bitfield, where bits 4-0 go to OAM attribute 3
; and 7-5 are the number of tiles to follow minus 1
; 7654 3210
; |||| |+++- GBC palette ID
; |||| +---- GBC bank ID
; |||+------ DMG palette ID
; +++------- Length of strip (0: 1 sprite/8 pixels; 7: 8 sprites/64 pixels)
; tile bits 7-6 are flip, and 5-0 are data
; 7654 3210
; ||++-++++- offset from hmsprBaseTile
; |+-------- Flip this sprite horizontally
; +--------- Flip this tile vertically
; and "+" means something is repeated 1 or more times
;
; @param hYHi, hYLo 16-bit Y coordinate of hotspot
; @param hXHi, hXLo 16-bit Y coordinate of hotspot
; @param hAttr palette and horizontal flip
; @param hBaseTile index of this sprite sheet in VRAM
; @param HL pointer to cel data
; Uses 8 bytes of locals for arguments and 4 bytes for scratch
draw_metasprite::
; args
local hYLo
local hYHi
local hXLo
local hXHi
local hAttr
local hSheetID
local hFrame
local hBaseTile
; internal
local hXAdd
local hStripY
local hStripXLo
local hStripXHi
ldh a,[.hAttr]
ld c,a ; C = flip flags
; Correct coordinates for offset binary representation.
; Not correcting for Y flip until a Y flip is needed in a game.
ldh a,[.hYLo]
sub 128-TMARGIN
ldh [.hYLo],a
ldh a,[.hYHi]
sbc 0
ldh [.hYHi],a
; Convert X coordintes and set increase direction for X flip
ld b,128-LMARGIN
ld a,SPRITEWID
bit OAMB_XFLIP,c
jr z,.noxcoordflipcorrect
ld b,127+SPRITEWID-LMARGIN
ld a,-SPRITEWID
.noxcoordflipcorrect:
ldh [.hXAdd],a
ldh a,[.hXLo]
sub b
ldh [.hXLo],a
ldh a,[.hXHi]
sbc 0
ldh [.hXHi],a
; Load destination address
ld de, wOAMUsed
ld a, [de]
ld e, a
.rowloop:
; Invariants here:
; DE is multiple of 4 and within shadow OAM
; HL at start of sprite strip
; C equals [.hAttr], not modified by a strip
; Load Y strip offset
ld a,[hl+]
or a ; Y=0 (that is, -128) terminates cel
ret z
bit OAMB_YFLIP,c
jr z,.noystripflipcorrect
cpl
.noystripflipcorrect:
ld b,a
ldh a,[.hYLo]
add b
ld b,a
ldh a,[.hYHi]
adc 0
jr nz,.strip_below_screen
ld a,b
cp TMARGIN+1-SPRITEHT
jr c,.strip_below_screen
cp SCRN_Y+TMARGIN
jr c,.strip_within_y_range
.strip_below_screen:
inc hl ; skip X position
ld a,[hl+] ; load length and attributes
and $E0 ; strip PVH bits contain width-1
rlca
rlca
rlca
inc a
add l
ld l,a
jr nc,.rowloop
inc h
jr .rowloop
.strip_within_y_range:
ldh [.hStripY],a
; Load X strip offset
ld a,[hl+]
bit OAMB_XFLIP,c
jr z,.noxstripflipcorrect
cpl
.noxstripflipcorrect:
ld b,a
ldh a,[.hXLo]
add b
ldh [.hStripXLo],a
ldh a,[.hXHi]
adc 0
ldh [.hStripXHi],a
; Third byte of strip is palette (bits 4-0) and length (bits 7-5)
ld a,[hl]
and $1F
xor c
ld c,a
ld a,[hl+]
and $E0 ; strip PVH bits contain width-1
rlca
rlca
rlca
inc a
ld b,a
; Copy sprites to OAM
.spriteloop:
push bc ; sprite count and strip attribute
ldh a,[.hStripY]
ld [de],a
; Only resulting X locations in 1-167 are in range
ldh a,[.hStripXHi]
or a
jr nz,.skip_one_tile
ldh a,[.hStripXLo]
or a
jr z,.skip_one_tile
cp SCRN_X+LMARGIN
jr nc,.skip_one_tile
; We're in range, and Y is already written.
; Acknowledge writing Y, and write X, tile, and attribute
inc e
ld [de],a
inc e
ld a,[hl]
and $3F
ld b,a
ldh a,[.hBaseTile]
add b
ld [de],a
inc e
ld a,[hl]
and $C0 ; combine with tile flip attribute
rrca
xor c
ld [de],a
inc e
.skip_one_tile:
ldh a,[.hXAdd]
ld b,a
ldh a,[.hStripXLo]
add b
ldh [.hStripXLo],a
ldh a,[.hStripXHi]
adc 0
bit 7,b
jr z,.anoneg
dec a
.anoneg:
ldh [.hStripXHi],a
pop bc
inc hl
dec b
jr nz,.spriteloop
ld a, e
ld [wOAMUsed], a
ldh a,[.hAttr]
ld c,a
jp .rowloop
Mindy_mspr:
include "Mindy.asm.inc"
Mindy_palette:
drgb $FFFFFF, $FFFFFF, $FFAAAA, $AA5555
drgb $FFFFFF, $AAFF00, $5555AA, $000055
.end
section "Mindy_chr", ROMX, bank[1], align[4]
Mindy_chr:
include "Mindy.2b.inc"
include "hardware.inc"
include "global.inc"
def GBC_BGP_EMULATION equ 1
section "Shadow OAM", WRAM0, ALIGN[8]
wShadowOAM:: ds 160
wOAMUsed:: ds 1
section "PPU various variables", HRAM
hVblanks:: ds 1
hCapability:: ds 1
section "vblank_isr", ROM0[$40]
push af
ld a, [hVblanks]
inc a
ldh [hVblanks], a
pop af
reti
section "ppuclear", ROM0
;;
; Waits for forced blank (rLCDC bit 7 clear) or vertical blank
; (rLY >= 144). Use before VRAM upload or before clearing rLCDC bit 7.
busy_wait_vblank::
; If rLCDC bit 7 already clear, we're already in forced blanking
ldh a,[rLCDC]
rlca
ret nc
; Otherwise, wait for LY to become 144 through 152.
; Most of line 153 is prerender, during which LY reads back as 0.
.wait:
ldh a, [rLY]
cp 144
jr c, .wait
ret
lcd_off::
call busy_wait_vblank
; Use a RMW instruction to turn off only bit 7
ld hl, rLCDC
res 7, [hl]
ret
;;
; Moves sprites in the display list from wShadowOAM+[wOAMUsed]
; through wShadowOAM+$9C offscreen by setting their Y coordinate to
; 0, which is completely above the screen top (16).
lcd_clear_oam::
; Destination address in shadow OAM
ld hl, wOAMUsed
ld a, [hl]
and $FC
ld l,a
; iteration count
rrca
rrca
add 256 - 40
ld c,a
xor a
.rowloop:
ld [hl+],a
inc l
inc l
inc l
inc c
jr nz, .rowloop
ret
load_full_nam::
ld bc,256*20+18
fallthrough load_nam
;;
; Copies a B column by C row tilemap from HL to screen at DE.
load_nam::
push bc
push de
.byteloop:
ld a,[hl+]
ld [de],a
inc de
dec b
jr nz,.byteloop
; Move to next screen row
pop de
ld a,32
add e
ld e,a
jr nc,.no_inc_d
inc d
.no_inc_d:
; Restore width; do more rows remain?
pop bc
dec c
jr nz,load_nam
ret
;;
; Turns off rendering and clears both GBC tilemaps' attribute plane.
; @return A=0
clear_gbc_attr::
call lcd_off
ldh a, [hCapability]
and $80
add a
ret nc
rla
ldh [rVBK],a
ld hl, $9800
ld c, l
ld a, l
.loop:
rst memset_tiny
bit 5, h
jr z, .loop
ldh [rVBK], a
ret
section "hblankcopy", ROM0
;;
; Performs an hblank copy that isn't a stack copy.
; Copies 4*B bytes from DE to HL (opposite of standard memcpy)
; at 4 bytes per line. C unchanged
hblankcopy::
ldh a, [rLCDC]
add a
jr nc, .unbusy_done
; wait for mode not 0
.unbusy:
ldh a, [rSTAT]
and $03
jr z, .unbusy
.unbusy_done:
push bc
; then wait for mode 0 or 1
ld a, [de]
ld c, a
inc e
ld a, [de]
ld b, a
inc e
.busy:
ldh a, [rSTAT]
and $02
jr nz, .busy ; spin wait can take up to 12 cycles
ld a, c ; 1
ld [hl+], a ; 2
ld a, b ; 1
ld [hl+], a ; 2
ld a, [de] ; 2
ld [hl+], a ; 2
inc e ; 1
ld a, [de] ; 2
ld [hl+], a ; 2
inc de
pop bc
dec b
jr nz, hblankcopy
ret
SECTION "load_gbc_palette", ROM0, align[3]
if GBC_BGP_EMULATION
gbmonopalette:
drgb $FFFFFF, $B2B2B2, $666666, $000000
;;
; Emulates mono palette feature on Game Boy Color.
; Call this only during blanking.
set_obp1::
ldh [rOBP1],a
ld bc,$8800 + low(rOCPS)
jr set_gbc_mono_palette
;;
; Emulates mono palette feature on Game Boy Color.
; Call this only during blanking.
set_obp0::
ldh [rOBP0],a
ld bc,$8000 + low(rOCPS)
jr set_gbc_mono_palette
;;
; Emulates mono palette feature on Game Boy Color.
; Call this only during blanking.
set_bgp::
ldh [rBGP],a
ld bc,$8000 + low(rBCPS)
fallthrough set_gbc_mono_palette
;;
; Emulates mono palette setting on Game Boy Color.
; @param A BGP or OBP0 value
; @param B offset into palette memory (0, 8, 16, ..., 56) plus $80
; @param C palette port to write: LOW(rBCPS) or LOW(rOCPS)
; @return AEHL clobbered, B=0, C increased by 1, D unchanged
set_gbc_mono_palette::
rlca
ld e,a
ld a,b ; Regmap now: E=BGP<<1, A=palette offset, C=address port
ld [$FF00+c],a
inc c ; C=data port
ld b,4 ; color count
ld h,high(gbmonopalette)
ld a, e
; Regmap now: B=count of remaining colors, C=data port address,
; A=E=BGP value rlc 1, HL=pointer to start of palette
.loop:
and %00000110
or low(gbmonopalette)
ld l,a ; now L points to this color so stuff it into the palette
ld a,[hl+]
ld [$FF00+c],a
ld a,[hl-]
ld [$FF00+c],a
ld a, e ; move to next bitfield of BGP
rrca
rrca
ld e, a
dec b
jr nz,.loop
; Restore BGP value
rrca
ret
endc
;;
; Loads native GBC palette data.
; @param A offset into palette memory (0, 8, 16, ..., 56) plus $80
; @param B number of bytes to copy: 8 times number of subpalettes
; @param C palette port to write: LOW(rBCPS) or LOW(rOCPS)
; @param HL data source
; @return HL at end, C increased by 1, B = 0, DE unchanged
set_gbc_palette::
ld [$FF00+c],a
inc c
.loop:
ld a,[hl+]
ld [$FF00+c],a
dec b
jr nz,.loop
ret
include "hardware.inc"
include "global.inc"
section "textwindow_state", WRAM0
wWindowLoadedPage: ds 1
wWindowProgress:: ds 1 ; count of lines of text already loaded
wWindowTextPtr: ds 2
section "textwindow", ROM0
textwindow_init::
; clear pattern table
ld hl, $9000-TEXTWINDOW_ROWS*$100
xor a
ld c, a
rept TEXTWINDOW_ROWS
rst memset_tiny
endr
dec a
ld [wWindowLoadedPage], a
; set up nametable
ld hl, $9C00
ld b, TEXTWINDOW_ROWS
.rowloop:
xor a
ld [hl+], a
ld [hl+], a
ld c, 16
ld a, c
sub b ; window uses tiles $B0-$FF
swap a
call memset_inc
ld c, 14
xor a
call memset_tiny
dec b
jr nz, .rowloop
ld a, PAGE_INSTRUCTIONS
fallthrough textwindow_start_page
;;
; Draws page A
textwindow_start_page::
; If the page is already loaded and showing,
; don't try to load it again
ld hl, wWindowLoadedPage
cp [hl]
ld [hl], a
jr nz, .not_already_loaded
ld a, [wWindowProgress]
cp TEXTWINDOW_ROWS
ret z
.not_already_loaded:
ld a, [hl] ; restore loaded page
add a
ld hl, window_txts
add l
ld l, a
adc h
sub l
ld h, a
ld a, [hl+]
ld [wWindowTextPtr], a
ld a, [hl+]
ld [wWindowTextPtr+1], a
xor a
ld [wWindowProgress], a
ret
textwindow_update::
; run only if a window update is requested and the screen is on
ld a, [wWindowProgress]
cp TEXTWINDOW_ROWS
ret nc
ldh a, [rLCDC]
add a
ret nc
call vwfClearBuf
ld hl, wWindowTextPtr
ld a, [hl+]
ld h, [hl]
ld l, a
ld b, 0
call vwfPuts
; skip newline; don't skip NUL terminator
ld a, [hl]
or a
jr z, .no_skip_newline
inc hl
.no_skip_newline:
ld a, l
ld [wWindowTextPtr], a
ld a, h
ld [wWindowTextPtr+1], a
ld hl, wWindowProgress
ld a, [hl]
inc [hl]
add $8B
ld h, a
ld l, 1
ld c, 16
jp vwfPutBufHBlank
section "window_txts", ROMX, BANK[1]
window_txts:
dw coin1_msg, coin2_msg, coin3_msg, coin4_msg, coin5_msg
dw sign1_msg, sign2_msg, sign3_msg, sign4_msg, Mindy_msg
dw win_msg, instructions_msg
def LF equ $0A
coin1_msg:
db "800 Rupees",LF
db "Currency of Hyrule and India",LF
db "(That's about $10)",0
coin2_msg:
db "800 Pokedollars",LF
db "Currency of Kanto",LF
db "and the Russia",LF
db "(That's about $10)",0
coin3_msg:
db "1400 Bells",LF
db "Currency of territories",LF
db "controlled by the Nook family",LF
db "(That's about $10)",0
coin4_msg:
db "5 Eurodollars",LF
db "Currency of Night City and",LF
db "banks outside the USA",LF
db "Invented by USSR in 1956",LF
db "Banned in USSR in Cyberpunk",0
coin5_msg:
db "A roll of quarters",LF
db "Currency of Toy Town",LF
db "(That's about $10)",0
sign1_msg:
db "DANGER",LF
db "BRIDGE OUT AHEAD",0
sign2_msg:
db "BEWARE OF FUNNY MONEY",LF
db "If something looks off,",LF
db "take no cash.",0
sign3_msg:
db "NO",LF
db "JUMPING",0
sign4_msg:
db "EVENT CALENDAR",LF
db "May 28-June 4:",LF
db " Summer Games Done Quick",LF
db "June 10: Yogic Flying Lesson",LF
db "June 16-18: Flea Market",0
Mindy_msg:
db "Hi! I'm Mindy!",LF
db "I'm looking for money so I",LF
db "can buy Game Boy games",LF
db "like Esprit and Star Anise.",0
win_msg:
db "You found them all!",LF
db "Thanks for playing my entry",LF
db "to Games Made QVIIck.",LF
db "- Pino",0
instructions_msg:
db "Control Pad moves cursor.",LF
db "Cursor is solid when over",LF
db "something; press the",LF
db "A Button to view it.",LF
db "View all 10 things to win.",0
db $00,$00,$00,$00,$00,$00,$00,$00,$00,$00,$00,$00,$00,$00,$00,$00,$00,$00,$00,$00,$00,$00,$0e,$0e,$1f,$1b,$1f,$11,$3f,$31,$3f,$20,$00,$00,$00,$00,$00,$00,$07,$07,$0f,$0d,$0f,$08,$9f,$98,$9f,$90,$00,$00,$07,$07,$0f,$0d,$0f,$08,$8f,$8d,$87,$87,$c0,$c0,$c7,$47,$00,$00,$00,$00,$80,$80,$80,$80,$80,$80,$00,$00,$1f,$1f,$3f,$36,$00,$00,$00,$00,$00,$00,$00,$00,$00,$00,$00,$00,$f8,$f8,$fe,$0e,$00,$00,$00,$00,$00,$00,$00,$00,$00,$00,$00,$00,$0f,$0f,$3f,$38,$00,$00,$1c,$1c,$3e,$36,$3e,$22,$3e,$22,$3e,$22,$fe,$e2,$fe,$22,$00,$00,$00,$00,$00,$00,$00,$00,$00,$00,$00,$00,$70,$70,$f8,$d8,$03,$03,$07,$06,$07,$04,$07,$04,$07,$06,$07,$04,$3f,$3e,$7f,$6f,$80,$80,$c0,$c0,$c0,$40,$c0,$40,$c0,$40,$c0,$40,$df,$df,$ff,$f0,$00,$00,$00,$00,$00,$00,$00,$00,$00,$00,$00,$00,$e0,$e0,$f8,$38,$00,$00,$00,$00,$01,$01,$01,$01,$01,$01,$01,$01,$01,$01,$01,$01,$00,$00,$e0,$e0,$f0,$b0,$f0,$10,$f0,$10,$f0,$10,$ff,$1f,$ff,$10,$00,$00,$01,$01,$03,$03,$03,$02,$03,$03,$01,$01,$c0,$c0,$f1,$71,$00,$00,$c7,$c7,$ef,$6d,$ef,$28,$ef,$68,$cf,$c8,$0f,$08,$cf,$c8,$00,$00,$00,$00,$80,$80,$80,$80,$80,$80,$80,$80,$8f,$8f,$9f,$99,$00,$00,$00,$00,$00,$00,$00,$00,$00,$00,$00,$00,$07,$07,$9f,$9c,$3f,$20,$3f,$20,$7f,$60,$7f,$44,$7f,$44,$7f,$44,$7f,$46,$ff,$c6,$9f,$90,$ff,$f0,$ff,$60,$ff,$62,$ff,$62,$ff,$62,$ff,$06,$ff,$06,$cf,$4d,$cf,$48,$ef,$68,$ef,$28,$ef,$28,$ef,$28,$ef,$28,$ff,$38,$bf,$a0,$bf,$a0,$bf,$a1,$bf,$a3,$be,$a2,$be,$a2,$be,$a2,$be,$a2,$fe,$02,$ff,$03,$ff,$e1,$3f,$31,$1f,$11,$1f,$11,$1f,$11,$1f,$11,$3f,$20,$7f,$60,$7f,$43,$7e,$46,$7c,$44,$7c,$44,$7c,$44,$7c,$44,$fe,$02,$fe,$02,$fe,$c2,$7e,$62,$3e,$22,$3e,$22,$3e,$22,$3e,$22,$fc,$8c,$fc,$84,$ff,$c7,$7f,$43,$7f,$63,$3f,$20,$3f,$30,$1f,$10,$fc,$c4,$fc,$84,$fc,$8c,$f8,$08,$f8,$18,$f0,$10,$f0,$30,$e0,$20,$ff,$c0,$ff,$80,$ff,$87,$ff,$87,$ff,$c1,$7f,$40,$7f,$70,$1f,$1e,$fc,$0c,$fc,$04,$fc,$cc,$78,$78,$e0,$e0,$f8,$38,$f8,$08,$fc,$0c,$01,$01,$01,$01,$01,$01,$01,$01,$01,$01,$01,$01,$01,$01,$01,$01,$ff,$00,$ff,$00,$ff,$0f,$f9,$19,$f0,$10,$f0,$10,$f0,$10,$f0,$10,$f3,$13,$fb,$1a,$fb,$0a,$fb,$8a,$fb,$8a,$fb,$8a,$fb,$8a,$fb,$8a,$ef,$68,$ef,$28,$ef,$28,$ef,$28,$ef,$28,$ef,$28,$ef,$28,$ef,$28,$bf,$b0,$ff,$e1,$ff,$c3,$fe,$86,$fc,$0c,$f8,$18,$fc,$0c,$fe,$46,$9f,$90,$bf,$b0,$3f,$21,$3f,$23,$3f,$20,$3f,$20,$3f,$20,$3f,$23,$fe,$02,$ff,$03,$ff,$e1,$ff,$f1,$ff,$01,$ff,$01,$ff,$01,$ff,$ff,$ff,$8e,$fb,$8a,$fb,$8b,$f9,$89,$f9,$d9,$70,$70,$00,$00,$00,$00,$ff,$07,$fd,$05,$fd,$0d,$f9,$09,$f9,$99,$f0,$f0,$00,$00,$00,$00,$ff,$18,$ff,$18,$ff,$18,$ff,$18,$ff,$bd,$e7,$e7,$00,$00,$00,$00,$be,$a2,$be,$a2,$be,$a2,$be,$a2,$be,$b6,$1c,$1c,$00,$00,$00,$00,$1f,$11,$1f,$11,$1f,$11,$1f,$11,$1f,$1b,$0e,$0e,$00,$00,$00,$00,$7e,$46,$7f,$43,$7f,$60,$3f,$20,$3f,$38,$0f,$0f,$00,$00,$00,$00,$7e,$62,$fe,$c2,$fe,$02,$fe,$02,$fe,$36,$fc,$fc,$00,$00,$00,$00,$1f,$18,$0f,$0c,$0f,$08,$1f,$18,$1f,$11,$1f,$11,$1f,$1b,$0e,$0e,$e0,$60,$c0,$40,$c0,$c0,$80,$80,$80,$80,$00,$00,$00,$00,$00,$00,$7b,$7b,$ff,$cf,$ff,$80,$ff,$c0,$7f,$70,$1f,$1f,$00,$00,$00,$00,$fc,$84,$fc,$84,$fc,$04,$fc,$0c,$f8,$38,$e0,$e0,$00,$00,$00,$00,$01,$01,$01,$01,$01,$01,$01,$01,$01,$01,$00,$00,$00,$00,$00,$00,$f0,$10,$f0,$10,$f0,$10,$f0,$10,$f0,$b0,$e0,$e0,$00,$00,$00,$00,$fb,$8a,$fb,$8a,$fb,$8a,$fb,$8a,$fb,$db,$71,$71,$00,$00,$00,$00,$ef,$28,$ef,$28,$ef,$28,$ef,$28,$ef,$6d,$c7,$c7,$00,$00,$00,$00,$ff,$c3,$ff,$e1,$bf,$b0,$9f,$98,$8f,$8c,$07,$07,$00,$00,$00,$00,$3f,$23,$bf,$a1,$ff,$f0,$df,$50,$df,$dc,$87,$87,$00,$00,$00,$00,$1e,$1e,$ff,$f3,$ff,$01,$ff,$03,$fe,$0e,$f8,$f8,$00,$00,$00,$00,$00,$00,$06,$06,$0f,$09,$1f,$11,$3e,$22,$7e,$66,$ff,$81,$ff,$81,$00,$00,$60,$60,$f0,$90,$f6,$96,$6f,$69,$6f,$68,$ff,$98,$ff,$99,$00,$00,$00,$00,$00,$00,$e1,$e1,$f3,$12,$f7,$14,$ef,$e9,$0f,$08,$00,$00,$00,$00,$00,$00,$e1,$e1,$fb,$1a,$ff,$06,$fd,$e5,$f8,$f8,$00,$00,$60,$60,$f0,$90,$f8,$98,$fc,$04,$fc,$04,$f8,$98,$f0,$90,$00,$00,$06,$06,$0f,$09,$0f,$09,$0f,$09,$0f,$09,$0f,$09,$0f,$09,$00,$00,$00,$00,$00,$00,$1f,$0e,$31,$3f,$5b,$60,$f1,$40,$a0,$cf,$00,$00,$00,$00,$00,$00,$03,$01,$86,$87,$4b,$cc,$fe,$48,$b4,$79,$00,$00,$01,$01,$03,$02,$e3,$c2,$33,$f2,$6b,$1a,$3f,$0a,$17,$ee,$00,$00,$80,$80,$c0,$40,$cc,$4c,$de,$52,$fe,$62,$fc,$44,$f8,$08,$7e,$66,$3c,$24,$3c,$24,$3c,$24,$3c,$24,$3c,$24,$18,$18,$00,$00,$ff,$99,$ff,$99,$ff,$99,$ff,$99,$ff,$99,$ff,$99,$66,$66,$00,$00,$07,$04,$03,$02,$07,$07,$0f,$09,$0f,$08,$07,$06,$01,$01,$00,$00,$f0,$10,$f8,$08,$fc,$c4,$fc,$e4,$f8,$08,$f0,$10,$e0,$e0,$00,$00,$f0,$90,$f0,$90,$f0,$90,$f0,$90,$f0,$90,$f0,$90,$60,$60,$00,$00,$0f,$09,$0f,$09,$0f,$09,$0f,$09,$0f,$09,$0f,$09,$06,$06,$00,$00,$e7,$88,$e7,$88,$60,$91,$b1,$4a,$7b,$44,$2e,$31,$1f,$0e,$00,$00,$fc,$31,$fc,$31,$cc,$32,$b6,$49,$cf,$48,$85,$86,$03,$01,$00,$00,$ff,$06,$ff,$06,$1b,$26,$37,$4a,$7b,$8a,$d3,$32,$e1,$c1,$00,$00,$f0,$10,$f8,$08,$fc,$44,$fe,$62,$df,$51,$cf,$49,$86,$86,$00,$00,$0c,$fc,$0c,$fc,$30,$ff,$30,$ff,$cf,$f0,$cf,$f0,$0f,$c0,$0f,$c0,$30,$3f,$30,$3f,$0c,$ff,$0c,$ff,$f3,$0f,$f3,$0f,$f0,$03,$f0,$03,$00,$00,$00,$00,$00,$00,$07,$00,$05,$00,$06,$00,$05,$00,$06,$00,$30,$c0,$30,$c0,$04,$f3,$08,$f3,$1d,$cc,$2e,$cc,$51,$0c,$a2,$0c,$0c,$03,$0c,$03,$10,$cf,$20,$cf,$74,$33,$b8,$33,$45,$30,$8a,$30,$00,$00,$00,$00,$00,$00,$e0,$00,$60,$00,$a0,$00,$60,$00,$a0,$00,$07,$00,$00,$00,$00,$00,$00,$00,$00,$00,$00,$00,$00,$00,$01,$00,$15,$c0,$2a,$c0,$44,$33,$08,$33,$10,$0f,$10,$0f,$03,$33,$c3,$33,$54,$03,$a8,$03,$12,$cc,$20,$cc,$08,$f0,$08,$f0,$c0,$cc,$c3,$cc,$e0,$00,$00,$00,$00,$00,$00,$00,$00,$00,$00,$00,$00,$00,$80,$00,$01,$00,$07,$00,$04,$00,$04,$00,$05,$00,$06,$00,$05,$00,$06,$00,$00,$30,$00,$30,$00,$30,$00,$30,$3f,$3f,$3f,$3f,$40,$3f,$80,$3f,$00,$0c,$00,$0c,$00,$0c,$00,$0c,$fc,$fc,$fc,$fc,$01,$fc,$02,$fc,$80,$00,$e0,$00,$20,$00,$20,$00,$60,$00,$a0,$00,$60,$00,$a0,$00,$04,$03,$00,$03,$0f,$0f,$0f,$0f,$0c,$0f,$0c,$0f,$30,$3f,$30,$3f,$40,$3f,$80,$3f,$c0,$ff,$c0,$ff,$00,$ff,$00,$ff,$00,$ff,$00,$ff,$01,$fc,$02,$fc,$03,$ff,$03,$ff,$00,$ff,$00,$ff,$00,$ff,$00,$ff,$20,$c0,$00,$c0,$f0,$f0,$f0,$f0,$30,$f0,$30,$f0,$0c,$fc,$0c,$fc,$3f,$3f,$3f,$3f,$3f,$3f,$3f,$3f,$03,$03,$03,$03,$00,$00,$00,$00,$00,$ff,$00,$ff,$ff,$ff,$ff,$ff,$ff,$ff,$ff,$ff,$c3,$ff,$c3,$ff,$fc,$fc,$fc,$fc,$fc,$fc,$fc,$fc,$c0,$c0,$c0,$c0,$00,$00,$00,$00,$00,$00,$03,$03,$07,$04,$07,$04,$07,$04,$07,$04,$07,$04,$07,$04,$00,$00,$fc,$fc,$fe,$02,$ff,$01,$ff,$f8,$87,$84,$87,$84,$ff,$f8,$00,$00,$00,$00,$00,$00,$37,$37,$ff,$c8,$ff,$c0,$ff,$c7,$f8,$c8,$00,$00,$00,$00,$00,$00,$0f,$0f,$9f,$90,$bf,$a0,$7f,$46,$7f,$4f,$00,$00,$00,$00,$00,$00,$03,$03,$87,$84,$cf,$48,$ff,$33,$ff,$31,$00,$00,$00,$00,$00,$00,$c0,$c0,$f1,$31,$fb,$0a,$ff,$cc,$f7,$f4,$00,$00,$00,$00,$00,$00,$f0,$f0,$fc,$0c,$fe,$02,$fe,$f2,$fc,$7c,$00,$00,$00,$00,$01,$01,$03,$02,$07,$04,$07,$04,$07,$04,$03,$02,$00,$00,$fe,$fe,$ff,$01,$ff,$00,$ff,$7c,$c3,$c3,$fc,$3c,$fe,$02,$00,$00,$0c,$0c,$1e,$12,$bf,$b3,$ff,$c0,$7f,$40,$3f,$33,$1e,$12,$00,$00,$00,$00,$00,$00,$0e,$0e,$9f,$91,$bf,$a0,$7f,$46,$79,$49,$00,$00,$00,$00,$00,$00,$cd,$cd,$ff,$32,$ff,$30,$ff,$31,$fe,$32,$00,$00,$03,$03,$07,$04,$cf,$cc,$ff,$30,$ff,$30,$cf,$cc,$07,$04,$00,$00,$00,$00,$80,$80,$c0,$c0,$e0,$20,$e0,$20,$c0,$c0,$80,$80,$07,$04,$07,$04,$07,$04,$07,$04,$07,$04,$07,$04,$03,$03,$00,$00,$ff,$01,$fe,$02,$fc,$fc,$80,$80,$80,$80,$80,$80,$00,$00,$00,$00,$78,$48,$78,$48,$78,$48,$78,$48,$78,$48,$78,$48,$30,$30,$00,$00,$7f,$40,$7f,$40,$7f,$4f,$7f,$47,$3f,$20,$1f,$10,$0f,$0f,$00,$00,$ef,$28,$e7,$24,$cf,$cf,$ff,$33,$ff,$30,$cf,$cc,$03,$03,$00,$00,$e3,$22,$f1,$11,$fb,$8b,$ff,$cc,$f7,$14,$e3,$23,$c0,$c0,$00,$00,$f8,$08,$fc,$04,$fe,$e2,$fe,$f2,$fc,$04,$f8,$08,$f0,$f0,$00,$00,$01,$01,$00,$00,$03,$03,$07,$04,$07,$04,$03,$02,$01,$01,$00,$00,$ff,$c1,$3f,$38,$07,$04,$ff,$f8,$ff,$01,$fe,$02,$fc,$fc,$00,$00,$1e,$12,$9e,$92,$9e,$92,$9e,$92,$1e,$12,$1e,$12,$0c,$0c,$00,$00,$79,$49,$79,$49,$79,$49,$7f,$46,$3f,$20,$1f,$11,$0e,$0e,$00,$00,$fe,$32,$fe,$32,$fe,$32,$fe,$32,$fe,$32,$fe,$32,$cc,$cc,$00,$00,$80,$80,$80,$80,$80,$80,$80,$80,$80,$80,$80,$80,$00,$00,$00,$00,$00,$00,$38,$38,$44,$44,$ba,$ba,$a2,$a2,$ba,$ba,$44,$44,$38,$38,$00,$00,$0c,$0c,$12,$12,$02,$02,$04,$04,$08,$08,$1e,$1e,$00,$00,$00,$00,$63,$63,$94,$94,$90,$90,$91,$91,$92,$92,$67,$67,$00,$00,$00,$00,$18,$18,$a4,$a4,$88,$88,$04,$04,$24,$24,$98,$98,$00,$00,$00,$00,$3c,$3c,$22,$22,$22,$22,$22,$22,$22,$22,$3c,$3c,$00,$00,$00,$00,$04,$04,$02,$02,$01,$01,$01,$01,$01,$01,$81,$81,$00,$00,$00,$00,$40,$40,$8c,$8c,$12,$12,$1e,$1e,$10,$10,$0e,$0e,$00,$00,$00,$00,$00,$00,$ee,$ee,$88,$88,$88,$88,$88,$88,$88,$88,$00,$00,$00,$00,$81,$81,$19,$19,$a5,$a5,$a1,$a1,$a1,$a1,$9d,$9d,$00,$00,$00,$00,$00,$00,$20,$20,$40,$40,$80,$80,$40,$40,$20,$20,$00,$00
db $80,$80,$80,$80,$80,$80,$80,$80,$80,$80,$80,$80,$80,$80,$80,$80,$80,$80,$80,$80,$80,$81,$82,$83,$84,$85,$86,$87,$88,$89,$8a,$8b,$8c,$8d,$8e,$8f,$90,$91,$85,$80,$80,$92,$93,$94,$95,$96,$97,$98,$99,$9a,$9b,$9c,$9d,$9e,$9f,$a0,$a1,$a2,$a3,$80,$80,$a4,$a5,$a6,$a7,$a8,$a9,$aa,$ab,$ac,$ad,$ae,$af,$b0,$b1,$b2,$b3,$b4,$b5,$80,$80,$80,$80,$80,$80,$80,$80,$80,$80,$80,$80,$80,$80,$80,$80,$80,$80,$80,$80,$80,$80,$80,$80,$80,$80,$b6,$b7,$b8,$b9,$ba,$bb,$bc,$bd,$be,$bf,$80,$80,$80,$80,$80,$80,$80,$80,$80,$80,$c0,$c1,$c2,$c3,$c4,$c5,$c6,$c7,$c8,$c9,$80,$80,$80,$80,$80,$80,$80,$80,$80,$80,$80,$80,$80,$80,$ca,$cb,$80,$80,$80,$80,$80,$80,$80,$80,$80,$80,$80,$80,$80,$80,$80,$80,$80,$cc,$cd,$ce,$cf,$80,$80,$80,$80,$80,$80,$80,$80,$80,$80,$80,$80,$80,$80,$80,$80,$d0,$d1,$d2,$d3,$80,$80,$80,$80,$80,$80,$80,$80,$80,$80,$80,$80,$80,$80,$80,$80,$d4,$d5,$d6,$d7,$80,$80,$80,$80,$80,$80,$80,$80,$80,$80,$80,$80,$80,$80,$80,$80,$d8,$d9,$da,$db,$80,$80,$80,$80,$80,$80,$80,$80,$80,$80,$80,$80,$80,$80,$80,$80,$dc,$dd,$dd,$de,$80,$80,$80,$80,$80,$80,$80,$80,$80,$80,$80,$80,$80,$80,$80,$80,$80,$80,$80,$80,$80,$80,$80,$80,$80,$80,$80,$80,$80,$80,$80,$df,$e0,$e1,$e2,$e3,$e4,$e5,$e6,$e7,$e8,$e9,$ea,$eb,$ec,$80,$80,$80,$80,$80,$80,$ed,$ee,$ef,$f0,$f1,$f2,$f3,$f4,$f5,$f6,$f7,$f8,$ed,$f9,$80,$80,$80,$80,$80,$80,$80,$80,$80,$80,$80,$80,$80,$80,$80,$80,$80,$80,$80,$80,$80,$80,$80,$80,$80,$80,$80,$80,$fa,$fb,$fc,$fd,$fe,$ff,$00,$01,$02,$03,$80,$80,$80,$80,$80
;
; PB16 decompression for Game Boy
; Copyright 2018 Damian Yerrick
;
; This software is provided 'as-is', without any express or implied
; warranty. In no event will the authors be held liable for any damages
; arising from the use of this software.
;
; Permission is granted to anyone to use this software for any purpose,
; including commercial applications, and to alter it and redistribute it
; freely, subject to the following restrictions:
;
; 1. The origin of this software must not be misrepresented; you must not
; claim that you wrote the original software. If you use this software
; in a product, an acknowledgment in the product documentation would be
; appreciated but is not required.
; 2. Altered source versions must be plainly marked as such, and must not be
; misrepresented as being the original software.
; 3. This notice may not be removed or altered from any source distribution.
;
include "global.inc"
section "pb16", ROM0
; The PB16 format is a starting point toward efficient RLE image
; codecs on Game Boy and Super NES.
;
; 0: Load a literal byte
; 1: Repeat from 2 bytes ago
pb16_unpack_packet:
local hByte0
; Read first bit of control byte. Treat B as a ring counter with
; a 1 bit as the sentinel. Once the 1 bit reaches carry, B will
; become 0, meaning the 8-byte packet is complete.
scf
.after_scf:
ld a,[de]
inc de
rla
ld b,a
.byteloop:
; If the bit from the control byte is clear, plane 0 is is literal
jr nc,.p0_is_literal
ldh a,[.hByte0]
jr .have_p0
.p0_is_literal:
ld a,[de]
inc de
ldh [.hByte0],a
.have_p0:
ld [hl+],a
; Read next bit. If it's clear, plane 1 is is literal.
ld a,c
sla b
jr c,.have_p1
.p1_is_copy:
ld a,[de]
inc de
ld c,a
.have_p1:
ld [hl+],a
; Read next bit of control byte
sla b
jr nz,.byteloop
ret
;;
; As pb16_unpack_block except destination and packet count
; precede length.
pb16_unpack_dest_length_block::
ld a, [de]
inc de
ld l, a
ld a, [de]
inc de
ld h, a
fallthrough pb16_unpack_length_block
;;
; As pb16_unpack_block except packet count precedes length.
pb16_unpack_length_block::
ld a, [de]
inc de
ld b, a
fallthrough pb16_unpack_block
;;
; Unpacks 2*B packets from DE to HL (opposite direction vs. memcpy),
; producing 8 bytes per packet.
; About 127 cycles (2 scanlines) per 8-byte packet; filling CHR RAM
; thus takes (6144/8)*127 = about 97536 cycles or 93 ms
pb16_unpack_block::
; Prefill with zeroes
xor a
ldh [pb16_unpack_packet.hByte0],a
ld c,a
.packetloop:
push bc
call pb16_unpack_packet
call pb16_unpack_packet.after_scf
ld a,c
pop bc
ld c,a
dec b
jr nz,.packetloop
ret
;
; Variable width font drawing for Game Boy
; Copyright 2018 Damian Yerrick
;
; This software is provided 'as-is', without any express or implied
; warranty. In no event will the authors be held liable for any damages
; arising from the use of this software.
;
; Permission is granted to anyone to use this software for any purpose,
; including commercial applications, and to alter it and redistribute it
; freely, subject to the following restrictions:
;
; 1. The origin of this software must not be misrepresented; you must not
; claim that you wrote the original software. If you use this software
; in a product, an acknowledgment in the product documentation would be
; appreciated but is not required.
; 2. Altered source versions must be plainly marked as such, and must not be
; misrepresented as being the original software.
; 3. This notice may not be removed or altered from any source distribution.
;
include "hardware.inc"
include "global.inc"
def USE_HBLANK_COPY EQU 1
def lineImgBufLen EQU 128 ; number of 1bpp planes
; Align is a logarithm in rgbasm, unlike in ca65 where it's an actual
; byte count
section "lineImgBuf",wram0,align[8]
lineImgBuf:: ds lineImgBufLen * 2
def CHAR_BIT EQU 8
def LOG_GLYPH_HEIGHT EQU 3
def GLYPH_HEIGHT EQU (1 << LOG_GLYPH_HEIGHT)
def GLYPH_HEIGHT_MINUS_1 EQU 7
; Approximate timing for vwfPutTile:
;
; The glyph drawing itself is about 478 cycles for height 8
; Per glyph: 46
; call: 6, rot glyphid: 5, get dstoffset: 6, get bitmask: 12,
; get shift slide jump: 6, split glyphid: 8, final ret: 3
; Per row: 53+(X%8) avg 56 or 12 if blank
; read blank sliver: 7
; read sliver: 6, shift sliver: 8+(X%8) avg 11, split sliver: 8,
; left OR: 11, right OR: 15, row advance: 5
;
; vwfPuts thus runs at avg 519 cycles/character
; load ch: 6, save and draw: 18+478 (or 3 for space),
; add width: 12, buffer overflow test: 5
;
; Further work:
; not drawing space (" ") at all
; skipping shifting for $00 slivers
section "vwfPutTile",ROM0,align[LOG_GLYPH_HEIGHT]
not_ff_shr_x:: db $00,$80,$C0,$E0,$F0,$F8,$FC,$FE
; The second half of the routine comes before the first half to ease alignment
vwfPutTile_shifter:
local hShifterMask, 1
local hDestAddrLo, 1
rept CHAR_BIT-1
rrca
endr
ld h,a ; H: all glyph bits, circularly rotated
; Load destination address
ldh a,[.hDestAddrLo]
ld l,a
; Break it up into 2 bytes
ldh a,[.hShifterMask]
and h
ld c,a ; C: right half bits
xor h ; A: left half bits
; OR in the left byte
ld h,high(lineImgBuf)
or [hl]
ld [hl],a
; OR in the left
ld a,l
add GLYPH_HEIGHT
ld l,a
ld a,[hl]
or c
ld [hl],a
ld a,l
sub GLYPH_HEIGHT-1
.have_dstoffset:
ldh [.hDestAddrLo],a
; Advance to next row
and GLYPH_HEIGHT-1
ret z
; Shift each row
.rowloop:
; Read an 8x1 sliver of the glyph into A
ld a,[de]
inc e
or a
jr z,.sliver_is_blank
; Shift the sliver
ld h,high(vwfPutTile_shifter)
ld l,b
jp hl
; Fast path handling for blank slivers
.sliver_is_blank:
ldh a,[.hDestAddrLo]
inc a
jr .have_dstoffset
;;
; Draws the tile for glyph A at horizontal position B
vwfPutTile::
; Calculate address of glyph
ld h,0
ld l,a
ld de,vwfChrData - (" "*GLYPH_HEIGHT)
rept LOG_GLYPH_HEIGHT
add hl,hl
endr
add hl,de
; Get the destination offset in line buffer
ld a,b
if LOG_GLYPH_HEIGHT > 3
rept LOG_GLYPH_HEIGHT-3
rlca
endr
endc
and $100-GLYPH_HEIGHT
ldh [vwfPutTile_shifter.hDestAddrLo],a
; Get the mask of which bits go here and which to the next tile
xor b
ld e,a ; E = horizontal offset within tile
ld bc,not_ff_shr_x
add c
ld c,a ; BC = ff_shr_x+horizontal offset
ld a,[bc]
ldh [vwfPutTile_shifter.hShifterMask],a
; Calculate the address of the shift routine
ld a,low(vwfPutTile_shifter) + CHAR_BIT - 1
sub e
ld b,a ; B: which shifter to use
ld d,h
ld e,l
jr vwfPutTile_shifter.rowloop
;;
; Write glyphs for the 8-bit-encoded characters string at (hl) to
; X position B in the VWF buffer
; @return HL pointer to the first character not drawn
vwfPuts::
.chloop:
; Load character, stopping at control character
ld a,[hl+]
cp 32
jr c,.decret
; Save position, draw glyph, load position
jr z,.nodrawspace
ld c,a
push hl
push bc
call vwfPutTile
pop bc
pop hl
ld a,c
.nodrawspace:
; Add up the width of the glyph
ld de,vwfChrWidths-" "
add e
ld e,a
jr nc,.gwnowrap
inc d
.gwnowrap:
ld a,[de]
add b
ld b,a
cp lineImgBufLen
jr c,.chloop
ret
; Return points HL at the first undrawn character
.decret:
dec hl
ret
;;
; Calculates the width of a string in pixels
; @param HL
; @return A: last char; B: width; HL points at end of string;
; C unchanged; DE trashed
vwfStrWidth::
ld b,0
.loop:
ld a,[hl+]
cp 32
jr c,vwfPuts.decret
ld de,vwfChrWidths-32
add e
ld e,a
jr nc,.gwnowrap
inc d
.gwnowrap:
ld a,[de]
add b
ld b,a
jr .loop
;;
; Clears the line image.
; @return C = 0; HL = lineImgBuf + lineImgBufLen
vwfClearBuf::
ld hl,lineImgBuf
ld c,lineImgBufLen/4+2
xor a
.loop:
rept 4
ld [hl+],a
endr
dec c
jr nz,.loop
ret
;;
; Copies the VWF buffer to VRAM address HL using fg color 3
; and bg color 0
; @param HL destination address
; @param DE source address within lineImgBuf (if using _continue)
; @param C tile count (if using _lenC)
; @param B $00 for FG color 0 or $FF for FG color 3
; @return DE end of lineImgBuf; C=0; B unchanged
vwfPutBuf03::
ld c,lineImgBufLen/8
fallthrough vwfPutBuf03_lenC
vwfPutBuf03_lenC::
ld de,lineImgBuf
fallthrough vwfPutBuf03_continue_lenC
vwfPutBuf03_continue_lenC::
sla c
.loop:
rept 4
ld a,[de]
inc e
ld [hl+],a
and b
ld [hl+],a
endr
dec c
jr nz,.loop
ret
if USE_HBLANK_COPY
;;
; Copies the VWF line buffer to WRAM during hblank.
;
; Drawing a glyph with 2 nonblank rows and 6 blank rows takes about
; 400 cycles. The 112 pixel window can hold about 25 glyphs across,
; totaling 13000 cycles or 88 scanlines to fill the buffer.
; Copying it to VRAM using the most general loop for forced-blank
; use at 4x unroll is 9 cycles/byte, completing 112 bytes in 1008.
; But when OAM DMA is active, only 1140-176=964 cycles are available.
; So most of this copying will be done during hblank, which has
; about 69 cycles depending on exact scroll and sprite positions,
; so long as the copy routine stays out of the way of the rSTAT IRQ.
;
; @param HL the address to start writing
; @param C number of tiles to copy
; clobbers all regs
vwfPutBufHBlank::
ld de,lineImgBuf
.tileloop:
; Read the first tile row and keep it in registers ready to
; write as soon as possible
ld a,[de]
inc e
ld b,a
; Wait for either vblank or the very start of hblank.
; This takes several spinloops.
; Skip lines around start of frame, as line 0 has no hblank
; period before the draw time. So if on line 153 or 0, wait
; for line 1.
.unsafe153:
ldh a,[rLY]
or a
jr z,.unsafe153
cp 153
jr z,.unsafe153
cp 144
jr nc,.safetime
; The two lines above the split point are also tricky, as the
; rSTAT IRQ handler can use enough cycles to overflow hblank.
ldh a,[rLYC]
push hl
push bc
sub 2
ld c,a
ld hl,rLY
.nonmiddle:
ld a,[HL]
sub c
cp 2
jr c,.nonmiddle
pop bc
; Wait for mode 1 (vblank) or 3 (draw)
ld hl,rSTAT
.nonhblank:
bit 0,[HL]
jr z,.nonhblank
; Wait for mode 0 (hblank) or 1 (vblank)
.nondraw:
bit 1,[HL]
jr nz,.nondraw
pop hl
.safetime:
; Now that we're in a safe time, copy the tile's first line
ld a,b
ld [hl+],a
inc l
; Copy the rest of the lines
rept 7
ld a,[de]
ld [hl+],a
inc l
inc e
endr
dec c
jr nz,.tileloop
ret
endc
Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment