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.
 
 
 
 

371 lines
6.2 KiB

INCLUDE "hardware.inc"
INCLUDE "oam.inc"
INCLUDE "player.inc"
INCLUDE "util.inc"
Section "Player Data", WRAM0
DEF PLAYER_INV_SIZE EQU 32
PLAYER_X:: db
PLAYER_Y:: dw
PLAYER_DIR:: db
PLAYER_STATE:: db
PLAYER_VY:: dw
PLAYER_INV:: ds (2 * PLAYER_INV_SIZE)
Section "Player Code", ROM0
spriteData:
INCBIN "png/sprite/player.2bpp"
DEF SPRITE_OAM_IDX EQU 0
DEF SPRITE_IDX EQU 32 ; tile index, rename later
DEF SPRITE_WIDTH EQU 2
DEF SPRITE_HEIGHT EQU 2
DEF PLAYER_SPEED EQU 2
DEF TILE_WIDTH EQU 8 ; Width of tile in bytes
DEF TILE_HEIGHT EQU 8 ; Height of tile in bytes
DEF TILE_SIZE EQU 16 ; Total length of tile in bytes
DEF GRAVITY EQU (0 << 8) | $2e ; 0.18
DEF INIT_VY EQU (3 << 8) | $99 ; 3.60
DEF INIT_FALL_VY EQU ($ff << 8) | $1a ; -1.1015625
DEF MAX_VY EQU ($f9 << 8) | $00 ; -7.0
Player_Init::
; Clear player data (X/Y initialized by map engine)
ld hl, PLAYER_DIR
xor a
REPT (7 + 2 * PLAYER_INV_SIZE)
ld [hl+], a
ENDR
; Copy sprite to VRAM
ld bc, _VRAM8000 + SPRITE_IDX * TILE_SIZE
ld hl, spriteData
ld d, TILE_SIZE * (SPRITE_WIDTH * SPRITE_HEIGHT)
call memcpy
; Initialize OAM entries with player state
call Player_UpdateOAM
ret
Player_Update::
; check for jump
ld a, [keys]
and PADF_UP
jr z, .jump_update_check
; initialize jump state if not already jumping
ld a, [PLAYER_STATE]
and PLAYER_STATEF_JUMP
jr nz, .jump_update
ld a, PLAYER_STATEF_JUMP
ld [PLAYER_STATE], a
ld hl, PLAYER_VY
STORE16 INIT_VY
; todo: deduplicate
.jump_update_check:
ld a, [PLAYER_STATE]
and PLAYER_STATEF_JUMP
jr z, .right
.jump_update:
; load y velocity into bc
ld hl, PLAYER_VY
ld b, [hl]
inc hl
ld c, [hl]
; adjust velocity by gravity
ld a, c
sub LOW(GRAVITY)
ld c, a
ld a, b
sbc HIGH(GRAVITY)
ld b, a
; ; we only need to clamp when moving down
; bit 7, b
; jr z, .no_clamp
; ; vy = MIN(MAX_VY, vy)
; ld a, b
; cp HIGH(MAX_VY)
; jr c, .no_clamp
; ld b, HIGH(MAX_VY)
; ld c, LOW(MAX_VY)
.no_clamp:
ld hl, PLAYER_VY
STORE16 bc
; y -= floor(vy)
ld hl, PLAYER_Y + 1
ld a, [hl]
sub c
ld [hl-], a
ld a, [hl]
sbc b
ld [hl], a
; roll back jump if there was a collision
call player_bg_collides
jr nz, .jump_Player_UpdateOAM
; TODO: Enable once scroll zones are implemented
; ld a, [PLAYER_VY]
; check if VY < 0 and call Map_ScrollUp / Map_ScrollDown
.jump_rollback:
ld hl, PLAYER_VY
bit 7, [hl]
ld hl, PLAYER_Y
jr z, .jump_rollback_down
dec [hl]
jr .jump_rollback_check
.jump_rollback_down:
inc [hl]
.jump_rollback_check:
call player_bg_collides
jr z, .jump_rollback
; set PLAYER_STATE = PLAYER_STATEF_WALK if VY < 0 (fell into ground)
ld hl, PLAYER_VY
bit 7, [hl]
; either way, set VY = 0.
; NOTE: MUST USE LD HERE TO KEEP FLAGS FROM BIT TEST
ld [hl], 0
ld hl, PLAYER_VY + 1
ld [hl], 0
jr z, .jump_Player_UpdateOAM
ld a, PLAYER_STATEF_WALK
ld [PLAYER_STATE], a
.jump_Player_UpdateOAM:
call Player_UpdateOAM
; check for move right
.right:
ld a, [keys]
and PADF_RIGHT
jr z, .left
; check for right boundary
ld a, [PLAYER_X]
add 16
cp SCRN_X
jr nc, .left
.move_right:
ld a, [PLAYER_X]
add PLAYER_SPEED
ld [PLAYER_X], a
call player_bg_collides
jr z, .right_rollback
; TODO: Enable once scroll zones are implemented
; ld d, PLAYER_SPEED
; call Map_ScrollRight
xor a
ld [PLAYER_DIR], a
call Player_UpdateOAM
ret
.right_rollback:
ld a, [PLAYER_X]
sub PLAYER_SPEED
ld [PLAYER_X], a
ret
.left:
; check for left button
ld hl, keys
ld a, [hl]
and PADF_LEFT
jr z, .fall
; check for left boundary
ld a, [PLAYER_X]
or a
jr z, .fall
sub PLAYER_SPEED
ld [PLAYER_X], a
call player_bg_collides
jr z, .left_rollback
; TODO: Enable once scroll zones are implemented
; ld d, PLAYER_SPEED
; call Map_ScrollLeft
ld a, $ff
ld [PLAYER_DIR], a
call Player_UpdateOAM
jr .fall
.left_rollback:
ld hl, PLAYER_X
inc [hl]
inc [hl]
.fall:
call player_in_air
ret z
; only set jump state if not already jumping
ld hl, PLAYER_STATE
ld a, [hl]
and PLAYER_STATEF_JUMP
ret nz
ld [hl], PLAYER_STATEF_JUMP
ld hl, PLAYER_VY
STORE16 INIT_FALL_VY
ret
; Update player metasprite with positional data
Player_UpdateOAM::
ld hl, PLAYER_DIR
ld a, [hl-] ; dir (0 = right , $ff = left)
and OAMF_XFLIP
ld c, a
dec hl ; skip fractional part
ld a, [hl-] ; y
add 16
ld d, a
ld a, [hl] ; x
add 8
ld b, a
ld a, d
ld_OAM_y hl, SPRITE_OAM_IDX
; top left sprite
ld [hli], a
ld [hl], b
inc hl
ld [hl], SPRITE_IDX
inc hl
ld [hl], c
inc hl
; top right
ld d, a
ld a, b
add 8
ld b, a
ld a, d
ld [hli], a
ld [hl], b
inc hl
ld [hl], SPRITE_IDX + 1
inc hl
ld [hl], c
inc hl
; bottom left
add 8
ld d, a
ld a, b
sub 8
ld b, a
ld a, d
ld [hli], a
ld [hl], b
inc hl
ld [hl], SPRITE_IDX + 2
inc hl
ld [hl], c
inc hl
; bottom right
ld d, a
ld a, b
add 8
ld b, a
ld a, d
ld [hli], a
ld [hl], b
inc hl
ld [hl], SPRITE_IDX + 3
inc hl
ld [hl], c
; flip tile indices if necessary
ld a, c
or c
jr z, .done
; TODO: Can be sped up by using LD A, [NN]
ld_OAM_tile hl, SPRITE_OAM_IDX
ld [hl], SPRITE_IDX + 1
ld_OAM_tile hl, SPRITE_OAM_IDX + 1
ld [hl], SPRITE_IDX
ld_OAM_tile hl, SPRITE_OAM_IDX + 2
ld [hl], SPRITE_IDX + 3
ld_OAM_tile hl, SPRITE_OAM_IDX + 3
ld [hl], SPRITE_IDX + 2
.done:
ret
; Add item(s) to the player's inventory
; @param b Item ID
; @param c Item quantity
Player_AddInvItem::
push de
ld hl, PLAYER_INV
ld e, PLAYER_INV_SIZE
.find_inv_slot:
ld a, [hl]
cp b
jr z, .update_item
inc hl
dec e
jr nz, .find_inv_slot
.update_item:
; set item id
ld a, b
ld [hl+], a
; update item qty
ld a, [hl]
add c
ld [hl], a
pop de
ret