You can not select more than 25 topics Topics must start with a letter or number, can include dashes ('-') and can be up to 35 characters long.
 
 
 
 

343 lines
5.3 KiB

INCLUDE "hardware.inc"
INCLUDE "util.inc"
SECTION "Map Data", WRAM0
PAGEX:: DB
PAGEY:: DB
LAST_SCX:: DB
LAST_SCY:: DB
CURRENT_DATA_START::
CURRENT_TILE_PTR:: DW
CURRENT_TILE_SIZE:: DB
CURRENT_MAP_PTR:: DW
CURRENT_MAP_COLLISION:: DW
CURRENT_MAP_WIDTH:: DB
CURRENT_MAP_HEIGHT:: DB
CURRENT_SPAWN_X:: DB
CURRENT_SPAWN_Y:: DB
CURRENT_CAMERA_X:: DB
CURRENT_CAMERA_Y:: DB
CURRENT_DATA_END::
SECTION "Map Code", ROM0
DEF INIT_SCX EQUS "((SCRN_VX - SCRN_X) / 2)"
DEF INIT_SCY EQUS "((SCRN_VY - SCRN_Y) / 2)"
DEF PAGE_SIZE EQU 2
DEF STACK_OFFSET_ROW EQU 3
DEF STACK_OFFSET_MAP EQU 1
DEF STACK_OFFSET_LEFT EQU 0
; Increments a 16-bit value located on the stack
; \1 Stack offset
MACRO INC_STACK16
ld hl, sp + \1
inc [hl]
jr nz, .no_carry\@
inc hl
inc [hl]
.no_carry\@:
ENDM
MACRO ZERO_ROW_TILE
ld hl, sp + STACK_OFFSET_ROW
ld a, [hl+]
ld e, a
ld d, [hl]
xor a
ld [de], a
ENDM
; Loads a map
; @param hl Pointer to map metadata
Map_Load::
; Initialize scroll state
ld a, INIT_SCX
ld [rSCX], a
ld [LAST_SCX], a
ld a, INIT_SCY
ld [rSCY], a
ld [LAST_SCY], a
ld a, 8
ld [PAGEX], a
ld [PAGEY], a
; Store metadata
ld bc, CURRENT_DATA_START
ld d, CURRENT_DATA_END - CURRENT_DATA_START
call memcpy
; Write tiles to VRAM
ld hl, CURRENT_TILE_PTR
ld a, [hl+]
ld c, a
ld a, [hl+]
ld b, a
ld a, [CURRENT_TILE_SIZE]
ld d, a
ld hl, _VRAM
MEMCPY hl, bc, d
; Write initial map data
ld hl, _SCRN0
ld a, [CURRENT_CAMERA_X]
sub INIT_SCX / 8
ld b, a
ld a, [CURRENT_CAMERA_Y]
sub INIT_SCY / 8
ld c, a
ld d, SCRN_VY_B
.write_rows:
call write_map_row
inc c
dec d
jr nz, .write_rows
ret
; Update map state based on SCX/SCY
Map_Scroll::
; If SCY = PAGEY, write map row
; map coords = CURRENT_CAMERA_X, CURRENT_CAMERA_Y - 2
; HL = _SCRN0 + 32 * (32 - page_y/8 - 2)
ld hl, PAGEY
ld a, [rSCY]
cp [hl]
jr nz, .scroll_down_check
ld a, [rSCX]
ld b, a
ld a, [CURRENT_CAMERA_X]
srl b
srl b
srl b
sub b
ld b, a
ld a, [CURRENT_CAMERA_Y]
cp 2
jr c, .done
sub 2
ld c, a
; a = scy/8 + (scy/8 < 2 ? 30 : -2)
ld a, [rSCY]
srl a
srl a
srl a
cp 2
jr nc, .loop0
add 32
.loop0:
sub 2
; hl = _SCRN0 + 32 * a
ld e, a
ld hl, _SCRN0
.loop:
ld a, e
or a
jr z, .write_up
ld a, 32
ADD16 hl
dec e
jr .loop
.write_up:
halt
call write_map_row
ld a, [PAGEY]
sub 8
ld [PAGEY], a
jr .done
.scroll_down_check:
; If SCY = SCRN_Y - PAGEY, write map row
; map coords = CURRENT_CAMERA_X, CURRENT_CAMERA_Y + 21
; HL = _SCRN0 + 32 * ((32 - page_y) - 1)
; TODO: Check math on these
; If SCX = PAGEX, write map col
; If SCX = SCRN_X - PAGEX, write map col
.done:
ld hl, LAST_SCY
ld a, [rSCY]
ld [hl], a
ret
; Write a row of map data into map RAM
; @param b Map X coordinate (signed)
; @param c Map Y coordinate (signed)
; @param hl Start of the row to write
write_map_row:
push bc
push de
; If Y < 0, write a row of 0s
bit 7, c
jr nz, .zero_row
; If Y >= MAP_HEIGHT, write a row of 0s
ld a, [CURRENT_MAP_HEIGHT]
dec a
cp c
jr nc, .begin_writing
.zero_row:
ld d, SCRN_VX_B
xor a
.zero_row_loop:
ld a, [hl+]
dec d
jr nz, .zero_row_loop
.zero_row_done:
pop de
pop bc
ret
.begin_writing:
push hl
; Allocate 2 bytes for map pointer
; Allocate 1 byte for number of tiles left
add sp, -3
; left = number of tiles left to write
ld hl, sp + STACK_OFFSET_LEFT
ld [hl], SCRN_VX_B
; HL = CURRENT_MAP_PTR + Y * CURRENT_MAP_HEIGHT
ld a, [CURRENT_MAP_PTR]
ld l, a
ld a, [CURRENT_MAP_PTR + 1]
ld h, a
.compute_map_row:
ld a, c
or a
jr z, .compute_map_row_done
ld a, [CURRENT_MAP_HEIGHT]
ADD16 HL
dec c
jr .compute_map_row
; map = HL
.compute_map_row_done:
LD16 de, hl
ld hl, sp + STACK_OFFSET_MAP
ld a, e
ld [hl+], a
ld a, d
ld [hl], a
ld hl, sp + STACK_OFFSET_LEFT
; While X < 0 and left > 0, write 0 to the row
.pad_left:
bit 7, b
jr z, .copy_center
ld a, [hl]
or a
jr z, .done
; *row = 0
ZERO_ROW_TILE
; row++
INC_STACK16 STACK_OFFSET_ROW
; X++, left--
inc b
ld hl, sp + STACK_OFFSET_LEFT
dec [hl]
jr .pad_left
; While X < MAP_WIDTH and [SP] > 0, copy from map
.copy_center:
ld a, [CURRENT_MAP_WIDTH]
dec a
cp b
jr z, .pad_right
ld a, [hl]
or a
jr z, .done
; A = *map_ptr
ld hl, sp + STACK_OFFSET_MAP
ld a, [hl+]
ld e, a
ld d, [hl]
ld a, [de]
; map_ptr++
INC_STACK16 STACK_OFFSET_MAP
; *row = A
ld hl, sp + STACK_OFFSET_ROW
ld e, [hl]
inc hl
ld d, [hl]
ld [de], a
; row++
INC_STACK16 3
; X++, [SP]--
.copy_center_inc:
inc b
ld hl, sp + STACK_OFFSET_LEFT
dec [hl]
jr .copy_center
; While [SP] > 0, write 0 to the row
.pad_right:
ld a, [hl]
or a
jr z, .done
; *row = 0
ZERO_ROW_TILE
; row++
INC_STACK16 STACK_OFFSET_ROW
; [SP]--
.pad_right_inc:
ld hl, sp + STACK_OFFSET_ROW
dec [hl]
jr .pad_right
.done:
add sp, 3
pop hl
pop de
pop bc
ret