; ---------------------------------------------------------------------------
; SUBROUTINE
;
; Decompresses sprite using RBY compression (e.g. Pokemon and trainer pics)
;
; Documentation on the compression format can be found here (although the
; English is a bit hard to understand):
; http://magicstone.de/rhwiki/article/Grafikkomprimierung_PKMN_RGBY
; ---------------------------------------------------------------------------
DecompressSprite: ; $24FD
ld b, a
ld a, [BANKNUM]
push af ; push bank number onto stack for later retrieval
ld a, b ; set bank to sprite bank
ld [BANKNUM], a
ld [BANKSWITCH], a
ld a, $A
ld [SRAM_ENABLE], a ; enable SRAM by setting $0000 to $A
xor a ; (the SRAM is used to house the two $188-byte buffers)
ld [BANKSWITCH_U], a ; clear upper bits of bank number
call DS_Start ; call decompression routine
pop af ; retrieve bank number from stack
ld [BANKNUM], a ; set bank back to old bank
ld [BANKSWITCH], a
ret
; ---------------------------------------------------------------------------
; Decompression routine begins here
; ---------------------------------------------------------------------------
DS_Start: ; $251A
ld hl, $A188 ; hl = $A188
ld c, $10 ; bc = $310
ld b, 3
xor a ; a = $0
call FillRAMArea ; clear $310 bytes at $A188 (for RAM buffers)
ld a, 1 ; initialize decompression values
ld [W_DS_CURBIT], a ; current bit = 1
ld a, 3
ld [W_DS_CURBITGROUP], a ; current bit group = 3
xor a
ld [W_DS_CURYSIZE], a
ld [W_DS_CURXSIZE], a
ld [W_DS_CURBUFFER], a
call DS_GetNextByte ; get first byte (X/Y size)
ld b, a ; x size = (lower nybble of byte) * 8
and $F
add a, a
add a, a
add a, a
ld [W_DS_XSIZE], a
ld a, b ; y size = (upper nybble of byte) * 8
swap a
and $F
add a, a
add a, a
add a, a
ld [W_DS_YSIZE], a
call DS_GetNextBit ; get which RAM buffer to use (0 = RAM1, 1 = RAM2)
ld [W_DS_CURBUFFER], a
DS_GetCurBuffer: ; $2556
ld hl, S_DS_RAM1 ; default buffer: RAM1
ld a, [W_DS_CURBUFFER]
bit 0, a ; is current buffer RAM2? (bit 0 = 1)
jr z, DS_GetInterpretation ; if not, branch
ld hl, S_DS_RAM2 ; set buffer to RAM2
DS_GetInterpretation: ; $2563
call DS_SetPositions ; set pos0 and pos1 to hl (beginning of current buffer)
ld a, [W_DS_CURBUFFER]
bit 1, a ; is bit 1 of current buffer set? (done at the end of first stream)
jr z, loc_257A ; if not, branch
call DS_GetNextBit ; get interpretation (either 1 or 2 bits)
and a
jr z, loc_2577 ; if bit read is 0, then branch (interpretation = 0)
call DS_GetNextBit ; else, interpretation = (next bit + 1)
inc a ; this results in a interpretation range of 0 to 2 (3 total)
loc_2577: ; CODE XREF: DS_Start+57j
ld [W_DS_INTRP], a ; set interpretation
loc_257A: ; CODE XREF: DS_Start+51j
call DS_GetNextBit ; get next bit (determines whether first packet is data or RLE)
and a ; is bit 0?
jr z, DS_RLEPacket ; if yes, it's an RLE packet, so branch
DS_DataPacket: ; $2580
call DS_GetNextBit
ld c, a
call DS_GetNextBit
sla c
or c
and a
jr z, DS_RLEPacket
call sub_2649
call sub_25D8
jr DS_DataPacket
; ---------------------------------------------------------------------------
DS_RLEPacket: ; $2595
ld c, 0 ; initialize c as 0
DS_RLEIndexLoop: ; $2597
call DS_GetNextBit ; c = number of bits set (index into RLE table)
and a ; is bit 0?
jr z, loc_25A0 ; if so, branch
inc c ; increment c
jr DS_RLEIndexLoop ; loop
; ---------------------------------------------------------------------------
loc_25A0: ; CODE XREF: DS_Start+81j
ld a, c
add a, a
ld hl, DS_RLETable
add a, l
ld l, a
jr nc, loc_25AA
inc h
loc_25AA: ; CODE XREF: DS_Start+8Dj
ldi a, [hl]
ld e, a
ld d, [hl]
push de
inc c
ld e, 0
ld d, e
loc_25B2: ; CODE XREF: DS_Start+A4j
call DS_GetNextBit
or e
ld e, a
dec c
jr z, loc_25C0
sla e
rl d
jr loc_25B2
; ---------------------------------------------------------------------------
loc_25C0: ; CODE XREF: DS_Start+9Ej
pop hl
add hl, de
ld e, l
ld d, h
loc_25C4: ; CODE XREF: DS_Start:loc_25D4j
ld b, e
xor a
call sub_2649
ld e, b
call sub_25D8
dec de
ld a, d
and a
jr nz, loc_25D4
ld a, e
and a
loc_25D4: ; CODE XREF: DS_Start+B6j
jr nz, loc_25C4
jr DS_DataPacket
; End of function DS_Start
; =============== S U B R O U T I N E =======================================
sub_25D8: ; CODE XREF: DS_Start+76p DS_Start+B0p
; FUNCTION CHUNK AT 26BF SIZE 00000015 BYTES
; FUNCTION CHUNK AT 27C7 SIZE 00000070 BYTES
; FUNCTION CHUNK AT 2877 SIZE 00000020 BYTES
ld a, [W_DS_XSIZE]
ld b, a
ld a, [W_DS_CURXSIZE]
inc a
cp b
jr z, loc_25F6
ld [W_DS_CURXSIZE], a
ld a, [W_DS_POS0]
inc a
ld [W_DS_POS0], a
ret nz
ld a, [W_DS_POS0+1]
inc a
ld [W_DS_POS0+1], a
ret
; ---------------------------------------------------------------------------
loc_25F6: ; CODE XREF: sub_25D8+9j
xor a
ld [W_DS_CURXSIZE], a
ld a, [W_DS_CURBITGROUP]
and a
jr z, loc_2610
dec a
ld [W_DS_CURBITGROUP], a
ld hl, W_DS_POS1
ldi a, [hl]
ld [W_DS_POS0], a
ld a, [hl]
ld [W_DS_POS0+1], a
ret
; ---------------------------------------------------------------------------
loc_2610: ; CODE XREF: sub_25D8+26j
ld a, 3
ld [W_DS_CURBITGROUP], a
ld a, [W_DS_CURYSIZE]
add a, 8
ld [W_DS_CURYSIZE], a
ld b, a
ld a, [W_DS_YSIZE]
cp b
jr z, loc_2630
ld a, [W_DS_POS0]
ld l, a
ld a, [W_DS_POS0+1]
ld h, a
inc hl
jp DS_SetPositions
; ---------------------------------------------------------------------------
loc_2630: ; CODE XREF: sub_25D8+4Aj
pop hl
xor a
ld [W_DS_CURYSIZE], a
ld a, [W_DS_CURBUFFER]
bit 1, a
jr nz, loc_2646
xor 1
set 1, a
ld [W_DS_CURBUFFER], a
jp DS_GetCurBuffer
; ---------------------------------------------------------------------------
loc_2646: ; CODE XREF: sub_25D8+62j
jp loc_26BF
; End of function sub_25D8
; =============== S U B R O U T I N E =======================================
sub_2649: ; CODE XREF: DS_Start+73p DS_Start+ACp
ld e, a
ld a, [W_DS_CURBITGROUP]
and a
jr z, loc_2664
cp 2
jr c, loc_265C
jr z, loc_2662
rrc e
rrc e
jr loc_2664
; ---------------------------------------------------------------------------
loc_265C: ; CODE XREF: sub_2649+9j
sla e
sla e
jr loc_2664
; ---------------------------------------------------------------------------
loc_2662: ; CODE XREF: sub_2649+Bj
swap e
loc_2664: ; CODE XREF: sub_2649+5j sub_2649+11j ...
ld a, [W_DS_POS0]
ld l, a
ld a, [W_DS_POS0+1]
ld h, a
ld a, [hl]
or e
ld [hl], a
ret
; End of function sub_2649
; ---------------------------------------------------------------------------
; SUBROUTINE
;
; Gets next bit of stream into a, increments position pointer and gets new
; byte if necessary
; ---------------------------------------------------------------------------
DS_GetNextBit: ; $2670
ld a, [W_DS_CURBIT]
dec a
jr nz, loc_267E
call DS_GetNextByte
ld [W_DS_CURBYTE], a
ld a, 8
loc_267E: ; CODE XREF: DS_GetNextBit+4j
ld [W_DS_CURBIT], a
ld a, [W_DS_CURBYTE]
rlca
ld [W_DS_CURBYTE], a
and 1
ret
; End of function DS_GetNextBit
; ---------------------------------------------------------------------------
; SUBROUTINE
;
; Gets next byte of stream into a, increments position pointer
; ---------------------------------------------------------------------------
DS_GetNextByte: ; $268B
ld a, [W_DS_CURPOS] ; hl = current position
ld l, a
ld a, [W_DS_CURPOS+1]
ld h, a
ld a, [hl+] ; b = [hl+]
ld b, a
ld a, l ; current position = hl (now incremented)
ld [W_DS_CURPOS], a
ld a, h
ld [W_DS_CURPOS+1], a
ld a, b ; a = b (new byte)
ret
; End of function DS_GetNextByte
; ---------------------------------------------------------------------------
; DATA
;
; RLE lookup table - the number of 1 bits (n) read at the start of an RLE packet
; is the index into this table. Then, an additional value (n+1 bits long) is
; read, and added to the value lifted from this table to get the total number
; of 00-bit groups to write.
; ---------------------------------------------------------------------------
DS_RLETable: ; $269F
dw 1
dw 3
dw 7
dw $F
dw $1F
dw $3F
dw $7F
dw $FF
dw $1FF
dw $3FF
dw $7FF
dw $FFF
dw $1FFF
dw $3FFF
dw $7FFF
dw $FFFF
; ---------------------------------------------------------------------------
; START OF FUNCTION CHUNK FOR sub_25D8
loc_26BF: ; CODE XREF: sub_25D8:loc_2646j
ld a, [W_DS_INTRP]
cp 2
jp z, loc_2877
and a
jp nz, loc_27C7
ld hl, $A188
call sub_26D4
ld hl, $A310
; END OF FUNCTION CHUNK FOR sub_25D8
; =============== S U B R O U T I N E =======================================
sub_26D4: ; CODE XREF: sub_25D8+F6p
; sub_25D8+201p ...
xor a
ld [W_DS_CURYSIZE], a
ld [W_DS_CURXSIZE], a
call DS_SetPositions
ld a, [$D0AA]
and a
jr z, loc_26EC
ld hl, DS_BitTable1M
ld de, DS_BitTable2M
jr loc_26F2
; ---------------------------------------------------------------------------
loc_26EC: ; CODE XREF: sub_26D4+Ej
ld hl, DS_BitTable1
ld de, DS_BitTable2
loc_26F2: ; CODE XREF: sub_26D4+16j
ld a, l
ld [$D0B1], a
ld a, h
ld [$D0B2], a
ld a, e
ld [$D0B3], a
ld a, d
ld [$D0B4], a
ld e, 0
loc_2704: ; CODE XREF: sub_26D4+71j sub_26D4+92j
ld a, [W_DS_POS0]
ld l, a
ld a, [W_DS_POS0+1]
ld h, a
ld a, [hl]
ld b, a
swap a
and $F
call sub_276D
swap a
ld d, a
ld a, b
and $F
call sub_276D
or d
ld b, a
ld a, [W_DS_POS0]
ld l, a
ld a, [W_DS_POS0+1]
ld h, a
ld a, b
ld [hl], a
ld a, [W_DS_XSIZE]
add a, l
jr nc, loc_2731
inc h
loc_2731: ; CODE XREF: sub_26D4+5Aj
ld [W_DS_POS0], a
ld a, h
ld [W_DS_POS0+1], a
ld a, [W_DS_CURYSIZE]
add a, 8
ld [W_DS_CURYSIZE], a
ld b, a
ld a, [W_DS_YSIZE]
cp b
jr nz, loc_2704
xor a
ld e, a
ld [W_DS_CURYSIZE], a
ld a, [W_DS_CURXSIZE]
inc a
ld [W_DS_CURXSIZE], a
ld b, a
ld a, [W_DS_XSIZE]
cp b
jr z, loc_2768
ld a, [W_DS_POS1]
ld l, a
ld a, [W_DS_POS1+1]
ld h, a
inc hl
call DS_SetPositions
jr loc_2704
; ---------------------------------------------------------------------------
loc_2768: ; CODE XREF: sub_26D4+84j
xor a
ld [W_DS_CURXSIZE], a
ret
; End of function sub_26D4
; =============== S U B R O U T I N E =======================================
sub_276D: ; CODE XREF: sub_26D4+3Ep sub_26D4+47p
srl a
ld c, 0
jr nc, loc_2775
ld c, 1
loc_2775: ; CODE XREF: sub_276D+4j
ld l, a
ld a, [$D0AA]
and a
jr z, loc_2780
bit 3, e
jr loc_2782
; ---------------------------------------------------------------------------
loc_2780: ; CODE XREF: sub_276D+Dj
bit 0, e
loc_2782: ; CODE XREF: sub_276D+11j
ld e, l
jr nz, loc_278E
ld a, [$D0B1]
ld l, a
ld a, [$D0B2]
jr loc_2795
; ---------------------------------------------------------------------------
loc_278E: ; CODE XREF: sub_276D+16j
ld a, [$D0B3]
ld l, a
ld a, [$D0B4]
loc_2795: ; CODE XREF: sub_276D+1Fj
ld h, a
ld a, e
add a, l
ld l, a
jr nc, loc_279C
inc h
loc_279C: ; CODE XREF: sub_276D+2Cj
ld a, [hl]
bit 0, c
jr nz, loc_27A3
swap a
loc_27A3: ; CODE XREF: sub_276D+32j
and $F
ld e, a
ret
; End of function sub_276D
; ---------------------------------------------------------------------------
DS_BitTable1: db 1 ; DATA XREF: sub_26D4:loc_26ECo
db $32 ; 2
db $76 ; v
db $45 ; E
db $FE ; þ
db $CD ; Í
db $89 ; ‰
db $BA ; º
DS_BitTable2: db $FE ; þ ; DATA XREF: sub_26D4+1Bo
db $CD ; Í
db $89 ; ‰
db $BA ; º
db 1
db $32 ; 2
db $76 ; v
db $45 ; E
DS_BitTable1M: db 8 ; DATA XREF: sub_26D4+10o
db $C4 ; Ä
db $E6 ; æ
db $2A ; *
db $F7 ; ÷
db $3B ; ;
db $19
db $D5 ; Õ
DS_BitTable2M: db $F7 ; ÷ ; DATA XREF: sub_26D4+13o
db $3B ; ;
db $19
db $D5 ; Õ
db 8
db $C4 ; Ä
db $E6 ; æ
db $2A ; *
; ---------------------------------------------------------------------------
; START OF FUNCTION CHUNK FOR sub_25D8
loc_27C7: ; CODE XREF: sub_25D8+F0j
; sub_25D8+2BCj
xor a
ld [W_DS_CURYSIZE], a
ld [W_DS_CURXSIZE], a
call sub_2841
ld a, [W_DS_POS0]
ld l, a
ld a, [W_DS_POS0+1]
ld h, a
call sub_26D4
call sub_2841
ld a, [W_DS_POS0]
ld l, a
ld a, [W_DS_POS0+1]
ld h, a
ld a, [W_DS_POS1]
ld e, a
ld a, [W_DS_POS1+1]
ld d, a
loc_27EF: ; CODE XREF: sub_25D8+245j
; sub_25D8+258j
ld a, [$D0AA]
and a
jr z, loc_280B
push de
ld a, [de]
ld b, a
swap a
and $F
call sub_2837
swap a
ld c, a
ld a, b
and $F
call sub_2837
or c
pop de
ld [de], a
loc_280B: ; CODE XREF: sub_25D8+21Bj
ldi a, [hl]
ld b, a
ld a, [de]
xor b
ld [de], a
inc de
ld a, [W_DS_CURXSIZE]
inc a
ld [W_DS_CURXSIZE], a
ld b, a
ld a, [W_DS_XSIZE]
cp b
jr nz, loc_27EF
xor a
ld [W_DS_CURXSIZE], a
ld a, [W_DS_CURYSIZE]
add a, 8
ld [W_DS_CURYSIZE], a
ld b, a
ld a, [W_DS_YSIZE]
cp b
jr nz, loc_27EF
xor a
ld [W_DS_CURYSIZE], a
ret
; END OF FUNCTION CHUNK FOR sub_25D8
; =============== S U B R O U T I N E =======================================
sub_2837: ; CODE XREF: sub_25D8+224p
; sub_25D8+22Dp
ld de, Intp2Table
add a, e
ld e, a
jr nc, loc_283F
inc d
loc_283F: ; CODE XREF: sub_2837+5j
ld a, [de]
ret
; End of function sub_2837
; =============== S U B R O U T I N E =======================================
sub_2841: ; CODE XREF: sub_25D8+1F6p
; sub_25D8+204p ...
ld a, [W_DS_CURBUFFER]
bit 0, a
jr nz, loc_2850
ld de, $A188
ld hl, $A310
jr loc_2856
; ---------------------------------------------------------------------------
loc_2850: ; CODE XREF: sub_2841+5j
ld de, $A310
ld hl, $A188
loc_2856: ; CODE XREF: sub_2841+Dj
ld a, l
ld [W_DS_POS0], a
ld a, h
ld [W_DS_POS0+1], a
ld a, e
ld [W_DS_POS1], a
ld a, d
ld [W_DS_POS1+1], a
ret
; End of function sub_2841
; ---------------------------------------------------------------------------
Intp2Table: db 0 ; DATA XREF: sub_2837o
db 8
db 4
db $C
db 2
db $A
db 6
db $E
db 1
db 9
db 5
db $D
db 3
db $B
db 7
db $F
; ---------------------------------------------------------------------------
; START OF FUNCTION CHUNK FOR sub_25D8
loc_2877: ; CODE XREF: sub_25D8+ECj
call sub_2841
ld a, [$D0AA]
push af
xor a
ld [$D0AA], a
ld a, [W_DS_POS1]
ld l, a
ld a, [W_DS_POS1+1]
ld h, a
call sub_26D4
call sub_2841
pop af
ld [$D0AA], a
jp loc_27C7
; END OF FUNCTION CHUNK FOR sub_25D8
; ---------------------------------------------------------------------------
; SUBROUTINE
;
; Sets POS0 and POS1 to the address in hl
; ---------------------------------------------------------------------------
DS_SetPositions: ; $2897
ld a, l
ld [W_DS_POS0], a
ld [W_DS_POS1], a
ld a, h
ld [W_DS_POS0+1], a
ld [W_DS_POS1+1], a
ret
; End of function DS_SetPositions
; ---------------------------------------------------------------------------