shithub: pokered

Download patch

ref: 6d8c6055b5d5910d4da6997199f0984f8cd9149f
parent: d424eb44385c8f9e02d982b715a658e395e56c4b
author: yenatch <yenatch@gmail.com>
date: Fri May 30 21:22:15 EDT 2014

Split more code out of home.asm.

--- /dev/null
+++ b/data/collision.asm
@@ -1,0 +1,24 @@
+Underground_Coll::  INCBIN  "gfx/tilesets/underground.tilecoll"
+Overworld_Coll::    INCBIN  "gfx/tilesets/overworld.tilecoll"
+RedsHouse1_Coll::
+RedsHouse2_Coll::   INCBIN  "gfx/tilesets/reds_house.tilecoll"
+Mart_Coll::
+Pokecenter_Coll::   INCBIN  "gfx/tilesets/pokecenter.tilecoll"
+Dojo_Coll::
+Gym_Coll::          INCBIN  "gfx/tilesets/gym.tilecoll"
+Forest_Coll::       INCBIN  "gfx/tilesets/forest.tilecoll"
+House_Coll::        INCBIN  "gfx/tilesets/house.tilecoll"
+ForestGate_Coll::
+Museum_Coll::
+Gate_Coll::         INCBIN  "gfx/tilesets/gate.tilecoll"
+Ship_Coll::         INCBIN  "gfx/tilesets/ship.tilecoll"
+ShipPort_Coll::     INCBIN  "gfx/tilesets/ship_port.tilecoll"
+Cemetery_Coll::     INCBIN  "gfx/tilesets/cemetery.tilecoll"
+Interior_Coll::     INCBIN  "gfx/tilesets/interior.tilecoll"
+Cavern_Coll::       INCBIN  "gfx/tilesets/cavern.tilecoll"
+Lobby_Coll::        INCBIN  "gfx/tilesets/lobby.tilecoll"
+Mansion_Coll::      INCBIN  "gfx/tilesets/mansion.tilecoll"
+Lab_Coll::          INCBIN  "gfx/tilesets/lab.tilecoll"
+Club_Coll::         INCBIN  "gfx/tilesets/club.tilecoll"
+Facility_Coll::     INCBIN  "gfx/tilesets/facility.tilecoll"
+Plateau_Coll::      INCBIN  "gfx/tilesets/plateau.tilecoll"
--- a/home.asm
+++ b/home.asm
@@ -909,30 +909,7 @@
 	jp CopyVideoData
 
 
-Underground_Coll::  INCBIN  "gfx/tilesets/underground.tilecoll"
-Overworld_Coll::    INCBIN  "gfx/tilesets/overworld.tilecoll"
-RedsHouse1_Coll::
-RedsHouse2_Coll::   INCBIN  "gfx/tilesets/reds_house.tilecoll"
-Mart_Coll::
-Pokecenter_Coll::   INCBIN  "gfx/tilesets/pokecenter.tilecoll"
-Dojo_Coll::
-Gym_Coll::          INCBIN  "gfx/tilesets/gym.tilecoll"
-Forest_Coll::       INCBIN  "gfx/tilesets/forest.tilecoll"
-House_Coll::        INCBIN  "gfx/tilesets/house.tilecoll"
-ForestGate_Coll::
-Museum_Coll::
-Gate_Coll::         INCBIN  "gfx/tilesets/gate.tilecoll"
-Ship_Coll::         INCBIN  "gfx/tilesets/ship.tilecoll"
-ShipPort_Coll::     INCBIN  "gfx/tilesets/ship_port.tilecoll"
-Cemetery_Coll::     INCBIN  "gfx/tilesets/cemetery.tilecoll"
-Interior_Coll::     INCBIN  "gfx/tilesets/interior.tilecoll"
-Cavern_Coll::       INCBIN  "gfx/tilesets/cavern.tilecoll"
-Lobby_Coll::        INCBIN  "gfx/tilesets/lobby.tilecoll"
-Mansion_Coll::      INCBIN  "gfx/tilesets/mansion.tilecoll"
-Lab_Coll::          INCBIN  "gfx/tilesets/lab.tilecoll"
-Club_Coll::         INCBIN  "gfx/tilesets/club.tilecoll"
-Facility_Coll::     INCBIN  "gfx/tilesets/facility.tilecoll"
-Plateau_Coll::      INCBIN  "gfx/tilesets/plateau.tilecoll"
+INCLUDE "data/collision.asm"
 
 
 FarCopyData2::
@@ -1166,783 +1143,12 @@
 
 
 INCLUDE "home/text.asm"
