; initializes parameters for a card list (e.g. list of hand cards in a duel, or booster pack cards)
; input:
   ; a = list length
   ; de = initial page scroll offset, initial item (in the visible page)
   ; hl: 9 bytes with the rest of the parameters
InitializeCardListParameters::
	ld [wNumListItems], a
	ld a, d
	ld [wListScrollOffset], a
	ld a, e
	ld [wCurMenuItem], a
	add d
	ldh [hCurScrollMenuItem], a
	ld a, [hli]
	ld [wCursorXPosition], a
	ld a, [hli]
	ld [wCursorYPosition], a
	ld a, [hli]
	ld [wListItemXPosition], a
	ld a, [hli]
	ld [wListItemNameMaxLength], a
	ld a, [hli]
	ld [wNumScrollMenuItems], a
	ld a, [hli]
	ld [wCursorTile], a
	ld a, [hli]
	ld [wTileBehindCursor], a
	ld a, [hli]
	ld [wListFunctionPointer], a
	ld a, [hli]
	ld [wListFunctionPointer + 1], a
	xor a
	ld [wCursorBlinkCounter], a
	ld a, 1
	ld [wYDisplacementBetweenMenuItems], a
	ret

; similar to HandleMenuInput, but conveniently returns parameters related to the
; state of the list in a, d, and e if A or B were pressed. also returns carry
; if A or B were pressed, nc otherwise. returns -1 in a if B was pressed.
; used for example in the Hand card list and Discard Pile card list screens.
HandleCardListInput::
	call HandleMenuInput
	ret nc
	ld a, [wListScrollOffset]
	ld d, a
	ld a, [wCurMenuItem]
	ld e, a
	ldh a, [hCurScrollMenuItem]
	scf
	ret

; initializes parameters for a menu, given the 8 bytes starting at hl,
; which are loaded to the following addresses:
;	wCursorXPosition, wCursorYPosition, wYDisplacementBetweenMenuItems, wNumScrollMenuItems,
;	wCursorTile, wTileBehindCursor, wMenuFunctionPointer.
; also sets the current menu item (wCurMenuItem) to the one specified in register a.
InitializeMenuParameters::
	ld [wCurMenuItem], a
	ldh [hCurScrollMenuItem], a
	ld de, wCursorXPosition
	ld b, wMenuFunctionPointer + $2 - wCursorXPosition
.loop
	ld a, [hli]
	ld [de], a
	inc de
	dec b
	jr nz, .loop
	xor a
	ld [wCursorBlinkCounter], a
	ret

; returns with the carry flag set if A or B were pressed
; returns a = 0 if A was pressed, a = -1 if B was pressed
; note: return values still subject to those of the function at [wMenuFunctionPointer] if any
HandleMenuInput::
	xor a
	ld [wRefreshMenuCursorSFX], a
	ldh a, [hDPadHeld]
	or a
	jr z, .up_down_done
	ld b, a
	ld a, [wNumScrollMenuItems]
	ld c, a
	ld a, [wCurMenuItem]
	bit B_PAD_UP, b
	jr z, .not_up
	dec a
	bit 7, a
	jr z, .handle_up_or_down
	ld a, [wNumScrollMenuItems]
	dec a ; wrapping around, so load the bottommost item
	jr .handle_up_or_down
.not_up
	bit B_PAD_DOWN, b
	jr z, .up_down_done
	inc a
	cp c
	jr c, .handle_up_or_down
	xor a ; wrapping around, so load the topmost item
.handle_up_or_down
	push af
	ld a, SFX_CURSOR
	ld [wRefreshMenuCursorSFX], a ; buffer sound for up/down
	call EraseCursor
	pop af
	ld [wCurMenuItem], a
	xor a
	ld [wCursorBlinkCounter], a
.up_down_done
	ld a, [wCurMenuItem]
	ldh [hCurScrollMenuItem], a
	ld hl, wMenuFunctionPointer ; call the function if non-0 (periodically)
	ld a, [hli]
	or [hl]
	jr z, .check_A_or_B
	ld a, [hld]
	ld l, [hl]
	ld h, a
	ldh a, [hCurScrollMenuItem]
	call CallHL
	jr nc, RefreshMenuCursor_CheckPlaySFX
