; writes n items of text each given in the following format in hl:
; x coord, y coord, text id
; $ff-terminated
PlaceTextItems::
	ld d, [hl] ; x coord
	inc hl
	bit 7, d
	ret nz ; return if no more items of text
	ld e, [hl] ; y coord
	inc hl ; hl = text id
	call InitTextPrinting
	push hl
	call ProcessTextFromPointerToID
	pop hl
	inc hl
	inc hl
	jr PlaceTextItems ; do next item

; like ProcessTextFromID, except it calls InitTextPrinting first
InitTextPrinting_ProcessTextFromID::
	call InitTextPrinting
	jr ProcessTextFromID

; like ProcessTextFromPointerToID, except it calls InitTextPrinting first
InitTextPrinting_ProcessTextFromPointerToID::
	call InitTextPrinting
;	fallthrough

; like ProcessTextFromID below, except a memory address containing a text ID is
; provided in hl rather than the text ID directly.
ProcessTextFromPointerToID::
	ld a, [hli]
	or [hl]
	ret z
	ld a, [hld]
	ld l, [hl]
	ld h, a
;	fallthrough

; given the ID of a text in hl, reads the characters from it processes them.
; loops until TX_END is found. ignores TX_RAM1, TX_RAM2, and TX_RAM3 characters.
; restores original ROM bank before returning.
ProcessTextFromID::
	ldh a, [hBankROM]
	push af
	call GetTextOffsetFromTextID
	call ProcessText
	pop af
	call BankswitchROM
	ret

; return, in a, the number of lines of the text given in hl as an ID
; this is calculated by counting the amount of '\n' characters and adding 1 to the result
CountLinesOfTextFromID::
	push hl
	push de
	push bc
	ldh a, [hBankROM]
	push af
	call GetTextOffsetFromTextID
	ld c, $00
.char_loop
	ld a, [hli]
	or a ; TX_END
	jr z, .end
	cp TX_CTRL_END
	jr nc, .char_loop
	cp TX_HALFWIDTH
	jr c, .skip
	cp '\n'
	jr nz, .char_loop
	inc c
	jr .char_loop
.skip
	inc hl
	jr .char_loop
.end
	pop af
	call BankswitchROM
	ld a, c
	inc a
	pop bc
	pop de
	pop hl
	ret

; call PrintScrollableText with text box label, then wait for the
; player to press A or B to advance the printed text
PrintScrollableText_WithTextBoxLabel::
	call PrintScrollableText_WithTextBoxLabel_NoWait
	jr WaitForPlayerToAdvanceText

PrintScrollableText_WithTextBoxLabel_NoWait::
	push hl
	ld hl, wTextBoxLabel
	ld [hl], e
	inc hl
	ld [hl], d
	pop hl
	ld a, $01
	jr PrintScrollableText

; call PrintScrollableText with no text box label, then wait for the
; player to press A or B to advance the printed text
PrintScrollableText_NoTextBoxLabel::
	xor a
	call PrintScrollableText
;	fallthrough

; when a text box is full or the text is over, prompt the player to
; press A or B in order to clear the text and print the next lines.
WaitForPlayerToAdvanceText::
	lb bc, SYM_CURSOR_D, SYM_BOX_BOTTOM ; cursor tile, tile behind cursor
	lb de, 18, 17 ; x, y
	call SetCursorParametersForTextBox
	call WaitForButtonAorB
	ret

; draws a text box, and prints the text with id at hl, with letter delay. unlike PrintText,
; PrintScrollableText also supports scrollable text, and prompts the user to press A or B
; to advance the page or close the text. register a determines whether the textbox is
; labeled or not. if labeled, the text id of the label is provided in wTextBoxLabel.
; PrintScrollableText is used mostly for overworld NPC text.
PrintScrollableText::
	ld [wIsTextBoxLabeled], a
	ldh a, [hBankROM]
	push af
	call DrawTextReadyLabeledOrRegularTextBox
	ld a, l
	or h
	jr z, .asm_2cc3
	call GetTextOffsetFromTextID
	call ResetTxRam_WriteToTextHeader
.print_char_loop
	ld a, [wTextSpeed]
	ld c, a
	inc c
	jr .go