+INCLUDE "home/vcopy.asm"
+INCLUDE "home/init.asm"
+INCLUDE "home/vblank.asm"
+INCLUDE "home/fade.asm"
 
 
-; this function seems to be used only once
-; it store the address of a row and column of the VRAM background map in hl
-; INPUT: h - row, l - column, b - high byte of background tile map address in VRAM
-GetRowColAddressBgMap:: ; 1cdd (0:1cdd)
-	xor a
-	srl h
-	rr a
-	srl h
-	rr a
-	srl h
-	rr a
-	or l
-	ld l,a
-	ld a,b
-	or h
-	ld h,a
-	ret
-
-; clears a VRAM background map with blank space tiles
-; INPUT: h - high byte of background tile map address in VRAM
-ClearBgMap:: ; 1cf0 (0:1cf0)
-	ld a," "
-	jr .next
-	ld a,l
-.next
-	ld de,$400 ; size of VRAM background map
-	ld l,e
-.loop
-	ld [hli],a
-	dec e
-	jr nz,.loop
-	dec d
-	jr nz,.loop
-	ret
-
-; When the player takes a step, a row or column of 2x2 tile blocks at the edge
-; of the screen toward which they moved is exposed and has to be redrawn.
-; This function does the redrawing.
-RedrawExposedScreenEdge:: ; 1d01 (0:1d01)
-	ld a,[H_SCREENEDGEREDRAW]
-	and a
-	ret z
-	ld b,a
-	xor a
-	ld [H_SCREENEDGEREDRAW],a
-	dec b
-	jr nz,.redrawRow
-.redrawColumn
-	ld hl,wScreenEdgeTiles
-	ld a,[H_SCREENEDGEREDRAWADDR]
-	ld e,a
-	ld a,[H_SCREENEDGEREDRAWADDR + 1]
-	ld d,a
-	ld c,18 ; screen height
-.loop1
-	ld a,[hli]
-	ld [de],a
-	inc de
-	ld a,[hli]
-	ld [de],a
-	ld a,31
-	add e
-	ld e,a
-	jr nc,.noCarry
-	inc d
-.noCarry
-; the following 4 lines wrap us from bottom to top if necessary
-	ld a,d
-	and a,$03
-	or a,$98
-	ld d,a
-	dec c
-	jr nz,.loop1
-	xor a
-	ld [H_SCREENEDGEREDRAW],a
-	ret
-.redrawRow
-	ld hl,wScreenEdgeTiles
-	ld a,[H_SCREENEDGEREDRAWADDR]
-	ld e,a
-	ld a,[H_SCREENEDGEREDRAWADDR + 1]
-	ld d,a
-	push de
-	call .drawHalf ; draw upper half
-	pop de
-	ld a,32 ; width of VRAM background map
-	add e
-	ld e,a
-	                 ; draw lower half
-.drawHalf
-	ld c,10
-.loop2
-	ld a,[hli]
-	ld [de],a
-	inc de
-	ld a,[hli]
-	ld [de],a
-	ld a,e
-	inc a
-; the following 6 lines wrap us from the right edge to the left edge if necessary
-	and a,$1f
-	ld b,a
-	ld a,e
-	and a,$e0
-	or b
-	ld e,a
-	dec c
-	jr nz,.loop2
-	ret
-
-; This function automatically transfers tile number data from the tile map at
-; wTileMap to VRAM during V-blank. Note that it only transfers one third of the
-; background per V-blank. It cycles through which third it draws.
-; This transfer is turned off when walking around the map, but is turned
-; on when talking to sprites, battling, using menus, etc. This is because
-; the above function, RedrawExposedScreenEdge, is used when walking to
-; improve efficiency.
-AutoBgMapTransfer:: ; 1d57 (0:1d57)
-	ld a,[H_AUTOBGTRANSFERENABLED]
-	and a
-	ret z
-	ld hl,[sp + 0]
-	ld a,h
-	ld [H_SPTEMP],a
-	ld a,l
-	ld [H_SPTEMP + 1],a ; save stack pinter
-	ld a,[H_AUTOBGTRANSFERPORTION]
-	and a
-	jr z,.transferTopThird
-	dec a
-	jr z,.transferMiddleThird
-.transferBottomThird
-	FuncCoord 0,12
-	ld hl,Coord
-	ld sp,hl
-	ld a,[H_AUTOBGTRANSFERDEST + 1]
-	ld h,a
-	ld a,[H_AUTOBGTRANSFERDEST]
-	ld l,a
-	ld de,(12 * 32)
-	add hl,de
-	xor a ; TRANSFERTOP
-	jr .doTransfer
-.transferTopThird
-	FuncCoord 0,0
-	ld hl,Coord
-	ld sp,hl
-	ld a,[H_AUTOBGTRANSFERDEST + 1]
-	ld h,a
-	ld a,[H_AUTOBGTRANSFERDEST]
-	ld l,a
-	ld a,TRANSFERMIDDLE
-	jr .doTransfer
-.transferMiddleThird
-	FuncCoord 0,6
-	ld hl,Coord
-	ld sp,hl
-	ld a,[H_AUTOBGTRANSFERDEST + 1]
-	ld h,a
-	ld a,[H_AUTOBGTRANSFERDEST]
-	ld l,a
-	ld de,(6 * 32)
-	add hl,de
-	ld a,TRANSFERBOTTOM
-.doTransfer
-	ld [H_AUTOBGTRANSFERPORTION],a ; store next portion
-	ld b,6
-
-TransferBgRows:: ; 1d9e (0:1d9e)
-; unrolled loop and using pop for speed
-
-	rept 20 / 2 - 1
-	pop de
-	ld [hl], e
-	inc l
-	ld [hl], d
-	inc l
-	endr
-
-	pop de
-	ld [hl], e
-	inc l
-	ld [hl], d
-
-i	ld a, 32 - (20 - 1)
-	add l
-	ld l, a
-	jr nc, .ok
-	inc h
-.ok
-	dec b
-	jr nz, TransferBgRows
-
-	ld a, [H_SPTEMP]
-	ld h, a
-	ld a, [H_SPTEMP + 1]
-	ld l, a
-	ld sp, hl
-	ret
-
-; Copies [H_VBCOPYBGNUMROWS] rows from H_VBCOPYBGSRC to H_VBCOPYBGDEST.
-; If H_VBCOPYBGSRC is XX00, the transfer is disabled.
-VBlankCopyBgMap:: ; 1de1 (0:1de1)
-	ld a,[H_VBCOPYBGSRC] ; doubles as enabling byte
-	and a
-	ret z
-	ld hl,[sp + 0]
-	ld a,h
-	ld [H_SPTEMP],a
-	ld a,l
-	ld [H_SPTEMP + 1],a ; save stack pointer
-	ld a,[H_VBCOPYBGSRC]
-	ld l,a
-	ld a,[H_VBCOPYBGSRC + 1]
-	ld h,a
-	ld sp,hl
-	ld a,[H_VBCOPYBGDEST]
-	ld l,a
-	ld a,[H_VBCOPYBGDEST + 1]
-	ld h,a
-	ld a,[H_VBCOPYBGNUMROWS]
-	ld b,a
-	xor a
-	ld [H_VBCOPYBGSRC],a ; disable transfer so it doesn't continue next V-blank
-	jr TransferBgRows
-
-
-VBlankCopyDouble::
-; Copy [H_VBCOPYDOUBLESIZE] 1bpp tiles
-; from H_VBCOPYDOUBLESRC to H_VBCOPYDOUBLEDEST.
-
-; While we're here, convert to 2bpp.
-; The process is straightforward:
-; copy each byte twice.
-
-	ld a, [H_VBCOPYDOUBLESIZE]
-	and a
-	ret z
-
-	ld hl, [sp + 0]
-	ld a, h
-	ld [H_SPTEMP], a
-	ld a, l
-	ld [H_SPTEMP + 1], a
-
-	ld a, [H_VBCOPYDOUBLESRC]
-	ld l, a
-	ld a, [H_VBCOPYDOUBLESRC + 1]
-	ld h, a
-	ld sp, hl
-
-	ld a, [H_VBCOPYDOUBLEDEST]
-	ld l, a
-	ld a, [H_VBCOPYDOUBLEDEST + 1]
-	ld h, a
-
-	ld a, [H_VBCOPYDOUBLESIZE]
-	ld b, a
-	xor a ; transferred
-	ld [H_VBCOPYDOUBLESIZE], a
-
-.loop
-	rept 3
-	pop de
-	ld [hl], e
-	inc l
-	ld [hl], e
-	inc l
-	ld [hl], d
-	inc l
-	ld [hl], d
-	inc l
-	endr
-
-	pop de
-	ld [hl], e
-	inc l
-	ld [hl], e
-	inc l
-	ld [hl], d
-	inc l
-	ld [hl], d
-	inc hl
-	dec b
-	jr nz, .loop
-
-	ld a, l
-	ld [H_VBCOPYDOUBLEDEST], a
-	ld a, h
-	ld [H_VBCOPYDOUBLEDEST + 1], a
-
-	ld hl, [sp + 0]
-	ld a, l
-	ld [H_VBCOPYDOUBLESRC], a
-	ld a, h
-	ld [H_VBCOPYDOUBLESRC + 1], a
-
-	ld a, [H_SPTEMP]
-	ld h, a
-	ld a, [H_SPTEMP + 1]
-	ld l, a
-	ld sp, hl
-
-	ret
-
-
-VBlankCopy::
-; Copy [H_VBCOPYSIZE] 2bpp tiles
-; from H_VBCOPYSRC to H_VBCOPYDEST.
-
-; Source and destination addresses
-; are updated, so transfer can
-; continue in subsequent calls.
-
-	ld a, [H_VBCOPYSIZE]
-	and a
-	ret z
-
-	ld hl, [sp + 0]
-	ld a, h
-	ld [H_SPTEMP], a
-	ld a, l
-	ld [H_SPTEMP + 1], a
-
-	ld a, [H_VBCOPYSRC]
-	ld l, a
-	ld a, [H_VBCOPYSRC + 1]
-	ld h, a
-	ld sp, hl
-
-	ld a, [H_VBCOPYDEST]
-	ld l, a
-	ld a, [H_VBCOPYDEST + 1]
-	ld h, a
-
-	ld a, [H_VBCOPYSIZE]
-	ld b, a
-	xor a ; transferred
-	ld [H_VBCOPYSIZE], a
-
-.loop
-	rept 7
-	pop de
-	ld [hl], e
-	inc l
-	ld [hl], d
-	inc l
-	endr
-
-	pop de
-	ld [hl], e
-	inc l
-	ld [hl], d
-	inc hl
-	dec b
-	jr nz, .loop
-
-	ld a, l
-	ld [H_VBCOPYDEST], a
-	ld a, h
-	ld [H_VBCOPYDEST + 1], a
-
-	ld hl, [sp + 0]
-	ld a, l
-	ld [H_VBCOPYSRC], a
-	ld a, h
-	ld [H_VBCOPYSRC + 1], a
-
-	ld a, [H_SPTEMP]
-	ld h, a
-	ld a, [H_SPTEMP + 1]
-	ld l, a
-	ld sp, hl
-
-	ret
-
-
-UpdateMovingBgTiles::
-; Animate water and flower
-; tiles in the overworld.
-
-	ld a, [$ffd7]
-	and a
-	ret z
-
-	ld a, [$ffd8]
-	inc a
-	ld [$ffd8], a
-	cp $14
-	ret c
-	cp $15
-	jr z, .flower
-
-	ld hl, vTileset + $14 * $10
-	ld c, $10
-
-	ld a, [wd085]
-	inc a
-	and 7
-	ld [wd085], a
-
-	and 4
-	jr nz, .left
-.right
-	ld a, [hl]
-	rrca
-	ld [hli], a
-	dec c
-	jr nz, .right
-	jr .done
-.left
-	ld a, [hl]
-	rlca
-	ld [hli], a
-	dec c
-	jr nz, .left
-.done
-	ld a, [$ffd7]
-	rrca
-	ret nc
-	xor a
-	ld [$ffd8], a
-	ret
-
-.flower
-	xor a
-	ld [$ffd8], a
-
-	ld a, [wd085]
-	and 3
-	cp 2
-	ld hl, FlowerTile1
-	jr c, .copy
-	ld hl, FlowerTile2
-	jr z, .copy
-	ld hl, FlowerTile3
-.copy
-	ld de, vTileset + $3 * $10
-	ld c, $10
-.loop
-	ld a, [hli]
-	ld [de], a
-	inc de
-	dec c
-	jr nz, .loop
-	ret
-
-FlowerTile1: INCBIN "gfx/tilesets/flower/flower1.2bpp"
-FlowerTile2: INCBIN "gfx/tilesets/flower/flower2.2bpp"
-FlowerTile3: INCBIN "gfx/tilesets/flower/flower3.2bpp"
-
-
-SoftReset::
-	call StopAllSounds
-	call GBPalWhiteOut
-	ld c, $20
-	call DelayFrames
-	; fallthrough
-
-Init::
-;  Program init.
-
-rLCDC_DEFAULT EQU %11100011
-; * LCD enabled
-; * Window tile map at $9C00
-; * Window display enabled
-; * BG and window tile data at $8800
-; * BG tile map at $9800
-; * 8x8 OBJ size
-; * OBJ display enabled
-; * BG display enabled
-
-	di
-
-	xor a
-	ld [rIF], a
-	ld [rIE], a
-	ld [$ff43], a
-	ld [$ff42], a
-	ld [$ff01], a
-	ld [$ff02], a
-	ld [$ff4b], a
-	ld [$ff4a], a
-	ld [$ff06], a
-	ld [$ff07], a
-	ld [$ff47], a
-	ld [$ff48], a
-	ld [$ff49], a
-
-	ld a, rLCDC_ENABLE_MASK
-	ld [rLCDC], a
-	call DisableLCD
-
-	ld sp, wStack
-
-	ld hl, $c000 ; start of WRAM
-	ld bc, $2000 ; size of WRAM
-.loop
-	ld [hl], 0
-	inc hl
-	dec bc
-	ld a, b
-	or c
-	jr nz, .loop
-
-	call ClearVram
-
-	ld hl, $ff80
-	ld bc, $ffff - $ff80
-	call FillMemory
-
-	call ClearSprites
-
-	ld a, Bank(WriteDMACodeToHRAM)
-	ld [H_LOADEDROMBANK], a
-	ld [MBC3RomBank], a
-	call WriteDMACodeToHRAM
-
-	xor a
-	ld [$ffd7], a
-	ld [$ff41], a
-	ld [$ffae], a
-	ld [$ffaf], a
-	ld [$ff0f], a
-	ld a, 1 << VBLANK + 1 << TIMER + 1 << SERIAL
-	ld [rIE], a
-
-	ld a, 144 ; move the window off-screen
-	ld [$ffb0], a
-	ld [rWY], a
-	ld a, 7
-	ld [rWX], a
-
-	ld a, $ff
-	ld [$ffaa], a
-
-	ld h, vBGMap0 / $100
-	call ClearBgMap
-	ld h, vBGMap1 / $100
-	call ClearBgMap
-
-	ld a, rLCDC_DEFAULT
-	ld [rLCDC], a
-	ld a, 16
-	ld [hSoftReset], a
-	call StopAllSounds
-
-	ei
-
-	ld a, $40 ; PREDEF_SGB_BORDER
-	call Predef
-
-	ld a, $1f
-	ld [wc0ef], a
-	ld [wc0f0], a
-	ld a, $9c
-	ld [$ffbd], a
-	xor a
-	ld [$ffbc], a
-	dec a
-	ld [wcfcb], a
-
-	ld a, $32 ; PREDEF_INTRO
-	call Predef
-
-	call DisableLCD
-	call ClearVram
-	call GBPalNormal
-	call ClearSprites
-	ld a, rLCDC_DEFAULT
-	ld [rLCDC], a
-
-	jp SetDefaultNamesBeforeTitlescreen
-
-ClearVram:
-	ld hl, $8000
-	ld bc, $2000
-	xor a
-	jp FillMemory
-
-
-StopAllSounds::
-	ld a, Bank(Func_9876)
-	ld [wc0ef], a
-	ld [wc0f0], a
-	xor a
-	ld [wMusicHeaderPointer], a
-	ld [wc0ee], a
-	ld [wcfca], a
-	dec a
-	jp PlaySound
-
-
-VBlank::
-
-	push af
-	push bc
-	push de
-	push hl
-
-	ld a, [H_LOADEDROMBANK]
-	ld [wd122], a
-
-	ld a, [$ffae]
-	ld [rSCX], a
-	ld a, [$ffaf]
-	ld [rSCY], a
-
-	ld a, [wd0a0]
-	and a
-	jr nz, .ok
-	ld a, [$ffb0]
-	ld [rWY], a
-.ok
-
-	call AutoBgMapTransfer
-	call VBlankCopyBgMap
-	call RedrawExposedScreenEdge
-	call VBlankCopy
-	call VBlankCopyDouble
-	call UpdateMovingBgTiles
-	call $ff80 ; hOAMDMA
-	ld a, Bank(PrepareOAMData)
-	ld [H_LOADEDROMBANK], a
-	ld [MBC3RomBank], a
-	call PrepareOAMData
-
-	; VBlank-sensitive operations end.
-
-	call Random
-
-	ld a, [H_VBLANKOCCURRED]
-	and a
-	jr z, .vblanked
-	xor a
-	ld [H_VBLANKOCCURRED], a
-.vblanked
-
-	ld a, [H_FRAMECOUNTER]
-	and a
-	jr z, .decced
-	dec a
-	ld [H_FRAMECOUNTER], a
-.decced
-
-	call Func_28cb
-
-	ld a, [wc0ef] ; music ROM bank
-	ld [H_LOADEDROMBANK], a
-	ld [MBC3RomBank], a
-
-	cp BANK(Func_9103)
-	jr nz, .notbank2
-.bank2
-	call Func_9103
-	jr .afterMusic
-.notbank2
-	cp 8
-	jr nz, .bank1F
-.bank8
-	call Func_2136e
-	call Func_21879
-	jr .afterMusic
-.bank1F
-	call Func_7d177
-.afterMusic
-
-	callba Func_18dee ; keep track of time played
-
-	ld a, [$fff9]
-	and a
-	call z, ReadJoypad
-
-	ld a, [wd122]
-	ld [H_LOADEDROMBANK], a
-	ld [MBC3RomBank], a
-
-	pop hl
-	pop de
-	pop bc
-	pop af
-	reti
-
-
-DelayFrame::
-; Wait for the next vblank interrupt.
-; As a bonus, this saves battery.
-
-NOT_VBLANKED EQU 1
-
-	ld a, NOT_VBLANKED
-	ld [H_VBLANKOCCURRED], a
-.halt
-	halt
-	ld a, [H_VBLANKOCCURRED]
-	and a
-	jr nz, .halt
-	ret
-
-
-; These routines manage gradual fading
-; (e.g., entering a doorway)
-LoadGBPal::
-	ld a, [wd35d] ;tells if cur.map is dark (requires HM5_FLASH?)
-	ld b, a
-	ld hl, FadePal4
-	ld a, l
-	sub b
-	ld l, a
-	jr nc, .ok
-	dec h
-.ok
-	ld a, [hli]
-	ld [rBGP], a
-	ld a, [hli]
-	ld [rOBP0], a
-	ld a, [hli]
-	ld [rOBP1], a
-	ret
-
-GBFadeOut1::
-	ld hl, FadePal1
-	ld b, 4
-	jr GBFadeOutCommon
-
-GBFadeOut2::
-	ld hl, FadePal6
-	ld b, 3
-
-GBFadeOutCommon::
-	ld a, [hli]
-	ld [rBGP], a
-	ld a, [hli]
-	ld [rOBP0], a
-	ld a, [hli]
-	ld [rOBP1], a
-	ld c, 8
-	call DelayFrames
-	dec b
-	jr nz, GBFadeOutCommon
-	ret
-
-GBFadeIn1::
-	ld hl, FadePal4 + 2
-	ld b, 4
-	jr GBFadeInCommon
-
-GBFadeIn2::
-	ld hl, FadePal7 + 2
-	ld b, 3
-
-GBFadeInCommon::
-	ld a, [hld]
-	ld [rOBP1], a
-	ld a, [hld]
-	ld [rOBP0], a
-	ld a, [hld]
-	ld [rBGP], a
-	ld c, 8
-	call DelayFrames
-	dec b
-	jr nz, GBFadeInCommon
-	ret
-
-FadePal1:: db %11111111, %11111111, %11111111
-FadePal2:: db %11111110, %11111110, %11111000
-FadePal3:: db %11111001, %11100100, %11100100
-FadePal4:: db %11100100, %11010000, %11100000
-;                rBGP      rOBP0      rOBP1
-FadePal5:: db %11100100, %11010000, %11100000
-FadePal6:: db %10010000, %10000000, %10010000
-FadePal7:: db %01000000, %01000000, %01000000
-FadePal8:: db %00000000, %00000000, %00000000
-
-
 Serial:: ; 2125 (0:2125)
 	push af
 	push bc
@@ -2248,194 +1454,15 @@
 	ld [$ff02], a
 	ret
 
+
 ; timer interrupt is apparently not invoked anyway
 Timer:: ; 2306 (0:2306)
 	reti
 
-Func_2307:: ; 2307 (0:2307)
-	call WaitForSoundToFinish
-	xor a
-	ld c, a
-	ld d, a
-	ld [wcfca], a
-	jr asm_2324
 