.A_pressed_draw_cursor
	call DrawCursor2
.A_pressed
	call PlayOpenOrExitScreenSFX
	ld a, [wCurMenuItem]
	ld e, a
	ldh a, [hCurScrollMenuItem]
	scf
	ret
.check_A_or_B
	ldh a, [hKeysPressed]
	and PAD_A | PAD_B
	jr z, RefreshMenuCursor_CheckPlaySFX
	and PAD_A
	jr nz, .A_pressed_draw_cursor
	; B button pressed
	ld a, [wCurMenuItem]
	ld e, a
	ld a, MENU_CANCEL
	ldh [hCurScrollMenuItem], a
	call PlayOpenOrExitScreenSFX
	scf
	ret

; if [hCurScrollMenuItem] = MENU_CANCEL (exit), play SFX_CANCEL,
; otherwise (open) SFX_CONFIRM
PlayOpenOrExitScreenSFX::
	push af
	ldh a, [hCurScrollMenuItem]
	inc a
	jr z, .play_exit_sfx
	ld a, SFX_CONFIRM
	jr .play_sfx
.play_exit_sfx
	ld a, SFX_CANCEL
.play_sfx
	call PlaySFX
	pop af
	ret

; called once per frame when a menu is open
; play the sound effect at wRefreshMenuCursorSFX if non-0 and blink the
; cursor when wCursorBlinkCounter hits 16 (i.e. every 16 frames)
RefreshMenuCursor_CheckPlaySFX::
	ld a, [wRefreshMenuCursorSFX]
	or a
	jr z, RefreshMenuCursor
	call PlaySFX
;	fallthrough

RefreshMenuCursor::
	ld hl, wCursorBlinkCounter
	ld a, [hl]
	inc [hl]
; blink the cursor every 16 frames
	and $f
	ret nz
	ld a, [wCursorTile]
	bit 4, [hl]
	jr z, DrawCursor
;	fallthrough

; set the tile at [wCursorXPosition],[wCursorYPosition] to [wTileBehindCursor]
EraseCursor::
	ld a, [wTileBehindCursor]
;	fallthrough

; set the tile at [wCursorXPosition],[wCursorYPosition] to a
DrawCursor::
	ld c, a
	ld a, [wYDisplacementBetweenMenuItems]
	ld l, a
	ld a, [wCurMenuItem]
	ld h, a
	call HtimesL
	ld a, l
	ld hl, wCursorXPosition
	ld d, [hl]
	inc hl
	add [hl]
	ld e, a
	call AdjustCoordinatesForBGScroll
	ld a, c
	ld c, e
	ld b, d
	call WriteByteToBGMap0
	or a
	ret

; set the tile at [wCursorXPosition],[wCursorYPosition] to [wCursorTile]
DrawCursor2::
	ld a, [wCursorTile]
	jr DrawCursor

; set wCurMenuItem, and hCurScrollMenuItem to a, and zero wCursorBlinkCounter
SetMenuItem::
	ld [wCurMenuItem], a
	ldh [hCurScrollMenuItem], a
	xor a
	ld [wCursorBlinkCounter], a
	ret

; handle input for the 2-row 3-column duel menu.
; only handles input not involving the B, START, or SELECT buttons, that is,
; navigating through the menu or selecting an item with the A button.
; other input in handled by PrintDuelMenuAndHandleInput.handle_input
HandleDuelMenuInput::
	ldh a, [hDPadHeld]
	or a
	jr z, .blink_cursor
	ld b, a
	ld hl, wCurMenuItem
	and PAD_UP | PAD_DOWN
	jr z, .check_left
	ld a, [hl]
	xor 1 ; move to the other menu item in the same column
	jr .dpad_pressed
.check_left
	bit B_PAD_LEFT, b
	jr z, .check_right
	ld a, [hl]
	sub 2
	jr nc, .dpad_pressed
	; wrap to the rightmost item in the same row
	and 1
	add 4
	jr .dpad_pressed
