- 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
|