-Func_2312:: ; 2312 (0:2312)
-	ld c, $a
-	ld d, $0
-	ld a, [wd72e]
-	bit 5, a
-	jr z, asm_2324
-	xor a
-	ld [wcfca], a
-	ld c, $8
-	ld d, c
-asm_2324:: ; 2324 (0:2324)
-	ld a, [wd700]
-	and a
-	jr z, .asm_2343
-	cp $2
-	jr z, .asm_2332
-	ld a, MUSIC_BIKE_RIDING
-	jr .asm_2334
-.asm_2332
-	ld a, MUSIC_SURFING
-.asm_2334
-	ld b, a
-	ld a, d
-	and a
-	ld a, Bank(Func_7d8ea)
-	jr nz, .asm_233e
-	ld [wc0ef], a
-.asm_233e
-	ld [wc0f0], a
-	jr .asm_234c
-.asm_2343
-	ld a, [wd35b]
-	ld b, a
-	call Func_2385
-	jr c, .asm_2351
-.asm_234c
-	ld a, [wcfca]
-	cp b
-	ret z
-.asm_2351
-	ld a, c
-	ld [wMusicHeaderPointer], a
-	ld a, b
-	ld [wcfca], a
-	ld [wc0ee], a
-	jp PlaySound
+INCLUDE "home/audio.asm"
 
-Func_235f:: ; 235f (0:235f)
-	ld a, [wc0ef]
-	ld b, a
-	cp $2
-	jr nz, .checkForBank08
-.bank02
-	ld hl, Func_9103
-	jr .asm_2378
-.checkForBank08
-	cp $8
-	jr nz, .bank1F
-.bank08
-	ld hl, Func_21879
-	jr .asm_2378
-.bank1F
-	ld hl, Func_7d177
-.asm_2378
-	ld c, $6
-.asm_237a
-	push bc
-	push hl
-	call Bankswitch
-	pop hl
-	pop bc
-	dec c
-	jr nz, .asm_237a
-	ret
 
-Func_2385:: ; 2385 (0:2385)
-	ld a, [wd35c]
-	ld e, a
-	ld a, [wc0ef]
-	cp e
-	jr nz, .asm_2394
-	ld [wc0f0], a
-	and a
-	ret
-.asm_2394
-	ld a, c
-	and a
-	ld a, e
-	jr nz, .asm_239c
-	ld [wc0ef], a
-.asm_239c
-	ld [wc0f0], a
-	scf
-	ret
-
-PlayMusic:: ; 23a1 (0:23a1)
-	ld b, a
-	ld [wc0ee], a
-	xor a
-	ld [wMusicHeaderPointer], a
-	ld a, c
-	ld [wc0ef], a
-	ld [wc0f0], a
-	ld a, b
-
-; plays music specified by a. If value is $ff, music is stopped
-PlaySound:: ; 23b1 (0:23b1)
-	push hl
-	push de
-	push bc
-	ld b, a
-	ld a, [wc0ee]
-	and a
-	jr z, .asm_23c8
-	xor a
-	ld [wc02a], a
-	ld [wc02b], a
-	ld [wc02c], a
-	ld [wc02d], a
-.asm_23c8
-	ld a, [wMusicHeaderPointer]
-	and a
-	jr z, .asm_23e3
-	ld a, [wc0ee]
-	and a
-	jr z, .asm_2425
-	xor a
-	ld [wc0ee], a
-	ld a, [wcfca]
-	cp $ff
-	jr nz, .asm_2414
-	xor a
-	ld [wMusicHeaderPointer], a
-.asm_23e3
-	xor a
-	ld [wc0ee], a
-	ld a, [H_LOADEDROMBANK]
-	ld [$ffb9], a
-	ld a, [wc0ef]
-	ld [H_LOADEDROMBANK], a
-	ld [$2000], a
-	cp $2
-	jr nz, .checkForBank08
-.bank02
-	ld a, b
-	call Func_9876
-	jr .asm_240b
-.checkForBank08
-	cp $8
-	jr nz, .bank1F
-.bank08
-	ld a, b
-	call Func_22035
-	jr .asm_240b
-.bank1F
-	ld a, b
-	call Func_7d8ea
-.asm_240b
-	ld a, [$ffb9]
-	ld [H_LOADEDROMBANK], a
-	ld [$2000], a
-	jr .asm_2425
-.asm_2414
-	ld a, b
-	ld [wcfca], a
-	ld a, [wMusicHeaderPointer]
-	ld [wcfc8], a
-	ld [wcfc9], a
-	ld a, b
-	ld [wMusicHeaderPointer], a
-.asm_2425
-	pop bc
-	pop de
-	pop hl
-	ret
-
 UpdateSprites:: ; 2429 (0:2429)
 	ld a, [wcfcb]
 	dec a
@@ -2486,598 +1513,10 @@
 	call Predef
 	jp TextScriptEnd
 
-; bankswitches and runs _UncompressSpriteData
-; bank is given in a, sprite input stream is pointed to in W_SPRITEINPUTPTR
-UncompressSpriteData:: ; 24fd (0:24fd)
-	ld b, a
-	ld a, [H_LOADEDROMBANK]
-	push af
-	ld a, b
-	ld [H_LOADEDROMBANK], a
-	ld [$2000], a
-	ld a, $a
-	ld [$0], a
-	xor a
-	ld [$4000], a
-	call _UncompressSpriteData
-	pop af
-	ld [H_LOADEDROMBANK], a
-	ld [$2000], a
-	ret
 
-; initializes necessary data to load a sprite and runs UncompressSpriteDataLoop
-_UncompressSpriteData:: ; 251a (0:251a)
-	ld hl, S_SPRITEBUFFER1
-	ld c, (2*SPRITEBUFFERSIZE) % $100
-	ld b, (2*SPRITEBUFFERSIZE) / $100
-	xor a
-	call FillMemory           ; clear sprite buffer 1 and 2
-	ld a, $1
-	ld [W_SPRITEINPUTBITCOUNTER], a
-	ld a, $3
-	ld [W_SPRITEOUTPUTBITOFFSET], a
-	xor a
-	ld [W_SPRITECURPOSX], a
-	ld [W_SPRITECURPOSY], a
-	ld [W_SPRITELOADFLAGS], a ; wd0a8
-	call ReadNextInputByte    ; first byte of input determines sprite width (high nybble) and height (low nybble) in tiles (8x8 pixels)
-	ld b, a
-	and $f
-	add a
-	add a
-	add a
-	ld [W_SPRITEHEIGHT], a
-	ld a, b
-	swap a
-	and $f
-	add a
-	add a
-	add a
-	ld [W_SPRITEWITDH], a
-	call ReadNextInputBit
-	ld [W_SPRITELOADFLAGS], a ; initialite bit1 to 0 and bit0 to the first input bit
-	                          ; this will load two chunks of data to S_SPRITEBUFFER1 and S_SPRITEBUFFER2
-	                          ; bit 0 decides in which one the first chunk is placed
-	; fall through
+INCLUDE "home/pic.asm"
 
-; uncompresses a chunk from the sprite input data stream (pointed to at wd0da) into S_SPRITEBUFFER1 or S_SPRITEBUFFER2
-; each chunk is a 1bpp sprite. A 2bpp sprite consist of two chunks which are merged afterwards
-; note that this is an endless loop which is terminated during a call to MoveToNextBufferPosition by manipulating the stack
-UncompressSpriteDataLoop:: ; 2556 (0:2556)
-	ld hl, S_SPRITEBUFFER1
-	ld a, [W_SPRITELOADFLAGS]  ; wd0a8
-	bit 0, a
-	jr z, .useSpriteBuffer1    ; check which buffer to use
-	ld hl, S_SPRITEBUFFER2
-.useSpriteBuffer1
-	call StoreSpriteOutputPointer
-	ld a, [W_SPRITELOADFLAGS]  ; wd0a8
-	bit 1, a
-	jr z, .startDecompression  ; check if last iteration
-	call ReadNextInputBit      ; if last chunk, read 1-2 bit unpacking mode
-	and a
-	jr z, .unpackingMode0      ; 0   -> mode 0
-	call ReadNextInputBit      ; 1 0 -> mode 1
-	inc a                      ; 1 1 -> mode 2
-.unpackingMode0
-	ld [W_SPRITEUNPACKMODE], a
-.startDecompression
-	call ReadNextInputBit
-	and a
-	jr z, .readRLEncodedZeros ; if first bit is 0, the input starts with zeroes, otherwise with (non-zero) input
-.readNextInput
-	call ReadNextInputBit
-	ld c, a
-	call ReadNextInputBit
-	sla c
-	or c                       ; read next two bits into c
-	and a
-	jr z, .readRLEncodedZeros ; 00 -> RLEncoded zeroes following
-	call WriteSpriteBitsToBuffer  ; otherwise write input to output and repeat
-	call MoveToNextBufferPosition
-	jr .readNextInput
-.readRLEncodedZeros
-	ld c, $0                   ; number of zeroes it length encoded, the number
-.countConsecutiveOnesLoop      ; of consecutive ones determines the number of bits the number has
-	call ReadNextInputBit
-	and a
-	jr z, .countConsecutiveOnesFinished
-	inc c
-	jr .countConsecutiveOnesLoop
-.countConsecutiveOnesFinished
-	ld a, c
-	add a
-	ld hl, LengthEncodingOffsetList
-	add l
-	ld l, a
-	jr nc, .noCarry
-	inc h
-.noCarry
-	ld a, [hli]                ; read offset that is added to the number later on
-	ld e, a                    ; adding an offset of 2^length - 1 makes every integer uniquely
-	ld d, [hl]                 ; representable in the length encoding and saves bits
-	push de
-	inc c
-	ld e, $0
-	ld d, e
-.readNumberOfZerosLoop        ; reads the next c+1 bits of input
-	call ReadNextInputBit
-	or e
-	ld e, a
-	dec c
-	jr z, .readNumberOfZerosDone
-	sla e
-	rl d
-	jr .readNumberOfZerosLoop
-.readNumberOfZerosDone
-	pop hl                     ; add the offset
-	add hl, de
-	ld e, l
-	ld d, h
-.writeZerosLoop
-	ld b, e
-	xor a                      ; write 00 to buffer
-	call WriteSpriteBitsToBuffer
-	ld e, b
-	call MoveToNextBufferPosition
-	dec de
-	ld a, d
-	and a
-	jr nz, .continueLoop
-	ld a, e
-	and a
-.continueLoop
-	jr nz, .writeZerosLoop
-	jr .readNextInput
 