.nonzero_text_speed
	ld a, [wTextSpeed]
	cp 2
	jr nc, .apply_delay
	; if text speed is 1, pressing b ignores it
	ldh a, [hKeysHeld]
	and PAD_B
	jr nz, .skip_delay
.apply_delay
	push bc
	call DoFrame
	pop bc
.go
	dec c
	jr nz, .nonzero_text_speed
.skip_delay
	call ProcessTextHeader
	jr c, .asm_2cc3
	ld a, [wCurTextLine]
	cp 3
	jr c, .print_char_loop
	; two lines of text already printed, so need to advance text
	call WaitForPlayerToAdvanceText
	call DrawTextReadyLabeledOrRegularTextBox
	jr .print_char_loop
.asm_2cc3
	pop af
	call BankswitchROM
	ret

; zero wWhichTextHeader, wWhichTxRam2 and wWhichTxRam3, and set hJapaneseSyllabary to TX_KATAKANA
; fill wTextHeader1 with TX_KATAKANA, wFontWidth, hBankROM, and register bc for the text's pointer.
ResetTxRam_WriteToTextHeader::
	xor a
	ld [wWhichTextHeader], a
	ld [wWhichTxRam2], a
	ld [wWhichTxRam3], a
	ld a, TX_KATAKANA
	ldh [hJapaneseSyllabary], a
;	fallthrough

; fill the wTextHeader specified in wWhichTextHeader (0-3) with hJapaneseSyllabary,
; wFontWidth, hBankROM, and register bc for the text's pointer.
WriteToTextHeader::
	push hl
	call GetPointerToTextHeader
	pop bc
	ldh a, [hJapaneseSyllabary]
	ld [hli], a
	ld a, [wFontWidth]
	ld [hli], a
	ldh a, [hBankROM]
	ld [hli], a
	ld [hl], c
	inc hl
	ld [hl], b
	ret

; same as WriteToTextHeader, except it then increases wWhichTextHeader to
; set the next text header to the current one (usually, because
; it will soon be written to due to a TX_RAM command).
WriteToTextHeader_MoveToNext::
	call WriteToTextHeader
	ld hl, wWhichTextHeader
	inc [hl]
	ret

; read the wTextHeader specified in wWhichTextHeader (0-3) and use the data to
; populate the corresponding memory addresses. also switch to the text's rombank
; and return the address of the next character in hl.
ReadTextHeader::
	call GetPointerToTextHeader
	ld a, [hli]
	ldh [hJapaneseSyllabary], a
	ld a, [hli]
	ld [wFontWidth], a
	ld a, [hli]
	call BankswitchROM
	ld a, [hli]
	ld h, [hl]
	ld l, a
	ret

; return in hl, the address of the wTextHeader specified in wWhichTextHeader (0-3)
GetPointerToTextHeader::
	ld a, [wWhichTextHeader]
	ld e, a
	add a
	add a
	add e
	ld e, a
	ld d, $0
	ld hl, wTextHeader1
	add hl, de
	ret

; draws a wide text box with or without label depending on wIsTextBoxLabeled
; if labeled, the label's text ID is provided in wTextBoxLabel
; calls InitTextPrintingInTextbox after drawing the text box
DrawTextReadyLabeledOrRegularTextBox::
	push hl
	lb de, 0, 12
	lb bc, 20, 6
	call AdjustCoordinatesForBGScroll
	ld a, [wIsTextBoxLabeled]
	or a
	jr nz, .labeled
	call DrawRegularTextBox
	call EnableLCD
	jr .init_text
.labeled
	ld hl, wTextBoxLabel
	ld a, [hli]
	ld h, [hl]
	ld l, a
	call DrawLabeledTextBox
.init_text
	lb de, 1, 14
	call AdjustCoordinatesForBGScroll
	ld a, 19
	call InitTextPrintingInTextbox
	pop hl
	ret

; reads the incoming character from the current wTextHeader and processes it
; then updates the current wTextHeader to point to the next character.
; a TX_RAM command causes a switch to a wTextHeader in the level below, and a TX_END
; command terminates the text unless there is a pending wTextHeader in the above level.
ProcessTextHeader::
	call ReadTextHeader
	ld a, [hli]
	or a ; TX_END
	jr z, .tx_end
	cp TX_CTRL_START
	jr c, .character_pair
	cp TX_CTRL_END
	jr nc, .character_pair
	call ProcessSpecialTextCharacter
	jr nc, .processed_char
	cp TX_RAM1
	jr z, .tx_ram1
	cp TX_RAM2
	jr z, .tx_ram2
	cp TX_RAM3
	jr z, .tx_ram3
	jr .processed_char
