INCLUDE "constants.asm"


SECTION "home/pokemon.asm@3A4B", ROM0

GetMonHeader::
; copies the base stat data of a pokemon to wMonHeader
; INPUT:
; [wCurSpecies] = pokemon ID in dex order
	push bc
	push de
	push hl
	ldh a, [hROMBank]
	push af
	ld a, BANK(BaseData)
	call Bankswitch
	ld a, [wCurSpecies]
	cp DEX_EGG
	jr z, .egg
	dec a
	ld bc, BaseData.FirstEntryEnd - BaseData
	ld hl, BaseData
	call AddNTimes
	ld de, wMonHeader
	ld bc, BaseData.FirstEntryEnd - BaseData
	call CopyBytes
	jr .done
.egg
	ld de, EggPicFront
	ln b, 5, 5 ; egg sprite dimension
	ld hl, wMonHSpriteDim
	ld [hl], b
	ld hl, wMonHFrontSprite
	ld [hl], e
	inc hl
	ld [hl], d
	jr .done ; useless
.done
	ld a, [wCurSpecies]
	ld [wMonHIndex], a
	pop af
	call Bankswitch
	pop hl
	pop de
	pop bc
	ret


SECTION "home/pokemon.asm@3AED", ROM0

UncompressMonSprite::
; Uncompresses the front or back sprite of the specified mon
; assumes the corresponding mon header is already loaded
; hl contains offset to sprite pointer ($b for front or $d for back)
	ld a, [wMonDexIndex]
	and a
	ret z
	ld bc, wMonHeader
	add hl, bc
	cp DEX_ANNON
	jr z, .uncompress_annon
	ld a, [hli]
	ld [wSpriteInputPtr], a
	ld a, [hl]
	ld [wSpriteInputPtr + 1], a
	ld hl, MonSpriteBankList
	ld a, [wMonDexIndex]
	ld b, a
	; get Pokémon picture bank pointer from list
.loop
	ld a, BANK(MonSpriteBankList)
	call GetFarByte
	inc hl
	inc hl
	cp b
	jr c, .loop
	dec hl
	ld a, BANK(MonSpriteBankList)
	call GetFarByte
	jp UncompressSpriteData
.uncompress_annon
	ld a, [hli]
	ld h, [hl]
	ld l, a
	ld a, [wAnnonID]
	dec a
	add a
	add a
	ld c, a
	ld b, $00
	add hl, bc
	ld a, BANK(AnnonPicPtrs)
	call GetFarByte
	ld [wSpriteInputPtr], a
	inc hl
	ld a, BANK(AnnonPicPtrs)
	call GetFarByte
	ld [wSpriteInputPtr + 1], a
	ld a, BANK(AnnonPics)
	jp UncompressSpriteData

LoadMonFrontSprite::
; Uncompress Pokémon Front Sprite for mon
; currently loaded in wMonHeader to vFrontPic
; de: destination location
; returns the sprite dimension in c
	push de
	ld hl, wMonHFrontSprite - wMonHeader
	call UncompressMonSprite
	ld hl, wMonHSpriteDim
	ld a, [hl]
	ld c, a
	pop de
	; fallthrough

LoadUncompressedSpriteData::
; postprocesses uncompressed sprite chunks to a 2bpp sprite and loads it into video ram
; calculates alignment parameters to place both sprite chunks in the center of the 7*7 tile sprite buffers
; de: destination location
; a,c:  sprite dimensions (in tiles of 8x8 each)
	push de
	and $0f
	ldh [hSpriteWidth], a ; each byte contains 8 pixels (in 1bpp), so tiles=bytes for width
	ld b, a
	ld a, $07
	sub b      ; 7-w
	inc a      ; 8-w
	srl a      ; (8-w)/2     ; horizontal center (in tiles, rounded up)
	ld b, a
	add a
	add a
	add a
	sub b      ; 7*((8-w)/2) ; skip for horizontal center (in tiles)
	ldh [hSpriteOffset], a
	ld a, c
	swap a
	and $0f
	ld b, a
	add a
	add a
	add a      ; 8*tiles is height in bytes
	ldh [hSpriteHeight], a
	ld a, $07
	sub b      ; 7-h         ; skip for vertical center (in tiles, relative to current column)
	ld b, a
	ldh a, [hSpriteOffset]
	add b      ; 7*((8-w)/2) + 7-h ; combined overall offset (in tiles)
	add a
	add a
	add a      ; 8*(7*((8-w)/2) + 7-h) ; combined overall offset (in bytes)
	ldh [hSpriteOffset], a
	ld a, $00
	call OpenSRAM
	ld hl, sSpriteBuffer0
	call ZeroSpriteBuffer   ; zero buffer 0
	ld de, sSpriteBuffer1
	ld hl, sSpriteBuffer0
	call AlignSpriteDataCentered    ; copy and align buffer 1 to 0 (containing the MSB of the 2bpp sprite)
	ld hl, sSpriteBuffer1
	call ZeroSpriteBuffer   ; zero buffer 1
	ld de, sSpriteBuffer2
	ld hl, sSpriteBuffer1
	call AlignSpriteDataCentered    ; copy and align buffer 2 to 1 (containing the LSB of the 2bpp sprite)
	call CloseSRAM
	pop de
	call InterlaceMergeSpriteBuffers
	ret

