SHARE
TWEET

Auto-wordwrap VWF engine for Game Boy

ISSOtm Aug 9th, 2019 (edited) 136 Never
Not a member of Pastebin yet? Sign Up, it unlocks many cool features!
  1. SECTION "VWF engine memory", WRAM0,ALIGN[6]
  2.  
  3. wTextCharBuffer::
  4.     ds 64
  5. wTextCharBufferEnd::
  6.  
  7. ; This is ALIGN[6]
  8. wTextTileBuffer::
  9.     ds $10 * 2
  10.  
  11. ; This is ALIGN[5]
  12. ; Format of entries: ptr(16bit LE), bank(8bit)
  13. wTextStack::
  14.     ds TEXT_STACK_CAPACITY * 3
  15. ; Number of entries in the stack
  16. wTextStackSize::
  17.     db
  18.  
  19. ; Tells which tile to wrap to after $7F
  20. wWrapTileID::
  21.     db
  22.  
  23. ; Tells which color to use in the palette for the text (in range 0-3)
  24. wTextColorID::
  25.     db
  26.  
  27. ; Defines which character table to use
  28. ; Upper nibble is language-defined, lower nibble is decoration
  29. wTextCharset::
  30.     db
  31.  
  32. wPreviousLanguage::
  33.     db
  34. wPreviousDecoration::
  35.     db
  36.  
  37. wTextSrcBank::
  38.     db
  39. wTextSrcPtr::
  40.     dw
  41.  
  42. wTextCurTile::
  43.     db
  44. wTextCurPixel::
  45.     db
  46.  
  47. ; Number of frames between each character
  48. wTextLetterDelay::
  49.     db
  50. ; Number of frames till next character
  51. wTextNextLetterDelay::
  52.     db
  53.  
  54. ; Bit 6 - Whether the text engine is currently waiting for a button press
  55. ; Bit 7 - Whether the text engine is halted, for syncing (can be reset)
  56. wTextPaused::
  57.     db
  58.  
  59. ; Number of tiles flushed, used to know how many tiles should be written to the tilemap
  60. wFlushedTiles::
  61.     db
  62.  
  63. ; Number of newlines that occurred during this print
  64. wNbNewlines::
  65.     db
  66. ; ID of the tiles during which newlines occurred (NOTE: there can be duplicates due to empty lines!!)
  67. wNewlineTiles::
  68.     ds TEXT_NEWLINE_CAPACITY
  69.  
  70. wPenStartingPosition::
  71.     dw
  72. wPenPosition::
  73.     dw
  74. wPenCurTile::
  75.     db
  76.  
  77. ; Low byte of the read ptr into wTextCharBuffer
  78. wTextReadPtrLow::
  79.     db
  80.  
  81. ; Length, in pixels, of the current text line
  82. wTextLineLength::
  83.     db
  84. wLineRemainingPixels::
  85.     db
  86. ; Ptr to last newlineable location
  87. wNewlinePtrLow::
  88.     db
  89. ; wLineRemainingPixels at the time wNewlinePtrLow is updated
  90. wNewlineRemainingPixels::
  91.     db
  92. ; Charset ptr is cached by refiller to speed up reads
  93. wCurCharsetPtr::
  94.     dw
  95. wRefillerCharset::
  96.     db
  97. wRefillerPrevLanguage::
  98.     db
  99. wRefillerPrevDecoration::
  100.     db
  101.  
  102.  
  103.  
  104.  
  105. SECTION "VWF engine", ROM0
  106.  
  107. ; Sets the pen's position somewhere in memory
  108. ; The code is designed for a pen in VRAM, but it can be anywhere
  109. ; Please call this after PrintVWFText, so wTextCurTile is properly updated
  110. ; @param hl The address to print to (usually in the tilemap)
  111. SetPenPosition::
  112. ; Note: relied upon preserving HL
  113.     ld a, l
  114.     ld [wPenPosition], a
  115.     ld [wPenStartingPosition], a
  116.     ld a, h
  117.     ld [wPenPosition + 1], a
  118.     ld [wPenStartingPosition + 1], a
  119.  
  120.     ld a, [wTextCurTile]
  121.     ld [wPenCurTile], a
  122.     ret
  123.  
  124. DrawVWFChars::
  125.     ld hl, wPenPosition
  126.     ld a, [hli]
  127.     ld e, a
  128.     ld a, [hli]
  129.     ld d, a
  130.     ; ld hl, wPenCurTile
  131.     ld c, [hl]
  132.  
  133.     ld hl, wNewlineTiles
  134.     ld a, [wFlushedTiles]
  135.     and a
  136.     jr z, .noNewTiles
  137.     ld b, a
  138.     xor a
  139.     ld [wFlushedTiles], a
  140. .writeNewTile
  141.     ; Check if current tile is subject to a newline
  142.     ld a, [wNbNewlines]
  143.     and a
  144.     jr z, .noNewline
  145.     ld a, c
  146.     cp [hl]
  147.     jr z, .newline
  148. .noNewline
  149.     wait_vram
  150.     ld a, c
  151.     ld [de], a
  152.     cp $7F
  153.     jr nz, .nowrap
  154.     ld a, [wWrapTileID]
  155.     ld c, a
  156.     db $3E ; ld a, imm8
  157. .nowrap
  158.     inc c
  159.     inc de
  160.     dec b
  161.     jr nz, .writeNewTile
  162. .noNewTiles
  163.  
  164. .tryAgain
  165.     ld a, [wNbNewlines]
  166.     and a
  167.     jr z, .noFinalNewline
  168.     ld a, c
  169.     cp [hl]
  170.     jr z, .finalNewline
  171. .noFinalNewline
  172.     xor a
  173.     ld [wNbNewlines], a
  174.  
  175.     ld hl, wPenCurTile
  176.     ld a, c
  177.     ld [hld], a
  178.     ld a, d
  179.     ld [hld], a
  180.     ld [hl], e
  181.  
  182.     ; If the current tile is empty (1 px == 1 space)
  183.     ld a, [wTextCurPixel]
  184.     cp 2
  185.     ret c
  186.     wait_vram
  187.     ld a, c
  188.     ld [de], a
  189.     ret
  190.  
  191. .newline
  192.     ld a, [wNbNewlines]
  193.     dec a
  194.     ld [wNbNewlines], a
  195.     ld a, [wPenStartingPosition]
  196.     and SCRN_VX_B - 1
  197.     ld c, a ; Get offset from column 0
  198.     ld a, e
  199.     and -SCRN_VX_B ; Get to column 0
  200.     add a, c ; Get to starting column
  201.     add a, SCRN_VX_B ; Go to next row (this might overflow)
  202.     ld e, a
  203.     jr nc, .nocarry
  204.     inc d
  205. .nocarry
  206.     ld c, [hl] ; Get back tile ID
  207.     xor a ; Clear this newline tile
  208.     ld [hli], a ; Go to the next newline (if any)
  209.     jr .writeNewTile
  210.  
  211. .finalNewline
  212.     ld a, [wNbNewlines]
  213.     dec a
  214.     ld [wNbNewlines], a
  215.     xor a
  216.     ld [hli], a ; Clear that
  217.     ld a, [wPenStartingPosition]
  218.     and SCRN_VX_B - 1
  219.     ld b, a
  220.     ld a, e
  221.     and -SCRN_VX_B
  222.     add a, b
  223.     add a, SCRN_VX_B
  224.     ld e, a
  225.     jr nc, .tryAgain ; noCarry
  226.     inc d
  227.     jr .tryAgain
  228.  
  229.  
  230.  
  231. ; Sets up the VWF engine to start printing text
  232. ; @param hl Pointer to the string to be displayed
  233. ; @param b  Bank containing the string
  234. ; @param a  Non-zero to flush the current string (use zero if you want to keep printing the same string)
  235. ; @return a 0
  236. ; @return hl wTextCharset
  237. ; @return f NC and Z
  238. ; @destroy bc de
  239. PrintVWFText::
  240.     and a ; Set Z flag for test below
  241.  
  242.     ; Write src ptr
  243.     ld a, b
  244.     ld [wTextSrcBank], a
  245.     ld a, l
  246.     ld [wTextSrcPtr], a
  247.     ld a, h
  248.     ld [wTextSrcPtr + 1], a
  249.  
  250.     ; Flag preserved from `and a`
  251.     jr z, .dontFlush
  252.     ; Don't flush if current tile is empty
  253.     ld a, [wTextCurPixel]
  254.     cp 2
  255.     ; Flush buffer to VRAM
  256.     call nc, FlushVWFBuffer
  257.     ; Reset position always, though
  258.     xor a
  259.     ld [wTextCurPixel], a
  260.     ; TODO: decrease remaining amount of pixels
  261. .dontFlush
  262.  
  263.     ; Force buffer refill
  264.     ld a, LOW(wTextCharBufferEnd)
  265.     ld [wTextReadPtrLow], a
  266.     ; Initialize auto line-wrapper
  267.     ld a, [wTextLineLength]
  268.     inc a ; Last pixel of all chars is blank, so we can actually fit 1 extra
  269.     ld [wLineRemainingPixels], a
  270.  
  271.     ; Use black color by default (which is normally loaded into color #3)
  272.     ld a, 3
  273.     ld [wTextColorID], a
  274.  
  275.     ; Preserve the language but reset the decoration
  276.     ld hl, wTextCharset
  277.     ld a, [hl]
  278.     and $F0
  279.     ld [hl], a
  280.  
  281.     ; Set initial letter delay to 0, to start printing directly
  282.     xor a
  283.     ld [wTextNextLetterDelay], a
  284.     ret
  285.  
  286. FlushVWFBuffer::
  287.     push hl
  288.  
  289.     ; Calculate ptr to next tile
  290.     ld a, [wTextCurTile]
  291.     swap a
  292.     ld d, a
  293.     and $F0
  294.     ld e, a
  295.     ld a, d
  296.     and $0F
  297.     add a, $80
  298.     ld d, a
  299.  
  300.     ; Copy buffer 1 to VRAM, buffer 2 to buffer 1, and clear buffer 2
  301.     ld hl, wTextTileBuffer
  302.     ld bc, wTextTileBuffer + $10
  303. .copyByte
  304.     ldh a, [rSTAT]
  305.     and STATF_BUSY
  306.     jr nz, .copyByte
  307.     ; Write tile buf to VRAM
  308.     ld a, [hl]
  309.     ld [de], a
  310.     inc e ; Faster than inc de, guaranteed thanks to ALIGN[4]
  311.     ; Copy second tile to first one
  312.     ld a, [bc]
  313.     ld [hli], a
  314.     ; Clear second tile
  315.     xor a
  316.     ld [bc], a
  317.     inc c
  318.  
  319.     ld a, l
  320.     cp LOW(wTextTileBuffer + $10)
  321.     jr nz, .copyByte
  322.  
  323.     ; Go to next tile
  324.     ld hl, wTextCurTile
  325.     ld a, [hl]
  326.     inc a
  327.     and $7F
  328.     jr nz, .noWrap
  329.     ld a, [wWrapTileID]
  330. .noWrap
  331.     ld [hl], a
  332.  
  333.     ld hl, wFlushedTiles
  334.     inc [hl]
  335.     pop hl
  336.     ret
  337.  
  338. ; Prints a VWF char (or more), applying delay if necessary
  339. ; Might print more than 1 char, eg. if wTextLetterDelay is zero
  340. ; Sets the high byte of the source pointer to $FF when finished
  341. ; **DO NOT CALL WITH SOURCE DATA IN FF00-FFFF, THIS WILL CAUSE AN EARLY RETURN!!
  342. ; Number of tiles to write to the tilemap is written in wFlushedTiles
  343. PrintVWFChar::
  344.     ld hl, wTextNextLetterDelay
  345.     ld a, [hl]
  346.     and a
  347.     jr nz, .delay
  348.     ; xor a
  349.     ld [wFlushedTiles], a
  350.  
  351.     ; Save current ROM bank
  352.     ldh a, [hCurROMBank]
  353.     push af
  354.  
  355.     ld a, BANK(_PrintVWFChar)
  356.     rst bankswitch
  357.     call _PrintVWFChar
  358.  
  359.     pop af
  360.     rst bankswitch
  361.     ret
  362.  
  363. .delay
  364.     dec a
  365.     ld [hl], a
  366.     ret
  367.  
  368.  
  369. RefillerOnlyControlChar:
  370.     ld bc, _RefillCharBuffer
  371.     push bc
  372.  
  373.     push hl
  374.     add a, LOW(RefillerOnlyControlChars)
  375.     ld l, a
  376.     ld a, $FF ; If we're here, the value in A is negative
  377.     adc a, HIGH(RefillerOnlyControlChars)
  378.     ld h, a
  379.     ld a, [hli]
  380.     ld b, [hl]
  381.     ld c, a
  382.     pop hl
  383.     push bc
  384.     ret
  385.  
  386. RefillerControlChar:
  387.     ld bc, _RefillCharBuffer.afterControlChar
  388.     push bc
  389.     inc e ; Otherwise the char isn't counted to be written!
  390.     push hl
  391.     add a, " "
  392.     add a, a ; Can't be zero because we handle that earlier
  393.     add a, LOW(RefillerControlChars - 2)
  394.     ld l, a
  395.     adc a, HIGH(RefillerControlChars - 2)
  396.     sub l
  397.     ld h, a
  398.     ld a, [hli]
  399.     ld b, [hl]
  400.     ld c, a
  401.     pop hl
  402.     push bc
  403.     ret
  404.  
  405. ; Refills the char buffer, assuming at least half of it has been read
  406. ; Newlines are injected into the buffer to implement auto line-wrapping
  407. ; @param hl The current read ptr into the buffer
  408. RefillCharBuffer:
  409.     ld de, wTextCharBuffer
  410.     ; First, copy remaining chars into the buffer
  411.     ld a, LOW(wTextCharBufferEnd)
  412.     sub l
  413.     ld c, a
  414.     jr z, .charBufferEmpty
  415. .copyLeftovers
  416.     ld a, [hli]
  417.     ld [de], a
  418.     inc e
  419.     dec c
  420.     jr nz, .copyLeftovers
  421. .charBufferEmpty
  422.  
  423.     ; Cache charset ptr to speed up calculations
  424.     ld a, [wTextCharset]
  425.     ld [wRefillerCharset], a
  426.     add a, a
  427.     add a, LOW(CharsetPtrs)
  428.     ld l, a
  429.     adc a, HIGH(CharsetPtrs)
  430.     sub l
  431.     ld h, a
  432.     ld a, [hli]
  433.     add a, 8 ; Code later on will want a +8 offset
  434.     ld [wCurCharsetPtr], a
  435.     ld a, 0 ; If you try to optimize this to `xor a` I will kick you in the nuts
  436.     adc a, [hl]
  437.     ld [wCurCharsetPtr+1], a
  438.  
  439.     ; Get ready to read chars into the buffer
  440.     ld hl, wTextSrcBank
  441.     ld a, [hli]
  442.     rst bankswitch
  443.     ld a, [hli]
  444.     ld h, [hl]
  445.     ld l, a
  446.  
  447. _RefillCharBuffer:
  448. .refillBuffer
  449.     ld a, [hli]
  450.     add a, a ; Test bit 7 and prepare for control char handling
  451.     jr z, .tryReturning
  452.     jr c, RefillerOnlyControlChar
  453.     rra ; Restore A
  454.     ld [de], a
  455.     sub " "
  456.     jr c, RefillerControlChar ; The refiller needs to be aware of some control chars
  457.  
  458.     ; Add char length to accumulated one
  459.     push hl
  460.     ld hl, wCurCharsetPtr
  461.     ld c, [hl]
  462.     inc hl
  463.     ld b, [hl]
  464.     ld l, a
  465.     ld h, 0
  466.     add hl, hl
  467.     add hl, hl
  468.     add hl, hl
  469.     add hl, bc ; Char * 8 + base + 8
  470.     ld c, a ; Stash this for later
  471.     ld b, 0
  472.     add hl, bc ; Char * 9 + base + 8
  473.     ld a, [wLineRemainingPixels]
  474.     sub a, [hl]
  475. .insertCustomSize
  476.     jr nc, .noNewline
  477.     ld b, a ; Stash this for later
  478.     ; Line length was overflowed, inject newline into buffer
  479.     ; Get ptr to newline injection point
  480.     ld h, d ; ld h, HIGH(wTextCharBuffer)
  481.     ld a, [wNewlinePtrLow]
  482.     ld l, a
  483.     ; Dashes aren't overwritten on newlines, instead the newline is inserted right after
  484.     ld a, [hl]
  485.     cp " "
  486.     ld d, "\n"
  487.     jr z, .overwritingNewline
  488.     ld a, e
  489.     cp LOW(wTextCharBufferEnd - 1)
  490.     jr z, .bufferFull
  491.     inc e ; We're going to insert an extra char unless that would overflow the buffer
  492. .bufferFull
  493. .copyNewlinedChars
  494.     ld a, d
  495.     ld d, [hl]
  496.     ld [hli], a
  497.     ld a, e ; Stop when we're about to write the last char
  498.     cp l
  499.     jr nz, .copyNewlinedChars
  500.     ; But write it, of course!
  501. .overwritingNewline
  502.     ld [hl], d
  503.     ; Restore dest ptr high byte
  504.     ld d, h ; ld d, HIGH(wTextCharBuffer)
  505.     ; Get amount of pixels remaining on next line after we move a word to it
  506.     ld a, [wNewlineRemainingPixels]
  507.     sub b ; Get pixels that word has
  508.     ld b, a
  509.     ld a, [wTextLineLength]
  510.     sub b ; Subtract that amount from a whole line's length
  511. .noNewline
  512.     ld [wLineRemainingPixels], a
  513.     pop hl
  514.  
  515.     ld a, c
  516.     ; If the character is a dash or a space, a newline can be inserted
  517.     and a ; cp " " - " "
  518.     jr z, .canNewline
  519.     inc e ; This increment is also shared by the main loop
  520.     cp "-" - " " ; Dashes aren't *overwritten* by the newline, instead it's inserted after
  521.     ld a, e ; The increment has to be placed in an awkward way because it alters flags
  522.     jr z, .canNewlineAfter
  523.  
  524. .afterControlChar
  525.     ld a, e
  526.     cp LOW(wTextCharBufferEnd)
  527.     jr nz, .refillBuffer
  528.  
  529. .done
  530.     ; Write src ptr for later
  531.     ld a, l
  532.     ld [wTextSrcPtr], a
  533.     ld a, h
  534.     ld [wTextSrcPtr+1], a
  535.     ldh a, [hCurROMBank]
  536.     ld [wTextSrcBank], a
  537.  
  538.     ld a, BANK(_PrintVWFChar)
  539.     rst bankswitch
  540.     ; Restart printer's reading
  541.     ld hl, wTextCharBuffer
  542.     ret
  543.  
  544.  
  545. .tryReturning
  546.     ld hl, wTextStackSize
  547.     ld a, [hl]
  548.     ld b, a
  549.     add a, a
  550.     ld [de], a ; If we're returning, we will need to write that $00; otherwise it'll be overwritten
  551.     jr z, .done
  552.     dec b
  553.     ld [hl], b
  554.     add a, b ; a = stack size * 3 + 2
  555.     add a, LOW(wTextStack)
  556.     ld l, a
  557.     adc a, HIGH(wTextStack)
  558.     sub l
  559.     ld h, a
  560.     ld a, [hld]
  561.     rst bankswitch
  562.     ld a, [hld]
  563.     ld l, [hl]
  564.     ld h, a
  565.     jp .refillBuffer ; Too far to `jr`
  566.  
  567.  
  568. .canNewline
  569.     ld a, e
  570.     inc e
  571. .canNewlineAfter
  572.     ld [wNewlinePtrLow], a
  573.     ld a, [wLineRemainingPixels]
  574.     ld [wNewlineRemainingPixels], a
  575.     jr .afterControlChar
  576.  
  577.  
  578. RefillerControlChars:
  579.     dw ReaderSetLanguage
  580.     dw ReaderRestoreLanguage
  581.     dw ReaderSetDecoration
  582.     dw ReaderRestoreDecoration
  583.     dw Reader2ByteNop
  584.     dw ReaderPrintBlank
  585.     dw Reader2ByteNop
  586.     dw Reader1ByteNop
  587.     dw ReaderClear
  588.     dw ReaderNewline
  589.     dw Reader1ByteNop
  590.  
  591.     ; The base of the table is located at its end
  592.     ; Unusual, I know, but it works better!
  593.     dw ReaderJumpTo
  594.     dw ReaderCall
  595. RefillerOnlyControlChars:
  596.  
  597. Reader2ByteNop:
  598.     ld a, [hli]
  599.     ld [de], a
  600.     inc e
  601. Reader1ByteNop:
  602.     ret
  603.  
  604. ReaderSetLanguage:
  605.     ld a, [wRefillerCharset]
  606.     ld c, a
  607.     ld [wRefillerPrevLanguage], a
  608.     ld a, [hli]
  609.     ld [de], a
  610.     inc e
  611.     swap a
  612.     xor c
  613.     and $F0
  614.     jr ReaderUpdateCharset
  615.  
  616. ReaderRestoreLanguage:
  617.     ld a, [wRefillerCharset]
  618.     and $0F
  619.     ld c, a
  620.     ld a, [wRefillerPrevLanguage]
  621.     and $F0
  622.     jr ReaderUpdateCharset
  623.  
  624. ReaderSetDecoration:
  625.     ld a, [wRefillerCharset]
  626.     ld c, a
  627.     ld [wRefillerPrevDecoration], a
  628.     ld a, [hli]
  629.     ld [de], a
  630.     inc e
  631.     xor c
  632.     and $0F
  633.     jr ReaderUpdateCharset
  634.  
  635. ReaderRestoreDecoration:
  636.     ld a, [wRefillerCharset]
  637.     and $F0
  638.     ld c, a
  639.     ld a, [wRefillerPrevDecoration]
  640.     and $0F
  641.     ; Fall through
  642. ReaderUpdateCharset:
  643.     xor c
  644.     ld [wRefillerCharset], a
  645.     add a, a
  646.     add a, LOW(CharsetPtrs)
  647.     ld c, a
  648.     adc a, HIGH(CharsetPtrs)
  649.     sub c
  650.     ld b, a
  651.     ld a, [bc]
  652.     ld [wCurCharsetPtr], a
  653.     inc bc
  654.     ld a, [bc]
  655.     ld [wCurCharsetPtr+1], a
  656.     ret
  657.  
  658. ReaderPrintBlank:
  659.     pop bc ; We're not gonna return because we're gonna insert a custom size instead
  660.     ld a, [hli] ; Read number of blanks
  661.     ld [de], a
  662.     ; inc e ; Don't increment dest ptr because the code path we'll jump into will do it
  663.     ld c, a
  664.     ld a, [wLineRemainingPixels]
  665.     sub c
  666.     ; We'll be jumping straight in the middle of some code path, make sure not to break it
  667.     push hl
  668.     ld c, "A" ; Make sure we won't get a newline
  669.     jp _RefillCharBuffer.insertCustomSize ; Too far to `jr`
  670.  
  671. ReaderClear:
  672.     ; For the purpose of line length counting, newline and clearing are the same
  673. ReaderNewline:
  674.     ; Reset line length, since we're forcing a newline
  675.     ld a, [wTextLineLength]
  676.     ld [wLineRemainingPixels], a
  677.     ret
  678.  
  679. ; Sets text ptr to given location
  680. ReaderJumpTo:
  681.     ld a, [hli]
  682.     ld b, a
  683.     ld a, [hli]
  684.     ld h, [hl]
  685.     ld l, a
  686.     ld a, b
  687.     rst bankswitch
  688.     ret
  689.  
  690. ; Start printing a new string, then keep writing this one
  691. ; NOTE: avoids corruption by preventing too much recursion, but this shouldn't happen at all
  692. ReaderCall:
  693.     ld a, [wTextStackSize]
  694.     cp TEXT_STACK_CAPACITY
  695.     call nc, TextStackOverflowError
  696.  
  697.     ; Read target ptr
  698.     inc a ; Increase stack size
  699.     ld [wTextStackSize], a
  700.  
  701.     ; Get ptr to end of 1st empty entry
  702.     ld b, a
  703.     add a, a
  704.     add a, b
  705.     add a, LOW(wTextStack - 1)
  706.     ld c, a
  707.     adc a, HIGH(wTextStack - 1)
  708.     sub c
  709.     ld b, a
  710.     ; Save ROM bank immediately, as we're gonna bankswitch
  711.     ldh a, [hCurROMBank]
  712.     ld [bc], a
  713.     dec bc
  714.  
  715.     ; Swap src ptrs
  716.     ld a, [hli]
  717.     ld [de], a ; Use current byte in char buffer as scratch
  718.     ; Save src ptr now (will require incrementing twice when returning but eh)
  719.     ld a, h
  720.     ld [bc], a
  721.     dec bc
  722.     ld a, l
  723.     ld [bc], a
  724.     ; Read new src ptr
  725.     ld a, [hli]
  726.     ld h, [hl]
  727.     ld l, a
  728.     ; Perform bankswitch now that all bytecode has been read
  729.     ld a, [de]
  730.     rst bankswitch
  731.     ret
  732.  
  733.  
  734. SECTION "VWF ROMX functions + data", ROMX
  735.  
  736. _PrintVWFChar:
  737.     ld h, HIGH(wTextCharBuffer)
  738.     ld a, [wTextReadPtrLow]
  739.     ld l, a
  740.  
  741. .setDelayAndNextChar
  742.     ; Reload delay
  743.     ld a, [wTextLetterDelay]
  744.     ld [wTextNextLetterDelay], a
  745.  
  746. .nextChar
  747.     ; First, check if the buffer is sufficiently full
  748.     ; Making the buffer wrap would be costly, so we're keeping a safety margin
  749.     ; Especially since control codes are multi-byte
  750.     ld a, l
  751.     cp LOW(wTextCharBufferEnd - 8)
  752.     call nc, RefillCharBuffer
  753.  
  754.     ; Read byte from string stream
  755.     ld a, [hli]
  756.     and a ; Check for terminator
  757.     jp z, .return
  758.     cp " "
  759.     jp c, .controlChar
  760.  
  761. ; Print char
  762.  
  763.     ; Save src ptr & letter ID
  764.     push hl
  765.  
  766.     sub " "
  767.     ld e, a
  768.  
  769.     ; Get ptr to charset table
  770.     ld a, [wTextCharset]
  771.     add a, a
  772.     add a, LOW(CharsetPtrs)
  773.     ld l, a
  774.     adc a, HIGH(CharsetPtrs)
  775.     sub l
  776.     ld h, a
  777.     ld a, [hli]
  778.     ld b, [hl]
  779.     ld c, a
  780.  
  781.     ; Get ptr to letter
  782.     ld d, 0
  783.     ld l, e
  784.     ld h, d ; ld h, 0
  785.     add hl, hl
  786.     add hl, hl
  787.     add hl, hl
  788.     add hl, de ; * 9
  789.     add hl, bc
  790.     ld d, h
  791.     ld e, l
  792.  
  793.     ; Get dest buffer ptr
  794.     ld hl, wTextTileBuffer
  795.  
  796.     ld a, 8
  797. .printOneLine
  798.     ldh [hVWFRowCount], a
  799.  
  800.     ld a, [wTextCurPixel]
  801.     ld b, a
  802.     and a ; Check now if shifting needs to happen
  803.  
  804.     ld a, [de]
  805.     inc de
  806.  
  807.     ld c, 0
  808.     jr z, .doneShifting
  809. .shiftRight
  810.     rra ; Actually `srl a`, since a 0 bit is always shifted in
  811.     rr c
  812.     dec b
  813.     jr nz, .shiftRight
  814. .doneShifting
  815.     ld b, a
  816.  
  817.     ld a, [wTextColorID]
  818.     rra
  819.     jr nc, .noLSB
  820.     ld a, b
  821.     or [hl]
  822.     ld [hl], a
  823.  
  824.     set 4, l
  825.     ld a, c
  826.     or [hl]
  827.     ld [hl], a
  828.     res 4, l
  829.  
  830.     ld a, [wTextColorID]
  831.     rra
  832. .noLSB
  833.     inc l
  834.  
  835.     rra
  836.     jr nc, .noMSB
  837.     ld a, b
  838.     or [hl]
  839.     ld [hl], a
  840.  
  841.     set 4, l
  842.     ld a, c
  843.     or [hl]
  844.     ld [hl], a
  845.     res 4, l
  846. .noMSB
  847.     inc l
  848.  
  849.     ldh a, [hVWFRowCount]
  850.     dec a
  851.     jr nz, .printOneLine
  852.  
  853.     ; Advance read by size
  854.     ld hl, wTextCurPixel
  855.     ld a, [de]
  856.     add a, [hl]
  857.     ld [hl], a
  858.  
  859.     ; Restore src ptr
  860.     pop hl
  861.  
  862. .charPrinted
  863.     ; Save src ptr
  864.     ld a, l
  865.     ld [wTextSrcPtr], a
  866.     ld a, h
  867.     ld [wTextSrcPtr + 1], a
  868.  
  869.     ; Check if flushing needs to be done
  870.     ld a, [wTextCurPixel]
  871.     sub 8
  872.     jr c, .noTilesToFlush
  873.  
  874.     ; Move back by 8 pixels
  875.     ld [wTextCurPixel], a
  876.     ; Flush them to VRAM
  877.     call FlushVWFBuffer
  878.     ; Check if the second tile needs to be flushed as well (happens with characters 9 pixels wide)
  879.     ; We might never use 9-px chars, but if we do, there'll be support for them ^^
  880.     ld a, [wTextCurPixel]
  881.     sub 8
  882.     jr c, .flushed
  883.     ld [wTextCurPixel], a
  884.     call FlushVWFBuffer
  885. .flushed
  886.  
  887. .noTilesToFlush
  888.     ; If not printing next char immediately, force to flush
  889.     ld a, [wTextNextLetterDelay]
  890.     and a
  891.     jp z, .setDelayAndNextChar
  892.     dec a
  893.     ld [wTextNextLetterDelay], a
  894.     ; Write back new read ptr into buffer for next iteration
  895.     ld a, l
  896.     ld [wTextReadPtrLow], a
  897.  
  898. .flushAndFinish
  899.     ; Check if flushing is necessary
  900.     ld a, [wTextCurPixel]
  901.     cp 2
  902.     ret c
  903.  
  904.     ld a, [wTextCurTile]
  905.     swap a
  906.     ld h, a
  907.     and $F0
  908.     ld l, a
  909.     ld a, h
  910.     and $0F
  911.     add a, $80
  912.     ld h, a
  913.     ld de, wTextTileBuffer
  914.     ld c, $10
  915.     jp LCDMemcpySmall ; Tail call
  916.  
  917.  
  918. .return
  919.     ; Tell caller we're done (if we're not, this'll be overwritten)
  920.     ld a, $FF
  921.     ld [wTextSrcPtr + 1], a
  922.     jr .flushAndFinish
  923.  
  924.  
  925. .controlChar
  926.     ; Check if ctrl char is valid
  927.     cp TEXT_BAD_CTRL_CHAR
  928.     call nc, TextCtrlCharError
  929.  
  930.     ; Control char, run the associated function
  931.     ld de, .charPrinted
  932.     push de
  933.  
  934.     ; Push the func's addr (so we can preserve hl when calling)
  935.     add a, a
  936.     add a, LOW(.controlCharFuncs - 2)
  937.     ld e, a
  938.     adc a, HIGH(.controlCharFuncs - 2)
  939.     sub e
  940.     ld d, a
  941.     ld a, [de]
  942.     ld c, a
  943.     inc de
  944.     ld a, [de]
  945.     ld b, a
  946.     push bc
  947.     ret ; Actually jump to the function, passing `hl` as a parameter for it to read (and advance)
  948.  
  949.  
  950. .controlCharFuncs
  951.     dw TextSetLanguage
  952.     dw TextRestoreLanguage
  953.     dw TextSetDecoration
  954.     dw TextRestoreDecoration
  955.     dw TextSetColor
  956.     dw TextPrintBlank
  957.     dw TextDelay
  958.     dw TextWaitButton
  959.     dw TextClear
  960.     dw TextNewline
  961.     dw TextHalt
  962.  
  963.  
  964. TextDelay:
  965.     ld a, [hli]
  966.     ld [wTextNextLetterDelay], a
  967.     ret
  968.  
  969.  
  970. TextRestoreLanguage:
  971.     ld de, wTextCharset
  972.     ld a, [de]
  973.     and $0F
  974.     ld b, a
  975.     ld a, [wPreviousLanguage]
  976.     and $F0
  977.     jr _TextSetCharset
  978.  
  979. TextRestoreDecoration:
  980.     ld de, wTextCharset
  981.     ld a, [de]
  982.     and $F0
  983.     ld b, a
  984.     ld a, [wPreviousDecoration]
  985.     and $0F
  986.     jr _TextSetCharset
  987.  
  988. TextSetDecoration:
  989.     ld de, wTextCharset
  990.     ld a, [de]
  991.     ld [wPreviousDecoration], a
  992.     and $F0
  993.     ld b, a
  994.     ld a, [hli]
  995.     and $0F
  996.     jr _TextSetCharset
  997.  
  998. TextSetLanguage:
  999.     ld de, wTextCharset
  1000.     ld a, [de]
  1001.     ld [wPreviousLanguage], a
  1002.     and $0F
  1003.     ld b, a
  1004.     ld a, [hli]
  1005.     swap a
  1006.     and $F0
  1007. _TextSetCharset:
  1008.     or b
  1009.     ld [de], a
  1010.     jr PrintNextCharInstant
  1011.  
  1012.  
  1013. TextSetColor:
  1014.     ld a, [hli]
  1015.     and 3
  1016.     ld [wTextColorID], a
  1017.     jr PrintNextCharInstant
  1018.  
  1019.  
  1020. TextPrintBlank:
  1021.     ld a, [hli]
  1022.     ld c, a
  1023.     ld a, [wTextCurPixel]
  1024.     add a, c
  1025.     ld c, a
  1026.     and $F8
  1027.     jr z, .noNewTiles
  1028.     rrca
  1029.     rrca
  1030.     rrca
  1031.     ld b, a
  1032. .printNewTile
  1033.     push bc
  1034.     call FlushVWFBuffer ; Preserves HL
  1035.     pop bc
  1036.     dec b
  1037.     jr nz, .printNewTile
  1038. .noNewTiles
  1039.     ld a, c
  1040.     and 7
  1041.     ld [wTextCurPixel], a
  1042.     jr PrintNextCharInstant
  1043.  
  1044.  
  1045. TextNewline:
  1046.     ; Flush the current tile if non-blank
  1047.     ld a, [wTextCurPixel]
  1048.     cp 2
  1049.     call nc, FlushVWFBuffer
  1050.     ; Reset position
  1051.     xor a
  1052.     ld [wTextCurPixel], a
  1053.  
  1054.     ld de, wNbNewlines
  1055.     ld a, [de]
  1056.     inc a
  1057.     ld [de], a
  1058.     dec a
  1059.     add a, LOW(wNewlineTiles)
  1060.     ld e, a
  1061.     adc a, HIGH(wNewlineTiles)
  1062.     sub e
  1063.     ld d, a
  1064.     ld a, [wTextCurTile]
  1065.     ld [de], a
  1066.     ; Fall through
  1067.  
  1068. PrintNextCharInstant:
  1069.     xor a
  1070.     ld [wTextNextLetterDelay], a
  1071.     ret
  1072.  
  1073.  
  1074. TextWaitButton:
  1075.     xor a ; FIXME: if other bits than 7 and 6 get used, this is gonna be problematic
  1076.     ld [wTextPaused], a
  1077.     ldh a, [hHeldButtons]
  1078.     and PADF_B
  1079.     jr nz, PrintNextCharInstant
  1080.     ldh a, [hPressedButtons]
  1081.     rra ; Get PADF_A
  1082.     jr c, PrintNextCharInstant
  1083.     ; If no button has been pressed, keep reading this char
  1084.     ; Ensure the engine reacts on the very next frame to allow swallowing buttons
  1085.     ld a, 1
  1086.     ld [wTextNextLetterDelay], a
  1087.     ; We know that text is running, so it's fine to overwrite bit 7
  1088.     ld a, $40
  1089.     ld [wTextPaused], a
  1090.     ; Decrement src ptr so this char keeps getting read
  1091.     dec hl
  1092.     ret
  1093.  
  1094.  
  1095. TextHalt:
  1096.     ld a, [wTextPaused]
  1097.     set 7, a
  1098.     ld [wTextPaused], a
  1099.     ret
  1100.  
  1101.  
  1102. TextClear:
  1103.     push hl
  1104.     ldcoord hl, 1, 2, vTextboxTilemap
  1105.     ld bc, SCRN_X_B - 4
  1106.     call LCDMemsetSmallFromB
  1107.     ld l, LOW(SCRN_VX_B * 2 + 2)
  1108.     ld c, SCRN_X_B - 4
  1109.     call LCDMemsetSmallFromB
  1110.  
  1111.     ; Reset text printing
  1112.     ; Don't flush if current tile is empty
  1113.     ld a, [wTextCurPixel]
  1114.     cp 2
  1115.     ; Flush buffer to VRAM
  1116.     call nc, FlushVWFBuffer
  1117.     ; Reset position always, though
  1118.     xor a
  1119.     ld [wTextCurPixel], a
  1120.     ldcoord hl, 1, 2, vTextboxTilemap
  1121.     call SetPenPosition
  1122.  
  1123.     pop hl
  1124.     ret
  1125.  
  1126.  
  1127.  
  1128. SECTION "Charset data", ROM0
  1129.  
  1130. CharsetPtrs::
  1131.     dw LatinCharsetBasic
  1132.     ; TODO: add more charsets (bold, JP, etc.)
  1133.  
  1134.  
  1135. LatinCharsetBasic::
  1136. INCBIN "res/textbox/latin.font" ; Each letter is 8 1bpp bitplaces followed by a horiz length bit
RAW Paste Data
We use cookies for various purposes including analytics. By continuing to use Pastebin, you agree to our use of cookies as described in the Cookies Policy. OK, I Understand
 
Top