mirror of https://github.com/pret/pokecrystal.git
368 lines
5.2 KiB
NASM
368 lines
5.2 KiB
NASM
|
FarDecompress: ; b40
|
||
|
; Decompress graphics data at a:hl to de
|
||
|
|
||
|
; put a away for a sec
|
||
|
ld [$c2c4], a
|
||
|
; save bank
|
||
|
ld a, [hROMBank]
|
||
|
push af
|
||
|
; bankswitch
|
||
|
ld a, [$c2c4]
|
||
|
rst Bankswitch
|
||
|
|
||
|
; what we came here for
|
||
|
call Decompress
|
||
|
|
||
|
; restore bank
|
||
|
pop af
|
||
|
rst Bankswitch
|
||
|
ret
|
||
|
; b50
|
||
|
|
||
|
|
||
|
Decompress: ; b50
|
||
|
; Pokemon Crystal uses an lz variant for compression.
|
||
|
|
||
|
; This is mainly used for graphics, but the intro's
|
||
|
; tilemaps also use this compression.
|
||
|
|
||
|
; This function decompresses lz-compressed data at hl to de.
|
||
|
|
||
|
|
||
|
; Basic rundown:
|
||
|
|
||
|
; A typical control command consists of:
|
||
|
; -the command (bits 5-7)
|
||
|
; -the count (bits 0-4)
|
||
|
; -and any additional params
|
||
|
|
||
|
; $ff is used as a terminator.
|
||
|
|
||
|
|
||
|
; Commands:
|
||
|
|
||
|
; 0: literal
|
||
|
; literal data for some number of bytes
|
||
|
; 1: iterate
|
||
|
; one byte repeated for some number of bytes
|
||
|
; 2: alternate
|
||
|
; two bytes alternated for some number of bytes
|
||
|
; 3: zero (whitespace)
|
||
|
; 0x00 repeated for some number of bytes
|
||
|
|
||
|
; Repeater control commands have a signed parameter used to determine the start point.
|
||
|
; Wraparound is simulated:
|
||
|
; Positive values are added to the start address of the decompressed data
|
||
|
; and negative values are subtracted from the current position.
|
||
|
|
||
|
; 4: repeat
|
||
|
; repeat some number of bytes from decompressed data
|
||
|
; 5: flipped
|
||
|
; repeat some number of flipped bytes from decompressed data
|
||
|
; ex: $ad = %10101101 -> %10110101 = $b5
|
||
|
; 6: reverse
|
||
|
; repeat some number of bytes in reverse from decompressed data
|
||
|
|
||
|
; If the value in the count needs to be larger than 5 bits,
|
||
|
; control code 7 can be used to expand the count to 10 bits.
|
||
|
|
||
|
; A new control command is read in bits 2-4.
|
||
|
; The new 10-bit count is split:
|
||
|
; bits 0-1 contain the top 2 bits
|
||
|
; another byte is added containing the latter 8
|
||
|
|
||
|
; So, the structure of the control command becomes:
|
||
|
; 111xxxyy yyyyyyyy
|
||
|
; | | | |
|
||
|
; | | our new count
|
||
|
; | the control command for this count
|
||
|
; 7 (this command)
|
||
|
|
||
|
; For more information, refer to the code below and in extras/gfx.py .
|
||
|
|
||
|
; save starting output address
|
||
|
ld a, e
|
||
|
ld [$c2c2], a
|
||
|
ld a, d
|
||
|
ld [$c2c3], a
|
||
|
|
||
|
.loop
|
||
|
; get next byte
|
||
|
ld a, [hl]
|
||
|
; done?
|
||
|
cp $ff ; end
|
||
|
ret z
|
||
|
|
||
|
; get control code
|
||
|
and %11100000
|
||
|
|
||
|
; 10-bit param?
|
||
|
cp $e0 ; LZ_HI
|
||
|
jr nz, .normal
|
||
|
|
||
|
|
||
|
; 10-bit param:
|
||
|
|
||
|
; get next 3 bits (%00011100)
|
||
|
ld a, [hl]
|
||
|
add a
|
||
|
add a ; << 3
|
||
|
add a
|
||
|
|
||
|
; this is our new control code
|
||
|
and %11100000
|
||
|
push af
|
||
|
|
||
|
; get param hi
|
||
|
ld a, [hli]
|
||
|
and %00000011
|
||
|
ld b, a
|
||
|
|
||
|
; get param lo
|
||
|
ld a, [hli]
|
||
|
ld c, a
|
||
|
|
||
|
; read at least 1 byte
|
||
|
inc bc
|
||
|
jr .readers
|
||
|
|
||
|
|
||
|
.normal
|
||
|
; push control code
|
||
|
push af
|
||
|
; get param
|
||
|
ld a, [hli]
|
||
|
and %00011111
|
||
|
ld c, a
|
||
|
ld b, $0
|
||
|
; read at least 1 byte
|
||
|
inc c
|
||
|
|
||
|
.readers
|
||
|
; let's get started
|
||
|
|
||
|
; inc loop counts since we bail as soon as they hit 0
|
||
|
inc b
|
||
|
inc c
|
||
|
|
||
|
; get control code
|
||
|
pop af
|
||
|
; command type
|
||
|
bit 7, a ; 80, a0, c0
|
||
|
jr nz, .repeatertype
|
||
|
|
||
|
; literals
|
||
|
cp $20 ; LZ_ITER
|
||
|
jr z, .iter
|
||
|
cp $40 ; LZ_ALT
|
||
|
jr z, .alt
|
||
|
cp $60 ; LZ_ZERO
|
||
|
jr z, .zero
|
||
|
; else $00
|
||
|
|
||
|
; 00 ; LZ_LIT
|
||
|
; literal data for bc bytes
|
||
|
.loop1
|
||
|
; done?
|
||
|
dec c
|
||
|
jr nz, .next1
|
||
|
dec b
|
||
|
jp z, .loop
|
||
|
|
||
|
.next1
|
||
|
ld a, [hli]
|
||
|
ld [de], a
|
||
|
inc de
|
||
|
jr .loop1
|
||
|
|
||
|
|
||
|
; 20 ; LZ_ITER
|
||
|
; write byte for bc bytes
|
||
|
.iter
|
||
|
ld a, [hli]
|
||
|
|
||
|
.iterloop
|
||
|
dec c
|
||
|
jr nz, .iternext
|
||
|
dec b
|
||
|
jp z, .loop
|
||
|
|
||
|
.iternext
|
||
|
ld [de], a
|
||
|
inc de
|
||
|
jr .iterloop
|
||
|
|
||
|
|
||
|
; 40 ; LZ_ALT
|
||
|
; alternate two bytes for bc bytes
|
||
|
|
||
|
; next pair
|
||
|
.alt
|
||
|
; done?
|
||
|
dec c
|
||
|
jr nz, .alt0
|
||
|
dec b
|
||
|
jp z, .altclose0
|
||
|
|
||
|
; alternate for bc
|
||
|
.alt0
|
||
|
ld a, [hli]
|
||
|
ld [de], a
|
||
|
inc de
|
||
|
dec c
|
||
|
jr nz, .alt1
|
||
|
; done?
|
||
|
dec b
|
||
|
jp z, .altclose1
|
||
|
.alt1
|
||
|
ld a, [hld]
|
||
|
ld [de], a
|
||
|
inc de
|
||
|
jr .alt
|
||
|
|
||
|
; skip past the bytes we were alternating
|
||
|
.altclose0
|
||
|
inc hl
|
||
|
.altclose1
|
||
|
inc hl
|
||
|
jr .loop
|
||
|
|
||
|
|
||
|
; 60 ; LZ_ZERO
|
||
|
; write 00 for bc bytes
|
||
|
.zero
|
||
|
xor a
|
||
|
|
||
|
.zeroloop
|
||
|
dec c
|
||
|
jr nz, .zeronext
|
||
|
dec b
|
||
|
jp z, .loop
|
||
|
|
||
|
.zeronext
|
||
|
ld [de], a
|
||
|
inc de
|
||
|
jr .zeroloop
|
||
|
|
||
|
|
||
|
; repeats
|
||
|
; 80, a0, c0
|
||
|
; repeat decompressed data from output
|
||
|
.repeatertype
|
||
|
push hl
|
||
|
push af
|
||
|
; get next byte
|
||
|
ld a, [hli]
|
||
|
; absolute?
|
||
|
bit 7, a
|
||
|
jr z, .absolute
|
||
|
|
||
|
; relative
|
||
|
; a = -a
|
||
|
and %01111111 ; forget the bit we just looked at
|
||
|
cpl
|
||
|
; add de (current output address)
|
||
|
add e
|
||
|
ld l, a
|
||
|
ld a, $ff ; -1
|
||
|
adc d
|
||
|
ld h, a
|
||
|
jr .repeaters
|
||
|
|
||
|
.absolute
|
||
|
; get next byte (lo)
|
||
|
ld l, [hl]
|
||
|
; last byte (hi)
|
||
|
ld h, a
|
||
|
; add starting output address
|
||
|
ld a, [$c2c2]
|
||
|
add l
|
||
|
ld l, a
|
||
|
ld a, [$c2c3]
|
||
|
adc h
|
||
|
ld h, a
|
||
|
|
||
|
.repeaters
|
||
|
pop af
|
||
|
cp $80 ; LZ_REPEAT
|
||
|
jr z, .repeat
|
||
|
cp $a0 ; LZ_FLIP
|
||
|
jr z, .flip
|
||
|
cp $c0 ; LZ_REVERSE
|
||
|
jr z, .reverse
|
||
|
|
||
|
; e0 -> 80
|
||
|
|
||
|
; 80 ; LZ_REPEAT
|
||
|
; repeat some decompressed data
|
||
|
.repeat
|
||
|
; done?
|
||
|
dec c
|
||
|
jr nz, .repeatnext
|
||
|
dec b
|
||
|
jr z, .cleanup
|
||
|
|
||
|
.repeatnext
|
||
|
ld a, [hli]
|
||
|
ld [de], a
|
||
|
inc de
|
||
|
jr .repeat
|
||
|
|
||
|
|
||
|
; a0 ; LZ_FLIP
|
||
|
; repeat some decompressed data w/ flipped bit order
|
||
|
.flip
|
||
|
dec c
|
||
|
jr nz, .flipnext
|
||
|
dec b
|
||
|
jp z, .cleanup
|
||
|
|
||
|
.flipnext
|
||
|
ld a, [hli]
|
||
|
push bc
|
||
|
ld bc, $0008
|
||
|
|
||
|
.fliploop
|
||
|
rra
|
||
|
rl b
|
||
|
dec c
|
||
|
jr nz, .fliploop
|
||
|
ld a, b
|
||
|
pop bc
|
||
|
ld [de], a
|
||
|
inc de
|
||
|
jr .flip
|
||
|
|
||
|
|
||
|
; c0 ; LZ_REVERSE
|
||
|
; repeat some decompressed data in reverse
|
||
|
.reverse
|
||
|
dec c
|
||
|
jr nz, .reversenext
|
||
|
|
||
|
dec b
|
||
|
jp z, .cleanup
|
||
|
|
||
|
.reversenext
|
||
|
ld a, [hld]
|
||
|
ld [de], a
|
||
|
inc de
|
||
|
jr .reverse
|
||
|
|
||
|
|
||
|
.cleanup
|
||
|
; get type of repeat we just used
|
||
|
pop hl
|
||
|
; was it relative or absolute?
|
||
|
bit 7, [hl]
|
||
|
jr nz, .next
|
||
|
|
||
|
; skip two bytes for absolute
|
||
|
inc hl
|
||
|
; skip one byte for relative
|
||
|
.next
|
||
|
inc hl
|
||
|
jp .loop
|
||
|
; c2f
|
||
|
|