-; moves output pointer to next position
-; also cancels the calling function if the all output is done (by removing the return pointer from stack)
-; and calls postprocessing functions according to the unpack mode
-MoveToNextBufferPosition:: ; 25d8 (0:25d8)
-	ld a, [W_SPRITEHEIGHT]
-	ld b, a
-	ld a, [W_SPRITECURPOSY]
-	inc a
-	cp b
-	jr z, .curColumnDone
-	ld [W_SPRITECURPOSY], a
-	ld a, [W_SPRITEOUTPUTPTR]
-	inc a
-	ld [W_SPRITEOUTPUTPTR], a
-	ret nz
-	ld a, [W_SPRITEOUTPUTPTR+1]
-	inc a
-	ld [W_SPRITEOUTPUTPTR+1], a
-	ret
-.curColumnDone
-	xor a
-	ld [W_SPRITECURPOSY], a
-	ld a, [W_SPRITEOUTPUTBITOFFSET]
-	and a
-	jr z, .bitOffsetsDone
-	dec a
-	ld [W_SPRITEOUTPUTBITOFFSET], a
-	ld hl, W_SPRITEOUTPUTPTRCACHED
-	ld a, [hli]
-	ld [W_SPRITEOUTPUTPTR], a
-	ld a, [hl]
-	ld [W_SPRITEOUTPUTPTR+1], a
-	ret
-.bitOffsetsDone
-	ld a, $3
-	ld [W_SPRITEOUTPUTBITOFFSET], a
-	ld a, [W_SPRITECURPOSX]
-	add $8
-	ld [W_SPRITECURPOSX], a
-	ld b, a
-	ld a, [W_SPRITEWITDH]
-	cp b
-	jr z, .allColumnsDone
-	ld a, [W_SPRITEOUTPUTPTR]
-	ld l, a
-	ld a, [W_SPRITEOUTPUTPTR+1]
-	ld h, a
-	inc hl
-	jp StoreSpriteOutputPointer
-.allColumnsDone
-	pop hl
-	xor a
-	ld [W_SPRITECURPOSX], a
-	ld a, [W_SPRITELOADFLAGS] ; wd0a8
-	bit 1, a
-	jr nz, .done            ; test if there is one more sprite to go
-	xor $1
-	set 1, a
-	ld [W_SPRITELOADFLAGS], a ; wd0a8
-	jp UncompressSpriteDataLoop
-.done
-	jp UnpackSprite
-
-; writes 2 bits (from a) to the output buffer (pointed to from W_SPRITEOUTPUTPTR)
-WriteSpriteBitsToBuffer:: ; 2649 (0:2649)
-	ld e, a
-	ld a, [W_SPRITEOUTPUTBITOFFSET]
-	and a
-	jr z, .offset0
-	cp $2
-	jr c, .offset1
-	jr z, .offset2
-	rrc e ; offset 3
-	rrc e
-	jr .offset0
-.offset1
-	sla e
-	sla e
-	jr .offset0
-.offset2
-	swap e
-.offset0
-	ld a, [W_SPRITEOUTPUTPTR]
-	ld l, a
-	ld a, [W_SPRITEOUTPUTPTR+1]
-	ld h, a
-	ld a, [hl]
-	or e
-	ld [hl], a
-	ret
-
-; reads next bit from input stream and returns it in a
-ReadNextInputBit:: ; 2670 (0:2670)
-	ld a, [W_SPRITEINPUTBITCOUNTER]
-	dec a
-	jr nz, .curByteHasMoreBitsToRead
-	call ReadNextInputByte
-	ld [W_SPRITEINPUTCURBYTE], a
-	ld a, $8
-.curByteHasMoreBitsToRead
-	ld [W_SPRITEINPUTBITCOUNTER], a
-	ld a, [W_SPRITEINPUTCURBYTE]
-	rlca
-	ld [W_SPRITEINPUTCURBYTE], a
-	and $1
-	ret
-
-; reads next byte from input stream and returns it in a
-ReadNextInputByte:: ; 268b (0:268b)
-	ld a, [W_SPRITEINPUTPTR]
-	ld l, a
-	ld a, [W_SPRITEINPUTPTR+1]
-	ld h, a
-	ld a, [hli]
-	ld b, a
-	ld a, l
-	ld [W_SPRITEINPUTPTR], a
-	ld a, h
-	ld [W_SPRITEINPUTPTR+1], a
-	ld a, b
-	ret
-
-; the nth item is 2^n - 1
-LengthEncodingOffsetList:: ; 269f (0:269f)
-	dw %0000000000000001
-	dw %0000000000000011
-	dw %0000000000000111
-	dw %0000000000001111
-	dw %0000000000011111
-	dw %0000000000111111
-	dw %0000000001111111
-	dw %0000000011111111
-	dw %0000000111111111
-	dw %0000001111111111
-	dw %0000011111111111
-	dw %0000111111111111
-	dw %0001111111111111
-	dw %0011111111111111
-	dw %0111111111111111
-	dw %1111111111111111
-
-; unpacks the sprite data depending on the unpack mode
-UnpackSprite:: ; 26bf (0:26bf)
-	ld a, [W_SPRITEUNPACKMODE]
-	cp $2
-	jp z, UnpackSpriteMode2
-	and a
-	jp nz, XorSpriteChunks
-	ld hl, S_SPRITEBUFFER1
-	call SpriteDifferentialDecode
-	ld hl, S_SPRITEBUFFER2
-	; fall through
-
-; decodes differential encoded sprite data
-; input bit value 0 preserves the current bit value and input bit value 1 toggles it (starting from initial value 0).
-SpriteDifferentialDecode:: ; 26d4 (0:26d4)
-	xor a
-	ld [W_SPRITECURPOSX], a
-	ld [W_SPRITECURPOSY], a
-	call StoreSpriteOutputPointer
-	ld a, [W_SPRITEFLIPPED]
-	and a
-	jr z, .notFlipped
-	ld hl, DecodeNybble0TableFlipped
-	ld de, DecodeNybble1TableFlipped
-	jr .storeDecodeTablesPointers
-.notFlipped
-	ld hl, DecodeNybble0Table
-	ld de, DecodeNybble1Table
-.storeDecodeTablesPointers
-	ld a, l
-	ld [W_SPRITEDECODETABLE0PTR], a
-	ld a, h
-	ld [W_SPRITEDECODETABLE0PTR+1], a
-	ld a, e
-	ld [W_SPRITEDECODETABLE1PTR], a
-	ld a, d
-	ld [W_SPRITEDECODETABLE1PTR+1], a
-	ld e, $0                          ; last decoded nybble, initialized to 0
-.decodeNextByteLoop
-	ld a, [W_SPRITEOUTPUTPTR]
-	ld l, a
-	ld a, [W_SPRITEOUTPUTPTR+1]
-	ld h, a
-	ld a, [hl]
-	ld b, a
-	swap a
-	and $f
-	call DifferentialDecodeNybble     ; decode high nybble
-	swap a
-	ld d, a
-	ld a, b
-	and $f
-	call DifferentialDecodeNybble     ; decode low nybble
-	or d
-	ld b, a
-	ld a, [W_SPRITEOUTPUTPTR]
-	ld l, a
-	ld a, [W_SPRITEOUTPUTPTR+1]
-	ld h, a
-	ld a, b
-	ld [hl], a                        ; write back decoded data
-	ld a, [W_SPRITEHEIGHT]
-	add l                             ; move on to next column
-	jr nc, .noCarry
-	inc h
-.noCarry
-	ld [W_SPRITEOUTPUTPTR], a
-	ld a, h
-	ld [W_SPRITEOUTPUTPTR+1], a
-	ld a, [W_SPRITECURPOSX]
-	add $8
-	ld [W_SPRITECURPOSX], a
-	ld b, a
-	ld a, [W_SPRITEWITDH]
-	cp b
-	jr nz, .decodeNextByteLoop        ; test if current row is done
-	xor a
-	ld e, a
-	ld [W_SPRITECURPOSX], a
-	ld a, [W_SPRITECURPOSY]           ; move on to next row
-	inc a
-	ld [W_SPRITECURPOSY], a
-	ld b, a
-	ld a, [W_SPRITEHEIGHT]
-	cp b
-	jr z, .done                       ; test if all rows finished
-	ld a, [W_SPRITEOUTPUTPTRCACHED]
-	ld l, a
-	ld a, [W_SPRITEOUTPUTPTRCACHED+1]
-	ld h, a
-	inc hl
-	call StoreSpriteOutputPointer
-	jr .decodeNextByteLoop
-.done
-	xor a
-	ld [W_SPRITECURPOSY], a
-	ret
-
-; decodes the nybble stored in a. Last decoded data is assumed to be in e (needed to determine if initial value is 0 or 1)
-DifferentialDecodeNybble:: ; 276d (0:276d)
-	srl a               ; c=a%2, a/=2
-	ld c, $0
-	jr nc, .evenNumber
-	ld c, $1
-.evenNumber
-	ld l, a
-	ld a, [W_SPRITEFLIPPED]
-	and a
-	jr z, .notFlipped     ; determine if initial value is 0 or one
-	bit 3, e              ; if flipped, consider MSB of last data
-	jr .selectLookupTable
-.notFlipped
-	bit 0, e              ; else consider LSB
-.selectLookupTable
-	ld e, l
-	jr nz, .initialValue1 ; load the appropriate table
-	ld a, [W_SPRITEDECODETABLE0PTR]
-	ld l, a
-	ld a, [W_SPRITEDECODETABLE0PTR+1]
-	jr .tableLookup
-.initialValue1
-	ld a, [W_SPRITEDECODETABLE1PTR]
-	ld l, a
-	ld a, [W_SPRITEDECODETABLE1PTR+1]
-.tableLookup
-	ld h, a
-	ld a, e
-	add l
-	ld l, a
-	jr nc, .noCarry
-	inc h
-.noCarry
-	ld a, [hl]
-	bit 0, c
-	jr nz, .selectLowNybble
-	swap a  ; select high nybble
-.selectLowNybble
-	and $f
-	ld e, a ; update last decoded data
-	ret
-
-DecodeNybble0Table:: ; 27a7 (0:27a7)
-	dn $0, $1
-	dn $3, $2
-	dn $7, $6
-	dn $4, $5
-	dn $f, $e
-	dn $c, $d
-	dn $8, $9
-	dn $b, $a
-DecodeNybble1Table:: ; 27af (0:27af)
-	dn $f, $e
-	dn $c, $d
-	dn $8, $9
-	dn $b, $a
-	dn $0, $1
-	dn $3, $2
-	dn $7, $6
-	dn $4, $5
-DecodeNybble0TableFlipped:: ; 27b7 (0:27b7)
-	dn $0, $8
-	dn $c, $4
-	dn $e, $6
-	dn $2, $a
-	dn $f, $7
-	dn $3, $b
-	dn $1, $9
-	dn $d, $5
-DecodeNybble1TableFlipped:: ; 27bf (0:27bf)
-	dn $f, $7
-	dn $3, $b
-	dn $1, $9
-	dn $d, $5
-	dn $0, $8
-	dn $c, $4
-	dn $e, $6
-	dn $2, $a
-
-; combines the two loaded chunks with xor (the chunk loaded second is the destination). The source chunk is differeintial decoded beforehand.
-XorSpriteChunks:: ; 27c7 (0:27c7)
-	xor a
-	ld [W_SPRITECURPOSX], a
-	ld [W_SPRITECURPOSY], a
-	call ResetSpriteBufferPointers
-	ld a, [W_SPRITEOUTPUTPTR]          ; points to buffer 1 or 2, depending on flags
-	ld l, a
-	ld a, [W_SPRITEOUTPUTPTR+1]
-	ld h, a
-	call SpriteDifferentialDecode      ; decode buffer 1 or 2, depending on flags
-	call ResetSpriteBufferPointers
-	ld a, [W_SPRITEOUTPUTPTR]          ; source buffer, points to buffer 1 or 2, depending on flags
-	ld l, a
-	ld a, [W_SPRITEOUTPUTPTR+1]
-	ld h, a
-	ld a, [W_SPRITEOUTPUTPTRCACHED]    ; destination buffer, points to buffer 2 or 1, depending on flags
-	ld e, a
-	ld a, [W_SPRITEOUTPUTPTRCACHED+1]
-	ld d, a
-.xorChunksLoop
-	ld a, [W_SPRITEFLIPPED]
-	and a
-	jr z, .notFlipped
-	push de
-	ld a, [de]
-	ld b, a
-	swap a
-	and $f
-	call ReverseNybble                 ; if flipped reverse the nybbles in the destination buffer
-	swap a
-	ld c, a
-	ld a, b
-	and $f
-	call ReverseNybble
-	or c
-	pop de
-	ld [de], a
-.notFlipped
-	ld a, [hli]
-	ld b, a
-	ld a, [de]
-	xor b
-	ld [de], a
-	inc de
-	ld a, [W_SPRITECURPOSY]
-	inc a
-	ld [W_SPRITECURPOSY], a             ; go to next row
-	ld b, a
-	ld a, [W_SPRITEHEIGHT]
-	cp b
-	jr nz, .xorChunksLoop               ; test if column finished
-	xor a
-	ld [W_SPRITECURPOSY], a
-	ld a, [W_SPRITECURPOSX]
-	add $8
-	ld [W_SPRITECURPOSX], a             ; go to next column
-	ld b, a
-	ld a, [W_SPRITEWITDH]
-	cp b
-	jr nz, .xorChunksLoop               ; test if all columns finished
-	xor a
-	ld [W_SPRITECURPOSX], a
-	ret
-
-; reverses the bits in the nybble given in register a
-ReverseNybble:: ; 2837 (0:2837)
-	ld de, NybbleReverseTable
-	add e
-	ld e, a
-	jr nc, .asm_283f
-	inc d
-.asm_283f
-	ld a, [de]
-	ret
-
-; resets sprite buffer pointers to buffer 1 and 2, depending on W_SPRITELOADFLAGS
-ResetSpriteBufferPointers:: ; 2841 (0:2841)
-	ld a, [W_SPRITELOADFLAGS] ; wd0a8
-	bit 0, a
-	jr nz, .buffer2Selected
-	ld de, S_SPRITEBUFFER1
-	ld hl, S_SPRITEBUFFER2
-	jr .storeBufferPointers
-.buffer2Selected
-	ld de, S_SPRITEBUFFER2
-	ld hl, S_SPRITEBUFFER1
-.storeBufferPointers
-	ld a, l
-	ld [W_SPRITEOUTPUTPTR], a
-	ld a, h
-	ld [W_SPRITEOUTPUTPTR+1], a
-	ld a, e
-	ld [W_SPRITEOUTPUTPTRCACHED], a
-	ld a, d
-	ld [W_SPRITEOUTPUTPTRCACHED+1], a
-	ret
-
-; maps each nybble to its reverse
-NybbleReverseTable:: ; 2867 (0:2867)
-	db $0, $8, $4, $c, $2, $a, $6 ,$e, $1, $9, $5, $d, $3, $b, $7 ,$f
-
-; combines the two loaded chunks with xor (the chunk loaded second is the destination). Both chunks are differeintial decoded beforehand.
-UnpackSpriteMode2:: ; 2877 (0:2877)
-	call ResetSpriteBufferPointers
-	ld a, [W_SPRITEFLIPPED]
-	push af
-	xor a
-	ld [W_SPRITEFLIPPED], a            ; temporarily clear flipped flag for decoding the destination chunk
-	ld a, [W_SPRITEOUTPUTPTRCACHED]
-	ld l, a
-	ld a, [W_SPRITEOUTPUTPTRCACHED+1]
-	ld h, a
-	call SpriteDifferentialDecode
-	call ResetSpriteBufferPointers
-	pop af
-	ld [W_SPRITEFLIPPED], a
-	jp XorSpriteChunks
-
-; stores hl into the output pointers
-StoreSpriteOutputPointer:: ; 2897 (0:2897)
-	ld a, l
-	ld [W_SPRITEOUTPUTPTR], a
-	ld [W_SPRITEOUTPUTPTRCACHED], a
-	ld a, h
-	ld [W_SPRITEOUTPUTPTR+1], a
-	ld [W_SPRITEOUTPUTPTRCACHED+1], a
-	ret
-
 ResetPlayerSpriteData:: ; 28a6 (0:28a6)
 	ld hl, wSpriteStateData1
 	call ResetPlayerSpriteData_ClearSpriteData