.character_pair
	ld e, a ; first char
	ld d, [hl] ; second char
	call ClassifyTextCharacterPair
	jr nc, .not_tx_fullwidth
	inc hl
.not_tx_fullwidth
	call Func_22ca
	xor a
	call ProcessSpecialTextCharacter
.processed_char
	call WriteToTextHeader
	or a
	ret
.tx_end
	call TerminateHalfWidthText
	ld a, [wWhichTextHeader]
	or a
	jr z, .no_more_text
	; handle text header in the above level
	dec a
	ld [wWhichTextHeader], a
	jr ProcessTextHeader
.no_more_text
	scf
	ret
.tx_ram2
	call WriteToTextHeader_MoveToNext
	ld a, TX_KATAKANA
	ldh [hJapaneseSyllabary], a
	xor a ; FULL_WIDTH
	ld [wFontWidth], a
	ld de, wTxRam2
	ld hl, wWhichTxRam2
	call HandleTxRam2Or3
	ld a, l
	or h
	jr z, .empty
	call GetTextOffsetFromTextID
	call WriteToTextHeader
	jr ProcessTextHeader
.empty
	ld hl, wDefaultText
	call WriteToTextHeader
	jr ProcessTextHeader
.tx_ram3
	call WriteToTextHeader_MoveToNext
	ld de, wTxRam3
	ld hl, wWhichTxRam3
	call HandleTxRam2Or3
	call TwoByteNumberToText_CountLeadingZeros
	call WriteToTextHeader
	jp ProcessTextHeader
.tx_ram1
	call WriteToTextHeader_MoveToNext
	call CopyPlayerNameOrTurnDuelistName
	ld a, [wStringBuffer]
	cp TX_HALFWIDTH
	jr z, .tx_halfwidth
	ld a, TX_HALF2FULL
	call ProcessSpecialTextCharacter
.tx_halfwidth
	call WriteToTextHeader
	jp ProcessTextHeader

; input:
  ; de: wTxRam2 or wTxRam3
  ; hl: wWhichTxRam2 or wWhichTxRam3
; return, in hl, the contents of the contents of the
; wTxRam* buffer's current entry, and increment wWhichTxRam*.
HandleTxRam2Or3::
	push de
	ld a, [hl]
	inc [hl]
	add a
	ld e, a
	ld d, $0
	pop hl
	add hl, de
	ld a, [hli]
	ld h, [hl]
	ld l, a
	ret

; uses the two byte text id in hl to read the three byte text offset
; loads the correct bank for the specific text and returns the pointer in hl
GetTextOffsetFromTextID::
	push bc
	push de
	add hl, hl
	add hl, hl
	ld a, BANK(TextOffsets)
	call BankpushROM
	ld e, [hl]
	inc hl
	ld d, [hl]
	inc hl
	ld b, [hl]
	call BankpopROM
	ld a, b
	ld h, d
	rl h
	rla
	rl h
	rla
	add BANK(TextOffsets)
	call BankswitchROM
	res 7, d
	set 6, d ; $4000 ≤ de ≤ $7fff
	ld l, e
	ld h, d
	pop de
	pop bc
	ret

; if [wFontWidth] == HALF_WIDTH:
;   convert the number at hl to text (ascii) format and write it to wStringBuffer
;   return c = 4 - leading_zeros
; if [wFontWidth] == FULL_WIDTH:
;   convert the number at hl to TX_SYMBOL text format and write it to wStringBuffer
;   replace leading zeros with SYM_SPACE
TwoByteNumberToText_CountLeadingZeros::
	ld a, [wFontWidth]
	or a ; FULL_WIDTH
	jp z, TwoByteNumberToTxSymbol_TrimLeadingZeros
	ld de, wStringBuffer
	push de
	call TwoByteNumberToText
	pop hl
	ld c, 4
.digit_loop
	ld a, [hl]
	cp '0'
	ret nz
	inc hl
	dec c
	jr nz, .digit_loop
	ret

