summaryrefslogtreecommitdiff
path: root/engine/menus
diff options
context:
space:
mode:
Diffstat (limited to 'engine/menus')
-rwxr-xr-xengine/menus/main_menu.asm361
-rwxr-xr-xengine/menus/menu.asm841
-rw-r--r--engine/menus/menu_2.asm253
-rwxr-xr-xengine/menus/naming_screen.asm1467
-rwxr-xr-xengine/menus/options_menu.asm583
-rwxr-xr-xengine/menus/scrolling_menu.asm543
-rwxr-xr-xengine/menus/start_menu.asm1993
-rwxr-xr-xengine/menus/trainer_card.asm623
8 files changed, 6664 insertions, 0 deletions
diff --git a/engine/menus/main_menu.asm b/engine/menus/main_menu.asm
new file mode 100755
index 000000000..d83ce873b
--- /dev/null
+++ b/engine/menus/main_menu.asm
@@ -0,0 +1,361 @@
+GFX_49c0c: ; 49c0c
+INCBIN "gfx/unknown/049c0c.2bpp"
+; 49cdc
+
+MainMenu: ; 49cdc
+ xor a
+ ld [wDisableTextAcceleration], a
+ call Function49ed0
+ ld b, SCGB_DIPLOMA
+ call GetSGBLayout
+ call SetPalettes
+ ld hl, wGameTimerPause
+ res GAMETIMERPAUSE_TIMER_PAUSED_F, [hl]
+ call MainMenu_GetWhichMenu
+ ld [wWhichIndexSet], a
+ call MainMenu_PrintCurrentTimeAndDay
+ ld hl, .MenuHeader
+ call LoadMenuHeader
+ call MainMenuJoypadLoop
+ call CloseWindow
+ jr c, .quit
+ call ClearTileMap
+ ld a, [wMenuSelection]
+ ld hl, .Jumptable
+ rst JumpTable
+ jr MainMenu
+
+.quit
+ ret
+; 49d14
+
+.MenuHeader: ; 49d14
+ db MENU_BACKUP_TILES ; flags
+ menu_coords 0, 0, 16, 7
+ dw .MenuData
+ db 1 ; default option
+; 49d1c
+
+.MenuData: ; 49d1c
+ db STATICMENU_CURSOR ; flags
+ db 0 ; items
+ dw MainMenuItems
+ dw PlaceMenuStrings
+ dw .Strings
+; 49d20
+
+.Strings: ; 49d24
+ db "CONTINUE@"
+ db "NEW GAME@"
+ db "OPTION@"
+ db "MYSTERY GIFT@"
+ db "MOBILE@"
+ db "MOBILE STUDIUM@"
+
+.Jumptable: ; 0x49d60
+ dw MainMenu_Continue
+ dw MainMenu_NewGame
+ dw MainMenu_Options
+ dw MainMenu_MysteryGift
+ dw MainMenu_Mobile
+ dw MainMenu_MobileStudium
+; 0x49d6c
+
+CONTINUE EQU 0
+NEW_GAME EQU 1
+OPTION EQU 2
+MYSTERY_GIFT EQU 3
+MOBILE EQU 4
+MOBILE_STUDIUM EQU 5
+
+MainMenuItems:
+
+NewGameMenu: ; 0x49d6c
+ db 2
+ db NEW_GAME
+ db OPTION
+ db -1
+
+ContinueMenu: ; 0x49d70
+ db 3
+ db CONTINUE
+ db NEW_GAME
+ db OPTION
+ db -1
+
+MobileMysteryMenu: ; 0x49d75
+ db 5
+ db CONTINUE
+ db NEW_GAME
+ db OPTION
+ db MYSTERY_GIFT
+ db MOBILE
+ db -1
+
+MobileMenu: ; 0x49d7c
+ db 4
+ db CONTINUE
+ db NEW_GAME
+ db OPTION
+ db MOBILE
+ db -1
+
+MobileStudiumMenu: ; 0x49d82
+ db 5
+ db CONTINUE
+ db NEW_GAME
+ db OPTION
+ db MOBILE
+ db MOBILE_STUDIUM
+ db -1
+
+MysteryMobileStudiumMenu: ; 0x49d89
+ db 6
+ db CONTINUE
+ db NEW_GAME
+ db OPTION
+ db MYSTERY_GIFT
+ db MOBILE
+ db MOBILE_STUDIUM
+ db -1
+
+MysteryMenu: ; 0x49d91
+ db 4
+ db CONTINUE
+ db NEW_GAME
+ db OPTION
+ db MYSTERY_GIFT
+ db -1
+
+MysteryStudiumMenu: ; 0x49d97
+ db 5
+ db CONTINUE
+ db NEW_GAME
+ db OPTION
+ db MYSTERY_GIFT
+ db MOBILE_STUDIUM
+ db -1
+
+StudiumMenu: ; 0x49d9e
+ db 4
+ db CONTINUE
+ db NEW_GAME
+ db OPTION
+ db MOBILE_STUDIUM
+ db -1
+
+
+MainMenu_GetWhichMenu: ; 49da4
+ nop
+ nop
+ nop
+ ld a, [wSaveFileExists]
+ and a
+ jr nz, .next
+ ld a, $0 ; New Game
+ ret
+
+.next
+ ld a, [hCGB]
+ cp $1
+ ld a, $1
+ ret nz
+ ld a, BANK(sNumDailyMysteryGiftPartnerIDs)
+ call GetSRAMBank
+ ld a, [sNumDailyMysteryGiftPartnerIDs]
+ cp -1
+ call CloseSRAM
+ jr nz, .mystery_gift
+ ; This check makes no difference.
+ ld a, [wStatusFlags]
+ bit STATUSFLAGS_MAIN_MENU_MOBILE_CHOICES_F, a
+ ld a, $1 ; Continue
+ jr z, .ok
+ jr .ok
+
+.ok
+ jr .ok2
+
+.ok2
+ ld a, $1 ; Continue
+ ret
+
+.mystery_gift
+ ; This check makes no difference.
+ ld a, [wStatusFlags]
+ bit STATUSFLAGS_MAIN_MENU_MOBILE_CHOICES_F, a
+ jr z, .ok3
+ jr .ok3
+
+.ok3
+ jr .ok4
+
+.ok4
+ ld a, $6 ; Mystery Gift
+ ret
+; 49de4
+
+MainMenuJoypadLoop: ; 49de4
+ call SetUpMenu
+.loop
+ call MainMenu_PrintCurrentTimeAndDay
+ ld a, [w2DMenuFlags1]
+ set 5, a
+ ld [w2DMenuFlags1], a
+ call GetScrollingMenuJoypad
+ ld a, [wMenuJoypad]
+ cp B_BUTTON
+ jr z, .b_button
+ cp A_BUTTON
+ jr z, .a_button
+ jr .loop
+
+.a_button
+ call PlayClickSFX
+ and a
+ ret
+
+.b_button
+ scf
+ ret
+; 49e09
+
+MainMenu_PrintCurrentTimeAndDay: ; 49e09
+ ld a, [wSaveFileExists]
+ and a
+ ret z
+ xor a
+ ld [hBGMapMode], a
+ call .PlaceBox
+ ld hl, wOptions
+ ld a, [hl]
+ push af
+ set NO_TEXT_SCROLL, [hl]
+ call .PlaceTime
+ pop af
+ ld [wOptions], a
+ ld a, $1
+ ld [hBGMapMode], a
+ ret
+; 49e27
+
+
+.PlaceBox: ; 49e27
+ call CheckRTCStatus
+ and $80
+ jr nz, .TimeFail
+ hlcoord 0, 14
+ ld b, 2
+ ld c, 18
+ call TextBox
+ ret
+
+.TimeFail:
+ call SpeechTextBox
+ ret
+; 49e3d
+
+
+.PlaceTime: ; 49e3d
+ ld a, [wSaveFileExists]
+ and a
+ ret z
+ call CheckRTCStatus
+ and $80
+ jp nz, .PrintTimeNotSet
+ call UpdateTime
+ call GetWeekday
+ ld b, a
+ decoord 1, 15
+ call .PlaceCurrentDay
+ decoord 4, 16
+ ld a, [hHours]
+ ld c, a
+ farcall PrintHour
+ ld [hl], ":"
+ inc hl
+ ld de, hMinutes
+ lb bc, PRINTNUM_LEADINGZEROS | 1, 2
+ call PrintNum
+ ret
+
+.min
+; unused
+ db "min.@"
+; 49e75
+
+.PrintTimeNotSet: ; 49e75
+ hlcoord 1, 14
+ ld de, .TimeNotSet
+ call PlaceString
+ ret
+; 49e7f
+
+.TimeNotSet: ; 49e7f
+ db "TIME NOT SET@"
+; 49e8c
+
+.UnusedText: ; 49e8c
+ ; Clock time unknown
+ text_jump UnknownText_0x1c5182
+ db "@"
+; 49e91
+
+.PlaceCurrentDay: ; 49e91
+ push de
+ ld hl, .Days
+ ld a, b
+ call GetNthString
+ ld d, h
+ ld e, l
+ pop hl
+ call PlaceString
+ ld h, b
+ ld l, c
+ ld de, .Day
+ call PlaceString
+ ret
+; 49ea8
+
+.Days:
+ db "SUN@"
+ db "MON@"
+ db "TUES@"
+ db "WEDNES@"
+ db "THURS@"
+ db "FRI@"
+ db "SATUR@"
+.Day:
+ db "DAY@"
+; 49ed0
+
+Function49ed0: ; 49ed0
+ xor a
+ ld [hMapAnims], a
+ call ClearTileMap
+ call LoadFontsExtra
+ call LoadStandardFont
+ call ClearWindowData
+ ret
+; 49ee0
+
+
+MainMenu_NewGame: ; 49ee0
+ farcall NewGame
+ ret
+; 49ee7
+
+MainMenu_Options: ; 49ee7
+ farcall OptionsMenu
+ ret
+; 49eee
+
+MainMenu_Continue: ; 49eee
+ farcall Continue
+ ret
+; 49ef5
+
+MainMenu_MysteryGift: ; 49ef5
+ farcall MysteryGift
+ ret
+; 49efc
diff --git a/engine/menus/menu.asm b/engine/menus/menu.asm
new file mode 100755
index 000000000..51de2e1a4
--- /dev/null
+++ b/engine/menus/menu.asm
@@ -0,0 +1,841 @@
+_2DMenu_:: ; 2400e
+ ld hl, CopyMenuData
+ ld a, [wMenuData_2DMenuItemStringsBank]
+ rst FarCall
+
+ call Draw2DMenu
+ call UpdateSprites
+ call ApplyTilemap
+ call Get2DMenuSelection
+ ret
+; 24022
+
+_InterpretBattleMenu:: ; 24022
+ ld hl, CopyMenuData
+ ld a, [wMenuData_2DMenuItemStringsBank]
+ rst FarCall
+
+ call Draw2DMenu
+ farcall MobileTextBorder
+ call UpdateSprites
+ call ApplyTilemap
+ call Get2DMenuSelection
+ ret
+; 2403c
+
+_InterpretMobileMenu:: ; 2403c
+ ld hl, CopyMenuData
+ ld a, [wMenuData_2DMenuItemStringsBank]
+ rst FarCall
+
+ call Draw2DMenu
+ farcall MobileTextBorder
+ call UpdateSprites
+ call ApplyTilemap
+ call Init2DMenuCursorPosition
+ ld hl, w2DMenuFlags1
+ set 7, [hl]
+.loop
+ call DelayFrame
+ farcall Function10032e
+ ld a, [wcd2b]
+ and a
+ jr nz, .quit
+ call MobileMenuJoypad
+ ld a, [wMenuJoypadFilter]
+ and c
+ jr z, .loop
+ call Mobile_GetMenuSelection
+ ret
+
+.quit
+ ld a, [w2DMenuNumCols]
+ ld c, a
+ ld a, [w2DMenuNumRows]
+ call SimpleMultiply
+ ld [wMenuCursorBuffer], a
+ and a
+ ret
+; 24085
+
+
+
+Draw2DMenu: ; 24085
+ xor a
+ ld [hBGMapMode], a
+ call MenuBox
+ call Place2DMenuItemStrings
+ ret
+; 2408f
+
+Get2DMenuSelection: ; 2408f
+ call Init2DMenuCursorPosition
+ call StaticMenuJoypad
+ call MenuClickSound
+Mobile_GetMenuSelection: ; 24098
+ ld a, [wMenuDataFlags]
+ bit 1, a
+ jr z, .skip
+ call GetMenuJoypad
+ bit SELECT_F, a
+ jr nz, .quit1
+
+.skip
+ ld a, [wMenuDataFlags]
+ bit 0, a
+ jr nz, .skip2
+ call GetMenuJoypad
+ bit B_BUTTON_F, a
+ jr nz, .quit2
+
+.skip2
+ ld a, [w2DMenuNumCols]
+ ld c, a
+ ld a, [wMenuCursorY]
+ dec a
+ call SimpleMultiply
+ ld c, a
+ ld a, [wMenuCursorX]
+ add c
+ ld [wMenuCursorBuffer], a
+ and a
+ ret
+
+.quit1
+ scf
+ ret
+
+.quit2
+ scf
+ ret
+; 240cd
+
+Get2DMenuNumberOfColumns: ; 240cd
+ ld a, [wMenuData_2DMenuDimensions]
+ and $f
+ ret
+; 240d3
+
+Get2DMenuNumberOfRows: ; 240d3
+ ld a, [wMenuData_2DMenuDimensions]
+ swap a
+ and $f
+ ret
+; 240db
+
+Place2DMenuItemStrings: ; 240db
+ ld hl, wMenuData_2DMenuItemStringsAddr
+ ld e, [hl]
+ inc hl
+ ld d, [hl]
+ call GetMenuTextStartCoord
+ call Coord2Tile
+ call Get2DMenuNumberOfRows
+ ld b, a
+.row
+ push bc
+ push hl
+ call Get2DMenuNumberOfColumns
+ ld c, a
+.col
+ push bc
+ ld a, [wMenuData_2DMenuItemStringsBank]
+ call Place2DMenuItemName
+ inc de
+ ld a, [wMenuData_2DMenuSpacing]
+ ld c, a
+ ld b, 0
+ add hl, bc
+ pop bc
+ dec c
+ jr nz, .col
+ pop hl
+ ld bc, 2 * SCREEN_WIDTH
+ add hl, bc
+ pop bc
+ dec b
+ jr nz, .row
+ ld hl, wMenuData_2DMenuFunctionAddr
+ ld a, [hli]
+ ld h, [hl]
+ ld l, a
+ or h
+ ret z
+ ld a, [wMenuData_2DMenuFunctionBank]
+ rst FarCall
+ ret
+; 2411a
+
+
+Init2DMenuCursorPosition: ; 2411a (9:411a)
+ call GetMenuTextStartCoord
+ ld a, b
+ ld [w2DMenuCursorInitY], a
+ dec c
+ ld a, c
+ ld [w2DMenuCursorInitX], a
+ call Get2DMenuNumberOfRows
+ ld [w2DMenuNumRows], a
+ call Get2DMenuNumberOfColumns
+ ld [w2DMenuNumCols], a
+ call .InitFlags_a
+ call .InitFlags_b
+ call .InitFlags_c
+ ld a, [w2DMenuNumCols]
+ ld e, a
+ ld a, [wMenuCursorBuffer]
+ ld b, a
+ xor a
+ ld d, 0
+.loop
+ inc d
+ add e
+ cp b
+ jr c, .loop
+ sub e
+ ld c, a
+ ld a, b
+ sub c
+ and a
+ jr z, .reset1
+ cp e
+ jr z, .okay1
+ jr c, .okay1
+.reset1
+ ld a, 1
+.okay1
+ ld [wMenuCursorX], a
+ ld a, [w2DMenuNumRows]
+ ld e, a
+ ld a, d
+ and a
+ jr z, .reset2
+ cp e
+ jr z, .okay2
+ jr c, .okay2
+.reset2
+ ld a, 1
+.okay2
+ ld [wMenuCursorY], a
+ xor a
+ ld [wCursorOffCharacter], a
+ ld [wCursorCurrentTile], a
+ ld [wCursorCurrentTile + 1], a
+ ret
+; 24179
+
+.InitFlags_a: ; 24179
+ xor a
+ ld hl, w2DMenuFlags1
+ ld [hli], a
+ ld [hld], a
+ ld a, [wMenuDataFlags]
+ bit 5, a
+ ret z
+ set 5, [hl]
+ set 4, [hl]
+ ret
+; 2418a
+
+.InitFlags_b: ; 2418a
+ ld a, [wMenuData_2DMenuSpacing]
+ or $20
+ ld [w2DMenuCursorOffsets], a
+ ret
+; 24193
+
+.InitFlags_c: ; 24193
+ ld hl, wMenuDataFlags
+ ld a, A_BUTTON
+ bit 0, [hl]
+ jr nz, .skip
+ or B_BUTTON
+.skip
+ bit 1, [hl]
+ jr z, .skip2
+ or SELECT
+.skip2
+ ld [wMenuJoypadFilter], a
+ ret
+; 241a8
+
+
+_StaticMenuJoypad:: ; 241a8
+ call Place2DMenuCursor
+_ScrollingMenuJoypad:: ; 241ab
+ ld hl, w2DMenuFlags2
+ res 7, [hl]
+ ld a, [hBGMapMode]
+ push af
+ call MenuJoypadLoop
+ pop af
+ ld [hBGMapMode], a
+ ret
+; 241ba
+
+MobileMenuJoypad: ; 241ba
+ ld hl, w2DMenuFlags2
+ res 7, [hl]
+ ld a, [hBGMapMode]
+ push af
+ call Move2DMenuCursor
+ call Do2DMenuRTCJoypad
+ jr nc, .skip_joypad
+ call _2DMenuInterpretJoypad
+.skip_joypad
+ pop af
+ ld [hBGMapMode], a
+ call GetMenuJoypad
+ ld c, a
+ ret
+; 241d5
+
+
+Unreferenced_Function241d5: ; 241d5
+ call Place2DMenuCursor
+.loop
+ call Move2DMenuCursor
+ call HDMATransferTileMapToWRAMBank3 ; BUG: This function is in another bank.
+ ; Pointer in current bank (9) is bogus.
+ call .loop2
+ jr nc, .done
+ call _2DMenuInterpretJoypad
+ jr c, .done
+ ld a, [w2DMenuFlags1]
+ bit 7, a
+ jr nz, .done
+ call GetMenuJoypad
+ ld c, a
+ ld a, [wMenuJoypadFilter]
+ and c
+ jr z, .loop
+
+.done
+ ret
+
+.loop2
+ call Menu_WasButtonPressed
+ ret c
+ ld c, 1
+ ld b, 3
+ call AdvanceMobileInactivityTimerAndCheckExpired ; BUG: This function is in another bank.
+ ; Pointer in current bank (9) is bogus.
+ ret c
+ farcall Function100337
+ ret c
+ ld a, [w2DMenuFlags1]
+ bit 7, a
+ jr z, .loop2
+ and a
+ ret
+; 24216
+
+
+MenuJoypadLoop: ; 24216
+.loop
+ call Move2DMenuCursor
+ call .BGMap_OAM
+ call Do2DMenuRTCJoypad
+ jr nc, .done
+ call _2DMenuInterpretJoypad
+ jr c, .done
+ ld a, [w2DMenuFlags1]
+ bit 7, a
+ jr nz, .done
+ call GetMenuJoypad
+ ld b, a
+ ld a, [wMenuJoypadFilter]
+ and b
+ jr z, .loop
+
+.done
+ ret
+; 24238
+
+.BGMap_OAM: ; 24238
+ ld a, [hOAMUpdate]
+ push af
+ ld a, $1
+ ld [hOAMUpdate], a
+ call WaitBGMap
+ pop af
+ ld [hOAMUpdate], a
+ xor a
+ ld [hBGMapMode], a
+ ret
+; 24249
+
+Do2DMenuRTCJoypad: ; 24249
+.loopRTC
+ call RTC
+ call Menu_WasButtonPressed
+ ret c
+ ld a, [w2DMenuFlags1]
+ bit 7, a
+ jr z, .loopRTC
+ and a
+ ret
+; 24259
+
+Menu_WasButtonPressed: ; 24259
+ ld a, [w2DMenuFlags1]
+ bit 6, a
+ jr z, .skip_to_joypad
+ callfar PlaySpriteAnimationsAndDelayFrame
+
+.skip_to_joypad
+ call JoyTextDelay
+ call GetMenuJoypad
+ and a
+ ret z
+ scf
+ ret
+; 24270
+
+_2DMenuInterpretJoypad: ; 24270
+ call GetMenuJoypad
+ bit A_BUTTON_F, a
+ jp nz, .a_b_start_select
+ bit B_BUTTON_F, a
+ jp nz, .a_b_start_select
+ bit SELECT_F, a
+ jp nz, .a_b_start_select
+ bit START_F, a
+ jp nz, .a_b_start_select
+ bit D_RIGHT_F, a
+ jr nz, .d_right
+ bit D_LEFT_F, a
+ jr nz, .d_left
+ bit D_UP_F, a
+ jr nz, .d_up
+ bit D_DOWN_F, a
+ jr nz, .d_down
+ and a
+ ret
+
+.set_bit_7 ; 24299
+ ld hl, w2DMenuFlags2
+ set 7, [hl]
+ scf
+ ret
+
+.d_down
+ ld hl, wMenuCursorY
+ ld a, [w2DMenuNumRows]
+ cp [hl]
+ jr z, .check_wrap_around_down
+ inc [hl]
+ xor a
+ ret
+
+.check_wrap_around_down
+ ld a, [w2DMenuFlags1]
+ bit 5, a
+ jr nz, .wrap_around_down
+ bit 3, a
+ jp nz, .set_bit_7
+ xor a
+ ret
+
+.wrap_around_down
+ ld [hl], $1
+ xor a
+ ret
+
+.d_up
+ ld hl, wMenuCursorY
+ ld a, [hl]
+ dec a
+ jr z, .check_wrap_around_up
+ ld [hl], a
+ xor a
+ ret
+
+.check_wrap_around_up
+ ld a, [w2DMenuFlags1]
+ bit 5, a
+ jr nz, .wrap_around_up
+ bit 2, a
+ jp nz, .set_bit_7
+ xor a
+ ret
+
+.wrap_around_up
+ ld a, [w2DMenuNumRows]
+ ld [hl], a
+ xor a
+ ret
+
+.d_left
+ ld hl, wMenuCursorX
+ ld a, [hl]
+ dec a
+ jr z, .check_wrap_around_left
+ ld [hl], a
+ xor a
+ ret
+
+.check_wrap_around_left
+ ld a, [w2DMenuFlags1]
+ bit 4, a
+ jr nz, .wrap_around_left
+ bit 1, a
+ jp nz, .set_bit_7
+ xor a
+ ret
+
+.wrap_around_left
+ ld a, [w2DMenuNumCols]
+ ld [hl], a
+ xor a
+ ret
+
+.d_right
+ ld hl, wMenuCursorX
+ ld a, [w2DMenuNumCols]
+ cp [hl]
+ jr z, .check_wrap_around_right
+ inc [hl]
+ xor a
+ ret
+
+.check_wrap_around_right
+ ld a, [w2DMenuFlags1]
+ bit 4, a
+ jr nz, .wrap_around_right
+ bit 0, a
+ jp nz, .set_bit_7
+ xor a
+ ret
+
+.wrap_around_right
+ ld [hl], $1
+ xor a
+ ret
+; 24318
+
+.a_b_start_select ; 24318
+ xor a
+ ret
+; 2431a
+
+Move2DMenuCursor: ; 2431a
+ ld hl, wCursorCurrentTile
+ ld a, [hli]
+ ld h, [hl]
+ ld l, a
+ ld a, [hl]
+ cp "▶"
+ jr nz, Place2DMenuCursor
+ ld a, [wCursorOffCharacter]
+ ld [hl], a
+Place2DMenuCursor: ; 24329
+ ld a, [w2DMenuCursorInitY]
+ ld b, a
+ ld a, [w2DMenuCursorInitX]
+ ld c, a
+ call Coord2Tile
+ ld a, [w2DMenuCursorOffsets]
+ swap a
+ and $f
+ ld c, a
+ ld a, [wMenuCursorY]
+ ld b, a
+ xor a
+ dec b
+ jr z, .got_row
+.row_loop
+ add c
+ dec b
+ jr nz, .row_loop
+
+.got_row
+ ld c, SCREEN_WIDTH
+ call AddNTimes
+ ld a, [w2DMenuCursorOffsets]
+ and $f
+ ld c, a
+ ld a, [wMenuCursorX]
+ ld b, a
+ xor a
+ dec b
+ jr z, .got_col
+.col_loop
+ add c
+ dec b
+ jr nz, .col_loop
+
+.got_col
+ ld c, a
+ add hl, bc
+ ld a, [hl]
+ cp "▶"
+ jr z, .cursor_on
+ ld [wCursorOffCharacter], a
+ ld [hl], "▶"
+
+.cursor_on
+ ld a, l
+ ld [wCursorCurrentTile], a
+ ld a, h
+ ld [wCursorCurrentTile + 1], a
+ ret
+; 24374
+
+_PushWindow:: ; 24374
+ ld a, [rSVBK]
+ push af
+ ld a, BANK(wWindowStack)
+ ld [rSVBK], a
+
+ ld hl, wWindowStackPointer
+ ld e, [hl]
+ inc hl
+ ld d, [hl]
+ push de
+
+ ld b, $10
+ ld hl, wMenuFlags
+.loop
+ ld a, [hli]
+ ld [de], a
+ dec de
+ dec b
+ jr nz, .loop
+
+; If bit 6 or 7 of the menu flags is set, set bit 0 of the address
+; at 7:[wWindowStackPointer], and draw the menu using the coordinates from the header.
+; Otherwise, reset bit 0 of 7:[wWindowStackPointer].
+ ld a, [wMenuFlags]
+ bit 6, a
+ jr nz, .bit_6
+ bit 7, a
+ jr z, .not_bit_7
+
+.bit_6
+ ld hl, wWindowStackPointer
+ ld a, [hli]
+ ld h, [hl]
+ ld l, a
+ set 0, [hl]
+ call MenuBoxCoord2Tile
+ call .copy
+ call MenuBoxCoord2Attr
+ call .copy
+ jr .done
+
+.not_bit_7
+ pop hl ; last-pushed register was de
+ push hl
+ ld a, [hld]
+ ld l, [hl]
+ ld h, a
+ res 0, [hl]
+
+.done
+ pop hl
+ call .ret ; empty function
+ ld a, h
+ ld [de], a
+ dec de
+ ld a, l
+ ld [de], a
+ dec de
+ ld hl, wWindowStackPointer
+ ld [hl], e
+ inc hl
+ ld [hl], d
+
+ pop af
+ ld [rSVBK], a
+ ld hl, wWindowStackSize
+ inc [hl]
+ ret
+; 243cd
+
+.copy ; 243cd
+ call GetMenuBoxDims
+ inc b
+ inc c
+ call .ret ; empty function
+
+.row
+ push bc
+ push hl
+
+.col
+ ld a, [hli]
+ ld [de], a
+ dec de
+ dec c
+ jr nz, .col
+
+ pop hl
+ ld bc, SCREEN_WIDTH
+ add hl, bc
+ pop bc
+ dec b
+ jr nz, .row
+
+ ret
+; 243e7
+
+.ret ; 243e7
+ ret
+; 243e8
+
+_ExitMenu:: ; 243e8
+ xor a
+ ld [hBGMapMode], a
+
+ ld a, [rSVBK]
+ push af
+ ld a, BANK(wWindowStack)
+ ld [rSVBK], a
+
+ call GetWindowStackTop
+ ld a, l
+ or h
+ jp z, Error_Cant_ExitMenu
+ ld a, l
+ ld [wWindowStackPointer], a
+ ld a, h
+ ld [wWindowStackPointer + 1], a
+ call PopWindow
+ ld a, [wMenuFlags]
+ bit 0, a
+ jr z, .loop
+ ld d, h
+ ld e, l
+ call RestoreTileBackup
+
+.loop
+ call GetWindowStackTop
+ ld a, h
+ or l
+ jr z, .done
+ call PopWindow
+
+.done
+ pop af
+ ld [rSVBK], a
+ ld hl, wWindowStackSize
+ dec [hl]
+ ret
+; 24423
+
+Unreferenced_Function24423: ; 24423
+ ld a, [wVramState]
+ bit 0, a
+ ret z
+ xor a ; sScratch
+ call GetSRAMBank
+ hlcoord 0, 0
+ ld de, sScratch
+ ld bc, SCREEN_WIDTH * SCREEN_HEIGHT
+ call CopyBytes
+ call CloseSRAM
+ call OverworldTextModeSwitch
+ xor a ; sScratch
+ call GetSRAMBank
+ ld hl, sScratch
+ decoord 0, 0
+ ld bc, SCREEN_WIDTH * SCREEN_HEIGHT
+.loop
+ ld a, [hl]
+ cp $61
+ jr c, .next
+ ld [de], a
+.next
+ inc hl
+ inc de
+ dec bc
+ ld a, c
+ or b
+ jr nz, .loop
+ call CloseSRAM
+ ret
+; 2445d
+
+Error_Cant_ExitMenu: ; 2445d
+ ld hl, .Text_NoWindowsAvailableForPopping
+ call PrintText
+ call WaitBGMap
+.InfiniteLoop:
+ jr .InfiniteLoop
+; 24468
+
+.Text_NoWindowsAvailableForPopping: ; 24468
+ text_jump UnknownText_0x1c46b7
+ db "@"
+; 2446d
+
+_InitVerticalMenuCursor:: ; 2446d
+ ld a, [wMenuDataFlags]
+ ld b, a
+ ld hl, w2DMenuCursorInitY
+ ld a, [wMenuBorderTopCoord]
+ inc a
+ bit 6, b
+ jr nz, .skip_offset
+ inc a
+.skip_offset
+ ld [hli], a
+; w2DMenuCursorInitX
+ ld a, [wMenuBorderLeftCoord]
+ inc a
+ ld [hli], a
+; w2DMenuNumRows
+ ld a, [wMenuDataItems]
+ ld [hli], a
+; w2DMenuNumCols
+ ld a, 1
+ ld [hli], a
+; w2DMenuFlags1
+ ld [hl], $0
+ bit 5, b
+ jr z, .skip_bit_5
+ set 5, [hl]
+.skip_bit_5
+ ld a, [wMenuFlags]
+ bit 4, a
+ jr z, .skip_bit_6
+ set 6, [hl]
+.skip_bit_6
+ inc hl
+; w2DMenuFlags2
+ xor a
+ ld [hli], a
+; w2DMenuCursorOffsets
+ ln a, 2, 0
+ ld [hli], a
+; wMenuJoypadFilter
+ ld a, A_BUTTON
+ bit 0, b
+ jr nz, .skip_bit_1
+ add B_BUTTON
+.skip_bit_1
+ ld [hli], a
+; wMenuCursorY
+ ld a, [wMenuCursorBuffer]
+ and a
+ jr z, .load_at_the_top
+ ld c, a
+ ld a, [wMenuDataItems]
+ cp c
+ jr nc, .load_position
+.load_at_the_top
+ ld c, 1
+.load_position
+ ld [hl], c
+ inc hl
+; wMenuCursorX
+ ld a, 1
+ ld [hli], a
+; wCursorOffCharacter, wCursorCurrentTile
+ xor a
+ ld [hli], a
+ ld [hli], a
+ ld [hli], a
+ ret
+; 244c3
diff --git a/engine/menus/menu_2.asm b/engine/menus/menu_2.asm
new file mode 100644
index 000000000..16cce5348
--- /dev/null
+++ b/engine/menus/menu_2.asm
@@ -0,0 +1,253 @@
+PlaceMenuItemName: ; 0x24ab4
+ push de
+ ld a, [wMenuSelection]
+ ld [wNamedObjectIndexBuffer], a
+ call GetItemName
+ pop hl
+ call PlaceString
+ ret
+
+PlaceMenuItemQuantity: ; 0x24ac3
+ push de
+ ld a, [wMenuSelection]
+ ld [wCurItem], a
+ farcall _CheckTossableItem
+ ld a, [wItemAttributeParamBuffer]
+ pop hl
+ and a
+ jr nz, .done
+ ld de, $15
+ add hl, de
+ ld [hl], "×"
+ inc hl
+ ld de, wMenuSelectionQuantity
+ lb bc, 1, 2
+ call PrintNum
+
+.done
+ ret
+
+PlaceMoneyTopRight: ; 24ae8
+ ld hl, MenuHeader_0x24b15
+ call CopyMenuHeader
+ jr PlaceMoneyTextBox
+
+PlaceMoneyBottomLeft: ; 24af0
+ ld hl, MenuHeader_0x24b1d
+ call CopyMenuHeader
+ jr PlaceMoneyTextBox
+
+PlaceMoneyAtTopLeftOfTextbox: ; 24af8
+ ld hl, MenuHeader_0x24b15
+ lb de, 0, 11
+ call OffsetMenuHeader
+
+PlaceMoneyTextBox: ; 24b01
+ call MenuBox
+ call MenuBoxCoord2Tile
+ ld de, SCREEN_WIDTH + 1
+ add hl, de
+ ld de, wMoney
+ lb bc, PRINTNUM_MONEY | 3, 6
+ call PrintNum
+ ret
+
+MenuHeader_0x24b15: ; 0x24b15
+ db MENU_BACKUP_TILES ; flags
+ menu_coords 11, 0, SCREEN_WIDTH - 1, 2
+ dw NULL
+ db 1 ; default option
+
+MenuHeader_0x24b1d: ; 0x24b1d
+ db MENU_BACKUP_TILES ; flags
+ menu_coords 0, 11, 8, 13
+ dw NULL
+ db 1 ; default option
+
+DisplayCoinCaseBalance: ; 24b25
+ ; Place a text box of size 1x7 at 11, 0.
+ hlcoord 11, 0
+ ld b, 1
+ ld c, 7
+ call TextBox
+ hlcoord 12, 0
+ ld de, CoinString
+ call PlaceString
+ hlcoord 17, 1
+ ld de, ShowMoney_TerminatorString
+ call PlaceString
+ ld de, wCoins
+ lb bc, 2, 4
+ hlcoord 13, 1
+ call PrintNum
+ ret
+
+DisplayMoneyAndCoinBalance: ; 24b4e
+ hlcoord 5, 0
+ ld b, 3
+ ld c, 13
+ call TextBox
+ hlcoord 6, 1
+ ld de, MoneyString
+ call PlaceString
+ hlcoord 12, 1
+ ld de, wMoney
+ lb bc, PRINTNUM_MONEY | 3, 6
+ call PrintNum
+ hlcoord 6, 3
+ ld de, CoinString
+ call PlaceString
+ hlcoord 15, 3
+ ld de, wCoins
+ lb bc, 2, 4
+ call PrintNum
+ ret
+
+MoneyString: ; 24b83
+ db "MONEY@"
+CoinString: ; 24b89
+ db "COIN@"
+ShowMoney_TerminatorString: ; 24b8e
+ db "@"
+
+Unreferenced_Function24b8f: ; 24b8f
+; related to safari?
+ ld hl, wOptions
+ ld a, [hl]
+ push af
+ set NO_TEXT_SCROLL, [hl]
+ hlcoord 0, 0
+ ld b, 3
+ ld c, 7
+ call TextBox
+ hlcoord 1, 1
+ ld de, wSafariTimeRemaining
+ lb bc, 2, 3
+ call PrintNum
+ hlcoord 4, 1
+ ld de, .slash_500
+ call PlaceString
+ hlcoord 1, 3
+ ld de, .booru_ko
+ call PlaceString
+ hlcoord 5, 3
+ ld de, wSafariBallsRemaining
+ lb bc, 1, 2
+ call PrintNum
+ pop af
+ ld [wOptions], a
+ ret
+
+.slash_500 ; 24bcf
+ db "/500@"
+.booru_ko ; 24bd4
+ db "ボール   こ@"
+
+StartMenu_DrawBugContestStatusBox: ; 24bdc
+ hlcoord 0, 0
+ ld b, 5
+ ld c, 17
+ call TextBox
+ ret
+
+StartMenu_PrintBugContestStatus: ; 24be7
+ ld hl, wOptions
+ ld a, [hl]
+ push af
+ set NO_TEXT_SCROLL, [hl]
+ call StartMenu_DrawBugContestStatusBox
+ hlcoord 1, 5
+ ld de, .Balls_EN
+ call PlaceString
+ hlcoord 8, 5
+ ld de, wParkBallsRemaining
+ lb bc, PRINTNUM_RIGHTALIGN | 1, 2
+ call PrintNum
+ hlcoord 1, 1
+ ld de, .CAUGHT
+ call PlaceString
+ ld a, [wContestMon]
+ and a
+ ld de, .None
+ jr z, .no_contest_mon
+ ld [wd265], a
+ call GetPokemonName
+
+.no_contest_mon
+ hlcoord 8, 1
+ call PlaceString
+ ld a, [wContestMon]
+ and a
+ jr z, .skip_level
+ hlcoord 1, 3
+ ld de, .LEVEL
+ call PlaceString
+ ld a, [wContestMonLevel]
+ ld h, b
+ ld l, c
+ inc hl
+ ld c, 3
+ call Print8BitNumRightAlign
+
+.skip_level
+ pop af
+ ld [wOptions], a
+ ret
+
+.Balls_JP: ; 24c43
+ db "ボール   こ@"
+.CAUGHT: ; 24c4b
+ db "CAUGHT@"
+.Balls_EN: ; 24c52
+ db "BALLS:@"
+.None: ; 24c59
+ db "None@"
+.LEVEL: ; 24c5e
+ db "LEVEL@"
+
+FindApricornsInBag: ; 24c64
+; Checks the bag for Apricorns.
+ ld hl, wBuffer1
+ xor a
+ ld [hli], a
+ dec a
+ ld bc, 10
+ call ByteFill
+
+ ld hl, ApricornBalls
+.loop
+ ld a, [hl]
+ cp -1
+ jr z, .done
+ push hl
+ ld [wCurItem], a
+ ld hl, wNumItems
+ call CheckItem
+ pop hl
+ jr nc, .nope
+ ld a, [hl]
+ call .addtobuffer
+.nope
+ inc hl
+ inc hl
+ jr .loop
+
+.done
+ ld a, [wBuffer1]
+ and a
+ ret nz
+ scf
+ ret
+
+.addtobuffer ; 24c94
+ push hl
+ ld hl, wBuffer1
+ inc [hl]
+ ld e, [hl]
+ ld d, 0
+ add hl, de
+ ld [hl], a
+ pop hl
+ ret
+
+INCLUDE "data/items/apricorn_balls.asm"
diff --git a/engine/menus/naming_screen.asm b/engine/menus/naming_screen.asm
new file mode 100755
index 000000000..a958e10eb
--- /dev/null
+++ b/engine/menus/naming_screen.asm
@@ -0,0 +1,1467 @@
+NAMINGSCREEN_CURSOR EQU $7e
+
+NAMINGSCREEN_BORDER EQUS "\"■\"" ; $60
+NAMINGSCREEN_MIDDLELINE EQUS "\"→\"" ; $eb
+NAMINGSCREEN_UNDERLINE EQUS "\"<DOT>\"" ; $f2
+
+_NamingScreen: ; 0x116b7
+ call DisableSpriteUpdates
+ call NamingScreen
+ call ReturnToMapWithSpeechTextbox
+ ret
+
+; 0x116c1
+
+NamingScreen: ; 116c1
+ ld hl, wNamingScreenDestinationPointer
+ ld [hl], e
+ inc hl
+ ld [hl], d
+ ld hl, wNamingScreenType
+ ld [hl], b
+ ld hl, wOptions
+ ld a, [hl]
+ push af
+ set NO_TEXT_SCROLL, [hl]
+ ld a, [hMapAnims]
+ push af
+ xor a
+ ld [hMapAnims], a
+ ld a, [hInMenu]
+ push af
+ ld a, $1
+ ld [hInMenu], a
+ call .SetUpNamingScreen
+ call DelayFrame
+.loop
+ call NamingScreenJoypadLoop
+ jr nc, .loop
+ pop af
+ ld [hInMenu], a
+ pop af
+ ld [hMapAnims], a
+ pop af
+ ld [wOptions], a
+ call ClearJoypad
+ ret
+
+; 116f8
+
+.SetUpNamingScreen: ; 116f8
+ call ClearBGPalettes
+ ld b, SCGB_DIPLOMA
+ call GetSGBLayout
+ call DisableLCD
+ call LoadNamingScreenGFX
+ call NamingScreen_InitText
+ ld a, LCDC_DEFAULT
+ ld [rLCDC], a
+ call .GetNamingScreenSetup
+ call WaitBGMap
+ call WaitTop
+ call SetPalettes
+ call NamingScreen_InitNameEntry
+ ret
+
+; 1171d
+
+.GetNamingScreenSetup: ; 1171d
+ ld a, [wNamingScreenType]
+ and 7
+ ld e, a
+ ld d, 0
+ ld hl, .Jumptable
+ add hl, de
+ add hl, de
+ ld a, [hli]
+ ld h, [hl]
+ ld l, a
+ jp hl
+
+; 1172e
+
+.Jumptable: ; 1172e (4:572e)
+ dw .Pokemon
+ dw .Player
+ dw .Rival
+ dw .Mom
+ dw .Box
+ dw .Tomodachi
+ dw .Pokemon
+ dw .Pokemon
+
+.Pokemon: ; 1173e (4:573e)
+ ld a, [wCurPartySpecies]
+ ld [wd265], a
+ ld hl, LoadMenuMonIcon
+ ld a, BANK(LoadMenuMonIcon)
+ ld e, $1
+ rst FarCall ; ; indirect jump to LoadMenuMonIcon (8e83f (23:683f))
+ ld a, [wCurPartySpecies]
+ ld [wd265], a
+ call GetPokemonName
+ hlcoord 5, 2
+ call PlaceString
+ ld l, c
+ ld h, b
+ ld de, .NicknameStrings
+ call PlaceString
+ inc de
+ hlcoord 5, 4
+ call PlaceString
+ farcall GetGender
+ jr c, .genderless
+ ld a, "♂"
+ jr nz, .place_gender
+ ld a, "♀"
+.place_gender
+ hlcoord 1, 2
+ ld [hl], a
+.genderless
+ call .StoreMonIconParams
+ ret
+
+; 11780 (4:5780)
+
+.NicknameStrings: ; 11780
+ db "'S@"
+ db "NICKNAME?@"
+
+; 1178d
+
+.Player: ; 1178d (4:578d)
+ farcall GetPlayerIcon
+ call .LoadSprite
+ hlcoord 5, 2
+ ld de, .PlayerNameString
+ call PlaceString
+ call .StoreSpriteIconParams
+ ret
+
+; 117a3 (4:57a3)
+
+.PlayerNameString: ; 117a3
+ db "YOUR NAME?@"
+
+; 117ae
+
+.Rival: ; 117ae (4:57ae)
+ ld de, SilverSpriteGFX
+ ld b, BANK(SilverSpriteGFX)
+ call .LoadSprite
+ hlcoord 5, 2
+ ld de, .RivalNameString
+ call PlaceString
+ call .StoreSpriteIconParams
+ ret
+
+; 117c3 (4:57c3)
+
+.RivalNameString: ; 117c3
+ db "RIVAL'S NAME?@"
+
+; 117d1
+
+.Mom: ; 117d1 (4:57d1)
+ ld de, MomSpriteGFX
+ ld b, BANK(MomSpriteGFX)
+ call .LoadSprite
+ hlcoord 5, 2
+ ld de, .MomNameString
+ call PlaceString
+ call .StoreSpriteIconParams
+ ret
+
+; 117e6 (4:57e6)
+
+.MomNameString: ; 117e6
+ db "MOTHER'S NAME?@"
+
+; 117f5
+
+.Box: ; 117f5 (4:57f5)
+ ld de, PokeBallSpriteGFX
+ ld hl, vTiles0 tile $00
+ lb bc, BANK(PokeBallSpriteGFX), 4
+ call Request2bpp
+ xor a
+ ld hl, wSpriteAnimDict
+ ld [hli], a
+ ld [hl], a
+ depixel 4, 4, 4, 0
+ ld a, SPRITE_ANIM_INDEX_RED_WALK
+ call _InitSpriteAnimStruct
+ ld hl, SPRITEANIMSTRUCT_FRAMESET_ID
+ add hl, bc
+ ld [hl], $0
+ hlcoord 5, 2
+ ld de, .BoxNameString
+ call PlaceString
+ call .StoreBoxIconParams
+ ret
+
+; 11822 (4:5822)
+
+.BoxNameString: ; 11822
+ db "BOX NAME?@"
+
+; 1182c
+
+.Tomodachi: ; 1182c (4:582c)
+ hlcoord 3, 2
+ ld de, .oTomodachi_no_namae_sutoringu
+ call PlaceString
+ call .StoreSpriteIconParams
+ ret
+
+; 11839 (4:5839)
+
+.oTomodachi_no_namae_sutoringu ; 11839
+ db "おともだち の なまえは?@"
+
+; 11847
+
+.LoadSprite: ; 11847 (4:5847)
+ push de
+ ld hl, vTiles0 tile $00
+ ld c, $4
+ push bc
+ call Request2bpp
+ pop bc
+ ld hl, 12 tiles
+ add hl, de
+ ld e, l
+ ld d, h
+ ld hl, vTiles0 tile $04
+ call Request2bpp
+ xor a
+ ld hl, wSpriteAnimDict
+ ld [hli], a
+ ld [hl], a
+ pop de
+ ld b, SPRITE_ANIM_INDEX_RED_WALK
+ ld a, d
+ cp HIGH(KrisSpriteGFX)
+ jr nz, .not_kris
+ ld a, e
+ cp LOW(KrisSpriteGFX)
+ jr nz, .not_kris
+ ld b, SPRITE_ANIM_INDEX_BLUE_WALK
+.not_kris
+ ld a, b
+ depixel 4, 4, 4, 0
+ call _InitSpriteAnimStruct
+ ret
+
+.StoreMonIconParams: ; 1187b (4:587b)
+ ld a, MON_NAME_LENGTH - 1
+ hlcoord 5, 6
+ jr .StoreParams
+
+.StoreSpriteIconParams: ; 11882 (4:5882)
+ ld a, PLAYER_NAME_LENGTH - 1
+ hlcoord 5, 6
+ jr .StoreParams
+
+.StoreBoxIconParams: ; 11889 (4:5889)
+ ld a, BOX_NAME_LENGTH - 1
+ hlcoord 5, 4
+ jr .StoreParams
+
+.StoreParams: ; 11890 (4:5890)
+ ld [wNamingScreenMaxNameLength], a
+ ld a, l
+ ld [wNamingScreenStringEntryCoord], a
+ ld a, h
+ ld [wNamingScreenStringEntryCoord + 1], a
+ ret
+
+NamingScreen_IsTargetBox: ; 1189c
+ push bc
+ push af
+ ld a, [wNamingScreenType]
+ sub $3
+ ld b, a
+ pop af
+ dec b
+ pop bc
+ ret
+
+; 118a8
+
+NamingScreen_InitText: ; 118a8
+ call WaitTop
+ hlcoord 0, 0
+ ld bc, SCREEN_WIDTH * SCREEN_HEIGHT
+ ld a, NAMINGSCREEN_BORDER
+ call ByteFill
+ hlcoord 1, 1
+ lb bc, 6, 18
+ call NamingScreen_IsTargetBox
+ jr nz, .not_box
+ lb bc, 4, 18
+
+.not_box
+ call ClearBox
+ ld de, NameInputUpper
+NamingScreen_ApplyTextInputMode: ; 118ca
+ call NamingScreen_IsTargetBox
+ jr nz, .not_box
+ ld hl, BoxNameInputLower - NameInputLower
+ add hl, de
+ ld d, h
+ ld e, l
+
+.not_box
+ push de
+ hlcoord 1, 8
+ lb bc, 7, 18
+ call NamingScreen_IsTargetBox
+ jr nz, .not_box_2
+ hlcoord 1, 6
+ lb bc, 9, 18
+
+.not_box_2
+ call ClearBox
+ hlcoord 1, 16
+ lb bc, 1, 18
+ call ClearBox
+ pop de
+ hlcoord 2, 8
+ ld b, $5
+ call NamingScreen_IsTargetBox
+ jr nz, .row
+ hlcoord 2, 6
+ ld b, $6
+
+.row
+ ld c, $11
+.col
+ ld a, [de]
+ ld [hli], a
+ inc de
+ dec c
+ jr nz, .col
+ push de
+ ld de, 2 * SCREEN_WIDTH - $11
+ add hl, de
+ pop de
+ dec b
+ jr nz, .row
+ ret
+
+; 11915
+
+NamingScreenJoypadLoop: ; 11915
+ call JoyTextDelay
+ ld a, [wJumptableIndex]
+ bit 7, a
+ jr nz, .quit
+ call .RunJumptable
+ farcall PlaySpriteAnimationsAndDelayFrame
+ call .UpdateStringEntry
+ call DelayFrame
+ and a
+ ret
+
+.quit
+ callfar ClearSpriteAnims
+ call ClearSprites
+ xor a
+ ld [hSCX], a
+ ld [hSCY], a
+ scf
+ ret
+
+; 11940
+
+.UpdateStringEntry: ; 11940
+ xor a
+ ld [hBGMapMode], a
+ hlcoord 1, 5
+ call NamingScreen_IsTargetBox
+ jr nz, .got_coords
+ hlcoord 1, 3
+
+.got_coords
+ lb bc, 1, 18
+ call ClearBox
+ ld hl, wNamingScreenDestinationPointer
+ ld e, [hl]
+ inc hl
+ ld d, [hl]
+ ld hl, wNamingScreenStringEntryCoord
+ ld a, [hli]
+ ld h, [hl]
+ ld l, a
+ call PlaceString
+ ld a, $1
+ ld [hBGMapMode], a
+ ret
+
+; 11968
+
+.RunJumptable: ; 11968
+ ld a, [wJumptableIndex]
+ ld e, a
+ ld d, $0
+ ld hl, .Jumptable
+ add hl, de
+ add hl, de
+ ld a, [hli]
+ ld h, [hl]
+ ld l, a
+ jp hl
+
+; 11977
+
+.Jumptable: ; 11977 (4:5977)
+ dw .InitCursor
+ dw .ReadButtons
+
+.InitCursor: ; 1197b (4:597b)
+ depixel 10, 3
+ call NamingScreen_IsTargetBox
+ jr nz, .got_cursor_position
+ ld d, 8 * 8
+.got_cursor_position
+ ld a, SPRITE_ANIM_INDEX_NAMING_SCREEN_CURSOR
+ call _InitSpriteAnimStruct
+ ld a, c
+ ld [wNamingScreenCursorObjectPointer], a
+ ld a, b
+ ld [wNamingScreenCursorObjectPointer + 1], a
+ ld hl, SPRITEANIMSTRUCT_FRAMESET_ID
+ add hl, bc
+ ld a, [hl]
+ ld hl, SPRITEANIMSTRUCT_0E
+ add hl, bc
+ ld [hl], a
+ ld hl, wJumptableIndex
+ inc [hl]
+ ret
+
+.ReadButtons: ; 119a1 (4:59a1)
+ ld hl, hJoyPressed ; $ffa7
+ ld a, [hl]
+ and A_BUTTON
+ jr nz, .a
+ ld a, [hl]
+ and B_BUTTON
+ jr nz, .b
+ ld a, [hl]
+ and START
+ jr nz, .start
+ ld a, [hl]
+ and SELECT
+ jr nz, .select
+ ret
+
+.a
+ call .GetCursorPosition
+ cp $1
+ jr z, .select
+ cp $2
+ jr z, .b
+ cp $3
+ jr z, .end
+ call NamingScreen_GetLastCharacter
+ call NamingScreen_TryAddCharacter
+ ret nc
+
+.start
+ ld hl, wNamingScreenCursorObjectPointer
+ ld c, [hl]
+ inc hl
+ ld b, [hl]
+ ld hl, SPRITEANIMSTRUCT_0C
+ add hl, bc
+ ld [hl], $8
+ ld hl, SPRITEANIMSTRUCT_0D
+ add hl, bc
+ ld [hl], $4
+ call NamingScreen_IsTargetBox
+ ret nz
+ inc [hl]
+ ret
+
+.b
+ call NamingScreen_DeleteCharacter
+ ret
+
+.end
+ call NamingScreen_StoreEntry
+ ld hl, wJumptableIndex
+ set 7, [hl]
+ ret
+
+.select
+ ld hl, wNamingScreenLetterCase
+ ld a, [hl]
+ xor 1
+ ld [hl], a
+ jr z, .upper
+ ld de, NameInputLower
+ call NamingScreen_ApplyTextInputMode
+ ret
+
+.upper
+ ld de, NameInputUpper
+ call NamingScreen_ApplyTextInputMode
+ ret
+
+.GetCursorPosition: ; 11a0b (4:5a0b)
+ ld hl, wNamingScreenCursorObjectPointer
+ ld c, [hl]
+ inc hl
+ ld b, [hl]
+
+NamingScreen_GetCursorPosition: ; 11a11 (4:5a11)
+ ld hl, SPRITEANIMSTRUCT_0D
+ add hl, bc
+ ld a, [hl]
+ push bc
+ ld b, $4
+ call NamingScreen_IsTargetBox
+ jr nz, .not_box
+ inc b
+.not_box
+ cp b
+ pop bc
+ jr nz, .not_bottom_row
+ ld hl, SPRITEANIMSTRUCT_0C
+ add hl, bc
+ ld a, [hl]
+ cp $3
+ jr c, .case_switch
+ cp $6
+ jr c, .delete
+ ld a, $3
+ ret
+
+.case_switch
+ ld a, $1
+ ret
+
+.delete
+ ld a, $2
+ ret
+
+.not_bottom_row
+ xor a
+ ret
+
+NamingScreen_AnimateCursor: ; 11a3b (4:5a3b)
+ call .GetDPad
+ ld hl, SPRITEANIMSTRUCT_0D
+ add hl, bc
+ ld a, [hl]
+ ld e, a
+ swap e
+ ld hl, SPRITEANIMSTRUCT_YOFFSET
+ add hl, bc
+ ld [hl], e
+ ld d, $4
+ call NamingScreen_IsTargetBox
+ jr nz, .ok
+ inc d
+.ok
+ cp d
+ ld de, .LetterEntries
+ ld a, SPRITE_ANIM_FRAMESET_TEXT_ENTRY_CURSOR - SPRITE_ANIM_FRAMESET_TEXT_ENTRY_CURSOR ; 0
+ jr nz, .ok2
+ ld de, .CaseDelEnd
+ ld a, SPRITE_ANIM_FRAMESET_TEXT_ENTRY_CURSOR_BIG - SPRITE_ANIM_FRAMESET_TEXT_ENTRY_CURSOR ; 1
+.ok2
+ ld hl, SPRITEANIMSTRUCT_0E
+ add hl, bc
+ add [hl] ; default SPRITE_ANIM_FRAMESET_TEXT_ENTRY_CURSOR
+ ld hl, SPRITEANIMSTRUCT_FRAMESET_ID
+ add hl, bc
+ ld [hl], a
+ ld hl, SPRITEANIMSTRUCT_0C
+ add hl, bc
+ ld l, [hl]
+ ld h, $0
+ add hl, de
+ ld a, [hl]
+ ld hl, SPRITEANIMSTRUCT_XOFFSET
+ add hl, bc
+ ld [hl], a
+ ret
+
+; 11a79 (4:5a79)
+
+.LetterEntries: ; 11a79
+ db $00, $10, $20, $30, $40, $50, $60, $70, $80
+
+.CaseDelEnd: ; 11a82
+ db $00, $00, $00, $30, $30, $30, $60, $60, $60
+
+; 11a8b
+
+.GetDPad: ; 11a8b (4:5a8b)
+ ld hl, hJoyLast
+ ld a, [hl]
+ and D_UP
+ jr nz, .up
+ ld a, [hl]
+ and D_DOWN
+ jr nz, .down
+ ld a, [hl]
+ and D_LEFT
+ jr nz, .left
+ ld a, [hl]
+ and D_RIGHT
+ jr nz, .right
+ ret
+
+.right
+ call NamingScreen_GetCursorPosition
+ and a
+ jr nz, .asm_11ab7
+ ld hl, SPRITEANIMSTRUCT_0C
+ add hl, bc
+ ld a, [hl]
+ cp $8
+ jr nc, .asm_11ab4
+ inc [hl]
+ ret
+
+.asm_11ab4
+ ld [hl], $0
+ ret
+
+.asm_11ab7
+ cp $3
+ jr nz, .asm_11abc
+ xor a
+.asm_11abc
+ ld e, a
+ add a
+ add e
+ ld hl, SPRITEANIMSTRUCT_0C
+ add hl, bc
+ ld [hl], a
+ ret
+
+.left
+ call NamingScreen_GetCursorPosition
+ and a
+ jr nz, .asm_11ad8
+ ld hl, SPRITEANIMSTRUCT_0C
+ add hl, bc
+ ld a, [hl]
+ and a
+ jr z, .asm_11ad5
+ dec [hl]
+ ret
+
+.asm_11ad5
+ ld [hl], $8
+ ret
+
+.asm_11ad8
+ cp $1
+ jr nz, .asm_11ade
+ ld a, $4
+.asm_11ade
+ dec a
+ dec a
+ ld e, a
+ add a
+ add e
+ ld hl, SPRITEANIMSTRUCT_0C
+ add hl, bc
+ ld [hl], a
+ ret
+
+.down
+ ld hl, SPRITEANIMSTRUCT_0D
+ add hl, bc
+ ld a, [hl]
+ call NamingScreen_IsTargetBox
+ jr nz, .asm_11af9
+ cp $5
+ jr nc, .asm_11aff
+ inc [hl]
+ ret
+
+.asm_11af9
+ cp $4
+ jr nc, .asm_11aff
+ inc [hl]
+ ret
+
+.asm_11aff
+ ld [hl], $0
+ ret
+
+.up
+ ld hl, SPRITEANIMSTRUCT_0D
+ add hl, bc
+ ld a, [hl]
+ and a
+ jr z, .asm_11b0c
+ dec [hl]
+ ret
+
+.asm_11b0c
+ ld [hl], $4
+ call NamingScreen_IsTargetBox
+ ret nz
+ inc [hl]
+ ret
+
+NamingScreen_TryAddCharacter: ; 11b14 (4:5b14)
+ ld a, [wNamingScreenLastCharacter] ; lost
+MailComposition_TryAddCharacter: ; 11b17 (4:5b17)
+ ld a, [wNamingScreenMaxNameLength]
+ ld c, a
+ ld a, [wNamingScreenCurrNameLength]
+ cp c
+ ret nc
+
+ ld a, [wNamingScreenLastCharacter]
+
+NamingScreen_LoadNextCharacter: ; 11b23
+ call NamingScreen_GetTextCursorPosition
+ ld [hl], a
+
+NamingScreen_AdvanceCursor_CheckEndOfString: ; 11b27
+ ld hl, wNamingScreenCurrNameLength
+ inc [hl]
+ call NamingScreen_GetTextCursorPosition
+ ld a, [hl]
+ cp "@"
+ jr z, .end_of_string
+ ld [hl], NAMINGSCREEN_UNDERLINE
+ and a
+ ret
+
+.end_of_string
+ scf
+ ret
+
+; 11b39 (4:5b39)
+
+; unused
+ ld a, [wNamingScreenCurrNameLength]
+ and a
+ ret z
+ push hl
+ ld hl, wNamingScreenCurrNameLength
+ dec [hl]
+ call NamingScreen_GetTextCursorPosition
+ ld c, [hl]
+ pop hl
+
+.loop
+ ld a, [hli]
+ cp $ff
+ jr z, NamingScreen_AdvanceCursor_CheckEndOfString
+ cp c
+ jr z, .done
+ inc hl
+ jr .loop
+
+.done
+ ld a, [hl]
+ jr NamingScreen_LoadNextCharacter
+
+; 11b56
+
+INCLUDE "data/text/unused_dakutens.asm"
+
+; 11bbc
+
+NamingScreen_DeleteCharacter: ; 11bbc (4:5bbc)
+ ld hl, wNamingScreenCurrNameLength
+ ld a, [hl]
+ and a
+ ret z
+ dec [hl]
+ call NamingScreen_GetTextCursorPosition
+ ld [hl], NAMINGSCREEN_UNDERLINE
+ inc hl
+ ld a, [hl]
+ cp NAMINGSCREEN_UNDERLINE
+ ret nz
+ ld [hl], NAMINGSCREEN_MIDDLELINE
+ ret
+
+NamingScreen_GetTextCursorPosition: ; 11bd0 (4:5bd0)
+ push af
+ ld hl, wNamingScreenDestinationPointer
+ ld a, [hli]
+ ld h, [hl]
+ ld l, a
+ ld a, [wNamingScreenCurrNameLength]
+ ld e, a
+ ld d, 0
+ add hl, de
+ pop af
+ ret
+
+; 11be0
+
+NamingScreen_InitNameEntry: ; 11be0
+; load NAMINGSCREEN_UNDERLINE, (NAMINGSCREEN_MIDDLELINE * [wNamingScreenMaxNameLength]), "@" into the dw address at wNamingScreenDestinationPointer
+ ld hl, wNamingScreenDestinationPointer
+ ld a, [hli]
+ ld h, [hl]
+ ld l, a
+ ld [hl], NAMINGSCREEN_UNDERLINE
+ inc hl
+ ld a, [wNamingScreenMaxNameLength]
+ dec a
+ ld c, a
+ ld a, NAMINGSCREEN_MIDDLELINE
+.loop
+ ld [hli], a
+ dec c
+ jr nz, .loop
+ ld [hl], "@"
+ ret
+
+; 11bf7
+
+NamingScreen_StoreEntry: ; 11bf7 (4:5bf7)
+ ld hl, wNamingScreenDestinationPointer
+ ld a, [hli]
+ ld h, [hl]
+ ld l, a
+ ld a, [wNamingScreenMaxNameLength]
+ ld c, a
+.loop
+ ld a, [hl]
+ cp NAMINGSCREEN_MIDDLELINE
+ jr z, .terminator
+ cp NAMINGSCREEN_UNDERLINE
+ jr nz, .not_terminator
+.terminator
+ ld [hl], "@"
+.not_terminator
+ inc hl
+ dec c
+ jr nz, .loop
+ ret
+
+NamingScreen_GetLastCharacter: ; 11c11 (4:5c11)
+ ld hl, wNamingScreenCursorObjectPointer
+ ld c, [hl]
+ inc hl
+ ld b, [hl]
+ ld hl, SPRITEANIMSTRUCT_XOFFSET
+ add hl, bc
+ ld a, [hl]
+ ld hl, SPRITEANIMSTRUCT_XCOORD
+ add hl, bc
+ add [hl]
+ sub $8
+ srl a
+ srl a
+ srl a
+ ld e, a
+ ld hl, SPRITEANIMSTRUCT_YOFFSET
+ add hl, bc
+ ld a, [hl]
+ ld hl, SPRITEANIMSTRUCT_YCOORD
+ add hl, bc
+ add [hl]
+ sub $10
+ srl a
+ srl a
+ srl a
+ ld d, a
+ hlcoord 0, 0
+ ld bc, SCREEN_WIDTH
+.loop
+ ld a, d
+ and a
+ jr z, .done
+ add hl, bc
+ dec d
+ jr .loop
+
+.done
+ add hl, de
+ ld a, [hl]
+ ld [wNamingScreenLastCharacter], a
+ ret
+
+LoadNamingScreenGFX: ; 11c51
+ call ClearSprites
+ callfar ClearSpriteAnims
+ call LoadStandardFont
+ call LoadFontsExtra
+
+ ld de, NamingScreenGFX_MiddleLine
+ ld hl, vTiles0 tile NAMINGSCREEN_MIDDLELINE
+ lb bc, BANK(NamingScreenGFX_MiddleLine), 1
+ call Get1bpp
+
+ ld de, NamingScreenGFX_UnderLine
+ ld hl, vTiles0 tile NAMINGSCREEN_UNDERLINE
+ lb bc, BANK(NamingScreenGFX_UnderLine), 1
+ call Get1bpp
+
+ ld de, vTiles2 tile NAMINGSCREEN_BORDER
+ ld hl, NamingScreenGFX_Border
+ ld bc, 1 tiles
+ ld a, BANK(NamingScreenGFX_Border)
+ call FarCopyBytes
+
+ ld de, vTiles0 tile NAMINGSCREEN_CURSOR
+ ld hl, NamingScreenGFX_Cursor
+ ld bc, 2 tiles
+ ld a, BANK(NamingScreenGFX_Cursor)
+ call FarCopyBytes
+
+ ld a, $5
+ ld hl, wSpriteAnimDict + 9 * 2
+ ld [hli], a
+ ld [hl], NAMINGSCREEN_CURSOR
+ xor a
+ ld [hSCY], a
+ ld [wGlobalAnimYOffset], a
+ ld [hSCX], a
+ ld [wGlobalAnimXOffset], a
+ ld [wJumptableIndex], a
+ ld [wNamingScreenLetterCase], a
+ ld [hBGMapMode], a
+ ld [wNamingScreenCurrNameLength], a
+ ld a, $7
+ ld [hWX], a
+ ret
+
+; 11cb7
+
+NamingScreenGFX_Border: ; 11cb7
+INCBIN "gfx/naming_screen/border.2bpp"
+; 11cc7
+
+NamingScreenGFX_Cursor: ; 11cc7
+INCBIN "gfx/naming_screen/cursor.2bpp"
+; 11ce7
+
+INCLUDE "data/text/name_input_chars.asm"
+; 11e5d
+
+NamingScreenGFX_End: ; unused
+INCBIN "gfx/naming_screen/end.1bpp"
+; 11e6d
+
+NamingScreenGFX_MiddleLine:
+INCBIN "gfx/naming_screen/middle_line.1bpp"
+; 11e6d
+
+NamingScreenGFX_UnderLine: ; 11e6d
+INCBIN "gfx/naming_screen/underline.1bpp"
+; 11e75
+
+_ComposeMailMessage: ; 11e75 (mail?)
+ ld hl, wNamingScreenDestinationPointer
+ ld [hl], e
+ inc hl
+ ld [hl], d
+ ld a, [hMapAnims]
+ push af
+ xor a
+ ld [hMapAnims], a
+ ld a, [hInMenu]
+ push af
+ ld a, $1
+ ld [hInMenu], a
+ call .InitBlankMail
+ call DelayFrame
+
+.loop
+ call .DoMailEntry
+ jr nc, .loop
+
+ pop af
+ ld [hInMenu], a
+ pop af
+ ld [hMapAnims], a
+ ret
+
+.InitBlankMail: ; 11e9a (4:5e9a)
+ call ClearBGPalettes
+ call DisableLCD
+ call LoadNamingScreenGFX
+ ld de, vTiles0 tile $00
+ ld hl, .MailIcon
+ ld bc, 8 tiles
+ ld a, BANK(.MailIcon)
+ call FarCopyBytes
+ xor a
+ ld hl, wSpriteAnimDict
+ ld [hli], a
+ ld [hl], a
+
+ ; init mail icon
+ depixel 3, 2
+ ld a, SPRITE_ANIM_INDEX_PARTY_MON
+ call _InitSpriteAnimStruct
+
+ ld hl, SPRITEANIMSTRUCT_ANIM_SEQ_ID
+ add hl, bc
+ ld [hl], $0
+ call .InitCharset
+ ld a, LCDC_DEFAULT
+ ld [rLCDC], a
+ call .initwNamingScreenMaxNameLength
+ ld b, SCGB_DIPLOMA
+ call GetSGBLayout
+ call WaitBGMap
+ call WaitTop
+ ld a, %11100100
+ call DmgToCgbBGPals
+ ld a, %11100100
+ call DmgToCgbObjPal0
+ call NamingScreen_InitNameEntry
+ ld hl, wNamingScreenDestinationPointer
+ ld e, [hl]
+ inc hl
+ ld d, [hl]
+ ld hl, MAIL_LINE_LENGTH
+ add hl, de
+ ld [hl], "<NEXT>"
+ ret
+
+; 11ef4 (4:5ef4)
+
+.MailIcon: ; 11ef4
+INCBIN "gfx/icons/mail_big.2bpp"
+; 11f74
+
+.initwNamingScreenMaxNameLength ; 11f74 (4:5f74)
+ ld a, MAIL_MSG_LENGTH + 1
+ ld [wNamingScreenMaxNameLength], a
+ ret
+
+; 11f7a (4:5f7a)
+
+.UnusedString11f7a:
+ db "メールを かいてね@"
+
+; 11f84
+
+.InitCharset: ; 11f84 (4:5f84)
+ call WaitTop
+ hlcoord 0, 0
+ ld bc, 6 * SCREEN_WIDTH
+ ld a, NAMINGSCREEN_BORDER
+ call ByteFill
+ hlcoord 0, 6
+ ld bc, 12 * SCREEN_WIDTH
+ ld a, " "
+ call ByteFill
+ hlcoord 1, 1
+ lb bc, 4, SCREEN_WIDTH - 2
+ call ClearBox
+ ld de, MailEntry_Uppercase
+
+.PlaceMailCharset: ; 11fa9 (4:5fa9)
+ hlcoord 1, 7
+ ld b, 6
+.next
+ ld c, SCREEN_WIDTH - 1
+.loop_
+ ld a, [de]
+ ld [hli], a
+ inc de
+ dec c
+ jr nz, .loop_
+ push de
+ ld de, SCREEN_WIDTH + 1
+ add hl, de
+ pop de
+ dec b
+ jr nz, .next
+ ret
+
+.DoMailEntry: ; 11fc0 (4:5fc0)
+ call JoyTextDelay
+ ld a, [wJumptableIndex]
+ bit 7, a
+ jr nz, .exit_mail
+ call .DoJumptable
+ farcall PlaySpriteAnimationsAndDelayFrame
+ call .Update
+ call DelayFrame
+ and a
+ ret
+
+.exit_mail
+ callfar ClearSpriteAnims
+ call ClearSprites
+ xor a
+ ld [hSCX], a
+ ld [hSCY], a
+ scf
+ ret
+
+.Update: ; 11feb (4:5feb)
+ xor a
+ ld [hBGMapMode], a
+ hlcoord 1, 1
+ lb bc, 4, 18
+ call ClearBox
+ ld hl, wNamingScreenDestinationPointer
+ ld e, [hl]
+ inc hl
+ ld d, [hl]
+ hlcoord 2, 2
+ call PlaceString
+ ld a, $1
+ ld [hBGMapMode], a
+ ret
+
+.DoJumptable: ; 12008 (4:6008)
+ ld a, [wJumptableIndex]
+ ld e, a
+ ld d, 0
+ ld hl, .Jumptable
+ add hl, de
+ add hl, de
+ ld a, [hli]
+ ld h, [hl]
+ ld l, a
+ jp hl
+
+.Jumptable: ; 12017 (4:6017)
+ dw .init_blinking_cursor
+ dw .process_joypad
+
+.init_blinking_cursor ; 1201b (4:601b)
+ depixel 9, 2
+ ld a, SPRITE_ANIM_INDEX_COMPOSE_MAIL_CURSOR
+ call _InitSpriteAnimStruct
+ ld a, c
+ ld [wNamingScreenCursorObjectPointer], a
+ ld a, b
+ ld [wNamingScreenCursorObjectPointer + 1], a
+ ld hl, SPRITEANIMSTRUCT_FRAMESET_ID
+ add hl, bc
+ ld a, [hl]
+ ld hl, SPRITEANIMSTRUCT_0E
+ add hl, bc
+ ld [hl], a
+ ld hl, wJumptableIndex
+ inc [hl]
+ ret
+
+.process_joypad ; 1203a (4:603a)
+ ld hl, hJoyPressed ; $ffa7
+ ld a, [hl]
+ and A_BUTTON
+ jr nz, .a
+ ld a, [hl]
+ and B_BUTTON
+ jr nz, .b
+ ld a, [hl]
+ and START
+ jr nz, .start
+ ld a, [hl]
+ and SELECT
+ jr nz, .select
+ ret
+
+.a
+ call NamingScreen_PressedA_GetCursorCommand
+ cp $1
+ jr z, .select
+ cp $2
+ jr z, .b
+ cp $3
+ jr z, .finished
+ call NamingScreen_GetLastCharacter
+ call MailComposition_TryAddLastCharacter
+ jr c, .start
+ ld hl, wNamingScreenCurrNameLength
+ ld a, [hl]
+ cp MAIL_LINE_LENGTH
+ ret nz
+ inc [hl]
+ call NamingScreen_GetTextCursorPosition
+ ld [hl], NAMINGSCREEN_UNDERLINE
+ dec hl
+ ld [hl], "<NEXT>"
+ ret
+
+.start
+ ld hl, wNamingScreenCursorObjectPointer
+ ld c, [hl]
+ inc hl
+ ld b, [hl]
+ ld hl, SPRITEANIMSTRUCT_0C
+ add hl, bc
+ ld [hl], $9
+ ld hl, SPRITEANIMSTRUCT_0D
+ add hl, bc
+ ld [hl], $5
+ ret
+
+.b
+ call NamingScreen_DeleteCharacter
+ ld hl, wNamingScreenCurrNameLength
+ ld a, [hl]
+ cp MAIL_LINE_LENGTH
+ ret nz
+ dec [hl]
+ call NamingScreen_GetTextCursorPosition
+ ld [hl], NAMINGSCREEN_UNDERLINE
+ inc hl
+ ld [hl], "<NEXT>"
+ ret
+
+.finished
+ call NamingScreen_StoreEntry
+ ld hl, wJumptableIndex
+ set 7, [hl]
+ ret
+
+.select
+ ld hl, wNamingScreenLetterCase
+ ld a, [hl]
+ xor 1
+ ld [hl], a
+ jr nz, .switch_to_lowercase
+ ld de, MailEntry_Uppercase
+ call .PlaceMailCharset
+ ret
+
+.switch_to_lowercase
+ ld de, MailEntry_Lowercase
+ call .PlaceMailCharset
+ ret
+
+; called from engine/sprite_anims.asm
+
+ComposeMail_AnimateCursor: ; 120c1 (4:60c1)
+ call .GetDPad
+ ld hl, SPRITEANIMSTRUCT_0D
+ add hl, bc
+ ld a, [hl]
+ ld e, a
+ swap e
+ ld hl, SPRITEANIMSTRUCT_YOFFSET
+ add hl, bc
+ ld [hl], e
+ cp $5
+ ld de, .LetterEntries
+ ld a, 0
+ jr nz, .got_pointer
+ ld de, .CaseDelEnd
+ ld a, 1
+.got_pointer
+ ld hl, SPRITEANIMSTRUCT_0E
+ add hl, bc
+ add [hl]
+ ld hl, SPRITEANIMSTRUCT_FRAMESET_ID
+ add hl, bc
+ ld [hl], a
+ ld hl, SPRITEANIMSTRUCT_0C
+ add hl, bc
+ ld l, [hl]
+ ld h, 0
+ add hl, de
+ ld a, [hl]
+ ld hl, SPRITEANIMSTRUCT_XOFFSET
+ add hl, bc
+ ld [hl], a
+ ret
+
+; 120f8 (4:60f8)
+
+.LetterEntries: ; 120f8
+ db $00, $10, $20, $30, $40, $50, $60, $70, $80, $90
+
+.CaseDelEnd: ; 12102
+ db $00, $00, $00, $30, $30, $30, $60, $60, $60, $60
+
+; 1210c
+
+.GetDPad: ; 1210c (4:610c)
+ ld hl, hJoyLast
+ ld a, [hl]
+ and D_UP
+ jr nz, .up
+ ld a, [hl]
+ and D_DOWN
+ jr nz, .down
+ ld a, [hl]
+ and D_LEFT
+ jr nz, .left
+ ld a, [hl]
+ and D_RIGHT
+ jr nz, .right
+ ret
+
+.right
+ call ComposeMail_GetCursorPosition
+ and a
+ jr nz, .case_del_done_right
+ ld hl, SPRITEANIMSTRUCT_0C
+ add hl, bc
+ ld a, [hl]
+ cp $9
+ jr nc, .wrap_around_letter_right
+ inc [hl]
+ ret
+
+.wrap_around_letter_right
+ ld [hl], $0
+ ret
+
+.case_del_done_right
+ cp $3
+ jr nz, .wrap_around_command_right
+ xor a
+.wrap_around_command_right
+ ld e, a
+ add a
+ add e
+ ld hl, SPRITEANIMSTRUCT_0C
+ add hl, bc
+ ld [hl], a
+ ret
+
+.left
+ call ComposeMail_GetCursorPosition
+ and a
+ jr nz, .caps_del_done_left
+ ld hl, SPRITEANIMSTRUCT_0C
+ add hl, bc
+ ld a, [hl]
+ and a
+ jr z, .wrap_around_letter_left
+ dec [hl]
+ ret
+
+.wrap_around_letter_left
+ ld [hl], $9
+ ret
+
+.caps_del_done_left
+ cp $1
+ jr nz, .wrap_around_command_left
+ ld a, $4
+.wrap_around_command_left
+ dec a
+ dec a
+ ld e, a
+ add a
+ add e
+ ld hl, SPRITEANIMSTRUCT_0C
+ add hl, bc
+ ld [hl], a
+ ret
+
+.down
+ ld hl, SPRITEANIMSTRUCT_0D
+ add hl, bc
+ ld a, [hl]
+ cp $5
+ jr nc, .wrap_around_down
+ inc [hl]
+ ret
+
+.wrap_around_down
+ ld [hl], $0
+ ret
+
+.up
+ ld hl, SPRITEANIMSTRUCT_0D
+ add hl, bc
+ ld a, [hl]
+ and a
+ jr z, .wrap_around_up
+ dec [hl]
+ ret
+
+.wrap_around_up
+ ld [hl], $5
+ ret
+
+NamingScreen_PressedA_GetCursorCommand: ; 12185 (4:6185)
+ ld hl, wNamingScreenCursorObjectPointer
+ ld c, [hl]
+ inc hl
+ ld b, [hl]
+
+ComposeMail_GetCursorPosition: ; 1218b (4:618b)
+ ld hl, SPRITEANIMSTRUCT_0D
+ add hl, bc
+ ld a, [hl]
+ cp $5
+ jr nz, .letter
+ ld hl, SPRITEANIMSTRUCT_0C
+ add hl, bc
+ ld a, [hl]
+ cp $3
+ jr c, .case
+ cp $6
+ jr c, .del
+ ld a, $3
+ ret
+
+.case
+ ld a, $1
+ ret
+
+.del
+ ld a, $2
+ ret
+
+.letter
+ xor a
+ ret
+
+MailComposition_TryAddLastCharacter: ; 121ac (4:61ac)
+ ld a, [wNamingScreenLastCharacter]
+ jp MailComposition_TryAddCharacter
+
+; 121b2 (4:61b2)
+
+; unused
+ ld a, [wNamingScreenCurrNameLength]
+ and a
+ ret z
+ cp $11
+ jr nz, .asm_121c3
+ push hl
+ ld hl, wNamingScreenCurrNameLength
+ dec [hl]
+ dec [hl]
+ jr .asm_121c8
+
+.asm_121c3
+ push hl
+ ld hl, wNamingScreenCurrNameLength
+ dec [hl]
+
+.asm_121c8
+ call NamingScreen_GetTextCursorPosition
+ ld c, [hl]
+ pop hl
+.asm_121cd
+ ld a, [hli]
+ cp $ff
+ jp z, NamingScreen_AdvanceCursor_CheckEndOfString
+ cp c
+ jr z, .asm_121d9
+ inc hl
+ jr .asm_121cd
+
+.asm_121d9
+ ld a, [hl]
+ jp NamingScreen_LoadNextCharacter
+
+; 121dd
+
+INCLUDE "data/text/mail_input_chars.asm"
+
+; 122c1
diff --git a/engine/menus/options_menu.asm b/engine/menus/options_menu.asm
new file mode 100755
index 000000000..c0a255cb0
--- /dev/null
+++ b/engine/menus/options_menu.asm
@@ -0,0 +1,583 @@
+_OptionsMenu: ; e41d0
+ ld hl, hInMenu
+ ld a, [hl]
+ push af
+ ld [hl], $1
+ call ClearBGPalettes
+ hlcoord 0, 0
+ ld b, 16
+ ld c, 18
+ call TextBox
+ hlcoord 2, 2
+ ld de, StringOptions
+ call PlaceString
+ xor a
+ ld [wJumptableIndex], a
+ ld c, $6 ; number of items on the menu minus 1 (for cancel)
+
+.print_text_loop ; this next will display the settings of each option when the menu is opened
+ push bc
+ xor a
+ ld [hJoyLast], a
+ call GetOptionPointer
+ pop bc
+ ld hl, wJumptableIndex
+ inc [hl]
+ dec c
+ jr nz, .print_text_loop
+
+ call UpdateFrame
+ xor a
+ ld [wJumptableIndex], a
+ inc a
+ ld [hBGMapMode], a
+ call WaitBGMap
+ ld b, SCGB_DIPLOMA
+ call GetSGBLayout
+ call SetPalettes
+
+.joypad_loop
+ call JoyTextDelay
+ ld a, [hJoyPressed]
+ and START | B_BUTTON
+ jr nz, .ExitOptions
+ call OptionsControl
+ jr c, .dpad
+ call GetOptionPointer
+ jr c, .ExitOptions
+
+.dpad
+ call Options_UpdateCursorPosition
+ ld c, 3
+ call DelayFrames
+ jr .joypad_loop
+
+.ExitOptions:
+ ld de, SFX_TRANSACTION
+ call PlaySFX
+ call WaitSFX
+ pop af
+ ld [hInMenu], a
+ ret
+; e4241
+
+StringOptions: ; e4241
+ db "TEXT SPEED<LNBRK>"
+ db " :<LNBRK>"
+ db "BATTLE SCENE<LNBRK>"
+ db " :<LNBRK>"
+ db "BATTLE STYLE<LNBRK>"
+ db " :<LNBRK>"
+ db "SOUND<LNBRK>"
+ db " :<LNBRK>"
+ db "PRINT<LNBRK>"
+ db " :<LNBRK>"
+ db "MENU ACCOUNT<LNBRK>"
+ db " :<LNBRK>"
+ db "FRAME<LNBRK>"
+ db " :TYPE<LNBRK>"
+ db "CANCEL@"
+; e42d6
+
+
+GetOptionPointer: ; e42d6
+ ld a, [wJumptableIndex] ; load the cursor position to a
+ ld e, a ; copy it to de
+ ld d, 0
+ ld hl, .Pointers
+ add hl, de
+ add hl, de
+ ld a, [hli]
+ ld h, [hl]
+ ld l, a
+ jp hl ; jump to the code of the current highlighted item
+; e42e5
+
+.Pointers:
+ dw Options_TextSpeed
+ dw Options_BattleScene
+ dw Options_BattleStyle
+ dw Options_Sound
+ dw Options_Print
+ dw Options_MenuAccount
+ dw Options_Frame
+ dw Options_Cancel
+; e42f5
+
+
+ const_def
+ const OPT_TEXT_SPEED_FAST ; 0
+ const OPT_TEXT_SPEED_MED ; 1
+ const OPT_TEXT_SPEED_SLOW ; 2
+
+Options_TextSpeed: ; e42f5
+ call GetTextSpeed
+ ld a, [hJoyPressed]
+ bit D_LEFT_F, a
+ jr nz, .LeftPressed
+ bit D_RIGHT_F, a
+ jr z, .NonePressed
+ ld a, c ; right pressed
+ cp OPT_TEXT_SPEED_SLOW
+ jr c, .Increase
+ ld c, OPT_TEXT_SPEED_FAST + -1
+
+.Increase:
+ inc c
+ ld a, e
+ jr .Save
+
+.LeftPressed:
+ ld a, c
+ and a
+ jr nz, .Decrease
+ ld c, OPT_TEXT_SPEED_SLOW + 1
+
+.Decrease:
+ dec c
+ ld a, d
+
+.Save:
+ ld b, a
+ ld a, [wOptions]
+ and $f0
+ or b
+ ld [wOptions], a
+
+.NonePressed:
+ ld b, 0
+ ld hl, .Strings
+ add hl, bc
+ add hl, bc
+ ld e, [hl]
+ inc hl
+ ld d, [hl]
+ hlcoord 11, 3
+ call PlaceString
+ and a
+ ret
+; e4331
+
+.Strings:
+; entries correspond to OPT_TEXT_SPEED_* constants
+ dw .Fast
+ dw .Mid
+ dw .Slow
+
+.Fast: db "FAST@"
+.Mid: db "MID @"
+.Slow: db "SLOW@"
+; e4346
+
+
+GetTextSpeed: ; e4346
+; converts TEXT_DELAY_* value in a to OPT_TEXT_SPEED_* value in c,
+; with previous/next TEXT_DELAY_* values in d/e
+ ld a, [wOptions]
+ and $7
+ cp TEXT_DELAY_SLOW
+ jr z, .slow
+ cp TEXT_DELAY_FAST
+ jr z, .fast
+ ; none of the above
+ ld c, OPT_TEXT_SPEED_MED
+ lb de, TEXT_DELAY_FAST, TEXT_DELAY_SLOW
+ ret
+
+.slow
+ ld c, OPT_TEXT_SPEED_SLOW
+ lb de, TEXT_DELAY_MED, TEXT_DELAY_FAST
+ ret
+
+.fast
+ ld c, OPT_TEXT_SPEED_FAST
+ lb de, TEXT_DELAY_SLOW, TEXT_DELAY_MED
+ ret
+; e4365
+
+
+Options_BattleScene: ; e4365
+ ld hl, wOptions
+ ld a, [hJoyPressed]
+ bit D_LEFT_F, a
+ jr nz, .LeftPressed
+ bit D_RIGHT_F, a
+ jr z, .NonePressed
+ bit BATTLE_SCENE, [hl]
+ jr nz, .ToggleOn
+ jr .ToggleOff
+
+.LeftPressed:
+ bit BATTLE_SCENE, [hl]
+ jr z, .ToggleOff
+ jr .ToggleOn
+
+.NonePressed:
+ bit BATTLE_SCENE, [hl]
+ jr z, .ToggleOn
+ jr .ToggleOff
+
+.ToggleOn:
+ res BATTLE_SCENE, [hl]
+ ld de, .On
+ jr .Display
+
+.ToggleOff:
+ set BATTLE_SCENE, [hl]
+ ld de, .Off
+
+.Display:
+ hlcoord 11, 5
+ call PlaceString
+ and a
+ ret
+; e4398
+
+.On: db "ON @"
+.Off: db "OFF@"
+; e43a0
+
+
+Options_BattleStyle: ; e43a0
+ ld hl, wOptions
+ ld a, [hJoyPressed]
+ bit D_LEFT_F, a
+ jr nz, .LeftPressed
+ bit D_RIGHT_F, a
+ jr z, .NonePressed
+ bit BATTLE_SHIFT, [hl]
+ jr nz, .ToggleShift
+ jr .ToggleSet
+
+.LeftPressed:
+ bit BATTLE_SHIFT, [hl]
+ jr z, .ToggleSet
+ jr .ToggleShift
+
+.NonePressed:
+ bit BATTLE_SHIFT, [hl]
+ jr nz, .ToggleSet
+
+.ToggleShift:
+ res BATTLE_SHIFT, [hl]
+ ld de, .Shift
+ jr .Display
+
+.ToggleSet:
+ set BATTLE_SHIFT, [hl]
+ ld de, .Set
+
+.Display:
+ hlcoord 11, 7
+ call PlaceString
+ and a
+ ret
+; e43d1
+
+.Shift: db "SHIFT@"
+.Set: db "SET @"
+; e43dd
+
+
+Options_Sound: ; e43dd
+ ld hl, wOptions
+ ld a, [hJoyPressed]
+ bit D_LEFT_F, a
+ jr nz, .LeftPressed
+ bit D_RIGHT_F, a
+ jr z, .NonePressed
+ bit STEREO, [hl]
+ jr nz, .SetMono
+ jr .SetStereo
+
+.LeftPressed:
+ bit STEREO, [hl]
+ jr z, .SetStereo
+ jr .SetMono
+
+.NonePressed:
+ bit STEREO, [hl]
+ jr nz, .ToggleStereo
+ jr .ToggleMono
+
+.SetMono:
+ res STEREO, [hl]
+ call RestartMapMusic
+
+.ToggleMono:
+ ld de, .Mono
+ jr .Display
+
+.SetStereo:
+ set STEREO, [hl]
+ call RestartMapMusic
+
+.ToggleStereo:
+ ld de, .Stereo
+
+.Display:
+ hlcoord 11, 9
+ call PlaceString
+ and a
+ ret
+; e4416
+
+.Mono: db "MONO @"
+.Stereo: db "STEREO@"
+; e4424
+
+
+ const_def
+ const OPT_PRINT_LIGHTEST ; 0
+ const OPT_PRINT_LIGHTER ; 1
+ const OPT_PRINT_NORMAL ; 2
+ const OPT_PRINT_DARKER ; 3
+ const OPT_PRINT_DARKEST ; 4
+
+Options_Print: ; e4424
+ call GetPrinterSetting
+ ld a, [hJoyPressed]
+ bit D_LEFT_F, a
+ jr nz, .LeftPressed
+ bit D_RIGHT_F, a
+ jr z, .NonePressed
+ ld a, c
+ cp OPT_PRINT_DARKEST
+ jr c, .Increase
+ ld c, OPT_PRINT_LIGHTEST - 1
+
+.Increase:
+ inc c
+ ld a, e
+ jr .Save
+
+.LeftPressed:
+ ld a, c
+ and a
+ jr nz, .Decrease
+ ld c, OPT_PRINT_DARKEST + 1
+
+.Decrease:
+ dec c
+ ld a, d
+
+.Save:
+ ld b, a
+ ld [wGBPrinter], a
+
+.NonePressed:
+ ld b, $0
+ ld hl, .Strings
+ add hl, bc
+ add hl, bc
+ ld e, [hl]
+ inc hl
+ ld d, [hl]
+ hlcoord 11, 11
+ call PlaceString
+ and a
+ ret
+; e445a
+
+.Strings:
+; entries correspond to OPT_PRINT_* constants
+ dw .Lightest
+ dw .Lighter
+ dw .Normal
+ dw .Darker
+ dw .Darkest
+
+.Lightest: db "LIGHTEST@"
+.Lighter: db "LIGHTER @"
+.Normal: db "NORMAL @"
+.Darker: db "DARKER @"
+.Darkest: db "DARKEST @"
+; e4491
+
+
+GetPrinterSetting: ; e4491
+; converts GBPRINTER_* value in a to OPT_PRINT_* value in c,
+; with previous/next GBPRINTER_* values in d/e
+ ld a, [wGBPrinter]
+ and a
+ jr z, .IsLightest
+ cp GBPRINTER_LIGHTER
+ jr z, .IsLight
+ cp GBPRINTER_DARKER
+ jr z, .IsDark
+ cp GBPRINTER_DARKEST
+ jr z, .IsDarkest
+ ; none of the above
+ ld c, OPT_PRINT_NORMAL
+ lb de, GBPRINTER_LIGHTER, GBPRINTER_DARKER
+ ret
+
+.IsLightest:
+ ld c, OPT_PRINT_LIGHTEST
+ lb de, GBPRINTER_DARKEST, GBPRINTER_LIGHTER
+ ret
+
+.IsLight:
+ ld c, OPT_PRINT_LIGHTER
+ lb de, GBPRINTER_LIGHTEST, GBPRINTER_NORMAL
+ ret
+
+.IsDark:
+ ld c, OPT_PRINT_DARKER
+ lb de, GBPRINTER_NORMAL, GBPRINTER_DARKEST
+ ret
+
+.IsDarkest:
+ ld c, OPT_PRINT_DARKEST
+ lb de, GBPRINTER_DARKER, GBPRINTER_LIGHTEST
+ ret
+; e44c1
+
+Options_MenuAccount: ; e44c1
+ ld hl, wOptions2
+ ld a, [hJoyPressed]
+ bit D_LEFT_F, a
+ jr nz, .LeftPressed
+ bit D_RIGHT_F, a
+ jr z, .NonePressed
+ bit MENU_ACCOUNT, [hl]
+ jr nz, .ToggleOff
+ jr .ToggleOn
+
+.LeftPressed:
+ bit MENU_ACCOUNT, [hl]
+ jr z, .ToggleOn
+ jr .ToggleOff
+
+.NonePressed:
+ bit MENU_ACCOUNT, [hl]
+ jr nz, .ToggleOn
+
+.ToggleOff:
+ res MENU_ACCOUNT, [hl]
+ ld de, .Off
+ jr .Display
+
+.ToggleOn:
+ set MENU_ACCOUNT, [hl]
+ ld de, .On
+
+.Display:
+ hlcoord 11, 13
+ call PlaceString
+ and a
+ ret
+; e44f2
+
+.Off: db "OFF@"
+.On: db "ON @"
+; e44fa
+
+
+Options_Frame: ; e44fa
+ ld hl, wTextBoxFrame
+ ld a, [hJoyPressed]
+ bit D_LEFT_F, a
+ jr nz, .LeftPressed
+ bit D_RIGHT_F, a
+ jr nz, .RightPressed
+ and a
+ ret
+
+.RightPressed:
+ ld a, [hl]
+ inc a
+ jr .Save
+
+.LeftPressed:
+ ld a, [hl]
+ dec a
+
+.Save:
+ and $7
+ ld [hl], a
+UpdateFrame: ; e4512
+ ld a, [wTextBoxFrame]
+ hlcoord 16, 15 ; where on the screen the number is drawn
+ add "1"
+ ld [hl], a
+ call LoadFontsExtra
+ and a
+ ret
+; e4520
+
+Options_Cancel: ; e4520
+ ld a, [hJoyPressed]
+ and A_BUTTON
+ jr nz, .Exit
+ and a
+ ret
+
+.Exit:
+ scf
+ ret
+; e452a
+
+OptionsControl: ; e452a
+ ld hl, wJumptableIndex
+ ld a, [hJoyLast]
+ cp D_DOWN
+ jr z, .DownPressed
+ cp D_UP
+ jr z, .UpPressed
+ and a
+ ret
+
+.DownPressed:
+ ld a, [hl] ; load the cursor position to a
+ cp $7 ; maximum number of items in option menu
+ jr nz, .CheckFive
+ ld [hl], $0
+ scf
+ ret
+
+.CheckFive: ; I have no idea why this exists...
+ cp $5
+ jr nz, .Increase
+ ld [hl], $5
+
+.Increase:
+ inc [hl]
+ scf
+ ret
+
+.UpPressed:
+ ld a, [hl]
+ cp $6
+ jr nz, .NotSix
+ ld [hl], $5 ; Another thing where I'm not sure why it exists
+ scf
+ ret
+
+.NotSix:
+ and a
+ jr nz, .Decrease
+ ld [hl], $8 ; number of option items +1
+
+.Decrease:
+ dec [hl]
+ scf
+ ret
+; e455c
+
+Options_UpdateCursorPosition: ; e455c
+ hlcoord 1, 1
+ ld de, SCREEN_WIDTH
+ ld c, $10
+.loop
+ ld [hl], " "
+ add hl, de
+ dec c
+ jr nz, .loop
+ hlcoord 1, 2
+ ld bc, 2 * SCREEN_WIDTH
+ ld a, [wJumptableIndex]
+ call AddNTimes
+ ld [hl], "▶"
+ ret
+; e4579
diff --git a/engine/menus/scrolling_menu.asm b/engine/menus/scrolling_menu.asm
new file mode 100755
index 000000000..3be3d839c
--- /dev/null
+++ b/engine/menus/scrolling_menu.asm
@@ -0,0 +1,543 @@
+_InitScrollingMenu:: ; 245af
+ xor a
+ ld [wMenuJoypad], a
+ ld [hBGMapMode], a
+ inc a
+ ld [hInMenu], a
+ call InitScrollingMenuCursor
+ call ScrollingMenu_InitFlags
+ call ScrollingMenu_ValidateSwitchItem
+ call ScrollingMenu_InitDisplay
+ call ApplyTilemap
+ xor a
+ ld [hBGMapMode], a
+ ret
+; 245cb
+
+_ScrollingMenu:: ; 245cb
+.loop
+ call ScrollingMenuJoyAction
+ jp c, .exit
+ call z, .zero
+ jr .loop
+; 245d6
+
+.exit ; 245d6
+ call MenuClickSound
+ ld [wMenuJoypad], a
+ ld a, 0
+ ld [hInMenu], a
+ ret
+; 245e1
+
+.zero ; 245e1
+ call ScrollingMenu_InitDisplay
+ ld a, 1
+ ld [hBGMapMode], a
+ ld c, 3
+ call DelayFrames
+ xor a
+ ld [hBGMapMode], a
+ ret
+; 245f1
+
+ScrollingMenu_InitDisplay: ; 245f1
+ xor a
+ ld [hBGMapMode], a
+ ld hl, wOptions
+ ld a, [hl]
+ push af
+ set NO_TEXT_SCROLL, [hl]
+ call ScrollingMenu_UpdateDisplay
+ call ScrollingMenu_PlaceCursor
+ call ScrollingMenu_CheckCallFunction3
+ pop af
+ ld [wOptions], a
+ ret
+; 24609
+
+ScrollingMenuJoyAction: ; 24609
+.loop
+ call ScrollingMenuJoypad
+ ld a, [hJoyLast]
+ and D_PAD
+ ld b, a
+ ld a, [hJoyPressed]
+ and BUTTONS
+ or b
+ bit A_BUTTON_F, a
+ jp nz, .a_button
+ bit B_BUTTON_F, a
+ jp nz, .b_button
+ bit SELECT_F, a
+ jp nz, .select
+ bit START_F, a
+ jp nz, .start
+ bit D_RIGHT_F, a
+ jp nz, .d_right
+ bit D_LEFT_F, a
+ jp nz, .d_left
+ bit D_UP_F, a
+ jp nz, .d_up
+ bit D_DOWN_F, a
+ jp nz, .d_down
+ jr .loop
+; 24640
+
+.unreferenced ; unused
+ ld a, -1
+ and a
+ ret
+; 24644
+
+.a_button ; 24644
+ call PlaceHollowCursor
+ ld a, [wMenuCursorY]
+ dec a
+ call ScrollingMenu_GetListItemCoordAndFunctionArgs
+ ld a, [wMenuSelection]
+ ld [wCurItem], a
+ ld a, [wMenuSelectionQuantity]
+ ld [wItemQuantityBuffer], a
+ call ScrollingMenu_GetCursorPosition
+ dec a
+ ld [wScrollingMenuCursorPosition], a
+ ld [wCurItemQuantity], a
+ ld a, [wMenuSelection]
+ cp -1
+ jr z, .b_button
+ ld a, A_BUTTON
+ scf
+ ret
+; 2466f
+
+.b_button ; 2466f
+ ld a, B_BUTTON
+ scf
+ ret
+; 24673
+
+.select ; 24673
+ ld a, [wMenuDataFlags]
+ bit 7, a
+ jp z, xor_a_dec_a
+ ld a, [wMenuCursorY]
+ dec a
+ call ScrollingMenu_GetListItemCoordAndFunctionArgs
+ ld a, [wMenuSelection]
+ cp -1
+ jp z, xor_a_dec_a
+ call ScrollingMenu_GetCursorPosition
+ dec a
+ ld [wScrollingMenuCursorPosition], a
+ ld a, SELECT
+ scf
+ ret
+; 24695
+
+.start ; 24695
+ ld a, [wMenuDataFlags]
+ bit 6, a
+ jp z, xor_a_dec_a
+ ld a, START
+ scf
+ ret
+; 246a1
+
+.d_left ; 246a1
+ ld hl, w2DMenuFlags2
+ bit 7, [hl]
+ jp z, xor_a_dec_a
+ ld a, [wMenuDataFlags]
+ bit 3, a
+ jp z, xor_a_dec_a
+ ld a, D_LEFT
+ scf
+ ret
+; 246b5
+
+.d_right ; 246b5
+ ld hl, w2DMenuFlags2
+ bit 7, [hl]
+ jp z, xor_a_dec_a
+ ld a, [wMenuDataFlags]
+ bit 2, a
+ jp z, xor_a_dec_a
+ ld a, D_RIGHT
+ scf
+ ret
+; 246c9
+
+.d_up ; 246c9
+ ld hl, w2DMenuFlags2
+ bit 7, [hl]
+ jp z, xor_a
+ ld hl, wMenuScrollPosition
+ ld a, [hl]
+ and a
+ jr z, .xor_dec_up
+ dec [hl]
+ jp xor_a
+
+.xor_dec_up
+ jp xor_a_dec_a
+; 246df
+
+.d_down ; 246df
+ ld hl, w2DMenuFlags2
+ bit 7, [hl]
+ jp z, xor_a
+ ld hl, wMenuScrollPosition
+ ld a, [wMenuData_ScrollingMenuHeight]
+ add [hl]
+ ld b, a
+ ld a, [wScrollingMenuListSize]
+ cp b
+ jr c, .xor_dec_down
+ inc [hl]
+ jp xor_a
+
+.xor_dec_down
+ jp xor_a_dec_a
+; 246fc
+
+ScrollingMenu_GetCursorPosition: ; 246fc
+ ld a, [wMenuScrollPosition]
+ ld c, a
+ ld a, [wMenuCursorY]
+ add c
+ ld c, a
+ ret
+; 24706
+
+ScrollingMenu_ClearLeftColumn: ; 24706 (9:4706)
+ call MenuBoxCoord2Tile
+ ld de, SCREEN_WIDTH
+ add hl, de
+ ld de, 2 * SCREEN_WIDTH
+ ld a, [wMenuData_ScrollingMenuHeight]
+.loop
+ ld [hl], " "
+ add hl, de
+ dec a
+ jr nz, .loop
+ ret
+
+InitScrollingMenuCursor: ; 2471a
+ ld hl, wMenuData_ItemsPointerAddr
+ ld a, [hli]
+ ld h, [hl]
+ ld l, a
+ ld a, [wMenuData_ItemsPointerBank]
+ call GetFarByte
+ ld [wScrollingMenuListSize], a
+ ld a, [wMenuData_ScrollingMenuHeight]
+ ld c, a
+ ld a, [wMenuScrollPosition]
+ add c
+ ld c, a
+ ld a, [wScrollingMenuListSize]
+ inc a
+ cp c
+ jr nc, .skip
+ ld a, [wMenuData_ScrollingMenuHeight]
+ ld c, a
+ ld a, [wScrollingMenuListSize]
+ inc a
+ sub c
+ jr nc, .store
+ xor a
+
+.store
+ ld [wMenuScrollPosition], a
+
+.skip
+ ld a, [wMenuScrollPosition]
+ ld c, a
+ ld a, [wMenuCursorBuffer]
+ add c
+ ld b, a
+ ld a, [wScrollingMenuListSize]
+ inc a
+ cp b
+ jr c, .asm_2475a
+ jr nc, .asm_24763
+
+.asm_2475a
+ xor a
+ ld [wMenuScrollPosition], a
+ ld a, $1
+ ld [wMenuCursorBuffer], a
+
+.asm_24763
+ ret
+; 24764
+
+ScrollingMenu_InitFlags: ; 24764
+ ld a, [wMenuDataFlags]
+ ld c, a
+ ld a, [wScrollingMenuListSize]
+ ld b, a
+ ld a, [wMenuBorderTopCoord]
+ add 1
+ ld [w2DMenuCursorInitY], a
+ ld a, [wMenuBorderLeftCoord]
+ add 0
+ ld [w2DMenuCursorInitX], a
+ ld a, [wMenuData_ScrollingMenuHeight]
+ cp b
+ jr c, .no_extra_row
+ jr z, .no_extra_row
+ ld a, b
+ inc a
+.no_extra_row
+ ld [w2DMenuNumRows], a
+ ld a, 1
+ ld [w2DMenuNumCols], a
+ ld a, $8c
+ bit 2, c
+ jr z, .skip_set_0
+ set 0, a
+
+.skip_set_0
+ bit 3, c
+ jr z, .skip_set_1
+ set 1, a
+
+.skip_set_1
+ ld [w2DMenuFlags1], a
+ xor a
+ ld [w2DMenuFlags2], a
+ ld a, $20
+ ld [w2DMenuCursorOffsets], a
+ ld a, A_BUTTON | B_BUTTON | D_UP | D_DOWN
+ bit 7, c
+ jr z, .disallow_select
+ add SELECT
+
+.disallow_select
+ bit 6, c
+ jr z, .disallow_start
+ add START
+
+.disallow_start
+ ld [wMenuJoypadFilter], a
+ ld a, [w2DMenuNumRows]
+ ld b, a
+ ld a, [wMenuCursorBuffer]
+ and a
+ jr z, .reset_cursor
+ cp b
+ jr z, .cursor_okay
+ jr c, .cursor_okay
+
+.reset_cursor
+ ld a, 1
+
+.cursor_okay
+ ld [wMenuCursorY], a
+ ld a, 1
+ ld [wMenuCursorX], a
+ xor a
+ ld [wCursorCurrentTile], a
+ ld [wCursorCurrentTile + 1], a
+ ld [wCursorOffCharacter], a
+ ret
+; 247dd
+
+ScrollingMenu_ValidateSwitchItem: ; 247dd
+ ld a, [wScrollingMenuListSize]
+ ld c, a
+ ld a, [wSwitchItem]
+ and a
+ jr z, .done
+ dec a
+ cp c
+ jr c, .done
+ xor a
+ ld [wSwitchItem], a
+
+.done
+ ret
+; 247f0
+
+ScrollingMenu_UpdateDisplay: ; 247f0
+ call ClearWholeMenuBox
+ ld a, [wMenuDataFlags]
+ bit 4, a ; place arrows
+ jr z, .okay
+ ld a, [wMenuScrollPosition]
+ and a
+ jr z, .okay
+ ld a, [wMenuBorderTopCoord]
+ ld b, a
+ ld a, [wMenuBorderRightCoord]
+ ld c, a
+ call Coord2Tile
+ ld [hl], "▲"
+
+.okay
+ call MenuBoxCoord2Tile
+ ld bc, SCREEN_WIDTH + 1
+ add hl, bc
+ ld a, [wMenuData_ScrollingMenuHeight]
+ ld b, a
+ ld c, $0
+.loop
+ ld a, [wMenuScrollPosition]
+ add c
+ ld [wScrollingMenuCursorPosition], a
+ ld a, c
+ call ScrollingMenu_GetListItemCoordAndFunctionArgs
+ ld a, [wMenuSelection]
+ cp -1
+ jr z, .cancel
+ push bc
+ push hl
+ call ScrollingMenu_CallFunctions1and2
+ pop hl
+ ld bc, 2 * SCREEN_WIDTH
+ add hl, bc
+ pop bc
+ inc c
+ ld a, c
+ cp b
+ jr nz, .loop
+ ld a, [wMenuDataFlags]
+ bit 4, a ; place arrows
+ jr z, .done
+ ld a, [wMenuBorderBottomCoord]
+ ld b, a
+ ld a, [wMenuBorderRightCoord]
+ ld c, a
+ call Coord2Tile
+ ld [hl], "▼"
+
+.done
+ ret
+
+.cancel
+ ld a, [wMenuDataFlags]
+ bit 0, a ; call function on cancel
+ jr nz, .call_function
+ ld de, .string_2485f
+ call PlaceString
+ ret
+
+.string_2485f
+ db "CANCEL@"
+
+.call_function
+ ld d, h
+ ld e, l
+ ld hl, wMenuData_ScrollingMenuFunction1
+ jp CallPointerAt
+; 2486e
+
+ScrollingMenu_CallFunctions1and2: ; 2486e
+ push hl
+ ld d, h
+ ld e, l
+ ld hl, wMenuData_ScrollingMenuFunction1
+ call CallPointerAt
+ pop hl
+ ld a, [wMenuData_ScrollingMenuWidth]
+ and a
+ jr z, .done
+ ld e, a
+ ld d, $0
+ add hl, de
+ ld d, h
+ ld e, l
+ ld hl, wMenuData_ScrollingMenuFunction2
+ call CallPointerAt
+
+.done
+ ret
+; 2488b
+
+ScrollingMenu_PlaceCursor: ; 2488b
+ ld a, [wSwitchItem]
+ and a
+ jr z, .done
+ ld b, a
+ ld a, [wMenuScrollPosition]
+ cp b
+ jr nc, .done
+ ld c, a
+ ld a, [wMenuData_ScrollingMenuHeight]
+ add c
+ cp b
+ jr c, .done
+ ld a, b
+ sub c
+ dec a
+ add a
+ add $1
+ ld c, a
+ ld a, [wMenuBorderTopCoord]
+ add c
+ ld b, a
+ ld a, [wMenuBorderLeftCoord]
+ add $0
+ ld c, a
+ call Coord2Tile
+ ld [hl], "▷"
+
+.done
+ ret
+; 248b8
+
+ScrollingMenu_CheckCallFunction3: ; 248b8
+ ld a, [wMenuDataFlags]
+ bit 5, a ; call function 3
+ ret z
+ bit 1, a ; call function 3 if not switching items
+ jr z, .call
+ ld a, [wSwitchItem]
+ and a
+ ret nz
+
+.call
+ ld a, [wMenuCursorY]
+ dec a
+ call ScrollingMenu_GetListItemCoordAndFunctionArgs
+ ld hl, wMenuData_ScrollingMenuFunction3
+ call CallPointerAt
+ ret
+; 248d5
+
+ScrollingMenu_GetListItemCoordAndFunctionArgs: ; 248d5
+ push de
+ push hl
+ ld e, a
+ ld a, [wMenuScrollPosition]
+ add e
+ ld e, a
+ ld d, $0
+ ld hl, wMenuData_ItemsPointerAddr
+ ld a, [hli]
+ ld h, [hl]
+ ld l, a
+ inc hl ; items
+ ld a, [wMenuData_ScrollingMenuSpacing]
+ cp 1
+ jr z, .got_spacing
+ cp 2
+ jr z, .pointless_jump
+.pointless_jump
+ add hl, de
+.got_spacing
+ add hl, de
+ ld a, [wMenuData_ItemsPointerBank]
+ call GetFarByte
+ ld [wMenuSelection], a
+ ld [wCurItem], a
+ inc hl
+ ld a, [wMenuData_ItemsPointerBank]
+ call GetFarByte
+ ld [wMenuSelectionQuantity], a
+ pop hl
+ pop de
+ ret
+; 2490c
diff --git a/engine/menus/start_menu.asm b/engine/menus/start_menu.asm
new file mode 100755
index 000000000..037efd947
--- /dev/null
+++ b/engine/menus/start_menu.asm
@@ -0,0 +1,1993 @@
+; StartMenu.Items indexes
+ const_def
+ const STARTMENUITEM_POKEDEX ; 0
+ const STARTMENUITEM_POKEMON ; 1
+ const STARTMENUITEM_PACK ; 2
+ const STARTMENUITEM_STATUS ; 3
+ const STARTMENUITEM_SAVE ; 4
+ const STARTMENUITEM_OPTION ; 5
+ const STARTMENUITEM_EXIT ; 6
+ const STARTMENUITEM_POKEGEAR ; 7
+ const STARTMENUITEM_QUIT ; 8
+
+
+StartMenu:: ; 125cd
+
+ call ClearWindowData
+
+ ld de, SFX_MENU
+ call PlaySFX
+
+ farcall ReanchorBGMap_NoOAMUpdate
+
+ ld hl, wStatusFlags2
+ bit STATUSFLAGS2_BUG_CONTEST_TIMER_F, [hl]
+ ld hl, .MenuHeader
+ jr z, .GotMenuData
+ ld hl, .ContestMenuHeader
+.GotMenuData:
+
+ call LoadMenuHeader
+ call .SetUpMenuItems
+ ld a, [wBattleMenuCursorBuffer]
+ ld [wMenuCursorBuffer], a
+ call .DrawMenuAccount_
+ call DrawVariableLengthMenuBox
+ call .DrawBugContestStatusBox
+ call SafeUpdateSprites
+ call _OpenAndCloseMenu_HDMATransferTileMapAndAttrMap
+ farcall LoadFonts_NoOAMUpdate
+ call .DrawBugContestStatus
+ call UpdateTimePals
+ jr .Select
+
+.Reopen:
+ call UpdateSprites
+ call UpdateTimePals
+ call .SetUpMenuItems
+ ld a, [wBattleMenuCursorBuffer]
+ ld [wMenuCursorBuffer], a
+
+.Select:
+ call .GetInput
+ jr c, .Exit
+ call .DrawMenuAccount
+ ld a, [wMenuCursorBuffer]
+ ld [wBattleMenuCursorBuffer], a
+ call PlayClickSFX
+ call PlaceHollowCursor
+ call .OpenMenu
+
+; Menu items have different return functions.
+; For example, saving exits the menu.
+ ld hl, .MenuReturns
+ ld e, a
+ ld d, 0
+ add hl, de
+ add hl, de
+ ld a, [hli]
+ ld h, [hl]
+ ld l, a
+ jp hl
+
+.MenuReturns:
+ dw .Reopen
+ dw .Exit
+ dw .ExitMenuCallFuncCloseText
+ dw .ExitMenuRunScriptCloseText
+ dw .ExitMenuRunScript
+ dw .ReturnEnd
+ dw .ReturnRedraw
+
+.Exit:
+ ld a, [hOAMUpdate]
+ push af
+ ld a, 1
+ ld [hOAMUpdate], a
+ call LoadFontsExtra
+ pop af
+ ld [hOAMUpdate], a
+.ReturnEnd:
+ call ExitMenu
+.ReturnEnd2:
+ call CloseText
+ call UpdateTimePals
+ ret
+
+.GetInput:
+; Return carry on exit, and no-carry on selection.
+ xor a
+ ld [hBGMapMode], a
+ call .DrawMenuAccount
+ call SetUpMenu
+ ld a, $ff
+ ld [wMenuSelection], a
+.loop
+ call .PrintMenuAccount
+ call GetScrollingMenuJoypad
+ ld a, [wMenuJoypad]
+ cp B_BUTTON
+ jr z, .b
+ cp A_BUTTON
+ jr z, .a
+ jr .loop
+.a
+ call PlayClickSFX
+ and a
+ ret
+.b
+ scf
+ ret
+; 12691
+
+.ExitMenuRunScript: ; 12691
+ call ExitMenu
+ ld a, HMENURETURN_SCRIPT
+ ld [hMenuReturn], a
+ ret
+; 12699
+
+.ExitMenuRunScriptCloseText: ; 12699
+ call ExitMenu
+ ld a, HMENURETURN_SCRIPT
+ ld [hMenuReturn], a
+ jr .ReturnEnd2
+; 126a2
+
+.ExitMenuCallFuncCloseText: ; 126a2
+ call ExitMenu
+ ld hl, wQueuedScriptAddr
+ ld a, [hli]
+ ld h, [hl]
+ ld l, a
+ ld a, [wQueuedScriptBank]
+ rst FarCall
+ jr .ReturnEnd2
+; 126b1
+
+.ReturnRedraw: ; 126b1
+ call .Clear
+ jp .Reopen
+; 126b7
+
+.Clear: ; 126b7
+ call ClearBGPalettes
+ call Call_ExitMenu
+ call ReloadTilesetAndPalettes
+ call .DrawMenuAccount_
+ call DrawVariableLengthMenuBox
+ call .DrawBugContestStatus
+ call UpdateSprites
+ call ret_d90
+ call FinishExitMenu
+ ret
+; 126d3
+
+
+.MenuHeader:
+ db MENU_BACKUP_TILES ; flags
+ menu_coords 10, 0, SCREEN_WIDTH - 1, SCREEN_HEIGHT - 1
+ dw .MenuData
+ db 1 ; default selection
+
+.ContestMenuHeader:
+ db MENU_BACKUP_TILES ; flags
+ menu_coords 10, 2, SCREEN_WIDTH - 1, SCREEN_HEIGHT - 1
+ dw .MenuData
+ db 1 ; default selection
+
+.MenuData:
+ db STATICMENU_CURSOR | STATICMENU_WRAP | STATICMENU_ENABLE_START ; flags
+ dn 0, 0 ; rows, columns
+ dw wMenuItemsList
+ dw .MenuString
+ dw .Items
+
+.Items:
+; entries correspond to STARTMENUITEM_* constants
+ dw StartMenu_Pokedex, .PokedexString, .PokedexDesc
+ dw StartMenu_Pokemon, .PartyString, .PartyDesc
+ dw StartMenu_Pack, .PackString, .PackDesc
+ dw StartMenu_Status, .StatusString, .StatusDesc
+ dw StartMenu_Save, .SaveString, .SaveDesc
+ dw StartMenu_Option, .OptionString, .OptionDesc
+ dw StartMenu_Exit, .ExitString, .ExitDesc
+ dw StartMenu_Pokegear, .PokegearString, .PokegearDesc
+ dw StartMenu_Quit, .QuitString, .QuitDesc
+
+.PokedexString: db "#DEX@"
+.PartyString: db "#MON@"
+.PackString: db "PACK@"
+.StatusString: db "<PLAYER>@"
+.SaveString: db "SAVE@"
+.OptionString: db "OPTION@"
+.ExitString: db "EXIT@"
+.PokegearString: db "<POKE>GEAR@"
+.QuitString: db "QUIT@"
+
+.PokedexDesc:
+ db "#MON"
+ next "database@"
+
+.PartyDesc:
+ db "Party <PKMN>"
+ next "status@"
+
+.PackDesc:
+ db "Contains"
+ next "items@"
+
+.PokegearDesc:
+ db "Trainer's"
+ next "key device@"
+
+.StatusDesc:
+ db "Your own"
+ next "status@"
+
+.SaveDesc:
+ db "Save your"
+ next "progress@"
+
+.OptionDesc:
+ db "Change"
+ next "settings@"
+
+.ExitDesc:
+ db "Close this"
+ next "menu@"
+
+.QuitDesc:
+ db "Quit and"
+ next "be judged.@"
+
+
+.OpenMenu: ; 127e5
+ ld a, [wMenuSelection]
+ call .GetMenuAccountTextPointer
+ ld a, [hli]
+ ld h, [hl]
+ ld l, a
+ jp hl
+; 127ef
+
+.MenuString: ; 127ef
+ push de
+ ld a, [wMenuSelection]
+ call .GetMenuAccountTextPointer
+ inc hl
+ inc hl
+ ld a, [hli]
+ ld d, [hl]
+ ld e, a
+ pop hl
+ call PlaceString
+ ret
+; 12800
+
+.MenuDesc: ; 12800
+ push de
+ ld a, [wMenuSelection]
+ cp $ff
+ jr z, .none
+ call .GetMenuAccountTextPointer
+rept 4
+ inc hl
+endr
+ ld a, [hli]
+ ld d, [hl]
+ ld e, a
+ pop hl
+ call PlaceString
+ ret
+.none
+ pop de
+ ret
+; 12819
+
+
+.GetMenuAccountTextPointer: ; 12819
+ ld e, a
+ ld d, 0
+ ld hl, wMenuDataPointerTableAddr
+ ld a, [hli]
+ ld h, [hl]
+ ld l, a
+rept 6
+ add hl, de
+endr
+ ret
+; 12829
+
+
+.SetUpMenuItems: ; 12829
+ xor a
+ ld [wWhichIndexSet], a
+ call .FillMenuList
+
+ ld hl, wStatusFlags
+ bit STATUSFLAGS_POKEDEX_F, [hl]
+ jr z, .no_pokedex
+ ld a, STARTMENUITEM_POKEDEX
+ call .AppendMenuList
+.no_pokedex
+
+ ld a, [wPartyCount]
+ and a
+ jr z, .no_pokemon
+ ld a, STARTMENUITEM_POKEMON
+ call .AppendMenuList
+.no_pokemon
+
+ ld a, [wLinkMode]
+ and a
+ jr nz, .no_pack
+ ld hl, wStatusFlags2
+ bit STATUSFLAGS2_BUG_CONTEST_TIMER_F, [hl]
+ jr nz, .no_pack
+ ld a, STARTMENUITEM_PACK
+ call .AppendMenuList
+.no_pack
+
+ ld hl, wPokegearFlags
+ bit POKEGEAR_OBTAINED_F, [hl]
+ jr z, .no_pokegear
+ ld a, STARTMENUITEM_POKEGEAR
+ call .AppendMenuList
+.no_pokegear
+
+ ld a, STARTMENUITEM_STATUS
+ call .AppendMenuList
+
+ ld a, [wLinkMode]
+ and a
+ jr nz, .no_save
+ ld hl, wStatusFlags2
+ bit STATUSFLAGS2_BUG_CONTEST_TIMER_F, [hl]
+ ld a, STARTMENUITEM_QUIT
+ jr nz, .write
+ ld a, STARTMENUITEM_SAVE
+.write
+ call .AppendMenuList
+.no_save
+
+ ld a, STARTMENUITEM_OPTION
+ call .AppendMenuList
+ ld a, STARTMENUITEM_EXIT
+ call .AppendMenuList
+ ld a, c
+ ld [wMenuItemsList], a
+ ret
+; 1288d
+
+
+.FillMenuList: ; 1288d
+ xor a
+ ld hl, wMenuItemsList
+ ld [hli], a
+ ld a, -1
+ ld bc, wMenuItemsListEnd - (wMenuItemsList + 1)
+ call ByteFill
+ ld de, wMenuItemsList + 1
+ ld c, 0
+ ret
+; 128a0
+
+.AppendMenuList: ; 128a0
+ ld [de], a
+ inc de
+ inc c
+ ret
+; 128a4
+
+.DrawMenuAccount_: ; 128a4
+ jp .DrawMenuAccount
+; 128a7
+
+.PrintMenuAccount: ; 128a7
+ call .IsMenuAccountOn
+ ret z
+ call .DrawMenuAccount
+ decoord 0, 14
+ jp .MenuDesc
+; 128b4
+
+.DrawMenuAccount: ; 128b4
+ call .IsMenuAccountOn
+ ret z
+ hlcoord 0, 13
+ lb bc, 5, 10
+ call ClearBox
+ hlcoord 0, 13
+ ld b, 3
+ ld c, 8
+ jp TextBoxPalette
+; 128cb
+
+.IsMenuAccountOn: ; 128cb
+ ld a, [wOptions2]
+ and 1 << MENU_ACCOUNT
+ ret
+; 128d1
+
+.DrawBugContestStatusBox: ; 128d1
+ ld hl, wStatusFlags2
+ bit STATUSFLAGS2_BUG_CONTEST_TIMER_F, [hl]
+ ret z
+ farcall StartMenu_DrawBugContestStatusBox
+ ret
+; 128de
+
+.DrawBugContestStatus: ; 128de
+ ld hl, wStatusFlags2
+ bit STATUSFLAGS2_BUG_CONTEST_TIMER_F, [hl]
+ jr nz, .contest
+ ret
+.contest
+ farcall StartMenu_PrintBugContestStatus
+ ret
+; 128ed
+
+
+StartMenu_Exit: ; 128ed
+; Exit the menu.
+
+ ld a, 1
+ ret
+; 128f0
+
+
+StartMenu_Quit: ; 128f0
+; Retire from the bug catching contest.
+
+ ld hl, .EndTheContestText
+ call StartMenuYesNo
+ jr c, .DontEndContest
+ ld a, BANK(BugCatchingContestReturnToGateScript)
+ ld hl, BugCatchingContestReturnToGateScript
+ call FarQueueScript
+ ld a, 4
+ ret
+
+.DontEndContest:
+ ld a, 0
+ ret
+
+.EndTheContestText:
+ text_jump UnknownText_0x1c1a6c
+ db "@"
+; 1290b
+
+
+StartMenu_Save: ; 1290b
+; Save the game.
+
+ call BufferScreen
+ farcall SaveMenu
+ jr nc, .asm_12919
+ ld a, 0
+ ret
+.asm_12919
+ ld a, 1
+ ret
+; 1291c
+
+
+StartMenu_Option: ; 1291c
+; Game options.
+
+ call FadeToMenu
+ farcall OptionsMenu
+ ld a, 6
+ ret
+; 12928
+
+
+StartMenu_Status: ; 12928
+; Player status.
+
+ call FadeToMenu
+ farcall TrainerCard
+ call CloseSubmenu
+ ld a, 0
+ ret
+; 12937
+
+
+StartMenu_Pokedex: ; 12937
+
+ ld a, [wPartyCount]
+ and a
+ jr z, .asm_12949
+
+ call FadeToMenu
+ farcall Pokedex
+ call CloseSubmenu
+
+.asm_12949
+ ld a, 0
+ ret
+; 1294c
+
+
+StartMenu_Pokegear: ; 1294c
+
+ call FadeToMenu
+ farcall PokeGear
+ call CloseSubmenu
+ ld a, 0
+ ret
+; 1295b
+
+
+StartMenu_Pack: ; 1295b
+
+ call FadeToMenu
+ farcall Pack
+ ld a, [wPackUsedItem]
+ and a
+ jr nz, .used_item
+ call CloseSubmenu
+ ld a, 0
+ ret
+
+.used_item
+ call ExitAllMenus
+ ld a, 4
+ ret
+; 12976
+
+
+StartMenu_Pokemon: ; 12976
+
+ ld a, [wPartyCount]
+ and a
+ jr z, .return
+
+ call FadeToMenu
+
+.choosemenu
+ xor a
+ ld [wPartyMenuActionText], a ; Choose a POKéMON.
+ call ClearBGPalettes
+
+.menu
+ farcall LoadPartyMenuGFX
+ farcall InitPartyMenuWithCancel
+ farcall InitPartyMenuGFX
+
+.menunoreload
+ farcall WritePartyMenuTilemap
+ farcall PrintPartyMenuText
+ call WaitBGMap
+ call SetPalettes ; load regular palettes?
+ call DelayFrame
+ farcall PartyMenuSelect
+ jr c, .return ; if cancelled or pressed B
+
+ call PokemonActionSubmenu
+ cp 3
+ jr z, .menu
+ cp 0
+ jr z, .choosemenu
+ cp 1
+ jr z, .menunoreload
+ cp 2
+ jr z, .quit
+
+.return
+ call CloseSubmenu
+ ld a, 0
+ ret
+
+.quit
+ ld a, b
+ push af
+ call ExitAllMenus
+ pop af
+ ret
+; 129d5
+
+HasNoItems: ; 129d5
+ ld a, [wNumItems]
+ and a
+ ret nz
+ ld a, [wNumKeyItems]
+ and a
+ ret nz
+ ld a, [wNumBalls]
+ and a
+ ret nz
+ ld hl, wTMsHMs
+ ld b, NUM_TMS + NUM_HMS
+.loop
+ ld a, [hli]
+ and a
+ jr nz, .done
+ dec b
+ jr nz, .loop
+ scf
+ ret
+.done
+ and a
+ ret
+
+TossItemFromPC: ; 129f4
+ push de
+ call PartyMonItemName
+ farcall _CheckTossableItem
+ ld a, [wItemAttributeParamBuffer]
+ and a
+ jr nz, .key_item
+ ld hl, .TossHowMany
+ call MenuTextBox
+ farcall SelectQuantityToToss
+ push af
+ call CloseWindow
+ call ExitMenu
+ pop af
+ jr c, .quit
+ ld hl, .ConfirmToss
+ call MenuTextBox
+ call YesNoBox
+ push af
+ call ExitMenu
+ pop af
+ jr c, .quit
+ pop hl
+ ld a, [wCurItemQuantity]
+ call TossItem
+ call PartyMonItemName
+ ld hl, .TossedThisMany
+ call MenuTextBox
+ call ExitMenu
+ and a
+ ret
+
+.key_item
+ call .CantToss
+.quit
+ pop hl
+ scf
+ ret
+
+.TossHowMany:
+ ; Toss out how many @ (S)?
+ text_jump UnknownText_0x1c1a90
+ db "@"
+
+.ConfirmToss:
+ ; Throw away @ @ (S)?
+ text_jump UnknownText_0x1c1aad
+ db "@"
+
+.TossedThisMany:
+ ; Discarded @ (S).
+ text_jump UnknownText_0x1c1aca
+ db "@"
+
+.CantToss:
+ ld hl, .TooImportantToToss
+ call MenuTextBoxBackup
+ ret
+
+.TooImportantToToss:
+ ; That's too impor- tant to toss out!
+ text_jump UnknownText_0x1c1adf
+ db "@"
+; 0x12a60
+
+CantUseItem: ; 12a60
+ ld hl, CantUseItemText
+ call MenuTextBoxWaitButton
+ ret
+; 12a67
+
+CantUseItemText: ; 12a67
+ text_jump UnknownText_0x1c1b03
+ db "@"
+; 12a6c
+
+
+PartyMonItemName: ; 12a6c
+ ld a, [wCurItem]
+ ld [wd265], a
+ call GetItemName
+ call CopyName1
+ ret
+; 12a79
+
+
+CancelPokemonAction: ; 12a79
+ farcall InitPartyMenuWithCancel
+ farcall UnfreezeMonIcons
+ ld a, 1
+ ret
+; 12a88
+
+
+PokemonActionSubmenu: ; 12a88
+ hlcoord 1, 15
+ lb bc, 2, 18
+ call ClearBox
+ farcall MonSubmenu
+ call GetCurNick
+ ld a, [wMenuSelection]
+ ld hl, .Actions
+ ld de, 3
+ call IsInArray
+ jr nc, .nothing
+
+ inc hl
+ ld a, [hli]
+ ld h, [hl]
+ ld l, a
+ jp hl
+
+.nothing
+ ld a, 0
+ ret
+
+.Actions:
+ dbw MONMENUITEM_CUT, MonMenu_Cut
+ dbw MONMENUITEM_FLY, MonMenu_Fly
+ dbw MONMENUITEM_SURF, MonMenu_Surf
+ dbw MONMENUITEM_STRENGTH, MonMenu_Strength
+ dbw MONMENUITEM_FLASH, MonMenu_Flash
+ dbw MONMENUITEM_WHIRLPOOL, MonMenu_Whirlpool
+ dbw MONMENUITEM_DIG, MonMenu_Dig
+ dbw MONMENUITEM_TELEPORT, MonMenu_Teleport
+ dbw MONMENUITEM_SOFTBOILED, MonMenu_Softboiled_MilkDrink
+ dbw MONMENUITEM_MILKDRINK, MonMenu_Softboiled_MilkDrink
+ dbw MONMENUITEM_HEADBUTT, MonMenu_Headbutt
+ dbw MONMENUITEM_WATERFALL, MonMenu_Waterfall
+ dbw MONMENUITEM_ROCKSMASH, MonMenu_RockSmash
+ dbw MONMENUITEM_SWEETSCENT, MonMenu_SweetScent
+ dbw MONMENUITEM_STATS, OpenPartyStats
+ dbw MONMENUITEM_SWITCH, SwitchPartyMons
+ dbw MONMENUITEM_ITEM, GiveTakePartyMonItem
+ dbw MONMENUITEM_CANCEL, CancelPokemonAction
+ dbw MONMENUITEM_MOVE, ManagePokemonMoves
+ dbw MONMENUITEM_MAIL, MonMailAction
+; 12aec
+
+
+SwitchPartyMons: ; 12aec
+
+; Don't try if there's nothing to switch!
+ ld a, [wPartyCount]
+ cp 2
+ jr c, .DontSwitch
+
+ ld a, [wCurPartyMon]
+ inc a
+ ld [wSwitchMon], a
+
+ farcall HoldSwitchmonIcon
+ farcall InitPartyMenuNoCancel
+
+ ld a, PARTYMENUACTION_MOVE
+ ld [wPartyMenuActionText], a
+ farcall WritePartyMenuTilemap
+ farcall PrintPartyMenuText
+
+ hlcoord 0, 1
+ ld bc, SCREEN_WIDTH * 2
+ ld a, [wSwitchMon]
+ dec a
+ call AddNTimes
+ ld [hl], "▷"
+ call WaitBGMap
+ call SetPalettes
+ call DelayFrame
+
+ farcall PartyMenuSelect
+ bit 1, b
+ jr c, .DontSwitch
+
+ farcall _SwitchPartyMons
+
+ xor a
+ ld [wPartyMenuActionText], a
+
+ farcall LoadPartyMenuGFX
+ farcall InitPartyMenuWithCancel
+ farcall InitPartyMenuGFX
+
+ ld a, 1
+ ret
+
+.DontSwitch:
+ xor a
+ ld [wPartyMenuActionText], a
+ call CancelPokemonAction
+ ret
+; 12b60
+
+
+GiveTakePartyMonItem: ; 12b60
+
+; Eggs can't hold items!
+ ld a, [wCurPartySpecies]
+ cp EGG
+ jr z, .cancel
+
+ ld hl, GiveTakeItemMenuData
+ call LoadMenuHeader
+ call VerticalMenu
+ call ExitMenu
+ jr c, .cancel
+
+ call GetCurNick
+ ld hl, wStringBuffer1
+ ld de, wMonOrItemNameBuffer
+ ld bc, MON_NAME_LENGTH
+ call CopyBytes
+ ld a, [wMenuCursorY]
+ cp 1
+ jr nz, .take
+
+ call LoadStandardMenuHeader
+ call ClearPalettes
+ call .GiveItem
+ call ClearPalettes
+ call LoadFontsBattleExtra
+ call ExitMenu
+ ld a, 0
+ ret
+
+.take
+ call TakePartyItem
+ ld a, 3
+ ret
+
+.cancel
+ ld a, 3
+ ret
+; 12ba9
+
+
+.GiveItem:
+
+ farcall DepositSellInitPackBuffers
+
+.loop
+ farcall DepositSellPack
+
+ ld a, [wcf66]
+ and a
+ jr z, .quit
+
+ ld a, [wcf65]
+ cp 2
+ jr z, .next
+
+ call CheckTossableItem
+ ld a, [wItemAttributeParamBuffer]
+ and a
+ jr nz, .next
+
+ call TryGiveItemToPartymon
+ jr .quit
+
+.next
+ ld hl, CantBeHeldText
+ call MenuTextBoxBackup
+ jr .loop
+
+.quit
+ ret
+; 12bd9
+
+
+TryGiveItemToPartymon: ; 12bd9
+
+ call SpeechTextBox
+ call PartyMonItemName
+ call GetPartyItemLocation
+ ld a, [hl]
+ and a
+ jr z, .give_item_to_mon
+
+ push hl
+ ld d, a
+ farcall ItemIsMail
+ pop hl
+ jr c, .please_remove_mail
+ ld a, [hl]
+ jr .already_holding_item
+
+.give_item_to_mon
+ call GiveItemToPokemon
+ ld hl, MadeHoldText
+ call MenuTextBoxBackup
+ call GivePartyItem
+ ret
+
+.please_remove_mail
+ ld hl, PleaseRemoveMailText
+ call MenuTextBoxBackup
+ ret
+
+.already_holding_item
+ ld [wd265], a
+ call GetItemName
+ ld hl, SwitchAlreadyHoldingText
+ call StartMenuYesNo
+ jr c, .abort
+
+ call GiveItemToPokemon
+ ld a, [wd265]
+ push af
+ ld a, [wCurItem]
+ ld [wd265], a
+ pop af
+ ld [wCurItem], a
+ call ReceiveItemFromPokemon
+ jr nc, .bag_full
+
+ ld hl, TookAndMadeHoldText
+ call MenuTextBoxBackup
+ ld a, [wd265]
+ ld [wCurItem], a
+ call GivePartyItem
+ ret
+
+.bag_full
+ ld a, [wd265]
+ ld [wCurItem], a
+ call ReceiveItemFromPokemon
+ ld hl, ItemStorageIsFullText
+ call MenuTextBoxBackup
+
+.abort
+ ret
+; 12c4c
+
+
+GivePartyItem: ; 12c4c
+
+ call GetPartyItemLocation
+ ld a, [wCurItem]
+ ld [hl], a
+ ld d, a
+ farcall ItemIsMail
+ jr nc, .done
+ call ComposeMailMessage
+
+.done
+ ret
+; 12c60
+
+
+TakePartyItem: ; 12c60
+
+ call SpeechTextBox
+ call GetPartyItemLocation
+ ld a, [hl]
+ and a
+ jr z, .asm_12c8c
+
+ ld [wCurItem], a
+ call ReceiveItemFromPokemon
+ jr nc, .asm_12c94
+
+ farcall ItemIsMail
+ call GetPartyItemLocation
+ ld a, [hl]
+ ld [wd265], a
+ ld [hl], NO_ITEM
+ call GetItemName
+ ld hl, TookFromText
+ call MenuTextBoxBackup
+ jr .asm_12c9a
+
+.asm_12c8c
+ ld hl, IsntHoldingAnythingText
+ call MenuTextBoxBackup
+ jr .asm_12c9a
+
+.asm_12c94
+ ld hl, ItemStorageIsFullText
+ call MenuTextBoxBackup
+
+.asm_12c9a
+ ret
+; 12c9b
+
+
+GiveTakeItemMenuData: ; 12c9b
+ db MENU_SPRITE_ANIMS | MENU_BACKUP_TILES ; flags
+ menu_coords 12, 12, SCREEN_WIDTH - 1, SCREEN_HEIGHT - 1
+ dw .Items
+ db 1 ; default option
+
+.Items:
+ db STATICMENU_CURSOR ; flags
+ db 2 ; # items
+ db "GIVE@"
+ db "TAKE@"
+; 12caf
+
+
+TookAndMadeHoldText: ; 12caf
+ text_jump UnknownText_0x1c1b2c
+ db "@"
+; 12cb4
+
+MadeHoldText: ; 12cb4
+ text_jump UnknownText_0x1c1b57
+ db "@"
+; 12cb9
+
+PleaseRemoveMailText: ; 12cb9
+ text_jump UnknownText_0x1c1b6f
+ db "@"
+; 12cbe
+
+IsntHoldingAnythingText: ; 12cbe
+ text_jump UnknownText_0x1c1b8e
+ db "@"
+; 12cc3
+
+ItemStorageIsFullText: ; 12cc3
+ text_jump UnknownText_0x1c1baa
+ db "@"
+; 12cc8
+
+TookFromText: ; 12cc8
+ text_jump UnknownText_0x1c1bc4
+ db "@"
+; 12ccd
+
+SwitchAlreadyHoldingText: ; 12ccd
+ text_jump UnknownText_0x1c1bdc
+ db "@"
+; 12cd2
+
+CantBeHeldText: ; 12cd2
+ text_jump UnknownText_0x1c1c09
+ db "@"
+; 12cd7
+
+
+GetPartyItemLocation: ; 12cd7
+ push af
+ ld a, MON_ITEM
+ call GetPartyParamLocation
+ pop af
+ ret
+; 12cdf
+
+
+ReceiveItemFromPokemon: ; 12cdf
+ ld a, 1
+ ld [wItemQuantityChangeBuffer], a
+ ld hl, wNumItems
+ jp ReceiveItem
+; 12cea
+
+
+GiveItemToPokemon: ; 12cea (4:6cea)
+ ld a, 1
+ ld [wItemQuantityChangeBuffer], a
+ ld hl, wNumItems
+ jp TossItem
+
+StartMenuYesNo: ; 12cf5
+ call MenuTextBox
+ call YesNoBox
+ jp ExitMenu
+; 12cfe
+
+
+ComposeMailMessage: ; 12cfe (4:6cfe)
+ ld de, wTempMailMessage
+ farcall _ComposeMailMessage
+ ld hl, wPlayerName
+ ld de, wTempMailAuthor
+ ld bc, NAME_LENGTH - 1
+ call CopyBytes
+ ld hl, wPlayerID
+ ld bc, 2
+ call CopyBytes
+ ld a, [wCurPartySpecies]
+ ld [de], a
+ inc de
+ ld a, [wCurItem]
+ ld [de], a
+ ld a, [wCurPartyMon]
+ ld hl, sPartyMail
+ ld bc, MAIL_STRUCT_LENGTH
+ call AddNTimes
+ ld d, h
+ ld e, l
+ ld hl, wTempMail
+ ld bc, MAIL_STRUCT_LENGTH
+ ld a, BANK(sPartyMail)
+ call GetSRAMBank
+ call CopyBytes
+ call CloseSRAM
+ ret
+
+MonMailAction: ; 12d45
+; If in the time capsule or trade center,
+; selecting the mail only allows you to
+; read the mail.
+ ld a, [wLinkMode]
+ cp LINK_TIMECAPSULE
+ jr z, .read
+ cp LINK_TRADECENTER
+ jr z, .read
+
+; Show the READ/TAKE/QUIT menu.
+ ld hl, .MenuHeader
+ call LoadMenuHeader
+ call VerticalMenu
+ call ExitMenu
+
+; Interpret the menu.
+ jp c, .done
+ ld a, [wMenuCursorY]
+ cp $1
+ jr z, .read
+ cp $2
+ jr z, .take
+ jp .done
+
+.read
+ farcall ReadPartyMonMail
+ ld a, $0
+ ret
+
+.take
+ ld hl, .sendmailtopctext
+ call StartMenuYesNo
+ jr c, .RemoveMailToBag
+ ld a, [wCurPartyMon]
+ ld b, a
+ farcall SendMailToPC
+ jr c, .MailboxFull
+ ld hl, .sentmailtopctext
+ call MenuTextBoxBackup
+ jr .done
+
+.MailboxFull:
+ ld hl, .mailboxfulltext
+ call MenuTextBoxBackup
+ jr .done
+
+.RemoveMailToBag:
+ ld hl, .mailwilllosemessagetext
+ call StartMenuYesNo
+ jr c, .done
+ call GetPartyItemLocation
+ ld a, [hl]
+ ld [wCurItem], a
+ call ReceiveItemFromPokemon
+ jr nc, .BagIsFull
+ call GetPartyItemLocation
+ ld [hl], $0
+ call GetCurNick
+ ld hl, .tookmailfrommontext
+ call MenuTextBoxBackup
+ jr .done
+
+.BagIsFull:
+ ld hl, .bagfulltext
+ call MenuTextBoxBackup
+ jr .done
+
+.done
+ ld a, $3
+ ret
+; 12dc9
+
+
+.MenuHeader:
+ db MENU_BACKUP_TILES ; flags
+ menu_coords 12, 10, SCREEN_WIDTH - 1, SCREEN_HEIGHT - 1
+ dw .MenuData
+ db 1 ; default option
+; 0x12dd1
+
+.MenuData:
+ db STATICMENU_CURSOR ; flags
+ db 3 ; items
+ db "READ@"
+ db "TAKE@"
+ db "QUIT@"
+; 0x12de2
+
+
+.mailwilllosemessagetext
+; The MAIL will lose its message. OK?
+ text_jump UnknownText_0x1c1c22
+ db "@"
+; 0x12de7
+
+.tookmailfrommontext
+; MAIL detached from <POKEMON>.
+ text_jump UnknownText_0x1c1c47
+ db "@"
+; 0x12dec
+
+.bagfulltext
+; There's no space for removing MAIL.
+ text_jump UnknownText_0x1c1c62
+ db "@"
+; 0x12df1
+
+.sendmailtopctext
+; Send the removed MAIL to your PC?
+ text_jump UnknownText_0x1c1c86
+ db "@"
+; 0x12df6
+
+.mailboxfulltext
+; Your PC's MAILBOX is full.
+ text_jump UnknownText_0x1c1ca9
+ db "@"
+; 0x12dfb
+
+.sentmailtopctext
+; The MAIL was sent to your PC.
+ text_jump UnknownText_0x1c1cc4
+ db "@"
+; 0x12e00
+
+
+OpenPartyStats: ; 12e00
+ call LoadStandardMenuHeader
+ call ClearSprites
+; PartyMon
+ xor a
+ ld [wMonType], a
+ call LowVolume
+ predef StatsScreenInit
+ call MaxVolume
+ call Call_ExitMenu
+ ld a, 0
+ ret
+; 12e1b
+
+
+MonMenu_Cut: ; 12e1b
+ farcall CutFunction
+ ld a, [wFieldMoveSucceeded]
+ cp $1
+ jr nz, .Fail
+ ld b, $4
+ ld a, $2
+ ret
+
+.Fail:
+ ld a, $3
+ ret
+; 12e30
+
+
+MonMenu_Fly: ; 12e30
+ farcall FlyFunction
+ ld a, [wFieldMoveSucceeded]
+ cp $2
+ jr z, .Fail
+ cp $0
+ jr z, .Error
+ farcall StubbedTrainerRankings_Fly
+ ld b, $4
+ ld a, $2
+ ret
+
+.Fail:
+ ld a, $3
+ ret
+
+.Error:
+ ld a, $0
+ ret
+
+.Unreferenced:
+ ld a, $1
+ ret
+; 12e55
+
+MonMenu_Flash: ; 12e55
+ farcall OWFlash
+ ld a, [wFieldMoveSucceeded]
+ cp $1
+ jr nz, .Fail
+ ld b, $4
+ ld a, $2
+ ret
+
+.Fail:
+ ld a, $3
+ ret
+; 12e6a
+
+MonMenu_Strength: ; 12e6a
+ farcall StrengthFunction
+ ld a, [wFieldMoveSucceeded]
+ cp $1
+ jr nz, .Fail
+ ld b, $4
+ ld a, $2
+ ret
+
+.Fail:
+ ld a, $3
+ ret
+; 12e7f
+
+MonMenu_Whirlpool: ; 12e7f
+ farcall WhirlpoolFunction
+ ld a, [wFieldMoveSucceeded]
+ cp $1
+ jr nz, .Fail
+ ld b, $4
+ ld a, $2
+ ret
+
+.Fail:
+ ld a, $3
+ ret
+; 12e94
+
+MonMenu_Waterfall: ; 12e94
+ farcall WaterfallFunction
+ ld a, [wFieldMoveSucceeded]
+ cp $1
+ jr nz, .Fail
+ ld b, $4
+ ld a, $2
+ ret
+
+.Fail:
+ ld a, $3
+ ret
+; 12ea9
+
+MonMenu_Teleport: ; 12ea9
+ farcall TeleportFunction
+ ld a, [wFieldMoveSucceeded]
+ and a
+ jr z, .Fail
+ ld b, $4
+ ld a, $2
+ ret
+
+.Fail:
+ ld a, $3
+ ret
+; 12ebd
+
+MonMenu_Surf: ; 12ebd
+ farcall SurfFunction
+ ld a, [wFieldMoveSucceeded]
+ and a
+ jr z, .Fail
+ ld b, $4
+ ld a, $2
+ ret
+
+.Fail:
+ ld a, $3
+ ret
+; 12ed1
+
+MonMenu_Dig: ; 12ed1
+ farcall DigFunction
+ ld a, [wFieldMoveSucceeded]
+ cp $1
+ jr nz, .Fail
+ ld b, $4
+ ld a, $2
+ ret
+
+.Fail:
+ ld a, $3
+ ret
+; 12ee6
+
+MonMenu_Softboiled_MilkDrink: ; 12ee6
+ call .CheckMonHasEnoughHP
+ jr nc, .NotEnoughHP
+ farcall Softboiled_MilkDrinkFunction
+ jr .finish
+
+.NotEnoughHP:
+ ld hl, .Text_NotEnoughHP
+ call PrintText
+
+.finish
+ xor a
+ ld [wPartyMenuActionText], a
+ ld a, $3
+ ret
+; 12f00
+
+.Text_NotEnoughHP:
+ ; Not enough HP!
+ text_jump UnknownText_0x1c1ce3
+ db "@"
+; 0x12f05
+
+.CheckMonHasEnoughHP:
+; Need to have at least (MaxHP / 5) HP left.
+ ld a, MON_MAXHP
+ call GetPartyParamLocation
+ ld a, [hli]
+ ld [hDividend + 0], a
+ ld a, [hl]
+ ld [hDividend + 1], a
+ ld a, 5
+ ld [hDivisor], a
+ ld b, 2
+ call Divide
+ ld a, MON_HP + 1
+ call GetPartyParamLocation
+ ld a, [hQuotient + 2]
+ sub [hl]
+ dec hl
+ ld a, [hQuotient + 1]
+ sbc [hl]
+ ret
+; 12f26
+
+MonMenu_Headbutt: ; 12f26
+ farcall HeadbuttFunction
+ ld a, [wFieldMoveSucceeded]
+ cp $1
+ jr nz, .Fail
+ ld b, $4
+ ld a, $2
+ ret
+
+.Fail:
+ ld a, $3
+ ret
+; 12f3b
+
+MonMenu_RockSmash: ; 12f3b
+ farcall RockSmashFunction
+ ld a, [wFieldMoveSucceeded]
+ cp $1
+ jr nz, .Fail
+ ld b, $4
+ ld a, $2
+ ret
+
+.Fail:
+ ld a, $3
+ ret
+; 12f50
+
+MonMenu_SweetScent: ; 12f50
+ farcall SweetScentFromMenu
+ ld b, $4
+ ld a, $2
+ ret
+; 12f5b
+
+ChooseMoveToDelete: ; 12f5b
+ ld hl, wOptions
+ ld a, [hl]
+ push af
+ set NO_TEXT_SCROLL, [hl]
+ call LoadFontsBattleExtra
+ call .ChooseMoveToDelete
+ pop bc
+ ld a, b
+ ld [wOptions], a
+ push af
+ call ClearBGPalettes
+ pop af
+ ret
+; 12f73
+
+.ChooseMoveToDelete
+ call SetUpMoveScreenBG
+ ld de, DeleteMoveScreenAttrs
+ call SetMenuAttributes
+ call SetUpMoveList
+ ld hl, w2DMenuFlags1
+ set 6, [hl]
+ jr .enter_loop
+
+.loop
+ call ScrollingMenuJoypad
+ bit B_BUTTON_F, a
+ jp nz, .b_button
+ bit A_BUTTON_F, a
+ jp nz, .a_button
+
+.enter_loop
+ call PrepareToPlaceMoveData
+ call PlaceMoveData
+ jp .loop
+; 12f9c
+
+.a_button
+ and a
+ jr .finish
+
+.b_button
+ scf
+
+.finish
+ push af
+ xor a
+ ld [wSwitchMon], a
+ ld hl, w2DMenuFlags1
+ res 6, [hl]
+ call ClearSprites
+ call ClearTileMap
+ pop af
+ ret
+; 12fb2
+
+DeleteMoveScreenAttrs: ; 12fb2
+ db 3, 1
+ db 3, 1
+ db $40, $00
+ dn 2, 0
+ db D_UP | D_DOWN | A_BUTTON | B_BUTTON
+; 12fba
+
+ManagePokemonMoves: ; 12fba
+ ld a, [wCurPartySpecies]
+ cp EGG
+ jr z, .egg
+ ld hl, wOptions
+ ld a, [hl]
+ push af
+ set NO_TEXT_SCROLL, [hl]
+ call MoveScreenLoop
+ pop af
+ ld [wOptions], a
+ call ClearBGPalettes
+
+.egg
+ ld a, $0
+ ret
+; 12fd5
+
+MoveScreenLoop: ; 12fd5
+ ld a, [wCurPartyMon]
+ inc a
+ ld [wPartyMenuCursor], a
+ call SetUpMoveScreenBG
+ call Function132d3
+ ld de, MoveScreenAttributes
+ call SetMenuAttributes
+.loop
+ call SetUpMoveList
+ ld hl, w2DMenuFlags1
+ set 6, [hl]
+ jr .skip_joy
+
+.joy_loop
+ call ScrollingMenuJoypad
+ bit 1, a
+ jp nz, .b_button
+ bit 0, a
+ jp nz, .a_button
+ bit 4, a
+ jp nz, .d_right
+ bit 5, a
+ jp nz, .d_left
+
+.skip_joy
+ call PrepareToPlaceMoveData
+ ld a, [wMoveSwapBuffer]
+ and a
+ jr nz, .moving_move
+ call PlaceMoveData
+ jp .joy_loop
+
+.moving_move
+ ld a, " "
+ hlcoord 1, 11
+ ld bc, 5
+ call ByteFill
+ hlcoord 1, 12
+ lb bc, 5, SCREEN_WIDTH - 2
+ call ClearBox
+ hlcoord 1, 12
+ ld de, String_MoveWhere
+ call PlaceString
+ jp .joy_loop
+.b_button
+ call PlayClickSFX
+ call WaitSFX
+ ld a, [wMoveSwapBuffer]
+ and a
+ jp z, .exit
+
+ ld a, [wMoveSwapBuffer]
+ ld [wMenuCursorY], a
+ xor a
+ ld [wMoveSwapBuffer], a
+ hlcoord 1, 2
+ lb bc, 8, SCREEN_WIDTH - 2
+ call ClearBox
+ jp .loop
+; 1305b
+
+.d_right
+ ld a, [wMoveSwapBuffer]
+ and a
+ jp nz, .joy_loop
+
+ ld a, [wCurPartyMon]
+ ld b, a
+ push bc
+ call .cycle_right
+ pop bc
+ ld a, [wCurPartyMon]
+ cp b
+ jp z, .joy_loop
+ jp MoveScreenLoop
+
+.d_left
+ ld a, [wMoveSwapBuffer]
+ and a
+ jp nz, .joy_loop
+ ld a, [wCurPartyMon]
+ ld b, a
+ push bc
+ call .cycle_left
+ pop bc
+ ld a, [wCurPartyMon]
+ cp b
+ jp z, .joy_loop
+ jp MoveScreenLoop
+
+.cycle_right
+ ld a, [wCurPartyMon]
+ inc a
+ ld [wCurPartyMon], a
+ ld c, a
+ ld b, 0
+ ld hl, wPartySpecies
+ add hl, bc
+ ld a, [hl]
+ cp -1
+ jr z, .cycle_left
+ cp EGG
+ ret nz
+ jr .cycle_right
+
+.cycle_left
+ ld a, [wCurPartyMon]
+ and a
+ ret z
+.cycle_left_loop
+ ld a, [wCurPartyMon]
+ dec a
+ ld [wCurPartyMon], a
+ ld c, a
+ ld b, 0
+ ld hl, wPartySpecies
+ add hl, bc
+ ld a, [hl]
+ cp EGG
+ ret nz
+ ld a, [wCurPartyMon]
+ and a
+ jr z, .cycle_right
+ jr .cycle_left_loop
+; 130c6
+
+.a_button
+ call PlayClickSFX
+ call WaitSFX
+ ld a, [wMoveSwapBuffer]
+ and a
+ jr nz, .place_move
+ ld a, [wMenuCursorY]
+ ld [wMoveSwapBuffer], a
+ call PlaceHollowCursor
+ jp .moving_move
+
+.place_move
+ ld hl, wPartyMon1Moves
+ ld bc, PARTYMON_STRUCT_LENGTH
+ ld a, [wCurPartyMon]
+ call AddNTimes
+ push hl
+ call .copy_move
+ pop hl
+ ld bc, $15
+ add hl, bc
+ call .copy_move
+ ld a, [wBattleMode]
+ jr z, .swap_moves
+ ld hl, wBattleMonMoves
+ ld bc, $20
+ ld a, [wCurPartyMon]
+ call AddNTimes
+ push hl
+ call .copy_move
+ pop hl
+ ld bc, 6
+ add hl, bc
+ call .copy_move
+
+.swap_moves
+ ld de, SFX_SWITCH_POKEMON
+ call PlaySFX
+ call WaitSFX
+ ld de, SFX_SWITCH_POKEMON
+ call PlaySFX
+ call WaitSFX
+ hlcoord 1, 2
+ lb bc, 8, 18
+ call ClearBox
+ hlcoord 10, 10
+ lb bc, 1, 9
+ call ClearBox
+ jp .loop
+; 1313a
+
+.copy_move
+ push hl
+ ld a, [wMenuCursorY]
+ dec a
+ ld c, a
+ ld b, $0
+ add hl, bc
+ ld d, h
+ ld e, l
+ pop hl
+ ld a, [wMoveSwapBuffer]
+ dec a
+ ld c, a
+ ld b, $0
+ add hl, bc
+ ld a, [de]
+ ld b, [hl]
+ ld [hl], a
+ ld a, b
+ ld [de], a
+ ret
+; 13154
+
+.exit
+ xor a
+ ld [wMoveSwapBuffer], a
+ ld hl, w2DMenuFlags1
+ res 6, [hl]
+ call ClearSprites
+ jp ClearTileMap
+; 13163
+
+MoveScreenAttributes: ; 13163
+ db 3, 1
+ db 3, 1
+ db $40, $00
+ dn 2, 0
+ db D_UP | D_DOWN | D_LEFT | D_RIGHT | A_BUTTON | B_BUTTON
+; 1316b
+
+String_MoveWhere: ; 1316b
+ db "Where?@"
+; 13172
+
+SetUpMoveScreenBG: ; 13172
+ call ClearBGPalettes
+ call ClearTileMap
+ call ClearSprites
+ xor a
+ ld [hBGMapMode], a
+ farcall LoadStatsScreenPageTilesGFX
+ farcall ClearSpriteAnims2
+ ld a, [wCurPartyMon]
+ ld e, a
+ ld d, $0
+ ld hl, wPartySpecies
+ add hl, de
+ ld a, [hl]
+ ld [wd265], a
+ ld e, $2
+ farcall LoadMenuMonIcon
+ hlcoord 0, 1
+ ld b, 9
+ ld c, 18
+ call TextBox
+ hlcoord 0, 11
+ ld b, 5
+ ld c, 18
+ call TextBox
+ hlcoord 2, 0
+ lb bc, 2, 3
+ call ClearBox
+ xor a
+ ld [wMonType], a
+ ld hl, wPartyMonNicknames
+ ld a, [wCurPartyMon]
+ call GetNick
+ hlcoord 5, 1
+ call PlaceString
+ push bc
+ farcall CopyMonToTempMon
+ pop hl
+ call PrintLevel
+ ld hl, wPlayerHPPal
+ call SetHPPal
+ ld b, SCGB_MOVE_LIST
+ call GetSGBLayout
+ hlcoord 16, 0
+ lb bc, 1, 3
+ jp ClearBox
+; 131ef
+
+SetUpMoveList: ; 131ef
+ xor a
+ ld [hBGMapMode], a
+ ld [wMoveSwapBuffer], a
+ ld [wMonType], a
+ predef CopyMonToTempMon
+ ld hl, wTempMonMoves
+ ld de, wListMoves_MoveIndicesBuffer
+ ld bc, NUM_MOVES
+ call CopyBytes
+ ld a, SCREEN_WIDTH * 2
+ ld [wBuffer1], a
+ hlcoord 2, 3
+ predef ListMoves
+ hlcoord 10, 4
+ predef ListMovePP
+ call WaitBGMap
+ call SetPalettes
+ ld a, [wNumMoves]
+ inc a
+ ld [w2DMenuNumRows], a
+ hlcoord 0, 11
+ ld b, 5
+ ld c, 18
+ jp TextBox
+; 13235
+
+PrepareToPlaceMoveData: ; 13235
+ ld hl, wPartyMon1Moves
+ ld bc, PARTYMON_STRUCT_LENGTH
+ ld a, [wCurPartyMon]
+ call AddNTimes
+ ld a, [wMenuCursorY]
+ dec a
+ ld c, a
+ ld b, $0
+ add hl, bc
+ ld a, [hl]
+ ld [wCurMove], a
+ hlcoord 1, 12
+ lb bc, 5, 18
+ jp ClearBox
+; 13256
+
+PlaceMoveData: ; 13256
+ xor a
+ ld [hBGMapMode], a
+ hlcoord 0, 10
+ ld de, String_MoveType_Top
+ call PlaceString
+ hlcoord 0, 11
+ ld de, String_MoveType_Bottom
+ call PlaceString
+ hlcoord 12, 12
+ ld de, String_MoveAtk
+ call PlaceString
+ ld a, [wCurMove]
+ ld b, a
+ hlcoord 2, 12
+ predef PrintMoveType
+ ld a, [wCurMove]
+ dec a
+ ld hl, Moves + MOVE_POWER
+ ld bc, MOVE_LENGTH
+ call AddNTimes
+ ld a, BANK(Moves)
+ call GetFarByte
+ hlcoord 16, 12
+ cp 2
+ jr c, .no_power
+ ld [wd265], a
+ ld de, wd265
+ lb bc, 1, 3
+ call PrintNum
+ jr .description
+
+.no_power
+ ld de, String_MoveNoPower
+ call PlaceString
+
+.description
+ hlcoord 1, 14
+ predef PrintMoveDesc
+ ld a, $1
+ ld [hBGMapMode], a
+ ret
+; 132ba
+
+String_MoveType_Top: ; 132ba
+ db "┌─────┐@"
+; 132c2
+String_MoveType_Bottom: ; 132c2
+ db "│TYPE/└@"
+; 132ca
+String_MoveAtk: ; 132ca
+ db "ATK/@"
+; 132cf
+String_MoveNoPower: ; 132cf
+ db "---@"
+; 132d3
+
+Function132d3: ; 132d3
+ call Function132da
+ call Function132fe
+ ret
+; 132da
+
+Function132da: ; 132da
+ ld a, [wCurPartyMon]
+ and a
+ ret z
+ ld c, a
+ ld e, a
+ ld d, 0
+ ld hl, wPartyCount
+ add hl, de
+.loop
+ ld a, [hl]
+ and a
+ jr z, .prev
+ cp EGG
+ jr z, .prev
+ cp NUM_POKEMON + 1
+ jr c, .legal
+
+.prev
+ dec hl
+ dec c
+ jr nz, .loop
+ ret
+
+.legal
+ hlcoord 16, 0
+ ld [hl], "◀"
+ ret
+; 132fe
+
+Function132fe: ; 132fe
+ ld a, [wCurPartyMon]
+ inc a
+ ld c, a
+ ld a, [wPartyCount]
+ cp c
+ ret z
+ ld e, c
+ ld d, 0
+ ld hl, wPartySpecies
+ add hl, de
+.loop
+ ld a, [hl]
+ cp -1
+ ret z
+ and a
+ jr z, .next
+ cp EGG
+ jr z, .next
+ cp NUM_POKEMON + 1
+ jr c, .legal
+
+.next
+ inc hl
+ jr .loop
+
+.legal
+ hlcoord 18, 0
+ ld [hl], "▶"
+ ret
+; 13327
diff --git a/engine/menus/trainer_card.asm b/engine/menus/trainer_card.asm
new file mode 100755
index 000000000..e84c1c9f3
--- /dev/null
+++ b/engine/menus/trainer_card.asm
@@ -0,0 +1,623 @@
+; TrainerCard.Jumptable indexes
+ const_def
+ const TRAINERCARDSTATE_PAGE1_LOADGFX ; 0
+ const TRAINERCARDSTATE_PAGE1_JOYPAD ; 1
+ const TRAINERCARDSTATE_PAGE2_LOADGFX ; 2
+ const TRAINERCARDSTATE_PAGE2_JOYPAD ; 3
+ const TRAINERCARDSTATE_PAGE3_LOADGFX ; 4
+ const TRAINERCARDSTATE_PAGE3_JOYPAD ; 5
+ const TRAINERCARDSTATE_QUIT ; 6
+
+TrainerCard: ; 25105
+ ld a, [wVramState]
+ push af
+ xor a
+ ld [wVramState], a
+ ld hl, wOptions
+ ld a, [hl]
+ push af
+ set NO_TEXT_SCROLL, [hl]
+ call .InitRAM
+.loop
+ call UpdateTime
+ call JoyTextDelay
+ ld a, [wJumptableIndex]
+ bit 7, a
+ jr nz, .quit
+ ld a, [hJoyLast]
+ and B_BUTTON
+ jr nz, .quit
+ call .RunJumptable
+ call DelayFrame
+ jr .loop
+
+.quit
+ pop af
+ ld [wOptions], a
+ pop af
+ ld [wVramState], a
+ ret
+
+.InitRAM: ; 2513b (9:513b)
+ call ClearBGPalettes
+ call ClearSprites
+ call ClearTileMap
+ call DisableLCD
+
+ farcall GetCardPic
+
+ ld hl, CardRightCornerGFX
+ ld de, vTiles2 tile $1c
+ ld bc, 1 tiles
+ ld a, BANK(CardRightCornerGFX)
+ call FarCopyBytes
+
+ ld hl, CardStatusGFX
+ ld de, vTiles2 tile $29
+ ld bc, 86 tiles
+ ld a, BANK(CardStatusGFX)
+ call FarCopyBytes
+
+ call TrainerCard_PrintTopHalfOfCard
+
+ hlcoord 0, 8
+ ld d, 6
+ call TrainerCard_InitBorder
+
+ call EnableLCD
+ call WaitBGMap
+ ld b, SCGB_TRAINER_CARD
+ call GetSGBLayout
+ call SetPalettes
+ call WaitBGMap
+ ld hl, wJumptableIndex
+ xor a ; TRAINERCARDSTATE_PAGE1_LOADGFX
+ ld [hli], a ; wJumptableIndex
+ ld [hli], a ; wTrainerCardBadgeFrameCounter
+ ld [hli], a ; wTrainerCardBadgeTileID
+ ld [hl], a ; wTrainerCardBadgeAttributes
+ ret
+
+.RunJumptable: ; 2518e (9:518e)
+ jumptable .Jumptable, wJumptableIndex
+
+.Jumptable: ; 2519d (9:519d)
+; entries correspond to TRAINERCARDSTATE_* constants
+ dw TrainerCard_Page1_LoadGFX
+ dw TrainerCard_Page1_Joypad
+ dw TrainerCard_Page2_LoadGFX
+ dw TrainerCard_Page2_Joypad
+ dw TrainerCard_Page3_LoadGFX
+ dw TrainerCard_Page3_Joypad
+ dw TrainerCard_Quit
+
+TrainerCard_IncrementJumptable: ; 251ab (9:51ab)
+ ld hl, wJumptableIndex
+ inc [hl]
+ ret
+
+TrainerCard_Quit: ; 251b0 (9:51b0)
+ ld hl, wJumptableIndex
+ set 7, [hl]
+ ret
+
+TrainerCard_Page1_LoadGFX: ; 251b6 (9:51b6)
+ call ClearSprites
+ hlcoord 0, 8
+ ld d, 6
+ call TrainerCard_InitBorder
+ call WaitBGMap
+ ld de, CardStatusGFX
+ ld hl, vTiles2 tile $29
+ lb bc, BANK(CardStatusGFX), 86
+ call Request2bpp
+ call TrainerCard_Page1_PrintDexCaught_GameTime
+ call TrainerCard_IncrementJumptable
+ ret
+
+TrainerCard_Page1_Joypad: ; 251d7 (9:51d7)
+ call TrainerCard_Page1_PrintGameTime
+ ld hl, hJoyLast
+ ld a, [hl]
+ and D_RIGHT | A_BUTTON
+ jr nz, .pressed_right_a
+ ret
+
+.pressed_right_a
+ ld a, TRAINERCARDSTATE_PAGE2_LOADGFX
+ ld [wJumptableIndex], a
+ ret
+
+.Unreferenced_KantoCheck:
+ ld a, [wKantoBadges]
+ and a
+ ret z
+ ld a, TRAINERCARDSTATE_PAGE3_LOADGFX
+ ld [wJumptableIndex], a
+ ret
+
+; 251f4
+
+TrainerCard_Page2_LoadGFX: ; 251f4 (9:51f4)
+ call ClearSprites
+ hlcoord 0, 8
+ ld d, 6
+ call TrainerCard_InitBorder
+ call WaitBGMap
+ ld de, LeaderGFX
+ ld hl, vTiles2 tile $29
+ lb bc, BANK(LeaderGFX), 86
+ call Request2bpp
+ ld de, BadgeGFX
+ ld hl, vTiles0 tile $00
+ lb bc, BANK(BadgeGFX), 44
+ call Request2bpp
+ call TrainerCard_Page2_3_InitObjectsAndStrings
+ call TrainerCard_IncrementJumptable
+ ret
+
+TrainerCard_Page2_Joypad: ; 25221 (9:5221)
+ ld hl, TrainerCard_JohtoBadgesOAM
+ call TrainerCard_Page2_3_AnimateBadges
+ ld hl, hJoyLast
+ ld a, [hl]
+ and A_BUTTON
+ jr nz, .Quit
+ ld a, [hl]
+ and D_LEFT
+ jr nz, .d_left
+ ret
+
+.d_left
+ ld a, TRAINERCARDSTATE_PAGE1_LOADGFX
+ ld [wJumptableIndex], a
+ ret
+
+.Unreferenced_KantoCheck:
+ ld a, [wKantoBadges]
+ and a
+ ret z
+ ld a, TRAINERCARDSTATE_PAGE3_LOADGFX
+ ld [wJumptableIndex], a
+ ret
+
+.Quit:
+ ld a, TRAINERCARDSTATE_QUIT
+ ld [wJumptableIndex], a
+ ret
+
+TrainerCard_Page3_LoadGFX: ; 2524c (9:524c)
+ call ClearSprites
+ hlcoord 0, 8
+ ld d, 6
+ call TrainerCard_InitBorder
+ call WaitBGMap
+ ld de, LeaderGFX2
+ ld hl, vTiles2 tile $29
+ lb bc, BANK(LeaderGFX2), 86
+ call Request2bpp
+ ld de, BadgeGFX2
+ ld hl, vTiles0 tile $00
+ lb bc, BANK(BadgeGFX2), 44
+ call Request2bpp
+ call TrainerCard_Page2_3_InitObjectsAndStrings
+ call TrainerCard_IncrementJumptable
+ ret
+
+TrainerCard_Page3_Joypad: ; 25279 (9:5279)
+ ld hl, TrainerCard_JohtoBadgesOAM
+ call TrainerCard_Page2_3_AnimateBadges
+ ld hl, hJoyLast
+ ld a, [hl]
+ and D_LEFT
+ jr nz, .left
+ ld a, [hl]
+ and D_RIGHT
+ jr nz, .right
+ ret
+
+.left
+ ld a, TRAINERCARDSTATE_PAGE2_LOADGFX
+ ld [wJumptableIndex], a
+ ret
+
+.right
+ ld a, TRAINERCARDSTATE_PAGE1_LOADGFX
+ ld [wJumptableIndex], a
+ ret
+
+TrainerCard_PrintTopHalfOfCard: ; 25299 (9:5299)
+ hlcoord 0, 0
+ ld d, 5
+ call TrainerCard_InitBorder
+ hlcoord 2, 2
+ ld de, .Name_Money
+ call PlaceString
+ hlcoord 2, 4
+ ld de, .ID_No
+ call TrainerCardSetup_PlaceTilemapString
+ hlcoord 7, 2
+ ld de, wPlayerName
+ call PlaceString
+ hlcoord 5, 4
+ ld de, wPlayerID
+ lb bc, PRINTNUM_LEADINGZEROS | 2, 5
+ call PrintNum
+ hlcoord 7, 6
+ ld de, wMoney
+ lb bc, PRINTNUM_MONEY | 3, 6
+ call PrintNum
+ hlcoord 1, 3
+ ld de, .HorizontalDivider
+ call TrainerCardSetup_PlaceTilemapString
+ hlcoord 14, 1
+ lb bc, 5, 7
+ xor a
+ ld [hGraphicStartTile], a
+ predef PlaceGraphic
+ ret
+
+; 252ec (9:52ec)
+
+.Name_Money: ; 252ec
+ db "NAME/"
+ next ""
+ next "MONEY@"
+
+.ID_No: ; 252f9
+ db $27, $28, -1 ; ID NO
+
+.HorizontalDivider: ; 252fc
+ db $25, $25, $25, $25, $25, $25, $25, $25, $25, $25, $25, $25, $26, -1 ; ____________>
+; 2530a
+
+TrainerCard_Page1_PrintDexCaught_GameTime: ; 2530a (9:530a)
+ hlcoord 2, 10
+ ld de, .Dex_PlayTime
+ call PlaceString
+ hlcoord 10, 15
+ ld de, .Badges
+ call PlaceString
+ ld hl, wPokedexCaught
+ ld b, wEndPokedexCaught - wPokedexCaught
+ call CountSetBits
+ ld de, wd265
+ hlcoord 15, 10
+ lb bc, 1, 3
+ call PrintNum
+ call TrainerCard_Page1_PrintGameTime
+ hlcoord 2, 8
+ ld de, .StatusTilemap
+ call TrainerCardSetup_PlaceTilemapString
+ ld a, [wStatusFlags]
+ bit STATUSFLAGS_POKEDEX_F, a
+ ret nz
+ hlcoord 1, 9
+ lb bc, 2, 17
+ call ClearBox
+ ret
+
+.Dex_PlayTime:
+ db "#DEX"
+ next "PLAY TIME@@"
+
+.Badges:
+ db " BADGES▶@"
+
+.StatusTilemap: ; 25366
+ db $29, $2a, $2b, $2c, $2d, -1
+; 2536c
+
+TrainerCard_Page2_3_InitObjectsAndStrings: ; 2536c (9:536c)
+ hlcoord 2, 8
+ ld de, .BadgesTilemap
+ call TrainerCardSetup_PlaceTilemapString
+ hlcoord 2, 10
+ ld a, $29
+ ld c, 4
+.loop
+ call TrainerCard_Page2_3_PlaceLeadersFaces
+rept 4
+ inc hl
+endr
+ dec c
+ jr nz, .loop
+ hlcoord 2, 13
+ ld a, $51
+ ld c, 4
+.loop2
+ call TrainerCard_Page2_3_PlaceLeadersFaces
+rept 4
+ inc hl
+endr
+ dec c
+ jr nz, .loop2
+ xor a
+ ld [wTrainerCardBadgeFrameCounter], a
+ ld hl, TrainerCard_JohtoBadgesOAM
+ call TrainerCard_Page2_3_OAMUpdate
+ ret
+
+; 253a2 (9:53a2)
+
+.BadgesTilemap: ; 253a2
+ db $79, $7a, $7b, $7c, $7d, -1 ; "BADGES"
+; 253a8
+
+TrainerCardSetup_PlaceTilemapString: ; 253a8 (9:53a8)
+.loop
+ ld a, [de]
+ cp -1
+ ret z
+ ld [hli], a
+ inc de
+ jr .loop
+
+TrainerCard_InitBorder: ; 253b0 (9:53b0)
+ ld e, SCREEN_WIDTH
+.loop1
+ ld a, $23
+ ld [hli], a
+ dec e
+ jr nz, .loop1
+
+ ld a, $23
+ ld [hli], a
+ ld e, SCREEN_HEIGHT - 1
+ ld a, " "
+.loop2
+ ld [hli], a
+ dec e
+ jr nz, .loop2
+
+ ld a, $1c
+ ld [hli], a
+ ld a, $23
+ ld [hli], a
+.loop3
+ ld a, $23
+ ld [hli], a
+
+ ld e, SCREEN_HEIGHT
+ ld a, " "
+.loop4
+ ld [hli], a
+ dec e
+ jr nz, .loop4
+
+ ld a, $23
+ ld [hli], a
+ dec d
+ jr nz, .loop3
+
+ ld a, $23
+ ld [hli], a
+ ld a, $24
+ ld [hli], a
+
+ ld e, SCREEN_HEIGHT - 1
+ ld a, " "
+.loop5
+ ld [hli], a
+ dec e
+ jr nz, .loop5
+ ld a, $23
+ ld [hli], a
+ ld e, SCREEN_WIDTH
+.loop6
+ ld a, $23
+ ld [hli], a
+ dec e
+ jr nz, .loop6
+ ret
+
+TrainerCard_Page2_3_PlaceLeadersFaces: ; 253f4 (9:53f4)
+ push de
+ push hl
+ ld [hli], a
+ inc a
+ ld [hli], a
+ inc a
+ ld [hli], a
+ inc a
+ ld [hli], a
+ inc a
+ ld de, SCREEN_WIDTH - 3
+ add hl, de
+ ld [hli], a
+ inc a
+ ld [hli], a
+ inc a
+ ld [hli], a
+ inc a
+ ld de, SCREEN_WIDTH - 3
+ add hl, de
+ ld [hli], a
+ inc a
+ ld [hli], a
+ inc a
+ ld [hli], a
+ inc a
+ pop hl
+ pop de
+ ret
+
+TrainerCard_Page1_PrintGameTime: ; 25415 (9:5415)
+ hlcoord 11, 12
+ ld de, wGameTimeHours
+ lb bc, 2, 4
+ call PrintNum
+ inc hl
+ ld de, wGameTimeMinutes
+ lb bc, PRINTNUM_LEADINGZEROS | 1, 2
+ call PrintNum
+ ld a, [hVBlankCounter]
+ and $1f
+ ret nz
+ hlcoord 15, 12
+ ld a, [hl]
+ xor " " ^ $2e ; alternate between space and small colon ($2e) tiles
+ ld [hl], a
+ ret
+
+TrainerCard_Page2_3_AnimateBadges: ; 25438 (9:5438)
+ ld a, [hVBlankCounter]
+ and %111
+ ret nz
+ ld a, [wTrainerCardBadgeFrameCounter]
+ inc a
+ and %111
+ ld [wTrainerCardBadgeFrameCounter], a
+ jr TrainerCard_Page2_3_OAMUpdate
+
+TrainerCard_Page2_3_OAMUpdate: ; 25448 (9:5448)
+; copy flag array pointer
+ ld a, [hli]
+ ld e, a
+ ld a, [hli]
+; get flag array
+ ld d, a
+ ld a, [de]
+ ld c, a
+ ld de, wVirtualOAMSprite00
+ ld b, NUM_JOHTO_BADGES
+.loop
+ srl c
+ push bc
+ jr nc, .skip_badge
+ push hl
+ ld a, [hli] ; y
+ ld b, a
+ ld a, [hli] ; x
+ ld c, a
+ ld a, [hli] ; pal
+ ld [wTrainerCardBadgeAttributes], a
+ ld a, [wTrainerCardBadgeFrameCounter]
+ add l
+ ld l, a
+ ld a, 0
+ adc h
+ ld h, a
+ ld a, [hl]
+ ld [wTrainerCardBadgeTileID], a
+ call .PrepOAM
+ pop hl
+.skip_badge
+ ld bc, $b ; 3 + 2 * 4
+ add hl, bc
+ pop bc
+ dec b
+ jr nz, .loop
+ ret
+
+.PrepOAM: ; 2547b (9:547b)
+ ld a, [wTrainerCardBadgeTileID]
+ and 1 << 7
+ jr nz, .xflip
+ ld hl, .facing1
+ jr .loop2
+
+.xflip
+ ld hl, .facing2
+.loop2
+ ld a, [hli]
+ cp -1
+ ret z
+ add b
+ ld [de], a ; y
+ inc de
+
+ ld a, [hli]
+ add c
+ ld [de], a ; x
+ inc de
+
+ ld a, [wTrainerCardBadgeTileID]
+ and $ff ^ (1 << 7)
+ add [hl]
+ ld [de], a ; tile id
+ inc hl
+ inc de
+
+ ld a, [wTrainerCardBadgeAttributes]
+ add [hl]
+ ld [de], a ; attributes
+ inc hl
+ inc de
+ jr .loop2
+
+; 254a7 (9:54a7)
+
+.facing1 ; 254a7
+ dsprite 0, 0, 0, 0, $00, 0
+ dsprite 0, 0, 1, 0, $01, 0
+ dsprite 1, 0, 0, 0, $02, 0
+ dsprite 1, 0, 1, 0, $03, 0
+ db -1
+
+.facing2 ; 254b8
+ dsprite 0, 0, 0, 0, $01, 0 | X_FLIP
+ dsprite 0, 0, 1, 0, $00, 0 | X_FLIP
+ dsprite 1, 0, 0, 0, $03, 0 | X_FLIP
+ dsprite 1, 0, 1, 0, $02, 0 | X_FLIP
+ db -1
+
+TrainerCard_JohtoBadgesOAM: ; 254c9
+; Template OAM data for each badge on the trainer card.
+; Format:
+ ; y, x, palette
+ ; cycle 1: face tile, in1 tile, in2 tile, in3 tile
+ ; cycle 2: face tile, in1 tile, in2 tile, in3 tile
+
+ dw wJohtoBadges
+
+ ; Zephyrbadge
+ db $68, $18, 0
+ db $00, $20, $24, $20 | (1 << 7)
+ db $00, $20, $24, $20 | (1 << 7)
+
+ ; Hivebadge
+ db $68, $38, 0
+ db $04, $20, $24, $20 | (1 << 7)
+ db $04, $20, $24, $20 | (1 << 7)
+
+ ; Plainbadge
+ db $68, $58, 0
+ db $08, $20, $24, $20 | (1 << 7)
+ db $08, $20, $24, $20 | (1 << 7)
+
+ ; Fogbadge
+ db $68, $78, 0
+ db $0c, $20, $24, $20 | (1 << 7)
+ db $0c, $20, $24, $20 | (1 << 7)
+
+ ; Mineralbadge
+ db $80, $38, 0
+ db $10, $20, $24, $20 | (1 << 7)
+ db $10, $20, $24, $20 | (1 << 7)
+
+ ; Stormbadge
+ db $80, $18, 0
+ db $14, $20, $24, $20 | (1 << 7)
+ db $14, $20, $24, $20 | (1 << 7)
+
+ ; Glacierbadge
+ db $80, $58, 0
+ db $18, $20, $24, $20 | (1 << 7)
+ db $18, $20, $24, $20 | (1 << 7)
+
+ ; Risingbadge
+ ; X-flips on alternate cycles.
+ db $80, $78, 0
+ db $1c, $20, $24, $20 | (1 << 7)
+ db $1c | (1 << 7), $20, $24, $20 | (1 << 7)
+; 25523
+
+CardStatusGFX: INCBIN "gfx/trainer_card/card_status.2bpp"
+
+LeaderGFX: INCBIN "gfx/trainer_card/leaders.2bpp"
+LeaderGFX2: INCBIN "gfx/trainer_card/leaders.2bpp"
+BadgeGFX: INCBIN "gfx/trainer_card/badges.2bpp"
+BadgeGFX2: INCBIN "gfx/trainer_card/badges.2bpp"
+
+CardRightCornerGFX: INCBIN "gfx/trainer_card/card_right_corner.2bpp"