.check_right
	bit B_PAD_RIGHT, b
	jr z, .dpad_not_pressed
	ld a, [hl]
	add 2
	cp 6
	jr c, .dpad_pressed
	; wrap to the leftmost item in the same row
	and 1
.dpad_pressed
	push af
	ld a, SFX_CURSOR
	call PlaySFX
	call .erase_cursor
	pop af
	ld [wCurMenuItem], a
	ldh [hCurScrollMenuItem], a
	xor a
	ld [wCursorBlinkCounter], a
	jr .blink_cursor
.dpad_not_pressed
	ldh a, [hDPadHeld]
	and PAD_A
	jp nz, HandleMenuInput.A_pressed
.blink_cursor
	; blink cursor every 16 frames
	ld hl, wCursorBlinkCounter
	ld a, [hl]
	inc [hl]
	and $f
	ret nz
	ld a, SYM_CURSOR_R
	bit 4, [hl]
	jr z, .draw_cursor
.erase_cursor
	ld a, SYM_SPACE
.draw_cursor
	ld e, a
	ld a, [wCurMenuItem]
	add a
	ld c, a
	ld b, $0
	ld hl, DuelMenuCursorCoords
	add hl, bc
	ld b, [hl]
	inc hl
	ld c, [hl]
	ld a, e
	call WriteByteToBGMap0
	ld a, [wCurMenuItem]
	ld e, a
	or a
	ret

DuelMenuCursorCoords::
	db  2, 14 ; Hand
	db  2, 16 ; Attack
	db  8, 14 ; Check
	db  8, 16 ; Pkmn Power
	db 14, 14 ; Retreat
	db 14, 16 ; Done

; print the items of a list of cards (hand cards in a duel, cards from a booster pack...)
; and initialize the parameters of the list given:
  ; wDuelTempList = card list source
  ; a = list length
  ; de = initial page scroll offset, initial item (in the visible page)
  ; hl: 9 bytes with the rest of the parameters
PrintCardListItems::
	call InitializeCardListParameters
	ld hl, wMenuFunctionPointer
	ld a, LOW(CardListMenuFunction)
	ld [hli], a
	ld a, HIGH(CardListMenuFunction)
	ld [hli], a
	ld a, 2
	ld [wYDisplacementBetweenMenuItems], a
	ld a, 1
	ld [wCardListIndicatorYPosition], a
;	fallthrough

; like PrintCardListItems, except more parameters are already initialized
; called instead of PrintCardListItems to reload the list after moving up or down
ReloadCardListItems::
	ld e, SYM_SPACE
	ld a, [wListScrollOffset]
	or a
	jr z, .cant_go_up
	ld e, SYM_CURSOR_U
.cant_go_up
	ld a, [wCursorYPosition]
	dec a
	ld c, a
	ld b, 18
	ld a, e
	call WriteByteToBGMap0
	ld e, SYM_SPACE
	ld a, [wListScrollOffset]
	ld hl, wNumScrollMenuItems
	add [hl]
	ld hl, wNumListItems
	cp [hl]
	jr nc, .cant_go_down
	ld e, SYM_CURSOR_D
.cant_go_down
	ld a, [wNumScrollMenuItems]
	add a
	add c
	dec a
	ld c, a
	ld a, e
	call WriteByteToBGMap0
	ld a, [wListScrollOffset]
	ld e, a
	ld d, $00
	ld hl, wDuelTempList
	add hl, de
	ld a, [wNumScrollMenuItems]
	ld b, a
	ld a, [wListItemXPosition]
	ld d, a
	ld a, [wCursorYPosition]
	ld e, a
	ld c, $00
.next_card
	ld a, [hl]
	cp $ff
	jr z, .done
	push hl
	push bc
	push de
	call LoadCardDataToBuffer1_FromDeckIndex
	call DrawCardSymbol
	call InitTextPrinting
	ld a, [wListItemNameMaxLength]
	call CopyCardNameAndLevel
	ld hl, wDefaultText
	call ProcessText
	pop de
	pop bc
	pop hl
	inc hl
	ld a, [wNumListItems]
	dec a
	inc c
	cp c
	jr c, .done
	inc e
	inc e
	dec b
	jr nz, .next_card
