SECTION "ram_textwriter", WRAM0 textwriter_curtext: ds 2 textwriter_posx: ds 1 textwriter_posy: ds 1 textwriter_curdelay: ds 1 textwriter_active: ds 1 textwriter_starting: ds 1 textwriter_ending: ds 1 textwriter_pausing: ds 1 SECTION "rom_textmap", ROM0,ALIGN[8] textwriter_map: ; 00 01 02 03 04 05 06 07 08 09 0A 0B 0C 0D 0E 0F db $44,$50,$50,$50,$50,$50,$50,$50,$50,$50,$50,$50,$50,$50,$50,$50 ; 0 ; 10 11 12 13 14 15 16 17 18 19 1A 1B 1C 1D 1E 1F db $50,$50,$50,$50,$50,$50,$50,$50,$50,$50,$50,$50,$50,$50,$50,$50 ; 16 ; 20 21 22 23 24 25 26 27 28 29 2A 2B 2C 2D 2E 2F db $50,$41,$50,$45,$50,$50,$50,$43,$50,$50,$50,$50,$42,$50,$3F,$50 ; 32 ; 30 31 32 33 34 35 36 37 38 39 3A 3B 3C 3D 3E 3F db $35,$36,$37,$38,$39,$3A,$3B,$3C,$3D,$3E,$50,$50,$50,$50,$50,$40 ; 48 ; 40 41 42 43 44 45 46 47 48 49 4A 4B 4C 4D 4E 4F db $50,$01,$02,$03,$04,$05,$06,$07,$08,$09,$0A,$0B,$0C,$0D,$0E,$0F ; 64 ; 50 51 52 53 54 55 56 57 58 59 5A 5B 5C 5D 5E 5F db $10,$11,$12,$13,$14,$15,$16,$17,$18,$19,$1A,$50,$50,$50,$50,$50 ; 80 ; 60 61 62 63 64 65 66 67 68 69 6A 6B 6C 6D 6E 6F db $50,$1B,$1C,$1D,$1E,$1F,$20,$21,$22,$23,$24,$25,$26,$27,$28,$29 ; 96 ; 70 71 72 73 74 75 76 77 78 79 7A 7B 7C 7D 7E 7F db $2A,$2B,$2C,$2D,$2E,$2F,$30,$31,$32,$33,$34,$50,$50,$50,$50,$50 ; 112 SECTION "TextWriter", ROM0 InitWindow: ; Fill first line in window with straight line ld hl, (_SCRN1 + 1) ld b, 19 ld a, $52 call Memfill ; Fill rest of the area with dark bg call ClearWindow ; Fill last line in window with straight line ld hl, (_SCRN1 + $61) ld b, 19 ld a, $57 call Memfill ; Top left corner ld hl, _SCRN1 ld [hl], $51 ; Top right corner ld hl, _SCRN1 + 19 ld [hl], $53 ; Bottom Left corner ld hl, _SCRN1 + $60 ld [hl], $56 ; Bottom Right corner ld hl, _SCRN1 + $60 + 19 ld [hl], $58 ; Left line ld hl, _SCRN1 + $20 ld [hl], $54 ld hl, _SCRN1 + $40 ld [hl], $54 ; Right line ld hl, _SCRN1 + $20 + 19 ld [hl], $55 ld hl, _SCRN1 + $40 + 19 ld [hl], $55 ; Some other common memory addresses that should be filled ld a, 0 ld [textwriter_posx], a ld [textwriter_posy], a ld [textwriter_ending], a ld [textwriter_pausing], a ld [textwriter_active], a ld [textwriter_curdelay], a ld [textwriter_starting], a ret ; Return ClearWindow: ld hl, (_SCRN1 + $21) ld a, $50 ld b, 18 call Memfill ld hl, (_SCRN1 + $41) ld b, 18 call Memfill ret ; Start to print a string on screen ; @param de - Address source string ; @return a - garbage ; @return b - PosX on where to draw text ; @return c - PosY on where to draw text ; @return hl - Workram position for text pointer ; @return de - Memory address to source string StartText: ld a, 10 ld [textwriter_curdelay], a ld a, 0 ld [textwriter_posx], a ld [textwriter_posy], a ld [textwriter_ending], a ld [textwriter_pausing], a ld a, 1 ld [textwriter_active], a ld hl, textwriter_curtext ld a, d ld [hli], a ld a, e ld [hl], a dec hl ld a, 16 ld [textwriter_starting], a call ClearWindow ; Clear it just in case ret ; Draw text if one is currently active DrawActiveText: ld a, [textwriter_active] ; Check if text is currently active and a ret z ; If no text is active, just exit immediately ld a, [textwriter_starting] ; Check if we're booting up the window and a jr z, .afterLoading ; Jump to after loading if we're not loading ; We are loading the window ld a, [rWY] ; Get current window position dec a ; Decrement twice (moves it slowly up) dec a ld [rWY], a ; Set the position back into window ld a, [textwriter_starting] dec a ld [textwriter_starting], a jr z, .afterLoading ret .afterLoading ld a, [textwriter_ending] ; Check if we are ending and a jr z, .checkPausing ; If we are not ending, jump to check pause ; We are ending, animate the window back down ld a, [rWY] ; Get current window position inc a ; Increment twice inc a ld [rWY], a ; Set the position back into window ld a, [textwriter_ending] ; Grab the ending guy dec a ; Decrement it ld [textwriter_ending], a ; Set it back jr z, .closingAll ; If we reach zero, we can disable text renderer ret .closingAll ld [textwriter_active], a ret .checkPausing ld a, [textwriter_pausing] ; Check if we're in a paused state and a jr z, .checkDelay ; Jump to Delayer if we're not in paused state ld b, a ; We are in pause state so store pause state in register b ld a, [controller_newkeys] ; Check our controller and a, PAD_A|PAD_B ; Check if we pressed either A or B ret z ; Exit if he didn't dec b ; Decrement B, our paused state jr z, .continuingNextLine ; If paused state was 1 then we continue ;to render next line ; If we reach here, paused state was 2 which means we should ; end text reader ld a, 16 ; Set a to 1 ld [textwriter_ending], a ; Mark it as we are ending ret .continuingNextLine call ClearWindow ld a, 0 ld [textwriter_pausing], a ld [textwriter_posx], a ld [textwriter_posy], a jr .delayFinished .checkDelay ; Delay writing a letter by 10 frames if no button is down ld a, [textwriter_curdelay] dec a ld [textwriter_curdelay], a jr z, .delayFinished ld a, [controller_curkeys] ; Check our controller and a, PAD_B ret z ; If B button is being held, we skip any delay .delayFinished ; Reset the curdelay ld a, 10 ld [textwriter_curdelay], a .startdrawtext ; Get the memory address pointing to the text currently being ; displayed. This is stored in textwriter_curtext ld hl, textwriter_curtext ; Get the memory address of the pointer ld d, [hl] ; Store the first byte address to d inc hl ; Move to next byte ld e, [hl] ; Store the next byte address to e ; We now have the current letter being drawn at [de] ; Get the current X position for the text on screen ld hl, (_SCRN1 + $21) ; Load the top-left window position for our text ; Load the x position for current text position and ld a, [textwriter_posx] ld b, a ld a, l add b ; Add the x position ld l, a ; Get the current Y position for the text on screen ld a, [textwriter_posy] and a ; Check if it's zero jr z, .drawletter ; If not, jump forward by a whole line. ld a, l add a, $20 ld l, a .drawletter ld a, [de] ; Load the first byte in the string ld bc, textwriter_map ; Get the map for the ASCII->Tile map ld c, a ; Set the position of C to the ASCII byte of current character ld a, [bc] ; Get the tile byte for the ASCII from the map ld [hl], a ; Print the byte to the map .checkIsEnding ld a, [de] and a ; Check if we reached the end jr nz, .checkContinuing ; We have reached the end of the string, mark it ld a, 2 ld [textwriter_pausing], a jr .continue ; Jump straight to continue. No need to check anything .checkContinuing ld a, [de] ; Regrab the ascii byte we printed cp a, $23 ; Check if it's '#' jr nz, .checkNewline ; Jump to next check if it wasn't ld a, 1 ld [textwriter_pausing], a jr .continue .checkNewline ld a, [de] ; Regrab the ascii byte we printed cp a, $0A ; Check if it was a new line '\n' jr nz, .checkRepeatOnce ; Jump to checkRepeatOnce if it wasn't a new line ; The byte we printed was a new line so we increment Y position ; and reset our X position. ld a, -1 ; Usually we'd print into first position but since we're jumping ; into continue, continue will automatically increment x for us. ld [textwriter_posx], a ld a, 1 ld [textwriter_posy], a ; Set our Y position to 1 ld [textwriter_curdelay], a ; Also set curdelay to 1 as well jr .continue .checkRepeatOnce ld a, [bc] ; Regrab the tile we printer ; Check if we printed an empty letter cp a, $50 jr nz, .continue ld a, 1 ld [textwriter_curdelay], a ; Set curdelay to 1 so it immediately prints next character .continue ; Time to update our work ram inc de ; Increment de to next letter ; Load the position pointer of current text and update it to the next letter ld hl, textwriter_curtext ld a, d ld [hli], a ld a, e ld [hl], a ; Update the x position in ram ld a, [textwriter_posx] inc a ld [textwriter_posx], a .exit ld a, [textwriter_active] ret