@@ -6721,56 +5160,7 @@
 	ret
 
 
-Predef::
-; Call predefined function a.
-; To preserve other registers, have the
-; destination call GetPredefRegisters.
-
-	; Save the predef id for GetPredefPointer.
-	ld [wPredefID], a
-
-	; A hack for LoadDestinationWarpPosition.
-	; See Func_c754 (predef $19).
-	ld a, [H_LOADEDROMBANK]
-	ld [wPredefParentBank], a
-
-	push af
-	ld a, BANK(GetPredefPointer)
-	ld [H_LOADEDROMBANK], a
-	ld [$2000], a
-
-	call GetPredefPointer
-
-	ld a, [wPredefBank]
-	ld [H_LOADEDROMBANK], a
-	ld [$2000], a
-
-	ld de, .done
-	push de
-	jp [hl]
-.done
-
-	pop af
-	ld [H_LOADEDROMBANK], a
-	ld [$2000], a
-	ret
-
-GetPredefRegisters::
-; Restore the contents of register pairs
-; when GetPredefPointer was called.
-	ld a, [wPredefRegisters + 0]
-	ld h, a
-	ld a, [wPredefRegisters + 1]
-	ld l, a
-	ld a, [wPredefRegisters + 2]
-	ld d, a
-	ld a, [wPredefRegisters + 3]
-	ld e, a
-	ld a, [wPredefRegisters + 4]
-	ld b, a
-	ld a, [wPredefRegisters + 5]
-	ld c, a
-	ret
+INCLUDE "home/predef.asm"
 
 
 Func_3ead:: ; 3ead (0:3ead)
