+  RHDN Forum Archive
|-+  Romhacking
| |-+  ROM Hacking Discussion
| | |-+  Uncompressing FF6
Pages: [1]
Author Topic: Uncompressing FF6  (Read 2 times)
Zeemis
Guest
« on: December 03, 2009, 10:47:47 pm »

A lot of Final Fantasy VI is compressed, I'm wondering how I'd uncompress the rom to edit a majorite of it's graphics.
I'm fairly sure it's possible as there is a custom title screen patch on the internet somewhere and the title screen is compressed.
Ryusui
Guest
« Reply #1 on: December 03, 2009, 11:30:51 pm »

Decompressing data is easy if you have Geiger's Snes9x and VSNES!

Step 1. Find out where the graphics you want to edit are decompressed to in RAM.
Step 2. Set a write breakpoint to the start of the decompressed data to find the tail end of the decompression routine.
Step 3. Trace through the compression routine and figure out how it works.
Step 4. Duplicate the compression routine in your favorite programming language.

The hardest part is writing a recompressor, since the game doesn't conveniently provide a blueprint for creating those, but it's not impossible with some trial and error.
Lenophis
Guest
« Reply #2 on: December 04, 2009, 02:20:08 am »

I would say to look at some disassemblies, but in this case the one in question isn't updated too often anymore.

Code:
"LZ" decompression routine
Coming in: $F3-$F5 - source
$F6-$F8 - destination
C2/FF6D: 8B      PHB
C2/FF6E: 0B      PHD
C2/FF6F: A20000  LDX #$0000     (LDX $00...)
C2/FF72: DA      PHX
C2/FF73: 2B      PLD
C2/FF74: C220    REP #$20
C2/FF76: A7F3    LDA [$F3]
C2/FF78: 85FC    STA $FC
C2/FF7A: A5F6    LDA $F6
C2/FF7C: 8F812100 STA $002181
C2/FF80: E220    SEP #$20
C2/FF82: A5F8    LDA $F8
C2/FF84: 2901    AND #$01
C2/FF86: 8F832100 STA $002183
C2/FF8A: A901    LDA #$01
C2/FF8C: 85FE    STA $FE
C2/FF8E: A00200  LDY #$0002
C2/FF91: A97F    LDA #$7F
C2/FF93: 48      PHA
C2/FF94: AB      PLB
C2/FF95: A200F8  LDX #$F800
C2/FF98: 7B      TDC
C2/FF99: 9D0000  STA $0000,x    (zero out $F800 - $FFFF)
C2/FF9C: E8      INX
C2/FF9D: D0FA    BNE $FF99
C2/FF9F: A2DEFF  LDX #$FFDE
C2/FFA2: C6FE    DEC $FE
C2/FFA4: D009    BNE $FFAF
C2/FFA6: A908    LDA #$08
C2/FFA8: 85FE    STA $FE
C2/FFAA: B7F3    LDA [$F3],y    (grab a byte from the buffer)
C2/FFAC: 85FF    STA $FF        (save it for now)
C2/FFAE: C8      INY            (next byte in the buffer)
C2/FFAF: 46FF    LSR $FF
C2/FFB1: 9011    BCC $FFC4
C2/FFB3: B7F3    LDA [$F3],y    (grab next byte from the buffer)
C2/FFB5: 8F802100 STA $002180    (to WRAM!)
C2/FFB9: 9D0000  STA $0000,x    (and then to 7F/FFDE+X)
C2/FFBC: E8      INX
C2/FFBD: D037    BNE $FFF6
C2/FFF6: C8      INY
C2/FFF7: C4FC    CPY $FC
C2/FFF9: D0A7    BNE $FFA2
C2/FFBF: A200F8  LDX #$F800
C2/FFC2: 8032    BRA $FFF6
C2/FFC4: B7F3    LDA [$F3],y    (grab next byte from the buffer)
C2/FFC6: EB      XBA
C2/FFC7: C8      INY            (next byte in the buffer)
C2/FFC8: 84F9    STY $F9        (save it for now)
C2/FFCA: B7F3    LDA [$F3],y    (grab another byte from the buffer)
C2/FFCC: 4A      LSR A
C2/FFCD: 4A      LSR A
C2/FFCE: 4A      LSR A          (divide by 8)
C2/FFCF: 18      CLC
C2/FFD0: 6903    ADC #$03       (and add 3)
C2/FFD2: 85FB    STA $FB
C2/FFD4: B7F3    LDA [$F3],y    (grab same byte as C2/FFCA)
C2/FFD6: 09F8    ORA #$F8       (set bits 3-7, this'll become an address)
C2/FFD8: EB      XBA
C2/FFD9: A8      TAY
C2/FFDA: B90000  LDA $0000,y    (load from 7F/F800+Y)
C2/FFDD: 8F802100 STA $002180    (to WRAM!)
C2/FFE1: 9D0000  STA $0000,x    (and to 7F/FFDE+X)
C2/FFE4: E8      INX            (has X reached 0 yet?)
C2/FFE5: D003    BNE $FFEA      (branch if not)
C2/FFE7: A200F8  LDX #$F800     (if so, set the starting position again)
C2/FFEA: C8      INY            (has Y reached 0 yet?)
C2/FFEB: D003    BNE $FFF0      (branch if not)
C2/FFED: A000F8  LDY #$F800     (if so, set the starting position again)
C2/FFF0: C6FB    DEC $FB
C2/FFF2: D0E6    BNE $FFDA
C2/FFF4: A4F9    LDY $F9
C2/FFF6: C8      INY
C2/FFF7: C4FC    CPY $FC        (have we run out of bytes to copy or exceeded the buffer?)
C2/FFF9: D0A7    BNE $FFA2      (if not, keep working)
C2/FFFB: 7B      TDC            (yay, all done)
C2/FFFC: EB      XBA
C2/FFFD: 2B      PLD
C2/FFFE: AB      PLB
C2/FFFF: 6B      RTL

