diff options
Diffstat (limited to 'src/home/print_text.asm')
-rw-r--r-- | src/home/print_text.asm | 543 |
1 files changed, 543 insertions, 0 deletions
diff --git a/src/home/print_text.asm b/src/home/print_text.asm new file mode 100644 index 0000000..455b03b --- /dev/null +++ b/src/home/print_text.asm @@ -0,0 +1,543 @@ +; 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 GetTextOffsetFromTextID + call DrawTextReadyLabeledOrRegularTextBox + 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 B_BUTTON + 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 + ld [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 + ld 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] + ld [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 + 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 + call TerminateHalfWidthText + scf + ret +.tx_ram2 + call WriteToTextHeader_MoveToNext + ld a, TX_KATAKANA + ld [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 de + ld e, l + ld d, h + add hl, hl + add hl, de + set 6, h ; hl = (hl * 3) + $4000 + ld a, BANK(TextOffsets) + call BankswitchROM + ld e, [hl] + inc hl + ld d, [hl] + inc hl + ld a, [hl] + 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 + 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_BUTTON_F, 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 + +; 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 + +; 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 |