.done
	ret

; reload a list of cards, except don't print their names
Func_2827::
	ld a, $01
	ldh [hffbb], a
	call ReloadCardListItems
	xor a
	ldh [hffbb], a
	ret

; convert the number at a to TX_SYMBOL text format and write it to wDefaultText
; if the first digit is a 0, delete it and shift the number one tile to the left
OneByteNumberToTxSymbol_TrimLeadingZerosAndAlign::
	call OneByteNumberToTxSymbol
	ld a, [hli]
	cp SYM_0
	jr nz, .not_zero
	; shift number one tile to the left
	ld a, [hld]
	ld [hli], a
	ld [hl], SYM_SPACE
.not_zero
	ret

; this function is always loaded to wMenuFunctionPointer by PrintCardListItems
; takes care of things like handling page scrolling and calling the function at wListFunctionPointer
CardListMenuFunction::
	ldh a, [hDPadHeld]
	ld b, a
	ld a, [wNumScrollMenuItems]
	dec a
	ld c, a
	ld a, [wCurMenuItem]
	bit B_PAD_UP, b
	jr z, .not_up
	cp c
	jp nz, .continue
	; we're at the top of the page
	xor a
	ld [wCurMenuItem], a ; set to first item
	ld hl, wListScrollOffset
	ld a, [hl]
	or a ; can we scroll up?
	jr z, .no_more_items
	dec [hl] ; scroll page up
	call ReloadCardListItems
	jp .continue
.not_up
	bit B_PAD_DOWN, b
	jr z, .not_down
	or a
	jr nz, .not_last_visible_item
	; we're at the bottom of the page
	ld a, c
	ld [wCurMenuItem], a ; set to last item
	ld a, [wListScrollOffset]
	add c
	inc a
	ld hl, wNumListItems
	cp [hl] ; can we scroll down?
	jr z, .no_more_items
	ld hl, wListScrollOffset
	inc [hl] ; scroll page down
	call ReloadCardListItems
	jp .continue
.not_last_visible_item
	; this appears to be a redundant check
	ld hl, wListScrollOffset
	add [hl]
	ld hl, wNumListItems
	cp [hl]
	jp c, .continue ; should always jump
	ld hl, wCurMenuItem
	dec [hl]
.no_more_items
	xor a
	ld [wRefreshMenuCursorSFX], a
	jp .continue
.not_down
	bit B_PAD_LEFT, b
	jr z, .not_left
	ld a, [wListScrollOffset]
	or a
	jr z, .continue
	ld hl, wNumScrollMenuItems
	sub [hl]
	jr c, .top_of_page_reached
	ld [wListScrollOffset], a
	call ReloadCardListItems
	jr .continue
.top_of_page_reached
	call EraseCursor
	ld a, [wListScrollOffset]
	ld hl, wCurMenuItem
	add [hl]
	ld c, a
	ld hl, wNumScrollMenuItems
	sub [hl]
	jr nc, .asm_28c4
	add [hl]
.asm_28c4
	ld [wCurMenuItem], a
	xor a
	ld [wListScrollOffset], a
	ld [wRefreshMenuCursorSFX], a
	call ReloadCardListItems
	jr .continue
.not_left
	bit B_PAD_RIGHT, b
	jr z, .continue
	ld a, [wNumScrollMenuItems]
	ld hl, wNumListItems
	cp [hl]
	jr nc, .continue
	ld a, [wListScrollOffset]
	ld hl, wNumScrollMenuItems
	add [hl]
	ld c, a
	add [hl]
	dec a
	ld hl, wNumListItems
	cp [hl]
	jr nc, .asm_28f9
	ld a, c
	ld [wListScrollOffset], a
	call ReloadCardListItems
	jr .continue
