INCLUDE "game.inc"
|
|
INCLUDE "hardware.inc"
|
|
INCLUDE "oam.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
|
|
|
|
; Remove item(s) from the player's inventory
|
|
; @param b Item ID
|
|
; @param c Item quantity
|