; --------------------------------------------------------------------------- ; 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 ; ---------------------------------------------------------------------------