.asm_28f9
	call EraseCursor
	ld a, [wListScrollOffset]
	ld hl, wCurMenuItem
	add [hl]
	ld c, a
	ld a, [wNumListItems]
	ld hl, wNumScrollMenuItems
	sub [hl]
	ld [wListScrollOffset], a
	ld b, a
	ld a, c
	sub b
	jr nc, .asm_2914
	add [hl]
.asm_2914
	ld [wCurMenuItem], a
	call ReloadCardListItems
.continue
	ld a, [wListScrollOffset]
	ld hl, wCurMenuItem
	add [hl]
	ldh [hCurScrollMenuItem], a
	ld a, [wCardListIndicatorYPosition]
	cp $ff
	jr z, .skip_printing_indicator
	; print <sel_item>/<num_items>
	ld c, a
	ldh a, [hCurScrollMenuItem]
	inc a
	call OneByteNumberToTxSymbol_TrimLeadingZeros
	ld b, 14
	ld a, 2
	call CopyDataToBGMap0
	ld b, 16
	ld a, SYM_SLASH
	call WriteByteToBGMap0
	ld a, [wNumListItems]
	call OneByteNumberToTxSymbol_TrimLeadingZeros
	ld b, 17
	ld a, 2
	call CopyDataToBGMap0
.skip_printing_indicator
	ld hl, wListFunctionPointer
	ld a, [hli]
	or [hl]
	jr z, .no_list_function
	ld a, [hld]
	ld l, [hl]
	ld h, a
	ldh a, [hCurScrollMenuItem]
	jp hl ; execute the function at wListFunctionPointer
.no_list_function
	ldh a, [hKeysPressed]
	and PAD_A | PAD_B
	ret z
	and PAD_B
	jr nz, .pressed_b
	scf
	ret
.pressed_b
	ld a, $ff
	ldh [hCurScrollMenuItem], a
	scf
	ret

; convert the number at a to TX_SYMBOL text format and write it to wDefaultText
; replace leading zeros with SYM_SPACE
OneByteNumberToTxSymbol_TrimLeadingZeros::
	call OneByteNumberToTxSymbol
	ld a, [hl]
	cp SYM_0
	ret nz
	ld [hl], SYM_SPACE
	ret

; convert the number at a to TX_SYMBOL text format and write it to wDefaultText
OneByteNumberToTxSymbol::
	ld hl, wDefaultText
	push hl
	ld e, SYM_0 - 1
.first_digit_loop
	inc e
	sub 10
	jr nc, .first_digit_loop
	ld [hl], e ; first digit
	inc hl
	add SYM_0 + 10
	ld [hli], a ; second digit
	ld [hl], SYM_SPACE
	pop hl
	ret

; translate the TYPE_* constant in wLoadedCard1Type to an index for CardSymbolTable
CardTypeToSymbolID::
	ld a, [wLoadedCard1Type]
	cp TYPE_TRAINER
	jr nc, .trainer_card
	cp TYPE_ENERGY
	jr c, .pokemon_card
	; energy card
	and 7 ; convert energy constant to type constant
	ret
.trainer_card
	ld a, 11
	ret
.pokemon_card
	ld a, [wLoadedCard1Stage] ; different symbol for each evolution stage
	add 8
	ret

; return the entry in CardSymbolTable of the TYPE_* constant in wLoadedCard1Type
; also return the first byte of said entry (starting tile number) in a
GetCardSymbolData::
	call CardTypeToSymbolID
	add a
	ld c, a
	ld b, 0
	ld hl, CardSymbolTable
	add hl, bc
	ld a, [hl]
	ret

; draw, at de, the 2x2 tile card symbol associated to the TYPE_* constant in wLoadedCard1Type
DrawCardSymbol::
	push hl
	push de
	push bc
	call GetCardSymbolData
	dec d
	dec d
	dec e
	ld a, [wConsole]
	cp CONSOLE_CGB
	jr nz, .tiles
	; CGB-only attrs (palette)
	push hl
	inc hl
	ld a, [hl]
	lb bc, 2, 2
	lb hl, 0, 0
	call BankswitchVRAM1
	call FillRectangle
	call BankswitchVRAM0
	pop hl