--- /dev/null
+++ b/home/audio.asm
@@ -1,0 +1,183 @@
+Func_2307:: ; 2307 (0:2307)
+	call WaitForSoundToFinish
+	xor a
+	ld c, a
+	ld d, a
+	ld [wcfca], a
+	jr asm_2324
+
+Func_2312:: ; 2312 (0:2312)
+	ld c, $a
+	ld d, $0
+	ld a, [wd72e]
+	bit 5, a
+	jr z, asm_2324
+	xor a
+	ld [wcfca], a
+	ld c, $8
+	ld d, c
+asm_2324:: ; 2324 (0:2324)
+	ld a, [wd700]
+	and a
+	jr z, .asm_2343
+	cp $2
+	jr z, .asm_2332
+	ld a, MUSIC_BIKE_RIDING
+	jr .asm_2334
+.asm_2332
+	ld a, MUSIC_SURFING
+.asm_2334
+	ld b, a
+	ld a, d
+	and a
+	ld a, Bank(Func_7d8ea)
+	jr nz, .asm_233e
+	ld [wc0ef], a
+.asm_233e
+	ld [wc0f0], a
+	jr .asm_234c
+.asm_2343
+	ld a, [wd35b]
+	ld b, a
+	call Func_2385
+	jr c, .asm_2351
+.asm_234c
+	ld a, [wcfca]
+	cp b
+	ret z
+.asm_2351
+	ld a, c
+	ld [wMusicHeaderPointer], a
+	ld a, b
+	ld [wcfca], a
+	ld [wc0ee], a
+	jp PlaySound
+
+Func_235f:: ; 235f (0:235f)
+	ld a, [wc0ef]
+	ld b, a
+	cp $2
+	jr nz, .checkForBank08
+.bank02
+	ld hl, Func_9103
+	jr .asm_2378
+.checkForBank08
+	cp $8
+	jr nz, .bank1F
+.bank08
+	ld hl, Func_21879
+	jr .asm_2378
+.bank1F
+	ld hl, Func_7d177
+.asm_2378
+	ld c, $6
+.asm_237a
+	push bc
+	push hl
+	call Bankswitch
+	pop hl
+	pop bc
+	dec c
+	jr nz, .asm_237a
+	ret
+
+Func_2385:: ; 2385 (0:2385)
+	ld a, [wd35c]
+	ld e, a
+	ld a, [wc0ef]
+	cp e
+	jr nz, .asm_2394
+	ld [wc0f0], a
+	and a
+	ret
+.asm_2394
+	ld a, c
+	and a
+	ld a, e
+	jr nz, .asm_239c
+	ld [wc0ef], a
+.asm_239c
+	ld [wc0f0], a
+	scf
+	ret
+
+PlayMusic:: ; 23a1 (0:23a1)
+	ld b, a
+	ld [wc0ee], a
+	xor a
+	ld [wMusicHeaderPointer], a
+	ld a, c
+	ld [wc0ef], a
+	ld [wc0f0], a
+	ld a, b
+
+; plays music specified by a. If value is $ff, music is stopped
+PlaySound:: ; 23b1 (0:23b1)
+	push hl
+	push de
+	push bc
+	ld b, a
+	ld a, [wc0ee]
+	and a
+	jr z, .asm_23c8
+	xor a
+	ld [wc02a], a
+	ld [wc02b], a
+	ld [wc02c], a
+	ld [wc02d], a
+.asm_23c8
+	ld a, [wMusicHeaderPointer]
+	and a
+	jr z, .asm_23e3
+	ld a, [wc0ee]
+	and a
+	jr z, .asm_2425
+	xor a
+	ld [wc0ee], a
+	ld a, [wcfca]
+	cp $ff
+	jr nz, .asm_2414
+	xor a
+	ld [wMusicHeaderPointer], a
+.asm_23e3
+	xor a
+	ld [wc0ee], a
+	ld a, [H_LOADEDROMBANK]
+	ld [$ffb9], a
+	ld a, [wc0ef]
+	ld [H_LOADEDROMBANK], a
+	ld [$2000], a
+	cp $2
+	jr nz, .checkForBank08
+.bank02
+	ld a, b
+	call Func_9876
+	jr .asm_240b
+.checkForBank08
+	cp $8
+	jr nz, .bank1F
+.bank08
+	ld a, b
+	call Func_22035
+	jr .asm_240b
+.bank1F
+	ld a, b
+	call Func_7d8ea
+.asm_240b
+	ld a, [$ffb9]
+	ld [H_LOADEDROMBANK], a
+	ld [$2000], a
+	jr .asm_2425
+.asm_2414
+	ld a, b
+	ld [wcfca], a
+	ld a, [wMusicHeaderPointer]
+	ld [wcfc8], a
+	ld [wcfc9], a
+	ld a, b
+	ld [wMusicHeaderPointer], a
+.asm_2425
+	pop bc
+	pop de
+	pop hl
+	ret
--- /dev/null
+++ b/home/fade.asm
@@ -1,0 +1,73 @@
+; These routines manage gradual fading
+; (e.g., entering a doorway)
+LoadGBPal::
+	ld a, [wd35d] ;tells if cur.map is dark (requires HM5_FLASH?)
+	ld b, a
+	ld hl, FadePal4
+	ld a, l
+	sub b
+	ld l, a
+	jr nc, .ok
+	dec h
+.ok
+	ld a, [hli]
+	ld [rBGP], a
+	ld a, [hli]
+	ld [rOBP0], a
+	ld a, [hli]
+	ld [rOBP1], a
+	ret
+
+GBFadeOut1::
+	ld hl, FadePal1
+	ld b, 4
+	jr GBFadeOutCommon
+
+GBFadeOut2::
+	ld hl, FadePal6
+	ld b, 3
+
+GBFadeOutCommon::
+	ld a, [hli]
+	ld [rBGP], a
+	ld a, [hli]
+	ld [rOBP0], a
+	ld a, [hli]
+	ld [rOBP1], a
+	ld c, 8
+	call DelayFrames
+	dec b
+	jr nz, GBFadeOutCommon
+	ret
+
+GBFadeIn1::
+	ld hl, FadePal4 + 2
+	ld b, 4
+	jr GBFadeInCommon
+
+GBFadeIn2::
+	ld hl, FadePal7 + 2
+	ld b, 3
+
+GBFadeInCommon::
+	ld a, [hld]
+	ld [rOBP1], a
+	ld a, [hld]
+	ld [rOBP0], a
+	ld a, [hld]
+	ld [rBGP], a
+	ld c, 8
+	call DelayFrames
+	dec b
+	jr nz, GBFadeInCommon
+	ret
+
+FadePal1:: db %11111111, %11111111, %11111111
+FadePal2:: db %11111110, %11111110, %11111000
+FadePal3:: db %11111001, %11100100, %11100100
+FadePal4:: db %11100100, %11010000, %11100000
+;                rBGP      rOBP0      rOBP1
+FadePal5:: db %11100100, %11010000, %11100000
+FadePal6:: db %10010000, %10000000, %10010000
+FadePal7:: db %01000000, %01000000, %01000000
+FadePal8:: db %00000000, %00000000, %00000000
--- /dev/null
+++ b/home/init.asm
@@ -1,0 +1,139 @@
+SoftReset::
+	call StopAllSounds
+	call GBPalWhiteOut
+	ld c, $20
+	call DelayFrames
+	; fallthrough
+
+Init::
+;  Program init.
+
+rLCDC_DEFAULT EQU %11100011
+; * LCD enabled
+; * Window tile map at $9C00
+; * Window display enabled
+; * BG and window tile data at $8800
+; * BG tile map at $9800
+; * 8x8 OBJ size
+; * OBJ display enabled
+; * BG display enabled
+
+	di
+
+	xor a
+	ld [rIF], a
+	ld [rIE], a
+	ld [$ff43], a
+	ld [$ff42], a
+	ld [$ff01], a
+	ld [$ff02], a
+	ld [$ff4b], a
+	ld [$ff4a], a
+	ld [$ff06], a
+	ld [$ff07], a
+	ld [$ff47], a
+	ld [$ff48], a
+	ld [$ff49], a
+
+	ld a, rLCDC_ENABLE_MASK
+	ld [rLCDC], a
+	call DisableLCD
+
+	ld sp, wStack
+
+	ld hl, $c000 ; start of WRAM
+	ld bc, $2000 ; size of WRAM
+.loop
+	ld [hl], 0
+	inc hl
+	dec bc
+	ld a, b
+	or c
+	jr nz, .loop
+
+	call ClearVram
+
+	ld hl, $ff80
+	ld bc, $ffff - $ff80
+	call FillMemory
+
+	call ClearSprites
+
+	ld a, Bank(WriteDMACodeToHRAM)
+	ld [H_LOADEDROMBANK], a
+	ld [MBC3RomBank], a
+	call WriteDMACodeToHRAM
+
+	xor a
+	ld [$ffd7], a
+	ld [$ff41], a
+	ld [$ffae], a
+	ld [$ffaf], a
+	ld [$ff0f], a
+	ld a, 1 << VBLANK + 1 << TIMER + 1 << SERIAL
+	ld [rIE], a
+
+	ld a, 144 ; move the window off-screen
+	ld [$ffb0], a
+	ld [rWY], a
+	ld a, 7
+	ld [rWX], a
+
+	ld a, $ff
+	ld [$ffaa], a
+
+	ld h, vBGMap0 / $100
+	call ClearBgMap
+	ld h, vBGMap1 / $100
+	call ClearBgMap
+
+	ld a, rLCDC_DEFAULT
+	ld [rLCDC], a
+	ld a, 16
+	ld [hSoftReset], a
+	call StopAllSounds
+
+	ei
+
+	ld a, $40 ; PREDEF_SGB_BORDER
+	call Predef
+
+	ld a, $1f
+	ld [wc0ef], a
+	ld [wc0f0], a
+	ld a, $9c
+	ld [$ffbd], a
+	xor a
+	ld [$ffbc], a
+	dec a
+	ld [wcfcb], a
+
+	ld a, $32 ; PREDEF_INTRO
+	call Predef
+
+	call DisableLCD
+	call ClearVram
+	call GBPalNormal
+	call ClearSprites
+	ld a, rLCDC_DEFAULT
+	ld [rLCDC], a
+
+	jp SetDefaultNamesBeforeTitlescreen
+
+ClearVram:
+	ld hl, $8000
+	ld bc, $2000
+	xor a
+	jp FillMemory
+
+
+StopAllSounds::
+	ld a, Bank(Func_9876)
+	ld [wc0ef], a
+	ld [wc0f0], a
+	xor a
+	ld [wMusicHeaderPointer], a
+	ld [wc0ee], a
+	ld [wcfca], a
+	dec a
+	jp PlaySound
--- /dev/null
+++ b/home/pic.asm
@@ -1,0 +1,591 @@
+; bankswitches and runs _UncompressSpriteData
+; bank is given in a, sprite input stream is pointed to in W_SPRITEINPUTPTR
+UncompressSpriteData:: ; 24fd (0:24fd)
+	ld b, a
+	ld a, [H_LOADEDROMBANK]
+	push af
+	ld a, b
+	ld [H_LOADEDROMBANK], a
+	ld [$2000], a
+	ld a, $a
+	ld [$0], a
+	xor a
+	ld [$4000], a
+	call _UncompressSpriteData
+	pop af
+	ld [H_LOADEDROMBANK], a
+	ld [$2000], a
+	ret
+
+; initializes necessary data to load a sprite and runs UncompressSpriteDataLoop
+_UncompressSpriteData:: ; 251a (0:251a)
+	ld hl, S_SPRITEBUFFER1
+	ld c, (2*SPRITEBUFFERSIZE) % $100
+	ld b, (2*SPRITEBUFFERSIZE) / $100
+	xor a
+	call FillMemory           ; clear sprite buffer 1 and 2
+	ld a, $1
+	ld [W_SPRITEINPUTBITCOUNTER], a
+	ld a, $3
+	ld [W_SPRITEOUTPUTBITOFFSET], a
+	xor a
+	ld [W_SPRITECURPOSX], a
+	ld [W_SPRITECURPOSY], a
+	ld [W_SPRITELOADFLAGS], a ; wd0a8
+	call ReadNextInputByte    ; first byte of input determines sprite width (high nybble) and height (low nybble) in tiles (8x8 pixels)
+	ld b, a
+	and $f
+	add a
+	add a
+	add a
+	ld [W_SPRITEHEIGHT], a
+	ld a, b
+	swap a
+	and $f
+	add a
+	add a
+	add a
+	ld [W_SPRITEWITDH], a
+	call ReadNextInputBit
+	ld [W_SPRITELOADFLAGS], a ; initialite bit1 to 0 and bit0 to the first input bit
+				  ; this will load two chunks of data to S_SPRITEBUFFER1 and S_SPRITEBUFFER2
+				  ; bit 0 decides in which one the first chunk is placed
+	; fall through
+
+; uncompresses a chunk from the sprite input data stream (pointed to at wd0da) into S_SPRITEBUFFER1 or S_SPRITEBUFFER2
+; each chunk is a 1bpp sprite. A 2bpp sprite consist of two chunks which are merged afterwards
+; note that this is an endless loop which is terminated during a call to MoveToNextBufferPosition by manipulating the stack
+UncompressSpriteDataLoop:: ; 2556 (0:2556)
+	ld hl, S_SPRITEBUFFER1
+	ld a, [W_SPRITELOADFLAGS]  ; wd0a8
+	bit 0, a
+	jr z, .useSpriteBuffer1    ; check which buffer to use
+	ld hl, S_SPRITEBUFFER2
+.useSpriteBuffer1
+	call StoreSpriteOutputPointer
+	ld a, [W_SPRITELOADFLAGS]  ; wd0a8
+	bit 1, a
+	jr z, .startDecompression  ; check if last iteration
+	call ReadNextInputBit      ; if last chunk, read 1-2 bit unpacking mode
+	and a
+	jr z, .unpackingMode0      ; 0   -> mode 0
+	call ReadNextInputBit      ; 1 0 -> mode 1
+	inc a                      ; 1 1 -> mode 2
+.unpackingMode0
+	ld [W_SPRITEUNPACKMODE], a
+.startDecompression
+	call ReadNextInputBit
+	and a
+	jr z, .readRLEncodedZeros ; if first bit is 0, the input starts with zeroes, otherwise with (non-zero) input
+.readNextInput
+	call ReadNextInputBit
+	ld c, a
+	call ReadNextInputBit
+	sla c
+	or c                       ; read next two bits into c
+	and a
+	jr z, .readRLEncodedZeros ; 00 -> RLEncoded zeroes following
+	call WriteSpriteBitsToBuffer  ; otherwise write input to output and repeat
+	call MoveToNextBufferPosition
+	jr .readNextInput
+.readRLEncodedZeros
+	ld c, $0                   ; number of zeroes it length encoded, the number
+.countConsecutiveOnesLoop      ; of consecutive ones determines the number of bits the number has
+	call ReadNextInputBit
+	and a
+	jr z, .countConsecutiveOnesFinished
+	inc c
+	jr .countConsecutiveOnesLoop
+.countConsecutiveOnesFinished
+	ld a, c
+	add a
+	ld hl, LengthEncodingOffsetList
+	add l
+	ld l, a
+	jr nc, .noCarry
+	inc h
+.noCarry
+	ld a, [hli]                ; read offset that is added to the number later on
+	ld e, a                    ; adding an offset of 2^length - 1 makes every integer uniquely
+	ld d, [hl]                 ; representable in the length encoding and saves bits
+	push de
+	inc c
+	ld e, $0
+	ld d, e
+.readNumberOfZerosLoop        ; reads the next c+1 bits of input
+	call ReadNextInputBit
+	or e
+	ld e, a
+	dec c
+	jr z, .readNumberOfZerosDone
+	sla e
+	rl d
+	jr .readNumberOfZerosLoop
+.readNumberOfZerosDone
+	pop hl                     ; add the offset
+	add hl, de
+	ld e, l
+	ld d, h
+.writeZerosLoop
+	ld b, e
+	xor a                      ; write 00 to buffer
+	call WriteSpriteBitsToBuffer
+	ld e, b
+	call MoveToNextBufferPosition
+	dec de
+	ld a, d
+	and a
+	jr nz, .continueLoop
+	ld a, e
+	and a
+.continueLoop
+	jr nz, .writeZerosLoop
+	jr .readNextInput
+
+; moves output pointer to next position
+; also cancels the calling function if the all output is done (by removing the return pointer from stack)
+; and calls postprocessing functions according to the unpack mode
+MoveToNextBufferPosition:: ; 25d8 (0:25d8)
+	ld a, [W_SPRITEHEIGHT]
+	ld b, a
+	ld a, [W_SPRITECURPOSY]
+	inc a
+	cp b
+	jr z, .curColumnDone
+	ld [W_SPRITECURPOSY], a
+	ld a, [W_SPRITEOUTPUTPTR]
+	inc a
+	ld [W_SPRITEOUTPUTPTR], a
+	ret nz
+	ld a, [W_SPRITEOUTPUTPTR+1]
+	inc a
+	ld [W_SPRITEOUTPUTPTR+1], a
+	ret
+.curColumnDone
+	xor a
+	ld [W_SPRITECURPOSY], a
+	ld a, [W_SPRITEOUTPUTBITOFFSET]
+	and a
+	jr z, .bitOffsetsDone
+	dec a
+	ld [W_SPRITEOUTPUTBITOFFSET], a
+	ld hl, W_SPRITEOUTPUTPTRCACHED
+	ld a, [hli]
+	ld [W_SPRITEOUTPUTPTR], a
+	ld a, [hl]
+	ld [W_SPRITEOUTPUTPTR+1], a
+	ret
+.bitOffsetsDone
+	ld a, $3
+	ld [W_SPRITEOUTPUTBITOFFSET], a
+	ld a, [W_SPRITECURPOSX]
+	add $8
+	ld [W_SPRITECURPOSX], a
+	ld b, a
+	ld a, [W_SPRITEWITDH]
+	cp b
+	jr z, .allColumnsDone
+	ld a, [W_SPRITEOUTPUTPTR]
+	ld l, a
+	ld a, [W_SPRITEOUTPUTPTR+1]
+	ld h, a
+	inc hl
+	jp StoreSpriteOutputPointer
+.allColumnsDone
+	pop hl
+	xor a
+	ld [W_SPRITECURPOSX], a
+	ld a, [W_SPRITELOADFLAGS] ; wd0a8
+	bit 1, a
+	jr nz, .done            ; test if there is one more sprite to go
+	xor $1
+	set 1, a
+	ld [W_SPRITELOADFLAGS], a ; wd0a8
+	jp UncompressSpriteDataLoop
+.done
+	jp UnpackSprite
+
+; writes 2 bits (from a) to the output buffer (pointed to from W_SPRITEOUTPUTPTR)
+WriteSpriteBitsToBuffer:: ; 2649 (0:2649)
+	ld e, a
+	ld a, [W_SPRITEOUTPUTBITOFFSET]
+	and a
+	jr z, .offset0
+	cp $2
+	jr c, .offset1
+	jr z, .offset2
+	rrc e ; offset 3
+	rrc e
+	jr .offset0
+.offset1
+	sla e
+	sla e
+	jr .offset0
+.offset2
+	swap e
+.offset0
+	ld a, [W_SPRITEOUTPUTPTR]
+	ld l, a
+	ld a, [W_SPRITEOUTPUTPTR+1]
+	ld h, a
+	ld a, [hl]
+	or e
+	ld [hl], a
+	ret
+
+; reads next bit from input stream and returns it in a
+ReadNextInputBit:: ; 2670 (0:2670)
+	ld a, [W_SPRITEINPUTBITCOUNTER]
+	dec a
+	jr nz, .curByteHasMoreBitsToRead
+	call ReadNextInputByte
+	ld [W_SPRITEINPUTCURBYTE], a
+	ld a, $8
+.curByteHasMoreBitsToRead
+	ld [W_SPRITEINPUTBITCOUNTER], a
+	ld a, [W_SPRITEINPUTCURBYTE]
+	rlca
+	ld [W_SPRITEINPUTCURBYTE], a
+	and $1
+	ret
+
+; reads next byte from input stream and returns it in a
+ReadNextInputByte:: ; 268b (0:268b)
+	ld a, [W_SPRITEINPUTPTR]
+	ld l, a
+	ld a, [W_SPRITEINPUTPTR+1]
+	ld h, a
+	ld a, [hli]
+	ld b, a
+	ld a, l
+	ld [W_SPRITEINPUTPTR], a
+	ld a, h
+	ld [W_SPRITEINPUTPTR+1], a
+	ld a, b
+	ret
+
+; the nth item is 2^n - 1
+LengthEncodingOffsetList:: ; 269f (0:269f)
+	dw %0000000000000001
+	dw %0000000000000011
+	dw %0000000000000111
+	dw %0000000000001111
+	dw %0000000000011111
+	dw %0000000000111111
+	dw %0000000001111111
+	dw %0000000011111111
+	dw %0000000111111111
+	dw %0000001111111111
+	dw %0000011111111111
+	dw %0000111111111111
+	dw %0001111111111111
+	dw %0011111111111111
+	dw %0111111111111111
+	dw %1111111111111111
+
+; unpacks the sprite data depending on the unpack mode
+UnpackSprite:: ; 26bf (0:26bf)
+	ld a, [W_SPRITEUNPACKMODE]
+	cp $2
+	jp z, UnpackSpriteMode2
+	and a
+	jp nz, XorSpriteChunks
+	ld hl, S_SPRITEBUFFER1
+	call SpriteDifferentialDecode
+	ld hl, S_SPRITEBUFFER2
+	; fall through
+
+; decodes differential encoded sprite data
+; input bit value 0 preserves the current bit value and input bit value 1 toggles it (starting from initial value 0).
+SpriteDifferentialDecode:: ; 26d4 (0:26d4)
+	xor a
+	ld [W_SPRITECURPOSX], a
+	ld [W_SPRITECURPOSY], a
+	call StoreSpriteOutputPointer
+	ld a, [W_SPRITEFLIPPED]
+	and a
+	jr z, .notFlipped
+	ld hl, DecodeNybble0TableFlipped
+	ld de, DecodeNybble1TableFlipped
+	jr .storeDecodeTablesPointers
+.notFlipped
+	ld hl, DecodeNybble0Table
+	ld de, DecodeNybble1Table
+.storeDecodeTablesPointers
+	ld a, l
+	ld [W_SPRITEDECODETABLE0PTR], a
+	ld a, h
+	ld [W_SPRITEDECODETABLE0PTR+1], a
+	ld a, e
+	ld [W_SPRITEDECODETABLE1PTR], a
+	ld a, d
+	ld [W_SPRITEDECODETABLE1PTR+1], a
+	ld e, $0                          ; last decoded nybble, initialized to 0
+.decodeNextByteLoop
+	ld a, [W_SPRITEOUTPUTPTR]
+	ld l, a
+	ld a, [W_SPRITEOUTPUTPTR+1]
+	ld h, a
+	ld a, [hl]
+	ld b, a
+	swap a
+	and $f
+	call DifferentialDecodeNybble     ; decode high nybble
+	swap a
+	ld d, a
+	ld a, b
+	and $f
+	call DifferentialDecodeNybble     ; decode low nybble
+	or d
+	ld b, a
+	ld a, [W_SPRITEOUTPUTPTR]
+	ld l, a
+	ld a, [W_SPRITEOUTPUTPTR+1]
+	ld h, a
+	ld a, b
+	ld [hl], a                        ; write back decoded data
+	ld a, [W_SPRITEHEIGHT]
+	add l                             ; move on to next column
+	jr nc, .noCarry
+	inc h
+.noCarry
+	ld [W_SPRITEOUTPUTPTR], a
+	ld a, h
+	ld [W_SPRITEOUTPUTPTR+1], a
+	ld a, [W_SPRITECURPOSX]
+	add $8
+	ld [W_SPRITECURPOSX], a
+	ld b, a
+	ld a, [W_SPRITEWITDH]
+	cp b
+	jr nz, .decodeNextByteLoop        ; test if current row is done
+	xor a
+	ld e, a
+	ld [W_SPRITECURPOSX], a
+	ld a, [W_SPRITECURPOSY]           ; move on to next row
+	inc a
+	ld [W_SPRITECURPOSY], a
+	ld b, a
+	ld a, [W_SPRITEHEIGHT]
+	cp b
+	jr z, .done                       ; test if all rows finished
+	ld a, [W_SPRITEOUTPUTPTRCACHED]
+	ld l, a
+	ld a, [W_SPRITEOUTPUTPTRCACHED+1]
+	ld h, a
+	inc hl
+	call StoreSpriteOutputPointer
+	jr .decodeNextByteLoop
+.done
+	xor a
+	ld [W_SPRITECURPOSY], a
+	ret
+
+; decodes the nybble stored in a. Last decoded data is assumed to be in e (needed to determine if initial value is 0 or 1)
+DifferentialDecodeNybble:: ; 276d (0:276d)
+	srl a               ; c=a%2, a/=2
+	ld c, $0
+	jr nc, .evenNumber
+	ld c, $1
+.evenNumber
+	ld l, a
+	ld a, [W_SPRITEFLIPPED]
+	and a
+	jr z, .notFlipped     ; determine if initial value is 0 or one
+	bit 3, e              ; if flipped, consider MSB of last data
+	jr .selectLookupTable
+.notFlipped
+	bit 0, e              ; else consider LSB
+.selectLookupTable
+	ld e, l
+	jr nz, .initialValue1 ; load the appropriate table
+	ld a, [W_SPRITEDECODETABLE0PTR]
+	ld l, a
+	ld a, [W_SPRITEDECODETABLE0PTR+1]
+	jr .tableLookup
+.initialValue1
+	ld a, [W_SPRITEDECODETABLE1PTR]
+	ld l, a
+	ld a, [W_SPRITEDECODETABLE1PTR+1]
+.tableLookup
+	ld h, a
+	ld a, e
+	add l
+	ld l, a
+	jr nc, .noCarry
+	inc h
+.noCarry
+	ld a, [hl]
+	bit 0, c
+	jr nz, .selectLowNybble
+	swap a  ; select high nybble
+.selectLowNybble
+	and $f
+	ld e, a ; update last decoded data
+	ret
+
+DecodeNybble0Table:: ; 27a7 (0:27a7)
+	dn $0, $1
+	dn $3, $2
+	dn $7, $6
+	dn $4, $5
+	dn $f, $e
+	dn $c, $d
+	dn $8, $9
+	dn $b, $a
+DecodeNybble1Table:: ; 27af (0:27af)
+	dn $f, $e
+	dn $c, $d
+	dn $8, $9
+	dn $b, $a
+	dn $0, $1
+	dn $3, $2
+	dn $7, $6
+	dn $4, $5
+DecodeNybble0TableFlipped:: ; 27b7 (0:27b7)
+	dn $0, $8
+	dn $c, $4
+	dn $e, $6
+	dn $2, $a
+	dn $f, $7
+	dn $3, $b
+	dn $1, $9
+	dn $d, $5
+DecodeNybble1TableFlipped:: ; 27bf (0:27bf)
+	dn $f, $7
+	dn $3, $b
+	dn $1, $9
+	dn $d, $5
+	dn $0, $8
+	dn $c, $4
+	dn $e, $6
+	dn $2, $a
+
+; combines the two loaded chunks with xor (the chunk loaded second is the destination). The source chunk is differeintial decoded beforehand.
+XorSpriteChunks:: ; 27c7 (0:27c7)
+	xor a
+	ld [W_SPRITECURPOSX], a
+	ld [W_SPRITECURPOSY], a
+	call ResetSpriteBufferPointers
+	ld a, [W_SPRITEOUTPUTPTR]          ; points to buffer 1 or 2, depending on flags
+	ld l, a
+	ld a, [W_SPRITEOUTPUTPTR+1]
+	ld h, a
+	call SpriteDifferentialDecode      ; decode buffer 1 or 2, depending on flags
+	call ResetSpriteBufferPointers
+	ld a, [W_SPRITEOUTPUTPTR]          ; source buffer, points to buffer 1 or 2, depending on flags
+	ld l, a
+	ld a, [W_SPRITEOUTPUTPTR+1]
+	ld h, a
+	ld a, [W_SPRITEOUTPUTPTRCACHED]    ; destination buffer, points to buffer 2 or 1, depending on flags
+	ld e, a
+	ld a, [W_SPRITEOUTPUTPTRCACHED+1]
+	ld d, a
+.xorChunksLoop
+	ld a, [W_SPRITEFLIPPED]
+	and a
+	jr z, .notFlipped
+	push de
+	ld a, [de]
+	ld b, a
+	swap a
+	and $f
+	call ReverseNybble                 ; if flipped reverse the nybbles in the destination buffer
+	swap a
+	ld c, a
+	ld a, b
+	and $f
+	call ReverseNybble
+	or c
+	pop de
+	ld [de], a
+.notFlipped
+	ld a, [hli]
+	ld b, a
+	ld a, [de]
+	xor b
+	ld [de], a
+	inc de
+	ld a, [W_SPRITECURPOSY]
+	inc a
+	ld [W_SPRITECURPOSY], a             ; go to next row
+	ld b, a
+	ld a, [W_SPRITEHEIGHT]
+	cp b
+	jr nz, .xorChunksLoop               ; test if column finished
+	xor a
+	ld [W_SPRITECURPOSY], a
+	ld a, [W_SPRITECURPOSX]
+	add $8
+	ld [W_SPRITECURPOSX], a             ; go to next column
+	ld b, a
+	ld a, [W_SPRITEWITDH]
+	cp b
+	jr nz, .xorChunksLoop               ; test if all columns finished
+	xor a
+	ld [W_SPRITECURPOSX], a
+	ret
+
+; reverses the bits in the nybble given in register a
+ReverseNybble:: ; 2837 (0:2837)
+	ld de, NybbleReverseTable
+	add e
+	ld e, a
+	jr nc, .asm_283f
+	inc d
+.asm_283f
+	ld a, [de]
+	ret
+
+; resets sprite buffer pointers to buffer 1 and 2, depending on W_SPRITELOADFLAGS
+ResetSpriteBufferPointers:: ; 2841 (0:2841)
+	ld a, [W_SPRITELOADFLAGS] ; wd0a8
+	bit 0, a
+	jr nz, .buffer2Selected
+	ld de, S_SPRITEBUFFER1
+	ld hl, S_SPRITEBUFFER2
+	jr .storeBufferPointers
+.buffer2Selected
+	ld de, S_SPRITEBUFFER2
+	ld hl, S_SPRITEBUFFER1
+.storeBufferPointers
+	ld a, l
+	ld [W_SPRITEOUTPUTPTR], a
+	ld a, h
+	ld [W_SPRITEOUTPUTPTR+1], a
+	ld a, e
+	ld [W_SPRITEOUTPUTPTRCACHED], a
+	ld a, d
+	ld [W_SPRITEOUTPUTPTRCACHED+1], a
+	ret
+
+; maps each nybble to its reverse
+NybbleReverseTable:: ; 2867 (0:2867)
+	db $0, $8, $4, $c, $2, $a, $6 ,$e, $1, $9, $5, $d, $3, $b, $7 ,$f
+
+; combines the two loaded chunks with xor (the chunk loaded second is the destination). Both chunks are differeintial decoded beforehand.
+UnpackSpriteMode2:: ; 2877 (0:2877)
+	call ResetSpriteBufferPointers
+	ld a, [W_SPRITEFLIPPED]
+	push af
+	xor a
+	ld [W_SPRITEFLIPPED], a            ; temporarily clear flipped flag for decoding the destination chunk
+	ld a, [W_SPRITEOUTPUTPTRCACHED]
+	ld l, a
+	ld a, [W_SPRITEOUTPUTPTRCACHED+1]
+	ld h, a
+	call SpriteDifferentialDecode
+	call ResetSpriteBufferPointers
+	pop af
+	ld [W_SPRITEFLIPPED], a
+	jp XorSpriteChunks
+
+; stores hl into the output pointers
+StoreSpriteOutputPointer:: ; 2897 (0:2897)
+	ld a, l
+	ld [W_SPRITEOUTPUTPTR], a
+	ld [W_SPRITEOUTPUTPTRCACHED], a
+	ld a, h
+	ld [W_SPRITEOUTPUTPTR+1], a
+	ld [W_SPRITEOUTPUTPTRCACHED+1], a
+	ret
--- /dev/null
+++ b/home/predef.asm
@@ -1,0 +1,50 @@
+Predef::
+; Call predefined function a.
+; To preserve other registers, have the
+; destination call GetPredefRegisters.
+
+	; Save the predef id for GetPredefPointer.
+	ld [wPredefID], a
+
+	; A hack for LoadDestinationWarpPosition.
+	; See Func_c754 (predef $19).
+	ld a, [H_LOADEDROMBANK]
+	ld [wPredefParentBank], a
+
+	push af
+	ld a, BANK(GetPredefPointer)
+	ld [H_LOADEDROMBANK], a
+	ld [$2000], a
+
+	call GetPredefPointer
+
+	ld a, [wPredefBank]
+	ld [H_LOADEDROMBANK], a
+	ld [$2000], a
+
+	ld de, .done
+	push de
+	jp [hl]
+.done
+
+	pop af
+	ld [H_LOADEDROMBANK], a
+	ld [$2000], a
+	ret
+
+GetPredefRegisters::
+; Restore the contents of register pairs
+; when GetPredefPointer was called.
+	ld a, [wPredefRegisters + 0]
+	ld h, a
+	ld a, [wPredefRegisters + 1]
+	ld l, a
+	ld a, [wPredefRegisters + 2]
+	ld d, a
+	ld a, [wPredefRegisters + 3]
+	ld e, a
+	ld a, [wPredefRegisters + 4]
+	ld b, a
+	ld a, [wPredefRegisters + 5]
+	ld c, a
+	ret
--- /dev/null
+++ b/home/vblank.asm
@@ -1,0 +1,105 @@
+VBlank::
+
+	push af
+	push bc
+	push de
+	push hl
+
+	ld a, [H_LOADEDROMBANK]
+	ld [wd122], a
+
+	ld a, [$ffae]
+	ld [rSCX], a
+	ld a, [$ffaf]
+	ld [rSCY], a
+
+	ld a, [wd0a0]
+	and a
+	jr nz, .ok
+	ld a, [$ffb0]
+	ld [rWY], a
+.ok
+
+	call AutoBgMapTransfer
+	call VBlankCopyBgMap
+	call RedrawExposedScreenEdge
+	call VBlankCopy
+	call VBlankCopyDouble
+	call UpdateMovingBgTiles
+	call $ff80 ; hOAMDMA
+	ld a, Bank(PrepareOAMData)
+	ld [H_LOADEDROMBANK], a
+	ld [MBC3RomBank], a
+	call PrepareOAMData
+
+	; VBlank-sensitive operations end.
+
+	call Random
+
+	ld a, [H_VBLANKOCCURRED]
+	and a
+	jr z, .vblanked
+	xor a
+	ld [H_VBLANKOCCURRED], a
+.vblanked
+
+	ld a, [H_FRAMECOUNTER]
+	and a
+	jr z, .decced
+	dec a
+	ld [H_FRAMECOUNTER], a
+.decced
+
+	call Func_28cb
+
+	ld a, [wc0ef] ; music ROM bank
+	ld [H_LOADEDROMBANK], a
+	ld [MBC3RomBank], a
+
+	cp BANK(Func_9103)
+	jr nz, .notbank2
+.bank2
+	call Func_9103
+	jr .afterMusic
+.notbank2
+	cp 8
+	jr nz, .bank1F
+.bank8
+	call Func_2136e
+	call Func_21879
+	jr .afterMusic
+.bank1F
+	call Func_7d177
+.afterMusic
+
+	callba Func_18dee ; keep track of time played
+
+	ld a, [$fff9]
+	and a
+	call z, ReadJoypad
+
+	ld a, [wd122]
+	ld [H_LOADEDROMBANK], a
+	ld [MBC3RomBank], a
+
+	pop hl
+	pop de
+	pop bc
+	pop af
+	reti
+
+
+DelayFrame::
+; Wait for the next vblank interrupt.
+; As a bonus, this saves battery.
+
+NOT_VBLANKED EQU 1
+
+	ld a, NOT_VBLANKED
+	ld [H_VBLANKOCCURRED], a
+.halt
+	halt
+	ld a, [H_VBLANKOCCURRED]
+	and a
+	jr nz, .halt
+	ret
--- /dev/null
+++ b/home/vcopy.asm
@@ -1,0 +1,450 @@
+; this function seems to be used only once
+; it store the address of a row and column of the VRAM background map in hl
+; INPUT: h - row, l - column, b - high byte of background tile map address in VRAM
+GetRowColAddressBgMap:: ; 1cdd (0:1cdd)
+	xor a
+	srl h
+	rr a
+	srl h
+	rr a
+	srl h
+	rr a
+	or l
+	ld l,a
+	ld a,b
+	or h
+	ld h,a
+	ret
+
+; clears a VRAM background map with blank space tiles
+; INPUT: h - high byte of background tile map address in VRAM
+ClearBgMap:: ; 1cf0 (0:1cf0)
+	ld a," "
+	jr .next
+	ld a,l
+.next
+	ld de,$400 ; size of VRAM background map
+	ld l,e
+.loop
+	ld [hli],a
+	dec e
+	jr nz,.loop
+	dec d
+	jr nz,.loop
+	ret
+
+; When the player takes a step, a row or column of 2x2 tile blocks at the edge
+; of the screen toward which they moved is exposed and has to be redrawn.
+; This function does the redrawing.
+RedrawExposedScreenEdge:: ; 1d01 (0:1d01)
+	ld a,[H_SCREENEDGEREDRAW]
+	and a
+	ret z
+	ld b,a
+	xor a
+	ld [H_SCREENEDGEREDRAW],a
+	dec b
+	jr nz,.redrawRow
+.redrawColumn
+	ld hl,wScreenEdgeTiles
+	ld a,[H_SCREENEDGEREDRAWADDR]
+	ld e,a
+	ld a,[H_SCREENEDGEREDRAWADDR + 1]
+	ld d,a
+	ld c,18 ; screen height
+.loop1
+	ld a,[hli]
+	ld [de],a
+	inc de
+	ld a,[hli]
+	ld [de],a
+	ld a,31
+	add e
+	ld e,a
+	jr nc,.noCarry
+	inc d
+.noCarry
+; the following 4 lines wrap us from bottom to top if necessary
+	ld a,d
+	and a,$03
+	or a,$98
+	ld d,a
+	dec c
+	jr nz,.loop1
+	xor a
+	ld [H_SCREENEDGEREDRAW],a
+	ret
+.redrawRow
+	ld hl,wScreenEdgeTiles
+	ld a,[H_SCREENEDGEREDRAWADDR]
+	ld e,a
+	ld a,[H_SCREENEDGEREDRAWADDR + 1]
+	ld d,a
+	push de
+	call .drawHalf ; draw upper half
+	pop de
+	ld a,32 ; width of VRAM background map
+	add e
+	ld e,a
+			 ; draw lower half
+.drawHalf
+	ld c,10
+.loop2
+	ld a,[hli]
+	ld [de],a
+	inc de
+	ld a,[hli]
+	ld [de],a
+	ld a,e
+	inc a
+; the following 6 lines wrap us from the right edge to the left edge if necessary
+	and a,$1f
+	ld b,a
+	ld a,e
+	and a,$e0
+	or b
+	ld e,a
+	dec c
+	jr nz,.loop2
+	ret
+
+; This function automatically transfers tile number data from the tile map at
+; wTileMap to VRAM during V-blank. Note that it only transfers one third of the
+; background per V-blank. It cycles through which third it draws.
+; This transfer is turned off when walking around the map, but is turned
+; on when talking to sprites, battling, using menus, etc. This is because
+; the above function, RedrawExposedScreenEdge, is used when walking to
+; improve efficiency.
+AutoBgMapTransfer:: ; 1d57 (0:1d57)
+	ld a,[H_AUTOBGTRANSFERENABLED]
+	and a
+	ret z
+	ld hl,[sp + 0]
+	ld a,h
+	ld [H_SPTEMP],a
+	ld a,l
+	ld [H_SPTEMP + 1],a ; save stack pinter
+	ld a,[H_AUTOBGTRANSFERPORTION]
+	and a
+	jr z,.transferTopThird
+	dec a
+	jr z,.transferMiddleThird
+.transferBottomThird
+	FuncCoord 0,12
+	ld hl,Coord
+	ld sp,hl
+	ld a,[H_AUTOBGTRANSFERDEST + 1]
+	ld h,a
+	ld a,[H_AUTOBGTRANSFERDEST]
+	ld l,a
+	ld de,(12 * 32)
+	add hl,de
+	xor a ; TRANSFERTOP
+	jr .doTransfer
+.transferTopThird
+	FuncCoord 0,0
+	ld hl,Coord
+	ld sp,hl
+	ld a,[H_AUTOBGTRANSFERDEST + 1]
+	ld h,a
+	ld a,[H_AUTOBGTRANSFERDEST]
+	ld l,a
+	ld a,TRANSFERMIDDLE
+	jr .doTransfer
+.transferMiddleThird
+	FuncCoord 0,6
+	ld hl,Coord
+	ld sp,hl
+	ld a,[H_AUTOBGTRANSFERDEST + 1]
+	ld h,a
+	ld a,[H_AUTOBGTRANSFERDEST]
+	ld l,a
+	ld de,(6 * 32)
+	add hl,de
+	ld a,TRANSFERBOTTOM
+.doTransfer
+	ld [H_AUTOBGTRANSFERPORTION],a ; store next portion
+	ld b,6
+
+TransferBgRows:: ; 1d9e (0:1d9e)
+; unrolled loop and using pop for speed
+
+	rept 20 / 2 - 1
+	pop de
+	ld [hl], e
+	inc l
+	ld [hl], d
+	inc l
+	endr
+
+	pop de
+	ld [hl], e
+	inc l
+	ld [hl], d
+
+i	ld a, 32 - (20 - 1)
+	add l
+	ld l, a
+	jr nc, .ok
+	inc h
+.ok
+	dec b
+	jr nz, TransferBgRows
+
+	ld a, [H_SPTEMP]
+	ld h, a
+	ld a, [H_SPTEMP + 1]
+	ld l, a
+	ld sp, hl
+	ret
+
+; Copies [H_VBCOPYBGNUMROWS] rows from H_VBCOPYBGSRC to H_VBCOPYBGDEST.
+; If H_VBCOPYBGSRC is XX00, the transfer is disabled.
+VBlankCopyBgMap:: ; 1de1 (0:1de1)
+	ld a,[H_VBCOPYBGSRC] ; doubles as enabling byte
+	and a
+	ret z
+	ld hl,[sp + 0]
+	ld a,h
+	ld [H_SPTEMP],a
+	ld a,l
+	ld [H_SPTEMP + 1],a ; save stack pointer
+	ld a,[H_VBCOPYBGSRC]
+	ld l,a
+	ld a,[H_VBCOPYBGSRC + 1]
+	ld h,a
+	ld sp,hl
+	ld a,[H_VBCOPYBGDEST]
+	ld l,a
+	ld a,[H_VBCOPYBGDEST + 1]
+	ld h,a
+	ld a,[H_VBCOPYBGNUMROWS]
+	ld b,a
+	xor a
+	ld [H_VBCOPYBGSRC],a ; disable transfer so it doesn't continue next V-blank
+	jr TransferBgRows
+
+
+VBlankCopyDouble::
+; Copy [H_VBCOPYDOUBLESIZE] 1bpp tiles
+; from H_VBCOPYDOUBLESRC to H_VBCOPYDOUBLEDEST.
+
+; While we're here, convert to 2bpp.
+; The process is straightforward:
+; copy each byte twice.
+
+	ld a, [H_VBCOPYDOUBLESIZE]
+	and a
+	ret z
+
+	ld hl, [sp + 0]
+	ld a, h
+	ld [H_SPTEMP], a
+	ld a, l
+	ld [H_SPTEMP + 1], a
+
+	ld a, [H_VBCOPYDOUBLESRC]
+	ld l, a
+	ld a, [H_VBCOPYDOUBLESRC + 1]
+	ld h, a
+	ld sp, hl
+
+	ld a, [H_VBCOPYDOUBLEDEST]
+	ld l, a
+	ld a, [H_VBCOPYDOUBLEDEST + 1]
+	ld h, a
+
+	ld a, [H_VBCOPYDOUBLESIZE]
+	ld b, a
+	xor a ; transferred
+	ld [H_VBCOPYDOUBLESIZE], a
+
+.loop
+	rept 3
+	pop de
+	ld [hl], e
+	inc l
+	ld [hl], e
+	inc l
+	ld [hl], d
+	inc l
+	ld [hl], d
+	inc l
+	endr
+
+	pop de
+	ld [hl], e
+	inc l
+	ld [hl], e
+	inc l
+	ld [hl], d
+	inc l
+	ld [hl], d
+	inc hl
+	dec b
+	jr nz, .loop
+
+	ld a, l
+	ld [H_VBCOPYDOUBLEDEST], a
+	ld a, h
+	ld [H_VBCOPYDOUBLEDEST + 1], a
+
+	ld hl, [sp + 0]
+	ld a, l
+	ld [H_VBCOPYDOUBLESRC], a
+	ld a, h
+	ld [H_VBCOPYDOUBLESRC + 1], a
+
+	ld a, [H_SPTEMP]
+	ld h, a
+	ld a, [H_SPTEMP + 1]
+	ld l, a
+	ld sp, hl
+
+	ret
+
+
+VBlankCopy::
+; Copy [H_VBCOPYSIZE] 2bpp tiles
+; from H_VBCOPYSRC to H_VBCOPYDEST.
+
+; Source and destination addresses
+; are updated, so transfer can
+; continue in subsequent calls.
+
+	ld a, [H_VBCOPYSIZE]
+	and a
+	ret z
+
+	ld hl, [sp + 0]
+	ld a, h
+	ld [H_SPTEMP], a
+	ld a, l
+	ld [H_SPTEMP + 1], a
+
+	ld a, [H_VBCOPYSRC]
+	ld l, a
+	ld a, [H_VBCOPYSRC + 1]
+	ld h, a
+	ld sp, hl
+
+	ld a, [H_VBCOPYDEST]
+	ld l, a
+	ld a, [H_VBCOPYDEST + 1]
+	ld h, a
+
+	ld a, [H_VBCOPYSIZE]
+	ld b, a
+	xor a ; transferred
+	ld [H_VBCOPYSIZE], a
+
+.loop
+	rept 7
+	pop de
+	ld [hl], e
+	inc l
+	ld [hl], d
+	inc l
+	endr
+
+	pop de
+	ld [hl], e
+	inc l
+	ld [hl], d
+	inc hl
+	dec b
+	jr nz, .loop
+
+	ld a, l
+	ld [H_VBCOPYDEST], a
+	ld a, h
+	ld [H_VBCOPYDEST + 1], a
+
+	ld hl, [sp + 0]
+	ld a, l
+	ld [H_VBCOPYSRC], a
+	ld a, h
+	ld [H_VBCOPYSRC + 1], a
+
+	ld a, [H_SPTEMP]
+	ld h, a
+	ld a, [H_SPTEMP + 1]
+	ld l, a
+	ld sp, hl
+
+	ret
+
+
+UpdateMovingBgTiles::
+; Animate water and flower
+; tiles in the overworld.
+
+	ld a, [$ffd7]
+	and a
+	ret z
+
+	ld a, [$ffd8]
+	inc a
+	ld [$ffd8], a
+	cp $14
+	ret c
+	cp $15
+	jr z, .flower
+
+	ld hl, vTileset + $14 * $10
+	ld c, $10
+
+	ld a, [wd085]
+	inc a
+	and 7
+	ld [wd085], a
+
+	and 4
+	jr nz, .left
+.right
+	ld a, [hl]
+	rrca
+	ld [hli], a
+	dec c
+	jr nz, .right
+	jr .done
+.left
+	ld a, [hl]
+	rlca
+	ld [hli], a
+	dec c
+	jr nz, .left
+.done
+	ld a, [$ffd7]
+	rrca
+	ret nc
+	xor a
+	ld [$ffd8], a
+	ret
+
+.flower
+	xor a
+	ld [$ffd8], a
+
+	ld a, [wd085]
+	and 3
+	cp 2
+	ld hl, FlowerTile1
+	jr c, .copy
+	ld hl, FlowerTile2
+	jr z, .copy
+	ld hl, FlowerTile3
+.copy
+	ld de, vTileset + $3 * $10
+	ld c, $10
+.loop
+	ld a, [hli]
+	ld [de], a
+	inc de
+	dec c
+	jr nz, .loop
+	ret
+
+FlowerTile1: INCBIN "gfx/tilesets/flower/flower1.2bpp"
+FlowerTile2: INCBIN "gfx/tilesets/flower/flower2.2bpp"
+FlowerTile3: INCBIN "gfx/tilesets/flower/flower3.2bpp"