ZeroSpriteBuffer::
; fills the sprite buffer (pointed to in hl) with zeros
	ld bc, SPRITEBUFFERSIZE
	xor a
	jp ByteFill

AlignSpriteDataCentered::
; copies and aligns the sprite data properly inside the sprite buffer
; sprite buffers are 7*7 tiles in size, the loaded sprite is centered within this area
	ldh a, [hSpriteOffset]
	ld c, a
	ld b, $00
	add hl, bc
	ldh a, [hSpriteWidth]
	ld b, a
	ldh a, [hSpriteHeight]
	ld c, a
.columnLoop
	push bc
	push hl
.columnInnerLoop
	ld a, [de]
	inc de
	ld [hli], a
	dec c
	jr nz, .columnInnerLoop
	pop hl
	ld bc, 7*8    ; 7 tiles
	add hl, bc    ; advance one full column
	pop bc
	dec b
	jr nz, .columnLoop
	ret

InterlaceMergeSpriteBuffers::
; combines the (7*7 tiles, 1bpp) sprite chunks in buffer 0 and 1 into a 2bpp sprite located in buffer 1 through 2
; in the resulting sprite, the rows of the two source sprites are interlaced
; de: output address
	ld a, $00
	call OpenSRAM
	push de
	call _InterlaceMergeSpriteBuffers
	pop hl
	ld de, sSpriteBuffer1
	ld c, (2 * SPRITEBUFFERSIZE) / 16 ; $31, number of 16 byte chunks to be copied
	ldh a, [hROMBank]
	ld b, a
	call Get2bpp
	call CloseSRAM
	ret

_InterlaceMergeSpriteBuffers::
; actual implementation of InterlaceMergeSpriteBuffers
; sprite flipping is now done during interlace merge loop
; and not as second loop after regular interlace merge
; to save time
	ld a, [wSpriteFlipped]
	and a
	jr nz, .flipped
	ld hl, sSpriteBuffer2 + (SPRITEBUFFERSIZE - 1) ; destination: end of buffer 2
	ld de, sSpriteBuffer1 + (SPRITEBUFFERSIZE - 1) ; source 2: end of buffer 1
	ld bc, sSpriteBuffer0 + (SPRITEBUFFERSIZE - 1) ; source 1: end of buffer 0
	ld a, SPRITEBUFFERSIZE/2 ; $c4
	ldh [hSpriteInterlaceCounter], a
.interlaceLoop
	ld a, [de]
	dec de
	ld [hld], a   ; write byte of source 2
	ld a, [bc]
	dec bc
	ld [hld], a   ; write byte of source 1
	ld a, [de]
	dec de
	ld [hld], a   ; write byte of source 2
	ld a, [bc]
	dec bc
	ld [hld], a   ; write byte of source 1
	ldh a, [hSpriteInterlaceCounter]
	dec a
	ldh [hSpriteInterlaceCounter], a
	jr nz, .interlaceLoop
	ld a, [wSpriteFlipped] ; always notFlipped; flip routine was optimized
	and a
	jr z, .notFlipped
	ld bc, 2*SPRITEBUFFERSIZE
	ld hl, sSpriteBuffer1
.swapLoop
	swap [hl]    ; if flipped swap nybbles in all bytes
	inc hl
	dec bc
	ld a, b
	or c
	jr nz, .swapLoop
.notFlipped
	ret
.flipped
	ld hl, sSpriteBuffer2 + (SPRITEBUFFERSIZE - 1) ; destination: end of buffer 2
	ld de, sSpriteBuffer1 + (SPRITEBUFFERSIZE - 1) ; source 2: end of buffer 1
	ld bc, sSpriteBuffer0 + (SPRITEBUFFERSIZE - 1) ; source 1: end of buffer 0
	ld a, SPRITEBUFFERSIZE / 2 ; $c4
	ldh [hSpriteInterlaceCounter], a
.interlaceLoopFlipped
	ld a, [de]
	dec de
	swap a
	ld [hld], a   ; write byte of source 2
	ld a, [bc]
	dec bc
	swap a
	ld [hld], a   ; write byte of source 1
	ld a, [de]
	dec de
	swap a
	ld [hld], a   ; write byte of source 2
	ld a, [bc]
	dec bc
	swap a
	ld [hld], a   ; write byte of source 1
	ldh a, [hSpriteInterlaceCounter]
	dec a
	ldh [hSpriteInterlaceCounter], a
	jr nz, .interlaceLoopFlipped
	ret