.tiles
	ld a, [hl]
	lb hl, 1, 2
	lb bc, 2, 2
	call FillRectangle
	pop bc
	pop de
	pop hl
	ret

CardSymbolTable::
; starting tile number, cgb palette (grey, yellow/red, green/blue, pink/orange)
	db $e0, $02 ; TYPE_ENERGY_FIRE
	db $e4, $03 ; TYPE_ENERGY_GRASS
	db $e8, $02 ; TYPE_ENERGY_LIGHTNING
	db $ec, $03 ; TYPE_ENERGY_WATER
	db $f0, $04 ; TYPE_ENERGY_PSYCHIC
	db $f4, $04 ; TYPE_ENERGY_FIGHTING
	db $f8, $00 ; TYPE_ENERGY_DOUBLE_COLORLESS
	db $fc, $03 ; TYPE_ENERGY_UNUSED
	db $d0, $03 ; TYPE_PKMN_*, Basic
	db $d4, $03 ; TYPE_PKMN_*, Stage 1
	db $d8, $02 ; TYPE_PKMN_*, Stage 2
	db $dc, $03 ; TYPE_TRAINER

; copy the name and level of the card at wLoadedCard1 to wDefaultText
; a = length in number of tiles (the resulting string will be padded with spaces to match it)
CopyCardNameAndLevel::
	push bc
	push de
	ld c, a
	ld a, [wLoadedCard1Type]
	cp TYPE_ENERGY
	jr nc, .level_done ; jump if energy or trainer
	ld a, [wLoadedCard1Level]
	or a
	jr z, .level_done
	inc c
	inc c
	ld a, [wLoadedCard1Level]
	cp 10
	jr c, .level_done
	inc c ; second digit
.level_done
	ld hl, wLoadedCard1Name
	ld a, [hli]
	ld h, [hl]
	ld l, a
	ld de, wDefaultText
	push de
	call CopyText
	pop hl
	push de
	ld e, c
	call GetTextLengthInTiles
	add e
	ld c, a
	pop hl
	push hl
.fill_loop
	ld a, $70
	ld [hli], a
	dec c
	jr nz, .fill_loop
	ld [hl], TX_END
	pop hl
	ld a, [wLoadedCard1Type]
	cp TYPE_ENERGY
	jr nc, .done
	ld a, [wLoadedCard1Level]
	or a
	jr z, .done
	ld a, TX_SYMBOL
	ld [hli], a
	ld [hl], SYM_Lv
	inc hl
	ld a, [wLoadedCard1Level]
	cp 10
	jr c, .one_digit
	ld [hl], TX_SYMBOL
	inc hl
	ld b, SYM_0 - 1
.first_digit_loop
	inc b
	sub 10
	jr nc, .first_digit_loop
	add 10
	ld [hl], b ; first digit
	inc hl
.one_digit
	ld [hl], TX_SYMBOL
	inc hl
	add SYM_0
	ld [hl], a ; last (or only) digit
	inc hl
.done
	pop de
	pop bc
	ret

; sets cursor parameters for navigating in a text box, but using
; default values for the cursor tile (SYM_CURSOR_R) and the tile behind it (SYM_SPACE).
; d,e: coordinates of the cursor
SetCursorParametersForTextBox_Default::
	lb bc, SYM_CURSOR_R, SYM_SPACE ; cursor tile, tile behind cursor
	call SetCursorParametersForTextBox
;	fallthrough

; wait until A or B is pressed.
; return carry if A is pressed, nc if B is pressed. erase the cursor either way
WaitForButtonAorB::
	call DoFrame
	call RefreshMenuCursor
	ldh a, [hKeysPressed]
	bit B_PAD_A, a
	jr nz, .a_pressed
	bit B_PAD_B, a
	jr z, WaitForButtonAorB
	call EraseCursor
	scf
	ret
.a_pressed
	call EraseCursor
	or a
	ret