There's 5 or 6 of these LZ decompression routines all scattered around the rom, all of them long calls. :banghead:

This may also interest you:

Code:
Various LZ-compressed sequences, and a giant head-scratcher for organization

Wedge, Vicks, and Terra walking to Narshe with credits
C2/6800: 4C1368  JMP $6813      (no BRA?)

World being torn apart
C2/6803: 4C0C68  JMP $680C      (no BRA?)

Rise of the floating continent
C2/6806: 4C1A68  JMP $681A      (no BRA?)

Title screen
C2/6809: 4C2168  JMP $6821      (no BRA?)

C2/680C: 202868  JSR $6828      (from C0/B96C -> C2/6803)
C2/680F: 5C00507E JMP $7E5000

C2/6813: 202868  JSR $6828      (from C0/B998 -> C2/6800)
C2/6816: 5C03507E JMP $7E5003

C2/681A: 202868  JSR $6828      (from C0/BA57 -> C2/6806)
C2/681D: 5C06507E JMP $7E5006

C2/6821: 202868  JSR $6828      (from C0/BA6F -> C2/6809)
C2/6824: 5C09507E JMP $7E5009
Zeemis
Guest
« Reply #3 on: December 04, 2009, 03:09:46 am »

Ah, thank you guys.
Glad to see you're back as well, Lenophis.
Gemini
Guest
« Reply #4 on: December 04, 2009, 11:20:58 am »

They could have used that compression a little more, like in Chrono Trigger.  Undecided\
Geiger
Guest
« Reply #5 on: December 09, 2009, 08:30:16 am »

You can use Peer Sprite Viewer to decompress / recompress packets from FFVI, though I don't know if it protects against overwriting surrounding packets.  You can also use the code from FFVI Extract to roll your own compression code.  (I believe the original decompression code is from the editor that was put out a number of years back.)
Pages: [1]  


Powered by SMF 1.1.4 | SMF © 2006-2007, Simple Machines LLC