;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;; ;VWF Dialogues Patch by RPG Hacker; ;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;; header lorom sa1rom ;fastrom print "" print "VWF Dialogues Patch v1.01 - (c) 2014 RPG Hacker" ;;;;;;;;;;;;;;;; ;Adress Defines; ;;;;;;;;;;;;;;;; ; These have to be 24-Bit addresses! !varram = $703000 ; 270 bytes - Must be EVEN! assert (!varram%2) == 0 ; If not EVEN, this code will "gently" warn you about that !backupram = $710000 ; 16 kb to backup L3 graphics and tilemap !tileram = $714000 ; 16 kb for VWF graphics and tilemap ;;;;;;;;;;;;;;;;;; ;Default Settings; ;;;;;;;;;;;;;;;;;; ; These are the default values to use if not changed ingame. !defbg = #$02 !bgcolor = #$0842 !defframe = #$05 !framepalette = #$03 !bitmode = !8 !hijackbox = !true ;;;;;;;; ;Labels; ;;;;;;;; ; DO NOT EDIT THOSE!!! !vwfmode = !varram ; 1 byte !message = !varram+1 ; 2 bytes !counter = !varram+3 ; 1 byte !width = !varram+4 ; 1 byte !height = !varram+5 ; 1 byte !xpos = !varram+6 ; 1 byte !ypos = !varram+7 ; 1 byte !boxcolor = !varram+8 ; 6 bytes !boxbg = !varram+14 ; 1 byte !boxframe = !varram+15 ; 1 byte !boxcreate = !varram+16 ; 1 byte !boxpalette = !varram+17 ; 1 byte !freezesprites = !varram+18 ; 1 byte !beep = !varram+19 ; 1 byte !beepbank = !varram+20 ; 2 bytes !beepend = !varram+22 ; 1 byte !beependbank = !varram+23 ; 2 bytes !beepcursor = !varram+25 ; 1 byte !beepcursorbank = !varram+26 ; 2 bytes !beepchoice = !varram+28 ; 1 byte !beepchoicebank = !varram+29 ; 2 bytes !font = !varram+31 ; 1 byte !edge = !varram+32 ; 1 byte !space = !varram+33 ; 1 byte !frames = !varram+34 ; 1 byte !layout = !varram+35 ; 1 byte !soundoff = !varram+36 ; 1 byte !speedup = !varram+37 ; 1 byte !autowait = !varram+38 ; 1 byte !vrampointer = !varram+39 ; 2 bytes !currentwidth = !varram+41 ; 1 byte !currentheight = !varram+42 ; 1 byte !currentx = !varram+43 ; 1 byte !vwftextsource = !varram+44 ; 3 bytes !currenty = !varram+47 ; 1 byte !vwfbytes = !varram+48 ; 2 bytes !vwfgfxdest = !varram+50 ; 3 bytes !vwftilemapdest = !varram+53 ; 3 bytes !vwfpixel = !varram+56 ; 2 bytes !vwfmaxwidth = !varram+58 ; 1 byte !vwfmaxheight = !varram+59 ; 1 byte !vwfchar = !varram+60 ; 2 bytes !vwfwidth = !varram+62 ; 1 byte !vwfroutine = !varram+63 ; 15 bytes !vwftileram = !varram+78 ; 96 bytes !tile = !varram+174 ; 1 byte !property = !varram+175 ; 1 byte !currentpixel = !varram+176 ; 1 byte !firsttile = !varram+177 ; 1 byte !clearbox = !varram+178 ; 1 byte !wait = !varram+179 ; 1 byte !timer = !varram+180 ; 1 byte !teleport = !varram+181 ; 1 byte !telepdest = !varram+182 ; 2 bytes !telepprop = !varram+184 ; 1 byte !forcesfx = !varram+185 ; 1 byte !widthcarry = !varram+186 ; 1 byte !choices = !varram+187 ; 1 byte !cursor = !varram+188 ; 2 bytes !currentchoice = !varram+190 ; 1 byte !choicetable = !varram+191 ; 3 bytes !choicespace = !varram+194 ; 1 byte !choicewidth = !varram+195 ; 1 byte !cursormove = !varram+196 ; 1 byte !nochoicelb = !varram+197 ; 1 byte !cursorupload = !varram+198 ; 1 byte !cursorend = !varram+199 ; 1 byte !paletteupload = !varram+200 ; 1 byte !palbackup = !varram+201 ; 64 bytes !cursorfix = !varram+265 ; 1 byte !cursorvram = !varram+266 ; 2 bytes !cursorsrc = !varram+268 ; 2 bytes !8 = 0 !16 = 1 !false = 0 !true = 1 !8bit = "if !bitmode == !8 :" !16bit = "if !bitmode == !16 :" !hijack = "if !hijackbox == !true :" ;;;;;;;; ;Macros; ;;;;;;;; ; A simple macro to prepare VRAM operations macro vramprepare(vramsettings, vramaddress, readword, readbyte) lda sta $2115 rep #$20 lda sta $2116 ; "lda $2139" for word VRAM reads sep #$20 ; "lda $2139/$213A" for byte VRAM reads endmacro ; A simple Macro for DMA transfers macro dmatransfer(channel, dmasettings, destination, sourcebank, sourcehigh, sourcelow, bytes) lda sta $4300 lda sta $4301 lda ; I put the label close to the opcode sta $4302 ; to allow length definitions lda sta $4303 lda sta $4304 rep #$20 lda sta $4305 sep #$20 lda sta $420B endmacro ; A macro for MVN transfers macro mvntransfer(bytes, start, source, destination) phb lda.b # ; Calculate starting index sta $211B lda.b #>>16 sta $211B lda #$00 sta $211C lda sta $211C rep #$30 lda $2134 ; Add source address clc ; to get new source address adc.w # tax ldy.w # ; Destination address lda.w #-1 ; Number of bytes db $54 ; MVN opcode in Hex db >>16 db >>16 sep #$30 plb endmacro ; Macros for new banks !PrevFreespace = AutoFreespaceCleaner macro nextbank() freedata : prot !PrevFreespace cleartable !PrevFreespace += a !PrevFreespace: endmacro macro binary(identifier, data) Data: incbin endmacro macro source(identifier, data) Data: incsrc endmacro ; Macros for text files macro textstart() cleartable table vwftable.txt endmacro macro textend() !8bit db $00 db %00001000,%01111000,%11010001,%11000000,$01,%00100000 dw $7FFF,$0000 db %11110100 db %00001111,$13,$13,$23,$29 !8bit db $FA !8bit db $FF !16bit dw $FFFA !16bit dw $FFFF endmacro ;;;;;;;;; ;Hijacks; ;;;;;;;;; org $008055 ; Initialize RAM to prevent glitches autoclean jml InitCall;workaround for Asar bug ; or game crashes nop org $0081F2 ; V-Blank code goes here jml VBlank nop org $008297 ; Hijack NMI for various things jml NMIHijack nop #$2 org $0086E2 ; Call RAM Init Routine on Title jml InitMode ; Screen org $00A1DF ; Hijack message box to call VWF dialogue !hijack jsl MessageBox org $00A2A9 ; Buffer data before loading up to VRAM jml Buffer ; in V-Blank nop #2 ;org $00FFD8 ; SRAM expansion ($07 => 2^7 kb) ; db $07 ;;;;;;;;;;;;;;;;; ;MAIN CODE START; ;;;;;;;;;;;;;;;;; freecode : prot Kleenex ;;;;;;;;;;;;;;;;;;;; ;RAM Initialization; ;;;;;;;;;;;;;;;;;;;; ; This section handles RAM initialization. It initializes the used ; RAM addresses at game startup, title screen and Game Over to ; prevent glitches and possible crahses. InitCall: jsr InitRAM ; RAM init on game start STZ $6100 ; Clear the game mode STZ $6109 ; Clear the level number jml $00805B InitMode: sty $00 pha lda $6100 cmp #$03 bne .NoTitle jsr InitRAM ; RAM init on Title Screen .NoTitle pla rep #$30 jml $0086E6 InitRAM: phx rep #$30 ldx #$0000 lda #$0000 .InitVarRAM sta !varram,x ; Initialize RAM inx #2 cpx #$010e ; Number of bytes bne .InitVarRAM sep #$30 .SetDefaults lda !defbg ; Set default values sta !boxbg lda !defframe sta !boxframe lda.b !bgcolor sta !boxcolor lda.b !bgcolor>>8 sta !boxcolor+1 .End plx rts ;;;;;;;;;;;;;;;;;;;; ;Message Box Hijack; ;;;;;;;;;;;;;;;;;;;; ; This hijacks SMW's original message routine to work with VWF ; dialogues. MessageBox: lda !vwfmode ; Already displaying a message? beq .CallDialogue stz $7426 rtl .CallDialogue lda $7426 ; Yoshi Special Message? cmp #$03 bne .NoYoshi lda #$01 sta !message bra .SetMessage .NoYoshi lda $6109 ; Intro Level Message? beq .NoIntro lda #$00 sta !message bra .SetMessage .NoIntro lda $03BB9B ; Inside Yoshi's House? (LM hacked cmp #$FF ; ROM only) bne .HackedROM lda #$28 .HackedROM cmp $73BF bne .NoYoshiHouse lda $787A ; Currently riding Yoshi? beq .NoYoshiHouse lda #$02 sta $7426 .NoYoshiHouse lda $73BF ; No special message, use regular message asl ; formula clc adc $7426 dec sta !message .SetMessage lda #$00 sta !message+1 stz $7426 lda #$01 sta !vwfmode .End rtl ;;;;;;;;;;;; ;NMI Hijack; ;;;;;;;;;;;; ; This changes the NMI Routine to move layer 3 and disable IRQ during ; dialogues. NMIHijack: phx lda !vwfmode tax lda.l .NMITable,x bne .SpecialNMI ; If NMITable = $00 load regular NMI sty $4209 stz $420A stz $11 lda #$A1 sta $4200 stz $2111 stz $2111 stz $2112 stz $2112 bra .End .SpecialNMI stz $11 ; Else load special NMI lda #$81 ; Disable IRQ sta $4200 lda #$00 ; Set layer 3 X scroll to $0100 sta $2111 lda #$01 sta $2111 lda #$1F ; Set layer 3 Y scroll to $011F sta $2112 lda #$01 sta $2112 .End plx jml $0082B0 .NMITable db $00,$00,$00,$01,$01 db $01,$01,$01,$01,$01 db $01,$01,$01,$00,$00 ;;;;;;;;;;;;; ;Tile Buffer; ;;;;;;;;;;;;; ; This buffers code to save time in V-Blank. Buffer: phx phy pha phb php phk plb lda $73D4 beq .NoPause bra .End .NoPause lda !vwfmode ; Prepare jump to routine beq .End asl tax lda .Routinetable,x sta $00 inx lda .Routinetable,x sta $01 phk pla sta $02 lda !freezesprites ; Freeze sprites if flag is set beq .NoFreezeSprites lda #$02 sta $73FB sta $9D sta $73D3 lda $15 and #$BF sta $15 lda $16 and #$BF sta $16 lda $17 and #$BF sta $17 lda $18 and #$BF sta $18 .NoFreezeSprites jml [$6000] .End plp ; Return plb pla ply plx lda $1C pha lda $1D pha jml $00A2AF .Routinetable dw .End,.End,VWFSetup,BufferGraphics,.End dw .End,BufferWindow,VWFInit,TextCreation,CollapseWindow dw .End,.End,.End,.End,.End VWFSetup: jsr GetMessageAndHeader jmp Buffer_End BufferGraphics: rep #$30 ldx #$0000 lda #$0000 .DrawEmpty sta !tileram,x ; Draw empty tile inx #2 cpx #$0010 bne .DrawEmpty sep #$30 jsr ClearScreen ; Copy text box graphics over to RAM %mvntransfer($0010,!boxbg,Patterns,!tileram+16) %mvntransfer($0090,!boxframe,Frames,!tileram+32) jmp Buffer_End ; This routine clears the screen by filling the tilemap with $00. ClearScreen: lda Emptytile sta !tile lda !boxpalette asl #2 ora Emptytile+1 sta !property rep #$30 ldx #$0000 lda !tile .InitTilemap sta !tileram+$3900,x inx #2 cpx #$0700 bne .InitTilemap sep #$30 rts BufferWindow: lda !counter ; Buffer text box tilemap bne .SkipInit lda #$00 ; Text box init sta !currentwidth sta !currentheight lda !xpos clc adc !width sta !currentx lda !ypos clc adc !height sta !currenty lda #$01 sta !counter .SkipInit lda !boxcreate ; Prepare jump to routine asl tax lda.l .Routinetable,x sta $00 inx lda.l .Routinetable,x sta $01 phk pla sta $02 jml [$6000] .Routinetable dw .NoBox,.SoEBox,.SoMBox,.MMZBox,.InstBox .End jmp Buffer_End .NoBox lda #$02 ; No text box sta !counter jmp .End .SoEBox lda !xpos sta !currentx lda !ypos sta !currenty lda !width asl sta !currentwidth jsr DrawBox lda !height asl cmp !currentheight bne .SoEEnd lda #$02 sta !counter .SoEEnd lda !currentheight inc sta !currentheight jmp .End .SoMBox lda !width asl cmp !currentwidth beq .ExpandVert jsr SoMLine lda !currentwidth inc #2 sta !currentwidth lda !currentx dec sta !currentx jmp .End .ExpandVert lda !height asl cmp !currentheight bcc .SoMEnd jsr DrawBox lda !currentheight inc #2 sta !currentheight lda !currenty dec sta !currenty jmp .End .SoMEnd lda #$02 sta !counter jmp .End .MMZBox lda !xpos sta !currentx lda !ypos sta !currenty lda !height asl sta !currentheight jsr DrawBox lda !width asl cmp !currentwidth bne .MMZEnd lda #$02 sta !counter .MMZEnd lda !currentwidth inc sta !currentwidth jmp .End .InstBox lda !xpos sta !currentx lda !ypos sta !currenty lda !width asl sta !currentwidth lda !height asl sta !currentheight jsr DrawBox .InstEnd lda #$02 sta !counter jmp .End SoMLine: lda !currentx sta $00 lda !currenty sta $01 lda #$01 sta $02 jsr GetTilemapPos rep #$20 lda.w #!tileram+$3900 clc adc $03 sta $03 sep #$20 lda.b #!tileram+$3900>>16 sta $05 ldy #$00 lda.b !framepalette<<2|$20 xba jsr LineLoop ldy #$40 lda.b !framepalette<<2|$A0 xba jsr LineLoop rts LineLoop: lda !currentwidth lsr inc tax phx lda #$08 rep #$20 and #$BFFF sta [$03],y dex iny #2 inc .Loop1 cpx #$00 beq .Prepare2 sta [$03],y dex iny #2 bra .Loop1 .Prepare2 ora #$4000 plx .Loop2 cpx #$01 beq .End sta [$03],y dex iny #2 bra .Loop2 .End dec sta [$03],y sep #$20 rts ; This routine takes the variables !currentx, !currenty, ; !currentwidth and !currentheight to create a complete text box ; in RAM, utilizing all of the the subroutines below. DrawBox: lda !currentx ; Create background sta $00 lda !currenty sta $01 lda.b #!tileram+$3900 sta $03 lda.b #!tileram+$3900>>8 sta $04 lda.b #!tileram+$3900>>16 sta $05 lda !currentwidth sta $06 lda !currentheight sta $07 jsr DrawBG lda !currentx ; Create frame sta $00 lda !currenty sta $01 lda.b #!tileram+$3900 sta $03 lda.b #!tileram+$3900>>8 sta $04 lda !currentwidth sta $06 lda !currentheight sta $07 jsr AddFrame rts ; This subroutine calculates the correct position of a tilemap with ; $7E0000 as X coordinate and $7E0001 as Y coordinate. ; If $7E0002 = $01 then the tilemap consists of two bytes per tile. ; The result is returned at $7E0003-$7E0004 to be added to the ; tilemap starting address after this routine is done. GetTilemapPos: lda $02 ; Tilemap consists of double bytes? beq .NoDouble lda $00 asl sta $00 lda #$20 asl bra .Store .NoDouble lda #$20 .Store sta $211B ; Multiply Y coordinate by $20/$40 lda #$00 sta $211B sta $211C lda $01 sta $211C lda #$00 xba lda $00 rep #$20 clc adc $2134 sta $03 sep #$20 lda $02 beq .End lda $00 ; Half $7E0000 again if previously doubled lsr sta $00 .End rts ; This draws the background of a text box. $7E0001-$7E0004 are the ; same as in GetTilemapPos, but $7E0002 gets set automatically. ; $7E0006 contains the width and $7E0007 the height of the text box. ; $7E0008-$7E000A are used as temporary variables. DrawBG: lda $06 ; Skip if width or height equal $00 beq .End lda $07 beq .End lda $01 sta $0A lda $07 ; Load text box height and add y position clc ; for a backwards loop adc $01 sta $01 lda #$01 sta $02 lda $03 sta $08 lda $04 sta $09 .InstLoopY jsr GetTilemapPos ; Get tilemap position rep #$20 lda $08 clc adc $03 sta $03 sep #$20 lda $06 asl tay lda !boxpalette asl #2 ora #$20 xba lda #$01 rep #$20 .InstLoopX sta [$03],y ; Create row dey #2 bne .InstLoopX sep #$20 dec $01 lda $01 cmp $0A bne .InstLoopY ; Loop to create multiple rows .End rts ; A routine which creates a text box frame in RAM. $7E0000-$7E0004 ; are used the same way as in GetTilemapPos, except for $7E0002, ; which is used as a temporary variable here. $7E0005 contains the ; tilemap bank, $7E0006 the text box width and $7E0007 the text box ; height. $7E0008-$7E000D are used as temporary variables. At the ; same time $7E000A is the tile number and $7E000B the "flip ; vertically" flag for the DrawTile subroutine. AddFrame: lda $03 ; Preserve tilemap address sta $08 lda $04 sta $09 jsr SetPos lda $07 ; Draw central tiles (vertical) inc #2 sta $0C lda #$07 sta $0A stz $0B .VerticalLoop jsr DrawTile rep #$20 lda $03 clc adc #$0040 sta $03 sep #$20 dec $0C lda $0C bne .VerticalLoop jsr DrawLine ; Draw top and bottom of text box lda #$01 sta $02 lda $01 sta $0D inc $01 jsr SetPos lda #$06 sta $0A jsr DrawTile lda $0D clc adc $07 sta $01 jsr SetPos lda #$80 sta $0B jsr DrawTile inc $01 jsr DrawLine lda $0D sta $01 rts ; Draw horizontal lines of the text box frame DrawLine: lda #$04 ; Prepare filling sta $0A jsr SetPos lda $06 beq .ZeroWidth inc lsr sta $0C and #$01 ; If uneven width skip first tile beq .HorizontalLoop bra .SkipDraw .HorizontalLoop jsr DrawTile ; Fill lines horizontally .SkipDraw rep #$20 inc $03 inc $03 dey #4 sep #$20 dec $0C lda $0C bne .HorizontalLoop lda #$05 ; Draw central part sta $0A jsr DrawTile jsr SetPos rep #$20 inc $03 inc $03 dey #4 sep #$20 lda #$03 ; Draw second and second last tile sta $0A jsr DrawTile jsr SetPos .ZeroWidth lda #$02 ; Draw outer parts sta $0A jsr DrawTile rts ; A short routine to easier get the position for drawing tiles SetPos: jsr GetTilemapPos rep #$20 lda $08 clc adc $03 sta $03 sep #$20 lda $06 ; Use Y register for right half of text box asl inc #2 tay rts ; Draw one or two tiles in a line DrawTile: lda.b !framepalette<<2|$20 ora $0B ; Vertical flip? xba lda $0A ; Tile number rep #$20 sta [$03] cpy #$00 beq .End ora #$4000 sta [$03],y .End sep #$20 rts CollapseWindow: lda !counter ; Collapse text box bne .SkipInit lda !width asl sta !currentwidth lda !height asl sta !currentheight lda !xpos ; Text box init sta !currentx lda !ypos sta !currenty lda #$01 sta !counter .SkipInit lda !boxcreate ; Prepare jump to routine asl tax lda.l .Routinetable,x sta $00 inx lda.l .Routinetable,x sta $01 phk pla sta $02 jml [$6000] .Routinetable dw .NoBox,.SoEBox,.SoMBox,.MMZBox,.InstBox .End jmp Buffer_End .NoBox jsr ClearScreen lda #$02 sta !counter jmp .End .SoEBox lda !xpos sta !currentx lda !ypos sta !currenty lda !width asl sta !currentwidth jsr DrawBox lda !ypos clc adc !currentheight inc #2 sta $01 jsr ClearHoriz lda !currentheight bne .SoEEnd lda #$02 sta !counter .SoEEnd lda !currentheight dec sta !currentheight jmp .End .SoMBox lda !currentheight beq .CollapseHorz lda !currenty sta $01 jsr ClearHoriz lda !currenty clc adc !currentheight inc #1 sta $01 jsr ClearHoriz lda !currentheight dec #2 sta !currentheight lda !currenty inc sta !currenty jsr DrawBox jmp .End .CollapseHorz lda !currentwidth cmp #$00 beq .SoMEnd lda !currentx sta $00 jsr ClearVert lda !currentx clc adc !currentwidth inc #1 sta $00 jsr ClearVert lda !currentwidth dec #2 sta !currentwidth lda !currentx inc sta !currentx jsr SoMLine jmp .End .SoMEnd lda #$02 sta !counter jmp .End .MMZBox lda !xpos sta !currentx lda !ypos sta !currenty lda !height asl sta !currentheight jsr DrawBox lda !xpos clc adc !currentwidth inc #2 sta $00 jsr ClearVert lda !currentwidth bne .MMZEnd lda #$02 sta !counter .MMZEnd lda !currentwidth dec sta !currentwidth jmp .End .InstBox jsr ClearScreen lda #$02 sta !counter jmp .End ; Clears a vertical line at X position $7E0000. ClearVert: lda Emptytile sta !tile lda !boxpalette asl #2 ora Emptytile+1 sta !property stz $01 lda #$01 sta $02 jsr GetTilemapPos lda.b #!tileram+$3900>>16 sta $05 rep #$20 lda.w #!tileram+$3900 clc adc $03 sta $03 ldy #$00 .FillLoop lda !tile sta [$03] lda $03 clc adc #$0040 sta $03 iny cpy #$1C bne .FillLoop sep #$20 rts ; Clears a horizontal line at Y position $7E0001. ClearHoriz: lda Emptytile sta !tile lda !boxpalette asl #2 ora Emptytile+1 sta !property stz $00 lda #$01 sta $02 jsr GetTilemapPos lda.b #!tileram+$3900>>16 sta $05 rep #$20 lda.w #!tileram+$3900 clc adc $03 sta $03 ldy #$00 lda !tile .FillLoop sta [$03],y iny #2 cpy #$40 bne .FillLoop sep #$20 rts VWFInit: jsr GetMessageAndHeader lda !boxpalette ; Update letter color asl #2 inc inc asl phy tay ldx #$00 .BoxColorLoop lda !boxcolor+2,x sta $6703,y inx iny cpx #$04 bne .BoxColorLoop ply lda #$01 sta !paletteupload jsr ClearBox .End jmp Buffer_End InitLine: lda #$01 sta !firsttile lda !edge ; Reset pixel count sta !currentpixel lda #$00 sta !widthcarry lda !width ; Reset available width asl #4 sec sbc !currentpixel sec sbc !currentpixel sta !vwfmaxwidth lda !currentchoice beq .NoChoicePixels lda !currentpixel clc adc !choicewidth sta !currentpixel lda !vwfmaxwidth sec sbc !choicewidth sta !vwfmaxwidth jmp .RegularLayout .NoChoicePixels lda !layout ; Centered layout? bne .Centered jmp .RegularLayout .Centered lda #$00 sta !vwfwidth sta !currentwidth lda !vwftextsource pha lda !vwftextsource+1 pha lda !vwftextsource+2 pha lda !font pha .WidthBegin jsr WordWidth lda !widthcarry beq .NoCarry lda #$00 sta !widthcarry lda !currentwidth bne .WidthEnd lda !vwfwidth sta !currentwidth bra .WidthEnd .NoCarry lda !vwfwidth sta !currentwidth !16bit rep #$20 lda !vwfchar !8bit cmp #$FE !16bit cmp #$FFFE !16bit sep #$20 bne .WidthEnd lda !vwfwidth clc adc !space bcs .WidthEnd cmp !vwfmaxwidth bcs .WidthEnd sta !vwfwidth bra .WidthBegin .WidthEnd lda !vwfmaxwidth sec sbc !currentwidth lsr clc adc !currentpixel sta !currentpixel pla sta !font pla sta !vwftextsource+2 pla sta !vwftextsource+1 pla sta !vwftextsource !16bit rep #$20 !16bit lda #$0000 !8bit lda #$00 sta !vwfchar !16bit sep #$20 .RegularLayout lda #$00 sta !currentx lda !currenty inc #2 sta !currenty cmp !vwfmaxheight bcc .NoClearBox lda !choices beq .NoChoicesClear lda #$01 sta !cursormove bra .NoClearBox .NoChoicesClear lda #$01 sta !clearbox lda !autowait beq .NoClearBox cmp #$01 beq .ButtonWait lda !autowait sta !wait bra .NoClearBox .ButtonWait jsr EndBeep !8bit lda #$FA !16bit rep #$20 !16bit lda #$FFFA sta !vwfchar !16bit sep #$20 .NoClearBox rep #$20 lda !tile ; Increment tile counter inc #2 sta !tile and #$03FF asl #4 clc adc.w #!tileram ; Add starting address sta $09 sep #$20 lda.b #!tileram>>16 sta $0B lda !currentpixel sta $4204 .NoNewTile lda #$00 sta $4205 lda #$08 sta $4206 nop #8 lda $4216 sta !currentpixel rep #$20 lda $4214 asl clc adc !tile sta !tile sep #$20 lda $4214 clc adc !currentx sta !currentx lda !currentchoice beq .End dec sta !currentchoice bne .End lda #$01 sta !cursormove .End rts ClearBox: jsr ClearScreen lda !boxcreate beq .Init lda !xpos sta !currentx lda !ypos sta !currenty lda !width asl sta !currentwidth lda !height asl sta !currentheight jsr DrawBox bra .Init .Init lda #$FE sta !currenty lda #$09 sta !tile lda !boxpalette asl #2 ora Emptytile+1 sta !property lda !height asl sta !vwfmaxheight jsr InitLine rts GetMessageAndHeader: REP #$20 LDY #GetMessageGSU>>16 LoadHeader_Base: LDA #GetMessageGSU JMP $1E80 GetMessageGSU: ;The GSU (only) routine takes ~30 bytes less than it's predecessor and takes ~50 cycles less as well ;Also, it doesn't matter if the routine is on cache or not, the result is equivalent of ~4 microseconds faster than SA-1 ;1.1 - Merged these two routines, spares SNES/GSU time! arch superfx CACHE SUB R0 ;\ Reset SRAM bank RAMB ;/ IBT R0,#Pointers>>16 ;Since GSU can't access +$5F banks, it's safe to assume 8-bit values here (without sign extend) ROMB ;Get ROM Bank LM R0,(!message) ;The operation below does this MULT #3 ;Message*3+Pointers = ROM Address IWT R1,#Pointers TO R14 ADD R1 IWT R11,#!vwftextsource IBT R12,#$03 MOVE R13,R15 INC R2 GETB STB (R11) INC R11 LOOP INC R14 base (LoadHeader_Base+3)&0xFF00|(LoadHeader_Base+2)&0x00FF MOVE R0,(!vwftextsource+2) ;\ Get ROM Bank ROMB ;/ MOVE R14,(!vwftextsource) ; Get ROM Address of the VWF text MOVE R5,R14 ; Backup ROM address !8bit GETB ;\ Get message font !8bit INC R14 ;| !8bit LEA R1,!font ;| !8bit MOVEB (R0),R1 ;/ GETB ;\ Get X position INC R14 ;| <> Increment for Y-Pos operation MOVE R2,R0 ;| You may ask why I copied the value to R2... REP 3 : LSR ;| You'll see soon... LEA R1,!xpos ;| MOVEB (R0),R1 ;/ MOVE R9,R0 FROM R2 ;\ Get Y position GETBH ;| Get the ROM data and place it in High Byte of R2 SWAP ;| Swap bytes and do AND operation, just like the original IWT R2,#$07C0 ;| AND R2 ;| REP 6 : LSR ;| LEA R1,!ypos ;| MOVEB (R0),R1 ;/ MOVE R11,R0 GETB ;\ Get Width INC R14 ;| <> Increment for Height operation MOVE R2,R0 ;| Same thing as above... IBT R3,#$3C ;| AND R3 ;| REP 2 : LSR ;| LEA R1,!width ;| MOVEB (R0),R1 ;/ MOVE R7,R0 FROM R2 ;\ Get Height GETBH ;| Get the ROM data and place it in High Byte of R2 SWAP ;| IWT R2,#$03C0 ;| AND R2 ;| REP 6 : LSR ;| LEA R1,!height ;| MOVEB (R0),R1 ;/ MOVE R8,R0 GETB ;\ Get Edge INC R14 ;| <> Increment for Space operation MOVE R2,R0 ;| Same thing as above... IBT R3,#$3C ;| AND R3 ;| REP 2 : LSR ;| LEA R1,!edge ;| MOVEB (R0),R1 ;/ FROM R2 ;\ Get Space GETBH ;| Get the ROM data and place it in High Byte of R2 SWAP ;| IWT R2,#$03C0 ;| AND R2 ;| REP 6 : LSR ;| LEA R1,!space ;| MOVEB (R0),R1 ;/ GETB ;\ Get Text Speed INC R14 ;| IBT R2,#$3F ;| AND R2 ;| LEA R1,!frames ;| MOVEB (R0),R1 ;/ GETB ;\ Get Auto Wait INC R14 ;| LEA R1,!autowait;| MOVEB (R0),R1 ;/ GETB ;\ Get Box Creation Style INC R14 ;| REP 4 : LSR ;| LEA R1,!boxcreate;| MOVEB (R0),R1 ;/ MOVE R12,R0 ; HINT: You know why I put R14 just after GETB? To buffer ROM data and reduce WAIT time. GETB ;\ Get Letter Color INC R14 ;| Unfortunately, I handed a bit of WAIT time in order to improve GETBH ;| Size and apparently speed INC R14 ;| SM (!boxcolor+2),R0 ;/ GETB ;\ Get Shading Color INC R14 ;| Same case as above... GETBH ;| INC R14 ;| SM (!boxcolor+4),R0 ;/ GETB ;\ Get the "Freeze sprites?" byte... MOVE R1,R0 ;| REP 7 : LSR ;| And store the result of LSRs to addresses below LEA R6,!freezesprites ;| LEA R2,$13FB ;| LEA R3,$9D ;| <> Stupid sign extending LEA R4,$13D3 ;| MOVEB (R0),R6 ;| MOVEB (R0),R2 ;| MOVEB (R0),R3 ;| MOVEB (R0),R4 ;/ BEQ .NoFreezeSprites ; <>If the above operation results in NO Freeze Byte set, branch NOP IBT R3,#$15 ;\ AND #$BF : STA $15 IWT R2,#$BF ;| AND R2 ;| MOVEB (R0),R3 ;/ INC R3 ;\ AND #$BF : STA $16 MOVEW R0,(R3) ;| AND R2 ;| MOVEB (R0),R3 ;/ INC R3 ;\ AND #$BF : STA $17 MOVEW R0,(R3) ;| AND R2 ;| MOVEB (R0),R3 ;/ INC R3 ;\ AND #$BF : STA $18 MOVEW R0,(R3) ;| AND R2 ;| MOVEB (R0),R3 ;/ .NoFreezeSprites IBT R2,#$70 ;\ Get Letter Palette FROM R1 ;| AND R2 ;| REP 4 : LSR ;| LEA R2,!boxpalette;| MOVEB (R0),R2 ;/ FROM R1 ;\ Get Layout AND #8 ;| REP 3 : LSR ;| LEA R2,!layout ;| MOVEB (R0),R2 ;/ FROM R1 ;\ Get Speed Up byte AND #4 ;| LSR ;| LSR ;| LEA R2,!speedup ;| MOVEB (R0),R2 ;/ INC R14 ;<> Skip byte already FROM R1 ;\ Disable sounds byte AND #1 ;| LEA R2,!soundoff;| ALT1 ;|<> Trick to avoid waste BNE .NoSounds ;| If the above operation gives !=0, branch STW (R2) ;/ NOTE: That isn't a STW GETB ; Get SFX banks MOVE R1,R0 INC R14 LEA R2,$C0 LEA R3,$1DF9 AND R2 REP 6 : LSR ADD R3 SM (!beepbank),R0 IBT R2,#$30 FROM R1 AND R2 REP 4 : LSR ADD R3 SM (!beependbank),R0 FROM R1 AND #12 LSR LSR ADD R3 SM (!beepcursorbank),R0 FROM R1 AND #3 ADD R3 SM (!beepchoicebank),R0 GETB ;\ SFX numbers INC R14 ;| LEA R2,!beep ;| MOVEB (R0),R2 ;/ GETB ;\ INC R14 ;| LEA R2,!beepend ;| MOVEB (R0),R2 ;/ GETB ;\ INC R14 ;| LEA R2,!beepcursor ;| MOVEB (R0),R2 ;/ GETB ;\ INC R14 ;| LEA R2,!beepchoice ;| MOVEB (R0),R2 ;/ WITH R5 ADD #5 .NoSounds FROM R5 !8bit ADD #12 !16bit ADD #11 SM (!vwftextsource),R0 .ValidationChecks ;R7 = Width backup | R8 = Height Backup | R9 = X-Pos Backup | R11 = Y-Pos Backup | R12 = Box creation Backup IBT R0,#$10 IBT R6,#$01 FROM R7 ; Validate all inputs CMP R0 BCC .WidthCheck2 NOP DEC R0 LEA R1,!width MOVEB (R0),R1 MOVE R7,R0 BRA .WidthOK NOP .WidthCheck2 MOVES R7,R7 BNE .WidthOK NOP LEA R1,!width MOVEB (R6),R1 MOVE R7,R6 .WidthOK IBT R0,#$0E FROM R8 CMP R0 BCC .HeightCheck2 NOP DEC R0 LEA R1,!height MOVEB (R0),R1 MOVE R8,R0 BRA .HeightOK NOP .HeightCheck2 MOVES R8,R8 BNE .HeightOK NOP LEA R1,!height MOVEB (R6),R1 MOVE R8,R6 .HeightOK IBT R1,#$0F IBT R6,#$21 FROM R7 ROL ADD #2 MOVE R13,R0 ADD R9 CMP R6 BCC .XPosOK NOP DEC R6 FROM R6 SUB R13 LEA R1,!xpos MOVEB (R0),R1 .XPosOK IBT R6,#$1D FROM R8 ROL ADD #2 MOVE R13,R0 ADD R11 CMP R6 BCC .YPosOK NOP DEC R6 FROM R6 SUB R13 LEA R1,!ypos MOVEB (R0),R1 .YPosOK IBT R6,#$03 FROM R7 CMP R6 BCS .EdgeOK NOP LEA R1,!edge LDW (R1) AND #7 STB (R1) DEC R6 FROM R7 CMP R6 BCS .EdgeOK SUB R0 STB (R1) .EdgeOK IBT R6,#$05 FROM R12 CMP R6 BCC .StyleOK DEC R6 LEA R1,!boxcreate WITH R6 STB (R1) .StyleOK STOP base off arch 65816 TextCreation: lda !wait beq .NoWait jmp .End .NoWait lda !cursormove bne .Cursor jmp .NoCursor .Cursor lda !currentchoice bne .NotZeroCursor lda #$01 sta !currentchoice lda #$00 sta $0F jsr BackupTilemap jmp .DisplayCursor .NotZeroCursor lda $16 and #$0C bne .CursorMove lda $18 and #$80 cmp #$80 beq .ChoicePressed jmp .End .ChoicePressed jsr ButtonBeep jmp .CursorEnd .CursorMove lda #$01 sta $0F jsr BackupTilemap lda $16 and #$0C cmp #$08 bcs .CursorUp lda !currentchoice inc sta !currentchoice bra .CursorSFX .CursorUp lda !currentchoice dec sta !currentchoice .CursorSFX jsr CursorBeep lda !currentchoice beq .ZeroCursor lda !choices cmp !currentchoice bcs .DisplayCursor lda #$01 sta !currentchoice bra .DisplayCursor .ZeroCursor lda !choices sta !currentchoice .DisplayCursor lda #$01 sta !cursorupload lda #$00 sta $0F jsr BackupTilemap %mvntransfer($0060, #$00, !tileram+$38A0, !vwftileram) lda !choicespace cmp #$08 bcs .NoChoiceCombine lda !choicewidth clc adc !edge lsr #3 asl tax rep #$20 lda !tileram+$3894,x and #$03FF asl #4 clc adc.w #!tileram sta $03 sep #$20 lda.b #!tileram>>16 sta $05 lda !choicewidth clc adc !edge lsr #3 asl #5 tax ldy #$00 .CombineLoop lda !vwftileram,x inx ora !vwftileram,x dex eor #$FF and [$03],y ora !vwftileram,x sta !vwftileram,x inx iny cpy #$20 bne .CombineLoop .NoChoiceCombine jmp .End .CursorEnd lda #$01 sta !cursorend jmp .End .NoCursor !16bit rep #$20 lda !vwfchar !8bit cmp #$FA !16bit cmp #$FFFA !16bit sep #$20 bne .NoButton jmp .End .NoButton lda !clearbox beq .NoClearBox jsr ClearBox jmp .End .NoClearBox jsr ReadPointer !16bit rep #$20 lda [$00] sta !vwfchar !16bit inc $00 !8bit cmp #$EC !16bit cmp #$FFEC bcs .Jump !16bit sep #$20 jmp .WriteLetter .Jump sec !8bit sbc #$EC !16bit sbc #$FFEC !16bit sep #$20 asl tax lda.l .Routinetable,x sta $0C inx lda.l .Routinetable,x sta $0D phk pla sta $0E !16bit jsr IncPointer jml [$600C] .Routinetable dw .EC_PlayBGM dw .ED_ClearBox dw .EE_ChangeColor dw .EF_Teleport dw .F0_Choices dw .F1_Execute dw .F2_ChangeFont dw .F3_ChangePalette dw .F4_Character dw .F5_RAMCharacter dw .F6_HexValue dw .F7_DecValue dw .F8_TextSpeed dw .F9_WaitFrames dw .FA_WaitButton dw .FB_TextPointer dw .FC_LoadMessage dw .FD_LineBreak dw .FE_Space dw .FF_End .EC_PlayBGM ldy #$01 lda [$00],y sta $7DFB jsr IncPointer jsr IncPointer jmp .NoButton .ED_ClearBox lda !choices beq .EDNoChoices jmp .FD_LineBreak .EDNoChoices lda #$01 sta !clearbox jsr IncPointer jmp TextCreation .EE_ChangeColor phx ldy #$01 lda [$00],y asl tax iny lda [$00],y sta $6703,x iny lda [$00],y sta $6704,x plx lda #$01 sta !paletteupload jsr IncPointer jsr IncPointer jsr IncPointer jsr IncPointer jmp .NoButton .EF_Teleport ldy #$01 lda [$00],y sta !telepdest iny lda [$00],y sta !telepdest+1 iny lda [$00],y sta !telepprop lda #$01 sta !teleport jsr IncPointer jsr IncPointer jsr IncPointer jsr IncPointer jmp .NoButton .F0_Choices jsr ReadPointer lda !firsttile eor #$01 sta !nochoicelb ldy #$01 lda [$00],y lsr #4 pha cmp !height bcc .ChoiceStore beq .ChoiceStore lda !height .ChoiceStore sta !choices inc sta !currentchoice lda !vwfmaxheight sec sbc !currenty beq .F0ClearForce sec sbc !nochoicelb sec sbc !nochoicelb lsr cmp !choices bcs .CreateCursor .F0ClearForce pla lda #$01 sta !clearbox jmp .F0ClearOptions .CreateCursor lda [$00],y and #$0F sta !choicespace iny lda [$00],y sta !cursor !16bit iny !16bit lda [$00],y !16bit sta !cursor+1 !16bit jsr IncPointer jsr IncPointer jsr IncPointer jsr IncPointer lda !vwftextsource sta !choicetable lda !vwftextsource+1 sta !choicetable+1 lda !vwftextsource+2 sta !choicetable+2 lda !edge and #$07 sta !currentpixel lda !firsttile sta !nochoicelb lda #$01 sta !firsttile !16bit lda !cursor+1 !16bit sta !font jsr GetFont rep #$20 lda #$0001 sta $0C lda.w #!cursor sta $00 lda.w #!tileram+$38A0 sta $09 sep #$20 lda.b #!cursor>>16 sta $02 lda.b #!tileram+$38A0>>16 sta $0B lda !currentx pha lda !tile pha lda #$00 sta !currentx lda !currentpixel sta $0E lda !firsttile sta $0F jsl GenerateVWF lda !vwfwidth clc adc !choicespace sta !choicewidth lda !boxcreate beq .F0NoBG rep #$20 ldx #$06 stx $03 lda.w #!tileram+$10 sta $00 lda.w #!tileram+$38A0 sta $04 sep #$20 lda.b #!tileram+$10>>16 sta $02 lda.b #!tileram+$38A0>>16 sta $06 jsr AddPattern .F0NoBG rep #$20 lda.w #!tileram+$38A0 sta $09 sep #$20 lda.b #!tileram+$38A0>>16 sta $0B lda !currentx asl #5 clc adc $09 sta $09 lda !currentpixel clc adc !choicespace sta !choicespace cmp #$08 bcs .NoChoiceWipe jsr WipePixels .NoChoiceWipe pla sta !tile pla sta !currentx lda #$00 sta $0D xba pla sta $0C asl clc adc $0C rep #$20 clc adc !vwftextsource sta !vwftextsource sep #$20 jsr InitLine lda !nochoicelb beq .F0NotStart lda !currenty dec #2 sta !currenty .F0NotStart lda !clearbox beq .F0Return lda !currentchoice inc sta !currentchoice .F0ClearOptions lda !autowait beq .F0NoAutowait cmp #$01 beq .F0ButtonWait lda !autowait sta !wait bra .F0NoAutowait .F0ButtonWait jsr EndBeep !16bit rep #$20 !16bit lda #$FFFA !8bit lda #$FA sta !vwfchar !16bit sep #$20 .F0NoAutowait jmp TextCreation .F0Return jmp .NoButton .F1_Execute lda #$22 sta !vwfroutine ldy #$01 lda [$00],y sta !vwfroutine+1 iny lda [$00],y sta !vwfroutine+2 iny lda [$00],y sta !vwfroutine+3 lda #$6B sta !vwfroutine+4 jsr IncPointer jsr IncPointer jsr IncPointer jsr IncPointer jsl !vwfroutine jmp .NoButton .F2_ChangeFont ldy #$01 lda [$00],y sta !font jsr IncPointer jsr IncPointer jmp .NoButton .F3_ChangePalette lda !property and #$E3 sta !property ldy #$01 lda [$00],y asl #2 inc asl phx tax lda [$00],y asl #2 ora !property sta !property lda !boxcolor sta $6703,x lda !boxcolor+1 sta $6704,x lda #$01 sta !paletteupload plx jsr IncPointer jsr IncPointer jmp .NoButton .F4_Character jsr IncPointer jsr ReadPointer !16bit rep #$20 lda [$00] sta !vwfchar !16bit sep #$20 jmp .WriteLetter .F5_RAMCharacter ldy #$01 lda [$00],y sta $0C iny lda [$00],y sta $0D iny lda [$00],y sta $0E !16bit rep #$20 lda [$0C] sta !vwfroutine !16bit sep #$20 lda #$FB sta !vwfroutine+1+!bitmode !16bit lda #$FF !16bit sta !vwfroutine+3 rep #$20 lda $00 inc #4 sta !vwfroutine+2+!bitmode+!bitmode sep #$20 lda $02 sta !vwfroutine+4+!bitmode+!bitmode lda.b #!vwfroutine sta !vwftextsource lda.b #!vwfroutine>>8 sta !vwftextsource+1 lda.b #!vwfroutine>>16 sta !vwftextsource+2 jmp .NoButton .F6_HexValue ldy #$01 lda [$00],y sta $0C iny lda [$00],y sta $0D iny lda [$00],y sta $0E lda [$0C] lsr #4 sta !vwfroutine !16bit lda #$00 !16bit sta !vwfroutine+1 lda [$0C] and #$0F sta !vwfroutine+1+!bitmode !16bit lda #$00 !16bit sta !vwfroutine+3 lda #$FB sta !vwfroutine+2+!bitmode+!bitmode !16bit lda #$FF !16bit sta !vwfroutine+5 rep #$20 lda $00 inc #4 sta !vwfroutine+3+!bitmode+!bitmode+!bitmode sep #$20 lda $02 sta !vwfroutine+5+!bitmode+!bitmode+!bitmode lda.b #!vwfroutine sta !vwftextsource lda.b #!vwfroutine>>8 sta !vwftextsource+1 lda.b #!vwfroutine>>16 sta !vwftextsource+2 jmp .NoButton .F7_DecValue lda #$FB !8bit sta !vwfroutine+5 !16bit sta !vwfroutine+10 !16bit lda #$FF !16bit sta !vwfroutine+11 rep #$20 lda $00 clc adc #$0005 !8bit sta !vwfroutine+6 !16bit sta !vwfroutine+12 sep #$20 lda $02 !8bit sta !vwfroutine+8 !16bit sta !vwfroutine+14 ldy #$01 lda [$00],y sta $07 iny lda [$00],y sta $08 iny lda [$00],y sta $09 iny lda [$00],y pha and #$F0 sta $04 jsr HextoDec stz $00 stz $01 lda $04 bne .SixteenBit inc $00 inc $00 !16bit inc $00 !16bit inc $00 .SixteenBit pla and #$0F beq .NoZeros lda $05 !16bit asl clc adc $00 sta $00 .NoZeros rep #$20 lda.w #!vwfroutine clc adc $00 sta !vwftextsource sep #$20 lda.b #!vwfroutine>>16 sta !vwftextsource+2 jmp .NoButton .F8_TextSpeed ldy #$01 lda [$00],y sta !frames jsr IncPointer jsr IncPointer jmp .End .F9_WaitFrames ldy #$01 lda [$00],y sta !wait lda #$01 sta !forcesfx jsr IncPointer jsr IncPointer jmp .End .FA_WaitButton jsr EndBeep jsr IncPointer jmp .End .FB_TextPointer ldy #$01 lda [$00],y sta !vwftextsource iny lda [$00],y sta !vwftextsource+1 iny lda [$00],y sta !vwftextsource+2 jmp .NoButton .FC_LoadMessage ldy #$01 lda [$00],y sta !message iny lda [$00],y sta !message+1 lda !vwfmode dec sta !vwfmode lda #$01 sta !clearbox jmp VWFInit .FD_LineBreak !16bit rep #$20 !16bit lda #$FFFD !8bit lda #$FD sta !vwfchar !16bit sep #$20 jsr IncPointer jsr InitLine lda !clearbox ora !cursormove beq .FDReturn jmp TextCreation .FDReturn jmp .NoButton .FE_Space jsr IncPointer lda !vwfmaxwidth cmp !space bcs .PutSpace jsr InitLine lda !clearbox ora !cursormove bne .SpaceClearBox jmp .FEReturn .SpaceClearBox jmp TextCreation .PutSpace lda !vwfmaxwidth sec sbc !space sta !vwfmaxwidth lda !currentpixel clc adc !space sta $4204 cmp #$08 bcc .NoNewTile lda #$01 sta !firsttile .NoNewTile lda #$00 sta $4205 lda #$08 sta $4206 nop #8 lda $4216 sta !currentpixel rep #$20 lda $4214 asl clc adc !tile sta !tile sep #$20 lda $4214 clc adc !currentx sta !currentx lda #$00 ; Preserve everything and get width sta !vwfwidth ; of next word (for word wrap) lda !vwftextsource pha lda !vwftextsource+1 pha lda !vwftextsource+2 pha lda !font pha lda !vwfchar pha !16bit lda !vwfchar+1 !16bit pha jsr WordWidth !16bit pla !16bit sta !vwfchar+1 pla sta !vwfchar pla sta !font pla sta !vwftextsource+2 pla sta !vwftextsource+1 pla sta !vwftextsource lda !widthcarry bne .FECarrySet lda !vwfmaxwidth cmp !vwfwidth bcs .FEReturn .FECarrySet lda #$00 sta !widthcarry jsr InitLine lda !clearbox ora !cursormove beq .FEReturn jmp TextCreation .FEReturn jmp .NoButton .FF_End lda !choices beq .FFNoChoices jmp .FD_LineBreak .FFNoChoices jsr IncPointer jmp .End .WriteLetter !16bit lda !vwfchar+1 !16bit sta !font jsr GetFont rep #$20 lda #$0001 sta $0C lda !vwftextsource sta $00 sep #$20 lda !vwftextsource+2 sta $02 lda [$00] ; Check if enough width available tay lda !vwfmaxwidth cmp [$06],y bcs .Create jsr InitLine jsr GetFont rep #$20 lda #$0001 sta $0C lda !vwftextsource sta $00 sep #$20 lda !vwftextsource+2 sta $02 lda !clearbox ora !cursormove beq .Create jmp TextCreation .Create jsr IncPointer !16bit jsr IncPointer lda [$06],y sta !vwfwidth jsr WriteTilemap jsr GetDestination lda $09 sta !vwfgfxdest lda $0A sta !vwfgfxdest+1 lda $0B sta !vwfgfxdest+2 lda !firsttile bne .NoWipe lda !boxcreate beq .NoWipe jsr WipePixels .NoWipe lda !currentpixel sta $0E lda !firsttile sta $0F jsl GenerateVWF lda !boxcreate beq .End lda.b #!tileram+$10 sta $00 lda.b #!tileram+$10>>8 sta $01 lda.b #!tileram+$10>>16 sta $02 lda !vwfgfxdest sta $04 lda !vwfgfxdest+1 sta $05 lda !vwfgfxdest+2 sta $06 lda #$06 sta $03 jsr AddPattern .End jmp Buffer_End GetFont: lda #$06 ; Multiply font number with 6 sta $211B lda #$00 sta $211B sta $211C lda !font sta $211C rep #$20 lda $2134 clc adc.w #Fonttable ; Add starting address sta $00 sep #$20 lda.b #Fonttable>>16 sta $02 ldy #$00 .Loop lda [$00],y ; Load addresses from table sta $6003,y iny cpy #$06 bne .Loop rts GetDestination: rep #$20 lda !tile and #$03FF ; Multiply tile number with 16 asl #4 clc adc.w #!tileram ; Add starting address sta $09 sep #$20 lda.b #!tileram>>16 sta $0B rts IncPointer: rep #$20 lda !vwftextsource inc sta !vwftextsource sep #$20 rts ReadPointer: rep #$20 lda !vwftextsource sta $00 sep #$20 lda !vwftextsource+2 sta $02 rts Beep: lda !soundoff beq .Begin rts .Begin lda !forcesfx bne .Play lda !frames bne .Play lda $13 and #$01 beq .Play bra .Return .Play lda #$00 sta !forcesfx rep #$20 lda !beepbank sta $00 sep #$20 lda #$70 sta $02 lda !beep sta [$00] .Return rts EndBeep: lda !soundoff beq .Begin rts .Begin rep #$20 lda !beependbank sta $00 sep #$20 lda #$70 sta $02 lda !beepend sta [$00] rts CursorBeep: lda !soundoff beq .Begin rts .Begin rep #$20 lda !beepcursorbank sta $00 sep #$20 lda #$70 sta $02 lda !beepcursor sta [$00] rts ButtonBeep: lda !soundoff beq .Begin rts .Begin rep #$20 lda !beepchoicebank sta $00 sep #$20 lda #$70 sta $02 lda !beepchoice sta [$00] rts WriteTilemap: rep #$20 lda $00 pha lda $02 pha lda $04 pha sep #$20 lda !currentx ; Get tilemap address inc clc adc !xpos sta $00 lda !currenty inc clc adc !ypos sta $01 lda #$01 sta $02 jsr GetTilemapPos lda.b #!tileram+$3900>>16 sta $05 sta !vwftilemapdest+2 rep #$20 lda.w #!tileram+$3900 clc adc $03 sta $03 sta !vwftilemapdest lda !vwfwidth clc adc !currentpixel tax lda !tile ldy #$02 sta [$03] ; Write to tilemap cpx #$09 bcc .SecondLine inc #2 sta [$03],y cpx #$11 bcc .SecondLine inc #2 iny #2 sta [$03],y .SecondLine lda !tile inc ldy #$40 sta [$03],y cpx #$09 bcc .Return inc #2 iny #2 sta [$03],y cpx #$11 bcc .Return inc #2 iny #2 sta [$03],y .Return pla sta $04 pla sta $02 pla sta $00 sep #$20 rts WipePixels: lda !currentpixel ; Wipe pixels to prevent overlapping tax ; graphics ldy #$00 .Loop lda [$09],y and .Pixeltable,x sta [$09],y iny cpy #$20 bne .Loop rts .Pixeltable db $00,$80,$C0,$E0,$F0,$F8,$FC,$FE ;$07 : Address ;$04 : Bitmode ;$05 : Zeros HextoDec: jsr Convert8Bit jsr GetZeros !16bit lda #$00 !16bit sta !vwfroutine+1 !16bit sta !vwfroutine+3 !16bit sta !vwfroutine+5 !16bit sta !vwfroutine+7 !16bit sta !vwfroutine+9 rts Convert8Bit: stz $00 stz $01 stz $02 stz $03 lda [$07] ldy $04 cpy #$00 beq .Hundreds jsr Convert16Bit .Hundreds cmp #$64 bcc .Tens inc $02 sec sbc #$64 bra .Hundreds .Tens cmp #$0A bcc .Ones inc $03 sec sbc #$0A bra .Tens .Ones sta !vwfroutine+4+!bitmode+!bitmode+!bitmode+!bitmode lda $03 sta !vwfroutine+3+!bitmode+!bitmode+!bitmode lda $02 sta !vwfroutine+2+!bitmode+!bitmode rts Convert16Bit: rep #$20 lda [$07] .Tenthousands cmp #$2710 bcc .Thousands inc $00 sec sbc #$2710 bra .Tenthousands .Thousands cmp #$03E8 bcc .Hundreds inc $01 sec sbc #$03E8 bra .Thousands .Hundreds cmp #$0064 bcc .End inc $02 sec sbc #$0064 bra .Hundreds .End pha lda $00 sta !vwfroutine pla sep #$20 rts GetZeros: stz $05 dec $05 stz $06 ldy $04 beq .Hundreds .Tenthousands inc $05 lda !vwfroutine beq .Thousands bra .End .Thousands inc $05 lda !vwfroutine+1+!bitmode beq .Hundreds bra .End .Hundreds inc $05 lda !vwfroutine+2+!bitmode+!bitmode beq .Tens bra .End .Tens inc $05 lda !vwfroutine+3+!bitmode+!bitmode+!bitmode beq .Ones bra .End .Ones inc $05 .End rts WordWidth: !8bit jsr GetFont .Begin jsr ReadPointer !16bit rep #$20 lda [$00] sta !vwfchar !8bit cmp #$EC !16bit cmp #$FFEC bcs .Jump !16bit sep #$20 !16bit jsr IncPointer jsr IncPointer jmp .Add .Jump sec !8bit sbc #$EC !16bit sbc #$FFEC !16bit sep #$20 asl tax lda.l .Routinetable,x sta $0C inx lda.l .Routinetable,x sta $0D phk pla sta $0E !16bit jsr IncPointer jsr IncPointer jsr ReadPointer jml [$600C] .Routinetable dw .EC_PlayBGM dw .ED_ClearBox dw .EE_ChangeColor dw .EF_Teleport dw .F0_Choices dw .F1_Execute dw .F2_ChangeFont dw .F3_ChangePalette dw .F4_Character dw .F5_RAMCharacter dw .F6_HexValue dw .F7_DecValue dw .F8_TextSpeed dw .F9_WaitFrames dw .FA_WaitButton dw .FB_TextPointer dw .FC_LoadMessage dw .FD_LineBreak dw .FE_Space dw .FF_End .EE_ChangeColor .EF_Teleport .F1_Execute jsr IncPointer jsr IncPointer jsr IncPointer jmp .Begin .F2_ChangeFont lda [$00] sta !font jsr IncPointer jmp WordWidth .F3_ChangePalette jsr IncPointer jmp .Begin .F4_Character !16bit rep #$20 lda [$00] sta !vwfchar !16bit sep #$20 !16bit jsr IncPointer jsr IncPointer jmp .Add .F5_RAMCharacter ldy #$01 lda [$00] sta $0C lda [$00],y sta $0D iny lda [$00],y sta $0E jsr IncPointer jsr IncPointer jsr IncPointer !16bit rep #$20 lda [$0C] sta !vwfchar !16bit sep #$20 jmp .Add .F6_HexValue ldy #$01 lda [$00] sta $0C lda [$00],y sta $0D iny lda [$00],y sta $0E lda [$0C] lsr #4 sta !vwfroutine !16bit lda #$00 !16bit sta !vwfroutine+1 lda [$0C] and #$0F sta !vwfroutine+1+!bitmode !16bit lda #$00 !16bit sta !vwfroutine+3 lda #$FB sta !vwfroutine+2+!bitmode+!bitmode !16bit lda #$FF !16bit sta !vwfroutine+5 rep #$20 lda $00 inc #3 sta !vwfroutine+3+!bitmode+!bitmode+!bitmode sep #$20 lda $02 sta !vwfroutine+5+!bitmode+!bitmode+!bitmode lda.b #!vwfroutine sta !vwftextsource lda.b #!vwfroutine>>8 sta !vwftextsource+1 lda.b #!vwfroutine>>16 sta !vwftextsource+2 jmp .Begin .F7_DecValue lda #$FB !8bit sta !vwfroutine+5 !16bit sta !vwfroutine+10 !16bit lda #$FF !16bit sta !vwfroutine+11 rep #$20 lda $00 clc adc #$0004 !8bit sta !vwfroutine+6 !16bit sta !vwfroutine+12 sep #$20 lda $02 !8bit sta !vwfroutine+8 !16bit sta !vwfroutine+14 ldy #$01 lda [$00] sta $07 lda [$00],y sta $08 iny lda [$00],y sta $09 iny lda [$00],y pha and #$F0 sta $04 jsr HextoDec stz $00 stz $01 lda $04 bne .SixteenBit inc $00 inc $00 !16bit inc $00 !16bit inc $00 .SixteenBit pla and #$0F beq .NoZeros lda $05 !16bit asl clc adc $00 sta $00 .NoZeros rep #$20 lda.w #!vwfroutine clc adc $00 sta !vwftextsource sep #$20 lda.b #!vwfroutine>>16 sta !vwftextsource+2 jmp WordWidth .EC_PlayBGM .F8_TextSpeed .F9_WaitFrames jsr IncPointer jmp .Begin .FA_WaitButton jmp .Begin .FB_TextPointer ldy #$01 lda [$00] sta !vwftextsource lda [$00],y sta !vwftextsource+1 iny lda [$00],y sta !vwftextsource+2 jmp .Begin .ED_ClearBox .F0_Choices .FC_LoadMessage .FD_LineBreak .FE_Space .FF_End jmp .Return .Add !16bit lda !vwfchar+1 !16bit sta !font !16bit jsr GetFont lda !vwfchar tay lda [$06],y clc adc !vwfwidth bcs .End cmp !vwfmaxwidth bcc .Continue beq .Continue bra .End .Continue sta !vwfwidth jmp .Begin .End lda #$01 sta !widthcarry .Return rts ;;;;;;;;;;;;;; ;V-Blank Code; ;;;;;;;;;;;;;; ; This loads up graphics and tilemaps to VRAM. VBlank: phx phy pha phb php phk plb lda $73D4 beq .NoPause bra .End .NoPause lda !vwfmode ; Prepare jump to routine beq .End lda !paletteupload ; This code takes care of palette upload requests beq .skip lda #$00 sta !paletteupload sta $2121 %dmatransfer(#$01,#$02,#$22,".b #$70",".b #$07",".b #$03",#$0040) .skip lda !vwfmode asl tax lda .Routinetable,x sta $00 inx lda .Routinetable,x sta $01 phk pla sta $02 lda #$F0 ; Hide Status Bar item sta $62E1 jml [$6000] .End plp ; Return plb pla ply plx lda !vwfmode ; Skip Status Bar in dialogues bne .SkipStatusBar lda $6D9B lsr bcs .SkipStatusBar phk ; Display Status Bar per $0006 pea $84CE jml $008DAC .SkipStatusBar jml $0081F7 .Routinetable dw .End,PrepareBackup,Backup,PrepareScreen,SetupColor dw BackupEnd,CreateWindow,PrepareScreen,TextUpload,CreateWindow dw PrepareBackup,Backup,SetupColor,BackupEnd,VBlankEnd VBlankEnd: lda $6109 ; Check if in the intro beq .NotIntroLevel jsl $05B15B jmp .NotSwitchPallace .NotIntroLevel lda $73D2 ; Check if in a Switch Pallace beq .NotSwitchPallace ldx $791E lda .SwitchTable,x sta $73D2 inc $7DE9 lda #$01 sta $73CE jsl $05B165 .NotSwitchPallace lda !freezesprites beq .NoFreezeSprites lda #$00 sta $73FB sta $9D sta $73D3 sta !freezesprites .NoFreezeSprites lda !teleport ; Check if teleport set beq .NoTeleport lda #$00 sta !teleport lda $5B beq .Horizontal ldx $97 bra .SetupTeleport .Horizontal ldx $95 .SetupTeleport lda !telepdest sta $79B8,x lda !telepdest+1 ora #$04 ora !telepprop sta $79D8,x .Teleport lda #$06 sta $71 stz $89 stz $88 .NoTeleport lda #$00 ; VWF dialogue end sta !vwfmode jmp VBlank_End .SwitchTable db $04,$01,$02,$03 PrepareBackup: lda #$08 ; Prepare backup of layer 3 sta !counter rep #$20 lda #$0000 sta !vrampointer sep #$20 lda #$04 ; Hide layer 3 trb $6D9D lda $6D9D sta $212C .End lda !vwfmode inc sta !vwfmode jmp VBlank_End Backup: rep #$20 lda !vrampointer asl a clc adc.w #!backupram ; Adjust destination address ; lda.w #!backupram ; Adjust destination address ; clc ; adc !vrampointer ; clc ; adc !vrampointer sta $00 lda #$4000 ; Adjust VRAM address clc adc !vrampointer sta $02 sep #$20 lda !vwfmode cmp #$02 beq .Backup jmp .Restore .Backup %vramprepare(#$80,$02,"lda $2139","") %dmatransfer(#$01,#$81,#$39,".b #!backupram>>16",".b $01",".b $00",#$0800) jmp .Continue .Restore %vramprepare(#$80,$02,"","") %dmatransfer(#$01,#$01,#$18,".b #!backupram>>16",".b $01",".b $00",#$0800) .Continue rep #$20 ; Adjust pointer lda !vrampointer clc adc #$0400 sta !vrampointer sep #$20 lda !counter ; Reduce iteration counter dec sta !counter bne .NotDone .End lda !vwfmode inc sta !vwfmode .NotDone jmp VBlank_End BackupEnd: lda #$04 ; Display layer 3 tsb $6D9D lda $6D9D sta $212C .End lda !vwfmode inc sta !vwfmode jmp VBlank_End SetupColor: ;lda #$00 ; Backup or restore layer 3 colors stz $2121 lda !vwfmode cmp #$04 beq .Backup .Restore %mvntransfer($0040, #$00, !palbackup, $700703) %dmatransfer(#$01,#$02,#$22,".b #$70",".b #$07",".b #$03",#$0040) jmp .End .Backup %dmatransfer(#$01,#$82,#$3B,".b #$70",".b #$07",".b #$03",#$0040) %mvntransfer($0040, #$00, $700703, !palbackup) lda !boxpalette ; Set BG and letter color asl #2 inc asl phy tay ldx #$00 .BoxColorLoop lda !boxcolor,x sta $6703,y iny inx cpx #$06 bne .BoxColorLoop ply lda !framepalette ; Set frame color asl #2 inc asl phx tax phk pla sta $02 lda #$06 sta $211b stz $211b stz $211c lda !boxframe sta $211c nop rep #$20 lda $2134 clc adc.w #Palettes sta $00 sep #$20 ldy #$00 .FrameColorLoop lda [$00],y sta $6703,x inx iny cpy #$06 bne .FrameColorLoop plx lda #$01 sta !paletteupload .End lda !vwfmode inc sta !vwfmode jmp VBlank_End PrepareScreen: ; Upload graphics and tilemap to VRAM %vramprepare(#$80,#$4000,"","") %dmatransfer(#$01,#$01,#$18,".b #!tileram>>16",".b #!tileram>>8",".b #!tileram",#$00B0) %vramprepare(#$80,#$5C80,"","") %dmatransfer(#$01,#$01,#$18,".b #!tileram+$3900>>16",".b #!tileram+$3900>>8",".b #!tileram+$3900",#$0700) .End lda !vwfmode inc sta !vwfmode jmp VBlank_End CreateWindow: %vramprepare(#$80,#$5C80,"","") %dmatransfer(#$01,#$01,#$18,".b #!tileram+$3900>>16",".b #!tileram+$3900>>8",".b #!tileram+$3900",#$0700) lda !counter cmp #$02 bne .Return .End lda #$00 sta !counter lda !vwfmode inc sta !vwfmode .Return jmp VBlank_End TextUpload: lda !cursorfix beq .SkipCursor dec sta !cursorfix %vramprepare(#$80,!cursorvram,"","") %dmatransfer(#$01,#$01,#$18,".b #!tileram+$3900>>16"," !cursorsrc+1"," !cursorsrc",#$0046) .SkipCursor lda !wait ; Wait for frames? beq .NoFrames lda !wait dec sta !wait jmp .Return .NoFrames lda !cursormove bne .Cursor jmp .NoCursor .Cursor lda !cursorupload bne .UploadCursor jmp .NoCursorUpload .UploadCursor lda #$00 sta !cursorupload %vramprepare(#$80,#$5C50,"","") %dmatransfer(#$01,#$01,#$18,".b #!vwftileram>>16",".b #!vwftileram>>8",".b #!vwftileram",#$0060) lda !edge lsr #3 sta !currentx lda !currenty pha sec sbc !choices sec sbc !choices sta !currenty lda !currentchoice dec asl clc adc !currenty sta !currenty lda #$00 sta !vwfwidth lda !edge and #$07 clc adc !choicewidth sta !currentpixel rep #$20 lda !tile and #$FC00 ora #$038A sta !tile sep #$20 jsr WriteTilemap pla sta !currenty rep #$20 lda !vwftilemapdest sec sbc.w #!tileram+$3900 lsr clc adc #$5C80 sta $00 sep #$20 %vramprepare(#$80,$00,"","") %dmatransfer(#$01,#$01,#$18," !vwftilemapdest+2"," !vwftilemapdest+1"," !vwftilemapdest",#$0046) jmp .Return .NoCursorUpload lda !cursorend bne .CursorEnd jmp .Return .CursorEnd lda #$00 sta !cursorend lda !currentchoice dec sta !currentchoice asl clc adc !currentchoice tay lda !choicetable sta $00 lda !choicetable+1 sta $01 lda !choicetable+2 sta $02 lda [$00],y sta !vwftextsource iny lda [$00],y sta !vwftextsource+1 iny lda [$00],y sta !vwftextsource+2 lda #$00 sta !cursormove sta !choices sta !currentchoice sta !vwfchar !16bit sta !vwfchar+1 lda #$01 sta !clearbox jmp .Return .NoCursor !16bit rep #$20 lda !vwfchar ; Dialogue done? !8bit cmp #$FF !16bit cmp #$FFFF bne .NoEnd !16bit lda #$0000 !8bit lda #$00 sta !vwfchar !16bit sep #$20 jmp .End .NoEnd !8bit cmp #$FA ; Waiting for A button? !16bit cmp #$FFFA !16bit sep #$20 beq .CheckButton jmp .Upload .CheckButton lda $18 and #$80 cmp #$80 bne .NotPressed jsr ButtonBeep lda #$00 sta !vwfchar !16bit sta !vwfchar+1 lda #$00 sta !timer .NotPressed lda !boxcreate bne .CheckTimer jmp .Return .CheckTimer lda !timer ; Display arrow if waiting for button inc sta !timer cmp #$21 bcc .NoReset lda #$00 sta !timer .NoReset lda !xpos clc adc !width inc sta $00 lda !height asl clc adc !ypos inc sta $01 lda #$00 sta $02 jsr GetTilemapPos rep #$20 lda #$5C80 clc adc $03 sta $03 sep #$20 %vramprepare(#$00,$03,"","") lda !timer cmp #$11 bcs .Arrow lda #$05 bra .Display .Arrow lda #$0A .Display sta $2118 jmp .Return .Upload lda !clearbox beq .Begin lda #$00 sta !clearbox %vramprepare(#$80,#$5C80,"","") %dmatransfer(#$01,#$01,#$18,".b #!tileram+$3900>>16",".b #!tileram+$3900>>8",".b #!tileram+$3900",#$0700) jmp .Return .Begin rep #$20 ; Upload GFX lda !vwfgfxdest sec sbc.w #!tileram lsr clc adc #$4000 sta $00 sep #$20 %vramprepare(#$80,$00,"","") %dmatransfer(#$01,#$01,#$18," !vwfgfxdest+2"," !vwfgfxdest+1"," !vwfgfxdest",#$0060) rep #$20 ; Upload Tilemap lda !vwftilemapdest sec sbc.w #!tileram+$3900 lsr clc adc #$5C80 sta $00 sep #$20 %vramprepare(#$80,$00,"","") %dmatransfer(#$01,#$01,#$18," !vwftilemapdest+2"," !vwftilemapdest+1"," !vwftilemapdest",#$0046) jsr Beep lda !frames sta !wait lda !speedup beq .Return !16bit rep #$20 lda !vwfchar !8bit cmp #$F9 !16bit cmp #$FFF9 !16bit sep #$20 beq .Return lda $15 and #$80 cmp #$80 bne .Return lda #$00 sta !wait jmp .Return .End lda !vwfmode inc sta !vwfmode .Return jmp VBlank_End BackupTilemap: lda !edge lsr #3 clc adc !xpos inc sta $00 lda !currenty sec sbc !choices sec sbc !choices sta $01 lda !currentchoice dec asl clc adc $01 clc adc !ypos inc sta $01 lda #$01 sta $02 jsr GetTilemapPos lda.b #!tileram+$3900>>16 sta $05 rep #$20 lda.w #!tileram+$3900 clc adc $03 sta $03 sep #$20 lda $0F beq .Backup jmp .Restore .Backup rep #$20 ldy #$02 lda [$03] sta !tileram+$3894 lda [$03],y sta !tileram+$3896 iny #2 lda [$03],y sta !tileram+$3898 ldy #$40 lda [$03],y sta !tileram+$389A iny #2 lda [$03],y sta !tileram+$389C iny #2 lda [$03],y sta !tileram+$389E sep #$20 rts .Restore rep #$20 ldy #$02 lda !tileram+$3894 sta [$03] lda !tileram+$3896 sta [$03],y iny #2 lda !tileram+$3898 sta [$03],y ldy #$40 lda !tileram+$389A sta [$03],y iny #2 lda !tileram+$389C sta [$03],y iny #2 lda !tileram+$389E sta [$03],y sep #$20 rep #$20 lda $03 sec sbc.w #!tileram+$3900 lsr clc adc #$5C80 ;sta $00 ;sep #$20 ;%vramprepare(#$80,$00,"","") ;%dmatransfer(#$01,#$01,#$18," $05"," $04"," $03",#$0046) ;Vitor Vilela's note: ;Here is one big issue with the cursor. ;This code actually is outside V-Blank and now I have to upload the following: ;VRAM: $00-$01 ;Source: $03-$05 ;Bytes: #$0046 ;I don't know if the tile gets preserved or not for the current frame. ;But for now I will have to preverse at least, $00-$01 and $03-$04, which means more 4 bytes ;of free ram, plus the upload flag, so 5 more bytes of free ram. sta !cursorvram lda $03 sta !cursorsrc sep #$20 lda #$01 sta !cursorfix rts ;;;;;;;;;;;;;; ;VWF Routines; ;;;;;;;;;;;;;; ; The actual VWF Creation routine. print "" print "VWF Creation Routine at address $",pc,"." ;$00 : Text ;$03 : GFX 1 ;$06 : Width ;$09 : Destination ;$0C : Number of Bytes -> GFX 2 ;$0E : Current Pixel ;$0F : First Tile? GenerateVWF: REP #$20 LDY #GenerateVWFGSU>>16 GenerateVWF_Base: LDA #GenerateVWFGSU JMP $1E80 GenerateVWFGSU: arch superfx base (GenerateVWF_Base+3)&0xFF00|(GenerateVWF_Base+2)&0x00FF LMS R7,($2) ;\ Get values already LMS R8,($1) ;/ The reason I put here, we'll see below... LMS R0,($7) ; The operation already loads two values into one SM (!currentpixel),R0 ; Doesn't necessarily saves time but it's smaller ;LMS R12,($6) ; Set up the values for VWF bytes (Loop counter) (Unused?) ;SM (!vwfbytes) ; (Unused?) ;Note: From what I analyzed the code, $C and therefore !vwfbytes are ALWAYS set to #$01 ;Unless there is something regarding this RAM (not mentioned elsewhere in this patch nor readme aside here) ;It is safe to assume this RAM is unused and therefore should be discarded ;I kept the original routine pointing to the data and can be changed if needed ;The removal of useless functions saved about ~40 cycles IBT R1,#$0E ;\ Get GFX 2 Offset LMS R0,($2) ;| HIB ;| STB (R1) ;/ IBT R1,#$20 ;\ Set value to ADD MERGE ;| MERGE the values loaded above ADD R1 ;| ADD it with the value in R1 and get back on R0 SMS ($6),R0 ;/ Store on $C .Read lda [$00] ; Read character inc $00 !16bit inc $00 !8bit sep #$20 sta !vwfchar !16bit sep #$20 !16bit lda !vwfchar+1 !16bit sta !font !16bit jsr GetFont !16bit lda $05 !16bit sta $0E !16bit rep #$20 !16bit lda $03 !16bit clc !16bit adc #$0020 !16bit sta $0C !16bit sep #$20 !16bit lda !vwfchar tay lda [$06],y ; Get width sta !vwfwidth lda !vwfmaxwidth sec sbc !vwfwidth sta !vwfmaxwidth .Begin lda !vwfchar ; Get letter offset into Y sta $211B lda #$00 sta $211B sta $211C lda #$40 sta $211C rep #$10 ldy $2134 ldx #$0000 .Draw lda !currentpixel sta $0F lda [$03],y ; Load one pixelrow of letter sta !vwftileram,x lda [$0C],y sta !vwftileram+32,x lda #$00 sta !vwftileram+64,x .Check lda $0F beq .Skip lda !vwftileram,x ; Shift to the right lsr sta !vwftileram,x lda !vwftileram+32,x ror sta !vwftileram+32,x lda !vwftileram+64,x ror sta !vwftileram+64,x dec $0F bra .Check .Skip iny inx cpx #$0020 bne .Draw sep #$10 ldx #$00 ldy #$00 lda !firsttile ; Skip one step if first tile in line beq .Combine lda #$00 sta !firsttile bra .Copy .Combine lda !vwftileram,x ; Combine old graphic with new ora [$09],y sta [$09],y inx iny cpx #$20 bne .Combine .Copy lda !vwftileram,x ; Copy remaining part of letter sta [$09],y inx iny cpx #$60 bne .Copy lda !currentpixel ; Adjust destination address clc adc !vwfwidth sta $4204 lda #$00 sta $4205 lda #$08 sta $4206 nop #8 lda $4216 sta !currentpixel rep #$20 lda $4214 asl clc adc !tile sta !tile sep #$20 lda $4214 clc adc !currentx sta !currentx lda $4214 sta $211B lda #$00 sta $211B sta $211C lda #$20 sta $211C rep #$20 lda $2134 clc adc $09 sta $09 lda !vwfbytes ; Adjust number of bytes dec sta !vwfbytes beq .End jmp .Read .End sep #$20 rtl ; Adds the background pattern to letters. print "Pattern Addition Routine at address $",pc,"." ;$00 : Graphic ;$03 : Number of tiles ;$04 : Destination ;That small routine got a tad... Souped up... ;There aren't indexing on GSU... ;Even though the routine increased in size ;It's extremely efficient for GSU standards ;NOTE: Due to pattern routine being souped for Super FX ;There is a significant increase of performance AddPattern: REP #$20 LDY #AddPatternGSU>>16 AddPattern_Base: LDA #AddPatternGSU JMP $1E80 AddPatternGSU: arch superfx base (AddPattern_Base+3)&0xFF00|(AddPattern_Base+2)&0x00FF LMS R0,($1) ;\ In case you want to do your own patterns TO R12 ;| This piece of code takes care the amount HIB ;| of LOOPs needed INC R12 ;/ <> Needed to fix shit IBT R4,#$04 ;$04 address (pointer) IBT R5,#$00 ;$00 address (pointer) IBT R6,#$10 ;Compare value LMS R11,($3) ;Get RAM Bank on R11 for later usage (Load once to avoid LOOP overhead) CACHE ;For each subsequent LOOP, run code through CACHE MOVE R13,R15 ;Loopback address IBT R3,#$00 ;Y Index .Combine INC R3 ;Increment Index WITH R7 ; LDW (R4) ;Get the pointer address WITH R8 ; LDW (R5) ;Get another pointer address FROM R11 ;\ Get correct RAM bank RAMB ;/ WITH R7 ;\ Do indexing of the pointer ADD R3 ;/ LDW (R7) ;Get the "word" value based on address pointed at R7 NOT ;NOT and store value of $04 in R0 DEC R3 ;Decrement Index DEC R7 ;Fix Index on R7 WITH R9 ;\ Get color value LDW (R7) ;/ WITH R8 ;\ Do indexing of the pointer ADD R3 ;/ TO R1 ; LDW (R8) ;Get the "word" value based on address pointed at R8 ;Get the value worked on R0 AND R1 ;\ AND it with the value in R1 OR R9 ;| OR it with the original value STB (R7) ;/ Store it to pointer in R7 INC R3 ;\ Increment Index twice INC R3 ;/ SUB R0 ;\ Clear R0 for RAM Bank Cleanup FROM R3 ;\ Compare if there's things still to be done CMP R6 ;| Could've used loop for that... Too much complicated for a nested loop ALT2 ;| Get data for fetch BNE .Combine ;/ At least, it is running inside CACHE RAM, therefore it isn't that slow... Right? GETC ;/ ALT2 + GETC = RAMB > FROM R0 : RAMB = Restore Bank to Normal LMS R0,($2) ;\ Load RAM $04 ADD R6 ;| Add #$10 LOOP ;| Loopback to the top of the routine while not done SBK ;/ While looping, store back the address value to $04 .End STOP base off arch 65816 Emptytile: db $00,$20 ;;;;;;;;;;;;;;;; ;[CUSTOMTABLES]; ;;;;;;;;;;;;;;;; Fonttable: dl Font1,Font1_Width Palettes: dw $0000,$FFFF,$0000 dw $0A56,$04ED,$0044 dw $45ED,$24E6,$0C41 dw $477D,$2E55,$214D dw $00C4,$1F7F,$15D1 dw $739C,$5250,$0000 dw $473F,$3EDC,$3258 dw $5235,$290A,$679F dw $3250,$2D09,$0C63 dw $3250,$2D09,$0C63 dw $3250,$2D09,$0C63 dw $45ED,$24E6,$0C41 dw $0A56,$04ED,$0044 dw $19F0,$00CB,$0044 dw $3250,$2D09,$0C63 dw $3250,$2D09,$0C63 ;;;;;;;;;;;;;;;; ;External Files; ;;;;;;;;;;;;;;;; Frames: incbin vwfframes.bin Patterns: incbin vwfpatterns.bin Font1: incbin vwffont1.bin .Width incsrc vwffont1.asm print "" print "VWF State register at address $",hex(!vwfmode),"." print "Message register at address $",hex(!message),"." print "BG GFX register at address $",hex(!boxbg),"." print "BG Color register at address $",hex(!boxcolor),"." print "Frame GFX register at address $",hex(!boxframe),"." print "" print "See Readme for details!" print "" freedata !PrevFreespace: Pointers: incsrc vwfmessagepointers.asm %nextbank() Text: incsrc vwfmessages.asm ;------------------------------------------------------------- ;INSERT DATA HERE! ;END ;------------------------------------------------------------- freedata : prot !PrevFreespace : Kleenex: db $00;ignore this line, it must be last in the patch for technical reasons