; sets cursor parameters for navigating in a text box
; d,e: coordinates of the cursor
; b,c: tile numbers of the cursor and of the tile behind it
SetCursorParametersForTextBox::
	xor a
	ld hl, wCurMenuItem
	ld [hli], a
	ld [hl], d ; wCursorXPosition
	inc hl
	ld [hl], e ; wCursorYPosition
	inc hl
	ld [hl], 0 ; wYDisplacementBetweenMenuItems
	inc hl
	ld [hl], 1 ; wNumScrollMenuItems
	inc hl
	ld [hl], b ; wCursorTile
	inc hl
	ld [hl], c ; wTileBehindCursor
	ld [wCursorBlinkCounter], a
	ret

; draw a 20x6 text box aligned to the bottom of the screen,
; print the text at hl without letter delay, and wait for A or B pressed
DrawWideTextBox_PrintTextNoDelay_Wait::
	call DrawWideTextBox_PrintTextNoDelay
	jp WaitForWideTextBoxInput

; draw a 20x6 text box aligned to the bottom of the screen
; and print the text at hl without letter delay
DrawWideTextBox_PrintTextNoDelay::
	push hl
	call DrawWideTextBox
	ld a, 19
	jr DrawTextBox_PrintTextNoDelay

; draw a 12x6 text box aligned to the bottom left of the screen
; and print the text at hl without letter delay
DrawNarrowTextBox_PrintTextNoDelay::
	push hl
	call DrawNarrowTextBox
	ld a, 11
;	fallthrough

DrawTextBox_PrintTextNoDelay::
	lb de, 1, 14
	call AdjustCoordinatesForBGScroll
	call InitTextPrintingInTextbox
	pop hl
	ld a, l
	or h
	jp nz, PrintTextNoDelay
	ld hl, wDefaultText
	jp ProcessText

; draw a 20x6 text box aligned to the bottom of the screen
; and print the text at hl with letter delay
DrawWideTextBox_PrintText::
	push hl
	call DrawWideTextBox
	ld a, 19
	lb de, 1, 14
	call AdjustCoordinatesForBGScroll
	call InitTextPrintingInTextbox
	call EnableLCD
	pop hl
	jp PrintText

; draw a 12x6 text box aligned to the bottom left of the screen
DrawNarrowTextBox::
	lb de, 0, 12
	lb bc, 12, 6
	call AdjustCoordinatesForBGScroll
	call DrawRegularTextBox
	ret

; draw a 12x6 text box aligned to the bottom left of the screen,
; print the text at hl without letter delay, and wait for A or B pressed
DrawNarrowTextBox_WaitForInput::
	call DrawNarrowTextBox_PrintTextNoDelay
	xor a
	ld hl, NarrowTextBoxMenuParameters
	call InitializeMenuParameters
	call EnableLCD
.wait_A_or_B_loop
	call DoFrame
	call RefreshMenuCursor
	ldh a, [hKeysPressed]
	and PAD_A | PAD_B
	jr z, .wait_A_or_B_loop
	ret

NarrowTextBoxMenuParameters::
	menu_params 10, 17, 1, 1, SYM_CURSOR_D, SYM_BOX_BOTTOM, NULL

; draw a 20x6 text box aligned to the bottom of the screen
DrawWideTextBox::
	lb de, 0, 12
	lb bc, 20, 6
	call AdjustCoordinatesForBGScroll
	call DrawRegularTextBox
	ret

; draw a 20x6 text box aligned to the bottom of the screen,
; print the text at hl with letter delay, and wait for A or B pressed
DrawWideTextBox_WaitForInput::
	call DrawWideTextBox_PrintText
;	fallthrough

; wait for A or B to be pressed on a wide (20x6) text box
WaitForWideTextBoxInput::
	xor a
	ld hl, WideTextBoxMenuParameters
	call InitializeMenuParameters
	call EnableLCD
.wait_A_or_B_loop
	call DoFrame
	call RefreshMenuCursor
	ldh a, [hKeysPressed]
	and PAD_A | PAD_B
	jr z, .wait_A_or_B_loop
	call EraseCursor
	ret

WaitForWideTextBoxInput_AdvanceRNG::
	xor a
	ld hl, WideTextBoxMenuParameters
	call InitializeMenuParameters
	call EnableLCD
