; / \ ; ;| SPRITED TEXT |; ; \ / ; ;< Defines >; !InitFlag = $0F5E|!addr !WriteFlag = $0F5E|!addr+1 !Pointer = $0F5E|!addr+2 !OAMIndex = $0F5E|!addr+5 !VWFPointer = $0F5E|!addr+7 !WaitFrames = $0F5E|!addr+9 !HorzPos = $0F5E|!addr+10 !VertPos = $0F5E|!addr+11 !LtrProps = $0F5E|!addr+4 !StrLength = $0F5E|!addr+12 !CurLetter = $0F5E|!addr+13 !WaitTimer = $0F5E|!addr+14 !CurOption = $0F5E|!addr+13 !PtraitPtr = $0F5E|!addr+15 !CurLtrHPos = $0F5E|!addr+18 !OAMBuffX = $1F49|!addr ;\ !OAMBuffer = $1F4A|!addr+1 ;/ RAM freed by SRAM/BW-RAM plus. ;!DynMode = $0F5E|!addr+19 ;> From the scrapped dynamic OAM mode. ;< Main code >; SpritedText: stx $59 rep #$20 lda !InitFlag ;\ and #$00FF ; | If initialized, don't run code. bne .DontInitialize ;/ stz !VWFPointer sep #$20 inc !InitFlag ;> Mark as initialized. stz !WriteFlag ;> Just in case, zero writing flag. sta !OAMBuffX rep #$20 lda $08 ;\ sta !Pointer ;/ Store pointer. .DontInitialize lda !Pointer ;\ sta $08 ;/ Put pointer in scratch. sep #$20 lda !InitFlag cmp #$02 bne .ByteLoop dec : sta $13D4|!addr ;> Pause game. sta !InitFlag + ;< Byte loop >; .ByteLoop lda !WriteFlag ;\ beq + ;/ If we're not writing, load header or end message. jmp .Writing ;> Otherwise keep displaying message. + lda [$08] ;> Load byte. bmi .Command ;> If negative (#$80-#$FF), jump to command. bne .Header ;> If not zero (#$01-#$7F), treat as header. jmp .WriteLoop ;> Otherwise (zero), start writing. .Header rep #$20 inc $08 ;> Increment pointer. %LoadPointer() ;\ asl #2 ; | and #$01FC ; | Get OAM index. sta !OAMIndex ;/ %LoadPointer() ;\ sep #$20 ; | Get frames to wait per letter. sta !WaitFrames ;/ rep #$20 lda $08 sta !Pointer sep #$20 bra .ByteLoop .Command and #$7F ;\ asl ; | tax ; | Jump to command's code. jmp (.Com,x) ;/ ;< Writing >; .WriteLoop { stz !CurLtrHPos ;> rep #$20 lda !VWFPointer sta $0D sep #$10 inc $08 %LoadPointer() ;\ sta !HorzPos ;/ Store string's position. inc $08 ;\ %LoadPointer() ; | sep #$20 sta !LtrProps rep #$20 %LoadPointer() ; | sep #$20 ; | Store the length of the string. sta !StrLength ;/ stz !CurLetter ;> Initialize letter counter. inc !WriteFlag ;> Mark as writing. .WritingInit lda !WaitFrames ;\ sta !WaitTimer ;/ Initialize. lda $15 : ora $16 ;\ and #$40 ; | If Y not pressed, don't speed up text. beq .Writing ;/ lsr !WaitTimer ;> Cut frame counter per half. .Writing lda !WaitTimer ;\ beq + ;/ If frame counter has reached its end dec !WaitTimer ;> Decrement by 1. rep #$20 lda $08 ;\ sta !Pointer ;/ Store pointer. sep #$20 jsr UpdateOAM rtl ;> Return. + ;< Draw letter in OAM >; lda $0A sta $0F rep #$30 ;\ ldy !OAMIndex ; | Get OAM index in Y... tya : lsr #2 : tax ;/ ...and entry to high OAM table in X. lda !VWFPointer sta $0D %LoadPointer() ;\ sep #$20 ;/ Get letter byte. sta $0B stz $0C cmp #$FD ;\ beq + ;/ Don't draw if it's a space. sta $0202|!addr,y ;> Store tile. lda !CurLtrHPos ;\ clc : adc !HorzPos ; | Calculate and store horizontal position. sta $0200|!addr,y ;/ lda !LtrProps ;\ sta $0203|!addr,y ;/ stz $0420|!addr,x phy sep #$10 lda !OAMBuffX : tax lda !VertPos ;\ sta !OAMBuffer|!addr,x ;/ Store vertical position. inx txa sta !OAMBuffX rep #$10 ply iny #4 : sty !OAMIndex ;> Update OAM adress to the next one. lda $59 sta $1DF9|!addr lda !CurLtrHPos ldy !VWFPointer beq .NoVWF ldy $0B clc : adc [$0D],y bra .Skip + lda !CurLtrHPos .NoVWF clc : adc #$08 .Skip sta !CurLtrHPos inc !CurLetter ;> Increment how many letters we have written. lda !CurLetter ;\ cmp !StrLength ; | End writing if we have reached the amount of letters we wanted to write. beq .WritingEnd ;/ sep #$10 jmp .WritingInit .WritingEnd rep #$20 lda $08 ;\ sta !Pointer ;/ Store pointer. sep #$30 stz !WriteFlag stz !CurLetter jmp .ByteLoop } ; / \ ; ;| Commands code |; ; \ / ; .Com: dw ..Done ;> End read, store #$80 to !InitFlag. dw ..Confirm ;> Stop, show a blinking tile, and continue if player presses B/START. dw ..ClearText ;> Clear letter tiles. dw ..ChangeFrameWait ;> Change text speed. dw ..Options ;> Allow the player to select options. dw ..RunCode ;> Run code. dw ..DoneNoFlag ;> End read, without storing. dw ..JumpToLine ;> Branch to adress. dw ..Unlock ;> Unlock game. dw ..Lock ;> Lock game. dw ..Portrait ;> Dynamic portrait. dw ..VWFTablePointer ;> Set pointer to variable width table. ;< Finish read >; ..Done { lda #$80 ;\ Store #$80 to InitFlag. sta !InitFlag ;/ Your code can read this bit to stop calling the routine. ..DoneNoFlag jsr UpdateOAM rtl ;> Return to your UberASM. } ;< Wait for player input while showing a blinking tile >; ..Confirm { rep #$10 ;\ ldy !OAMIndex ; | rep #$20 ; | Get OAM index, low and high table. tya : lsr #2 : tax ;/ inc $08 : %LoadPointer() ;\ sta $0200|!addr,y ;/ Write horizontal & vertical position. inc $08 : %LoadPointer() ;\ inc $08 ; | Write tile and properties. sta $0202|!addr,y ;/ sep #$20 stz $0420|!addr,x ;> Make it 8x8 sized. inc !WaitTimer ;\ lda !WaitTimer ; | and #$18 ; | cmp #$18 ; | Recycle WaitTimer as blink timer. bne + ; | lda #$F0 ; | sta $0201|!addr,y ;/ + sep #$20 lda $16 ;\ and #$90 ; | beq + ; | Skip if there's no input. stz $16 ;/ lda #$F0 ;\ sta $0201|!addr,y ;/ Clear tile. rep #$20 lda $08 ;\ sta !Pointer ;/ Restore pointer. sep #$30 jmp .ByteLoop ;> Keep reading. + sep #$10 jsr UpdateOAM rtl ;> Return to your UberASM. } ;< Clear letter sprites >; ..ClearText { stz $00 rep #$30 inc $08 %LoadPointer() ;\ asl #2 ; | and #$01FC ; | Get OAM index to start clearing. sta $01 ;/ tay ;> Put OAM index in Y. lsr #2 tax sep #$20 ;\ lda #$F0 ;/ Load an OAM vertical position that is considered as "cleared". ..Loop0 sta $0201|!addr,y ;> Clear letter. stz $0420|!addr,x inc $00 inx iny #4 ;\ cpy !OAMIndex ; | Keep clearing if we haven't reached the current letter's OAM index. bne ..Loop0 ;/ ldy $01 ;\ sty !OAMIndex ;/ Set OAM index to the first one we cleared. ldy $08 ;\ sty !Pointer ;/ Restore pointer. sep #$30 lda !OAMBuffX sec : sbc $00 sta !OAMBuffX jmp .ByteLoop ;> Keep reading. } ;< Change text speed >; ..ChangeFrameWait { rep #$20 inc $08 %LoadPointer() sep #$20 sta !WaitFrames rep #$20 lda $08 sta !Pointer sep #$20 jmp .ByteLoop } ;< Show options for the player to select. Also contains JumpToLine >; ..Options { rep #$20 inc $08 ;\ %LoadPointer() ; | sep #$20 ; | Get cursor's tile. sta $0B ;/ lda !CurOption ;\ rep #$30 ; | and #$00FF ; | Option * 2 in $0E. asl : sta $0E ;/ asl #2 ;\ clc : adc $0E ; | clc : adc $08 ; | sta $08 ;/ ldy !OAMIndex ;\ tya : lsr #2 : tax ;/ OAM index in Y, for high table in X. %LoadPointer() : inc $08 ;\ sta $0200|!addr,y ;/ Get tile's horizontal and vertical pos. sep #$20 lda $0B ;\ sta $0202|!addr,y ;/ Write tile. lda #$39 ;\ sta $0203|!addr,y ;/ Write properties. stz $0420|!addr,x ;> Make it 8x8 sized. inc !WaitTimer ;\ lda !WaitTimer ; | and #$18 ; | cmp #$18 ; | Blink cursor by recycling WaitTimer. bne + ; | lda #$F0 ; | sta $0201|!addr,y ;/ + lda $16 ;\ and [$08] ; | beq ..NoPress ; | If defined button not pressed, skip. stz $16 ;/ lda #$F0 ;\ sta $0201|!addr,y ;/ Clear cursor tile. ;> Code for %TextBranch too. ..JumpToLine rep #$20 inc $08 lda [$08] : pha inc $08 : inc $08 : lda [$08] sep #$20 sta $0A rep #$20 pla : sta $08 : sta !Pointer sep #$30 jmp .ByteLoop ..NoPress rep #$20 lda $08 ;\ clc : adc #$0007 ; | Point to option's direction bytes. sta $08 ;/ sep #$30 ldx #$03 ;> Process the four directions. lda $16 ;> Load pressed inputs. ...Loop0 lsr : bcc + ;> Direction not pressed, ignore. pha ;> Preserve our procesed value. lda [$08] ;\ cmp !CurOption ; | Ignore if option to jump to is the same as the one we're on. beq ++ ;/ sta !CurOption ;> Store it. lda #$23 ;\ sta $1DFC|!addr ;/ Play a confirmation SFX. stz !WaitTimer ;> Clear wait timer. ++ pla ;> Get back processed value. + rep #$20 ;\ dec $08 ; | Point to next option's direction byte. sep #$20 ;/ dex : bpl ...Loop0 ;> Keep looping for each direction. jsr UpdateOAM rtl ;> Return to your UberASM. } ;< Run code >; ..RunCode { rep #$20 inc $08 : %LoadPointer() sta $0D inc $08 : %LoadPointer() sep #$20 sta $0F phk : pea.w ...Label0-1 : jmp [$000D|!dp] ...Label0 rep #$20 lda $08 : sta !Pointer sep #$20 jmp .ByteLoop } ;< Lock or unlock game >; ..Lock { lda #$02 ;\ sta !InitFlag ;/ Set to $13D4 the next frame. rep #$20 inc $08 lda $08 : sta !Pointer sep #$20 jsr UpdateOAM rtl ;> Return to your UberASM. ..Unlock stz $13D4|!addr ;> Clear pause flag. + rep #$20 inc $08 sep #$20 jmp .ByteLoop ;> Keep reading. } ;< Draw character portrait >; ..Portrait { rep #$20 inc $08 : %LoadPointer() sep #$10 tay sty $0B %LoadPointer() ;\ sta !PtraitPtr ; | inc $08 : %LoadPointer() ; | GFX location in ROM at $0D. tax : stx !PtraitPtr+2 ;/ ldy #$03 sty !InitFlag rep #$10 %LoadPointer() : sta $00 %LoadPointer() : sta $01 %LoadPointer() : sta $02 ldy !OAMIndex stz $0C ldx #$0000 ...DrawLoop jsr ...DrawRt iny #4 inx cpx $0B bcs ...End lda $00 clc : adc #$10 sta $00 jsr ...DrawRt iny #4 inx cpx $0B bcs ...End lda $00 sec : sbc #$10 sta $00 lda $01 clc : adc #$10 sta $01 bra ...DrawLoop ...End sty !OAMIndex lda $08 : sta !Pointer sep #$30 jsr UpdateOAM rtl ;> Return to your UberASM. ...DynamicTiles: db $C0,$C2,$E0,$E2,$C4,$C6,$E4,$E6 ;< Draw a tile from the portrait >; ...DrawRt lda.l ...DynamicTiles,x ;\ sta $0202|!addr,y ;/ Set tile. lda $02 : sta $0203|!addr,y ;> Set properties. lda $00 : sta $0200|!addr,y ;> Set horizontal position. rep #$20 phy tya : lsr #2 : tay sep #$20 lda #$02 ;\ sta $0420|!addr,y ;/ Tile is 16x16 sized. sep #$10 lda !OAMBuffX : tax lda $01 ;\ sta !OAMBuffer,x ;/ Store vertical position at buffer. txa inc sta !OAMBuffX rep #$10 ply rts } ;< Set pointer to VWF table >; ..VWFTablePointer { rep #$20 inc $08 : %LoadPointer() sta !VWFPointer inc $08 sep #$20 jmp .ByteLoop ;> Keep reading. } ; / \ ; ;| Update letters' OAM vertical position, else they would disappear |; ; \ / ; UpdateOAM: lda !OAMBuffX beq + rep #$30 and #$00FF ; tax ; dex sep #$20 ldy !OAMIndex dey #4 - lda !OAMBuffer,x ;\ sta $0201|!addr,y ;/ Set vertical position. dey #4 dex bpl - sep #$10 + rts