; in the overworld: copy the player's name to wStringBuffer
; in a duel: copy the name of the duelist whose turn it is to wStringBuffer
CopyPlayerNameOrTurnDuelistName::
	ld de, wStringBuffer
	push de
	ldh a, [hWhoseTurn]
	cp OPPONENT_TURN
	jp z, .opponent_turn
	call CopyPlayerName
	pop hl
	ret
.opponent_turn
	call CopyOpponentName
	pop hl
	ret

; prints text with id at hl, with letter delay, in a textbox area.
; the text must fit in the textbox; PrintScrollableText should be used instead.
PrintText::
	ld a, l
	or h
	jr z, .from_ram
	ldh a, [hBankROM]
	push af
	call GetTextOffsetFromTextID
	call .print_text
	pop af
	call BankswitchROM
	ret
.from_ram
	ld hl, wDefaultText
.print_text
	call ResetTxRam_WriteToTextHeader
.next_tile_loop
	ldh a, [hKeysHeld]
	ld b, a
	ld a, [wTextSpeed]
	inc a
	cp 3
	jr nc, .apply_delay
	; if text speed is 1, pressing b ignores it
	bit B_PAD_B, b
	jr nz, .skip_delay
	jr .apply_delay
.text_delay_loop
	; wait a number of frames equal to [wTextSpeed] between printing each text tile
	call DoFrame
.apply_delay
	dec a
	jr nz, .text_delay_loop
.skip_delay
	call ProcessTextHeader
	jr nc, .next_tile_loop
	ret

PrintTextNoDelay_Init::
	call InitTextPrinting
;	fallthrough

; prints text with id at hl, without letter delay, in a textbox area.
; the text must fit in the textbox; PrintScrollableText should be used instead.
PrintTextNoDelay::
	ldh a, [hBankROM]
	push af
	call GetTextOffsetFromTextID
	call ResetTxRam_WriteToTextHeader
.next_tile_loop
	call ProcessTextHeader
	jr nc, .next_tile_loop
	pop af
	call BankswitchROM
	ret

; hl = text ID
; de = coordinates
Func_2c4b::
	push hl
	push de
	call PrintTextNoDelay_Init
	pop de
	pop hl
	ldh a, [hffbb]
	or a
	ret nz
	ldh a, [hTextLineCurPos]
	call ZeroAttributesAtDE ; can be fallthrough
	ret

; a = number of zero bytes
; de = coordinates
ZeroAttributesAtDE::
	push hl
	push de
	push bc
	ld b, a
	ld a, l
	or h
	jr z, .null
	ld a, b
	ld b, d
	ld c, e
	ld hl, Zeroes
	call BankswitchVRAM1
	call CopyDataToBGMap0
	call BankswitchVRAM0
.null
	pop bc
	pop de
	pop hl
	ret

; copies a text given its id at hl, to de
; if hl is 0, the name of the turn duelist is copied instead
CopyText::
	ld a, l
	or h
	jr z, .special
	ldh a, [hBankROM]
	push af
	call GetTextOffsetFromTextID
.next_tile_loop
	ld a, [hli]
	ld [de], a
	inc de
	or a
	jr nz, .next_tile_loop
	pop af
	call BankswitchROM
	dec de
	ret
.special
	ldh a, [hWhoseTurn]
	cp OPPONENT_TURN
	jp z, CopyOpponentName
	jp CopyPlayerName

; copy text of maximum length a (in tiles) from its ID at hl to de,
; then terminate the text with TX_END if it doesn't contain it already.
; fill any remaining bytes with spaces plus TX_END to match the length specified in a.
; return the text's actual length in characters (i.e. before the first TX_END) in e.
CopyTextData_FromTextID::
	ldh [hff96], a
	ldh a, [hBankROM]
	push af
	call GetTextOffsetFromTextID
	ldh a, [hff96]
	call CopyTextData
	pop af
	call BankswitchROM
	ret

; text id (usually of a card name) for TX_RAM2
LoadTxRam2::
	ld a, l
	ld [wTxRam2], a
	ld a, h
	ld [wTxRam2 + 1], a
	ret

; a number between 0 and 65535 for TX_RAM3
LoadTxRam3::
	ld a, l
	ld [wTxRam3], a
	ld a, h
	ld [wTxRam3 + 1], a
	ret
