User:Kmeisthax/Findings/2011/6/19/v83 Patch Notes
Multi-Text Mode VWF Hack
There are four 'text modes' in Telefang:
Mode 0: Common text. This is currently the only text type VWF'd. The glyph is drawn out on both bitplanes, like so:
10110101 10110101
Mode 1: D-Shot text. The glyph is drawn on the first bitplane, and the second is all white:
10110101 11111111
Mode 2: Inverted text (possibly used on intro cutscene text) The glyph is drawn on both bitplanes, inverted:
01001010 01001010
Mode 3: ??? text. The glyph is drawn on the second bitplane, and the first is all white:
11111111 10110101
The VWF is split into two routines: The "entry point" VWF advice, which every text routine ends up calling now. And the VWF core routine, which does the actual heavy lifting of drawing tiles. Nothing calls the VWF core directly other than the VWF advice. Here's a disassembled listing of the VWF advice routine:
ROM:0002CE29 ; --------------------------------------------------------------------------- ROM:0002CE29 jp 2FC00 ROM:0002CE2C ; --------------------------------------------------------------------------- ROM:0002CE2C add a, a ROM:0002CE2D jr nc, 2CE30 ROM:0002CE2F inc b ROM:0002CE30 sla a ROM:0002CE32 rl b ROM:0002CE34 sla a ROM:0002CE36 rl b ROM:0002CE38 ld c, a ROM:0002CE39 ld hl, $5229 ROM:0002CE3C add hl, bc ROM:0002CE3D ld d, h ROM:0002CE3E ld e, l ROM:0002CE3F pop hl ROM:0002CE40 ld a, [WRAM_TextStyle] ROM:0002CE43 cp 0 ROM:0002CE45 jr z, loc_CE53 ROM:0002CE47 cp 1 ROM:0002CE49 jr z, loc_CE65 ROM:0002CE4B cp 2 ROM:0002CE4D jr z, loc_CE79 ROM:0002CE4F cp 3 ROM:0002CE51 jr z, loc_CE8C ROM:0002CE53 call 2F9C1 ; VWF Core ROM:0002CE56 jr 2CE64 ROM:0002CE58 ; --------------------------------------------------------------------------- ROM:0002CE58 and 2 ; Dead code (used to be Textmode 0 pre VWF) ROM:0002CE5A jr nz, loc_CE56 ROM:0002CE5C ld a, [de] ROM:0002CE5D ldi [hl], a ROM:0002CE5E ldi [hl], a ROM:0002CE5F ei ROM:0002CE60 inc de ROM:0002CE61 dec b ROM:0002CE62 jr nz, loc_CE55 ROM:0002CE64 ret ; this is actually jumped to, ROM:0002CE64 ; you just don't get a label ROM:0002CE64 ; because IDA sucks for banked ROM:0002CE64 ; ROM disassembly ROM:0002CE65 ; --------------------------------------------------------------------------- ROM:0002CE65 ld b, 8 ; Textmode 1: D-Shot Menu ROM:0002CE67 di ROM:0002CE68 ld a, [byte_FF41] ROM:0002CE6A and 2 ROM:0002CE6C jr nz, loc_CE67+1 ROM:0002CE6E ld a, [de] ROM:0002CE6F ldi [hl], a ROM:0002CE70 ld a, $FF ROM:0002CE72 ldi [hl], a ROM:0002CE73 ei ROM:0002CE74 inc de ROM:0002CE75 dec b ROM:0002CE76 jr nz, loc_CE67 ROM:0002CE78 ret ROM:0002CE79 ; --------------------------------------------------------------------------- ROM:0002CE79 ld b, 8 ; Textmode 2 ROM:0002CE7B di ROM:0002CE7C ld a, [byte_FF41] ROM:0002CE7E and 2 ROM:0002CE80 jr nz, loc_CE7C ROM:0002CE82 ld a, [de] ROM:0002CE83 cpl ROM:0002CE84 ldi [hl], a ROM:0002CE85 ldi [hl], a ROM:0002CE86 ei ROM:0002CE87 inc de ROM:0002CE88 dec b ROM:0002CE89 jr nz, loc_CE7B ROM:0002CE8B ret ROM:0002CE8C ; --------------------------------------------------------------------------- ROM:0002CE8C ld b, 8 ; Textmode 3 ROM:0002CE8E di ROM:0002CE8F ld a, [byte_FF41] ROM:0002CE91 and 2 ROM:0002CE93 jr nz, loc_CE8F ROM:0002CE95 ld a, $FF ROM:0002CE97 ldi [hl], a ROM:0002CE98 ld a, [de] ROM:0002CE99 ldi [hl], a ROM:0002CE9A ei ROM:0002CE9B inc de ROM:0002CE9C dec b ROM:0002CE9D jr nz, loc_CE8E ROM:0002CE9F ret ROM:0002CE9F ; ---------------------------------------------------------------------------
WRAM_TextStyle lives in WRAM CDB1, and it controls the color of the text. Sadly, the previous hacker who worked on VWF did not bother to make his VWF handle multiple text styles and instead decided to make it such that all other kinds of text styles don't touch the VWF. Sadly, with the enabling of status item VWFing, this also means that setting the text mode has the side effect of never allowing more than one letter to be drawn at a time.
So let's make our text VWF. First off, this also means ALL of the textmode code is dead now, so the VWF routine should just look like this:
ROM:0002CE29 ; --------------------------------------------------------------------------- ROM:0002CE29 jp 2FC00 ROM:0002CE2C ; --------------------------------------------------------------------------- ROM:0002CE2C add a, a ROM:0002CE2D jr nc, 2CE30 ROM:0002CE2F inc b ROM:0002CE30 sla a ROM:0002CE32 rl b ROM:0002CE34 sla a ROM:0002CE36 rl b ROM:0002CE38 ld c, a ROM:0002CE39 ld hl, $5229 ROM:0002CE3C add hl, bc ROM:0002CE3D ld d, h ROM:0002CE3E ld e, l ROM:0002CE3F pop hl ROM:0002CE40 call 2F9C1 ; VWF Core ; CD C1 79 ROM:0002CE43 ret ; C9 ROM:0002CE43 ; --------------------------------------------------------------------------- to ; FREE PARKING^WSPACE (Do not pass go, do not collect 0x5C bytes) ROM:0002CE9F ; ---------------------------------------------------------------------------
We get a whole nother 5C bytes out of the deal. Awesome. Now let's look at the VWF core...
This is an updated version of my earlier ROM B:79C1 disassembly. Relative jumps aren't properly corrected because I didn't bother to correct them. The relevant variables start from C7C1, and are:
WRAM_VWF_CurrentLetter WRAM_VWF_GlyphShift WRAM_VWF_SPILL_CompositingArea WRAM_VWF_SPILL_CompositingArea + 1 WRAM_VWF_OldTileMode WRAM_VWF_MainScriptHack
ROM:0002F9C1 ; --------------------------------------------------------------------------- ROM:0002F9C1 ld b, 8 ROM:0002F9C3 ld a, $CF ; '-' ROM:0002F9C5 ld [WRAM_VWF_SPILL_CompositingArea], a ROM:0002F9C8 ld a, $D0 ; '-' ROM:0002F9CA ld [WRAM_VWF_SPILL_CompositingArea1], a ROM:0002F9CD push hl ROM:0002F9CE push bc ROM:0002F9CF ld a, [WRAM_VWF_CurrentLetter] ROM:0002F9D2 ld h, $7B ; '{' ROM:0002F9D4 ld l, a ROM:0002F9D5 xor a ROM:0002F9D6 ld b, [hl] ROM:0002F9D7 ld a, [WRAM_VWF_GlyphShift] ROM:0002F9DA add a, b ROM:0002F9DB bit 3, a ROM:0002F9DD jr nz, loc_F9E2 ROM:0002F9DF xor a ROM:0002F9E0 jr loc_F9E4 ROM:0002F9E2 ; --------------------------------------------------------------------------- ROM:0002F9E2 ld a, 1 ROM:0002F9E4 pop bc ROM:0002F9E5 pop hl ROM:0002F9E6 push bc ROM:0002F9E7 push de ROM:0002F9E8 push hl ROM:0002F9E9 push af ROM:0002F9EA di ROM:0002F9EB ld a, [WRAM_VWF_SPILL_CompositingArea] ROM:0002F9EE ld h, a ROM:0002F9EF ld a, [WRAM_VWF_SPILL_CompositingArea1] ROM:0002F9F2 ld l, a ROM:0002F9F3 ld b, [hl] ROM:0002F9F4 inc hl ROM:0002F9F5 ld c, [hl] ROM:0002F9F6 dec hl ROM:0002F9F7 ld a, [de] ROM:0002F9F8 ld d, a ROM:0002F9F9 ld e, 0 ROM:0002F9FB ld a, [WRAM_VWF_OldTileMode] ROM:0002F9FE cp 2 ROM:0002FA00 jr z, loc_FA07+1 ROM:0002FA02 cp 1 ROM:0002FA04 jr z, loc_FA0A ROM:0002FA06 jr loc_FA0A+1 ROM:0002FA08 ; --------------------------------------------------------------------------- ROM:0002FA08 ld c, 0 ROM:0002FA0A ld b, c ROM:0002FA0B ld a, [WRAM_VWF_GlyphShift] ROM:0002FA0E or a ROM:0002FA0F jr z, loc_FA18 ROM:0002FA11 srl d ROM:0002FA13 rr e ROM:0002FA15 dec a ROM:0002FA16 jr nz, loc_FA10+1 ROM:0002FA18 ld a, d ROM:0002FA19 or b ROM:0002FA1A ld b, a ROM:0002FA1B ld c, e ROM:0002FA1C ld [hl], b ROM:0002FA1D inc hl ROM:0002FA1E ld [hl], c ROM:0002FA1F inc hl ROM:0002FA20 ld a, h ROM:0002FA21 ld [WRAM_VWF_SPILL_CompositingArea], a ROM:0002FA24 ld a, l ROM:0002FA25 ld [WRAM_VWF_SPILL_CompositingArea1], a ROM:0002FA28 pop af ROM:0002FA29 pop hl ROM:0002FA2A ld d, h ROM:0002FA2B ld e, l ROM:0002FA2C push af ROM:0002FA2D ld a, [byte_FF41] ROM:0002FA2F and 2 ROM:0002FA31 jr nz, loc_FA2C+1 ; Wait for blanking ROM:0002FA33 ld a, b ROM:0002FA34 ldi [hl], a ROM:0002FA35 ldi [hl], a ROM:0002FA36 pop af ROM:0002FA37 push hl ROM:0002FA38 push af ROM:0002FA39 or a ROM:0002FA3A jr z, loc_FA47+2 ROM:0002FA3C ld hl, $10 ROM:0002FA3F add hl, de ROM:0002FA40 ld a, [byte_FF41] ROM:0002FA42 and 2 ROM:0002FA44 jr nz, loc_FA3F+1 ; Wait for Blanking ROM:0002FA46 ld a, c ROM:0002FA47 ldi [hl], a ROM:0002FA48 ldi [hl], a ROM:0002FA49 ei ROM:0002FA4A pop af ROM:0002FA4B pop hl ROM:0002FA4C pop de ROM:0002FA4D pop bc ROM:0002FA4E inc de ROM:0002FA4F dec b ROM:0002FA50 jr nz, loc_F9E4+2 ROM:0002FA52 ld a, 0 ROM:0002FA54 ld [WRAM_VWF_OldTileMode], a ROM:0002FA57 ld b, $7B ; '{' ROM:0002FA59 ld a, [WRAM_VWF_CurrentLetter] ROM:0002FA5C ld c, a ROM:0002FA5D ld a, [bc] ROM:0002FA5E inc a ROM:0002FA5F ld b, a ROM:0002FA60 ld a, [WRAM_VWF_GlyphShift] ROM:0002FA63 add a, b ROM:0002FA64 bit 3, a ROM:0002FA66 jr z, loc_FA7D ROM:0002FA68 sub 8 ROM:0002FA6A push af ROM:0002FA6B ld a, 1 ROM:0002FA6D ld [WRAM_VWF_OldTileMode], a ROM:0002FA70 ld a, [byte_C7C6] ROM:0002FA73 cp 1 ROM:0002FA75 jr nz, unk_FA7C ROM:0002FA77 ld a, 0 ROM:0002FA79 ld [byte_C7C6], a ROM:0002FA7C pop af ROM:0002FA7D ld [WRAM_VWF_GlyphShift], a ROM:0002FA80 ret ROM:0002FA80 ; --------------------------------------------------------------------------- ROM:0002FA81 db 0 ROM:0002FA82 db 0 ROM:0002FA83 db 0 ROM:0002FA84 db 0 ROM:0002FA85 db 0 ROM:0002FA86 db 0 ROM:0002FA87 db 0
We have a bit of extra space but that doesn't matter right now. We want to insert some advice. It'll be in the form of a subroutine call because we want to insert it in two places and we're already jumping out of the function (we don't have nearly enough room to do it inline). Our params will be:
a 1bpp glyph hl place to draw to
VWFColorizeGlyph: push bc ;C5 ld b, a ;47 ld a, [WRAM_TextStyle] ;FA B1 CD bit 0, a ;CB 47 jr nz, .VWFColorize_DetX1 ;20 06 bit 1, a ;CB 4F jr z, .VWFColorize_Mode0 ;28 14 jr nz, .VWFColorize_Mode2 ;20 2C .VWFColorize_DetX1: bit 1, a ;CB 4F jr z, .VWFColorize_Mode1 ;28 1A ;VWFColorize_Mode3 .Mode3WFB: ld a, [FF41] ;FA 41 FF and 2 ;E6 02 jr nz, Mode3WFB ;20 F9 ld a, $FF ;3E FF ldi [hl], a ;22 ld a, b ;78 ldi [hl], a ;22 jr .RestoreAndExit ;18 27 .VWFColorize_Mode0: ld a, [FF41] ;FA 41 FF and 2 ;E6 02 jr nz, VWFColorize_Mode0 ;20 F9 ld a, b ;78 ldi [hl], a ;22 ldi [hl], a ;22 jr .RestoreAndExit ;18 1B
.VWFColorize_Mode1: ld a, [FF41] ;FA 41 FF and 2 ;E6 02 jr nz, VWFColorize_Mode1 ;20 F9 ld a, b ;78 ldi [hl], a ;22 ld a, $FF ;3E FF ldi [hl], a ;22
jr .RestoreAndExit ;18 0D
.VWFColorize_Mode2: ld a, b ;78 cpl ;2F ld b, a ;47 .Mode2WFB: ld a, [FF41] ;FA 41 FF and 2 ;E6 02 jr nz, .Mode2WFB ;20 F9
ld a, b ;78 ldi [hl], a ;22 ldi [hl], a ;22
.RestoreAndExit pop bc ;C1 ret ;C9
The routine is 75, or 0x4B, bytes long. We'll put it at 2FC3F, since nothing's been added to this free space since v65 on Bank B. The new free space pointer in BANK B is 2FC89 (B:7C89). It's done being assembled, so we're HALFWAY THERE!
Let's change the VWF now...
ROM:0002FA2D ld a, b ;78 2FA2E call 2FC3F ;CD 3F 7C 31 nop 2 nop 3 nop 4 nop 5 nop ; 5 free bytes ROM:0002FA36 pop af ROM:0002FA37 push hl ROM:0002FA38 push af ROM:0002FA39 or a ROM:0002FA3A jr z, loc_FA47+2 ROM:0002FA3C ld hl, $10 ROM:0002FA3F add hl, de ROM:0002FA40 ld a, c ;79 41 call 2FC3F ;CD 3F 7C 4 nop 5 nop 6 nop 7 nop 8 nop ; 5 more free bytes ROM:0002FA49 ei
I'm not going to move those NOPs out because that means fixing some relajumps and I'm too tired to do that. If you need more space in this routine, just defrag it...