diff options
Diffstat (limited to 'src/home/process_text.asm')
-rw-r--r-- | src/home/process_text.asm | 862 |
1 files changed, 862 insertions, 0 deletions
diff --git a/src/home/process_text.asm b/src/home/process_text.asm new file mode 100644 index 0000000..6845664 --- /dev/null +++ b/src/home/process_text.asm @@ -0,0 +1,862 @@ +; similar to ProcessText except it calls InitTextPrinting first +; with the first two bytes of hl being used to set hTextBGMap0Address. +; (the caller to ProcessText usually calls InitTextPrinting first) +InitTextPrinting_ProcessText: ; 21ba (0:21ba) + push de + push bc + ld d, [hl] + inc hl + ld e, [hl] + inc hl + call InitTextPrinting + jr ProcessText.next_char + +; reads the characters from the text at hl processes them. loops until +; TX_END is found. ignores TX_RAM1, TX_RAM2, and TX_RAM3 characters. +ProcessText: ; 21c5 (0:21c5) + push de + push bc + call InitTextFormat + jr .next_char +.char_loop + cp TX_CTRL_START + jr c, .character_pair + cp TX_CTRL_END + jr nc, .character_pair + call ProcessSpecialTextCharacter + jr .next_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 +.next_char + ld a, [hli] + or a + jr nz, .char_loop + ; TX_END + call TerminateHalfWidthText + pop bc + pop de + ret + +; processes the text character provided in a checking for specific control characters. +; hl points to the text character coming right after the one loaded into a. +; returns carry if the character was not processed by this function. +ProcessSpecialTextCharacter: ; 21f2 (0:21f2) + or a ; TX_END + jr z, .tx_end + cp TX_HIRAGANA + jr z, .set_syllabary + cp TX_KATAKANA + jr z, .set_syllabary + cp "\n" + jr z, .end_of_line + cp TX_SYMBOL + jr z, .tx_symbol + cp TX_HALFWIDTH + jr z, .tx_halfwidth + cp TX_HALF2FULL + jr z, .tx_half2full + scf + ret +.tx_halfwidth + ld a, HALF_WIDTH + ld [wFontWidth], a + ret +.tx_half2full + call TerminateHalfWidthText + xor a ; FULL_WIDTH + ld [wFontWidth], a + ld a, TX_KATAKANA + ldh [hJapaneseSyllabary], a + ret +.set_syllabary + ldh [hJapaneseSyllabary], a + xor a + ret +.tx_symbol + ld a, [wFontWidth] + push af + ld a, HALF_WIDTH + ld [wFontWidth], a + call TerminateHalfWidthText + pop af + ld [wFontWidth], a + ldh a, [hffb0] + or a + jr nz, .skip_placing_tile + ld a, [hl] + push hl + call PlaceNextTextTile + pop hl +.skip_placing_tile + inc hl +.tx_end + ldh a, [hTextLineLength] + or a + ret z + ld b, a + ldh a, [hTextLineCurPos] + cp b + jr z, .end_of_line + xor a + ret +.end_of_line + call TerminateHalfWidthText + ld a, [wLineSeparation] + or a + call z, .next_line +.next_line + xor a + ldh [hTextLineCurPos], a + ldh a, [hTextHorizontalAlign] + add BG_MAP_WIDTH + ld b, a + ; get current line's starting BGMap0 address + ldh a, [hTextBGMap0Address] + and $e0 + ; advance to next line + add b ; apply background scroll correction + ldh [hTextBGMap0Address], a + ldh a, [hTextBGMap0Address + 1] + adc $0 + ldh [hTextBGMap0Address + 1], a + ld a, [wCurTextLine] + inc a + ld [wCurTextLine], a + xor a + ret + +; calls InitTextFormat, selects tiles at $8800-$97FF for text, and clears the wc600. +; selects the first and last tile to be reserved for constructing text tiles in VRAM +; based on the values given in d and e respectively. +SetupText: ; 2275 (0:2275) + ld a, d + dec a + ld [wcd04], a + ld a, e + ldh [hffa8], a + call InitTextFormat + xor a + ldh [hffb0], a + ldh [hffa9], a + ld a, $88 + ld [wTilePatternSelector], a + ld a, $80 + ld [wTilePatternSelectorCorrection], a + ld hl, wc600 +.clear_loop + xor a + ld [hl], a + inc l + jr nz, .clear_loop + ret + +; wFontWidth <- FULL_WIDTH +; hTextLineCurPos <- 0 +; wHalfWidthPrintState <- 0 +; hJapaneseSyllabary <- TX_KATAKANA +InitTextFormat: ; 2298 (0:2298) + xor a ; FULL_WIDTH + ld [wFontWidth], a + ldh [hTextLineCurPos], a + ld [wHalfWidthPrintState], a + ld a, TX_KATAKANA + ldh [hJapaneseSyllabary], a + ret + +; call InitTextPrinting +; hTextLineLength <- a +InitTextPrintingInTextbox: ; 22a6 (0:22a6) + push af + call InitTextPrinting + pop af + ldh [hTextLineLength], a + ret + +; hTextHorizontalAlign <- d +; hTextLineLength <- 0 +; wCurTextLine <- 0 +; write BGMap0-translated DE to hTextBGMap0Address +; call InitTextFormat +InitTextPrinting: ; 22ae (0:22ae) + push hl + ld a, d + ldh [hTextHorizontalAlign], a + xor a + ldh [hTextLineLength], a + ld [wCurTextLine], a + call DECoordToBGMap0Address + ld a, l + ldh [hTextBGMap0Address], a + ld a, h + ldh [hTextBGMap0Address + 1], a + call InitTextFormat + xor a + ld [wHalfWidthPrintState], a + pop hl + ret + +; requests a text tile to be generated and prints it in the screen +; different modes depending on hffb0: + ; hffb0 == $0: generate and place text tile + ; hffb0 == $2 (bit 1 set): only generate text tile? + ; hffb0 == $1 (bit 0 set): not even generate it, but just update text buffers? +Func_22ca: ; 22ca (0:22ca) + push hl + push de + push bc + ldh a, [hffb0] + and $1 + jr nz, .asm_22ed + call Func_2325 + jr c, .tile_already_exists + or a + jr nz, .done + call GenerateTextTile +.tile_already_exists + ldh a, [hffb0] + and $2 + jr nz, .done + ldh a, [hffa9] + call PlaceNextTextTile +.done + pop bc + pop de + pop hl + ret +.asm_22ed + call Func_235e + jr .done + +; writes a to wCurTextTile and to the tile pointed to by hTextBGMap0Address, +; then increments hTextBGMap0Address and hTextLineCurPos +PlaceNextTextTile: ; 22f2 (0:22f2) + ld [wCurTextTile], a + ld hl, hTextBGMap0Address + ld e, [hl] + inc hl + ld d, [hl] + inc de + ld [hl], d + dec hl + ld [hl], e + dec de + ld l, e + ld h, d + ld de, wCurTextTile + ld c, 1 + call SafeCopyDataDEtoHL + ld hl, hTextLineCurPos + inc [hl] + ret + +; when terminating half-width text with "\n" or TX_END, or switching to full-width +; with TX_HALF2FULL or to symbols with TX_SYMBOL, check if it's necessary to append +; a half-width space to finish an incomplete character pair. +TerminateHalfWidthText: ; 230f (0:230f) + ld a, [wFontWidth] + or a ; FULL_WIDTH + ret z + ld a, [wHalfWidthPrintState] + or a + ret z ; return if the last printed character was the second of a pair + push hl + push de + push bc + ld e, " " + call Func_22ca + pop bc + pop de + pop hl + ret + +Func_2325: ; 2325 (0:2325) + call Func_235e + ret c + or a + ret nz + ldh a, [hffa8] + ld hl, wcd04 + cp [hl] + jr nz, .asm_2345 + ldh a, [hffa9] + ld h, $c8 +.asm_2337 + ld l, a + ld a, [hl] + or a + jr nz, .asm_2337 + ld h, $c9 + ld c, [hl] + ld b, $c8 + xor a + ld [bc], a + jr .asm_234a +.asm_2345 + inc [hl] + jr nz, .asm_2349 + inc [hl] +.asm_2349 + ld l, [hl] +.asm_234a + ldh a, [hffa9] + ld c, a + ld b, $c9 + ld a, l + ldh [hffa9], a + ld [bc], a + ld h, $c8 + ld [hl], c + ld h, $c6 + ld [hl], e + inc h ; $c7 + ld [hl], d + ld b, l + xor a + ret + +; search linked-list for text characters e/d (registers), if found hoist +; the result to head of list and return it. carry flag denotes success. +Func_235e: ; 235e (0:235e) + ld a, [wFontWidth] + or a + jr z, .print + call CaseHalfWidthLetter + ; if [wHalfWidthPrintState] != 0, load it to d and print the pair of chars + ; zero wHalfWidthPrintState for next iteration + ld a, [wHalfWidthPrintState] + ld d, a + or a + jr nz, .print + ; if [wHalfWidthPrintState] == 0, don't print text in this iteration + ; load the next value of register d into wHalfWidthPrintState + ld a, e + ld [wHalfWidthPrintState], a + ld a, $1 + or a + ret ; nz +.print + xor a + ld [wHalfWidthPrintState], a + ldh a, [hffa9] + ld l, a ; l ← [hffa9]; index to to linked-list head +.asm_237d + ld h, $c6 ; + ld a, [hl] ; a ← key1[l] ; + or a ; + ret z ; if NULL, return a = 0 ; + cp e ; loop for e/d key in + jr nz, .asm_238a ; ; linked list + inc h ; $c7 ; ; + ld a, [hl] ; if key1[l] == e and ; + cp d ; key2[l] == d: ; + jr z, .asm_238f ; break ; +.asm_238a + ld h, $c8 ; ; + ld l, [hl] ; l ← next[l] ; + jr .asm_237d +.asm_238f + ldh a, [hffa9] + cp l + jr z, .asm_23af ; assert at least one iteration + ld c, a + ld b, $c9 + ld a, l + ld [bc], a ; prev[i0] ← i + ldh [hffa9], a ; [hffa9] ← i (update linked-list head) + ld h, $c9 + ld b, [hl] + ld [hl], $0 ; prev[i] ← 0 + ld h, $c8 + ld a, c + ld c, [hl] + ld [hl], a ; next[i] ← i0 + ld l, b + ld [hl], c ; next[prev[i]] ← next[i] + ld h, $c9 + inc c + dec c + jr z, .asm_23af ; if next[i] != NULL: + ld l, c ; l ← next[i] + ld [hl], b ; prev[next[i]] ← prev[i] +.asm_23af + scf ; set carry to indicate success + ret ; (return new linked-list head in a) + +; uppercases e if [wUppercaseHalfWidthLetters] is nonzero +CaseHalfWidthLetter: ; 23b1 (0:23b1) + ld a, [wUppercaseHalfWidthLetters] + or a + ret z + ld a, e + cp $60 + ret c + cp $7b + ret nc + sub "a" - "A" + ld e, a + ret + +; iterates over text at hl until TX_END is found, and sets wFontWidth to +; FULL_WIDTH if the first character is TX_HALFWIDTH +; returns: +; b = length of text in tiles +; c = length of text in bytes +; a = -b +GetTextLengthInTiles: ; 23c1 (0:23c1) + ld a, [hl] + cp TX_HALFWIDTH + jr nz, .full_width + call GetTextLengthInHalfTiles + ; return a = - ceil(b/2) + inc b + srl b + xor a + sub b + ret +.full_width + xor a ; FULL_WIDTH + ld [wFontWidth], a +; fallthrough + +; iterates over text at hl until TX_END is found +; returns: +; b = length of text in half-tiles +; c = length of text in bytes +; a = -b +GetTextLengthInHalfTiles: ; 23d3 (0:23d3) + push hl + push de + lb bc, $00, $00 +.char_loop + ld a, [hli] + or a ; TX_END + jr z, .tx_end + inc c ; any char except TX_END: c ++ + ; TX_FULLWIDTH, TX_SYMBOL, or > TX_CTRL_END : b ++ + cp TX_CTRL_START + jr c, .character_pair + cp TX_CTRL_END + jr nc, .character_pair + cp TX_SYMBOL + jr nz, .char_loop + inc b + jr .next +.character_pair + ld e, a ; first char + ld d, [hl] ; second char + inc b + call ClassifyTextCharacterPair + jr nc, .char_loop + ; TX_FULLWIDTH +.next + inc c ; TX_FULLWIDTH or TX_SYMBOL: c ++ + inc hl + jr .char_loop +.tx_end + ; return a = -b + xor a + sub b + pop de + pop hl + ret + +; copy text of maximum length a (in tiles) from 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: ; 23fd (0:23fd) + ld [wTextMaxLength], a + ld a, [hl] + cp TX_HALFWIDTH + jr z, .half_width_text + ld a, [wTextMaxLength] + call .copyTextData + jr c, .fw_text_done + push hl +.fill_fw_loop + ld a, FW_SPACE + ld [hli], a + dec d + jr nz, .fill_fw_loop + ld [hl], TX_END + pop hl +.fw_text_done + ld a, e + ret +.half_width_text + ld a, [wTextMaxLength] + add a + call .copyTextData + jr c, .hw_text_done + push hl +.fill_hw_loop + ld a, " " + ld [hli], a + dec d + jr nz, .fill_hw_loop + ld [hl], TX_END + pop hl +.hw_text_done + ld a, e + ret + +.copyTextData + push bc + ld c, l + ld b, h + ld l, e + ld h, d + ld d, a + ld e, 0 +.loop + ld a, [bc] + or a ; TX_END + jr z, .done + inc bc + ld [hli], a + cp TX_CTRL_START + jr c, .character_pair + cp TX_CTRL_END + jr c, .loop +.character_pair + push de + ld e, a ; first char + ld a, [bc] + ld d, a ; second char + call ClassifyTextCharacterPair + jr nc, .not_tx_fullwidth + ld a, [bc] + inc bc + ld [hli], a +.not_tx_fullwidth + pop de + inc e ; return in e the amount of characters actually copied + dec d ; return in d the difference between the maximum length and e + jr nz, .loop + ld [hl], TX_END + pop bc + scf ; return carry if the text did not already end with TX_END + ret +.done + pop bc + or a + ret + +; convert the number at hl to TX_SYMBOL text format and write it to wStringBuffer +; replace leading zeros with SYM_SPACE +TwoByteNumberToTxSymbol_TrimLeadingZeros: ; 245d (0:245d) + push de + push bc + ld de, wStringBuffer + push de + ld bc, -10000 + call .get_digit + ld bc, -1000 + call .get_digit + ld bc, -100 + call .get_digit + ld bc, -10 + call .get_digit + ld bc, -1 + call .get_digit + xor a ; TX_END + ld [de], a + pop hl + ld e, 5 +.digit_loop + inc hl + ld a, [hl] + cp SYM_0 + jr nz, .done ; jump if not zero + ld [hl], SYM_SPACE ; trim leading zero + inc hl + dec e + jr nz, .digit_loop + dec hl + ld [hl], SYM_0 +.done + dec hl + pop bc + pop de + ret + +.get_digit + ld a, TX_SYMBOL + ld [de], a + inc de + ld a, SYM_0 - 1 +.subtract_loop + inc a + add hl, bc + jr c, .subtract_loop + ld [de], a + inc de + ld a, l + sub c + ld l, a + ld a, h + sbc b + ld h, a + ret + +; generates a text tile and copies it to VRAM +; if wFontWidth == FULL_WIDTH + ; de = full-width font tile number +; if wFontWidth == HALF_WIDTH + ; d = half-width character 1 (left) + ; e = half-width character 2 (right) +; b = destination VRAM tile number +GenerateTextTile: ; 24ac (0:24ac) + push hl + push de + push bc + ld a, [wFontWidth] + or a + jr nz, .half_width +;.full_width + call CreateFullWidthFontTile_ConvertToTileDataAddress + call SafeCopyDataDEtoHL +.done + pop bc + pop de + pop hl + ret +.half_width + call CreateHalfWidthFontTile + call ConvertTileNumberToTileDataAddress + call SafeCopyDataDEtoHL + jr .done + +; create, at wTextTileBuffer, a half-width font tile +; made from the ascii characters given in d and e +CreateHalfWidthFontTile: ; 24ca (0:24ca) + push bc + ldh a, [hBankROM] + push af + ld a, BANK(HalfWidthFont) + call BankswitchROM + ; write the right half of the tile (first character) to wTextTileBuffer + 2n + push de + ld a, e + ld de, wTextTileBuffer + call CopyHalfWidthCharacterToDE + pop de + ; write the left half of the tile (second character) to wTextTileBuffer + 2n+1 + ld a, d + ld de, wTextTileBuffer + 1 + call CopyHalfWidthCharacterToDE + ; construct the 2bpp-converted half-width font tile + ld hl, wTextTileBuffer + ld b, TILE_SIZE_1BPP +.loop + ld a, [hli] + swap a + or [hl] + dec hl + ld [hli], a + ld [hli], a + dec b + jr nz, .loop + call BankpopROM + pop bc + ld de, wTextTileBuffer + ret + +; copies a 1bpp tile corresponding to a half-width font character to de. +; the ascii value of the character to copy is provided in a. +; assumes BANK(HalfWidthFont) is already loaded. +CopyHalfWidthCharacterToDE: ; 24fa (0:24fa) + sub $20 ; HalfWidthFont begins at ascii $20 + ld l, a + ld h, $0 + add hl, hl + add hl, hl + add hl, hl + ld bc, HalfWidthFont + add hl, bc + ld b, TILE_SIZE_1BPP +.loop + ld a, [hli] + ld [de], a + inc de + inc de + dec b + jr nz, .loop + ret + +; create, at wTextTileBuffer, a full-width font tile given its tile +; number within the full-width font graphics (FullWidthFonts) in de. +; return its v*Tiles address in hl, and return c = TILE_SIZE. +CreateFullWidthFontTile_ConvertToTileDataAddress: ; 2510 (0:2510) + push bc + call GetFullWidthFontTileOffset + call CreateFullWidthFontTile + pop bc +; fallthrough + +; given a tile number in b, return its v*Tiles address in hl, and return c = TILE_SIZE +; wTilePatternSelector and wTilePatternSelectorCorrection are used to select the source: +; - if wTilePatternSelector == $80 and wTilePatternSelectorCorrection == $00 -> $8000-$8FFF +; - if wTilePatternSelector == $88 and wTilePatternSelectorCorrection == $80 -> $8800-$97FF +ConvertTileNumberToTileDataAddress: ; 2518 (0:2518) + ld hl, wTilePatternSelectorCorrection + ld a, b + xor [hl] + ld h, $0 + ld l, a + add hl, hl + add hl, hl + add hl, hl + add hl, hl + ld a, [wTilePatternSelector] + ld b, a + ld c, $0 + add hl, bc + ld c, TILE_SIZE + ret + +; create, at wTextTileBuffer, a full-width font tile given its +; within the full-width font graphics (FullWidthFonts) in hl +CreateFullWidthFontTile: ; 252e (0:252e) + ld a, BANK(Fonts) ; BANK(DuelGraphics) + call BankpushROM + ld de, wTextTileBuffer + push de + ld c, TILE_SIZE_1BPP +.loop + ld a, [hli] + ld [de], a + inc de + ld [de], a + inc de + dec c + jr nz, .loop + pop de + call BankpopROM + ret + +; given two text characters at de, use the char at e (first one) +; to determine which type of text this pair of characters belongs to. +; return carry if TX_FULLWIDTH1 to TX_FULLWIDTH4. +ClassifyTextCharacterPair: ; 2546 (0:2546) + ld a, [wFontWidth] + or a ; FULL_WIDTH + jr nz, .half_width + ld a, e + cp TX_CTRL_END + jr c, .continue_check + cp $60 + jr nc, .not_katakana + ldh a, [hJapaneseSyllabary] + cp TX_KATAKANA + jr nz, .not_katakana + ld d, TX_KATAKANA + or a + ret +.half_width +; in half width mode, the first character goes in e, so leave them like that + or a + ret +.continue_check + cp TX_CTRL_START + jr c, .ath_font +.not_katakana +; 0_1_hiragana.1bpp (e < $60) or 0_2_digits_kanji1.1bpp (e >= $60) + ld d, $0 + or a + ret +.ath_font +; TX_FULLWIDTH1 to TX_FULLWIDTH4 +; swap d and e to put the TX_FULLWIDTH* character first + ld e, d + ld d, a + scf + ret + +; convert the full-width font tile number at de to the +; equivalent offset within the full-width font tile graphics. +; if d == TX_KATAKANA: get tile from the 0_0_katakana.1bpp font. +; if d == TX_HIRAGANA or d == $0: get tile from the 0_1_hiragana.1bpp or 0_2_digits_kanji1.1bpp font. +; if d >= TX_FULLWIDTH1 and d <= TX_FULLWIDTH4: get tile from one of the other full-width fonts. +GetFullWidthFontTileOffset: ; 256d (0:256d) + ld bc, $50 tiles_1bpp + ld a, d + cp TX_HIRAGANA + jr z, .hiragana + cp TX_KATAKANA + jr nz, .get_address + ld bc, $0 tiles + ld a, e + sub $10 ; the first $10 are control characters, but this font's graphics start at $0 + ld e, a +.hiragana + ld d, $0 +.get_address + ld l, e + ld h, d + add hl, hl + add hl, hl + add hl, hl + add hl, bc + ret + +; pointers to VRAM? +; unreferenced +Unknown_2589: ; 2589 (0:2589) + db $18 + dw $8140 + dw $817e + dw $8180 + dw $81ac + dw $81b8 + dw $81bf + dw $81c8 + dw $81ce + dw $81da + dw $81e8 + dw $81f0 + dw $81f7 + dw $81fc + dw $81fc + dw $824f + dw $8258 + dw $8260 + dw $8279 + dw $8281 + dw $829a + dw $829f + dw $82f1 + dw $8340 + dw $837e + dw $8380 + dw $8396 + dw $839f + dw $83b6 + dw $83bf + dw $83d6 + dw $8440 + dw $8460 + dw $8470 + dw $847e + dw $8480 + dw $8491 + dw $849f + dw $84be + dw $889f + dw $88fc + dw $8940 + dw $9443 + dw $9840 + dw $9872 + dw $989f + dw $98fc + dw $9940 + dw $ffff |