|
|
@ -1,4 +1,3 @@ |
|
|
|
INCLUDE "dir.inc" |
|
|
|
INCLUDE "hardware.inc" |
|
|
|
INCLUDE "util.inc" |
|
|
|
|
|
|
@ -7,8 +6,6 @@ SECTION "Map Data", WRAM0 |
|
|
|
DEF ROW_BUFFER_SIZE EQUS "SCRN_X_B + 4" |
|
|
|
DEF COL_BUFFER_SIZE EQUS "SCRN_Y_B + 4" |
|
|
|
|
|
|
|
SCROLL_DIR:: DB |
|
|
|
|
|
|
|
PENDING_ROW_PTR:: DW ; Where to write pending row data (0 = no write) |
|
|
|
PENDING_ROW_DATA:: DS ROW_BUFFER_SIZE ; Row to be written |
|
|
|
|
|
|
@ -33,6 +30,8 @@ SECTION "Map Code", ROM0 |
|
|
|
DEF INIT_SCX EQUS "((SCRN_VX - SCRN_X) / 2)" |
|
|
|
DEF INIT_SCY EQUS "((SCRN_VY - SCRN_Y) / 2)" |
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
; Loads a map |
|
|
|
; @param hl Pointer to map metadata |
|
|
|
Map_Load:: |
|
|
@ -85,27 +84,35 @@ Map_Load:: |
|
|
|
|
|
|
|
ret |
|
|
|
|
|
|
|
; Update map state based on SCX/SCY |
|
|
|
Map_Scroll:: |
|
|
|
; Check scroll up/down |
|
|
|
ld a, [SCROLL_DIR] |
|
|
|
and DIRF_UP | DIRF_DOWN |
|
|
|
jr nz, .scroll_horiz |
|
|
|
|
|
|
|
; Check SCY % 8 = 0 |
|
|
|
|
|
|
|
; Scroll the map upwards |
|
|
|
; @param d The amount to scroll by (0 < d < 8) |
|
|
|
Map_ScrollUp:: |
|
|
|
; Check whether we crossed tile boundary |
|
|
|
ld a, [rSCY] |
|
|
|
and %111 |
|
|
|
ret nz |
|
|
|
cp d |
|
|
|
jr nc, .done |
|
|
|
|
|
|
|
; Don't scroll if at top tile |
|
|
|
ld a, [CURRENT_CAMERA_Y] |
|
|
|
or a |
|
|
|
ret z |
|
|
|
|
|
|
|
ld a, [rSCY] |
|
|
|
sub d |
|
|
|
ld [rSCY], a |
|
|
|
|
|
|
|
; CAMERA_Y -= 1 |
|
|
|
dec a |
|
|
|
ld [CURRENT_CAMERA_Y], a |
|
|
|
|
|
|
|
; B = CAMERA_X - 2 |
|
|
|
ld a, [CURRENT_CAMERA_X] |
|
|
|
sub 2 |
|
|
|
ld b, a |
|
|
|
|
|
|
|
ld a, [SCROLL_DIR] |
|
|
|
cp DIRB_UP |
|
|
|
jr nz, .scroll_down |
|
|
|
|
|
|
|
; C = CAMERA_Y - 2 |
|
|
|
ld a, [CURRENT_CAMERA_Y] |
|
|
|
sub 2 |
|
|
@ -116,9 +123,65 @@ Map_Scroll:: |
|
|
|
srln a, 3 |
|
|
|
sub 2 |
|
|
|
|
|
|
|
jr .write_row |
|
|
|
jr Map_ScrollRow |
|
|
|
|
|
|
|
.done: |
|
|
|
ld a, [rSCY] |
|
|
|
sub d |
|
|
|
ld [rSCY], a |
|
|
|
ret |
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
Map_ScrollDown:: |
|
|
|
; Don't scroll if at bottom tile |
|
|
|
ld a, [CURRENT_CAMERA_Y] |
|
|
|
add SCRN_Y_B |
|
|
|
ld hl, CURRENT_MAP_HEIGHT |
|
|
|
cp [hl] |
|
|
|
jr nz, .down |
|
|
|
|
|
|
|
ld a, [rSCY] |
|
|
|
add d |
|
|
|
and %111 |
|
|
|
ld [rSCY], a |
|
|
|
ret |
|
|
|
|
|
|
|
; Check whether we crossed tile boundary |
|
|
|
.down: |
|
|
|
ld a, [rSCY] |
|
|
|
and %111 |
|
|
|
add d |
|
|
|
cp 8 |
|
|
|
jr c, .done |
|
|
|
|
|
|
|
; TODO: |
|
|
|
; if CAMERA_Y + 18 = MAP_HEIGHT { |
|
|
|
; if SCY % 8 != 0 { |
|
|
|
; SCY += MIN(D, 8 - SCY % 8) |
|
|
|
; } |
|
|
|
; return |
|
|
|
; } |
|
|
|
; if SCY % 8 + D > 8 { |
|
|
|
; SCY += D |
|
|
|
; LOAD_COLUMN(CAMERA_X - 2, CAMERA_Y + 18 + 1); |
|
|
|
; } else { |
|
|
|
; SCY += D |
|
|
|
; } |
|
|
|
|
|
|
|
ld a, [rSCY] |
|
|
|
add d |
|
|
|
ld [rSCY], a |
|
|
|
|
|
|
|
; CAMERA_Y += 1 |
|
|
|
inc a |
|
|
|
ld [CURRENT_CAMERA_Y], a |
|
|
|
|
|
|
|
; B = CAMERA_X - 2 |
|
|
|
ld a, [CURRENT_CAMERA_X] |
|
|
|
sub 2 |
|
|
|
ld b, a |
|
|
|
|
|
|
|
.scroll_down: |
|
|
|
; C = CAMERA_Y + 18 + 1 |
|
|
|
ld a, [CURRENT_CAMERA_Y] |
|
|
|
add SCRN_Y_B + 1 |
|
|
@ -129,7 +192,21 @@ Map_Scroll:: |
|
|
|
srln a, 3 |
|
|
|
add SCRN_Y_B + 1 |
|
|
|
|
|
|
|
.write_row: |
|
|
|
jr Map_ScrollRow |
|
|
|
|
|
|
|
.done: |
|
|
|
ld a, [rSCY] |
|
|
|
add d |
|
|
|
ld [rSCY], a |
|
|
|
ret |
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
; Scroll in a new row |
|
|
|
; @param a Map VRAM Y-coordinate |
|
|
|
; @param b Data X-coordinate |
|
|
|
; @param c Data Y-coordinate |
|
|
|
Map_ScrollRow: |
|
|
|
and %11111 |
|
|
|
call get_row_ptr |
|
|
|
|
|
|
@ -145,16 +222,21 @@ Map_Scroll:: |
|
|
|
call enqueue_row_write |
|
|
|
ret |
|
|
|
|
|
|
|
.scroll_horiz: |
|
|
|
; Check SCX % 8 = 0 |
|
|
|
Map_ScrollLeft:: |
|
|
|
; Check whether we crossed tile boundary |
|
|
|
ld a, [rSCX] |
|
|
|
and %111 |
|
|
|
ret nz |
|
|
|
cp d |
|
|
|
jr nc, .done |
|
|
|
|
|
|
|
; C = CAMERA_Y - 2 |
|
|
|
ld a, [CURRENT_CAMERA_Y] |
|
|
|
sub 2 |
|
|
|
ld c, a |
|
|
|
ld a, [rSCX] |
|
|
|
sub d |
|
|
|
ld [rSCX], a |
|
|
|
|
|
|
|
; Don't scroll if at left tile |
|
|
|
ld a, [CURRENT_CAMERA_X] |
|
|
|
or a |
|
|
|
ret z |
|
|
|
|
|
|
|
ld a, [rSCY] |
|
|
|
sub 16 |
|
|
@ -163,42 +245,91 @@ Map_Scroll:: |
|
|
|
srl a |
|
|
|
call get_row_ptr |
|
|
|
|
|
|
|
ld a, [SCROLL_DIR] |
|
|
|
cp DIRB_LEFT |
|
|
|
jr nz, .scroll_right |
|
|
|
|
|
|
|
; B = CAMERA_X - 2 |
|
|
|
ld a, [CURRENT_CAMERA_X] |
|
|
|
sub 2 |
|
|
|
ld b, a |
|
|
|
|
|
|
|
; HL = VRAM + (SCX/8 - 2) |
|
|
|
; E = VRAM + (SCX/8 - 2) |
|
|
|
ld a, [rSCX] |
|
|
|
srln a, 3 |
|
|
|
sub 2 |
|
|
|
|
|
|
|
jr .write_col |
|
|
|
jr Map_ScrollColumn |
|
|
|
|
|
|
|
.done: |
|
|
|
ld a, [rSCX] |
|
|
|
sub d |
|
|
|
ld [rSCX], a |
|
|
|
ret |
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
Map_ScrollRight:: |
|
|
|
; Check whether we crossed tile boundary |
|
|
|
ld a, [rSCX] |
|
|
|
and %111 |
|
|
|
add d |
|
|
|
cp 8 |
|
|
|
jr nc, .done |
|
|
|
|
|
|
|
ld a, [rSCX] |
|
|
|
add d |
|
|
|
ld [rSCX], a |
|
|
|
|
|
|
|
; Don't scroll if at bottom tile |
|
|
|
ld a, [CURRENT_CAMERA_X] |
|
|
|
inc a |
|
|
|
ld hl, CURRENT_MAP_WIDTH |
|
|
|
cp [hl] |
|
|
|
ret z |
|
|
|
|
|
|
|
; CAMERA_X += 1 |
|
|
|
inc a |
|
|
|
ld [CURRENT_CAMERA_X], a |
|
|
|
|
|
|
|
ld a, [rSCY] |
|
|
|
sub 16 |
|
|
|
srl a |
|
|
|
srl a |
|
|
|
srl a |
|
|
|
call get_row_ptr |
|
|
|
|
|
|
|
.scroll_right: |
|
|
|
; B = CAMERA_X + 20 + 1 |
|
|
|
ld a, [CURRENT_CAMERA_X] |
|
|
|
add SCRN_X_B + 1 |
|
|
|
ld b, a |
|
|
|
|
|
|
|
; HL = VRAM + SCX/8 + SCRN_X_B + 1 |
|
|
|
; E = VRAM + SCX/8 + SCRN_X_B + 1 |
|
|
|
ld a, [rSCX] |
|
|
|
srl a |
|
|
|
srl a |
|
|
|
srl a |
|
|
|
add SCRN_X_B + 1 |
|
|
|
ld e, a |
|
|
|
|
|
|
|
.write_col: |
|
|
|
and %11111 |
|
|
|
ADD16 hl |
|
|
|
jr Map_ScrollColumn |
|
|
|
|
|
|
|
.done: |
|
|
|
ld a, [rSCX] |
|
|
|
add d |
|
|
|
ld [rSCX], a |
|
|
|
ret |
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
Map_ScrollColumn: |
|
|
|
; C = CAMERA_Y - 2 |
|
|
|
ld a, [CURRENT_CAMERA_Y] |
|
|
|
sub 2 |
|
|
|
ld c, a |
|
|
|
|
|
|
|
call enqueue_col_write |
|
|
|
ret |
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
Map_Update:: |
|
|
|
; Skip row update if PENDING_ROW_PTR is 0 |
|
|
|
ld a, [PENDING_ROW_PTR] |
|
|
@ -232,6 +363,11 @@ Map_Update:: |
|
|
|
dec d |
|
|
|
jr nz, .copy_row |
|
|
|
|
|
|
|
; Reset PENDING_ROW_PTR |
|
|
|
xor a |
|
|
|
ld [PENDING_ROW_PTR], a |
|
|
|
ld [PENDING_ROW_PTR + 1], a |
|
|
|
|
|
|
|
.update_col: |
|
|
|
; Skip column update if PENDING_COL_PTR is 0 |
|
|
|
ld a, [PENDING_COL_PTR] |
|
|
@ -259,8 +395,15 @@ Map_Update:: |
|
|
|
dec d |
|
|
|
jr nz, .update_col_loop |
|
|
|
|
|
|
|
; Reset PENDING_COL_PTR |
|
|
|
xor a |
|
|
|
ld [PENDING_COL_PTR], a |
|
|
|
ld [PENDING_COL_PTR + 1], a |
|
|
|
|
|
|
|
ret |
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
; Computes the offset into map RAM |
|
|
|
; @param a The map RAM y-coordinate |
|
|
|
; @return hl Pointer into map RAM |
|
|
@ -276,6 +419,8 @@ get_row_ptr: |
|
|
|
pop de |
|
|
|
ret |
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
; Write a row of map data into row buffer |
|
|
|
; @param b Map X coordinate (signed) |
|
|
|
; @param c Map Y coordinate (signed) |
|
|
@ -398,6 +543,8 @@ enqueue_row_write: |
|
|
|
jr nz, .zero_row_loop |
|
|
|
ret |
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
; NOTE: This works by enqueueing a row to write, and then immediately flushing |
|
|
|
; the queue. The subroutine could be sped up by writing to map RAM directly, but |
|
|
|
; this is simpler to write and saves on code size. |
|
|
@ -419,6 +566,8 @@ write_map_row: |
|
|
|
|
|
|
|
ret |
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
; Write a column of map data into column buffer |
|
|
|
; @param b Map X coordinate (signed) |
|
|
|
; @param c Map Y coordinate (signed) |
|
|
@ -545,6 +694,7 @@ enqueue_col_write: |
|
|
|
ret |
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
; Basically enqueue_col_write but for entire row, used during map load |
|
|
|
; TODO: Deduplicate |
|
|
|
; @param b Map X coordinate (signed) |
|
|
|