.wait_A_or_B_loop
	call DoFrame
	call UpdateRNGSources
	call RefreshMenuCursor
	ldh a, [hKeysPressed]
	and PAD_A | PAD_B
	jr z, .wait_A_or_B_loop
	call EraseCursor
	ret

WideTextBoxMenuParameters::
	menu_params 18, 17, 1, 1, SYM_CURSOR_D, SYM_BOX_BOTTOM, NULL

; display a two-item horizontal menu with custom text provided in hl and handle input
TwoItemHorizontalMenu::
	call DrawWideTextBox_PrintText
	lb de, 6, 16 ; x, y
	ld a, d
	ld [wLeftmostItemCursorX], a
	lb bc, SYM_CURSOR_R, SYM_SPACE ; cursor tile, tile behind cursor
	call SetCursorParametersForTextBox
	ld a, 1
	ld [wCurMenuItem], a
	call EnableLCD
	jp HandleYesOrNoMenu.refresh_menu

YesOrNoMenuWithText_SetCursorToYes::
	ld a, $01
	ld [wDefaultYesOrNo], a
;	fallthrough

; display a yes / no menu in a 20x8 textbox with custom text provided in hl and handle input
; wDefaultYesOrNo determines whether the cursor initially points to YES or to NO
; returns carry if "no" selected
YesOrNoMenuWithText::
	call DrawWideTextBox_PrintText
;	fallthrough

; prints the YES / NO menu items at coordinates x,y = 7,16 and handles input
; input: wDefaultYesOrNo. returns carry if "no" selected
YesOrNoMenu::
	lb de, 7, 16 ; x, y
	call PrintYesOrNoItems
	lb de, 6, 16 ; x, y
	jr HandleYesOrNoMenu

; prints the YES / NO menu items at coordinates x,y = 3,16 and handles input
; input: wDefaultYesOrNo. returns carry if "no" selected
YesOrNoMenuWithText_LeftAligned::
	call DrawNarrowTextBox_PrintTextNoDelay
	lb de, 3, 16 ; x, y
	call PrintYesOrNoItems
	lb de, 2, 16 ; x, y
;	fallthrough

HandleYesOrNoMenu::
	ld a, d
	ld [wLeftmostItemCursorX], a
	lb bc, SYM_CURSOR_R, SYM_SPACE ; cursor tile, tile behind cursor
	call SetCursorParametersForTextBox
	ld a, [wDefaultYesOrNo]
	ld [wCurMenuItem], a
	call EnableLCD
	jr .refresh_menu
.wait_button_loop
	call DoFrame
	call RefreshMenuCursor
	ldh a, [hKeysPressed]
	bit B_PAD_A, a
	jr nz, .a_pressed
	ldh a, [hDPadHeld]
	and PAD_RIGHT | PAD_LEFT
	jr z, .wait_button_loop
	; left or right pressed, so switch to the other menu item
	ld a, SFX_CURSOR
	call PlaySFX
	call EraseCursor
.refresh_menu
	ld a, [wLeftmostItemCursorX]
	ld c, a
	; default to the second option (NO)
	ld hl, wCurMenuItem
	ld a, [hl]
	xor $1
	ld [hl], a
	; x separation between left and right items is 4 tiles
	add a
	add a
	add c
	ld [wCursorXPosition], a
	xor a
	ld [wCursorBlinkCounter], a
	jr .wait_button_loop
.a_pressed
	ld a, [wCurMenuItem]
	ldh [hCurScrollMenuItem], a
	or a
	jr nz, .no
;.yes
	ld [wDefaultYesOrNo], a ; 0
	ret
.no
	xor a
	ld [wDefaultYesOrNo], a ; 0
	ld a, 1
	ldh [hCurScrollMenuItem], a
	scf
	ret

; prints "YES NO" at de
PrintYesOrNoItems::
	call AdjustCoordinatesForBGScroll
	ldtx hl, YesOrNoText
	call InitTextPrinting_ProcessTextFromID
	ret

BuildVersion::
	db "VER 1/18 14:36", TX_END
