Level selection menu: main logic of landmark transitions involving page change (#12)

This commit is contained in:
xCrystal 2023-08-25 13:42:23 +02:00
parent d5dc7b38df
commit f067112be6
2 changed files with 200 additions and 15 deletions

View File

@ -1,9 +1,14 @@
; TILE_WIDTH represents the top/left border tile, $8/$10 represent the OAM screen position offsets, and 4 are custom offsets ; TILE_WIDTH represents the top/left border tile, $8/$10 represent the OAM screen position offsets,
; and 4 are custom offsets to make the player sprite centered in a 8x8 tile rather than in a 16x16 square.
DEF LEVELSELECTIONMENU_LANDMARK_OFFSET_X EQU TILE_WIDTH + $8 + 4 DEF LEVELSELECTIONMENU_LANDMARK_OFFSET_X EQU TILE_WIDTH + $8 + 4
DEF LEVELSELECTIONMENU_LANDMARK_OFFSET_Y EQU TILE_WIDTH + $10 + 4 DEF LEVELSELECTIONMENU_LANDMARK_OFFSET_Y EQU TILE_WIDTH + $10 + 4
MACRO level_selection_menu_landmark MACRO level_selection_menu_landmark
; page number, xcoord (in tiles), ycoord (in tiles), ptr to name, spawn point (SPAWN_*) ; page number, xcoord (in tiles), ycoord (in tiles), ptr to name, spawn point (SPAWN_*)
; xcoord ranges between 0 and 17 (SCREEN_WIDTH points minus two)
; when crossing pages, x=17 and x=0 are adjacent (one tile apart)
; ycoord ranges between 0 and 13 (SCREEN_HEIGH points minus four)
; when crossing pages, y=13 and y=0 are adjacent (one tile apart)
db \1 db \1
db LEVELSELECTIONMENU_LANDMARK_OFFSET_X + \2 * TILE_WIDTH db LEVELSELECTIONMENU_LANDMARK_OFFSET_X + \2 * TILE_WIDTH
db LEVELSELECTIONMENU_LANDMARK_OFFSET_Y + \3 * TILE_WIDTH db LEVELSELECTIONMENU_LANDMARK_OFFSET_Y + \3 * TILE_WIDTH
@ -58,20 +63,20 @@ LevelSelectionMenu_LandmarkTransitions:
level_selection_menu_landmark_transition RIGHT, FALSE level_selection_menu_landmark_transition RIGHT, FALSE
; LANDMARK_LEVEL_3 ; LANDMARK_LEVEL_3
level_selection_menu_landmark_transition DOWN, 6, LANDMARK_LEVEL_5 level_selection_menu_landmark_transition DOWN, 7, DOWN, 1, LANDMARK_LEVEL_5
level_selection_menu_landmark_transition UP, 5, RIGHT, 2, DOWN, 3, LANDMARK_LEVEL_2 level_selection_menu_landmark_transition UP, 5, RIGHT, 2, DOWN, 3, LANDMARK_LEVEL_2
level_selection_menu_landmark_transition LEFT, 7, LEFT, 2, LANDMARK_LEVEL_4 level_selection_menu_landmark_transition LEFT, 7, LEFT, 4, LANDMARK_LEVEL_4
level_selection_menu_landmark_transition RIGHT, 7, LANDMARK_LEVEL_1 level_selection_menu_landmark_transition RIGHT, 7, LANDMARK_LEVEL_1
; LANDMARK_LEVEL_4 ; LANDMARK_LEVEL_4
level_selection_menu_landmark_transition DOWN, FALSE level_selection_menu_landmark_transition DOWN, FALSE
level_selection_menu_landmark_transition UP, FALSE level_selection_menu_landmark_transition UP, FALSE
level_selection_menu_landmark_transition LEFT, FALSE level_selection_menu_landmark_transition LEFT, FALSE
level_selection_menu_landmark_transition RIGHT, 7, RIGHT, 2, LANDMARK_LEVEL_3 level_selection_menu_landmark_transition RIGHT, 7, RIGHT, 4, LANDMARK_LEVEL_3
; LANDMARK_LEVEL_5 ; LANDMARK_LEVEL_5
level_selection_menu_landmark_transition DOWN, FALSE level_selection_menu_landmark_transition DOWN, FALSE
level_selection_menu_landmark_transition UP, 6, LANDMARK_LEVEL_3 level_selection_menu_landmark_transition UP, 7, UP, 1, LANDMARK_LEVEL_3
level_selection_menu_landmark_transition LEFT, FALSE level_selection_menu_landmark_transition LEFT, FALSE
level_selection_menu_landmark_transition RIGHT, FALSE level_selection_menu_landmark_transition RIGHT, FALSE
@ -79,8 +84,9 @@ assert const_value == NUM_LANDMARKS * NUM_DIRECTIONS
LevelSelectionMenu_PageGrid: LevelSelectionMenu_PageGrid:
db -1, -1, -1, -1 db -1, -1, -1, -1
db -1, 2, 3, -1 db -1, 1, 0, -1
db -1, 0, 1, -1 db -1, 3, 2, -1
db -1, -1, -1, -1 db -1, -1, -1, -1
DEF LEVELSELECTIONMENU_PAGE_GRID_WIDTH EQU 4 DEF LEVELSELECTIONMENU_PAGE_GRID_WIDTH EQU 4
DEF LEVELSELECTIONMENU_PAGE_GRID_HEIGHT EQU 4

View File

@ -29,6 +29,8 @@ LevelSelectionMenu::
ld b, CGB_LEVEL_SELECTION_MENU ld b, CGB_LEVEL_SELECTION_MENU
call GetCGBLayout ; apply and commit attrmap (takes 4 frames) and pals call GetCGBLayout ; apply and commit attrmap (takes 4 frames) and pals
call SetPalettes call SetPalettes
xor a
ldh [hBGMapMode], a
ld de, MUSIC_GAME_CORNER ld de, MUSIC_GAME_CORNER
call PlayMusic call PlayMusic
@ -105,6 +107,7 @@ LevelSelectionMenu::
; by setting wLevelSelectionMenuStandingStill to TRUE ; by setting wLevelSelectionMenuStandingStill to TRUE
farcall PlaySpriteAnimations farcall PlaySpriteAnimations
call DelayFrame call DelayFrame
call LevelSelectionMenu_DoPageChangeEvent
ld a, [wLevelSelectionMenuStandingStill] ld a, [wLevelSelectionMenuStandingStill]
and a and a
jr z, .wait_transition_loop jr z, .wait_transition_loop
@ -136,8 +139,8 @@ LevelSelectionMenu::
call DelayFrames call DelayFrames
ld a, [wLevelSelectionMenuCurrentLandmark] ld a, [wLevelSelectionMenuCurrentLandmark]
ld [wDefaultSpawnpoint], a
call LevelSelectionMenu_GetLandmarkSpawnPoint call LevelSelectionMenu_GetLandmarkSpawnPoint
ld [wDefaultSpawnpoint], a
ld a, MAPSETUP_WARP ld a, MAPSETUP_WARP
ld [hMapEntryMethod], a ld [hMapEntryMethod], a
xor a xor a
@ -210,13 +213,10 @@ LevelSelectionMenu_InitPlayerSprite:
; because ClearSpriteAnims was called before, it's always loaded to wSpriteAnim1 ; because ClearSpriteAnims was called before, it's always loaded to wSpriteAnim1
push af push af
depixel 0, 0 depixel 0, 0
; all the SPRITE_ANIM_* related to the level selection menu are sorted by direction, then by gender
ld b, SPRITE_ANIM_INDEX_LEVEL_SELECTION_MENU_MALE_WALK_DOWN ld b, SPRITE_ANIM_INDEX_LEVEL_SELECTION_MENU_MALE_WALK_DOWN
ld a, [wPlayerGender] ld a, [wPlayerGender]
bit PLAYERGENDER_FEMALE_F, a add b
jr z, .got_gender
ld b, SPRITE_ANIM_INDEX_LEVEL_SELECTION_MENU_FEMALE_WALK_DOWN
.got_gender
ld a, b
call InitSpriteAnimStruct call InitSpriteAnimStruct
ld hl, SPRITEANIMSTRUCT_TILE_ID ld hl, SPRITEANIMSTRUCT_TILE_ID
add hl, bc add hl, bc
@ -224,6 +224,7 @@ LevelSelectionMenu_InitPlayerSprite:
pop af pop af
ld e, a ld e, a
call LevelSelectionMenu_GetLandmarkCoords call LevelSelectionMenu_GetLandmarkCoords
; wSpriteAnim1*Coord contain the coord of the bottom right object of the player sprite
ld hl, SPRITEANIMSTRUCT_XCOORD ld hl, SPRITEANIMSTRUCT_XCOORD
add hl, bc add hl, bc
ld [hl], e ld [hl], e
@ -330,6 +331,146 @@ LevelSelectionMenu_SetAnimSeqAndFrameset:
ld [hl], a ld [hl], a
ret ret
LevelSelectionMenu_DoPageChangeEvent:
ld de, .Events
ld bc, wSpriteAnim1
.loop
ld a, [de] ; SPRITE_ANIM_SEQ_* or $00 table terminator
and a
ret z
inc de
ld hl, SPRITEANIMSTRUCT_ANIM_SEQ_ID
add hl, bc
cp [hl]
jr nz, .next1
ld a, [de] ; SPRITEANIMSTRUCT_YCOORD or SPRITEANIMSTRUCT_XCOORD
ld l, a
ld h, 0
add hl, bc
inc de
ld a, [de] ; X/Y coordinate
cp [hl]
jr nz, .next2
; this entry matches
inc de
ld a, [de]
ld l, a
inc de
ld a, [de]
ld h, a
jp hl
.next1
inc de
.next2
inc de
inc de
inc de
jr .loop
; LEVELSELECTIONMENU_PAGE_EDGE_* represent values when the player sprite is at:
; UU
; =========UU=========
; =------------------=
; =------------------=
; =------------------=
; =------------------=
; =------------------=
; =------------------=
; =------------------=
;LL------------------RR
;LL------------------RR
; =------------------=
; =------------------=
; =------------------=
; =------------------=
; =------------------=
; =========DD=========
; =========DD=========
; ====================
; for movements spanning two pages, when one edge is reached, the page change occurs
; and the player appears in the other page at the coordinate of the new edge.
; hence, for calculating movement length, it's as if both pages were adjacent without the border frame.
DEF PAGE_EDGE_DOWN EQU $90
DEF PAGE_EDGE_UP EQU $10
DEF PAGE_EDGE_LEFT EQU $08
DEF PAGE_EDGE_RIGHT EQU $a8
DEF PAGE_CHANGE_FADE_FRAMES EQU 16
DEF PAGE_CHANGE_NON_FADE_FRAMES EQU 13
; total frame delay of page change is 16 + 13 + 16 = 45 frames
MACRO page_change_event
; SPRITE_ANIM_SEQ_* to match, Match object's X or Y, X/Y coordinate, Action if both SPRITE_ANIM_SEQ_* and X/Y match
db \1, \2, \3
dw \4
ENDM
.Events:
page_change_event SPRITE_ANIM_SEQ_LEVEL_SELECTION_MENU_WALK_DOWN, SPRITEANIMSTRUCT_YCOORD, PAGE_EDGE_DOWN, .PageChangeDown
page_change_event SPRITE_ANIM_SEQ_LEVEL_SELECTION_MENU_WALK_UP, SPRITEANIMSTRUCT_YCOORD, PAGE_EDGE_UP, .PageChangeUp
page_change_event SPRITE_ANIM_SEQ_LEVEL_SELECTION_MENU_WALK_LEFT, SPRITEANIMSTRUCT_XCOORD, PAGE_EDGE_LEFT, .PageChangeLeft
page_change_event SPRITE_ANIM_SEQ_LEVEL_SELECTION_MENU_WALK_RIGHT, SPRITEANIMSTRUCT_XCOORD, PAGE_EDGE_RIGHT, .PageChangeRight
db $0
.PageChangeDown:
call .PageChangeFadeOut
ld a, PAGE_EDGE_UP
ld [wSpriteAnim1YCoord], a ; respawn in opposite edge
ld e, DOWN
jr .PageChange_Common
.PageChangeUp:
call .PageChangeFadeOut
ld a, PAGE_EDGE_DOWN
ld [wSpriteAnim1YCoord], a ; respawn in opposite edge
ld e, UP
jr .PageChange_Common
.PageChangeLeft:
call .PageChangeFadeOut
ld a, PAGE_EDGE_RIGHT
ld [wSpriteAnim1XCoord], a ; respawn in opposite edge
ld e, LEFT
jr .PageChange_Common
.PageChangeRight:
call .PageChangeFadeOut
ld a, PAGE_EDGE_LEFT
ld [wSpriteAnim1XCoord], a ; respawn in opposite edge
ld e, RIGHT
jr .PageChange_Common
.PageChange_Common:
; set new page and redraw screen
call LevelSelectionMenu_GetNewPage
ld [wLevelSelectionMenuCurrentPage], a
call LevelSelectionMenu_InitTilemap
ld b, CGB_LEVEL_SELECTION_MENU
call GetCGBLayout
xor a
ldh [hBGMapMode], a
ld c, PAGE_CHANGE_NON_FADE_FRAMES
call DelayFrames
call .PageChangeFadeIn
; adjust steps left for the "duplicate" movement of the player leaving and entering a page
ld hl, wLevelSelectionMenuMovementStepsLeft
ld a, [hl]
add 2 * TILE_WIDTH
ld [hl], a
ret
.PageChangeFadeOut:
ld c, PAGE_CHANGE_FADE_FRAMES
call DelayFrames
ret
.PageChangeFadeIn:
ld c, PAGE_CHANGE_FADE_FRAMES
call DelayFrames
ret
LevelSelectionMenu_GetLandmarkPage: LevelSelectionMenu_GetLandmarkPage:
; Return page number (a) of landmark a. ; Return page number (a) of landmark a.
push hl push hl
@ -467,6 +608,42 @@ LevelSelectionMenu_GetValidDirections:
pop hl pop hl
ret ret
LevelSelectionMenu_GetNewPage:
; return in a the new page that the player is ending up at during this movement involving page change.
; direction (in wWalkingDirection order) is provided in e.
ld hl, LevelSelectionMenu_PageGrid - 1
ld c, LEVELSELECTIONMENU_PAGE_GRID_WIDTH * LEVELSELECTIONMENU_PAGE_GRID_HEIGHT + 1
.loop
inc hl
dec c
jr z, .out_of_bounds
ld a, [wLevelSelectionMenuCurrentPage]
cp [hl]
jr nz, .loop
; find the next page in the grid according to movement direction
ld a, e
ld bc, LEVELSELECTIONMENU_PAGE_GRID_WIDTH
cp DOWN
jr z, .ok
ld bc, -LEVELSELECTIONMENU_PAGE_GRID_WIDTH
cp UP
jr z, .ok
ld bc, -1
cp LEFT
jr z, .ok
ld bc, 1
.ok
add hl, bc
ld a, [hl]
cp -1
jr z, .out_of_bounds
ret
.out_of_bounds
ld a, 1
ret
LevelSelectionMenu_Delay10Frames: LevelSelectionMenu_Delay10Frames:
; Delay 10 frames while playing sprite anims ; Delay 10 frames while playing sprite anims
ld a, 10 ld a, 10
@ -500,9 +677,11 @@ _LevelSelectionMenuHandleTransition:
.not_first_step .not_first_step
and a and a
jr z, .movement_over jr z, .movement_over
; one less step left to finish this movement
; one less step left to finish this movement
dec a dec a
ld [de], a ld [de], a
.done
; return carry to signal back to apply a displacement during this frame ; return carry to signal back to apply a displacement during this frame
scf scf
ret ret