summaryrefslogtreecommitdiff
path: root/engine/gfx
diff options
context:
space:
mode:
authormid-kid <esteve.varela@gmail.com>2018-03-13 13:07:16 +0100
committermid-kid <esteve.varela@gmail.com>2018-03-13 13:21:40 +0100
commitbaa0dc5a963a79843b37888bcfe1d2dfe833ade9 (patch)
tree968c86105bd67a3121d8f3f20018bfc59191f4c9 /engine/gfx
parent12070ca50067d3abe36a730190f88ee43f2cace9 (diff)
Organize the engine/ directory
This is an informed attempt at reorganizing the engine/ directory by creating categorized subdirectories, in order to make it easier to navigate and find things. The directories created are as follows: * engine/game: Contains all "minigames", things like the unown puzzle and slot machine. * engine/gfx: Contains all handling of graphics. From loading palettes to playing animations. * engine/link: Contains all multiplayer functionality. * engine/menu: Contains all generic/misc. menus and menu code. Other, more specialized menus are in their own subdirectories (pokedex, pokegear, party menu, etc). * engine/overworld: Contains all handling of the overworld. From loading and connecting maps to wild encounters and the scripting engine. * engine/pokegear: In the same vein as engine/pokedex, except it could use some more splitting up. * engine/pokemon: Contains everything related to manipulating pokemon data. From the pokemon storage system to evolution and mail. * engine/printer: Contains everything related to printing things as well as the printer communication. * engine/title: Contains intro sequences, title screens and credits.
Diffstat (limited to 'engine/gfx')
-rw-r--r--engine/gfx/cgb_layouts.asm1033
-rw-r--r--engine/gfx/color.asm1356
-rwxr-xr-xengine/gfx/crystal_layouts.asm325
-rwxr-xr-xengine/gfx/evolution_animation.asm368
-rw-r--r--engine/gfx/gbc_only.asm149
-rw-r--r--engine/gfx/load_font.asm156
-rwxr-xr-xengine/gfx/load_pics.asm491
-rw-r--r--engine/gfx/map_palettes.asm86
-rw-r--r--engine/gfx/mapgroup_roofs.asm20
-rwxr-xr-xengine/gfx/mon_icons.asm471
-rw-r--r--engine/gfx/pic_animation.asm1141
-rw-r--r--engine/gfx/player_gfx.asm224
-rw-r--r--engine/gfx/sgb_layouts.asm605
-rwxr-xr-xengine/gfx/sprite_anims.asm889
-rwxr-xr-xengine/gfx/sprites.asm677
-rw-r--r--engine/gfx/tileset_anims.asm1060
-rw-r--r--engine/gfx/tileset_palettes.asm151
-rw-r--r--engine/gfx/timeofdaypals.asm415
-rwxr-xr-xengine/gfx/trade_animation.asm1646
19 files changed, 11263 insertions, 0 deletions
diff --git a/engine/gfx/cgb_layouts.asm b/engine/gfx/cgb_layouts.asm
new file mode 100644
index 000000000..b36dceeb6
--- /dev/null
+++ b/engine/gfx/cgb_layouts.asm
@@ -0,0 +1,1033 @@
+; Replaces the functionality of sgb.asm to work with CGB hardware.
+
+CheckCGB: ; 8d55
+ ld a, [hCGB]
+ and a
+ ret
+; 8d59
+
+LoadSGBLayoutCGB: ; 8d59
+ ld a, b
+ cp SCGB_RAM
+ jr nz, .not_ram
+ ld a, [wSGBPredef]
+.not_ram
+ cp SCGB_PARTY_MENU_HP_PALS
+ jp z, CGB_ApplyPartyMenuHPPals
+ call ResetBGPals
+ ld l, a
+ ld h, 0
+ add hl, hl
+ ld de, .dw
+ add hl, de
+ ld a, [hli]
+ ld h, [hl]
+ ld l, a
+ ld de, .ReturnFromJumpTable
+ push de
+ jp hl
+; 8d79
+
+.ReturnFromJumpTable: ; 8d79
+ ret
+; 8d7a
+
+.dw ; 8d7a
+ dw _CGB_BattleGrayscale
+ dw _CGB_BattleColors
+ dw _CGB_PokegearPals
+ dw _CGB_StatsScreenHPPals
+ dw _CGB_Pokedex
+ dw _CGB_SlotMachine
+ dw _CGB06
+ dw _CGB_GSIntro
+ dw _CGB_Diploma
+ dw _CGB_MapPals
+ dw _CGB_PartyMenu
+ dw _CGB_Evolution
+ dw _CGB_GSTitleScreen
+ dw _CGB0d
+ dw _CGB_MoveList
+ dw _CGB0f
+ dw _CGB_PokedexSearchOption
+ dw _CGB11
+ dw _CGB_Pokepic
+ dw _CGB13
+ dw _CGB_PackPals
+ dw _CGB_TrainerCard
+ dw _CGB_PokedexUnownMode
+ dw _CGB_BillsPC
+ dw _CGB_UnownPuzzle
+ dw _CGB_GamefreakLogo
+ dw _CGB_PlayerOrMonFrontpicPals
+ dw _CGB_TradeTube
+ dw _CGB_TrainerOrMonFrontpicPals
+ dw _CGB_MysteryGift
+ dw _CGB1e
+; 8db8
+
+_CGB_BattleGrayscale: ; 8db8
+ ld hl, PalPacket_BattleGrayscale + 1
+ ld de, wBGPals1
+ ld c, 4
+ call CopyPalettes
+ ld hl, PalPacket_BattleGrayscale + 1
+ ld de, wBGPals1 palette PAL_BATTLE_BG_EXP
+ ld c, 4
+ call CopyPalettes
+ ld hl, PalPacket_BattleGrayscale + 1
+ ld de, wOBPals1
+ ld c, 2
+ call CopyPalettes
+ jr _CGB_FinishBattleScreenLayout
+
+_CGB_BattleColors: ; 8ddb
+ ld de, wBGPals1
+ call GetBattlemonBackpicPalettePointer
+ push hl
+ call LoadPalette_White_Col1_Col2_Black ; PAL_BATTLE_BG_PLAYER
+ call GetEnemyFrontpicPalettePointer
+ push hl
+ call LoadPalette_White_Col1_Col2_Black ; PAL_BATTLE_BG_ENEMY
+ ld a, [wEnemyHPPal]
+ ld l, a
+ ld h, $0
+ add hl, hl
+ add hl, hl
+ ld bc, HPBarPals
+ add hl, bc
+ call LoadPalette_White_Col1_Col2_Black ; PAL_BATTLE_BG_ENEMY_HP
+ ld a, [wPlayerHPPal]
+ ld l, a
+ ld h, $0
+ add hl, hl
+ add hl, hl
+ ld bc, HPBarPals
+ add hl, bc
+ call LoadPalette_White_Col1_Col2_Black ; PAL_BATTLE_BG_PLAYER_HP
+ ld hl, ExpBarPalette
+ call LoadPalette_White_Col1_Col2_Black ; PAL_BATTLE_BG_EXP
+ ld de, wOBPals1
+ pop hl
+ call LoadPalette_White_Col1_Col2_Black ; PAL_BATTLE_OB_ENEMY
+ pop hl
+ call LoadPalette_White_Col1_Col2_Black ; PAL_BATTLE_OB_PLAYER
+ ld a, SCGB_BATTLE_COLORS
+ ld [wSGBPredef], a
+ call ApplyPals
+_CGB_FinishBattleScreenLayout: ; 8e23
+ call InitPartyMenuBGPal7
+ hlcoord 0, 0, wAttrMap
+ ld bc, SCREEN_WIDTH * SCREEN_HEIGHT
+ ld a, PAL_BATTLE_BG_ENEMY_HP
+ call ByteFill
+ hlcoord 0, 4, wAttrMap
+ lb bc, 8, 10
+ ld a, PAL_BATTLE_BG_PLAYER
+ call FillBoxCGB
+ hlcoord 10, 0, wAttrMap
+ lb bc, 7, 10
+ ld a, PAL_BATTLE_BG_ENEMY
+ call FillBoxCGB
+ hlcoord 0, 0, wAttrMap
+ lb bc, 4, 10
+ ld a, PAL_BATTLE_BG_ENEMY_HP
+ call FillBoxCGB
+ hlcoord 10, 7, wAttrMap
+ lb bc, 5, 10
+ ld a, PAL_BATTLE_BG_PLAYER_HP
+ call FillBoxCGB
+ hlcoord 10, 11, wAttrMap
+ lb bc, 1, 9
+ ld a, PAL_BATTLE_BG_EXP
+ call FillBoxCGB
+ hlcoord 0, 12, wAttrMap
+ ld bc, 6 * SCREEN_WIDTH
+ ld a, PAL_BATTLE_BG_TEXT
+ call ByteFill
+ ld hl, BattleObjectPals
+ ld de, wOBPals1 palette PAL_BATTLE_OB_GRAY
+ ld bc, 6 palettes
+ ld a, BANK(wOBPals1)
+ call FarCopyWRAM
+ call ApplyAttrMap
+ ret
+; 8e85
+
+
+InitPartyMenuBGPal7: ; 8e85
+ farcall Function100dc0
+Mobile_InitPartyMenuBGPal7: ; 8e8b
+ ld hl, PartyMenuBGPalette
+ jr nc, .not_mobile
+ ld hl, PartyMenuBGMobilePalette
+.not_mobile
+ ld de, wBGPals1 palette 7
+ ld bc, 1 palettes
+ ld a, BANK(wBGPals1)
+ call FarCopyWRAM
+ ret
+; 8e9f
+
+InitPartyMenuBGPal0: ; 8e9f
+ farcall Function100dc0
+ ld hl, PartyMenuBGPalette
+ jr nc, .not_mobile
+ ld hl, PartyMenuBGMobilePalette
+.not_mobile
+ ld de, wBGPals1 palette 0
+ ld bc, 1 palettes
+ ld a, BANK(wBGPals1)
+ call FarCopyWRAM
+ ret
+; 8eb9
+
+_CGB_PokegearPals: ; 8eb9
+ ld a, [wPlayerGender]
+ bit PLAYERGENDER_FEMALE_F, a
+ jr z, .male
+ ld hl, FemalePokegearPals
+ jr .got_pals
+
+.male
+ ld hl, MalePokegearPals
+.got_pals
+ ld de, wBGPals1
+ ld bc, 6 palettes
+ ld a, BANK(wBGPals1)
+ call FarCopyWRAM
+ call ApplyPals
+ ld a, $1
+ ld [hCGBPalUpdate], a
+ ret
+; 8edb
+
+_CGB_StatsScreenHPPals: ; 8edb
+ ld de, wBGPals1
+ ld a, [wCurHPPal]
+ ld l, a
+ ld h, $0
+ add hl, hl
+ add hl, hl
+ ld bc, HPBarPals
+ add hl, bc
+ call LoadPalette_White_Col1_Col2_Black ; hp palette
+ ld a, [wCurPartySpecies]
+ ld bc, wTempMonDVs
+ call GetPlayerOrMonPalettePointer
+ call LoadPalette_White_Col1_Col2_Black ; mon palette
+ ld hl, ExpBarPalette
+ call LoadPalette_White_Col1_Col2_Black ; exp palette
+ ld hl, StatsScreenPagePals
+ ld de, wBGPals1 palette 3
+ ld bc, 3 palettes ; pink, green, and blue page palettes
+ ld a, BANK(wBGPals1)
+ call FarCopyWRAM
+ call WipeAttrMap
+
+ hlcoord 0, 0, wAttrMap
+ lb bc, 8, SCREEN_WIDTH
+ ld a, $1 ; mon palette
+ call FillBoxCGB
+
+ hlcoord 10, 16, wAttrMap
+ ld bc, 10
+ ld a, $2 ; exp palette
+ call ByteFill
+
+ hlcoord 13, 5, wAttrMap
+ lb bc, 2, 2
+ ld a, $3 ; pink page palette
+ call FillBoxCGB
+
+ hlcoord 15, 5, wAttrMap
+ lb bc, 2, 2
+ ld a, $4 ; green page palette
+ call FillBoxCGB
+
+ hlcoord 17, 5, wAttrMap
+ lb bc, 2, 2
+ ld a, $5 ; blue page palette
+ call FillBoxCGB
+
+ call ApplyAttrMap
+ call ApplyPals
+ ld a, $1
+ ld [hCGBPalUpdate], a
+ ret
+; 8f52
+
+StatsScreenPagePals: ; 8f52
+INCLUDE "gfx/stats/pages.pal"
+; 8f6a
+
+StatsScreenPals: ; 8f6a
+INCLUDE "gfx/stats/stats.pal"
+; 8f70
+
+_CGB_Pokedex: ; 8f70
+ ld de, wBGPals1
+ ld a, PREDEFPAL_POKEDEX
+ call GetPredefPal
+ call LoadHLPaletteIntoDE ; dex interface palette
+ ld a, [wCurPartySpecies]
+ cp $ff
+ jr nz, .is_pokemon
+ ld hl, .PokedexQuestionMarkPalette
+ call LoadHLPaletteIntoDE ; green question mark palette
+ jr .got_palette
+
+.is_pokemon
+ call GetMonPalettePointer_
+ call LoadPalette_White_Col1_Col2_Black ; mon palette
+.got_palette
+ call WipeAttrMap
+ hlcoord 1, 1, wAttrMap
+ lb bc, 7, 7
+ ld a, $1 ; green question mark palette
+ call FillBoxCGB
+ call InitPartyMenuOBPals
+ ld hl, .PokedexCursorPalette
+ ld de, wOBPals1 palette 7 ; green cursor palette
+ ld bc, 1 palettes
+ ld a, BANK(wOBPals1)
+ call FarCopyWRAM
+ call ApplyAttrMap
+ call ApplyPals
+ ld a, $1
+ ld [hCGBPalUpdate], a
+ ret
+; 8fba
+
+.PokedexQuestionMarkPalette: ; 8fba
+INCLUDE "gfx/pokedex/question_mark.pal"
+; 8fc2
+
+.PokedexCursorPalette: ; 8fc2
+INCLUDE "gfx/pokedex/cursor.pal"
+; 8fca
+
+_CGB_BillsPC: ; 8fca
+ ld de, wBGPals1
+ ld a, PREDEFPAL_POKEDEX
+ call GetPredefPal
+ call LoadHLPaletteIntoDE
+ ld a, [wCurPartySpecies]
+ cp $ff
+ jr nz, .GetMonPalette
+ ld hl, .BillsPCOrangePalette
+ call LoadHLPaletteIntoDE
+ jr .Resume
+
+.GetMonPalette:
+ ld bc, wTempMonDVs
+ call GetPlayerOrMonPalettePointer
+ call LoadPalette_White_Col1_Col2_Black
+.Resume:
+ call WipeAttrMap
+ hlcoord 1, 4, wAttrMap
+ lb bc, 7, 7
+ ld a, $1
+ call FillBoxCGB
+ call InitPartyMenuOBPals
+ call ApplyAttrMap
+ call ApplyPals
+ ld a, $1
+ ld [hCGBPalUpdate], a
+ ret
+; 9009
+
+.Function9009: ; 9009
+ ld hl, .BillsPCOrangePalette
+ call LoadHLPaletteIntoDE
+ jr .asm_901a
+
+.unused
+ ld bc, wTempMonDVs
+ call GetPlayerOrMonPalettePointer
+ call LoadPalette_White_Col1_Col2_Black
+.asm_901a
+ call WipeAttrMap
+ hlcoord 1, 1, wAttrMap
+ lb bc, 7, 7
+ ld a, $1
+ call FillBoxCGB
+ call InitPartyMenuOBPals
+ call ApplyAttrMap
+ call ApplyPals
+ ld a, $1
+ ld [hCGBPalUpdate], a
+ ret
+; 9036
+
+.BillsPCOrangePalette: ; 9036
+INCLUDE "gfx/pc/orange.pal"
+; 903e
+
+_CGB_PokedexUnownMode: ; 903e
+ ld de, wBGPals1
+ ld a, PREDEFPAL_POKEDEX
+ call GetPredefPal
+ call LoadHLPaletteIntoDE
+ ld a, [wCurPartySpecies]
+ call GetMonPalettePointer_
+ call LoadPalette_White_Col1_Col2_Black
+ call WipeAttrMap
+ hlcoord 7, 5, wAttrMap
+ lb bc, 7, 7
+ ld a, $1
+ call FillBoxCGB
+ call InitPartyMenuOBPals
+ call ApplyAttrMap
+ call ApplyPals
+ ld a, $1
+ ld [hCGBPalUpdate], a
+ ret
+; 906e
+
+_CGB_SlotMachine: ; 906e
+ ld hl, SlotMachinePals
+ ld de, wBGPals1
+ ld bc, 16 palettes
+ ld a, BANK(wBGPals1)
+ call FarCopyWRAM
+ call WipeAttrMap
+ hlcoord 0, 2, wAttrMap
+ lb bc, 10, 3
+ ld a, $2
+ call FillBoxCGB
+ hlcoord 17, 2, wAttrMap
+ lb bc, 10, 3
+ ld a, $2
+ call FillBoxCGB
+ hlcoord 0, 4, wAttrMap
+ lb bc, 6, 3
+ ld a, $3
+ call FillBoxCGB
+ hlcoord 17, 4, wAttrMap
+ lb bc, 6, 3
+ ld a, $3
+ call FillBoxCGB
+ hlcoord 0, 6, wAttrMap
+ lb bc, 2, 3
+ ld a, $4
+ call FillBoxCGB
+ hlcoord 17, 6, wAttrMap
+ lb bc, 2, 3
+ ld a, $4
+ call FillBoxCGB
+ hlcoord 4, 2, wAttrMap
+ lb bc, 2, 12
+ ld a, $1
+ call FillBoxCGB
+ hlcoord 3, 2, wAttrMap
+ lb bc, 10, 1
+ ld a, $1
+ call FillBoxCGB
+ hlcoord 16, 2, wAttrMap
+ lb bc, 10, 1
+ ld a, $1
+ call FillBoxCGB
+ hlcoord 0, 12, wAttrMap
+ ld bc, $78
+ ld a, $7
+ call ByteFill
+ call ApplyAttrMap
+ call ApplyPals
+ ld a, $1
+ ld [hCGBPalUpdate], a
+ ret
+; 90f8
+
+_CGB06: ; 90f8
+ ld hl, PalPacket_SCGB_06 + 1
+ call CopyFourPalettes
+ call WipeAttrMap
+ ld de, wOBPals1
+ ld a, PREDEFPAL_PACK
+ call GetPredefPal
+ call LoadHLPaletteIntoDE
+ hlcoord 0, 6, wAttrMap
+ lb bc, 12, SCREEN_WIDTH
+ ld a, $1
+ call FillBoxCGB
+ call ApplyAttrMap
+ call ApplyPals
+ ld a, $1
+ ld [hCGBPalUpdate], a
+ ret
+; 9122
+
+_CGB_GSIntro: ; 9122
+ ld b, 0
+ ld hl, .Jumptable
+ add hl, bc
+ add hl, bc
+ ld a, [hli]
+ ld h, [hl]
+ ld l, a
+ jp hl
+; 912d
+
+.Jumptable: ; 912d
+ dw .ShellderLaprasScene
+ dw .JigglypuffPikachuScene
+ dw .StartersCharizardScene
+; 9133
+
+.ShellderLaprasScene: ; 9133
+ ld hl, .ShellderLaprasBGPalette
+ ld de, wBGPals1
+ call LoadHLPaletteIntoDE
+ ld hl, .ShellderLaprasOBPals
+ ld de, wOBPals1
+ ld bc, 2 palettes
+ ld a, BANK(wOBPals1)
+ call FarCopyWRAM
+ call WipeAttrMap
+ ret
+; 914e
+
+.ShellderLaprasBGPalette: ; 914e
+ RGB 19, 31, 19
+ RGB 18, 23, 31
+ RGB 11, 21, 28
+ RGB 04, 16, 24
+
+.ShellderLaprasOBPals: ; 9156
+ RGB 29, 29, 29
+ RGB 20, 19, 20
+ RGB 19, 06, 04
+ RGB 03, 04, 06
+
+ RGB 31, 31, 31
+ RGB 31, 31, 31
+ RGB 31, 00, 00
+ RGB 03, 04, 06
+; 9166
+
+.JigglypuffPikachuScene: ; 9166
+ ld de, wBGPals1
+ ld a, PREDEFPAL_GS_INTRO_JIGGLYPUFF_PIKACHU_BG
+ call GetPredefPal
+ call LoadHLPaletteIntoDE
+
+ ld de, wOBPals1
+ ld a, PREDEFPAL_GS_INTRO_JIGGLYPUFF_PIKACHU_OB
+ call GetPredefPal
+ call LoadHLPaletteIntoDE
+ call WipeAttrMap
+ ret
+; 9180
+
+.StartersCharizardScene: ; 9180
+ ld hl, PalPacket_Pack + 1
+ call CopyFourPalettes
+ ld de, wOBPals1
+ ld a, PREDEFPAL_GS_INTRO_STARTERS_TRANSITION
+ call GetPredefPal
+ call LoadHLPaletteIntoDE
+ call WipeAttrMap
+ ret
+; 9195
+
+_CGB11: ; 9195
+ ld hl, Palettes_SCGB_11
+ ld de, wBGPals1
+ ld bc, 5 palettes
+ ld a, BANK(wBGPals1)
+ call FarCopyWRAM
+ call ApplyPals
+ call WipeAttrMap
+ call ApplyAttrMap
+ ret
+; 91ad
+
+_CGB_Diploma: ; 91ad
+ ld hl, DiplomaPalettes
+ ld de, wBGPals1
+ ld bc, 16 palettes
+ ld a, BANK(wBGPals1)
+ call FarCopyWRAM
+
+ ld hl, PalPacket_Diploma + 1
+ call CopyFourPalettes
+ call WipeAttrMap
+ call ApplyAttrMap
+ ret
+; 91c8
+
+_CGB_MapPals: ; 91c8
+ call LoadMapPals
+ ld a, SCGB_MAPPALS
+ ld [wSGBPredef], a
+ ret
+; 91d1
+
+_CGB_PartyMenu: ; 91d1
+ ld hl, PalPacket_PartyMenu + 1
+ call CopyFourPalettes
+ call InitPartyMenuBGPal0
+ call InitPartyMenuBGPal7
+ call InitPartyMenuOBPals
+ call ApplyAttrMap
+ ret
+; 91e4
+
+_CGB_Evolution: ; 91e4
+ ld de, wBGPals1
+ ld a, c
+ and a
+ jr z, .pokemon
+ ld a, PREDEFPAL_BLACKOUT
+ call GetPredefPal
+ call LoadHLPaletteIntoDE
+ jr .got_palette
+
+.pokemon
+ ld hl, wPartyMon1DVs
+ ld bc, PARTYMON_STRUCT_LENGTH
+ ld a, [wCurPartyMon]
+ call AddNTimes
+ ld c, l
+ ld b, h
+ ld a, [wPlayerHPPal]
+ call GetPlayerOrMonPalettePointer
+ call LoadPalette_White_Col1_Col2_Black
+ ld hl, BattleObjectPals
+ ld de, wOBPals1 palette PAL_BATTLE_OB_GRAY
+ ld bc, 6 palettes
+ ld a, BANK(wOBPals1)
+ call FarCopyWRAM
+
+.got_palette
+ call WipeAttrMap
+ call ApplyAttrMap
+ call ApplyPals
+ ld a, $1
+ ld [hCGBPalUpdate], a
+ ret
+; 9228
+
+_CGB_GSTitleScreen: ; 9228
+ ld hl, UnusedGSTitleBGPals
+ ld de, wBGPals1
+ ld bc, 5 palettes
+ ld a, BANK(wBGPals1)
+ call FarCopyWRAM
+ ld hl, UnusedGSTitleOBPals
+ ld de, wOBPals1
+ ld bc, 2 palettes
+ ld a, BANK(wOBPals1)
+ call FarCopyWRAM
+ ld a, SCGB_DIPLOMA
+ ld [wSGBPredef], a
+ call ApplyPals
+ ld a, $1
+ ld [hCGBPalUpdate], a
+ ret
+; 9251
+
+_CGB0d: ; 9251
+ ld hl, PalPacket_Diploma + 1
+ call CopyFourPalettes
+ call WipeAttrMap
+ call ApplyAttrMap
+ ret
+; 925e
+
+_CGB_UnownPuzzle: ; 925e
+ ld hl, PalPacket_UnownPuzzle + 1
+ call CopyFourPalettes
+ ld de, wOBPals1
+ ld a, PREDEFPAL_UNOWN_PUZZLE
+ call GetPredefPal
+ call LoadHLPaletteIntoDE
+ ld a, [rSVBK]
+ push af
+ ld a, BANK(wOBPals1)
+ ld [rSVBK], a
+ ld hl, wOBPals1
+ ld a, LOW(palred 31 + palgreen 0 + palblue 0)
+ ld [hli], a
+ ld a, HIGH(palred 31 + palgreen 0 + palblue 0)
+ ld [hl], a
+ pop af
+ ld [rSVBK], a
+ call WipeAttrMap
+ call ApplyAttrMap
+ ret
+; 9289
+
+_CGB_TrainerCard: ; 9289
+ ld de, wBGPals1
+ xor a ; CHRIS
+ call GetTrainerPalettePointer
+ call LoadPalette_White_Col1_Col2_Black
+ ld a, FALKNER ; KRIS
+ call GetTrainerPalettePointer
+ call LoadPalette_White_Col1_Col2_Black
+ ld a, BUGSY
+ call GetTrainerPalettePointer
+ call LoadPalette_White_Col1_Col2_Black
+ ld a, WHITNEY
+ call GetTrainerPalettePointer
+ call LoadPalette_White_Col1_Col2_Black
+ ld a, MORTY
+ call GetTrainerPalettePointer
+ call LoadPalette_White_Col1_Col2_Black
+ ld a, CHUCK
+ call GetTrainerPalettePointer
+ call LoadPalette_White_Col1_Col2_Black
+ ld a, JASMINE
+ call GetTrainerPalettePointer
+ call LoadPalette_White_Col1_Col2_Black
+ ld a, PRYCE
+ call GetTrainerPalettePointer
+ call LoadPalette_White_Col1_Col2_Black
+ ld a, PREDEFPAL_CGB_BADGE
+ call GetPredefPal
+ call LoadHLPaletteIntoDE
+
+ ; fill screen with opposite-gender palette for the card border
+ hlcoord 0, 0, wAttrMap
+ ld bc, SCREEN_WIDTH * SCREEN_HEIGHT
+ ld a, [wPlayerGender]
+ and a
+ ld a, $1 ; kris
+ jr z, .got_gender
+ ld a, $0 ; chris
+.got_gender
+ call ByteFill
+ ; fill trainer sprite area with same-gender palette
+ hlcoord 14, 1, wAttrMap
+ lb bc, 7, 5
+ ld a, [wPlayerGender]
+ and a
+ ld a, $0 ; chris
+ jr z, .got_gender2
+ ld a, $1 ; kris
+.got_gender2
+ call FillBoxCGB
+ ; top-right corner still uses the border's palette
+ hlcoord 18, 1, wAttrMap
+ ld [hl], $1
+ hlcoord 2, 11, wAttrMap
+ lb bc, 2, 4
+ ld a, $1 ; falkner
+ call FillBoxCGB
+ hlcoord 6, 11, wAttrMap
+ lb bc, 2, 4
+ ld a, $2 ; bugsy
+ call FillBoxCGB
+ hlcoord 10, 11, wAttrMap
+ lb bc, 2, 4
+ ld a, $3 ; whitney
+ call FillBoxCGB
+ hlcoord 14, 11, wAttrMap
+ lb bc, 2, 4
+ ld a, $4 ; morty
+ call FillBoxCGB
+ hlcoord 2, 14, wAttrMap
+ lb bc, 2, 4
+ ld a, $5 ; chuck
+ call FillBoxCGB
+ hlcoord 6, 14, wAttrMap
+ lb bc, 2, 4
+ ld a, $6 ; jasmine
+ call FillBoxCGB
+ hlcoord 10, 14, wAttrMap
+ lb bc, 2, 4
+ ld a, $7 ; pryce
+ call FillBoxCGB
+ ; clair uses kris's palette
+ ld a, [wPlayerGender]
+ and a
+ push af
+ jr z, .got_gender3
+ hlcoord 14, 14, wAttrMap
+ lb bc, 2, 4
+ ld a, $1
+ call FillBoxCGB
+.got_gender3
+ pop af
+ ld c, $0
+ jr nz, .got_gender4
+ inc c
+.got_gender4
+ ld a, c
+ hlcoord 18, 1, wAttrMap
+ ld [hl], a
+ call ApplyAttrMap
+ call ApplyPals
+ ld a, $1
+ ld [hCGBPalUpdate], a
+ ret
+; 9373
+
+_CGB_MoveList: ; 9373
+ ld de, wBGPals1
+ ld a, PREDEFPAL_GOLDENROD
+ call GetPredefPal
+ call LoadHLPaletteIntoDE
+ ld a, [wPlayerHPPal]
+ ld l, a
+ ld h, 0
+ add hl, hl
+ add hl, hl
+ ld bc, HPBarPals
+ add hl, bc
+ call LoadPalette_White_Col1_Col2_Black
+ call WipeAttrMap
+ hlcoord 11, 1, wAttrMap
+ lb bc, 2, 9
+ ld a, $1
+ call FillBoxCGB
+ call ApplyAttrMap
+ call ApplyPals
+ ld a, $1
+ ld [hCGBPalUpdate], a
+ ret
+; 93a6
+
+_CGB0f: ; 93a6
+ ld hl, PalPacket_SCGB_0F + 1
+ call CopyFourPalettes
+ call WipeAttrMap
+ call ApplyAttrMap
+ call ApplyPals
+ ld a, $1
+ ld [hCGBPalUpdate], a
+ ret
+; 93ba
+
+_CGB_PokedexSearchOption: ; 93ba
+ ld de, wBGPals1
+ ld a, PREDEFPAL_POKEDEX
+ call GetPredefPal
+ call LoadHLPaletteIntoDE
+ call WipeAttrMap
+ call ApplyAttrMap
+ call ApplyPals
+ ld a, $1
+ ld [hCGBPalUpdate], a
+ ret
+; 93d3
+
+_CGB_PackPals: ; 93d3
+; pack pals
+ ld a, [wBattleType]
+ cp BATTLETYPE_TUTORIAL
+ jr z, .tutorial_male
+
+ ld a, [wPlayerGender]
+ bit PLAYERGENDER_FEMALE_F, a
+ jr z, .tutorial_male
+
+ ld hl, .KrisPackPals
+ jr .got_gender
+
+.tutorial_male
+ ld hl, .ChrisPackPals
+
+.got_gender
+ ld de, wBGPals1
+ ld bc, 8 palettes ; 6 palettes?
+ ld a, BANK(wBGPals1)
+ call FarCopyWRAM
+ call WipeAttrMap
+ hlcoord 0, 0, wAttrMap
+ lb bc, 1, 10
+ ld a, $1
+ call FillBoxCGB
+ hlcoord 10, 0, wAttrMap
+ lb bc, 1, 10
+ ld a, $2
+ call FillBoxCGB
+ hlcoord 7, 2, wAttrMap
+ lb bc, 9, 1
+ ld a, $3
+ call FillBoxCGB
+ hlcoord 0, 7, wAttrMap
+ lb bc, 3, 5
+ ld a, $4
+ call FillBoxCGB
+ hlcoord 0, 3, wAttrMap
+ lb bc, 3, 5
+ ld a, $5
+ call FillBoxCGB
+ call ApplyAttrMap
+ call ApplyPals
+ ld a, $1
+ ld [hCGBPalUpdate], a
+ ret
+; 9439
+
+.ChrisPackPals: ; 9439
+INCLUDE "gfx/pack/pack.pal"
+; 9469
+
+.KrisPackPals: ; 9469
+INCLUDE "gfx/pack/pack_f.pal"
+; 9499
+
+_CGB_Pokepic: ; 9499
+ call _CGB_MapPals
+ ld de, SCREEN_WIDTH
+ hlcoord 0, 0, wAttrMap
+ ld a, [wMenuBorderTopCoord]
+.loop
+ and a
+ jr z, .found_top
+ dec a
+ add hl, de
+ jr .loop
+
+.found_top
+ ld a, [wMenuBorderLeftCoord]
+ ld e, a
+ ld d, $0
+ add hl, de
+ ld a, [wMenuBorderTopCoord]
+ ld b, a
+ ld a, [wMenuBorderBottomCoord]
+ inc a
+ sub b
+ ld b, a
+ ld a, [wMenuBorderLeftCoord]
+ ld c, a
+ ld a, [wMenuBorderRightCoord]
+ sub c
+ inc a
+ ld c, a
+ ld a, $0
+ call FillBoxCGB
+ call ApplyAttrMap
+ ret
+; 94d0
+
+_CGB13: ; 94d0
+ ld hl, PalPacket_SCGB_13 + 1
+ call CopyFourPalettes
+ call WipeAttrMap
+ hlcoord 0, 4, wAttrMap
+ lb bc, 10, SCREEN_WIDTH
+ ld a, $2
+ call FillBoxCGB
+ hlcoord 0, 6, wAttrMap
+ lb bc, 6, SCREEN_WIDTH
+ ld a, $1
+ call FillBoxCGB
+ call ApplyAttrMap
+ call ApplyPals
+ ld a, $1
+ ld [hCGBPalUpdate], a
+ ret
+; 94fa
+
+_CGB_GamefreakLogo: ; 94fa
+ ld de, wBGPals1
+ ld a, PREDEFPAL_GAMEFREAK_LOGO
+ call GetPredefPal
+ call LoadHLPaletteIntoDE
+ ld hl, .Palette
+ ld de, wOBPals1
+ call LoadHLPaletteIntoDE
+ ld hl, .Palette
+ ld de, wOBPals1 palette 1
+ call LoadHLPaletteIntoDE
+ call WipeAttrMap
+ call ApplyAttrMap
+ call ApplyPals
+ ret
+; 9521
+
+.Palette: ; 9521
+INCLUDE "gfx/splash/logo.pal"
+; 9529
+
+_CGB_PlayerOrMonFrontpicPals: ; 9529
+ ld de, wBGPals1
+ ld a, [wCurPartySpecies]
+ ld bc, wTempMonDVs
+ call GetPlayerOrMonPalettePointer
+ call LoadPalette_White_Col1_Col2_Black
+ call WipeAttrMap
+ call ApplyAttrMap
+ call ApplyPals
+ ret
+; 9542
+
+_CGB1e: ; 9542
+ ld de, wBGPals1
+ ld a, [wCurPartySpecies]
+ call GetMonPalettePointer_
+ call LoadPalette_White_Col1_Col2_Black
+ call WipeAttrMap
+ call ApplyAttrMap
+ ret
+; 9555
+
+_CGB_TradeTube: ; 9555
+ ld hl, PalPacket_TradeTube + 1
+ call CopyFourPalettes
+ ld hl, PartyMenuOBPals
+ ld de, wOBPals1
+ ld bc, 1 palettes
+ ld a, BANK(wOBPals1)
+ call FarCopyWRAM
+ ld de, wOBPals1 palette 7
+ ld a, PREDEFPAL_TRADE_TUBE
+ call GetPredefPal
+ call LoadHLPaletteIntoDE
+ call WipeAttrMap
+ ret
+; 9578
+
+_CGB_TrainerOrMonFrontpicPals: ; 9578
+ ld de, wBGPals1
+ ld a, [wCurPartySpecies]
+ ld bc, wTempMonDVs
+ call GetFrontpicPalettePointer
+ call LoadPalette_White_Col1_Col2_Black
+ call WipeAttrMap
+ call ApplyAttrMap
+ call ApplyPals
+ ret
+; 9591
+
+_CGB_MysteryGift: ; 9591
+ ld hl, .Palettes
+ ld de, wBGPals1
+ ld bc, 2 palettes
+ ld a, BANK(wBGPals1)
+ call FarCopyWRAM
+ call ApplyPals
+ call WipeAttrMap
+ hlcoord 3, 7, wAttrMap
+ lb bc, 8, 14
+ ld a, $1
+ call FillBoxCGB
+ hlcoord 1, 5, wAttrMap
+ lb bc, 1, 18
+ ld a, $1
+ call FillBoxCGB
+ hlcoord 1, 16, wAttrMap
+ lb bc, 1, 18
+ ld a, $1
+ call FillBoxCGB
+ hlcoord 0, 0, wAttrMap
+ lb bc, 17, 2
+ ld a, $1
+ call FillBoxCGB
+ hlcoord 18, 5, wAttrMap
+ lb bc, 12, 1
+ ld a, $1
+ call FillBoxCGB
+ call ApplyAttrMap
+ ret
+; 95e0
+
+.Palettes: ; 95e0
+INCLUDE "gfx/mystery_gift/mystery_gift.pal"
+; 95f0
diff --git a/engine/gfx/color.asm b/engine/gfx/color.asm
new file mode 100644
index 000000000..6cf896ff4
--- /dev/null
+++ b/engine/gfx/color.asm
@@ -0,0 +1,1356 @@
+INCLUDE "engine/gfx/sgb_layouts.asm"
+
+SHINY_ATK_BIT EQU 5
+SHINY_DEF_VAL EQU 10
+SHINY_SPD_VAL EQU 10
+SHINY_SPC_VAL EQU 10
+
+CheckShininess:
+; Check if a mon is shiny by DVs at bc.
+; Return carry if shiny.
+
+ ld l, c
+ ld h, b
+
+; Attack
+ ld a, [hl]
+ and 1 << SHINY_ATK_BIT
+ jr z, .NotShiny
+
+; Defense
+ ld a, [hli]
+ and $f
+ cp SHINY_DEF_VAL
+ jr nz, .NotShiny
+
+; Speed
+ ld a, [hl]
+ and $f0
+ cp SHINY_SPD_VAL << 4
+ jr nz, .NotShiny
+
+; Special
+ ld a, [hl]
+ and $f
+ cp SHINY_SPC_VAL
+ jr nz, .NotShiny
+
+.Shiny:
+ scf
+ ret
+
+.NotShiny:
+ and a
+ ret
+
+Unused_CheckContestMon:
+; Check a mon's DVs at hl in the bug catching contest.
+; Return carry if its DVs are good enough to place in the contest.
+
+; Attack
+ ld a, [hl]
+ cp 10 << 4
+ jr c, .Bad
+
+; Defense
+ ld a, [hli]
+ and $f
+ cp 10
+ jr c, .Bad
+
+; Speed
+ ld a, [hl]
+ cp 10 << 4
+ jr c, .Bad
+
+; Special
+ ld a, [hl]
+ and $f
+ cp 10
+ jr c, .Bad
+
+.Good:
+ scf
+ ret
+
+.Bad:
+ and a
+ ret
+
+Unreferenced_Function8aa4:
+ push de
+ push bc
+ ld hl, PalPacket_9ce6
+ ld de, wSGBPals
+ ld bc, PALPACKET_LENGTH
+ call CopyBytes
+ pop bc
+ pop de
+ ld a, c
+ ld [wSGBPals + 3], a
+ ld a, b
+ ld [wSGBPals + 4], a
+ ld a, e
+ ld [wSGBPals + 5], a
+ ld a, d
+ ld [wSGBPals + 6], a
+ ld hl, wSGBPals
+ call PushSGBPals_
+ ld hl, BlkPacket_9a86
+ call PushSGBPals_
+ ret
+
+InitPartyMenuPalettes:
+ ld hl, PalPacket_PartyMenu + 1
+ call CopyFourPalettes
+ call InitPartyMenuOBPals
+ call WipeAttrMap
+ ret
+
+; SGB layout for SCGB_PARTY_MENU_HP_PALS
+SGB_ApplyPartyMenuHPPals: ; 8ade
+ ld hl, wHPPals
+ ld a, [wSGBPals]
+ ld e, a
+ ld d, $0
+ add hl, de
+ ld e, l
+ ld d, h
+ ld a, [de]
+ and a
+ ld e, $5
+ jr z, .okay
+ dec a
+ ld e, $a
+ jr z, .okay
+ ld e, $f
+.okay
+ push de
+ ld hl, wSGBPals + 10
+ ld bc, $6
+ ld a, [wSGBPals]
+ call AddNTimes
+ pop de
+ ld [hl], e
+ ret
+
+Unreferenced_Function8b07:
+ call CheckCGB
+ ret z
+; CGB only
+ ld hl, .BGPal
+ ld de, wBGPals1
+ ld bc, 1 palettes
+ ld a, BANK(wBGPals1)
+ call FarCopyWRAM
+
+ ld hl, .OBPal
+ ld de, wOBPals1
+ ld bc, 1 palettes
+ ld a, BANK(wOBPals1)
+ call FarCopyWRAM
+
+ call ApplyPals
+ ld a, $1
+ ld [hCGBPalUpdate], a
+ ret
+
+.BGPal:
+ RGB 31, 31, 31
+ RGB 18, 23, 31
+ RGB 15, 20, 31
+ RGB 00, 00, 00
+
+.OBPal:
+ RGB 31, 31, 31
+ RGB 31, 31, 12
+ RGB 08, 16, 28
+ RGB 00, 00, 00
+
+Unreferenced_Function8b3f:
+ call CheckCGB
+ ret nz
+ ld a, [hSGB]
+ and a
+ ret z
+ ld hl, BlkPacket_9a86
+ jp PushSGBPals_
+
+Unreferenced_Function8b4d:
+ call CheckCGB
+ jr nz, .cgb
+ ld a, [hSGB]
+ and a
+ ret z
+ ld hl, PalPacket_Function8b4d
+ jp PushSGBPals_
+
+.cgb
+ ld de, wOBPals1
+ ld a, PREDEFPAL_3B
+ call GetPredefPal
+ jp LoadHLPaletteIntoDE
+
+Unreferenced_Function8b67:
+ call CheckCGB
+ jr nz, .cgb
+ ld a, [hSGB]
+ and a
+ ret z
+ ld hl, PalPacket_Pack
+ jp PushSGBPals_
+
+.cgb
+ ld de, wOBPals1
+ ld a, PREDEFPAL_PACK
+ call GetPredefPal
+ jp LoadHLPaletteIntoDE
+
+Unreferenced_Function8b81:
+ call CheckCGB
+ jr nz, .cgb
+ ld a, [hSGB]
+ and a
+ ret z
+ ld a, c
+ push af
+ ld hl, PalPacket_9ce6
+ ld de, wSGBPals
+ ld bc, PALPACKET_LENGTH
+ call CopyBytes
+ pop af
+ call GetMonPalettePointer_
+ ld a, [hli]
+ ld [wSGBPals + 3], a
+ ld a, [hli]
+ ld [wSGBPals + 4], a
+ ld a, [hli]
+ ld [wSGBPals + 5], a
+ ld a, [hl]
+ ld [wSGBPals + 6], a
+ ld hl, wSGBPals
+ jp PushSGBPals_
+
+.cgb
+ ld de, wOBPals1
+ ld a, c
+ call GetMonPalettePointer_
+ call LoadPalette_White_Col1_Col2_Black
+ ret
+
+LoadTrainerClassPaletteAsNthBGPal:
+ ld a, [wTrainerClass]
+ call GetTrainerPalettePointer
+ ld a, e
+ jr got_palette_pointer_8bd7
+
+LoadMonPaletteAsNthBGPal:
+ ld a, [wCurPartySpecies]
+ call GetMonPalettePointer
+ ld a, e
+ bit 7, a
+ jr z, got_palette_pointer_8bd7
+ and $7f
+ inc hl
+ inc hl
+ inc hl
+ inc hl
+
+got_palette_pointer_8bd7
+ push hl
+ ld hl, wBGPals1
+ ld de, 1 palettes
+.loop
+ and a
+ jr z, .got_addr
+ add hl, de
+ dec a
+ jr .loop
+
+.got_addr
+ ld e, l
+ ld d, h
+ pop hl
+ call LoadPalette_White_Col1_Col2_Black
+ ret
+
+Unreferenced_Function8bec:
+ ld a, [hCGB]
+ and a
+ jr nz, .cgb
+ ld hl, wPlayerLightScreenCount
+ jp PushSGBPals_
+
+.cgb
+ ld a, [wEnemyLightScreenCount] ; col
+ ld c, a
+ ld a, [wEnemyReflectCount] ; row
+ hlcoord 0, 0, wAttrMap
+ ld de, SCREEN_WIDTH
+.loop
+ and a
+ jr z, .done
+ add hl, de
+ dec a
+ jr .loop
+
+.done
+ ld b, $0
+ add hl, bc
+ lb bc, 6, 4
+ ld a, [wEnemySafeguardCount] ; value
+ and $3
+ call FillBoxCGB
+ call CopyTilemapAtOnce
+ ret
+
+ApplyMonOrTrainerPals:
+ call CheckCGB
+ ret z
+ ld a, e
+ and a
+ jr z, .get_trainer
+ ld a, [wCurPartySpecies]
+ call GetMonPalettePointer_
+ jr .load_palettes
+
+.get_trainer
+ ld a, [wTrainerClass]
+ call GetTrainerPalettePointer
+
+.load_palettes
+ ld de, wBGPals1
+ call LoadPalette_White_Col1_Col2_Black
+ call WipeAttrMap
+ call ApplyAttrMap
+ call ApplyPals
+ ret
+
+ApplyHPBarPals:
+ ld a, [wWhichHPBar]
+ and a
+ jr z, .Enemy
+ cp $1
+ jr z, .Player
+ cp $2
+ jr z, .PartyMenu
+ ret
+
+.Enemy:
+ ld de, wBGPals2 palette PAL_BATTLE_BG_ENEMY_HP color 1
+ jr .okay
+
+.Player:
+ ld de, wBGPals2 palette PAL_BATTLE_BG_PLAYER_HP color 1
+
+.okay
+ ld l, c
+ ld h, $0
+ add hl, hl
+ add hl, hl
+ ld bc, HPBarPals
+ add hl, bc
+ ld bc, 4
+ ld a, BANK(wBGPals2)
+ call FarCopyWRAM
+ ld a, $1
+ ld [hCGBPalUpdate], a
+ ret
+
+.PartyMenu:
+ ld e, c
+ inc e
+ hlcoord 11, 1, wAttrMap
+ ld bc, 2 * SCREEN_WIDTH
+ ld a, [wCurPartyMon]
+.loop
+ and a
+ jr z, .done
+ add hl, bc
+ dec a
+ jr .loop
+
+.done
+ lb bc, 2, 8
+ ld a, e
+ call FillBoxCGB
+ ret
+
+LoadStatsScreenPals:
+ call CheckCGB
+ ret z
+ ld hl, StatsScreenPals
+ ld b, 0
+ dec c
+ add hl, bc
+ add hl, bc
+ ld a, [rSVBK]
+ push af
+ ld a, BANK(wBGPals1)
+ ld [rSVBK], a
+ ld a, [hli]
+ ld [wBGPals1 palette 0], a
+ ld [wBGPals1 palette 2], a
+ ld a, [hl]
+ ld [wBGPals1 palette 0 + 1], a
+ ld [wBGPals1 palette 2 + 1], a
+ pop af
+ ld [rSVBK], a
+ call ApplyPals
+ ld a, $1
+ ret
+
+LoadMailPalettes:
+ ld l, e
+ ld h, 0
+ add hl, hl
+ add hl, hl
+ add hl, hl
+ ld de, .MailPals
+ add hl, de
+ call CheckCGB
+ jr nz, .cgb
+ push hl
+ ld hl, PalPacket_9ce6
+ ld de, wSGBPals
+ ld bc, PALPACKET_LENGTH
+ call CopyBytes
+ pop hl
+ inc hl
+ inc hl
+ ld a, [hli]
+ ld [wSGBPals + 3], a
+ ld a, [hli]
+ ld [wSGBPals + 4], a
+ ld a, [hli]
+ ld [wSGBPals + 5], a
+ ld a, [hli]
+ ld [wSGBPals + 6], a
+ ld hl, wSGBPals
+ call PushSGBPals_
+ ld hl, BlkPacket_9a86
+ call PushSGBPals_
+ ret
+
+.cgb
+ ld de, wBGPals1
+ ld bc, 1 palettes
+ ld a, BANK(wBGPals1)
+ call FarCopyWRAM
+ call ApplyPals
+ call WipeAttrMap
+ call ApplyAttrMap
+ ret
+
+.MailPals:
+INCLUDE "gfx/mail/mail.pal"
+
+INCLUDE "engine/gfx/cgb_layouts.asm"
+
+Unreferenced_Function95f0:
+ ld hl, .Palette
+ ld de, wBGPals1
+ ld bc, 1 palettes
+ ld a, BANK(wBGPals1)
+ call FarCopyWRAM
+ call ApplyPals
+ call WipeAttrMap
+ call ApplyAttrMap
+ ret
+
+.Palette:
+ RGB 31, 31, 31
+ RGB 09, 31, 31
+ RGB 10, 12, 31
+ RGB 00, 03, 19
+
+CopyFourPalettes:
+ ld de, wBGPals1
+ ld c, 4
+
+CopyPalettes:
+.loop
+ push bc
+ ld a, [hli]
+ push hl
+ call GetPredefPal
+ call LoadHLPaletteIntoDE
+ pop hl
+ inc hl
+ pop bc
+ dec c
+ jr nz, .loop
+ ret
+
+GetPredefPal:
+ ld l, a
+ ld h, $0
+ add hl, hl
+ add hl, hl
+ add hl, hl
+ ld bc, PredefPals
+ add hl, bc
+ ret
+
+LoadHLPaletteIntoDE:
+ ld a, [rSVBK]
+ push af
+ ld a, BANK(wOBPals1)
+ ld [rSVBK], a
+ ld c, 1 palettes
+.loop
+ ld a, [hli]
+ ld [de], a
+ inc de
+ dec c
+ jr nz, .loop
+ pop af
+ ld [rSVBK], a
+ ret
+
+LoadPalette_White_Col1_Col2_Black:
+ ld a, [rSVBK]
+ push af
+ ld a, BANK(wBGPals1)
+ ld [rSVBK], a
+
+ ld a, LOW(PALRGB_WHITE)
+ ld [de], a
+ inc de
+ ld a, HIGH(PALRGB_WHITE)
+ ld [de], a
+ inc de
+
+ ld c, 2 * PAL_COLOR_SIZE
+.loop
+ ld a, [hli]
+ ld [de], a
+ inc de
+ dec c
+ jr nz, .loop
+
+ xor a
+ ld [de], a
+ inc de
+ ld [de], a
+ inc de
+
+ pop af
+ ld [rSVBK], a
+ ret
+
+FillBoxCGB:
+.row
+ push bc
+ push hl
+.col
+ ld [hli], a
+ dec c
+ jr nz, .col
+ pop hl
+ ld bc, SCREEN_WIDTH
+ add hl, bc
+ pop bc
+ dec b
+ jr nz, .row
+ ret
+
+ResetBGPals:
+ push af
+ push bc
+ push de
+ push hl
+
+ ld a, [rSVBK]
+ push af
+ ld a, BANK(wBGPals1)
+ ld [rSVBK], a
+
+ ld hl, wBGPals1
+ ld c, 1 palettes
+.loop
+ ld a, $ff
+ ld [hli], a
+ ld [hli], a
+ ld [hli], a
+ ld [hli], a
+ xor a
+ ld [hli], a
+ ld [hli], a
+ ld [hli], a
+ ld [hli], a
+ dec c
+ jr nz, .loop
+
+ pop af
+ ld [rSVBK], a
+
+ pop hl
+ pop de
+ pop bc
+ pop af
+ ret
+
+WipeAttrMap:
+ hlcoord 0, 0, wAttrMap
+ ld bc, SCREEN_WIDTH * SCREEN_HEIGHT
+ xor a
+ call ByteFill
+ ret
+
+ApplyPals:
+ ld hl, wBGPals1
+ ld de, wBGPals2
+ ld bc, 16 palettes
+ ld a, BANK(wGBCPalettes)
+ call FarCopyWRAM
+ ret
+
+ApplyAttrMap:
+ ld a, [rLCDC]
+ bit rLCDC_ENABLE, a
+ jr z, .UpdateVBank1
+ ld a, [hBGMapMode]
+ push af
+ ld a, $2
+ ld [hBGMapMode], a
+ call DelayFrame
+ call DelayFrame
+ call DelayFrame
+ call DelayFrame
+ pop af
+ ld [hBGMapMode], a
+ ret
+
+.UpdateVBank1:
+ hlcoord 0, 0, wAttrMap
+ debgcoord 0, 0
+ ld b, SCREEN_HEIGHT
+ ld a, $1
+ ld [rVBK], a
+.row
+ ld c, SCREEN_WIDTH
+.col
+ ld a, [hli]
+ ld [de], a
+ inc de
+ dec c
+ jr nz, .col
+ ld a, BG_MAP_WIDTH - SCREEN_WIDTH
+ add e
+ jr nc, .okay
+ inc d
+.okay
+ ld e, a
+ dec b
+ jr nz, .row
+ ld a, $0
+ ld [rVBK], a
+ ret
+
+; CGB layout for SCGB_PARTY_MENU_HP_PALS
+CGB_ApplyPartyMenuHPPals: ; 96f3
+ ld hl, wHPPals
+ ld a, [wSGBPals]
+ ld e, a
+ ld d, $0
+ add hl, de
+ ld e, l
+ ld d, h
+ ld a, [de]
+ inc a
+ ld e, a
+ hlcoord 11, 2, wAttrMap
+ ld bc, 2 * SCREEN_WIDTH
+ ld a, [wSGBPals]
+.loop
+ and a
+ jr z, .done
+ add hl, bc
+ dec a
+ jr .loop
+.done
+ lb bc, 2, 8
+ ld a, e
+ call FillBoxCGB
+ ret
+
+InitPartyMenuOBPals:
+ ld hl, PartyMenuOBPals
+ ld de, wOBPals1
+ ld bc, 2 palettes
+ ld a, BANK(wOBPals1)
+ call FarCopyWRAM
+ ret
+
+GetBattlemonBackpicPalettePointer:
+ push de
+ farcall GetPartyMonDVs
+ ld c, l
+ ld b, h
+ ld a, [wTempBattleMonSpecies]
+ call GetPlayerOrMonPalettePointer
+ pop de
+ ret
+
+GetEnemyFrontpicPalettePointer:
+ push de
+ farcall GetEnemyMonDVs
+ ld c, l
+ ld b, h
+ ld a, [wTempEnemyMonSpecies]
+ call GetFrontpicPalettePointer
+ pop de
+ ret
+
+GetPlayerOrMonPalettePointer:
+ and a
+ jp nz, GetMonNormalOrShinyPalettePointer
+ ld a, [wPlayerSpriteSetupFlags]
+ bit PLAYERSPRITESETUP_FEMALE_TO_MALE_F, a
+ jr nz, .male
+ ld a, [wPlayerGender]
+ and a
+ jr z, .male
+ ld hl, KrisPalette
+ ret
+
+.male
+ ld hl, PlayerPalette
+ ret
+
+GetFrontpicPalettePointer:
+ and a
+ jp nz, GetMonNormalOrShinyPalettePointer
+ ld a, [wTrainerClass]
+
+GetTrainerPalettePointer:
+ ld l, a
+ ld h, 0
+ add hl, hl
+ add hl, hl
+ ld bc, TrainerPalettes
+ add hl, bc
+ ret
+
+GetMonPalettePointer_:
+ call GetMonPalettePointer
+ ret
+
+Unreferenced_Function9779:
+ ret
+ call CheckCGB
+ ret z
+ ld hl, BattleObjectPals
+ ld a, $90
+ ld [rOBPI], a
+ ld c, 6 palettes
+.loop
+ ld a, [hli]
+ ld [rOBPD], a
+ dec c
+ jr nz, .loop
+ ld hl, BattleObjectPals
+ ld de, wOBPals1 palette 2
+ ld bc, 2 palettes
+ ld a, BANK(wOBPals1)
+ call FarCopyWRAM
+ ret
+
+BattleObjectPals:
+INCLUDE "gfx/battle_anims/battle_anims.pal"
+
+Unreferenced_Function97cc:
+ call CheckCGB
+ ret z
+ ld a, $90
+ ld [rOBPI], a
+ ld a, PREDEFPAL_TRADE_TUBE
+ call GetPredefPal
+ call .PushPalette
+ ld a, PREDEFPAL_RB_GREENMON
+ call GetPredefPal
+ call .PushPalette
+ ret
+
+.PushPalette:
+ ld c, 1 palettes
+.loop
+ ld a, [hli]
+ ld [rOBPD], a
+ dec c
+ jr nz, .loop
+ ret
+
+GetMonPalettePointer:
+ ld l, a
+ ld h, $0
+ add hl, hl
+ add hl, hl
+ add hl, hl
+ ld bc, PokemonPalettes
+ add hl, bc
+ ret
+
+GetMonNormalOrShinyPalettePointer:
+ push bc
+ call GetMonPalettePointer
+ pop bc
+ push hl
+ call CheckShininess
+ pop hl
+ ret nc
+rept 4
+ inc hl
+endr
+ ret
+
+PushSGBPals_:
+ ld a, [wcfbe]
+ push af
+ set 7, a
+ ld [wcfbe], a
+ call PushSGBPals
+ pop af
+ ld [wcfbe], a
+ ret
+
+PushSGBPals:
+ ld a, [hl]
+ and $7
+ ret z
+ ld b, a
+.loop
+ push bc
+ xor a
+ ld [rJOYP], a
+ ld a, $30
+ ld [rJOYP], a
+ ld b, $10
+.loop2
+ ld e, $8
+ ld a, [hli]
+ ld d, a
+.loop3
+ bit 0, d
+ ld a, $10
+ jr nz, .okay
+ ld a, $20
+.okay
+ ld [rJOYP], a
+ ld a, $30
+ ld [rJOYP], a
+ rr d
+ dec e
+ jr nz, .loop3
+ dec b
+ jr nz, .loop2
+ ld a, $20
+ ld [rJOYP], a
+ ld a, $30
+ ld [rJOYP], a
+ call SGBDelayCycles
+ pop bc
+ dec b
+ jr nz, .loop
+ ret
+
+InitSGBBorder:
+ call CheckCGB
+ ret nz
+; SGB/DMG only
+ di
+ ld a, [wcfbe]
+ push af
+ set 7, a
+ ld [wcfbe], a
+ xor a
+ ld [rJOYP], a
+ ld [hSGB], a
+ call PushSGBBorderPalsAndWait
+ jr nc, .skip
+ ld a, $1
+ ld [hSGB], a
+ call _InitSGBBorderPals
+ call SGBBorder_PushBGPals
+ call SGBDelayCycles
+ call SGB_ClearVRAM
+ call PushSGBBorder
+ call SGBDelayCycles
+ call SGB_ClearVRAM
+ ld hl, MaskEnCancelPacket
+ call PushSGBPals
+
+.skip
+ pop af
+ ld [wcfbe], a
+ ei
+ ret
+
+InitCGBPals::
+ call CheckCGB
+ ret z
+; CGB only
+ ld a, BANK(vTiles3)
+ ld [rVBK], a
+ ld hl, vTiles3
+ ld bc, $200 tiles
+ xor a
+ call ByteFill
+ ld a, BANK(vTiles0)
+ ld [rVBK], a
+ ld a, 1 << rBGPI_AUTO_INCREMENT
+ ld [rBGPI], a
+ ld c, 4 * 8
+.bgpals_loop
+ ld a, LOW(PALRGB_WHITE)
+ ld [rBGPD], a
+ ld a, HIGH(PALRGB_WHITE)
+ ld [rBGPD], a
+ dec c
+ jr nz, .bgpals_loop
+ ld a, 1 << rOBPI_AUTO_INCREMENT
+ ld [rOBPI], a
+ ld c, 4 * 8
+.obpals_loop
+ ld a, LOW(PALRGB_WHITE)
+ ld [rOBPD], a
+ ld a, HIGH(PALRGB_WHITE)
+ ld [rOBPD], a
+ dec c
+ jr nz, .obpals_loop
+ ld a, [rSVBK]
+ push af
+ ld a, BANK(wBGPals1)
+ ld [rSVBK], a
+ ld hl, wBGPals1
+ call .LoadWhitePals
+ ld hl, wBGPals2
+ call .LoadWhitePals
+ pop af
+ ld [rSVBK], a
+ ret
+
+.LoadWhitePals:
+ ld c, 4 * 16
+.loop
+ ld a, LOW(PALRGB_WHITE)
+ ld [hli], a
+ ld a, HIGH(PALRGB_WHITE)
+ ld [hli], a
+ dec c
+ jr nz, .loop
+ ret
+
+_InitSGBBorderPals:
+ ld hl, .PacketPointerTable
+ ld c, 9
+.loop
+ push bc
+ ld a, [hli]
+ push hl
+ ld h, [hl]
+ ld l, a
+ call PushSGBPals
+ pop hl
+ inc hl
+ pop bc
+ dec c
+ jr nz, .loop
+ ret
+
+.PacketPointerTable:
+ dw MaskEnFreezePacket
+ dw DataSndPacket1
+ dw DataSndPacket2
+ dw DataSndPacket3
+ dw DataSndPacket4
+ dw DataSndPacket5
+ dw DataSndPacket6
+ dw DataSndPacket7
+ dw DataSndPacket8
+
+Unreferenced_Function9911:
+ di
+ xor a
+ ld [rJOYP], a
+ ld hl, MaskEnFreezePacket
+ call PushSGBPals
+ call PushSGBBorder
+ call SGBDelayCycles
+ call SGB_ClearVRAM
+ ld hl, MaskEnCancelPacket
+ call PushSGBPals
+ ei
+ ret
+
+PushSGBBorder:
+ call .LoadSGBBorderPointers
+ push de
+ call SGBBorder_YetMorePalPushing
+ pop hl
+ call SGBBorder_MorePalPushing
+ ret
+
+.LoadSGBBorderPointers:
+ ld hl, SGBBorder
+ ld de, SGBBorderMap
+ ret
+
+SGB_ClearVRAM:
+ ld hl, VRAM_Begin
+ ld bc, VRAM_End - VRAM_Begin
+ xor a
+ call ByteFill
+ ret
+
+PushSGBBorderPalsAndWait:
+ ld hl, MltReq2Packet
+ call PushSGBPals
+ call SGBDelayCycles
+ ld a, [rJOYP]
+ and $3
+ cp $3
+ jr nz, .carry
+ ld a, $20
+ ld [rJOYP], a
+ ld a, [rJOYP]
+ ld a, [rJOYP]
+ call SGBDelayCycles
+ call SGBDelayCycles
+ ld a, $30
+ ld [rJOYP], a
+ call SGBDelayCycles
+ call SGBDelayCycles
+ ld a, $10
+ ld [rJOYP], a
+rept 6
+ ld a, [rJOYP]
+endr
+ call SGBDelayCycles
+ call SGBDelayCycles
+ ld a, $30
+ ld [rJOYP], a
+ ld a, [rJOYP]
+ ld a, [rJOYP]
+ ld a, [rJOYP]
+ call SGBDelayCycles
+ call SGBDelayCycles
+ ld a, [rJOYP]
+ and $3
+ cp $3
+ jr nz, .carry
+ call .FinalPush
+ and a
+ ret
+
+.carry
+ call .FinalPush
+ scf
+ ret
+
+.FinalPush:
+ ld hl, MltReq1Packet
+ call PushSGBPals
+ jp SGBDelayCycles
+
+SGBBorder_PushBGPals:
+ call DisableLCD
+ ld a, %11100100
+ ld [rBGP], a
+ ld hl, PredefPals
+ ld de, vTiles1
+ ld bc, $100 tiles
+ call CopyData
+ call DrawDefaultTiles
+ ld a, LCDC_DEFAULT
+ ld [rLCDC], a
+ ld hl, PalTrnPacket
+ call PushSGBPals
+ xor a
+ ld [rBGP], a
+ ret
+
+SGBBorder_MorePalPushing:
+ call DisableLCD
+ ld a, $e4
+ ld [rBGP], a
+ ld de, vTiles1
+ ld bc, 20 tiles
+ call CopyData
+ ld b, 18
+.loop
+ push bc
+ ld bc, $c
+ call CopyData
+ ld bc, $28
+ call ClearBytes
+ ld bc, $c
+ call CopyData
+ pop bc
+ dec b
+ jr nz, .loop
+ ld bc, $140
+ call CopyData
+ ld bc, Start
+ call ClearBytes
+ ld bc, 16 palettes
+ call CopyData
+ call DrawDefaultTiles
+ ld a, LCDC_DEFAULT
+ ld [rLCDC], a
+ ld hl, PctTrnPacket
+ call PushSGBPals
+ xor a
+ ld [rBGP], a
+ ret
+
+SGBBorder_YetMorePalPushing:
+ call DisableLCD
+ ld a, %11100100
+ ld [rBGP], a
+ ld de, vTiles1
+ ld b, $80
+.loop
+ push bc
+ ld bc, 1 tiles
+ call CopyData
+ ld bc, 1 tiles
+ call ClearBytes
+ pop bc
+ dec b
+ jr nz, .loop
+ call DrawDefaultTiles
+ ld a, LCDC_DEFAULT
+ ld [rLCDC], a
+ ld hl, ChrTrnPacket
+ call PushSGBPals
+ xor a
+ ld [rBGP], a
+ ret
+
+CopyData: ; 0x9a52
+; copy bc bytes of data from hl to de
+.loop
+ ld a, [hli]
+ ld [de], a
+ inc de
+ dec bc
+ ld a, c
+ or b
+ jr nz, .loop
+ ret
+; 0x9a5b
+
+ClearBytes: ; 0x9a5b
+; clear bc bytes of data starting from de
+.loop
+ xor a
+ ld [de], a
+ inc de
+ dec bc
+ ld a, c
+ or b
+ jr nz, .loop
+ ret
+; 0x9a64
+
+DrawDefaultTiles: ; 0x9a64
+; Draw 240 tiles (2/3 of the screen) from tiles in VRAM
+ hlbgcoord 0, 0 ; BG Map 0
+ ld de, BG_MAP_WIDTH - SCREEN_WIDTH
+ ld a, $80 ; starting tile
+ ld c, 12 + 1
+.line
+ ld b, 20
+.tile
+ ld [hli], a
+ inc a
+ dec b
+ jr nz, .tile
+; next line
+ add hl, de
+ dec c
+ jr nz, .line
+ ret
+; 0x9a7a
+
+SGBDelayCycles:
+ ld de, 7000
+.wait
+ nop
+ nop
+ nop
+ dec de
+ ld a, d
+ or e
+ jr nz, .wait
+ ret
+
+INCLUDE "gfx/sgb/blk_packets.asm"
+INCLUDE "gfx/sgb/pal_packets.asm"
+INCLUDE "data/sgb_ctrl_packets.asm"
+
+PredefPals:
+INCLUDE "gfx/sgb/predef.pal"
+
+SGBBorderMap:
+; interleaved tile ids and palette ids
+INCBIN "gfx/sgb/sgb_border.bin"
+
+SGBBorderPalettes:
+INCLUDE "gfx/sgb/sgb_border.pal"
+
+SGBBorder:
+INCBIN "gfx/sgb/sgb_border.2bpp"
+
+HPBarPals:
+INCLUDE "gfx/battle/hp_bar.pal"
+
+ExpBarPalette:
+INCLUDE "gfx/battle/exp_bar.pal"
+
+INCLUDE "data/pokemon/palettes.asm"
+
+INCLUDE "data/trainers/palettes.asm"
+
+LoadMapPals:
+ farcall LoadSpecialMapPalette
+ jr c, .got_pals
+
+ ; Which palette group is based on whether we're outside or inside
+ ld a, [wEnvironment]
+ and 7
+ ld e, a
+ ld d, 0
+ ld hl, EnvironmentColorsPointers
+ add hl, de
+ add hl, de
+ ld a, [hli]
+ ld h, [hl]
+ ld l, a
+ ; Futher refine by time of day
+ ld a, [wTimeOfDayPal]
+ maskbits NUM_DAYTIMES
+ add a
+ add a
+ add a
+ ld e, a
+ ld d, 0
+ add hl, de
+ ld e, l
+ ld d, h
+ ; Switch to palettes WRAM bank
+ ld a, [rSVBK]
+ push af
+ ld a, BANK(wBGPals1)
+ ld [rSVBK], a
+ ld hl, wBGPals1
+ ld b, 8
+.outer_loop
+ ld a, [de] ; lookup index for TilesetBGPalette
+ push de
+ push hl
+ ld l, a
+ ld h, 0
+ add hl, hl
+ add hl, hl
+ add hl, hl
+ ld de, TilesetBGPalette
+ add hl, de
+ ld e, l
+ ld d, h
+ pop hl
+ ld c, 1 palettes
+.inner_loop
+ ld a, [de]
+ inc de
+ ld [hli], a
+ dec c
+ jr nz, .inner_loop
+ pop de
+ inc de
+ dec b
+ jr nz, .outer_loop
+ pop af
+ ld [rSVBK], a
+
+.got_pals
+ ld a, [wTimeOfDayPal]
+ maskbits NUM_DAYTIMES
+ ld bc, 8 palettes
+ ld hl, MapObjectPals
+ call AddNTimes
+ ld de, wOBPals1
+ ld bc, 8 palettes
+ ld a, BANK(wOBPals1)
+ call FarCopyWRAM
+
+ ld a, [wEnvironment]
+ cp TOWN
+ jr z, .outside
+ cp ROUTE
+ ret nz
+.outside
+ ld a, [wMapGroup]
+ ld l, a
+ ld h, 0
+ add hl, hl
+ add hl, hl
+ add hl, hl
+ ld de, RoofPals
+ add hl, de
+ ld a, [wTimeOfDayPal]
+ maskbits NUM_DAYTIMES
+ cp NITE_F
+ jr c, .morn_day
+rept 4
+ inc hl
+endr
+.morn_day
+ ld de, wBGPals1 palette PAL_BG_ROOF color 1
+ ld bc, 4
+ ld a, BANK(wBGPals1)
+ call FarCopyWRAM
+ ret
+
+INCLUDE "data/maps/environment_colors.asm"
+
+PartyMenuBGMobilePalette:
+INCLUDE "gfx/stats/party_menu_bg_mobile.pal"
+
+PartyMenuBGPalette:
+INCLUDE "gfx/stats/party_menu_bg.pal"
+
+TilesetBGPalette:
+INCLUDE "gfx/tilesets/bg_tiles.pal"
+
+MapObjectPals::
+INCLUDE "gfx/overworld/npc_sprites.pal"
+
+RoofPals:
+INCLUDE "gfx/tilesets/roofs.pal"
+
+DiplomaPalettes:
+INCLUDE "gfx/diploma/diploma.pal"
+
+PartyMenuOBPals:
+INCLUDE "gfx/stats/party_menu_ob.pal"
+
+UnusedGSTitleBGPals:
+INCLUDE "gfx/title/unused_gs_bg.pal"
+
+UnusedGSTitleOBPals:
+INCLUDE "gfx/title/unused_gs_fg.pal"
+
+MalePokegearPals:
+INCLUDE "gfx/pokegear/pokegear.pal"
+
+FemalePokegearPals:
+INCLUDE "gfx/pokegear/pokegear_f.pal"
+
+Palettes_SCGB_11:
+INCLUDE "gfx/unknown/b789.pal"
+
+SlotMachinePals:
+INCLUDE "gfx/slots/slots.pal"
diff --git a/engine/gfx/crystal_layouts.asm b/engine/gfx/crystal_layouts.asm
new file mode 100755
index 000000000..0133916e5
--- /dev/null
+++ b/engine/gfx/crystal_layouts.asm
@@ -0,0 +1,325 @@
+GetMysteryGift_MobileAdapterLayout: ; 4930f (mobile)
+ ld a, b
+ cp SCGB_RAM
+ jr nz, .not_ram
+ ld a, [wSGBPredef]
+.not_ram
+ push af
+ farcall ResetBGPals
+ pop af
+ ld l, a
+ ld h, 0
+ add hl, hl
+ ld de, .dw
+ add hl, de
+ ld a, [hli]
+ ld h, [hl]
+ ld l, a
+ ld de, .done
+ push de
+ jp hl
+.done
+ ret
+; 49330 (12:5330)
+
+.dw ; 49330
+ dw MG_Mobile_Layout00
+ dw MG_Mobile_Layout01
+ dw MG_Mobile_Layout02
+; 49336
+
+MG_Mobile_Layout_FillBox: ; 49336
+.row
+ push bc
+ push hl
+.col
+ ld [hli], a
+ dec c
+ jr nz, .col
+ pop hl
+ ld bc, SCREEN_WIDTH
+ add hl, bc
+ pop bc
+ dec b
+ jr nz, .row
+ ret
+; 49346
+
+MG_Mobile_Layout_WipeAttrMap: ; 49346 (12:5346)
+ hlcoord 0, 0, wAttrMap
+ ld bc, SCREEN_HEIGHT * SCREEN_WIDTH
+ xor a
+ call ByteFill
+ ret
+
+MG_Mobile_Layout_LoadPals: ; 49351 (12:5351)
+ ld de, wBGPals1
+ ld hl, Palette_MysteryGiftMobile
+ ld bc, 5 palettes
+ ld a, BANK(wBGPals1)
+ call FarCopyWRAM
+ ld de, wBGPals1 palette PAL_BG_TEXT
+ ld hl, Palette_TextBG7
+ ld bc, 1 palettes
+ ld a, BANK(wBGPals1)
+ call FarCopyWRAM
+ ret
+
+MG_Mobile_Layout00: ; 4936e (12:536e)
+ call MG_Mobile_Layout_LoadPals
+ call MG_Mobile_Layout_WipeAttrMap
+ call MG_Mobile_Layout_CreatePalBoxes
+ farcall ApplyAttrMap
+ farcall ApplyPals
+ ret
+
+MG_Mobile_Layout_CreatePalBoxes: ; 49384 (12:5384)
+ hlcoord 0, 0, wAttrMap
+ lb bc, 4, 1
+ ld a, $1
+ call MG_Mobile_Layout_FillBox
+ lb bc, 2, 1
+ ld a, $2
+ call MG_Mobile_Layout_FillBox
+ lb bc, 6, 1
+ ld a, $3
+ call MG_Mobile_Layout_FillBox
+ hlcoord 1, 0, wAttrMap
+ ld a, $1
+ lb bc, 3, 18
+ call MG_Mobile_Layout_FillBox
+ lb bc, 2, 18
+ ld a, $2
+ call MG_Mobile_Layout_FillBox
+ lb bc, 12, 18
+ ld a, $3
+ call MG_Mobile_Layout_FillBox
+ hlcoord 19, 0, wAttrMap
+ lb bc, 4, 1
+ ld a, $1
+ call MG_Mobile_Layout_FillBox
+ lb bc, 2, 1
+ ld a, $2
+ call MG_Mobile_Layout_FillBox
+ lb bc, 6, 1
+ ld a, $3
+ call MG_Mobile_Layout_FillBox
+ hlcoord 0, 12, wAttrMap
+ ld bc, 6 * SCREEN_WIDTH
+ ld a, $7
+ call ByteFill
+ ret
+; 493e1 (12:53e1)
+
+Palette_MysteryGiftMobile: ; 493e1
+INCLUDE "gfx/mystery_gift/mg_mobile.pal"
+; 49409
+
+LoadOW_BGPal7:: ; 49409
+ ld hl, Palette_TextBG7
+ ld de, wBGPals1 palette PAL_BG_TEXT
+ ld bc, 1 palettes
+ ld a, BANK(wBGPals1)
+ call FarCopyWRAM
+ ret
+; 49418
+
+Palette_TextBG7: ; 49418
+INCLUDE "gfx/font/bg_text.pal"
+; 49420
+
+Function49420:: ; 49420 (12:5420)
+ ld hl, MansionPalette1 + 8 palettes
+ ld de, wBGPals1 palette PAL_BG_ROOF
+ ld bc, 1 palettes
+ ld a, BANK(wBGPals1)
+ call FarCopyWRAM
+ ret
+; 4942f (12:542f)
+
+MG_Mobile_Layout01: ; 4942f
+ call MG_Mobile_Layout_LoadPals
+ ld de, wBGPals1 palette PAL_BG_TEXT
+ ld hl, .Palette_49478
+ ld bc, 1 palettes
+ ld a, BANK(wBGPals1)
+ call FarCopyWRAM
+ call MG_Mobile_Layout_WipeAttrMap
+ hlcoord 0, 0, wAttrMap
+ ld bc, SCREEN_WIDTH * SCREEN_HEIGHT
+ xor a
+ call ByteFill
+ hlcoord 0, 14, wAttrMap
+ ld bc, 4 * SCREEN_WIDTH
+ ld a, $7
+ call ByteFill
+ ld a, [wd002]
+ bit 6, a
+ jr z, .asm_49464
+ call Function49480
+ jr .asm_49467
+
+.asm_49464
+ call Function49496
+
+.asm_49467
+ farcall ApplyAttrMap
+ farcall ApplyPals
+ ld a, $1
+ ld [hCGBPalUpdate], a
+ ret
+; 49478
+
+.Palette_49478: ; 49478
+ RGB 31, 31, 31
+ RGB 26, 31, 00
+ RGB 20, 16, 03
+ RGB 00, 00, 00
+; 49480
+
+Function49480: ; 49480
+ hlcoord 0, 0, wAttrMap
+ lb bc, 4, SCREEN_WIDTH
+ ld a, $7
+ call MG_Mobile_Layout_FillBox
+ hlcoord 0, 2, wAttrMap
+ ld a, $4
+ ld [hl], a
+ hlcoord 19, 2, wAttrMap
+ ld [hl], a
+ ret
+; 49496
+
+Function49496: ; 49496
+ hlcoord 0, 0, wAttrMap
+ lb bc, 2, SCREEN_WIDTH
+ ld a, $7
+ call MG_Mobile_Layout_FillBox
+ hlcoord 0, 1, wAttrMap
+ ld a, $4
+ ld [hl], a
+ hlcoord 19, 1, wAttrMap
+ ld [hl], a
+ ret
+; 494ac
+
+INCLUDE "engine/gfx/tileset_palettes.asm"
+
+MG_Mobile_Layout02: ; 49706
+ ld hl, .Palette_49732
+ ld de, wBGPals1
+ ld bc, 1 palettes
+ ld a, BANK(wBGPals1)
+ call FarCopyWRAM
+ farcall ApplyPals
+ call MG_Mobile_Layout_WipeAttrMap
+ farcall ApplyAttrMap
+ ld hl, .Palette_4973a
+ ld de, wOBPals1
+ ld bc, 1 palettes
+ ld a, BANK(wOBPals1)
+ call FarCopyWRAM
+ ret
+; 49732
+
+.Palette_49732: ; 49732
+ RGB 31, 31, 31
+ RGB 23, 16, 07
+ RGB 23, 07, 07
+ RGB 03, 07, 20
+; 4973a
+
+.Palette_4973a: ; 4973a
+ RGB 00, 00, 00
+ RGB 07, 05, 31
+ RGB 14, 18, 31
+ RGB 31, 31, 31
+; 49742
+
+Function49742: ; 49742
+ ld hl, .Palette_49757
+ ld de, wBGPals1
+ ld bc, 8 palettes
+ ld a, BANK(wBGPals1)
+ call FarCopyWRAM
+ farcall ApplyPals
+ ret
+; 49757
+
+.Palette_49757: ; 49757
+INCLUDE "gfx/unknown/49757.pal"
+; 49797
+
+_InitMG_Mobile_LinkTradePalMap: ; 49797
+ hlcoord 0, 0, wAttrMap
+ lb bc, 16, 2
+ ld a, $4
+ call MG_Mobile_Layout_FillBox
+ ld a, $3
+ ldcoord_a 0, 1, wAttrMap
+ ldcoord_a 0, 14, wAttrMap
+ hlcoord 2, 0, wAttrMap
+ lb bc, 8, 18
+ ld a, $5
+ call MG_Mobile_Layout_FillBox
+ hlcoord 2, 8, wAttrMap
+ lb bc, 8, 18
+ ld a, $6
+ call MG_Mobile_Layout_FillBox
+ hlcoord 0, 16, wAttrMap
+ lb bc, 2, SCREEN_WIDTH
+ ld a, $4
+ call MG_Mobile_Layout_FillBox
+ ld a, $3
+ lb bc, 6, 1
+ hlcoord 6, 1, wAttrMap
+ call MG_Mobile_Layout_FillBox
+ ld a, $3
+ lb bc, 6, 1
+ hlcoord 17, 1, wAttrMap
+ call MG_Mobile_Layout_FillBox
+ ld a, $3
+ lb bc, 6, 1
+ hlcoord 6, 9, wAttrMap
+ call MG_Mobile_Layout_FillBox
+ ld a, $3
+ lb bc, 6, 1
+ hlcoord 17, 9, wAttrMap
+ call MG_Mobile_Layout_FillBox
+ ld a, $2
+ hlcoord 2, 16, wAttrMap
+ ld [hli], a
+ ld a, $7
+ ld [hli], a
+ ld [hli], a
+ ld [hli], a
+ ld a, $2
+ ld [hl], a
+ hlcoord 2, 17, wAttrMap
+ ld a, $3
+ ld bc, 6
+ call ByteFill
+ ret
+; 49811
+
+LoadTradeRoomBGPals: ; 49811
+ ld hl, TradeRoomPalette
+ ld de, wBGPals1 palette PAL_BG_GREEN
+ ld bc, 6 palettes
+ ld a, BANK(wBGPals1)
+ call FarCopyWRAM
+ farcall ApplyPals
+ ret
+; 49826
+
+TradeRoomPalette: ; 49826
+INCLUDE "gfx/trade/border.pal"
+; 49856
+
+InitMG_Mobile_LinkTradePalMap: ; 49856
+ call _InitMG_Mobile_LinkTradePalMap
+ ret
+; 4985a
+
+; unused
+INCLUDE "gfx/unknown/4985a.asm"
diff --git a/engine/gfx/evolution_animation.asm b/engine/gfx/evolution_animation.asm
new file mode 100755
index 000000000..978f9e968
--- /dev/null
+++ b/engine/gfx/evolution_animation.asm
@@ -0,0 +1,368 @@
+EvolutionAnimation: ; 4e5e1
+ push hl
+ push de
+ push bc
+ ld a, [wCurSpecies]
+ push af
+ ld a, [rOBP0]
+ push af
+ ld a, [wBaseDexNo]
+ push af
+
+ call .EvolutionAnimation
+
+ pop af
+ ld [wBaseDexNo], a
+ pop af
+ ld [rOBP0], a
+ pop af
+ ld [wCurSpecies], a
+ pop bc
+ pop de
+ pop hl
+
+ ld a, [wEvolutionCanceled]
+ and a
+ ret z
+
+ scf
+ ret
+; 4e607
+
+.EvolutionAnimation: ; 4e607
+ ld a, %11100100
+ ld [rOBP0], a
+
+ ld de, MUSIC_NONE
+ call PlayMusic
+
+ farcall ClearSpriteAnims
+
+ ld de, .GFX
+ ld hl, vTiles0
+ lb bc, BANK(.GFX), 8
+ call Request2bpp
+
+ xor a
+ ld [wLowHealthAlarm], a
+ call WaitBGMap
+ xor a
+ ld [hBGMapMode], a
+ ld a, [wEvolutionOldSpecies]
+ ld [wPlayerHPPal], a
+
+ ld c, $0
+ call .GetSGBLayout
+ ld a, [wEvolutionOldSpecies]
+ ld [wCurPartySpecies], a
+ ld [wCurSpecies], a
+ call .PlaceFrontpic
+
+ ld de, vTiles2
+ ld hl, vTiles2 tile $31
+ ld bc, 7 * 7
+ call Request2bpp
+
+ ld a, 7 * 7
+ ld [wEvolutionPicOffset], a
+ call .ReplaceFrontpic
+ ld a, [wEvolutionNewSpecies]
+ ld [wCurPartySpecies], a
+ ld [wCurSpecies], a
+ call .LoadFrontpic
+ ld a, [wEvolutionOldSpecies]
+ ld [wCurPartySpecies], a
+ ld [wCurSpecies], a
+
+ ld a, $1
+ ld [hBGMapMode], a
+ call .check_statused
+ jr c, .skip_cry
+
+ ld a, [wEvolutionOldSpecies]
+ call PlayMonCry
+
+.skip_cry
+ ld de, MUSIC_EVOLUTION
+ call PlayMusic
+
+ ld c, 80
+ call DelayFrames
+
+ ld c, $1
+ call .GetSGBLayout
+ call .AnimationSequence
+ jr c, .cancel_evo
+
+ ld a, -7 * 7
+ ld [wEvolutionPicOffset], a
+ call .ReplaceFrontpic
+ xor a
+ ld [wEvolutionCanceled], a
+
+ ld a, [wEvolutionNewSpecies]
+ ld [wPlayerHPPal], a
+
+ ld c, $0
+ call .GetSGBLayout
+ call .PlayEvolvedSFX
+ farcall ClearSpriteAnims
+ call .check_statused
+ jr c, .no_anim
+
+ ld a, [wBoxAlignment]
+ push af
+ ld a, $1
+ ld [wBoxAlignment], a
+ ld a, [wCurPartySpecies]
+ push af
+
+ ld a, [wPlayerHPPal]
+ ld [wCurPartySpecies], a
+ hlcoord 7, 2
+ ld d, $0
+ ld e, ANIM_MON_EVOLVE
+ predef AnimateFrontpic
+
+ pop af
+ ld [wCurPartySpecies], a
+ pop af
+ ld [wBoxAlignment], a
+ ret
+
+.no_anim
+ ret
+
+.cancel_evo
+ ld a, $1
+ ld [wEvolutionCanceled], a
+
+ ld a, [wEvolutionOldSpecies]
+ ld [wPlayerHPPal], a
+
+ ld c, $0
+ call .GetSGBLayout
+ call .PlayEvolvedSFX
+ farcall ClearSpriteAnims
+ call .check_statused
+ ret c
+
+ ld a, [wPlayerHPPal]
+ call PlayMonCry
+ ret
+; 4e703
+
+.GetSGBLayout: ; 4e703
+ ld b, SCGB_EVOLUTION
+ jp GetSGBLayout
+; 4e708
+
+.PlaceFrontpic: ; 4e708
+ call GetBaseData
+ hlcoord 7, 2
+ jp PrepMonFrontpic
+; 4e711
+
+.LoadFrontpic: ; 4e711
+ call GetBaseData
+ ld a, $1
+ ld [wBoxAlignment], a
+ ld de, vTiles2
+ predef GetAnimatedFrontpic
+ xor a
+ ld [wBoxAlignment], a
+ ret
+; 4e726
+
+.AnimationSequence: ; 4e726
+ call ClearJoypad
+ lb bc, 1, 2 * 7 ; flash b times, wait c frames in between
+.loop
+ push bc
+ call .WaitFrames_CheckPressedB
+ pop bc
+ jr c, .exit_sequence
+ push bc
+ call .Flash
+ pop bc
+ inc b
+ dec c
+ dec c
+ jr nz, .loop
+ and a
+ ret
+
+.exit_sequence
+ scf
+ ret
+; 4e741
+
+.Flash: ; 4e741
+ ld a, -7 * 7 ; new stage
+ ld [wEvolutionPicOffset], a
+ call .ReplaceFrontpic
+ ld a, 7 * 7 ; previous stage
+ ld [wEvolutionPicOffset], a
+ call .ReplaceFrontpic
+ dec b
+ jr nz, .Flash
+ ret
+; 4e755
+
+.ReplaceFrontpic: ; 4e755
+ push bc
+ xor a
+ ld [hBGMapMode], a
+ hlcoord 7, 2
+ lb bc, 7, 7
+ ld de, SCREEN_WIDTH - 7
+.loop1
+ push bc
+.loop2
+ ld a, [wEvolutionPicOffset]
+ add [hl]
+ ld [hli], a
+ dec c
+ jr nz, .loop2
+ pop bc
+ add hl, de
+ dec b
+ jr nz, .loop1
+ ld a, $1
+ ld [hBGMapMode], a
+ call WaitBGMap
+ pop bc
+ ret
+; 4e779
+
+.WaitFrames_CheckPressedB: ; 4e779
+ call DelayFrame
+ push bc
+ call JoyTextDelay
+ ld a, [hJoyDown]
+ pop bc
+ and B_BUTTON
+ jr nz, .pressed_b
+.loop3
+ dec c
+ jr nz, .WaitFrames_CheckPressedB
+ and a
+ ret
+
+.pressed_b
+ ld a, [wForceEvolution]
+ and a
+ jr nz, .loop3
+ scf
+ ret
+; 4e794
+
+.check_statused ; 4e794
+ ld a, [wCurPartyMon]
+ ld hl, wPartyMon1Species
+ call GetPartyLocation
+ ld b, h
+ ld c, l
+ farcall CheckFaintedFrzSlp
+ ret
+; 4e7a6
+
+.PlayEvolvedSFX: ; 4e7a6
+ ld a, [wEvolutionCanceled]
+ and a
+ ret nz
+ ld de, SFX_EVOLVED
+ call PlaySFX
+ ld hl, wJumptableIndex
+ ld a, [hl]
+ push af
+ ld [hl], $0
+.loop4
+ call .balls_of_light
+ jr nc, .done
+ call .AnimateBallsOfLight
+ jr .loop4
+
+.done
+ ld c, 32
+.loop5
+ call .AnimateBallsOfLight
+ dec c
+ jr nz, .loop5
+ pop af
+ ld [wJumptableIndex], a
+ ret
+; 4e7cf
+
+.balls_of_light ; 4e7cf
+ ld hl, wJumptableIndex
+ ld a, [hl]
+ cp 32
+ ret nc
+ ld d, a
+ inc [hl]
+ and $1
+ jr nz, .done_balls
+ ld e, $0
+ call .GenerateBallOfLight
+ ld e, $10
+ call .GenerateBallOfLight
+
+.done_balls
+ scf
+ ret
+; 4e7e8
+
+.GenerateBallOfLight: ; 4e7e8
+ push de
+ depixel 9, 11
+ ld a, SPRITE_ANIM_INDEX_EVOLUTION_BALL_OF_LIGHT
+ call _InitSpriteAnimStruct
+ ld hl, SPRITEANIMSTRUCT_JUMPTABLE_INDEX
+ add hl, bc
+ ld a, [wJumptableIndex]
+ and %1110
+ sla a
+ pop de
+ add e
+ ld [hl], a
+ ld hl, SPRITEANIMSTRUCT_TILE_ID
+ add hl, bc
+ ld [hl], $0
+ ld hl, SPRITEANIMSTRUCT_0C
+ add hl, bc
+ ld [hl], $10
+ ret
+; 4e80c
+
+.AnimateBallsOfLight: ; 4e80c
+ push bc
+ callfar PlaySpriteAnimations
+ ; a = (([hVBlankCounter] + 4) / 2) % NUM_PALETTES
+ ld a, [hVBlankCounter]
+ and %1110
+ srl a
+ inc a
+ inc a
+ and $7
+ ld b, a
+ ld hl, wVirtualOAMSprite00Attributes
+ ld c, NUM_SPRITE_OAM_STRUCTS
+.loop6
+ ld a, [hl]
+ or b
+ ld [hli], a ; attributes
+rept SPRITEOAMSTRUCT_LENGTH + -1
+ inc hl
+endr
+ dec c
+ jr nz, .loop6
+ pop bc
+ call DelayFrame
+ ret
+; 4e831
+
+
+.GFX:
+INCBIN "gfx/evo/bubble_large.2bpp"
+INCBIN "gfx/evo/bubble.2bpp"
diff --git a/engine/gfx/gbc_only.asm b/engine/gfx/gbc_only.asm
new file mode 100644
index 000000000..badd953aa
--- /dev/null
+++ b/engine/gfx/gbc_only.asm
@@ -0,0 +1,149 @@
+GBCOnlyScreen: ; 4ea82
+
+ ld a, [hCGB]
+ and a
+ ret nz
+
+ ld de, MUSIC_NONE
+ call PlayMusic
+
+ call ClearTileMap
+
+ ld hl, GBCOnlyGFX
+ ld de, wGBCOnlyDecompressBuffer
+ ld a, [rSVBK]
+ push af
+ ld a, 0 ; this has the same effect as selecting bank 1
+ ld [rSVBK], a
+ call Decompress
+ pop af
+ ld [rSVBK], a
+
+ ld de, wGBCOnlyDecompressBuffer
+ ld hl, vTiles2
+ lb bc, BANK(GBCOnlyGFX), 84
+ call Get2bpp
+
+ ld de, Font
+ ld hl, vTiles1
+ lb bc, BANK(Font), $80
+ call Get1bpp
+
+ call DrawGBCOnlyScreen
+
+ call WaitBGMap
+
+; better luck next time
+.loop
+ call DelayFrame
+ jr .loop
+; 4eac5
+
+
+DrawGBCOnlyScreen: ; 4eac5
+
+ call DrawGBCOnlyBorder
+
+ ; Pokemon
+ hlcoord 3, 2
+ ld b, 14
+ ld c, 4
+ ld a, $8
+ call DrawGBCOnlyGraphic
+
+ ; Crystal
+ hlcoord 5, 6
+ ld b, 10
+ ld c, 2
+ ld a, $40
+ call DrawGBCOnlyGraphic
+
+ ld de, GBCOnlyString
+ hlcoord 1, 10
+ call PlaceString
+
+ ret
+; 4eaea
+
+
+DrawGBCOnlyBorder: ; 4eaea
+
+ hlcoord 0, 0
+ ld [hl], 0 ; top-left
+
+ inc hl
+ ld a, 1 ; top
+ call .FillRow
+
+ ld [hl], 2 ; top-right
+
+ hlcoord 0, 1
+ ld a, 3 ; left
+ call .FillColumn
+
+ hlcoord 19, 1
+ ld a, 4 ; right
+ call .FillColumn
+
+ hlcoord 0, 17
+ ld [hl], 5 ; bottom-left
+
+ inc hl
+ ld a, 6 ; bottom
+ call .FillRow
+
+ ld [hl], 7 ; bottom-right
+ ret
+; 4eb15
+
+.FillRow: ; 4eb15
+ ld c, SCREEN_WIDTH - 2
+.next_column
+ ld [hli], a
+ dec c
+ jr nz, .next_column
+ ret
+; 4eb1c
+
+.FillColumn: ; 4eb1c
+ ld de, SCREEN_WIDTH
+ ld c, SCREEN_HEIGHT - 2
+.next_row
+ ld [hl], a
+ add hl, de
+ dec c
+ jr nz, .next_row
+ ret
+; 4eb27
+
+
+DrawGBCOnlyGraphic: ; 4eb27
+ ld de, SCREEN_WIDTH
+.y
+ push bc
+ push hl
+.x
+ ld [hli], a
+ inc a
+ dec b
+ jr nz, .x
+ pop hl
+ add hl, de
+ pop bc
+ dec c
+ jr nz, .y
+ ret
+; 4eb38
+
+
+GBCOnlyString: ; 4eb38
+ db "This Game Pak is"
+ next "designed only for"
+ next "use on the"
+ next "Game Boy Color.@"
+; 4eb76
+
+
+GBCOnlyGFX: ; 4eb76
+INCBIN "gfx/sgb/gbc_only.2bpp.lz"
+; 4f0bc
diff --git a/engine/gfx/load_font.asm b/engine/gfx/load_font.asm
new file mode 100644
index 000000000..40dbb9c10
--- /dev/null
+++ b/engine/gfx/load_font.asm
@@ -0,0 +1,156 @@
+INCLUDE "gfx/font.asm"
+
+; This and the following two functions are unreferenced.
+; Debug, perhaps?
+Unreferenced_fb434:
+ db 0
+
+Unreferenced_Functionfb435: ; 4b435
+ ld a, [Unreferenced_fb434]
+ and a
+ jp nz, Get1bpp_2
+ jp Get1bpp
+; fb43f
+
+Unreferenced_Functionfb43f: ; fb43f
+ ld a, [Unreferenced_fb434]
+ and a
+ jp nz, Get2bpp_2
+ jp Get2bpp
+; End unreferenced block
+; fb449
+
+_LoadStandardFont:: ; fb449
+ ld de, Font
+ ld hl, vTiles1
+ lb bc, BANK(Font), 128 ; "A" to "9"
+ ld a, [rLCDC]
+ bit rLCDC_ENABLE, a
+ jp z, Copy1bpp
+
+ ld de, Font
+ ld hl, vTiles1
+ lb bc, BANK(Font), 32 ; "A" to "]"
+ call Get1bpp_2
+ ld de, Font + 32 * LEN_1BPP_TILE
+ ld hl, vTiles1 tile $20
+ lb bc, BANK(Font), 32 ; "a" to $bf
+ call Get1bpp_2
+ ld de, Font + 64 * LEN_1BPP_TILE
+ ld hl, vTiles1 tile $40
+ lb bc, BANK(Font), 32 ; "Ä" to "←"
+ call Get1bpp_2
+ ld de, Font + 96 * LEN_1BPP_TILE
+ ld hl, vTiles1 tile $60
+ lb bc, BANK(Font), 32 ; "'" to "9"
+ call Get1bpp_2
+ ret
+; fb48a
+
+_LoadFontsExtra1:: ; fb48a
+ ld de, FontsExtra_SolidBlackGFX
+ ld hl, vTiles2 tile "■" ; $60
+ lb bc, BANK(FontsExtra_SolidBlackGFX), 1
+ call Get1bpp_2
+ ld de, PokegearPhoneIconGFX
+ ld hl, vTiles2 tile "☎" ; $62
+ lb bc, BANK(PokegearPhoneIconGFX), 1
+ call Get2bpp_2
+ ld de, FontExtra + 3 tiles ; "<BOLD_D>"
+ ld hl, vTiles2 tile "<BOLD_D>"
+ lb bc, BANK(FontExtra), 22 ; "<BOLD_D>" to "ぉ"
+ call Get2bpp_2
+ jr LoadFrame
+; fb4b0
+
+_LoadFontsExtra2:: ; fb4b0
+ ld de, FontsExtra2_UpArrowGFX
+ ld hl, vTiles2 tile "▲" ; $61
+ ld b, BANK(FontsExtra2_UpArrowGFX)
+ ld c, 1
+ call Get2bpp_2
+ ret
+; fb4be
+
+_LoadFontsBattleExtra:: ; fb4be
+ ld de, FontBattleExtra
+ ld hl, vTiles2 tile $60
+ lb bc, BANK(FontBattleExtra), 25
+ call Get2bpp_2
+ jr LoadFrame
+; fb4cc
+
+LoadFrame: ; fb4cc
+ ld a, [wTextBoxFrame]
+ maskbits NUM_FRAMES
+ ld bc, 6 * LEN_1BPP_TILE
+ ld hl, Frames
+ call AddNTimes
+ ld d, h
+ ld e, l
+ ld hl, vTiles2 tile "┌" ; $79
+ lb bc, BANK(Frames), 6 ; "┌" to "┘"
+ call Get1bpp_2
+ ld hl, vTiles2 tile " " ; $7f
+ ld de, TextBoxSpaceGFX
+ lb bc, BANK(TextBoxSpaceGFX), 1
+ call Get1bpp_2
+ ret
+; fb4f2
+
+LoadBattleFontsHPBar: ; fb4f2
+ ld de, FontBattleExtra
+ ld hl, vTiles2 tile $60
+ lb bc, BANK(FontBattleExtra), 12
+ call Get2bpp_2
+ ld hl, vTiles2 tile $70
+ ld de, FontBattleExtra + 16 tiles ; "<DO>"
+ lb bc, BANK(FontBattleExtra), 3 ; "<DO>" to "『"
+ call Get2bpp_2
+ call LoadFrame
+
+LoadHPBar: ; fb50d
+ ld de, EnemyHPBarBorderGFX
+ ld hl, vTiles2 tile $6c
+ lb bc, BANK(EnemyHPBarBorderGFX), 4
+ call Get1bpp_2
+ ld de, HPExpBarBorderGFX
+ ld hl, vTiles2 tile $73
+ lb bc, BANK(HPExpBarBorderGFX), 6
+ call Get1bpp_2
+ ld de, ExpBarGFX
+ ld hl, vTiles2 tile $55
+ lb bc, BANK(ExpBarGFX), 9
+ call Get2bpp_2
+ ld de, MobilePhoneTilesGFX + 7 tiles ; mobile phone icon
+ ld hl, vTiles2 tile $5e
+ lb bc, BANK(MobilePhoneTilesGFX), 2
+ call Get2bpp_2
+ ret
+; fb53e
+
+StatsScreen_LoadFont: ; fb53e
+ call _LoadFontsBattleExtra
+ ld de, EnemyHPBarBorderGFX
+ ld hl, vTiles2 tile $6c
+ lb bc, BANK(EnemyHPBarBorderGFX), 4
+ call Get1bpp_2
+ ld de, HPExpBarBorderGFX
+ ld hl, vTiles2 tile $78
+ lb bc, BANK(HPExpBarBorderGFX), 1
+ call Get1bpp_2
+ ld de, HPExpBarBorderGFX + 3 * LEN_1BPP_TILE
+ ld hl, vTiles2 tile $76
+ lb bc, BANK(HPExpBarBorderGFX), 2
+ call Get1bpp_2
+ ld de, ExpBarGFX
+ ld hl, vTiles2 tile $55
+ lb bc, BANK(ExpBarGFX), 8
+ call Get2bpp_2
+LoadStatsScreenPageTilesGFX: ; fb571
+ ld de, StatsScreenPageTilesGFX
+ ld hl, vTiles2 tile $31
+ lb bc, BANK(StatsScreenPageTilesGFX), 17
+ call Get2bpp_2
+ ret
+; fb57e
diff --git a/engine/gfx/load_pics.asm b/engine/gfx/load_pics.asm
new file mode 100755
index 000000000..b533ee56b
--- /dev/null
+++ b/engine/gfx/load_pics.asm
@@ -0,0 +1,491 @@
+GetUnownLetter: ; 51040
+; Return Unown letter in wUnownLetter based on DVs at hl
+
+; Take the middle 2 bits of each DV and place them in order:
+; atk def spd spc
+; .ww..xx. .yy..zz.
+
+ ; atk
+ ld a, [hl]
+ and %01100000
+ sla a
+ ld b, a
+ ; def
+ ld a, [hli]
+ and %00000110
+ swap a
+ srl a
+ or b
+ ld b, a
+
+ ; spd
+ ld a, [hl]
+ and %01100000
+ swap a
+ sla a
+ or b
+ ld b, a
+ ; spc
+ ld a, [hl]
+ and %00000110
+ srl a
+ or b
+
+; Divide by 10 to get 0-25
+ ld [hDividend + 3], a
+ xor a
+ ld [hDividend], a
+ ld [hDividend + 1], a
+ ld [hDividend + 2], a
+ ld a, $ff / NUM_UNOWN + 1
+ ld [hDivisor], a
+ ld b, 4
+ call Divide
+
+; Increment to get 1-26
+ ld a, [hQuotient + 2]
+ inc a
+ ld [wUnownLetter], a
+ ret
+
+GetMonFrontpic: ; 51077
+ ld a, [wCurPartySpecies]
+ ld [wCurSpecies], a
+ call IsAPokemon
+ ret c
+ ld a, [rSVBK]
+ push af
+ call _GetFrontpic
+ pop af
+ ld [rSVBK], a
+ ret
+
+GetAnimatedFrontpic: ; 5108b
+ ld a, [wCurPartySpecies]
+ ld [wCurSpecies], a
+ call IsAPokemon
+ ret c
+ ld a, [rSVBK]
+ push af
+ xor a
+ ld [hBGMapMode], a
+ call _GetFrontpic
+ call GetAnimatedEnemyFrontpic
+ pop af
+ ld [rSVBK], a
+ ret
+
+_GetFrontpic: ; 510a5
+ push de
+ call GetBaseData
+ ld a, [wBasePicSize]
+ and $f
+ ld b, a
+ push bc
+ call GetFrontpicPointer
+ ld a, BANK(wDecompressEnemyFrontpic)
+ ld [rSVBK], a
+ ld a, b
+ ld de, wDecompressEnemyFrontpic
+ call FarDecompress
+ pop bc
+ ld hl, wDecompressScratch
+ ld de, wDecompressEnemyFrontpic
+ call PadFrontpic
+ pop hl
+ push hl
+ ld de, wDecompressScratch
+ ld c, 7 * 7
+ ld a, [hROMBank]
+ ld b, a
+ call Get2bpp
+ pop hl
+ ret
+
+GetFrontpicPointer: ; 510d7
+ ld a, [wCurPartySpecies]
+ cp UNOWN
+ jr z, .unown
+ ld a, [wCurPartySpecies]
+ ld d, BANK(PokemonPicPointers)
+ jr .ok
+
+.unown
+ ld a, [wUnownLetter]
+ ld d, BANK(UnownPicPointers)
+
+.ok
+ ld hl, PokemonPicPointers ; UnownPicPointers
+ dec a
+ ld bc, 6
+ call AddNTimes
+ ld a, d
+ call GetFarByte
+ call FixPicBank
+ push af
+ inc hl
+ ld a, d
+ call GetFarHalfword
+ pop bc
+ ret
+
+GetAnimatedEnemyFrontpic: ; 51103
+ ld a, BANK(vTiles3)
+ ld [rVBK], a
+ push hl
+ ld de, wDecompressScratch
+ ld c, 7 * 7
+ ld a, [hROMBank]
+ ld b, a
+ call Get2bpp
+ pop hl
+ ld de, 7 * 7 tiles
+ add hl, de
+ push hl
+ ld a, BANK(wBasePicSize)
+ ld hl, wBasePicSize
+ call GetFarWRAMByte
+ pop hl
+ and $f
+ ld de, wDecompressEnemyFrontpic + 5 * 5 tiles
+ ld c, 5 * 5
+ cp 5
+ jr z, .got_dims
+ ld de, wDecompressEnemyFrontpic + 6 * 6 tiles
+ ld c, 6 * 6
+ cp 6
+ jr z, .got_dims
+ ld de, wDecompressEnemyFrontpic + 7 * 7 tiles
+ ld c, 7 * 7
+.got_dims
+
+ push hl
+ push bc
+ call LoadFrontpicTiles
+ pop bc
+ pop hl
+ ld de, wDecompressScratch
+ ld a, [hROMBank]
+ ld b, a
+ call Get2bpp
+ xor a
+ ld [rVBK], a
+ ret
+
+LoadFrontpicTiles: ; 5114f
+ ld hl, wDecompressScratch
+ swap c
+ ld a, c
+ and $f
+ ld b, a
+ ld a, c
+ and $f0
+ ld c, a
+ push bc
+ call LoadOrientedFrontpic
+ pop bc
+.loop
+ push bc
+ ld c, 0
+ call LoadOrientedFrontpic
+ pop bc
+ dec b
+ jr nz, .loop
+ ret
+
+GetMonBackpic: ; 5116c
+ ld a, [wCurPartySpecies]
+ call IsAPokemon
+ ret c
+
+ ld a, [wCurPartySpecies]
+ ld b, a
+ ld a, [wUnownLetter]
+ ld c, a
+ ld a, [rSVBK]
+ push af
+ ld a, BANK(wDecompressScratch)
+ ld [rSVBK], a
+ push de
+
+ ; These are assumed to be at the same address in their respective banks.
+ ld hl, PokemonPicPointers ; UnownPicPointers
+ ld a, b
+ ld d, BANK(PokemonPicPointers)
+ cp UNOWN
+ jr nz, .ok
+ ld a, c
+ ld d, BANK(UnownPicPointers)
+.ok
+ dec a
+ ld bc, 6
+ call AddNTimes
+ ld bc, 3
+ add hl, bc
+ ld a, d
+ call GetFarByte
+ call FixPicBank
+ push af
+ inc hl
+ ld a, d
+ call GetFarHalfword
+ ld de, wDecompressScratch
+ pop af
+ call FarDecompress
+ ld hl, wDecompressScratch
+ ld c, 6 * 6
+ call FixBackpicAlignment
+ pop hl
+ ld de, wDecompressScratch
+ ld a, [hROMBank]
+ ld b, a
+ call Get2bpp
+ pop af
+ ld [rSVBK], a
+ ret
+
+FixPicBank: ; 511c5
+; This is a thing for some reason.
+
+PICS_FIX EQU $36
+GLOBAL PICS_FIX
+
+ push hl
+ push bc
+ sub BANK(Pics_1) - PICS_FIX
+ ld c, a
+ ld b, 0
+ ld hl, .PicsBanks
+ add hl, bc
+ ld a, [hl]
+ pop bc
+ pop hl
+ ret
+
+.PicsBanks: ; 511d4
+ db BANK(Pics_1) + 0
+ db BANK(Pics_1) + 1
+ db BANK(Pics_1) + 2
+ db BANK(Pics_1) + 3
+ db BANK(Pics_1) + 4
+ db BANK(Pics_1) + 5
+ db BANK(Pics_1) + 6
+ db BANK(Pics_1) + 7
+ db BANK(Pics_1) + 8
+ db BANK(Pics_1) + 9
+ db BANK(Pics_1) + 10
+ db BANK(Pics_1) + 11
+ db BANK(Pics_1) + 12
+ db BANK(Pics_1) + 13
+ db BANK(Pics_1) + 14
+ db BANK(Pics_1) + 15
+ db BANK(Pics_1) + 16
+ db BANK(Pics_1) + 17
+ db BANK(Pics_1) + 18
+ db BANK(Pics_1) + 19
+ db BANK(Pics_1) + 20
+ db BANK(Pics_1) + 21
+ db BANK(Pics_1) + 22
+ db BANK(Pics_1) + 23
+
+Function511ec: ; 511ec
+ ld a, c
+ push de
+ ld hl, PokemonPicPointers
+ dec a
+ ld bc, 6
+ call AddNTimes
+ ld a, BANK(PokemonPicPointers)
+ call GetFarByte
+ call FixPicBank
+ push af
+ inc hl
+ ld a, BANK(PokemonPicPointers)
+ call GetFarHalfword
+ pop af
+ pop de
+ call FarDecompress
+ ret
+
+GetTrainerPic: ; 5120d
+ ld a, [wTrainerClass]
+ and a
+ ret z
+ cp NUM_TRAINER_CLASSES
+ ret nc
+ call WaitBGMap
+ xor a
+ ld [hBGMapMode], a
+ ld hl, TrainerPicPointers
+ ld a, [wTrainerClass]
+ dec a
+ ld bc, 3
+ call AddNTimes
+ ld a, [rSVBK]
+ push af
+ ld a, BANK(wDecompressScratch)
+ ld [rSVBK], a
+ push de
+ ld a, BANK(TrainerPicPointers)
+ call GetFarByte
+ call FixPicBank
+ push af
+ inc hl
+ ld a, BANK(TrainerPicPointers)
+ call GetFarHalfword
+ pop af
+ ld de, wDecompressScratch
+ call FarDecompress
+ pop hl
+ ld de, wDecompressScratch
+ ld c, 7 * 7
+ ld a, [hROMBank]
+ ld b, a
+ call Get2bpp
+ pop af
+ ld [rSVBK], a
+ call WaitBGMap
+ ld a, $1
+ ld [hBGMapMode], a
+ ret
+
+DecompressGet2bpp: ; 5125d
+; Decompress lz data from b:hl to scratch space at 6:d000, then copy it to address de.
+
+ ld a, [rSVBK]
+ push af
+ ld a, BANK(wDecompressScratch)
+ ld [rSVBK], a
+
+ push de
+ push bc
+ ld a, b
+ ld de, wDecompressScratch
+ call FarDecompress
+ pop bc
+ ld de, wDecompressScratch
+ pop hl
+ ld a, [hROMBank]
+ ld b, a
+ call Get2bpp
+
+ pop af
+ ld [rSVBK], a
+ ret
+
+FixBackpicAlignment: ; 5127c
+ push de
+ push bc
+ ld a, [wBoxAlignment]
+ and a
+ jr z, .keep_dims
+ ld a, c
+ cp 7 * 7
+ ld de, 7 * 7 tiles
+ jr z, .got_dims
+ cp 6 * 6
+ ld de, 6 * 6 tiles
+ jr z, .got_dims
+ ld de, 5 * 5 tiles
+
+.got_dims
+ ld a, [hl]
+ ld b, 0
+ ld c, 8
+.loop
+ rra
+ rl b
+ dec c
+ jr nz, .loop
+ ld a, b
+ ld [hli], a
+ dec de
+ ld a, e
+ or d
+ jr nz, .got_dims
+
+.keep_dims
+ pop bc
+ pop de
+ ret
+
+PadFrontpic: ; 512ab
+; pads frontpic to fill 7x7 box
+ ld a, b
+ cp 6
+ jr z, .six
+ cp 5
+ jr z, .five
+
+.seven_loop
+ ld c, $70
+ call LoadOrientedFrontpic
+ dec b
+ jr nz, .seven_loop
+ ret
+
+.six
+ ld c, $70
+ xor a
+ call .Fill
+.six_loop
+ ld c, $10
+ xor a
+ call .Fill
+ ld c, $60
+ call LoadOrientedFrontpic
+ dec b
+ jr nz, .six_loop
+ ret
+
+.five
+ ld c, $70
+ xor a
+ call .Fill
+.five_loop
+ ld c, $20
+ xor a
+ call .Fill
+ ld c, $50
+ call LoadOrientedFrontpic
+ dec b
+ jr nz, .five_loop
+ ld c, $70
+ xor a
+ call .Fill
+ ret
+
+.Fill:
+ ld [hli], a
+ dec c
+ jr nz, .Fill
+ ret
+
+LoadOrientedFrontpic: ; 512f2
+ ld a, [wBoxAlignment]
+ and a
+ jr nz, .x_flip
+.left_loop
+ ld a, [de]
+ inc de
+ ld [hli], a
+ dec c
+ jr nz, .left_loop
+ ret
+
+.x_flip
+ push bc
+.right_loop
+ ld a, [de]
+ inc de
+ ld b, a
+ xor a
+rept 8
+ rr b
+ rla
+endr
+ ld [hli], a
+ dec c
+ jr nz, .right_loop
+ pop bc
+ ret
diff --git a/engine/gfx/map_palettes.asm b/engine/gfx/map_palettes.asm
new file mode 100644
index 000000000..a9d2b382f
--- /dev/null
+++ b/engine/gfx/map_palettes.asm
@@ -0,0 +1,86 @@
+SwapTextboxPalettes:: ; 4c000
+ hlcoord 0, 0
+ decoord 0, 0, wAttrMap
+ ld b, SCREEN_HEIGHT
+.loop
+ push bc
+ ld c, SCREEN_WIDTH
+.innerloop
+ ld a, [hl]
+ push hl
+ srl a
+ jr c, .UpperNybble
+ ld hl, wTilesetPalettes
+ add [hl]
+ ld l, a
+ ld a, [wTilesetPalettes + 1]
+ adc 0
+ ld h, a
+ ld a, [hl]
+ and $f
+ jr .next
+
+.UpperNybble:
+ ld hl, wTilesetPalettes
+ add [hl]
+ ld l, a
+ ld a, [wTilesetPalettes + 1]
+ adc 0
+ ld h, a
+ ld a, [hl]
+ swap a
+ and $f
+
+.next
+ pop hl
+ ld [de], a
+ res 7, [hl]
+ inc hl
+ inc de
+ dec c
+ jr nz, .innerloop
+ pop bc
+ dec b
+ jr nz, .loop
+ ret
+
+ScrollBGMapPalettes:: ; 4c03f
+ ld hl, wBGMapBuffer
+ ld de, wBGMapPalBuffer
+.loop
+ ld a, [hl]
+ push hl
+ srl a
+ jr c, .UpperNybble
+
+; .LowerNybble
+ ld hl, wTilesetPalettes
+ add [hl]
+ ld l, a
+ ld a, [wTilesetPalettes + 1]
+ adc 0
+ ld h, a
+ ld a, [hl]
+ and $f
+ jr .next
+
+.UpperNybble:
+ ld hl, wTilesetPalettes
+ add [hl]
+ ld l, a
+ ld a, [wTilesetPalettes + 1]
+ adc 0
+ ld h, a
+ ld a, [hl]
+ swap a
+ and $f
+
+.next
+ pop hl
+ ld [de], a
+ res 7, [hl]
+ inc hl
+ inc de
+ dec c
+ jr nz, .loop
+ ret
diff --git a/engine/gfx/mapgroup_roofs.asm b/engine/gfx/mapgroup_roofs.asm
new file mode 100644
index 000000000..58e5e7cfe
--- /dev/null
+++ b/engine/gfx/mapgroup_roofs.asm
@@ -0,0 +1,20 @@
+LoadMapGroupRoof:: ; 1c000
+ ld a, [wMapGroup]
+ ld e, a
+ ld d, 0
+ ld hl, MapGroupRoofs
+ add hl, de
+ ld a, [hl]
+ cp -1
+ ret z
+ ld hl, Roofs
+ ld bc, 9 tiles
+ call AddNTimes
+ ld de, vTiles2 tile $0a
+ ld bc, 9 tiles
+ call CopyBytes
+ ret
+; 1c021
+
+
+INCLUDE "data/maps/roofs.asm"
diff --git a/engine/gfx/mon_icons.asm b/engine/gfx/mon_icons.asm
new file mode 100755
index 000000000..5a26d2d7c
--- /dev/null
+++ b/engine/gfx/mon_icons.asm
@@ -0,0 +1,471 @@
+LoadOverworldMonIcon: ; 8e82b
+ ld a, e
+ call ReadMonMenuIcon
+ ld l, a
+ ld h, 0
+ add hl, hl
+ ld de, IconPointers
+ add hl, de
+ ld a, [hli]
+ ld e, a
+ ld d, [hl]
+ ld b, BANK(Icons)
+ ld c, 8
+ ret
+; 8e83f
+
+LoadMenuMonIcon: ; 8e83f
+ push hl
+ push de
+ push bc
+ call .LoadIcon
+ pop bc
+ pop de
+ pop hl
+ ret
+; 8e849
+
+.LoadIcon: ; 8e849
+ ld d, 0
+ ld hl, .Jumptable
+ add hl, de
+ add hl, de
+ ld a, [hli]
+ ld h, [hl]
+ ld l, a
+ jp hl
+; 8e854
+
+
+.Jumptable: ; 8e854 (23:6854)
+ dw PartyMenu_InitAnimatedMonIcon ; party menu
+ dw NamingScreen_InitAnimatedMonIcon ; naming screen
+ dw MoveList_InitAnimatedMonIcon ; moves (?)
+ dw Trade_LoadMonIconGFX ; trade
+ dw Mobile_InitAnimatedMonIcon ; mobile
+ dw Mobile_InitPartyMenuBGPal71 ; mobile
+ dw .GetPartyMenuMonIcon ; unused
+
+.GetPartyMenuMonIcon: ; 8e862 (23:6862)
+ call InitPartyMenuIcon
+ call .GetPartyMonItemGFX
+ call SetPartyMonIconAnimSpeed
+ ret
+
+.GetPartyMonItemGFX: ; 8e86c (23:686c)
+ push bc
+ ld a, [hObjectStructIndexBuffer]
+ ld hl, wPartyMon1Item
+ ld bc, PARTYMON_STRUCT_LENGTH
+ call AddNTimes
+ pop bc
+ ld a, [hl]
+ and a
+ jr z, .no_item
+ push hl
+ push bc
+ ld d, a
+ callfar ItemIsMail
+ pop bc
+ pop hl
+ jr c, .not_mail
+ ld a, $6
+ jr .got_tile
+.not_mail
+ ld a, $5
+ ; jr .got_tile
+
+.no_item
+ ld a, $4
+.got_tile
+ ld hl, SPRITEANIMSTRUCT_FRAMESET_ID
+ add hl, bc
+ ld [hl], a
+ ret
+
+Mobile_InitAnimatedMonIcon: ; 8e898 (23:6898)
+ call PartyMenu_InitAnimatedMonIcon
+ ld hl, SPRITEANIMSTRUCT_ANIM_SEQ_ID
+ add hl, bc
+ ld a, SPRITE_ANIM_SEQ_NULL
+ ld [hl], a
+ ld hl, SPRITEANIMSTRUCT_XCOORD
+ add hl, bc
+ ld a, 9 * 8
+ ld [hl], a
+ ld hl, SPRITEANIMSTRUCT_YCOORD
+ add hl, bc
+ ld a, 9 * 8
+ ld [hl], a
+ ret
+
+Mobile_InitPartyMenuBGPal71: ; 8e8b1 (23:68b1)
+ call InitPartyMenuIcon
+ call SetPartyMonIconAnimSpeed
+ ld hl, SPRITEANIMSTRUCT_ANIM_SEQ_ID
+ add hl, bc
+ ld a, SPRITE_ANIM_SEQ_NULL
+ ld [hl], a
+ ld hl, SPRITEANIMSTRUCT_XCOORD
+ add hl, bc
+ ld a, 3 * 8
+ ld [hl], a
+ ld hl, SPRITEANIMSTRUCT_YCOORD
+ add hl, bc
+ ld a, 12 * 8
+ ld [hl], a
+ ld a, c
+ ld [wc608], a
+ ld a, b
+ ld [wc608 + 1], a
+ ret
+
+PartyMenu_InitAnimatedMonIcon: ; 8e8d5 (23:68d5)
+ call InitPartyMenuIcon
+ call .SpawnItemIcon
+ call SetPartyMonIconAnimSpeed
+ ret
+
+.SpawnItemIcon: ; 8e8df (23:68df)
+ push bc
+ ld a, [hObjectStructIndexBuffer]
+ ld hl, wPartyMon1Item
+ ld bc, PARTYMON_STRUCT_LENGTH
+ call AddNTimes
+ pop bc
+ ld a, [hl]
+ and a
+ ret z
+ push hl
+ push bc
+ ld d, a
+ callfar ItemIsMail
+ pop bc
+ pop hl
+ jr c, .mail
+ ld a, SPRITE_ANIM_FRAMESET_PARTY_MON_WITH_ITEM
+ jr .okay
+
+.mail
+ ld a, SPRITE_ANIM_FRAMESET_PARTY_MON_WITH_MAIL
+.okay
+ ld hl, SPRITEANIMSTRUCT_FRAMESET_ID
+ add hl, bc
+ ld [hl], a
+ ret
+
+InitPartyMenuIcon: ; 8e908 (23:6908)
+ ld a, [wCurIconTile]
+ push af
+ ld a, [hObjectStructIndexBuffer]
+ ld hl, wPartySpecies
+ ld e, a
+ ld d, $0
+ add hl, de
+ ld a, [hl]
+ call ReadMonMenuIcon
+ ld [wCurIcon], a
+ call GetMemIconGFX
+ ld a, [hObjectStructIndexBuffer]
+; y coord
+ add a
+ add a
+ add a
+ add a
+ add $1c
+ ld d, a
+; x coord
+ ld e, $10
+; type is partymon icon
+ ld a, SPRITE_ANIM_INDEX_PARTY_MON
+ call InitSpriteAnimStruct
+ pop af
+ ld hl, SPRITEANIMSTRUCT_TILE_ID
+ add hl, bc
+ ld [hl], a
+ ret
+
+SetPartyMonIconAnimSpeed: ; 8e936 (23:6936)
+ push bc
+ ld a, [hObjectStructIndexBuffer]
+ ld b, a
+ call .getspeed
+ ld a, b
+ pop bc
+ ld hl, SPRITEANIMSTRUCT_DURATIONOFFSET
+ add hl, bc
+ ld [hl], a
+ rlca
+ rlca
+ ld hl, SPRITEANIMSTRUCT_0D
+ add hl, bc
+ ld [hl], a
+ ret
+
+.getspeed ; 8e94c (23:694c)
+ farcall PlacePartymonHPBar
+ call GetHPPal
+ ld e, d
+ ld d, 0
+ ld hl, .speeds
+ add hl, de
+ ld b, [hl]
+ ret
+; 8e95e (23:695e)
+
+.speeds ; 8e95e
+ db $00 ; HP_GREEN
+ db $40 ; HP_YELLOW
+ db $80 ; HP_RED
+; 8e961
+
+NamingScreen_InitAnimatedMonIcon: ; 8e961 (23:6961)
+ ld a, [wd265]
+ call ReadMonMenuIcon
+ ld [wCurIcon], a
+ xor a
+ call GetIconGFX
+ depixel 4, 4, 4, 0
+ ld a, SPRITE_ANIM_INDEX_PARTY_MON
+ call InitSpriteAnimStruct
+ ld hl, SPRITEANIMSTRUCT_ANIM_SEQ_ID
+ add hl, bc
+ ld [hl], SPRITE_ANIM_SEQ_NULL
+ ret
+
+MoveList_InitAnimatedMonIcon: ; 8e97d (23:697d)
+ ld a, [wd265]
+ call ReadMonMenuIcon
+ ld [wCurIcon], a
+ xor a
+ call GetIconGFX
+ ld d, 3 * 8 + 2 ; depixel 3, 4, 2, 4
+ ld e, 4 * 8 + 4
+ ld a, SPRITE_ANIM_INDEX_PARTY_MON
+ call InitSpriteAnimStruct
+ ld hl, SPRITEANIMSTRUCT_ANIM_SEQ_ID
+ add hl, bc
+ ld [hl], SPRITE_ANIM_SEQ_NULL
+ ret
+
+Trade_LoadMonIconGFX: ; 8e99a (23:699a)
+ ld a, [wd265]
+ call ReadMonMenuIcon
+ ld [wCurIcon], a
+ ld a, $62
+ ld [wCurIconTile], a
+ call GetMemIconGFX
+ ret
+
+GetSpeciesIcon: ; 8e9ac
+; Load species icon into VRAM at tile a
+ push de
+ ld a, [wd265]
+ call ReadMonMenuIcon
+ ld [wCurIcon], a
+ pop de
+ ld a, e
+ call GetIconGFX
+ ret
+; 8e9bc
+
+
+FlyFunction_GetMonIcon: ; 8e9bc (23:69bc)
+ push de
+ ld a, [wd265]
+ call ReadMonMenuIcon
+ ld [wCurIcon], a
+ pop de
+ ld a, e
+ call GetIcon_a
+ ret
+; 8e9cc (23:69cc)
+
+Unreferenced_GetMonIcon2: ; 8e9cc
+ push de
+ ld a, [wd265]
+ call ReadMonMenuIcon
+ ld [wCurIcon], a
+ pop de
+ call GetIcon_de
+ ret
+; 8e9db
+
+GetMemIconGFX: ; 8e9db (23:69db)
+ ld a, [wCurIconTile]
+GetIconGFX: ; 8e9de
+ call GetIcon_a
+ ld de, 8 tiles
+ add hl, de
+ ld de, HeldItemIcons
+ lb bc, BANK(HeldItemIcons), 2
+ call GetGFXUnlessMobile
+ ld a, [wCurIconTile]
+ add 10
+ ld [wCurIconTile], a
+ ret
+
+HeldItemIcons:
+INCBIN "gfx/icons/mail.2bpp"
+INCBIN "gfx/icons/item.2bpp"
+; 8ea17
+
+GetIcon_de: ; 8ea17
+; Load icon graphics into VRAM starting from tile de.
+ ld l, e
+ ld h, d
+ jr GetIcon
+
+GetIcon_a: ; 8ea1b
+; Load icon graphics into VRAM starting from tile a.
+ ld l, a
+ ld h, 0
+
+GetIcon: ; 8ea1e
+; Load icon graphics into VRAM starting from tile hl.
+
+; One tile is 16 bytes long.
+rept 4
+ add hl, hl
+endr
+
+ ld de, vTiles0
+ add hl, de
+ push hl
+
+; The icons are contiguous, in order and of the same
+; size, so the pointer table is somewhat redundant.
+ ld a, [wCurIcon]
+ push hl
+ ld l, a
+ ld h, 0
+ add hl, hl
+ ld de, IconPointers
+ add hl, de
+ ld a, [hli]
+ ld e, a
+ ld d, [hl]
+ pop hl
+
+ lb bc, BANK(Icons), 8
+ call GetGFXUnlessMobile
+
+ pop hl
+ ret
+; 8ea3f
+
+GetGFXUnlessMobile: ; 8ea3f
+ ld a, [wLinkMode]
+ cp LINK_MOBILE
+ jp nz, Request2bpp
+ jp Get2bpp_2
+; 8ea4a
+
+FreezeMonIcons: ; 8ea4a
+ ld hl, wSpriteAnimationStructs
+ ld e, PARTY_LENGTH
+ ld a, [wMenuCursorY]
+ ld d, a
+.loop
+ ld a, [hl]
+ and a
+ jr z, .next
+ cp d
+ jr z, .loadwithtwo
+ ld a, SPRITE_ANIM_SEQ_NULL
+ jr .ok
+
+.loadwithtwo
+ ld a, SPRITE_ANIM_SEQ_PARTY_MON_SWITCH
+
+.ok
+ push hl
+ ld c, l
+ ld b, h
+ ld hl, SPRITEANIMSTRUCT_ANIM_SEQ_ID
+ add hl, bc
+ ld [hl], a
+ pop hl
+
+.next
+ ld bc, $10
+ add hl, bc
+ dec e
+ jr nz, .loop
+ ret
+; 8ea71
+
+UnfreezeMonIcons: ; 8ea71
+ ld hl, wSpriteAnimationStructs
+ ld e, PARTY_LENGTH
+.loop
+ ld a, [hl]
+ and a
+ jr z, .next
+ push hl
+ ld c, l
+ ld b, h
+ ld hl, SPRITEANIMSTRUCT_ANIM_SEQ_ID
+ add hl, bc
+ ld [hl], SPRITE_ANIM_SEQ_PARTY_MON
+ pop hl
+.next
+ ld bc, $10
+ add hl, bc
+ dec e
+ jr nz, .loop
+ ret
+; 8ea8c (23:6a8c)
+
+HoldSwitchmonIcon: ; 8ea8c
+ ld hl, wSpriteAnimationStructs
+ ld e, PARTY_LENGTH
+ ld a, [wSwitchMon]
+ ld d, a
+.loop
+ ld a, [hl]
+ and a
+ jr z, .next
+ cp d
+ jr z, .is_switchmon
+ ld a, SPRITE_ANIM_SEQ_PARTY_MON_SELECTED
+ jr .join_back
+
+.is_switchmon
+ ld a, SPRITE_ANIM_SEQ_PARTY_MON_SWITCH
+.join_back
+ push hl
+ ld c, l
+ ld b, h
+ ld hl, SPRITEANIMSTRUCT_ANIM_SEQ_ID
+ add hl, bc
+ ld [hl], a
+ pop hl
+.next
+ ld bc, $10
+ add hl, bc
+ dec e
+ jr nz, .loop
+ ret
+
+ReadMonMenuIcon: ; 8eab3
+ cp EGG
+ jr z, .egg
+ dec a
+ ld hl, MonMenuIcons
+ ld e, a
+ ld d, 0
+ add hl, de
+ ld a, [hl]
+ ret
+.egg
+ ld a, ICON_EGG
+ ret
+; 8eac4
+
+
+INCLUDE "data/pokemon/menu_icons.asm"
+
+INCLUDE "data/icon_pointers.asm"
+
+INCLUDE "gfx/icons.asm"
diff --git a/engine/gfx/pic_animation.asm b/engine/gfx/pic_animation.asm
new file mode 100644
index 000000000..8781c2fd0
--- /dev/null
+++ b/engine/gfx/pic_animation.asm
@@ -0,0 +1,1141 @@
+; Pic animation arrangement.
+
+Unused_AnimateMon_Slow_Normal: ; d0000
+ hlcoord 12, 0
+ ld a, [wBattleMode]
+ cp WILD_BATTLE
+ jr z, .wild
+ ld e, ANIM_MON_SLOW
+ ld d, $0
+ call AnimateFrontpic
+ ret
+
+.wild
+ ld e, ANIM_MON_NORMAL
+ ld d, $0
+ call AnimateFrontpic
+ ret
+; d001a
+
+AnimateMon_Menu: ; d001a
+ ld e, ANIM_MON_MENU
+ ld d, $0
+ call AnimateFrontpic
+ ret
+; d0022
+
+AnimateMon_Trade: ; d0022
+ ld e, ANIM_MON_TRADE
+ ld d, $0
+ call AnimateFrontpic
+ ret
+; d002a
+
+AnimateMon_Evolve: ; d002a
+ ld e, ANIM_MON_EVOLVE
+ ld d, $0
+ call AnimateFrontpic
+ ret
+; d0032
+
+AnimateMon_Hatch: ; d0032
+ ld e, ANIM_MON_HATCH
+ ld d, $0
+ call AnimateFrontpic
+ ret
+; d003a
+
+AnimateMon_Unused: ; d003a
+ ld e, ANIM_MON_UNUSED
+ ld d, $0
+ call AnimateFrontpic
+ ret
+; d0042
+
+pokeanim: MACRO
+ rept _NARG
+; Workaround for a bug where macro args can't come after the start of a symbol
+if !DEF(\1_POKEANIM)
+\1_POKEANIM EQUS "PokeAnim_\1_"
+endc
+ db (\1_POKEANIM - PokeAnim_SetupCommands) / 2
+ shift
+ endr
+ db (PokeAnim_Finish_ - PokeAnim_SetupCommands) / 2
+ENDM
+
+PokeAnims: ; d0042
+ dw .Slow
+ dw .Normal
+ dw .Menu
+ dw .Trade
+ dw .Evolve
+ dw .Hatch
+ dw .Unused ; same as .Menu
+ dw .Egg1
+ dw .Egg2
+
+.Slow: pokeanim StereoCry, Setup2, Play
+.Normal: pokeanim StereoCry, Setup, Play
+.Menu: pokeanim CryNoWait, Setup, Play, SetWait, Wait, Idle, Play
+.Trade: pokeanim Idle, Play2, Idle, Play, SetWait, Wait, Cry, Setup, Play
+.Evolve: pokeanim Idle, Play, SetWait, Wait, CryNoWait, Setup, Play
+.Hatch: pokeanim Idle, Play, CryNoWait, Setup, Play, SetWait, Wait, Idle, Play
+.Unused: pokeanim CryNoWait, Setup, Play, SetWait, Wait, Idle, Play
+.Egg1: pokeanim Setup, Play
+.Egg2: pokeanim Idle, Play
+
+
+AnimateFrontpic: ; d008e
+ call AnimateMon_CheckIfPokemon
+ ret c
+ call LoadMonAnimation
+.loop
+ call SetUpPokeAnim
+ push af
+ farcall HDMATransferTileMapToWRAMBank3
+ pop af
+ jr nc, .loop
+ ret
+; d00a3
+
+LoadMonAnimation: ; d00a3
+ push hl
+ ld c, e
+ ld b, 0
+ ld hl, PokeAnims
+ add hl, bc
+ add hl, bc
+ ld a, [hli]
+ ld b, [hl]
+ ld c, a
+ pop hl
+ call PokeAnim_InitPicAttributes
+ ret
+; d00b4
+
+SetUpPokeAnim: ; d00b4
+ ld a, [rSVBK]
+ push af
+ ld a, BANK(wPokeAnimSceneIndex)
+ ld [rSVBK], a
+ ld a, [wPokeAnimSceneIndex]
+ ld c, a
+ ld b, 0
+ ld hl, wPokeAnimPointer
+ ld a, [hli]
+ ld h, [hl]
+ ld l, a
+ add hl, bc
+ ld a, [hl]
+ ld hl, PokeAnim_SetupCommands
+ rst JumpTable
+ ld a, [wPokeAnimSceneIndex]
+ ld c, a
+ pop af
+ ld [rSVBK], a
+ ld a, c
+ and $80
+ ret z
+ scf
+ ret
+; d00da
+
+PokeAnim_SetupCommands: ; d00da
+setup_command: MACRO
+\1_: dw \1
+ENDM
+ setup_command PokeAnim_Finish
+ setup_command PokeAnim_BasePic
+ setup_command PokeAnim_SetWait
+ setup_command PokeAnim_Wait
+ setup_command PokeAnim_Setup
+ setup_command PokeAnim_Setup2
+ setup_command PokeAnim_Idle
+ setup_command PokeAnim_Play
+ setup_command PokeAnim_Play2
+ setup_command PokeAnim_Cry
+ setup_command PokeAnim_CryNoWait
+ setup_command PokeAnim_StereoCry
+; d00f2
+
+PokeAnim_SetWait: ; d00f2
+ ld a, 18
+ ld [wPokeAnimWaitCounter], a
+ ld a, [wPokeAnimSceneIndex]
+ inc a
+ ld [wPokeAnimSceneIndex], a
+
+PokeAnim_Wait: ; d00fe
+ ld hl, wPokeAnimWaitCounter
+ dec [hl]
+ ret nz
+ ld a, [wPokeAnimSceneIndex]
+ inc a
+ ld [wPokeAnimSceneIndex], a
+ ret
+; d010b
+
+PokeAnim_Setup: ; d010b
+ ld c, FALSE
+ ld b, 0
+ call PokeAnim_InitAnim
+ call PokeAnim_SetVBank1
+ ld a, [wPokeAnimSceneIndex]
+ inc a
+ ld [wPokeAnimSceneIndex], a
+ ret
+; d011d
+
+PokeAnim_Setup2: ; d011d
+ ld c, FALSE
+ ld b, 4
+ call PokeAnim_InitAnim
+ call PokeAnim_SetVBank1
+ ld a, [wPokeAnimSceneIndex]
+ inc a
+ ld [wPokeAnimSceneIndex], a
+ ret
+; d012f
+
+PokeAnim_Idle: ; d012f
+ ld c, TRUE
+ ld b, 0
+ call PokeAnim_InitAnim
+ call PokeAnim_SetVBank1
+ ld a, [wPokeAnimSceneIndex]
+ inc a
+ ld [wPokeAnimSceneIndex], a
+ ret
+; d0141
+
+PokeAnim_Play: ; d0141
+ call PokeAnim_DoAnimScript
+ ld a, [wPokeAnimJumptableIndex]
+ bit 7, a
+ ret z
+ call PokeAnim_PlaceGraphic
+ ld a, [wPokeAnimSceneIndex]
+ inc a
+ ld [wPokeAnimSceneIndex], a
+ ret
+; d0155
+
+PokeAnim_Play2: ; d0155
+ call PokeAnim_DoAnimScript
+ ld a, [wPokeAnimJumptableIndex]
+ bit 7, a
+ ret z
+ ld a, [wPokeAnimSceneIndex]
+ inc a
+ ld [wPokeAnimSceneIndex], a
+ ret
+; d0166
+
+PokeAnim_BasePic: ; d0166
+ call PokeAnim_DeinitFrames
+ ld a, [wPokeAnimSceneIndex]
+ inc a
+ ld [wPokeAnimSceneIndex], a
+ ret
+; d0171
+
+PokeAnim_Finish: ; d0171
+ call PokeAnim_DeinitFrames
+ ld hl, wPokeAnimSceneIndex
+ set 7, [hl]
+ ret
+; d017a
+
+PokeAnim_Cry: ; d017a
+ ld a, [wPokeAnimSpecies]
+ call _PlayMonCry
+ ld a, [wPokeAnimSceneIndex]
+ inc a
+ ld [wPokeAnimSceneIndex], a
+ ret
+; d0188
+
+PokeAnim_CryNoWait: ; d0188
+ ld a, [wPokeAnimSpecies]
+ call PlayMonCry2
+ ld a, [wPokeAnimSceneIndex]
+ inc a
+ ld [wPokeAnimSceneIndex], a
+ ret
+; d0196
+
+PokeAnim_StereoCry: ; d0196
+ ld a, $f
+ ld [wCryTracks], a
+ ld a, [wPokeAnimSpecies]
+ call PlayStereoCry2
+ ld a, [wPokeAnimSceneIndex]
+ inc a
+ ld [wPokeAnimSceneIndex], a
+ ret
+; d01a9
+
+PokeAnim_DeinitFrames: ; d01a9
+ ld a, [rSVBK]
+ push af
+ ld a, BANK(wPokeAnimCoord)
+ ld [rSVBK], a
+ call PokeAnim_PlaceGraphic
+ farcall HDMATransferTileMapToWRAMBank3
+ call PokeAnim_SetVBank0
+ farcall HDMATransferAttrMapToWRAMBank3
+ pop af
+ ld [rSVBK], a
+ ret
+; d01c6
+
+AnimateMon_CheckIfPokemon: ; d01c6
+ ld a, [wCurPartySpecies]
+ cp EGG
+ jr z, .fail
+ call IsAPokemon
+ jr c, .fail
+ and a
+ ret
+
+.fail
+ scf
+ ret
+; d01d6
+
+PokeAnim_InitPicAttributes: ; d01d6
+ ld a, [rSVBK]
+ push af
+ ld a, BANK(wPokeAnimSceneIndex)
+ ld [rSVBK], a
+
+ push bc
+ push de
+ push hl
+ ld hl, wPokeAnimSceneIndex
+ ld bc, wPokeAnimStructEnd - wPokeAnimSceneIndex
+ xor a
+ call ByteFill
+ pop hl
+ pop de
+ pop bc
+
+; bc contains anim pointer
+ ld a, c
+ ld [wPokeAnimPointer], a
+ ld a, b
+ ld [wPokeAnimPointer + 1], a
+; hl contains tilemap coords
+ ld a, l
+ ld [wPokeAnimCoord], a
+ ld a, h
+ ld [wPokeAnimCoord + 1], a
+; d = start tile
+ ld a, d
+ ld [wPokeAnimGraphicStartTile], a
+
+ ld a, BANK(wCurPartySpecies)
+ ld hl, wCurPartySpecies
+ call GetFarWRAMByte
+ ld [wPokeAnimSpecies], a
+
+ ld a, BANK(wUnownLetter)
+ ld hl, wUnownLetter
+ call GetFarWRAMByte
+ ld [wPokeAnimUnownLetter], a
+
+ call PokeAnim_GetSpeciesOrUnown
+ ld [wPokeAnimSpeciesOrUnown], a
+
+ call PokeAnim_GetFrontpicDims
+ ld a, c
+ ld [wPokeAnimFrontpicHeight], a
+
+ pop af
+ ld [rSVBK], a
+ ret
+; d0228
+
+PokeAnim_InitAnim: ; d0228
+ ld a, [rSVBK]
+ push af
+ ld a, BANK(wPokeAnimIdleFlag)
+ ld [rSVBK], a
+ push bc
+ ld hl, wPokeAnimIdleFlag
+ ld bc, wPokeAnimStructEnd - wPokeAnimIdleFlag
+ xor a
+ call ByteFill
+ pop bc
+ ld a, b
+ ld [wPokeAnimSpeed], a
+ ld a, c
+ ld [wPokeAnimIdleFlag], a
+ call GetMonAnimPointer
+ call GetMonFramesPointer
+ call GetMonBitmaskPointer
+ pop af
+ ld [rSVBK], a
+ ret
+; d0250
+
+PokeAnim_DoAnimScript: ; d0250
+ xor a
+ ld [hBGMapMode], a
+.loop
+ ld a, [wPokeAnimJumptableIndex]
+ and $7f
+ ld hl, .Jumptable
+ rst JumpTable
+ ret
+; d025d
+
+.Jumptable: ; d025d
+ dw .RunAnim
+ dw .WaitAnim
+; d0261
+
+.RunAnim: ; d0261
+ call PokeAnim_GetPointer
+ ld a, [wPokeAnimCommand]
+ cp -1
+ jr z, PokeAnim_End
+ cp -2
+ jr z, .SetRepeat
+ cp -3
+ jr z, .DoRepeat
+ call PokeAnim_GetFrame
+ ld a, [wPokeAnimParameter]
+ call PokeAnim_GetDuration
+ ld [wPokeAnimWaitCounter], a
+ call PokeAnim_StartWaitAnim
+.WaitAnim: ; d0282
+ ld a, [wPokeAnimWaitCounter]
+ dec a
+ ld [wPokeAnimWaitCounter], a
+ ret nz
+ call PokeAnim_StopWaitAnim
+ ret
+; d028e
+
+.SetRepeat: ; d028e
+ ld a, [wPokeAnimParameter]
+ ld [wPokeAnimRepeatTimer], a
+ jr .loop
+; d0296
+
+.DoRepeat: ; d0296
+ ld a, [wPokeAnimRepeatTimer]
+ and a
+ ret z
+ dec a
+ ld [wPokeAnimRepeatTimer], a
+ ret z
+ ld a, [wPokeAnimParameter]
+ ld [wPokeAnimFrame], a
+ jr .loop
+; d02a8
+
+PokeAnim_End: ; d02a8
+ ld hl, wPokeAnimJumptableIndex
+ set 7, [hl]
+ ret
+; d02ae
+
+PokeAnim_GetDuration: ; d02ae
+; a * (1 + [wPokeAnimSpeed] / 16)
+ ld c, a
+ ld b, $0
+ ld hl, 0
+ ld a, [wPokeAnimSpeed]
+ call AddNTimes
+ ld a, h
+ swap a
+ and $f0
+ ld h, a
+ ld a, l
+ swap a
+ and $f
+ or h
+ add c
+ ret
+; d02c8
+
+PokeAnim_GetFrame: ; d02c8
+ call PokeAnim_PlaceGraphic
+ ld a, [wPokeAnimCommand]
+ and a
+ ret z
+ call PokeAnim_GetBitmaskIndex
+ push hl
+ call PokeAnim_CopyBitmaskToBuffer
+ pop hl
+ call PokeAnim_ConvertAndApplyBitmask
+ ret
+; d02dc
+
+PokeAnim_StartWaitAnim: ; d02dc
+ ld a, [wPokeAnimJumptableIndex]
+ inc a
+ ld [wPokeAnimJumptableIndex], a
+ ret
+; d02e4
+
+PokeAnim_StopWaitAnim: ; d02e4
+ ld a, [wPokeAnimJumptableIndex]
+ dec a
+ ld [wPokeAnimJumptableIndex], a
+ ret
+; d02ec
+
+PokeAnim_IsUnown: ; d02ec
+ ld a, [wPokeAnimSpecies]
+ cp UNOWN
+ ret
+; d02f2
+
+PokeAnim_IsEgg: ; d02f2
+ ld a, [wPokeAnimSpecies]
+ cp EGG
+ ret
+; d02f8
+
+PokeAnim_GetPointer: ; d02f8
+ push hl
+ ld a, [wPokeAnimFrame]
+ ld e, a
+ ld d, $0
+ ld hl, wPokeAnimPointerAddr
+ ld a, [hli]
+ ld h, [hl]
+ ld l, a
+ add hl, de
+ add hl, de
+ ld a, [wPokeAnimPointerBank]
+ call GetFarHalfword
+ ld a, l
+ ld [wPokeAnimCommand], a
+ ld a, h
+ ld [wPokeAnimParameter], a
+ ld hl, wPokeAnimFrame
+ inc [hl]
+ pop hl
+ ret
+; d031b
+
+PokeAnim_GetBitmaskIndex: ; d031b
+ ld a, [wPokeAnimCommand]
+ dec a
+ ld c, a
+ ld b, $0
+ ld hl, wPokeAnimFramesAddr
+ ld a, [hli]
+ ld h, [hl]
+ ld l, a
+ add hl, bc
+ add hl, bc
+ ld a, [wPokeAnimFramesBank]
+ call GetFarHalfword
+ ld a, [wPokeAnimFramesBank]
+ call GetFarByte
+ ld [wPokeAnimCurBitmask], a
+ inc hl
+ ret
+; d033b
+
+PokeAnim_CopyBitmaskToBuffer: ; d033b
+ call .GetSize
+ push bc
+ ld hl, wPokeAnimBitmaskAddr
+ ld a, [hli]
+ ld h, [hl]
+ ld l, a
+ ld a, [wPokeAnimCurBitmask]
+ call AddNTimes
+ pop bc
+ ld de, wPokeAnimBitmaskBuffer
+ ld a, [wPokeAnimBitmaskBank]
+ call FarCopyBytes
+ ret
+; d0356
+
+.GetSize: ; d0356
+ push hl
+ ld a, [wPokeAnimFrontpicHeight]
+ sub 5 ; to get a number 0, 1, or 2
+ ld c, a
+ ld b, 0
+ ld hl, .Sizes
+ add hl, bc
+ ld c, [hl]
+ ld b, 0
+ pop hl
+ ret
+; d0368
+
+.Sizes: db 4, 5, 7
+
+poke_anim_box: MACRO
+y = 7
+rept \1
+x = 7 + -\1
+rept \1
+ db x + y
+x = x + 1
+endr
+y = y + 7
+endr
+ENDM
+
+PokeAnim_ConvertAndApplyBitmask: ; d036b
+ xor a
+ ld [wPokeAnimBitmaskCurBit], a
+ ld [wPokeAnimBitmaskCurRow], a
+ ld [wPokeAnimBitmaskCurCol], a
+.loop
+ push hl
+ call .IsCurBitSet
+ pop hl
+ ld a, b
+ and a
+ jr z, .next
+
+ ld a, [wPokeAnimFramesBank]
+ call GetFarByte
+ inc hl
+ push hl
+ call .ApplyFrame
+ pop hl
+
+.next
+ push hl
+ call .NextBit
+ pop hl
+ jr nc, .loop
+ ret
+; d0392
+
+.IsCurBitSet: ; d0392
+; which byte
+ ld a, [wPokeAnimBitmaskCurBit]
+ and $f8
+ rrca
+ rrca
+ rrca
+ ld e, a
+ ld d, 0
+ ld hl, wPokeAnimBitmaskBuffer
+ add hl, de
+ ld b, [hl]
+; which bit
+ ld a, [wPokeAnimBitmaskCurBit]
+ and $7
+ jr z, .skip
+
+ ld c, a
+ ld a, b
+.loop2
+ rrca
+ dec c
+ jr nz, .loop2
+ ld b, a
+
+.skip
+ xor a
+ bit 0, b
+ jr z, .finish
+ ld a, 1
+
+.finish
+ ld b, a
+ ld hl, wPokeAnimBitmaskCurBit
+ inc [hl]
+ ret
+; d03bd
+
+.ApplyFrame: ; d03bd
+ push af
+ call .GetCoord
+ pop af
+ push hl
+ call .GetTilemap
+ ld hl, wPokeAnimGraphicStartTile
+ add [hl]
+ pop hl
+ ld [hl], a
+ ret
+; d03cd
+
+.GetCoord: ; d03cd
+ call .GetStartCoord
+ ld a, [wPokeAnimBitmaskCurRow]
+ ld bc, SCREEN_WIDTH
+ call AddNTimes
+ ld a, [wBoxAlignment]
+ and a
+ jr nz, .go
+ ld a, [wPokeAnimBitmaskCurCol]
+ ld e, a
+ ld d, 0
+ add hl, de
+ jr .skip2
+
+.go
+ ld a, [wPokeAnimBitmaskCurCol]
+ ld e, a
+ ld a, l
+ sub e
+ ld l, a
+ ld a, h
+ sbc 0
+ ld h, a
+
+.skip2
+ ret
+; d03f4
+
+; unused
+ db 6, 5, 4
+
+.GetTilemap: ; d03f7
+ push af
+ ld a, [wPokeAnimFrontpicHeight]
+ cp 5
+ jr z, .check_add_24
+ cp 6
+ jr z, .check_add_13
+ pop af
+ ret
+
+.check_add_24
+ pop af
+ cp 5 * 5
+ jr nc, .add_24
+ push hl
+ push de
+ ld hl, ._5by5
+ ld e, a
+ ld d, 0
+ add hl, de
+ ld a, [hl]
+ pop de
+ pop hl
+ ret
+
+.add_24
+ add 24
+ ret
+
+.check_add_13
+ pop af
+ cp 6 * 6
+ jr nc, .add_13
+ push hl
+ push de
+ ld hl, ._6by6
+ ld e, a
+ ld d, 0
+ add hl, de
+ ld a, [hl]
+ pop de
+ pop hl
+ ret
+
+.add_13
+ add 13
+ ret
+; d042f
+
+._5by5:
+ poke_anim_box 5
+ ; db 9, 10, 11, 12, 13
+ ; db 16, 17, 18, 19, 20
+ ; db 23, 24, 25, 26, 27
+ ; db 30, 31, 32, 33, 34
+ ; db 37, 38, 39, 40, 41
+
+._6by6:
+ poke_anim_box 6
+ ; db 8, 9, 10, 11, 12, 13
+ ; db 15, 16, 17, 18, 19, 20
+ ; db 22, 23, 24, 25, 26, 27
+ ; db 29, 30, 31, 32, 33, 34
+ ; db 36, 37, 38, 39, 40, 41
+ ; db 43, 44, 45, 46, 47, 48
+
+
+.GetStartCoord: ; d046c
+ ld hl, wPokeAnimCoord
+ ld a, [hli]
+ ld h, [hl]
+ ld l, a
+
+ ld a, [wPokeAnimFrontpicHeight]
+ ld de, 0
+ ld bc, 6
+ cp 7
+ jr z, .okay
+ ld de, SCREEN_WIDTH + 1
+ ld bc, SCREEN_WIDTH + 5
+ cp 6
+ jr z, .okay
+ ld de, 2 * SCREEN_WIDTH + 1
+ ld bc, 2 * SCREEN_WIDTH + 5
+.okay
+
+ ld a, [wBoxAlignment]
+ and a
+ jr nz, .add_bc
+ add hl, de
+ ret
+
+.add_bc
+ add hl, bc
+ ret
+; d0499
+
+.NextBit: ; d0499
+ ld a, [wPokeAnimBitmaskCurRow]
+ inc a
+ ld [wPokeAnimBitmaskCurRow], a
+ ld c, a
+ ld a, [wPokeAnimFrontpicHeight]
+ cp c
+ jr nz, .no_carry
+ xor a
+ ld [wPokeAnimBitmaskCurRow], a
+ ld a, [wPokeAnimBitmaskCurCol]
+ inc a
+ ld [wPokeAnimBitmaskCurCol], a
+ ld c, a
+ ld a, [wPokeAnimFrontpicHeight]
+ cp c
+ jr nz, .no_carry
+ scf
+ ret
+
+.no_carry
+ xor a
+ ret
+; d04bd
+
+PokeAnim_PlaceGraphic: ; d04bd
+ call .ClearBox
+ ld a, [wBoxAlignment]
+ and a
+ jr nz, .flipped
+ ld de, 1
+ ld bc, 0
+ jr .okay
+
+.flipped
+ ld de, -1
+ ld bc, 6
+
+.okay
+ ld hl, wPokeAnimCoord
+ ld a, [hli]
+ ld h, [hl]
+ ld l, a
+ add hl, bc
+ ld c, 7
+ ld b, 7
+ ld a, [wPokeAnimGraphicStartTile]
+.loop
+ push bc
+ push hl
+ push de
+ ld de, SCREEN_WIDTH
+.loop2
+ ld [hl], a
+ inc a
+ add hl, de
+ dec b
+ jr nz, .loop2
+ pop de
+ pop hl
+ add hl, de
+ pop bc
+ dec c
+ jr nz, .loop
+ ret
+; d04f6
+
+.ClearBox: ; d04f6
+ ld hl, wPokeAnimCoord
+ ld a, [hli]
+ ld h, [hl]
+ ld l, a
+ ld b, 7
+ ld c, 7
+ call ClearBox
+ ret
+; d0504
+
+PokeAnim_SetVBank1: ; d0504
+ ld a, [rSVBK]
+ push af
+ ld a, BANK(wPokeAnimCoord)
+ ld [rSVBK], a
+ xor a
+ ld [hBGMapMode], a
+ call .SetFlag
+ farcall HDMATransferAttrMapToWRAMBank3
+ pop af
+ ld [rSVBK], a
+ ret
+; d051b
+
+.SetFlag: ; d051b
+ call PokeAnim_GetAttrMapCoord
+ ld b, 7
+ ld c, 7
+ ld de, SCREEN_WIDTH
+.row
+ push bc
+ push hl
+.col
+ ld a, [hl]
+ or 8
+ ld [hl], a
+ add hl, de
+ dec c
+ jr nz, .col
+ pop hl
+ inc hl
+ pop bc
+ dec b
+ jr nz, .row
+ ret
+; d0536
+
+PokeAnim_SetVBank0: ; d0536
+ call PokeAnim_GetAttrMapCoord
+ ld b, 7
+ ld c, 7
+ ld de, SCREEN_WIDTH
+.row
+ push bc
+ push hl
+.col
+ ld a, [hl]
+ and $f7
+ ld [hl], a
+ add hl, de
+ dec c
+ jr nz, .col
+ pop hl
+ inc hl
+ pop bc
+ dec b
+ jr nz, .row
+ ret
+; d0551
+
+PokeAnim_GetAttrMapCoord: ; d0551
+ ld hl, wPokeAnimCoord
+ ld a, [hli]
+ ld h, [hl]
+ ld l, a
+ ld de, wAttrMap - wTileMap
+ add hl, de
+ ret
+; d055c
+
+GetMonAnimPointer: ; d055c
+ call PokeAnim_IsEgg
+ jr z, .egg
+
+ ld c, BANK(UnownAnimations)
+ ld hl, UnownAnimationPointers
+ ld de, UnownAnimationIdlePointers
+ call PokeAnim_IsUnown
+ jr z, .unown
+ ld c, BANK(PicAnimations)
+ ld hl, AnimationPointers
+ ld de, AnimationIdlePointers
+.unown
+
+ ld a, [wPokeAnimIdleFlag]
+ and a
+ jr z, .idles
+ ld h, d
+ ld l, e
+.idles
+
+ ld a, [wPokeAnimSpeciesOrUnown]
+ dec a
+ ld e, a
+ ld d, 0
+ add hl, de
+ add hl, de
+ ld a, c
+ ld [wPokeAnimPointerBank], a
+ call GetFarHalfword
+ ld a, l
+ ld [wPokeAnimPointerAddr], a
+ ld a, h
+ ld [wPokeAnimPointerAddr + 1], a
+ ret
+
+.egg
+ ld hl, EggAnimation
+ ld c, BANK(EggAnimation)
+ ld a, [wPokeAnimIdleFlag]
+ and a
+ jr z, .idles_egg
+ ld hl, EggAnimationIdle
+ ld c, BANK(EggAnimationIdle)
+.idles_egg
+
+ ld a, c
+ ld [wPokeAnimPointerBank], a
+ ld a, l
+ ld [wPokeAnimPointerAddr], a
+ ld a, h
+ ld [wPokeAnimPointerAddr + 1], a
+ ret
+; d05b4
+
+PokeAnim_GetFrontpicDims: ; d05b4
+ ld a, [rSVBK]
+ push af
+ ld a, BANK(wCurPartySpecies)
+ ld [rSVBK], a
+ ld a, [wCurPartySpecies]
+ ld [wCurSpecies], a
+ call GetBaseData
+ ld a, [wBasePicSize]
+ and $f
+ ld c, a
+ pop af
+ ld [rSVBK], a
+ ret
+; d05ce
+
+GetMonFramesPointer: ; d05ce
+ call PokeAnim_IsEgg
+ jr z, .egg
+
+ call PokeAnim_IsUnown
+ ld b, BANK(UnownFramesPointers)
+ ld c, BANK(UnownsFrames)
+ ld hl, UnownFramesPointers
+ jr z, .got_frames
+ ld a, [wPokeAnimSpecies]
+ cp JOHTO_POKEMON
+ ld b, BANK(FramesPointers)
+ ld c, BANK(KantoFrames)
+ ld hl, FramesPointers
+ jr c, .got_frames
+ ld c, BANK(JohtoFrames)
+.got_frames
+ ld a, c
+ ld [wPokeAnimFramesBank], a
+
+ ld a, [wPokeAnimSpeciesOrUnown]
+ dec a
+ ld e, a
+ ld d, 0
+ add hl, de
+ add hl, de
+ ld a, b
+ call GetFarHalfword
+ ld a, l
+ ld [wPokeAnimFramesAddr], a
+ ld a, h
+ ld [wPokeAnimFramesAddr + 1], a
+ ret
+
+.egg
+ ld hl, EggFrames
+ ld c, BANK(EggFrames)
+ ld a, c
+ ld [wPokeAnimFramesBank], a
+ ld a, l
+ ld [wPokeAnimFramesAddr], a
+ ld a, h
+ ld [wPokeAnimFramesAddr + 1], a
+ ret
+; d061b
+
+GetMonBitmaskPointer: ; d061b
+ call PokeAnim_IsEgg
+ jr z, .egg
+
+ call PokeAnim_IsUnown
+ ld a, BANK(UnownBitmasksPointers)
+ ld hl, UnownBitmasksPointers
+ jr z, .unown
+ ld a, BANK(BitmasksPointers)
+ ld hl, BitmasksPointers
+.unown
+ ld [wPokeAnimBitmaskBank], a
+
+ ld a, [wPokeAnimSpeciesOrUnown]
+ dec a
+ ld e, a
+ ld d, 0
+ add hl, de
+ add hl, de
+ ld a, [wPokeAnimBitmaskBank]
+ call GetFarHalfword
+ ld a, l
+ ld [wPokeAnimBitmaskAddr], a
+ ld a, h
+ ld [wPokeAnimBitmaskAddr + 1], a
+ ret
+
+.egg
+ ld c, BANK(EggBitmasks)
+ ld hl, EggBitmasks
+ ld a, c
+ ld [wPokeAnimBitmaskBank], a
+ ld a, l
+ ld [wPokeAnimBitmaskAddr], a
+ ld a, h
+ ld [wPokeAnimBitmaskAddr + 1], a
+ ret
+; d065c
+
+PokeAnim_GetSpeciesOrUnown: ; d065c
+ call PokeAnim_IsUnown
+ jr z, .unown
+ ld a, [wPokeAnimSpecies]
+ ret
+
+.unown
+ ld a, [wPokeAnimUnownLetter]
+ ret
+; d0669
+
+Unused_HOF_AnimateAlignedFrontpic: ; d0669
+ ld a, $1
+ ld [wBoxAlignment], a
+
+HOF_AnimateFrontpic: ; d066e
+ call AnimateMon_CheckIfPokemon
+ jr c, .fail
+ ld h, d
+ ld l, e
+ push bc
+ push hl
+ ld de, vTiles2
+ predef GetAnimatedFrontpic
+ pop hl
+ pop bc
+ ld d, 0
+ ld e, c
+ call AnimateFrontpic
+ xor a
+ ld [wBoxAlignment], a
+ ret
+
+.fail
+ xor a
+ ld [wBoxAlignment], a
+ inc a
+ ld [wCurPartySpecies], a
+ ret
+; d0695
diff --git a/engine/gfx/player_gfx.asm b/engine/gfx/player_gfx.asm
new file mode 100644
index 000000000..deb16ad3a
--- /dev/null
+++ b/engine/gfx/player_gfx.asm
@@ -0,0 +1,224 @@
+Unreferenced_Function88248: ; 88248
+ ld c, CAL
+ ld a, [wPlayerGender]
+ bit PLAYERGENDER_FEMALE_F, a
+ jr z, .okay
+ ld c, KAREN
+
+.okay
+ ld a, c
+ ld [wTrainerClass], a
+ ret
+
+MovePlayerPicRight: ; 88258
+ hlcoord 6, 4
+ ld de, 1
+ jr MovePlayerPic
+
+MovePlayerPicLeft: ; 88260
+ hlcoord 13, 4
+ ld de, -1
+ ; fallthrough
+
+MovePlayerPic: ; 88266
+; Move player pic at hl by de * 7 tiles.
+ ld c, $8
+.loop
+ push bc
+ push hl
+ push de
+ xor a
+ ld [hBGMapMode], a
+ lb bc, 7, 7
+ predef PlaceGraphic
+ xor a
+ ld [hBGMapThird], a
+ call WaitBGMap
+ call DelayFrame
+ pop de
+ pop hl
+ add hl, de
+ pop bc
+ dec c
+ ret z
+ push hl
+ push bc
+ ld a, l
+ sub e
+ ld l, a
+ ld a, h
+ sbc d
+ ld h, a
+ lb bc, 7, 7
+ call ClearBox
+ pop bc
+ pop hl
+ jr .loop
+
+ShowPlayerNamingChoices: ; 88297
+ ld hl, ChrisNameMenuHeader
+ ld a, [wPlayerGender]
+ bit PLAYERGENDER_FEMALE_F, a
+ jr z, .GotGender
+ ld hl, KrisNameMenuHeader
+.GotGender:
+ call LoadMenuHeader
+ call VerticalMenu
+ ld a, [wMenuCursorY]
+ dec a
+ call CopyNameFromMenu
+ call CloseWindow
+ ret
+
+INCLUDE "data/player_names.asm"
+
+GetPlayerNameArray: ; 88318 This Function is never called
+ ld hl, wPlayerName
+ ld de, MalePlayerNameArray
+ ld a, [wPlayerGender]
+ bit PLAYERGENDER_FEMALE_F, a
+ jr z, .done
+ ld de, FemalePlayerNameArray
+
+.done
+ call InitName
+ ret
+
+GetPlayerIcon: ; 8832c
+; Get the player icon corresponding to gender
+
+; Male
+ ld de, ChrisSpriteGFX
+ ld b, BANK(ChrisSpriteGFX)
+
+ ld a, [wPlayerGender]
+ bit PLAYERGENDER_FEMALE_F, a
+ jr z, .done
+
+; Female
+ ld de, KrisSpriteGFX
+ ld b, BANK(KrisSpriteGFX)
+
+.done
+ ret
+
+GetCardPic: ; 8833e
+ ld hl, ChrisCardPic
+ ld a, [wPlayerGender]
+ bit PLAYERGENDER_FEMALE_F, a
+ jr z, .GotClass
+ ld hl, KrisCardPic
+.GotClass:
+ ld de, vTiles2 tile $00
+ ld bc, $23 tiles
+ ld a, BANK(ChrisCardPic) ; BANK(KrisCardPic)
+ call FarCopyBytes
+ ld hl, CardGFX
+ ld de, vTiles2 tile $23
+ ld bc, 6 tiles
+ ld a, BANK(CardGFX)
+ call FarCopyBytes
+ ret
+
+ChrisCardPic: ; 88365
+INCBIN "gfx/trainer_card/chris_card.2bpp"
+
+KrisCardPic: ; 88595
+INCBIN "gfx/trainer_card/kris_card.2bpp"
+
+CardGFX: ; 887c5
+INCBIN "gfx/trainer_card/trainer_card.2bpp"
+
+GetPlayerBackpic: ; 88825
+ ld a, [wPlayerGender]
+ bit PLAYERGENDER_FEMALE_F, a
+ jr z, GetChrisBackpic
+ call GetKrisBackpic
+ ret
+
+GetChrisBackpic: ; 88830
+ ld hl, ChrisBackpic
+ ld b, BANK(ChrisBackpic)
+ ld de, vTiles2 tile $31
+ ld c, 7 * 7
+ predef DecompressGet2bpp
+ ret
+
+HOF_LoadTrainerFrontpic: ; 88840
+ call WaitBGMap
+ xor a
+ ld [hBGMapMode], a
+ ld e, 0
+ ld a, [wPlayerGender]
+ bit PLAYERGENDER_FEMALE_F, a
+ jr z, .GotClass
+ ld e, 1
+
+.GotClass:
+ ld a, e
+ ld [wTrainerClass], a
+ ld de, ChrisPic
+ ld a, [wPlayerGender]
+ bit PLAYERGENDER_FEMALE_F, a
+ jr z, .GotPic
+ ld de, KrisPic
+
+.GotPic:
+ ld hl, vTiles2
+ ld b, BANK(ChrisPic) ; BANK(KrisPic)
+ ld c, 7 * 7
+ call Get2bpp
+ call WaitBGMap
+ ld a, $1
+ ld [hBGMapMode], a
+ ret
+
+DrawIntroPlayerPic: ; 88874
+; Draw the player pic at (6,4).
+
+; Get class
+ ld e, CHRIS
+ ld a, [wPlayerGender]
+ bit PLAYERGENDER_FEMALE_F, a
+ jr z, .GotClass
+ ld e, KRIS
+.GotClass:
+ ld a, e
+ ld [wTrainerClass], a
+
+; Load pic
+ ld de, ChrisPic
+ ld a, [wPlayerGender]
+ bit PLAYERGENDER_FEMALE_F, a
+ jr z, .GotPic
+ ld de, KrisPic
+.GotPic:
+ ld hl, vTiles2
+ ld b, BANK(ChrisPic) ; BANK(KrisPic)
+ ld c, 7 * 7 ; dimensions
+ call Get2bpp
+
+; Draw
+ xor a
+ ld [hGraphicStartTile], a
+ hlcoord 6, 4
+ lb bc, 7, 7
+ predef PlaceGraphic
+ ret
+
+ChrisPic: ; 888a9
+INCBIN "gfx/player/chris.2bpp"
+
+KrisPic: ; 88bb9
+INCBIN "gfx/player/kris.2bpp"
+
+GetKrisBackpic: ; 88ec9
+; Kris's backpic is uncompressed.
+ ld de, KrisBackpic
+ ld hl, vTiles2 tile $31
+ lb bc, BANK(KrisBackpic), 7 * 7 ; dimensions
+ call Get2bpp
+ ret
+
+KrisBackpic: ; 88ed6
+INCBIN "gfx/player/kris_back.2bpp"
diff --git a/engine/gfx/sgb_layouts.asm b/engine/gfx/sgb_layouts.asm
new file mode 100644
index 000000000..24bdc952e
--- /dev/null
+++ b/engine/gfx/sgb_layouts.asm
@@ -0,0 +1,605 @@
+LoadSGBLayout: ; 864c
+ call CheckCGB
+ jp nz, LoadSGBLayoutCGB
+
+ ld a, b
+ cp SCGB_RAM
+ jr nz, .not_ram
+ ld a, [wSGBPredef]
+.not_ram
+ cp SCGB_PARTY_MENU_HP_PALS
+ jp z, SGB_ApplyPartyMenuHPPals
+ ld l, a
+ ld h, 0
+ add hl, hl
+ ld de, .Jumptable
+ add hl, de
+ ld a, [hli]
+ ld h, [hl]
+ ld l, a
+ ld de, _LoadSGBLayout_ReturnFromJumpTable
+ push de
+ jp hl
+; 866f
+
+.Jumptable: ; 866f
+ dw .SGB_BattleGrayscale
+ dw .SGB_BattleColors
+ dw .SGB_PokegearPals
+ dw .SGB_StatsScreenHPPals
+ dw .SGB_Pokedex
+ dw .SGB_SlotMachine
+ dw .SGB06
+ dw .SGB_GSIntro
+ dw .SGB_Diploma
+ dw .SGB_MapPals
+ dw .SGB_PartyMenu
+ dw .SGB_Evolution
+ dw .SGB_GSTitleScreen
+ dw .SGB0d
+ dw .SGB_MoveList
+ dw .SGB0f
+ dw .SGB_PokedexSearchOption
+ dw .SGB11
+ dw .SGB12
+ dw .SGB13
+ dw .SGB_PackPals
+ dw .SGB_TrainerCard
+ dw .SGB_PokedexUnownMode
+ dw .SGB_BillsPC
+ dw .SGB_UnownPuzzle
+ dw .SGB_GamefreakLogo
+ dw .SGB_PlayerOrMonFrontpicPals
+ dw .SGB_TradeTube
+ dw .SGB_TrainerOrMonFrontpicPals
+ dw .SGB_MysteryGift
+ dw .SGB1e
+; 86ad
+
+.SGB_BattleGrayscale: ; 86ad
+ ld hl, PalPacket_BattleGrayscale
+ ld de, BlkPacket_Battle
+ ret
+; 86b4
+
+.SGB_BattleColors: ; 86b4
+ ld hl, BlkPacket_Battle
+ call PushSGBPals_
+
+ ld hl, PalPacket_9ce6
+ ld de, wSGBPals
+ ld bc, PALPACKET_LENGTH
+ call CopyBytes
+
+ ld a, [wPlayerHPPal]
+ ld l, a
+ ld h, 0
+ add hl, hl
+ add hl, hl
+ ld de, HPBarPals
+ add hl, de
+
+ ld a, [hli]
+ ld [wSGBPals + 3], a
+ ld a, [hli]
+ ld [wSGBPals + 4], a
+ ld a, [hli]
+ ld [wSGBPals + 5], a
+ ld a, [hl]
+ ld [wSGBPals + 6], a
+
+ ld a, [wEnemyHPPal]
+ ld l, a
+ ld h, 0
+ add hl, hl
+ add hl, hl
+
+ ld de, HPBarPals
+ add hl, de
+ ld a, [hli]
+ ld [wSGBPals + 9], a
+ ld a, [hli]
+ ld [wSGBPals + 10], a
+ ld a, [hli]
+ ld [wSGBPals + 11], a
+ ld a, [hl]
+ ld [wSGBPals + 12], a
+
+ ld hl, PalPacket_9cf6
+ ld de, wSGBPals + PALPACKET_LENGTH
+ ld bc, PALPACKET_LENGTH
+ call CopyBytes
+
+ call GetBattlemonBackpicPalettePointer
+
+ ld a, [hli]
+ ld [wSGBPals + 19], a
+ ld a, [hli]
+ ld [wSGBPals + 20], a
+ ld a, [hli]
+ ld [wSGBPals + 21], a
+ ld a, [hl]
+ ld [wSGBPals + 22], a
+ call GetEnemyFrontpicPalettePointer
+ ld a, [hli]
+ ld [wSGBPals + 25], a
+ ld a, [hli]
+ ld [wSGBPals + 26], a
+ ld a, [hli]
+ ld [wSGBPals + 27], a
+ ld a, [hl]
+ ld [wSGBPals + 28], a
+
+ ld hl, wSGBPals
+ ld de, wSGBPals + PALPACKET_LENGTH
+ ld a, SCGB_BATTLE_COLORS
+ ld [wSGBPredef], a
+ ret
+; 873c
+
+.SGB_MoveList: ; 873c
+ ld hl, PalPacket_9bd6
+ ld de, wSGBPals
+ ld bc, PALPACKET_LENGTH
+ call CopyBytes
+
+ ld hl, wSGBPals + 1
+ ld [hl], $10
+ inc hl
+ inc hl
+
+ ld a, [wPlayerHPPal]
+ add PREDEFPAL_HP_GREEN
+ ld [hl], a
+ ld hl, wSGBPals
+ ld de, BlkPacket_MoveList
+ ret
+; 875c
+
+.SGB_PokegearPals: ; 875c
+ ld hl, PalPacket_Pokegear
+ ld de, BlkPacket_9a86
+ ret
+; 8763
+
+.SGB_StatsScreenHPPals: ; 8763
+ ld hl, PalPacket_9ce6
+ ld de, wSGBPals
+ ld bc, PALPACKET_LENGTH
+ call CopyBytes
+ ld a, [wCurHPPal]
+ ld l, a
+ ld h, 0
+ add hl, hl
+ add hl, hl
+ ld de, HPBarPals
+ add hl, de
+ ld a, [hli]
+ ld [wSGBPals + 3], a
+ ld a, [hli]
+ ld [wSGBPals + 4], a
+ ld a, [hli]
+ ld [wSGBPals + 5], a
+ ld a, [hl]
+ ld [wSGBPals + 6], a
+ ld a, [wCurPartySpecies]
+ ld bc, wTempMonDVs
+ call GetPlayerOrMonPalettePointer
+ ld a, [hli]
+ ld [wSGBPals + 9], a
+ ld a, [hli]
+ ld [wSGBPals + 10], a
+ ld a, [hli]
+ ld [wSGBPals + 11], a
+ ld a, [hl]
+ ld [wSGBPals + 12], a
+ ld hl, wSGBPals
+ ld de, BlkPacket_StatsScreen
+ ret
+; 87ab
+
+.SGB_PartyMenu: ; 87ab
+ ld hl, PalPacket_PartyMenu
+ ld de, wSGBPals + 1
+ ret
+; 87b2
+
+.SGB_Pokedex: ; 87b2
+ ld hl, PalPacket_9ce6
+ ld de, wSGBPals
+ ld bc, PALPACKET_LENGTH
+ call CopyBytes
+ ld hl, wSGBPals + 3
+ ld [hl], LOW(palred 31 + palgreen 20 + palblue 10)
+ inc hl
+ ld [hl], HIGH(palred 31 + palgreen 20 + palblue 10)
+ inc hl
+ ld [hl], LOW(palred 26 + palgreen 10 + palblue 6)
+ inc hl
+ ld [hl], HIGH(palred 26 + palgreen 10 + palblue 6)
+ ld a, [wCurPartySpecies]
+ call GetMonPalettePointer_
+ ld a, [hli]
+ ld [wSGBPals + 9], a
+ ld a, [hli]
+ ld [wSGBPals + 10], a
+ ld a, [hli]
+ ld [wSGBPals + 11], a
+ ld a, [hl]
+ ld [wSGBPals + 12], a
+ ld hl, wSGBPals
+ ld de, BlkPacket_Pokedex_PC
+ ret
+; 87e9
+
+.SGB_BillsPC: ; 87e9
+ ld hl, PalPacket_9ce6
+ ld de, wSGBPals
+ ld bc, PALPACKET_LENGTH
+ call CopyBytes
+ ld hl, wSGBPals + 3
+ ld [hl], LOW(palred 31 + palgreen 20 + palblue 10)
+ inc hl
+ ld [hl], HIGH(palred 31 + palgreen 20 + palblue 10)
+ inc hl
+ ld [hl], LOW(palred 26 + palgreen 10 + palblue 6)
+ inc hl
+ ld [hl], HIGH(palred 26 + palgreen 10 + palblue 6)
+ ld a, [wCurPartySpecies]
+ ld bc, wTempMonDVs
+ call GetPlayerOrMonPalettePointer
+ ld a, [hli]
+ ld [wSGBPals + 9], a
+ ld a, [hli]
+ ld [wSGBPals + 10], a
+ ld a, [hli]
+ ld [wSGBPals + 11], a
+ ld a, [hl]
+ ld [wSGBPals + 12], a
+ ld hl, wSGBPals
+ ld de, BlkPacket_Pokedex_PC
+ ret
+; 8823
+
+.SGB_PokedexUnownMode: ; 8823
+ call .SGB_Pokedex
+ ld de, BlkPacket_PokedexUnownMode
+ ret
+; 882a
+
+.SGB_PokedexSearchOption: ; 882a
+ ld hl, PalPacket_9ce6
+ ld de, wSGBPals
+ ld bc, PALPACKET_LENGTH
+ call CopyBytes
+ ld hl, wSGBPals + 3
+ ld [hl], LOW(palred 31 + palgreen 20 + palblue 10)
+ inc hl
+ ld [hl], HIGH(palred 31 + palgreen 20 + palblue 10)
+ inc hl
+ ld [hl], LOW(palred 26 + palgreen 10 + palblue 6)
+ inc hl
+ ld [hl], HIGH(palred 26 + palgreen 10 + palblue 6)
+ ld hl, wSGBPals
+ ld de, BlkPacket_9a86
+ ret
+; 884b
+
+.SGB_PackPals: ; 884b
+ ld hl, PalPacket_Pack
+ ld de, BlkPacket_9a86
+ ret
+; 8852
+
+.SGB_SlotMachine: ; 8852
+ ld hl, PalPacket_SlotMachine
+ ld de, BlkPacket_SlotMachine
+ ret
+; 8859
+
+.SGB06: ; 8859
+ ld hl, PalPacket_SCGB_06
+ ld de, BlkPacket_SCGB_06
+ ret
+; 8860
+
+.SGB_Diploma:
+.SGB_MysteryGift: ; 8860
+ ld hl, PalPacket_Diploma
+ ld de, BlkPacket_9a86
+ ret
+; 8867
+
+.SGB_GSIntro: ; 8867
+ ld b, 0
+ ld hl, .BlkPacketTable_GSIntro
+rept 4
+ add hl, bc
+endr
+ ld e, [hl]
+ inc hl
+ ld d, [hl]
+ inc hl
+ ld a, [hli]
+ ld h, [hl]
+ ld l, a
+ ret
+; 8878
+
+.BlkPacketTable_GSIntro: ; 8878
+ dw BlkPacket_9a86, PalPacket_GSIntroShellderLapras
+ dw BlkPacket_GSIntroJigglypuffPikachu, PalPacket_GSIntroJigglypuffPikachu
+ dw BlkPacket_9a86, PalPacket_GSIntroStartersTransition
+; 8884
+
+.SGB_GSTitleScreen: ; 8884
+ ld hl, PalPacket_GSTitleScreen
+ ld de, BlkPacket_GSTitleScreen
+ ld a, SCGB_DIPLOMA
+ ld [wSGBPredef], a
+ ret
+; 8890
+
+.SGB13: ; 8890
+ ld hl, PalPacket_SCGB_13
+ ld de, BlkPacket_SCGB_13
+ ret
+; 8897
+
+.SGB0f: ; 8897
+ ld hl, PalPacket_SCGB_0F
+ ld de, BlkPacket_9a86
+ ret
+; 889e
+
+.SGB11: ; 889e
+ ld hl, BlkPacket_9a86
+ ld de, wPlayerLightScreenCount ; ???
+ ld bc, PALPACKET_LENGTH
+ call CopyBytes
+ ld hl, PalPacket_SCGB_11
+ ld de, BlkPacket_9a86
+ ret
+; 88b1
+
+.SGB_MapPals: ; 88b1
+ ld hl, PalPacket_9bd6
+ ld de, wSGBPals
+ ld bc, PALPACKET_LENGTH
+ call CopyBytes
+ call .GetMapPalsIndex
+ ld hl, wSGBPals + 1
+ ld [hld], a
+ ld de, BlkPacket_9a86
+ ld a, SCGB_MAPPALS
+ ld [wSGBPredef], a
+ ret
+; 88cd
+
+.SGB_Evolution: ; 88cd
+ push bc
+ ld hl, PalPacket_9ce6
+ ld de, wSGBPals
+ ld bc, PALPACKET_LENGTH
+ call CopyBytes
+ pop bc
+ ld a, c
+ and a
+ jr z, .partymon
+ ; Egg
+ ld hl, wSGBPals + 3
+ ld [hl], LOW(palred 7 + palgreen 7 + palblue 7)
+ inc hl
+ ld [hl], HIGH(palred 7 + palgreen 7 + palblue 7)
+ inc hl
+ ld [hl], LOW(palred 2 + palgreen 3 + palblue 3)
+ inc hl
+ ld [hl], HIGH(palred 2 + palgreen 3 + palblue 3)
+ jr .done
+
+.partymon
+ ld hl, wPartyMon1DVs
+ ld bc, PARTYMON_STRUCT_LENGTH
+ ld a, [wCurPartyMon]
+ call AddNTimes
+ ld c, l
+ ld b, h
+ ld a, [wPlayerHPPal]
+ call GetPlayerOrMonPalettePointer
+ ld a, [hli]
+ ld [wSGBPals + 3], a
+ ld a, [hli]
+ ld [wSGBPals + 4], a
+ ld a, [hli]
+ ld [wSGBPals + 5], a
+ ld a, [hl]
+ ld [wSGBPals + 6], a
+
+.done
+ ld hl, wSGBPals
+ ld de, BlkPacket_9a86
+ ret
+; 891a
+
+.SGB0d:
+.SGB_TrainerCard: ; 891a
+ ld hl, PalPacket_Diploma
+ ld de, BlkPacket_9a86
+ ret
+; 8921
+
+.SGB_UnownPuzzle: ; 8921
+ ld hl, PalPacket_UnownPuzzle
+ ld de, BlkPacket_9a86
+ ret
+; 8928
+
+.SGB12: ; 8928
+ ld hl, PalPacket_9bd6
+ ld de, wSGBPals
+ ld bc, PALPACKET_LENGTH
+ call CopyBytes
+ ld hl, BlkPacket_9a86
+ ld de, wSGBPals + PALPACKET_LENGTH
+ ld bc, PALPACKET_LENGTH
+ call CopyBytes
+ call .GetMapPalsIndex
+ ld hl, wSGBPals + 1
+ ld [hl], a
+ ld hl, wSGBPals + 3
+ ld [hl], $2e
+ ld hl, wSGBPals + $13
+ ld a, 5
+ ld [hli], a
+ ld a, [wMenuBorderLeftCoord]
+ ld [hli], a
+ ld a, [wMenuBorderTopCoord]
+ ld [hli], a
+ ld a, [wMenuBorderRightCoord]
+ ld [hli], a
+ ld a, [wMenuBorderBottomCoord]
+ ld [hl], a
+ ld hl, wSGBPals
+ ld de, wSGBPals + PALPACKET_LENGTH
+ ret
+; 8969
+
+.SGB1e: ; 8969
+ ld hl, PalPacket_9ce6
+ ld de, wSGBPals
+ ld bc, PALPACKET_LENGTH
+ call CopyBytes
+ ld a, [wCurPartySpecies]
+ ld l, a
+ ld h, 0
+ add hl, hl
+ add hl, hl
+ add hl, hl
+ ld de, PokemonPalettes
+ add hl, de
+ ld a, [wcf65]
+ and 3
+ sla a
+ sla a
+ ld c, a
+ ld b, 0
+ add hl, bc
+ ld a, [hli]
+ ld [wSGBPals + 3], a
+ ld a, [hli]
+ ld [wSGBPals + 4], a
+ ld a, [hli]
+ ld [wSGBPals + 5], a
+ ld a, [hl]
+ ld [wSGBPals + 6], a
+ ld hl, wSGBPals
+ ld de, BlkPacket_9a86
+ ret
+; 89a6
+
+.SGB_GamefreakLogo: ; 89a6
+ ld hl, PalPacket_GamefreakLogo
+ ld de, BlkPacket_9a86
+ ret
+; 89ad
+
+.SGB_PlayerOrMonFrontpicPals: ; 89ad
+ ld hl, PalPacket_9ce6
+ ld de, wSGBPals
+ ld bc, PALPACKET_LENGTH
+ call CopyBytes
+ ld a, [wCurPartySpecies]
+ ld bc, wTempMonDVs
+ call GetPlayerOrMonPalettePointer
+ ld a, [hli]
+ ld [wSGBPals + 3], a
+ ld a, [hli]
+ ld [wSGBPals + 4], a
+ ld a, [hli]
+ ld [wSGBPals + 5], a
+ ld a, [hl]
+ ld [wSGBPals + 6], a
+ ld hl, wSGBPals
+ ld de, BlkPacket_9a86
+ ret
+; 89d9
+
+.SGB_TradeTube: ; 89d9
+ ld hl, PalPacket_TradeTube
+ ld de, BlkPacket_9a86
+ ret
+; 89e0
+
+.SGB_TrainerOrMonFrontpicPals: ; 89e0
+ ld hl, PalPacket_9ce6
+ ld de, wSGBPals
+ ld bc, PALPACKET_LENGTH
+ call CopyBytes
+ ld a, [wCurPartySpecies]
+ ld bc, wTempMonDVs
+ call GetFrontpicPalettePointer
+ ld a, [hli]
+ ld [wSGBPals + 3], a
+ ld a, [hli]
+ ld [wSGBPals + 4], a
+ ld a, [hli]
+ ld [wSGBPals + 5], a
+ ld a, [hl]
+ ld [wSGBPals + 6], a
+ ld hl, wSGBPals
+ ld de, BlkPacket_9a86
+ ret
+; 8a0c
+
+.GetMapPalsIndex: ; 8a0c
+ ld a, [wTimeOfDayPal]
+ cp NITE_F
+ jr c, .morn_day
+ ld a, PREDEFPAL_NITE
+ ret
+
+.morn_day
+ ld a, [wEnvironment]
+ cp ROUTE
+ jr z, .route
+ cp CAVE
+ jr z, .cave
+ cp DUNGEON
+ jr z, .cave
+ cp ENVIRONMENT_5
+ jr z, .perm5
+ cp GATE
+ jr z, .gate
+ ld a, [wMapGroup]
+ ld e, a
+ ld d, 0
+ ld hl, MapGroupRoofSGBPalInds
+ add hl, de
+ ld a, [hl]
+ ret
+
+.route
+ ld a, PREDEFPAL_00
+ ret
+
+.cave
+ ld a, PREDEFPAL_DUNGEONS
+ ret
+
+.perm5
+ ld a, PREDEFPAL_VERMILION
+ ret
+
+.gate
+ ld a, PREDEFPAL_PEWTER
+ ret
+; 8a45
+
+INCLUDE "data/maps/sgb_roof_pal_inds.asm"
+
+_LoadSGBLayout_ReturnFromJumpTable: ; 8a60
+ push de
+ call PushSGBPals_
+ pop hl
+ jp PushSGBPals_
+; 8a68
diff --git a/engine/gfx/sprite_anims.asm b/engine/gfx/sprite_anims.asm
new file mode 100755
index 000000000..9353b71c9
--- /dev/null
+++ b/engine/gfx/sprite_anims.asm
@@ -0,0 +1,889 @@
+DoAnimFrame: ; 8d24b
+ ld hl, SPRITEANIMSTRUCT_ANIM_SEQ_ID
+ add hl, bc
+ ld e, [hl]
+ ld d, 0
+ ld hl, .Jumptable
+ add hl, de
+ add hl, de
+ ld a, [hli]
+ ld h, [hl]
+ ld l, a
+ jp hl
+; 8d25b
+
+.Jumptable: ; 8d25b (23:525b)
+; entries correspond to SPRITE_ANIM_SEQ_* constants
+ dw .Null
+ dw .PartyMon
+ dw .PartyMonSwitch
+ dw .PartyMonSelected
+ dw .GSTitleTrail
+ dw .NamingScreenCursor
+ dw .GameFreakLogo
+ dw .GSIntroStar
+ dw .GSIntroSparkle
+ dw .SlotsGolem
+ dw .SlotsChansey
+ dw .SlotsChanseyEgg
+ dw .MailCursor
+ dw .UnusedCursor
+ dw .DummyGameCursor
+ dw .PokegearArrow
+ dw .TradePokeBall
+ dw .TradeTubeBulge
+ dw .TrademonInTube
+ dw .RevealNewMon
+ dw .RadioTuningKnob
+ dw .CutLeaves
+ dw .FlyFrom
+ dw .FlyLeaf
+ dw .FlyTo
+ dw .GSIntroHoOh
+ dw .EZChatCursor
+ dw .MobileTradeSentPulse
+ dw .MobileTradeOTPulse
+ dw .IntroSuicune
+ dw .IntroPichuWooper
+ dw .Celebi
+ dw .IntroUnown
+ dw .IntroUnownF
+ dw .IntroSuicuneAway
+
+.Null: ; 8d2a1 (23:52a1)
+ ret
+
+.PartyMon ; 8d2a2 (23:52a2)
+ ld a, [wMenuCursorY]
+
+ ld hl, SPRITEANIMSTRUCT_INDEX
+ add hl, bc
+ cp [hl]
+ jr z, .PartyMonSwitch
+
+ ld hl, SPRITEANIMSTRUCT_XCOORD
+ add hl, bc
+ ld [hl], 8 * 2
+
+ ld hl, SPRITEANIMSTRUCT_YOFFSET
+ add hl, bc
+ ld [hl], $0
+ ret
+
+.PartyMonSwitch ; 8d2b9 (23:52b9)
+ ld hl, SPRITEANIMSTRUCT_XCOORD
+ add hl, bc
+ ld [hl], 8 * 3
+
+ ld hl, SPRITEANIMSTRUCT_0C
+ add hl, bc
+ ld a, [hl]
+ ld d, a
+ inc [hl]
+ and $f
+ ret nz
+
+ ld hl, SPRITEANIMSTRUCT_0D
+ add hl, bc
+ ld e, [hl]
+
+ ld hl, SPRITEANIMSTRUCT_YOFFSET
+ add hl, bc
+ ld a, d
+ and $10 ; bit 4
+ jr z, .load_zero
+ ld a, e
+ and a
+ jr z, .load_minus_two
+ cp $1
+ jr z, .load_minus_one
+.load_zero
+ xor a
+ ld [hl], a
+ ret
+
+.load_minus_one
+ ld a, -1
+ ld [hl], a
+ ret
+
+.load_minus_two
+ ld a, -2
+ ld [hl], a
+ ret
+
+.PartyMonSelected ; 8d2ea (23:52ea)
+ ld a, [wMenuCursorY]
+
+ ld hl, SPRITEANIMSTRUCT_INDEX
+ add hl, bc
+ cp [hl]
+ jr z, .three_offset_right
+
+ ld hl, SPRITEANIMSTRUCT_XCOORD
+ add hl, bc
+ ld [hl], 8 * 2
+ ret
+
+.three_offset_right
+ ld hl, SPRITEANIMSTRUCT_XCOORD
+ add hl, bc
+ ld [hl], 8 * 3
+ ret
+
+.GSTitleTrail ; 8d302 (23:5302)
+ call .AnonymousJumptable
+ jp hl
+; 8d306 (23:5306)
+
+; Anonymous dw (see .AnonymousJumptable)
+ dw .four_zero
+ dw .four_one
+; 8d30a
+
+.four_zero ; 8d30a
+ call .IncrementJumptableIndex
+
+ ld hl, SPRITEANIMSTRUCT_INDEX
+ add hl, bc
+ ld a, [hl]
+
+ ld hl, SPRITEANIMSTRUCT_0D
+ add hl, bc
+ and $3
+ ld [hl], a
+ inc [hl]
+ swap a
+
+ ld hl, SPRITEANIMSTRUCT_0C
+ add hl, bc
+ ld [hl], a
+
+.four_one ; 8d321
+ ld hl, SPRITEANIMSTRUCT_XCOORD
+ add hl, bc
+ ld a, [hl]
+ cp $a4
+ jr nc, .asm_8d356
+
+ ld hl, SPRITEANIMSTRUCT_0D
+ add hl, bc
+ add $4
+
+ ld hl, SPRITEANIMSTRUCT_XCOORD
+ add hl, bc
+ ld [hl], a
+
+ ld hl, SPRITEANIMSTRUCT_YCOORD
+ add hl, bc
+ inc [hl]
+
+ ld hl, SPRITEANIMSTRUCT_0D
+ add hl, bc
+ ld a, [hl]
+ sla a
+ sla a
+ ld d, $2
+
+ ld hl, SPRITEANIMSTRUCT_0C
+ add hl, bc
+ ld a, [hl]
+ add $3
+ ld [hl], a
+ call .Sprites_Sine
+
+ ld hl, SPRITEANIMSTRUCT_YOFFSET
+ add hl, bc
+ ld [hl], a
+ ret
+
+.asm_8d356
+ call DeinitializeSprite
+ ret
+; 8d35a
+
+.GSIntroHoOh ; 8d35a (23:535a)
+ ld hl, SPRITEANIMSTRUCT_0C
+ add hl, bc
+ ld a, [hl]
+ inc a
+ ld [hl], a
+ ld d, $2
+ call .Sprites_Sine
+
+ ld hl, SPRITEANIMSTRUCT_YOFFSET
+ add hl, bc
+ ld [hl], a
+ ret
+
+.NamingScreenCursor ; 8d36c (23:536c)
+ callfar NamingScreen_AnimateCursor
+ ret
+
+.MailCursor ; 8d373 (23:5373)
+ callfar ComposeMail_AnimateCursor
+ ret
+
+.GameFreakLogo: ; 8d37a (23:537a)
+ callfar GameFreakLogoJumper
+ ret
+
+.GSIntroStar ; 8d381 (23:5381)
+ ld hl, SPRITEANIMSTRUCT_0C
+ add hl, bc
+ ld a, [hl]
+ and a
+ jr z, .asm_8d3ba
+ dec [hl]
+ dec [hl]
+ ld d, a
+ and $1f
+ jr nz, .asm_8d395
+
+ ld hl, SPRITEANIMSTRUCT_0D
+ add hl, bc
+ dec [hl]
+.asm_8d395
+ ld hl, SPRITEANIMSTRUCT_JUMPTABLE_INDEX
+ add hl, bc
+ ld a, [hl]
+ push af
+ push de
+ call .Sprites_Sine
+
+ ld hl, SPRITEANIMSTRUCT_YOFFSET
+ add hl, bc
+ ld [hl], a
+ pop de
+ pop af
+ call .Sprites_Cosine
+
+ ld hl, SPRITEANIMSTRUCT_XOFFSET
+ add hl, bc
+ ld [hl], a
+
+ ld hl, SPRITEANIMSTRUCT_0D
+ add hl, bc
+ ld a, [hl]
+
+ ld hl, SPRITEANIMSTRUCT_JUMPTABLE_INDEX
+ add hl, bc
+ add [hl]
+ ld [hl], a
+ ret
+
+.asm_8d3ba
+ ld a, $1
+ ld [wcf64], a
+ call DeinitializeSprite
+ ret
+
+.GSIntroSparkle ; 8d3c3 (23:53c3)
+ ld hl, SPRITEANIMSTRUCT_0C
+ add hl, bc
+ ld a, [hli]
+ or [hl]
+ jr z, .asm_8d41e
+
+ ld hl, SPRITEANIMSTRUCT_0F
+ add hl, bc
+ ld d, [hl]
+
+ ld hl, SPRITEANIMSTRUCT_JUMPTABLE_INDEX
+ add hl, bc
+ ld a, [hl]
+ push af
+ push de
+ call .Sprites_Sine
+
+ ld hl, SPRITEANIMSTRUCT_YOFFSET
+ add hl, bc
+ ld [hl], a
+ pop de
+ pop af
+ call .Sprites_Cosine
+
+ ld hl, SPRITEANIMSTRUCT_XOFFSET
+ add hl, bc
+ ld [hl], a
+
+ ld hl, SPRITEANIMSTRUCT_0C
+ add hl, bc
+ ld e, [hl]
+ inc hl
+ ld d, [hl]
+
+ ld hl, SPRITEANIMSTRUCT_0E
+ add hl, bc
+ ld a, [hli]
+ ld h, [hl]
+ ld l, a
+ add hl, de
+ ld e, l
+ ld d, h
+
+ ld hl, SPRITEANIMSTRUCT_0E
+ add hl, bc
+ ld [hl], e
+ inc hl
+ ld [hl], d
+
+ ld hl, SPRITEANIMSTRUCT_0C
+ add hl, bc
+ ld a, [hli]
+ ld h, [hl]
+ ld l, a
+ ld de, -$10
+ add hl, de
+ ld e, l
+ ld d, h
+
+ ld hl, SPRITEANIMSTRUCT_0C
+ add hl, bc
+ ld [hl], e
+ inc hl
+ ld [hl], d
+
+ ld hl, SPRITEANIMSTRUCT_JUMPTABLE_INDEX
+ add hl, bc
+ ld a, [hl]
+ xor $20
+ ld [hl], a
+ ret
+
+.asm_8d41e
+ call DeinitializeSprite
+ ret
+
+.SlotsGolem: ; 8d422 (23:5422)
+ callfar Slots_AnimateGolem
+ ret
+
+.SlotsChansey: ; 8d429 (23:5429)
+ callfar Slots_AnimateChansey
+ ld hl, wcf64
+ ld a, [hl]
+ cp $2
+ ret nz
+ ld [hl], $3
+ ld a, SPRITE_ANIM_FRAMESET_SLOTS_CHANSEY_2
+ call _ReinitSpriteAnimFrame
+ ret
+
+.SlotsChanseyEgg: ; 8d43e (23:543e)
+ ld hl, SPRITEANIMSTRUCT_JUMPTABLE_INDEX
+ add hl, bc
+ ld a, [hl]
+ dec [hl]
+ ld e, a
+ and $1
+ jr z, .move_vertical
+
+ ld hl, SPRITEANIMSTRUCT_XCOORD
+ add hl, bc
+ ld a, [hl]
+ cp 15 * 8
+ jr c, .move_right
+ call DeinitializeSprite
+ ld a, $4
+ ld [wcf64], a
+ ld de, SFX_PLACE_PUZZLE_PIECE_DOWN
+ call PlaySFX
+ ret
+
+.move_right
+ inc [hl]
+.move_vertical
+ ld a, e
+ ld d, $20
+ call .Sprites_Sine
+
+ ld hl, SPRITEANIMSTRUCT_YOFFSET
+ add hl, bc
+ ld [hl], a
+ ret
+
+.UnusedCursor ; 8d46e (23:546e)
+ callfar ret_e00ed
+ ret
+
+.PokegearArrow ; 8d475 (23:5475)
+ callfar AnimatePokegearModeIndicatorArrow
+ ret
+
+.DummyGameCursor ; 8d47c (23:547c)
+ callfar DummyGame_InterpretJoypad_AnimateCursor
+ ret
+
+.TradePokeBall ; 8d483 (23:5483)
+ call .AnonymousJumptable
+ jp hl
+; 8d487 (23:5487)
+
+; Anonymous dw (see .AnonymousJumptable)
+ dw .TradePokeBall_zero
+ dw .TradePokeBall_one
+ dw .TradePokeBall_two
+ dw .TradePokeBall_three
+ dw .TradePokeBall_four
+ dw .TradePokeBall_five
+; 8d493
+
+.TradePokeBall_zero ; 8d493
+ ld a, SPRITE_ANIM_FRAMESET_TRADE_POKE_BALL_WOBBLE
+ call _ReinitSpriteAnimFrame
+
+ ld hl, SPRITEANIMSTRUCT_JUMPTABLE_INDEX
+ add hl, bc
+ ld [hl], $2
+
+ ld hl, SPRITEANIMSTRUCT_0C
+ add hl, bc
+ ld [hl], $20
+ ret
+; 8d4a5
+
+.TradePokeBall_two ; 8d4a5
+ ld hl, SPRITEANIMSTRUCT_0C
+ add hl, bc
+ ld a, [hl]
+ and a
+ jr z, .asm_8d4af
+ dec [hl]
+ ret
+
+.asm_8d4af
+ call .IncrementJumptableIndex
+
+ ld hl, SPRITEANIMSTRUCT_0C
+ add hl, bc
+ ld [hl], $40
+
+.TradePokeBall_three ; 8d4b8
+ ld hl, SPRITEANIMSTRUCT_0C
+ add hl, bc
+ ld a, [hl]
+ cp $30
+ jr c, .asm_8d4cd
+ dec [hl]
+ ld d, $28
+ call .Sprites_Sine
+
+ ld hl, SPRITEANIMSTRUCT_YOFFSET
+ add hl, bc
+ ld [hl], a
+ ret
+
+.asm_8d4cd
+ ld de, SFX_GOT_SAFARI_BALLS
+ call PlaySFX
+ jr .TradePokeBall_five
+; 8d4d5
+
+.TradePokeBall_one ; 8d4d5
+ ld hl, SPRITEANIMSTRUCT_JUMPTABLE_INDEX
+ add hl, bc
+ ld [hl], $4
+
+ ld hl, SPRITEANIMSTRUCT_0C
+ add hl, bc
+ ld [hl], $30
+
+ ld hl, SPRITEANIMSTRUCT_0D
+ add hl, bc
+ ld [hl], $24
+ ret
+; 8d4e8
+
+.TradePokeBall_four ; 8d4e8
+ ld hl, SPRITEANIMSTRUCT_0D
+ add hl, bc
+ ld a, [hl]
+ and a
+ jr z, .asm_8d51c
+ ld d, a
+
+ ld hl, SPRITEANIMSTRUCT_0C
+ add hl, bc
+ ld a, [hl]
+ call Sprites_Sine
+
+ ld hl, SPRITEANIMSTRUCT_YOFFSET
+ add hl, bc
+ ld [hl], a
+
+ ld hl, SPRITEANIMSTRUCT_0C
+ add hl, bc
+ inc [hl]
+ ld a, [hl]
+ and $3f
+ ret nz
+
+ ld hl, SPRITEANIMSTRUCT_0C
+ add hl, bc
+ ld [hl], $20
+
+ ld hl, SPRITEANIMSTRUCT_0D
+ add hl, bc
+ ld a, [hl]
+ sub $c
+ ld [hl], a
+ ld de, SFX_SWITCH_POKEMON
+ call PlaySFX
+ ret
+
+.asm_8d51c
+ xor a
+
+ ld hl, SPRITEANIMSTRUCT_YOFFSET
+ add hl, bc
+ ld [hl], a
+ call .IncrementJumptableIndex
+ ret
+
+.TradePokeBall_five ; 8d526
+ call DeinitializeSprite
+ ret
+; 8d52a
+
+.TradeTubeBulge ; 8d52a (23:552a)
+ ld hl, SPRITEANIMSTRUCT_XCOORD
+ add hl, bc
+ ld a, [hl]
+ inc [hl]
+ inc [hl]
+ cp $b0
+ jr nc, .delete
+ and $3
+ ret nz
+ ld de, SFX_POKEBALLS_PLACED_ON_TABLE
+ call PlaySFX
+ ret
+
+.delete
+ call DeinitializeSprite
+ ret
+
+.TrademonInTube ; 8d543 (23:5543)
+ callfar TradeAnim_AnimateTrademonInTube
+ ret
+
+.RevealNewMon: ; 8d54a (23:554a)
+ ld hl, SPRITEANIMSTRUCT_0C
+ add hl, bc
+ ld a, [hl]
+ cp $80
+ jr nc, .finish_EggShell
+ ld d, a
+ add $8
+ ld [hl], a
+
+ ld hl, SPRITEANIMSTRUCT_JUMPTABLE_INDEX
+ add hl, bc
+ ld a, [hl]
+ xor $20
+ ld [hl], a
+
+ push af
+ push de
+ call .Sprites_Sine
+
+ ld hl, SPRITEANIMSTRUCT_YOFFSET
+ add hl, bc
+ ld [hl], a
+
+ pop de
+ pop af
+ call .Sprites_Cosine
+
+ ld hl, SPRITEANIMSTRUCT_XOFFSET
+ add hl, bc
+ ld [hl], a
+ ret
+
+.finish_EggShell
+ call DeinitializeSprite
+ ret
+
+.RadioTuningKnob: ; 8d578 (23:5578)
+ callfar AnimateTuningKnob
+ ret
+
+.CutLeaves ; 8d57f (23:557f)
+ ld hl, SPRITEANIMSTRUCT_0D
+ add hl, bc
+ ld e, [hl]
+ inc hl
+ ld d, [hl]
+ ld hl, $80
+ add hl, de
+ ld e, l
+ ld d, h
+
+ ld hl, SPRITEANIMSTRUCT_0D
+ add hl, bc
+ ld [hl], e
+ inc hl
+ ld [hl], d
+
+ ld hl, SPRITEANIMSTRUCT_0C
+ add hl, bc
+ ld a, [hl]
+ inc [hl]
+ inc [hl]
+ inc [hl]
+ push af
+ push de
+ call .Sprites_Sine
+
+ ld hl, SPRITEANIMSTRUCT_YOFFSET
+ add hl, bc
+ ld [hl], a
+ pop de
+ pop af
+ call .Sprites_Cosine
+
+ ld hl, SPRITEANIMSTRUCT_XOFFSET
+ add hl, bc
+ ld [hl], a
+ ret
+
+.FlyFrom: ; 8d5b0 (23:55b0)
+ ld hl, SPRITEANIMSTRUCT_YCOORD
+ add hl, bc
+ ld a, [hl]
+ and a
+ ret z
+
+ ld hl, SPRITEANIMSTRUCT_0D
+ add hl, bc
+ ld a, [hl]
+ inc [hl]
+ cp $40
+ ret c
+
+ ld hl, SPRITEANIMSTRUCT_YCOORD
+ add hl, bc
+ dec [hl]
+ dec [hl]
+
+ ld hl, SPRITEANIMSTRUCT_0F
+ add hl, bc
+ ld a, [hl]
+ ld d, a
+ cp $40
+ jr nc, .skip
+ add $8
+ ld [hl], a
+.skip
+ ld hl, SPRITEANIMSTRUCT_0E
+ add hl, bc
+ ld a, [hl]
+ inc [hl]
+ call .Sprites_Cosine
+
+ ld hl, SPRITEANIMSTRUCT_XOFFSET
+ add hl, bc
+ ld [hl], a
+ ret
+
+.FlyLeaf: ; 8d5e2 (23:55e2)
+ ld hl, SPRITEANIMSTRUCT_XCOORD
+ add hl, bc
+ ld a, [hl]
+ cp -9 * 8
+ jr nc, .delete_leaf
+ inc [hl]
+ inc [hl]
+
+ ld hl, SPRITEANIMSTRUCT_YCOORD
+ add hl, bc
+ dec [hl]
+
+ ld d, $40
+ ld hl, SPRITEANIMSTRUCT_0C
+ add hl, bc
+ ld a, [hl]
+ inc [hl]
+ call .Sprites_Cosine
+
+ ld hl, SPRITEANIMSTRUCT_XOFFSET
+ add hl, bc
+ ld [hl], a
+ ret
+
+.delete_leaf
+ call DeinitializeSprite
+ ret
+
+.FlyTo: ; 8d607 (23:5607)
+ ld hl, SPRITEANIMSTRUCT_YCOORD
+ add hl, bc
+ ld a, [hl]
+ cp 10 * 8 + 4
+ ret z
+
+ ld hl, SPRITEANIMSTRUCT_YCOORD
+ add hl, bc
+ inc [hl]
+ inc [hl]
+
+ ld hl, SPRITEANIMSTRUCT_0F
+ add hl, bc
+ ld a, [hl]
+ ld d, a
+ and a
+ jr z, .asm_8d621
+ sub $2
+ ld [hl], a
+.asm_8d621
+ ld hl, SPRITEANIMSTRUCT_0E
+ add hl, bc
+ ld a, [hl]
+ inc [hl]
+ call .Sprites_Cosine
+
+ ld hl, SPRITEANIMSTRUCT_XOFFSET
+ add hl, bc
+ ld [hl], a
+ ret
+
+.MobileTradeSentPulse ; 8d630 (23:5630)
+ farcall Function108bc7
+ ret
+
+.MobileTradeOTPulse ; 8d637 (23:5637)
+ farcall Function108be0
+ ret
+
+.IntroSuicune ; 8d63e (23:563e)
+ ld a, [wcf65]
+ and a
+ jr nz, .asm_8d645
+ ret
+.asm_8d645
+ ld hl, SPRITEANIMSTRUCT_YOFFSET
+ add hl, bc
+ ld [hl], $0
+
+ ld hl, SPRITEANIMSTRUCT_0D
+ add hl, bc
+ ld a, [hl]
+ add $2
+ ld [hl], a
+ xor $ff
+ inc a
+ ld d, $20
+ call .Sprites_Sine
+
+ ld hl, SPRITEANIMSTRUCT_YOFFSET
+ add hl, bc
+ ld [hl], a
+ ld a, SPRITE_ANIM_FRAMESET_INTRO_SUICUNE_2
+ call _ReinitSpriteAnimFrame
+ ret
+
+.IntroPichuWooper ; 8d666 (23:5666)
+ ld hl, SPRITEANIMSTRUCT_0C
+ add hl, bc
+ ld a, [hl]
+ cp $14
+ jr nc, .asm_8d67f
+ add $2
+ ld [hl], a
+ xor $ff
+ inc a
+ ld d, $20
+ call .Sprites_Sine
+
+ ld hl, SPRITEANIMSTRUCT_YOFFSET
+ add hl, bc
+ ld [hl], a
+.asm_8d67f
+ ret
+
+.IntroUnown ; 8d680 (23:5680)
+ ld hl, SPRITEANIMSTRUCT_JUMPTABLE_INDEX
+ add hl, bc
+ ld d, [hl]
+ inc [hl]
+ inc [hl]
+ inc [hl]
+
+ ld hl, SPRITEANIMSTRUCT_0C
+ add hl, bc
+ ld a, [hl]
+ push af
+ push de
+ call .Sprites_Sine
+
+ ld hl, SPRITEANIMSTRUCT_YOFFSET
+ add hl, bc
+ ld [hl], a
+ pop de
+ pop af
+ call .Sprites_Cosine
+
+ ld hl, SPRITEANIMSTRUCT_XOFFSET
+ add hl, bc
+ ld [hl], a
+ ret
+
+.IntroUnownF ; 8d6a2 (23:56a2)
+ ld a, [wcf64]
+ cp $40
+ ret nz
+ ld a, SPRITE_ANIM_FRAMESET_INTRO_UNOWN_F_2
+ call _ReinitSpriteAnimFrame
+ ret
+
+.IntroSuicuneAway ; 8d6ae (23:56ae)
+ ld hl, SPRITEANIMSTRUCT_YCOORD
+ add hl, bc
+ ld a, [hl]
+ add $10
+ ld [hl], a
+ ret
+
+.EZChatCursor ; 8d6b7 (23:56b7)
+ farcall AnimateEZChatCursor
+ ret
+
+.Celebi ; 8d6be (23:56be)
+ farcall UpdateCelebiPosition
+ ret
+
+.AnonymousJumptable: ; 8d6c5 (23:56c5)
+ ld hl, sp+$0
+ ld e, [hl]
+ inc hl
+ ld d, [hl]
+ inc de
+
+ ld hl, SPRITEANIMSTRUCT_JUMPTABLE_INDEX
+ add hl, bc
+ ld l, [hl]
+ ld h, $0
+ add hl, hl
+ add hl, de
+ ld a, [hli]
+ ld h, [hl]
+ ld l, a
+ ret
+; 8d6d8 (23:56d8)
+
+.IncrementJumptableIndex: ; 8d6d8
+ ld hl, SPRITEANIMSTRUCT_JUMPTABLE_INDEX
+ add hl, bc
+ inc [hl]
+ ret
+; 8d6de
+
+.Sprites_Sine: ; 8d6de (23:56de)
+ call Sprites_Sine
+ ret
+
+.Sprites_Cosine: ; 8d6e2 (23:56e2)
+ call Sprites_Cosine
+ ret
+; 8d6e6 (23:56e6)
diff --git a/engine/gfx/sprites.asm b/engine/gfx/sprites.asm
new file mode 100755
index 000000000..63666c624
--- /dev/null
+++ b/engine/gfx/sprites.asm
@@ -0,0 +1,677 @@
+ClearSpriteAnims: ; 8cf53
+ ld hl, wSpriteAnimDict
+ ld bc, wSpriteAnimsEnd - wSpriteAnimDict
+.loop
+ ld [hl], $0
+ inc hl
+ dec bc
+ ld a, c
+ or b
+ jr nz, .loop
+ ret
+; 8cf62
+
+PlaySpriteAnimationsAndDelayFrame: ; 8cf62
+ call PlaySpriteAnimations
+ call DelayFrame
+ ret
+; 8cf69
+
+PlaySpriteAnimations: ; 8cf69
+ push hl
+ push de
+ push bc
+ push af
+
+ ld a, LOW(wVirtualOAM)
+ ld [wCurrSpriteOAMAddr], a
+ call DoNextFrameForAllSprites
+
+ pop af
+ pop bc
+ pop de
+ pop hl
+ ret
+; 8cf7a
+
+DoNextFrameForAllSprites: ; 8cf7a
+ ld hl, wSpriteAnimationStructs
+ ld e, NUM_SPRITE_ANIM_STRUCTS
+
+.loop
+ ld a, [hl]
+ and a
+ jr z, .next ; This struct is deinitialized.
+ ld c, l
+ ld b, h
+ push hl
+ push de
+ call DoAnimFrame ; Uses a massive dw
+ call UpdateAnimFrame
+ pop de
+ pop hl
+ jr c, .done
+
+.next
+ ld bc, SPRITEANIMSTRUCT_LENGTH
+ add hl, bc
+ dec e
+ jr nz, .loop
+
+ ld a, [wCurrSpriteOAMAddr]
+ ld l, a
+ ld h, HIGH(wVirtualOAM)
+
+.loop2 ; Clear (wVirtualOAM + [wCurrSpriteOAMAddr] --> wVirtualOAMEnd)
+ ld a, l
+ cp LOW(wVirtualOAMEnd)
+ jr nc, .done
+ xor a
+ ld [hli], a
+ jr .loop2
+
+.done
+ ret
+; 8cfa8
+
+DoNextFrameForFirst16Sprites: ; 8cfa8 (23:4fa8)
+ ld hl, wSpriteAnimationStructs
+ ld e, NUM_SPRITE_ANIM_STRUCTS
+
+.loop
+ ld a, [hl]
+ and a
+ jr z, .next
+ ld c, l
+ ld b, h
+ push hl
+ push de
+ call DoAnimFrame ; Uses a massive dw
+ call UpdateAnimFrame
+ pop de
+ pop hl
+ jr c, .done
+
+.next
+ ld bc, SPRITEANIMSTRUCT_LENGTH
+ add hl, bc
+ dec e
+ jr nz, .loop
+
+ ld a, [wCurrSpriteOAMAddr]
+ ld l, a
+ ld h, HIGH(wVirtualOAMSprite16)
+
+.loop2 ; Clear (wVirtualOAM + [wCurrSpriteOAMAddr] --> Sprites + $40)
+ ld a, l
+ cp LOW(wVirtualOAMSprite16)
+ jr nc, .done
+ xor a
+ ld [hli], a
+ jr .loop2
+
+.done
+ ret
+
+InitSpriteAnimStruct:: ; 8cfd6
+; Initialize animation a at pixel x=e, y=d
+; Find if there's any room in the wSpriteAnimationStructs array, which is 10x16
+ push de
+ push af
+ ld hl, wSpriteAnimationStructs
+ ld e, NUM_SPRITE_ANIM_STRUCTS
+.loop
+ ld a, [hl]
+ and a
+ jr z, .found
+ ld bc, SPRITEANIMSTRUCT_LENGTH
+ add hl, bc
+ dec e
+ jr nz, .loop
+; We've reached the end. There is no more room here.
+; Return carry.
+ pop af
+ pop de
+ scf
+ ret
+
+.found
+; Back up the structure address to bc.
+ ld c, l
+ ld b, h
+; Value [wSpriteAnimCount] is initially set to -1. Set it to
+; the number of objects loaded into this array.
+ ld hl, wSpriteAnimCount
+ inc [hl]
+ ld a, [hl]
+ and a
+ jr nz, .initialized
+ inc [hl]
+
+.initialized
+; Get row a of SpriteAnimSeqData, copy the pointer into de
+ pop af
+ ld e, a
+ ld d, 0
+ ld hl, SpriteAnimSeqData
+ add hl, de
+ add hl, de
+ add hl, de
+ ld e, l
+ ld d, h
+; Set hl to the first field (field 0) in the current structure.
+ ld hl, SPRITEANIMSTRUCT_INDEX
+ add hl, bc
+; Load the index.
+ ld a, [wSpriteAnimCount]
+ ld [hli], a
+; Copy the table entry to the next two fields.
+ ld a, [de]
+ ld [hli], a
+ inc de
+ ld a, [de]
+ ld [hli], a
+ inc de
+; Look up the third field from the table in the wSpriteAnimDict array (10x2).
+; Take the value and load it in
+ ld a, [de]
+ call GetSpriteAnimVTile
+ ld [hli], a
+ pop de
+; Set hl to field 4 (X coordinate). Kinda pointless, because we're presumably already here.
+ ld hl, SPRITEANIMSTRUCT_XCOORD
+ add hl, bc
+; Load the original value of de into here.
+ ld a, e
+ ld [hli], a
+ ld a, d
+ ld [hli], a
+; load 0 into the next four fields
+ xor a
+ ld [hli], a
+ ld [hli], a
+ xor a
+ ld [hli], a
+ ld [hli], a
+; load -1 into the next field
+ dec a
+ ld [hli], a
+; load 0 into the last five fields
+ xor a
+rept 4
+ ld [hli], a
+endr
+ ld [hl], a
+; back up the address of the first field to wSpriteAnimAddrBackup
+ ld a, c
+ ld [wSpriteAnimAddrBackup], a
+ ld a, b
+ ld [wSpriteAnimAddrBackup + 1], a
+ ret
+; 8d036
+
+DeinitializeSprite: ; 8d036
+; Clear the index field of the struct in bc.
+ ld hl, SPRITEANIMSTRUCT_INDEX
+ add hl, bc
+ ld [hl], $0
+ ret
+; 8d03d
+
+
+DeinitializeAllSprites: ; 8d03d (23:503d)
+; Clear the index field of every struct in the wSpriteAnimationStructs array.
+ ld hl, wSpriteAnimationStructs
+ ld bc, SPRITEANIMSTRUCT_LENGTH
+ ld e, NUM_SPRITE_ANIM_STRUCTS
+ xor a
+.loop
+ ld [hl], a
+ add hl, bc
+ dec e
+ jr nz, .loop
+ ret
+
+
+UpdateAnimFrame: ; 8d04c
+ call InitSpriteAnimBuffer ; init WRAM
+ call GetSpriteAnimFrame ; read from a memory array
+ cp -3
+ jr z, .done
+ cp -4
+ jr z, .delete
+ call GetFrameOAMPointer
+ ; add byte to [wCurrAnimVTile]
+ ld a, [wCurrAnimVTile]
+ add [hl]
+ ld [wCurrAnimVTile], a
+ inc hl
+ ; load pointer into hl
+ ld a, [hli]
+ ld h, [hl]
+ ld l, a
+ push bc
+ ld a, [wCurrSpriteOAMAddr]
+ ld e, a
+ ld d, HIGH(wVirtualOAM)
+ ld a, [hli]
+ ld c, a ; number of objects
+.loop
+ ; first byte: y (px)
+ ; [de] = [wCurrAnimYCoord] + [wCurrAnimYOffset] + [wGlobalAnimYOffset] + AddOrSubtractY([hl])
+ ld a, [wCurrAnimYCoord]
+ ld b, a
+ ld a, [wCurrAnimYOffset]
+ add b
+ ld b, a
+ ld a, [wGlobalAnimYOffset]
+ add b
+ ld b, a
+ call AddOrSubtractY
+ add b
+ ld [de], a
+ inc hl
+ inc de
+ ; second byte: x (px)
+ ; [de] = [wCurrAnimXCoord] + [wCurrAnimXOffset] + [wGlobalAnimXOffset] + AddOrSubtractX([hl])
+ ld a, [wCurrAnimXCoord]
+ ld b, a
+ ld a, [wCurrAnimXOffset]
+ add b
+ ld b, a
+ ld a, [wGlobalAnimXOffset]
+ add b
+ ld b, a
+ call AddOrSubtractX
+ add b
+ ld [de], a
+ inc hl
+ inc de
+ ; third byte: vtile
+ ; [de] = [wCurrAnimVTile] + [hl]
+ ld a, [wCurrAnimVTile]
+ add [hl]
+ ld [de], a
+ inc hl
+ inc de
+ ; fourth byte: attributes
+ ; [de] = GetSpriteOAMAttr([hl])
+ call GetSpriteOAMAttr
+ ld [de], a
+ inc hl
+ inc de
+ ld a, e
+ ld [wCurrSpriteOAMAddr], a
+ cp LOW(wVirtualOAMEnd)
+ jr nc, .reached_the_end
+ dec c
+ jr nz, .loop
+ pop bc
+ jr .done
+
+.delete
+ call DeinitializeSprite
+.done
+ and a
+ ret
+
+.reached_the_end
+ pop bc
+ scf
+ ret
+; 8d0be
+
+AddOrSubtractY: ; 8d0be
+ push hl
+ ld a, [hl]
+ ld hl, wCurrSpriteAddSubFlags
+ bit 6, [hl]
+ jr z, .ok
+ ; 8 - a
+ add $8
+ xor $ff
+ inc a
+
+.ok
+ pop hl
+ ret
+; 8d0ce
+
+AddOrSubtractX: ; 8d0ce
+ push hl
+ ld a, [hl]
+ ld hl, wCurrSpriteAddSubFlags
+ bit 5, [hl] ; x flip
+ jr z, .ok
+ ; 8 - a
+ add $8
+ xor $ff
+ inc a
+
+.ok
+ pop hl
+ ret
+; 8d0de
+
+GetSpriteOAMAttr: ; 8d0de
+ ld a, [wCurrSpriteAddSubFlags]
+ ld b, a
+ ld a, [hl]
+ xor b
+ and $e0
+ ld b, a
+ ld a, [hl]
+ and $1f
+ or b
+ ret
+; 8d0ec
+
+InitSpriteAnimBuffer: ; 8d0ec
+ xor a
+ ld [wCurrSpriteAddSubFlags], a
+ ld hl, SPRITEANIMSTRUCT_TILE_ID
+ add hl, bc
+ ld a, [hli]
+ ld [wCurrAnimVTile], a
+ ld a, [hli]
+ ld [wCurrAnimXCoord], a
+ ld a, [hli]
+ ld [wCurrAnimYCoord], a
+ ld a, [hli]
+ ld [wCurrAnimXOffset], a
+ ld a, [hli]
+ ld [wCurrAnimYOffset], a
+ ret
+; 8d109
+
+GetSpriteAnimVTile: ; 8d109
+; a = wSpriteAnimDict[a] if a in wSpriteAnimDict else 0
+; vTiles offset
+ push hl
+ push bc
+ ld hl, wSpriteAnimDict
+ ld b, a
+ ld c, NUM_SPRITE_ANIM_STRUCTS
+.loop
+ ld a, [hli]
+ cp b
+ jr z, .ok
+ inc hl
+ dec c
+ jr nz, .loop
+ xor a
+ jr .done
+
+.ok
+ ld a, [hl]
+
+.done
+ pop bc
+ pop hl
+ ret
+; 8d120
+
+_ReinitSpriteAnimFrame:: ; 8d120
+ ld hl, SPRITEANIMSTRUCT_FRAMESET_ID
+ add hl, bc
+ ld [hl], a
+ ld hl, SPRITEANIMSTRUCT_DURATION
+ add hl, bc
+ ld [hl], 0
+ ld hl, SPRITEANIMSTRUCT_FRAME
+ add hl, bc
+ ld [hl], -1
+ ret
+; 8d132
+
+
+GetSpriteAnimFrame: ; 8d132
+.loop
+ ld hl, SPRITEANIMSTRUCT_DURATION
+ add hl, bc
+ ld a, [hl]
+ and a
+ jr z, .next_frame ; finished the current sequence
+ dec [hl]
+ call .GetPointer ; load pointer from SpriteAnimFrameData
+ ld a, [hli]
+ push af
+ jr .okay
+
+.next_frame
+ ld hl, SPRITEANIMSTRUCT_FRAME
+ add hl, bc
+ inc [hl]
+ call .GetPointer ; load pointer from SpriteAnimFrameData
+ ld a, [hli]
+ cp dorestart_command
+ jr z, .restart
+ cp endanim_command
+ jr z, .repeat_last
+
+ push af
+ ld a, [hl]
+ push hl
+ and $3f
+ ld hl, SPRITEANIMSTRUCT_DURATIONOFFSET
+ add hl, bc
+ add [hl]
+ ld hl, SPRITEANIMSTRUCT_DURATION
+ add hl, bc
+ ld [hl], a
+ pop hl
+.okay
+ ld a, [hl]
+ and $c0
+ srl a
+ ld [wCurrSpriteAddSubFlags], a
+ pop af
+ ret
+
+.repeat_last
+ xor a
+ ld hl, SPRITEANIMSTRUCT_DURATION
+ add hl, bc
+ ld [hl], a
+
+ ld hl, SPRITEANIMSTRUCT_FRAME
+ add hl, bc
+ dec [hl]
+ dec [hl]
+ jr .loop
+
+.restart
+ xor a
+ ld hl, SPRITEANIMSTRUCT_DURATION
+ add hl, bc
+ ld [hl], a
+
+ dec a
+ ld hl, SPRITEANIMSTRUCT_FRAME
+ add hl, bc
+ ld [hl], a
+ jr .loop
+; 8d189
+
+.GetPointer: ; 8d189
+ ; Get the data for the current frame for the current animation sequence
+
+ ; SpriteAnimFrameData[SpriteAnim[SPRITEANIMSTRUCT_FRAMESET_ID]][SpriteAnim[SPRITEANIMSTRUCT_FRAME]]
+ ld hl, SPRITEANIMSTRUCT_FRAMESET_ID
+ add hl, bc
+ ld e, [hl]
+ ld d, 0
+ ld hl, SpriteAnimFrameData
+ add hl, de
+ add hl, de
+ ld e, [hl]
+ inc hl
+ ld d, [hl]
+ ld hl, SPRITEANIMSTRUCT_FRAME
+ add hl, bc
+ ld l, [hl]
+ ld h, 0
+ add hl, hl
+ add hl, de
+ ret
+; 8d1a2
+
+GetFrameOAMPointer: ; 8d1a2
+; Load OAM data pointer
+ ld e, a
+ ld d, 0
+ ld hl, SpriteAnimOAMData
+ add hl, de
+ add hl, de
+ add hl, de
+ ret
+; 8d1ac
+
+Unreferenced_BrokenGetStdGraphics: ; 8d1ac
+ push hl
+ ld l, a
+ ld h, 0
+ add hl, hl
+ add hl, hl
+ ld de, BrokenStdGFXPointers ; broken 2bpp pointers
+ add hl, de
+ ld c, [hl]
+ inc hl
+ ld b, [hl]
+ inc hl
+ ld e, [hl]
+ inc hl
+ ld d, [hl]
+ pop hl
+ push bc
+ call Request2bpp
+ pop bc
+ ret
+; 8d1c4
+
+
+INCLUDE "data/sprite_anims/sequences.asm"
+
+INCLUDE "engine/gfx/sprite_anims.asm"
+
+INCLUDE "data/sprite_anims/framesets.asm"
+
+INCLUDE "data/sprite_anims/oam.asm"
+
+
+BrokenStdGFXPointers:
+ ; tile count, bank, pointer
+ ; (all pointers were dummied out to .deleted)
+ dbbw 128, $01, .deleted
+ dbbw 128, $01, .deleted
+ dbbw 128, $01, .deleted
+ dbbw 128, $01, .deleted
+ dbbw 16, $37, .deleted
+ dbbw 16, $11, .deleted
+ dbbw 16, $39, .deleted
+ dbbw 16, $24, .deleted
+ dbbw 16, $21, .deleted
+
+.deleted
+; 8e72a (23:672a)
+
+
+Sprites_Cosine: ; 8e72a
+; a = d * cos(a * pi/32)
+ add %010000 ; cos(x) = sin(x + pi/2)
+ ; fallthrough
+Sprites_Sine: ; 8e72c
+; a = d * sin(a * pi/32)
+ calc_sine_wave
+
+
+AnimateEndOfExpBar: ; 8e79d
+ ld a, [hSGB]
+ ld de, EndOfExpBarGFX
+ and a
+ jr z, .load
+ ld de, SGBEndOfExpBarGFX
+
+.load
+ ld hl, vTiles0 tile $00
+ lb bc, BANK(EndOfExpBarGFX), 1
+ call Request2bpp
+ ld c, 8
+ ld d, 0
+.loop
+ push bc
+ call .AnimateFrame
+ call DelayFrame
+ pop bc
+ inc d
+ inc d
+ dec c
+ jr nz, .loop
+ call ClearSprites
+ ret
+; 8e7c6
+
+.AnimateFrame: ; 8e7c6
+ ld hl, wVirtualOAMSprite00
+ ld c, 8 ; number of animated circles
+.anim_loop
+ ld a, c
+ and a
+ ret z
+ dec c
+ ld a, c
+; multiply by 8
+ sla a
+ sla a
+ sla a
+ push af
+
+ push de
+ push hl
+ call Sprites_Sine
+ pop hl
+ pop de
+ add 13 * TILE_WIDTH
+ ld [hli], a ; y
+
+ pop af
+ push de
+ push hl
+ call Sprites_Cosine
+ pop hl
+ pop de
+ add 10 * TILE_WIDTH + 4
+ ld [hli], a ; x
+
+ ld a, $0
+ ld [hli], a ; tile id
+ ld a, PAL_BATTLE_OB_BLUE
+ ld [hli], a ; attributes
+ jr .anim_loop
+; 8e7f4
+
+EndOfExpBarGFX: ; 8e7f4
+INCBIN "gfx/battle/expbarend.2bpp"
+SGBEndOfExpBarGFX: ; 8e804
+INCBIN "gfx/battle/expbarend_sgb.2bpp"
+
+ClearSpriteAnims2: ; 8e814
+ push hl
+ push de
+ push bc
+ push af
+ ld hl, wSpriteAnimDict
+ ld bc, wSpriteAnimsEnd - wSpriteAnimDict
+.loop
+ ld [hl], 0
+ inc hl
+ dec bc
+ ld a, c
+ or b
+ jr nz, .loop
+ pop af
+ pop bc
+ pop de
+ pop hl
+ ret
+; 8e82b
diff --git a/engine/gfx/tileset_anims.asm b/engine/gfx/tileset_anims.asm
new file mode 100644
index 000000000..bf0037e65
--- /dev/null
+++ b/engine/gfx/tileset_anims.asm
@@ -0,0 +1,1060 @@
+_AnimateTileset:: ; fc000
+; Iterate over a given pointer array of
+; animation functions (one per frame).
+
+; Typically in wra1, vra0
+
+ ld a, [wTilesetAnim]
+ ld e, a
+ ld a, [wTilesetAnim + 1]
+ ld d, a
+
+ ld a, [hTileAnimFrame]
+ ld l, a
+ inc a
+ ld [hTileAnimFrame], a
+
+ ld h, 0
+ add hl, hl
+ add hl, hl
+ add hl, de
+
+; 2-byte parameter
+; All functions take input de.
+ ld e, [hl]
+ inc hl
+ ld d, [hl]
+ inc hl
+
+; Function address
+ ld a, [hli]
+ ld h, [hl]
+ ld l, a
+
+ jp hl
+; fc01b
+
+Tileset0Anim: ; 0xfc01b
+TilesetJohtoModernAnim: ; 0xfc01b
+TilesetKantoAnim: ; 0xfc01b
+ dw vTiles2 tile $14, AnimateWaterTile
+ dw NULL, WaitTileAnimation
+ dw NULL, WaitTileAnimation
+ dw NULL, WaitTileAnimation
+ dw NULL, TileAnimationPalette
+ dw NULL, WaitTileAnimation
+ dw NULL, AnimateFlowerTile
+ dw NULL, WaitTileAnimation
+ dw NULL, WaitTileAnimation
+ dw NULL, StandingTileFrame8
+ dw NULL, DoneTileAnimation
+; 0xfc047
+
+TilesetParkAnim: ; 0xfc047
+ dw vTiles2 tile $14, AnimateWaterTile
+ dw NULL, WaitTileAnimation
+ dw vTiles2 tile $5f, AnimateFountain
+ dw NULL, WaitTileAnimation
+ dw NULL, TileAnimationPalette
+ dw NULL, WaitTileAnimation
+ dw NULL, AnimateFlowerTile
+ dw NULL, WaitTileAnimation
+ dw NULL, WaitTileAnimation
+ dw NULL, StandingTileFrame8
+ dw NULL, DoneTileAnimation
+; 0xfc073
+
+TilesetForestAnim: ; 0xfc073
+ dw NULL, ForestTreeLeftAnimation
+ dw NULL, ForestTreeRightAnimation
+ dw NULL, WaitTileAnimation
+ dw NULL, WaitTileAnimation
+ dw NULL, WaitTileAnimation
+ dw NULL, ForestTreeLeftAnimation2
+ dw NULL, ForestTreeRightAnimation2
+ dw NULL, AnimateFlowerTile
+ dw vTiles2 tile $14, AnimateWaterTile
+ dw NULL, TileAnimationPalette
+ dw NULL, StandingTileFrame8
+ dw NULL, DoneTileAnimation
+; 0xfc0a3
+
+TilesetJohtoAnim: ; 0xfc0a3
+ dw vTiles2 tile $14, AnimateWaterTile
+ dw NULL, WaitTileAnimation
+ dw NULL, WaitTileAnimation
+ dw NULL, TileAnimationPalette
+ dw NULL, WaitTileAnimation
+ dw NULL, AnimateFlowerTile
+ dw WhirlpoolFrames1, AnimateWhirlpoolTile
+ dw WhirlpoolFrames2, AnimateWhirlpoolTile
+ dw WhirlpoolFrames3, AnimateWhirlpoolTile
+ dw WhirlpoolFrames4, AnimateWhirlpoolTile
+ dw NULL, WaitTileAnimation
+ dw NULL, StandingTileFrame8
+ dw NULL, DoneTileAnimation
+; 0xfc0d7
+
+UnusedTilesetAnim_fc0d7: ; 0xfc0d7
+ dw vTiles2 tile $03, WriteTileToBuffer
+ dw wTileAnimBuffer, ScrollTileRightLeft
+ dw vTiles2 tile $03, WriteTileFromBuffer
+ dw NULL, WaitTileAnimation
+ dw NULL, WaitTileAnimation
+ dw NULL, WaitTileAnimation
+ dw NULL, AnimateFlowerTile
+ dw NULL, WaitTileAnimation
+ dw NULL, WaitTileAnimation
+ dw NULL, WaitTileAnimation
+ dw NULL, DoneTileAnimation
+; 0xfc103
+
+UnusedTilesetAnim_fc103: ; 0xfc103
+ dw vTiles2 tile $14, WriteTileToBuffer
+ dw wTileAnimBuffer, ScrollTileRightLeft
+ dw vTiles2 tile $14, WriteTileFromBuffer
+ dw NULL, WaitTileAnimation
+ dw NULL, WaitTileAnimation
+ dw NULL, WaitTileAnimation
+ dw NULL, WaitTileAnimation
+ dw NULL, WaitTileAnimation
+ dw NULL, WaitTileAnimation
+ dw NULL, WaitTileAnimation
+ dw NULL, DoneTileAnimation
+; 0xfc12f
+
+TilesetPortAnim: ; 0xfc12f
+ dw vTiles2 tile $14, AnimateWaterTile
+ dw NULL, WaitTileAnimation
+ dw NULL, WaitTileAnimation
+ dw NULL, WaitTileAnimation
+ dw NULL, WaitTileAnimation
+ dw NULL, TileAnimationPalette
+ dw NULL, WaitTileAnimation
+ dw NULL, WaitTileAnimation
+ dw NULL, WaitTileAnimation
+ dw NULL, WaitTileAnimation
+ dw NULL, StandingTileFrame8
+ dw NULL, DoneTileAnimation
+; 0xfc15f
+
+TilesetEliteFourRoomAnim: ; 0xfc15f
+ dw NULL, LavaBubbleAnim2
+ dw NULL, WaitTileAnimation
+ dw NULL, WaitTileAnimation
+ dw NULL, WaitTileAnimation
+ dw NULL, LavaBubbleAnim1
+ dw NULL, WaitTileAnimation
+ dw NULL, StandingTileFrame8
+ dw NULL, DoneTileAnimation
+; 0xfc17f
+
+UnusedTilesetAnim_fc17f: ; 0xfc17f
+ dw vTiles2 tile $53, WriteTileToBuffer
+ dw wTileAnimBuffer, ScrollTileDown
+ dw wTileAnimBuffer, ScrollTileDown
+ dw vTiles2 tile $53, WriteTileFromBuffer
+ dw vTiles2 tile $03, WriteTileToBuffer
+ dw wTileAnimBuffer, ScrollTileRightLeft
+ dw vTiles2 tile $03, WriteTileFromBuffer
+ dw vTiles2 tile $53, WriteTileToBuffer
+ dw wTileAnimBuffer, ScrollTileDown
+ dw wTileAnimBuffer, ScrollTileDown
+ dw vTiles2 tile $53, WriteTileFromBuffer
+ dw NULL, DoneTileAnimation
+; 0xfc1af
+
+UnusedTilesetAnim_fc1af: ; 0xfc1af
+ dw vTiles2 tile $54, WriteTileToBuffer
+ dw wTileAnimBuffer, ScrollTileDown
+ dw wTileAnimBuffer, ScrollTileDown
+ dw vTiles2 tile $54, WriteTileFromBuffer
+ dw NULL, WaitTileAnimation
+ dw vTiles2 tile $03, WriteTileToBuffer
+ dw wTileAnimBuffer, ScrollTileRightLeft
+ dw vTiles2 tile $03, WriteTileFromBuffer
+ dw NULL, WaitTileAnimation
+ dw vTiles2 tile $54, WriteTileToBuffer
+ dw wTileAnimBuffer, ScrollTileDown
+ dw wTileAnimBuffer, ScrollTileDown
+ dw vTiles2 tile $54, WriteTileFromBuffer
+ dw NULL, DoneTileAnimation
+; 0xfc1e7
+
+TilesetCaveAnim: ; 0xfc1e7
+TilesetDarkCaveAnim: ; 0xfc1e7
+ dw vTiles2 tile $14, WriteTileToBuffer
+ dw NULL, FlickeringCaveEntrancePalette
+ dw wTileAnimBuffer, ScrollTileRightLeft
+ dw NULL, FlickeringCaveEntrancePalette
+ dw vTiles2 tile $14, WriteTileFromBuffer
+ dw NULL, FlickeringCaveEntrancePalette
+ dw NULL, TileAnimationPalette
+ dw NULL, FlickeringCaveEntrancePalette
+ dw vTiles2 tile $40, WriteTileToBuffer
+ dw NULL, FlickeringCaveEntrancePalette
+ dw wTileAnimBuffer, ScrollTileDown
+ dw NULL, FlickeringCaveEntrancePalette
+ dw wTileAnimBuffer, ScrollTileDown
+ dw NULL, FlickeringCaveEntrancePalette
+ dw wTileAnimBuffer, ScrollTileDown
+ dw NULL, FlickeringCaveEntrancePalette
+ dw vTiles2 tile $40, WriteTileFromBuffer
+ dw NULL, FlickeringCaveEntrancePalette
+ dw NULL, DoneTileAnimation
+; 0xfc233
+
+TilesetIcePathAnim: ; 0xfc233
+ dw vTiles2 tile $35, WriteTileToBuffer
+ dw NULL, FlickeringCaveEntrancePalette
+ dw wTileAnimBuffer, ScrollTileRightLeft
+ dw NULL, FlickeringCaveEntrancePalette
+ dw vTiles2 tile $35, WriteTileFromBuffer
+ dw NULL, FlickeringCaveEntrancePalette
+ dw NULL, TileAnimationPalette
+ dw NULL, FlickeringCaveEntrancePalette
+ dw vTiles2 tile $31, WriteTileToBuffer
+ dw NULL, FlickeringCaveEntrancePalette
+ dw wTileAnimBuffer, ScrollTileDown
+ dw NULL, FlickeringCaveEntrancePalette
+ dw wTileAnimBuffer, ScrollTileDown
+ dw NULL, FlickeringCaveEntrancePalette
+ dw wTileAnimBuffer, ScrollTileDown
+ dw NULL, FlickeringCaveEntrancePalette
+ dw vTiles2 tile $31, WriteTileFromBuffer
+ dw NULL, FlickeringCaveEntrancePalette
+ dw NULL, DoneTileAnimation
+; 0xfc27f
+
+TilesetTowerAnim: ; 0xfc27f
+ dw TowerPillarTilePointer9, AnimateTowerPillarTile
+ dw TowerPillarTilePointer10, AnimateTowerPillarTile
+ dw TowerPillarTilePointer7, AnimateTowerPillarTile
+ dw TowerPillarTilePointer8, AnimateTowerPillarTile
+ dw TowerPillarTilePointer5, AnimateTowerPillarTile
+ dw TowerPillarTilePointer6, AnimateTowerPillarTile
+ dw TowerPillarTilePointer3, AnimateTowerPillarTile
+ dw TowerPillarTilePointer4, AnimateTowerPillarTile
+ dw TowerPillarTilePointer1, AnimateTowerPillarTile
+ dw TowerPillarTilePointer2, AnimateTowerPillarTile
+ dw NULL, StandingTileFrame
+ dw NULL, WaitTileAnimation
+ dw NULL, WaitTileAnimation
+ dw NULL, WaitTileAnimation
+ dw NULL, WaitTileAnimation
+ dw NULL, DoneTileAnimation
+; 0xfc2bf
+
+UnusedTilesetAnim_fc2bf: ; 0xfc2bf
+ dw vTiles2 tile $4f, WriteTileToBuffer
+ dw wTileAnimBuffer, ScrollTileRightLeft
+ dw vTiles2 tile $4f, WriteTileFromBuffer
+ dw NULL, WaitTileAnimation
+ dw NULL, WaitTileAnimation
+ dw NULL, WaitTileAnimation
+ dw NULL, WaitTileAnimation
+ dw NULL, WaitTileAnimation
+ dw NULL, WaitTileAnimation
+ dw NULL, DoneTileAnimation
+; 0xfc2e7
+
+TilesetBattleTowerOutsideAnim: ; 0xfc2e7
+TilesetHouseAnim: ; 0xfc2e7
+TilesetPlayersHouseAnim: ; 0xfc2e7
+TilesetPokecenterAnim: ; 0xfc2e7
+TilesetGateAnim: ; 0xfc2e7
+TilesetLabAnim: ; 0xfc2e7
+TilesetFacilityAnim: ; 0xfc2e7
+TilesetMartAnim: ; 0xfc2e7
+TilesetMansionAnim: ; 0xfc2e7
+TilesetGameCornerAnim: ; 0xfc2e7
+TilesetTraditionalHouseAnim: ; 0xfc2e7
+TilesetTrainStationAnim: ; 0xfc2e7
+TilesetChampionsRoomAnim: ; 0xfc2e7
+TilesetLighthouseAnim: ; 0xfc2e7
+TilesetPlayersRoomAnim: ; 0xfc2e7
+TilesetPokeComCenterAnim: ; 0xfc2e7
+TilesetBattleTowerAnim: ; 0xfc2e7
+TilesetRuinsOfAlphAnim: ; 0xfc2e7
+TilesetRadioTowerAnim: ; 0xfc2e7
+TilesetUndergroundAnim: ; 0xfc2e7
+TilesetBetaWordRoomAnim: ; 0xfc2e7
+TilesetHoOhWordRoomAnim: ; 0xfc2e7
+TilesetKabutoWordRoomAnim: ; 0xfc2e7
+TilesetOmanyteWordRoomAnim: ; 0xfc2e7
+TilesetAerodactylWordRoomAnim: ; 0xfc2e7
+ dw NULL, WaitTileAnimation
+ dw NULL, WaitTileAnimation
+ dw NULL, WaitTileAnimation
+ dw NULL, WaitTileAnimation
+ dw NULL, DoneTileAnimation
+; 0xfc2fb
+
+DoneTileAnimation: ; fc2fb
+; Reset the animation command loop.
+ xor a
+ ld [hTileAnimFrame], a
+
+WaitTileAnimation: ; fc2fe
+; Do nothing this frame.
+ ret
+; fc2ff
+
+StandingTileFrame8: ; fc2ff
+ ld a, [wTileAnimationTimer]
+ inc a
+ and %111
+ ld [wTileAnimationTimer], a
+ ret
+; fc309
+
+
+ScrollTileRightLeft: ; fc309
+; Scroll right for 4 ticks, then left for 4 ticks.
+ ld a, [wTileAnimationTimer]
+ inc a
+ and %111
+ ld [wTileAnimationTimer], a
+ and %100
+ jr nz, ScrollTileLeft
+ jr ScrollTileRight
+; fc318
+
+ScrollTileUpDown: ; fc318
+; Scroll up for 4 ticks, then down for 4 ticks.
+ ld a, [wTileAnimationTimer]
+ inc a
+ and %111
+ ld [wTileAnimationTimer], a
+ and %100
+ jr nz, ScrollTileDown
+ jr ScrollTileUp
+; fc327
+
+ScrollTileLeft: ; fc327
+ ld h, d
+ ld l, e
+ ld c, 4
+.loop
+rept 4
+ ld a, [hl]
+ rlca
+ ld [hli], a
+endr
+ dec c
+ jr nz, .loop
+ ret
+; fc33b
+
+ScrollTileRight: ; fc33b
+ ld h, d
+ ld l, e
+ ld c, 4
+.loop
+rept 4
+ ld a, [hl]
+ rrca
+ ld [hli], a
+endr
+ dec c
+ jr nz, .loop
+ ret
+; fc34f
+
+ScrollTileUp: ; fc34f
+ ld h, d
+ ld l, e
+ ld d, [hl]
+ inc hl
+ ld e, [hl]
+ ld bc, TILE_WIDTH * 2 - 2
+ add hl, bc
+ ld a, TILE_WIDTH / 2
+.loop
+ ld c, [hl]
+ ld [hl], e
+ dec hl
+ ld b, [hl]
+ ld [hl], d
+ dec hl
+ ld e, [hl]
+ ld [hl], c
+ dec hl
+ ld d, [hl]
+ ld [hl], b
+ dec hl
+ dec a
+ jr nz, .loop
+ ret
+; fc36a
+
+ScrollTileDown: ; fc36a
+ ld h, d
+ ld l, e
+ ld de, TILE_WIDTH * 2 - 2
+ push hl
+ add hl, de
+ ld d, [hl]
+ inc hl
+ ld e, [hl]
+ pop hl
+ ld a, TILE_WIDTH / 2
+.loop
+ ld b, [hl]
+ ld [hl], d
+ inc hl
+ ld c, [hl]
+ ld [hl], e
+ inc hl
+ ld d, [hl]
+ ld [hl], b
+ inc hl
+ ld e, [hl]
+ ld [hl], c
+ inc hl
+ dec a
+ jr nz, .loop
+ ret
+; fc387
+
+
+AnimateFountain: ; fc387
+ ld hl, sp+0
+ ld b, h
+ ld c, l
+ ld hl, .frames
+ ld a, [wTileAnimationTimer]
+ and %111
+ add a
+ add l
+ ld l, a
+ jr nc, .okay
+ inc h
+.okay
+ ld a, [hli]
+ ld h, [hl]
+ ld l, a
+ ld sp, hl
+ ld l, e
+ ld h, d
+ jp WriteTile
+
+.frames
+ dw .frame1
+ dw .frame2
+ dw .frame3
+ dw .frame4
+ dw .frame3
+ dw .frame4
+ dw .frame5
+ dw .frame1
+
+.frame1 INCBIN "gfx/tilesets/fountain/1.2bpp"
+.frame2 INCBIN "gfx/tilesets/fountain/2.2bpp"
+.frame3 INCBIN "gfx/tilesets/fountain/3.2bpp"
+.frame4 INCBIN "gfx/tilesets/fountain/4.2bpp"
+.frame5 INCBIN "gfx/tilesets/fountain/5.2bpp"
+; fc402
+
+
+AnimateWaterTile: ; fc402
+; Draw a water tile for the current frame in VRAM tile at de.
+
+; Save sp in bc (see WriteTile).
+ ld hl, sp+0
+ ld b, h
+ ld c, l
+
+ ld a, [wTileAnimationTimer]
+
+; 4 tile graphics, updated every other frame.
+ and %110
+
+; 2 x 8 = 16 bytes per tile
+ add a
+ add a
+ add a
+
+ add LOW(WaterTileFrames)
+ ld l, a
+ ld a, 0
+ adc HIGH(WaterTileFrames)
+ ld h, a
+
+; The stack now points to the start of the tile for this frame.
+ ld sp, hl
+
+ ld l, e
+ ld h, d
+
+ jp WriteTile
+; fc41c
+
+WaterTileFrames: ; fc41c
+ INCBIN "gfx/tilesets/water/water.2bpp"
+; fc45c
+
+
+ForestTreeLeftAnimation: ; fc45c
+ ld hl, sp+0
+ ld b, h
+ ld c, l
+
+; Only during the Celebi event.
+ ld a, [wCelebiEvent]
+ bit CELEBIEVENT_FOREST_IS_RESTLESS_F, a
+ jr nz, .asm_fc46c
+ ld hl, ForestTreeLeftFrames
+ jr .asm_fc47d
+
+.asm_fc46c
+ ld a, [wTileAnimationTimer]
+ call GetForestTreeFrame
+ add a
+ add a
+ add a
+ add LOW(ForestTreeLeftFrames)
+ ld l, a
+ ld a, 0
+ adc HIGH(ForestTreeLeftFrames)
+ ld h, a
+
+.asm_fc47d
+ ld sp, hl
+ ld hl, vTiles2 tile $0c
+ jp WriteTile
+; fc484
+
+
+ForestTreeLeftFrames: ; fc484
+ INCBIN "gfx/tilesets/forest-tree/1.2bpp"
+ INCBIN "gfx/tilesets/forest-tree/2.2bpp"
+; fc4a4
+
+ForestTreeRightFrames: ; fc4a4
+ INCBIN "gfx/tilesets/forest-tree/3.2bpp"
+ INCBIN "gfx/tilesets/forest-tree/4.2bpp"
+; fc4c4
+
+
+ForestTreeRightAnimation: ; fc4c4
+ ld hl, sp+0
+ ld b, h
+ ld c, l
+
+; Only during the Celebi event.
+ ld a, [wCelebiEvent]
+ bit CELEBIEVENT_FOREST_IS_RESTLESS_F, a
+ jr nz, .asm_fc4d4
+ ld hl, ForestTreeRightFrames
+ jr .asm_fc4eb
+
+.asm_fc4d4
+ ld a, [wTileAnimationTimer]
+ call GetForestTreeFrame
+ add a
+ add a
+ add a
+ add LOW(ForestTreeLeftFrames)
+ ld l, a
+ ld a, 0
+ adc HIGH(ForestTreeLeftFrames)
+ ld h, a
+ push bc
+ ld bc, ForestTreeRightFrames - ForestTreeLeftFrames
+ add hl, bc
+ pop bc
+
+.asm_fc4eb
+ ld sp, hl
+ ld hl, vTiles2 tile $0f
+ jp WriteTile
+; fc4f2
+
+
+ForestTreeLeftAnimation2: ; fc4f2
+ ld hl, sp+0
+ ld b, h
+ ld c, l
+
+; Only during the Celebi event.
+ ld a, [wCelebiEvent]
+ bit CELEBIEVENT_FOREST_IS_RESTLESS_F, a
+ jr nz, .asm_fc502
+ ld hl, ForestTreeLeftFrames
+ jr .asm_fc515
+
+.asm_fc502
+ ld a, [wTileAnimationTimer]
+ call GetForestTreeFrame
+ xor 2
+ add a
+ add a
+ add a
+ add LOW(ForestTreeLeftFrames)
+ ld l, a
+ ld a, 0
+ adc HIGH(ForestTreeLeftFrames)
+ ld h, a
+
+.asm_fc515
+ ld sp, hl
+ ld hl, vTiles2 tile $0c
+ jp WriteTile
+; fc51c
+
+
+ForestTreeRightAnimation2: ; fc51c
+ ld hl, sp+0
+ ld b, h
+ ld c, l
+
+; Only during the Celebi event.
+ ld a, [wCelebiEvent]
+ bit CELEBIEVENT_FOREST_IS_RESTLESS_F, a
+ jr nz, .asm_fc52c
+ ld hl, ForestTreeRightFrames
+ jr .asm_fc545
+
+.asm_fc52c
+ ld a, [wTileAnimationTimer]
+ call GetForestTreeFrame
+ xor 2
+ add a
+ add a
+ add a
+ add LOW(ForestTreeLeftFrames)
+ ld l, a
+ ld a, 0
+ adc HIGH(ForestTreeLeftFrames)
+ ld h, a
+ push bc
+ ld bc, ForestTreeRightFrames - ForestTreeLeftFrames
+ add hl, bc
+ pop bc
+
+.asm_fc545
+ ld sp, hl
+ ld hl, vTiles2 tile $0f
+ jp WriteTile
+; fc54c
+
+
+GetForestTreeFrame: ; fc54c
+; Return 0 if a is even, or 2 if odd.
+ and a
+ jr z, .even
+ cp 1
+ jr z, .odd
+ cp 2
+ jr z, .even
+ cp 3
+ jr z, .odd
+ cp 4
+ jr z, .even
+ cp 5
+ jr z, .odd
+ cp 6
+ jr z, .even
+.odd
+ ld a, 2
+ scf
+ ret
+.even
+ xor a
+ ret
+; fc56d
+
+
+AnimateFlowerTile: ; fc56d
+; No parameters.
+
+; Save sp in bc (see WriteTile).
+ ld hl, sp+0
+ ld b, h
+ ld c, l
+
+; Alternate tile graphic every other frame
+ ld a, [wTileAnimationTimer]
+ and %10
+ ld e, a
+
+; CGB has different color mappings for flowers.
+ ld a, [hCGB]
+ and 1
+
+ add e
+ swap a
+ ld e, a
+ ld d, 0
+ ld hl, FlowerTileFrames
+ add hl, de
+ ld sp, hl
+
+ ld hl, vTiles2 tile $03
+
+ jp WriteTile
+; fc58c
+
+FlowerTileFrames: ; fc58c
+ INCBIN "gfx/tilesets/flower/dmg_1.2bpp"
+ INCBIN "gfx/tilesets/flower/cgb_1.2bpp"
+ INCBIN "gfx/tilesets/flower/dmg_2.2bpp"
+ INCBIN "gfx/tilesets/flower/cgb_2.2bpp"
+; fc5cc
+
+
+LavaBubbleAnim1: ; fc5cc
+; Splash in the bottom-right corner of the fountain.
+ ld hl, sp+0
+ ld b, h
+ ld c, l
+ ld a, [wTileAnimationTimer]
+ and %110
+ srl a
+ inc a
+ inc a
+ and %011
+ swap a
+ ld e, a
+ ld d, 0
+ ld hl, LavaBubbleFrames
+ add hl, de
+ ld sp, hl
+ ld hl, vTiles2 tile $5b
+ jp WriteTile
+; fc5eb
+
+
+LavaBubbleAnim2: ; fc5eb
+; Splash in the top-left corner of the fountain.
+ ld hl, sp+0
+ ld b, h
+ ld c, l
+ ld a, [wTileAnimationTimer]
+ and %110
+ add a
+ add a
+ add a
+ ld e, a
+ ld d, 0
+ ld hl, LavaBubbleFrames
+ add hl, de
+ ld sp, hl
+ ld hl, vTiles2 tile $38
+ jp WriteTile
+; fc605
+
+
+LavaBubbleFrames: ; fc605
+ INCBIN "gfx/tilesets/lava/1.2bpp"
+ INCBIN "gfx/tilesets/lava/2.2bpp"
+ INCBIN "gfx/tilesets/lava/3.2bpp"
+ INCBIN "gfx/tilesets/lava/4.2bpp"
+; fc645
+
+
+AnimateTowerPillarTile: ; fc645
+; Read from struct at de:
+; Destination (VRAM)
+; Address of the first tile in the frame array
+
+ ld hl, sp+0
+ ld b, h
+ ld c, l
+
+ ld a, [wTileAnimationTimer]
+ and %111
+
+; Get frame index a
+ ld hl, .frames
+ add l
+ ld l, a
+ ld a, 0
+ adc h
+ ld h, a
+ ld a, [hl]
+
+; Destination
+ ld l, e
+ ld h, d
+ ld e, [hl]
+ inc hl
+ ld d, [hl]
+ inc hl
+
+; Add the frame index to the starting address
+ add [hl]
+ inc hl
+ ld h, [hl]
+ ld l, a
+ ld a, 0
+ adc h
+ ld h, a
+
+ ld sp, hl
+ ld l, e
+ ld h, d
+ jr WriteTile
+
+.frames
+ db $00, $10, $20, $30, $40, $30, $20, $10
+; fc673
+
+
+StandingTileFrame: ; fc673
+ ld hl, wTileAnimationTimer
+ inc [hl]
+ ret
+; fc678
+
+
+AnimateWhirlpoolTile: ; fc678
+; Update whirlpool tile using struct at de.
+
+; Struct:
+; VRAM address
+; Address of the first tile
+
+; Only does one of 4 tiles at a time.
+
+; Save sp in bc (see WriteTile).
+ ld hl, sp+0
+ ld b, h
+ ld c, l
+
+; de = VRAM address
+ ld l, e
+ ld h, d
+ ld e, [hl]
+ inc hl
+ ld d, [hl]
+ inc hl
+; Tile address is now at hl.
+
+; Get the tile for this frame.
+ ld a, [wTileAnimationTimer]
+ and %11 ; 4 frames x2
+ swap a ; * 16 bytes per tile
+
+ add [hl]
+ inc hl
+ ld h, [hl]
+ ld l, a
+ ld a, 0
+ adc h
+ ld h, a
+
+; The stack now points to the desired frame.
+ ld sp, hl
+
+ ld l, e
+ ld h, d
+
+ jr WriteTile
+; fc696
+
+
+WriteTileFromBuffer: ; fc696
+; Write tiledata at wTileAnimBuffer to de.
+; wTileAnimBuffer is loaded to sp for WriteTile.
+
+ ld hl, sp+0
+ ld b, h
+ ld c, l
+
+ ld hl, wTileAnimBuffer
+ ld sp, hl
+
+ ld h, d
+ ld l, e
+ jr WriteTile
+; fc6a2
+
+
+WriteTileToBuffer: ; fc6a2
+; Write tiledata de to wTileAnimBuffer.
+; de is loaded to sp for WriteTile.
+
+ ld hl, sp+0
+ ld b, h
+ ld c, l
+
+ ld h, d
+ ld l, e
+ ld sp, hl
+
+ ld hl, wTileAnimBuffer
+
+ ; fallthrough
+
+WriteTile: ; fc6ac
+; Write one 8x8 tile ($10 bytes) from sp to hl.
+
+; Warning: sp is saved in bc so we can abuse pop.
+; sp is restored to address bc. Save sp in bc before calling.
+
+ pop de
+ ld [hl], e
+ inc hl
+ ld [hl], d
+
+rept 7
+ pop de
+ inc hl
+ ld [hl], e
+ inc hl
+ ld [hl], d
+endr
+
+; restore sp
+ ld h, b
+ ld l, c
+ ld sp, hl
+ ret
+; fc6d7
+
+
+TileAnimationPalette: ; fc6d7
+; Transition between color values 0-2 for color 0 in palette 3.
+
+; No palette changes on DMG.
+ ld a, [hCGB]
+ and a
+ ret z
+
+; We don't want to mess with non-standard palettes.
+ ld a, [rBGP] ; BGP
+ cp %11100100
+ ret nz
+
+; Only update on even frames.
+ ld a, [wTileAnimationTimer]
+ ld l, a
+ and 1 ; odd
+ ret nz
+
+; Ready for BGPD input...
+
+ ld a, (1 << rBGPI_AUTO_INCREMENT) palette PAL_BG_WATER
+ ld [rBGPI], a
+
+ ld a, [rSVBK]
+ push af
+ ld a, BANK(wBGPals1)
+ ld [rSVBK], a
+
+; Update color 0 in order 0 1 2 1
+ ld a, l
+ and %110 ; frames 0 2 4 6
+ jr z, .color0
+ cp %100 ; frame 4
+ jr z, .color2
+
+.color1
+ ld hl, wBGPals1 palette PAL_BG_WATER color 1
+ ld a, [hli]
+ ld [rBGPD], a
+ ld a, [hli]
+ ld [rBGPD], a
+ jr .end
+
+.color0
+ ld hl, wBGPals1 palette PAL_BG_WATER color 0
+ ld a, [hli]
+ ld [rBGPD], a
+ ld a, [hli]
+ ld [rBGPD], a
+ jr .end
+
+.color2
+ ld hl, wBGPals1 palette PAL_BG_WATER color 2
+ ld a, [hli]
+ ld [rBGPD], a
+ ld a, [hli]
+ ld [rBGPD], a
+
+.end
+ pop af
+ ld [rSVBK], a
+ ret
+; fc71e
+
+
+FlickeringCaveEntrancePalette: ; fc71e
+; No palette changes on DMG.
+ ld a, [hCGB]
+ and a
+ ret z
+; We don't want to mess with non-standard palettes.
+ ld a, [rBGP]
+ cp %11100100
+ ret nz
+; We only want to be here if we're in a dark cave.
+ ld a, [wTimeOfDayPalset]
+ cp %11111111 ; 3,3,3,3
+ ret nz
+
+ ld a, [rSVBK]
+ push af
+ ld a, BANK(wBGPals1)
+ ld [rSVBK], a
+; Ready for BGPD input...
+ ld a, (1 << rBGPI_AUTO_INCREMENT) palette PAL_BG_YELLOW
+ ld [rBGPI], a
+ ld a, [hVBlankCounter]
+ and %10
+ jr nz, .bit1set
+ ld hl, wBGPals1 palette PAL_BG_YELLOW
+ jr .okay
+
+.bit1set
+ ld hl, wBGPals1 palette PAL_BG_YELLOW color 1
+
+.okay
+ ld a, [hli]
+ ld [rBGPD], a
+ ld a, [hli]
+ ld [rBGPD], a
+
+ pop af
+ ld [rSVBK], a
+ ret
+; fc750
+
+
+TowerPillarTilePointer1: dw vTiles2 tile $2d, TowerPillarTile1
+TowerPillarTilePointer2: dw vTiles2 tile $2f, TowerPillarTile2
+TowerPillarTilePointer3: dw vTiles2 tile $3d, TowerPillarTile3
+TowerPillarTilePointer4: dw vTiles2 tile $3f, TowerPillarTile4
+TowerPillarTilePointer5: dw vTiles2 tile $3c, TowerPillarTile5
+TowerPillarTilePointer6: dw vTiles2 tile $2c, TowerPillarTile6
+TowerPillarTilePointer7: dw vTiles2 tile $4d, TowerPillarTile7
+TowerPillarTilePointer8: dw vTiles2 tile $4f, TowerPillarTile8
+TowerPillarTilePointer9: dw vTiles2 tile $5d, TowerPillarTile9
+TowerPillarTilePointer10: dw vTiles2 tile $5f, TowerPillarTile10
+
+TowerPillarTile1: INCBIN "gfx/tilesets/tower-pillar/1.2bpp"
+TowerPillarTile2: INCBIN "gfx/tilesets/tower-pillar/2.2bpp"
+TowerPillarTile3: INCBIN "gfx/tilesets/tower-pillar/3.2bpp"
+TowerPillarTile4: INCBIN "gfx/tilesets/tower-pillar/4.2bpp"
+TowerPillarTile5: INCBIN "gfx/tilesets/tower-pillar/5.2bpp"
+TowerPillarTile6: INCBIN "gfx/tilesets/tower-pillar/6.2bpp"
+TowerPillarTile7: INCBIN "gfx/tilesets/tower-pillar/7.2bpp"
+TowerPillarTile8: INCBIN "gfx/tilesets/tower-pillar/8.2bpp"
+TowerPillarTile9: INCBIN "gfx/tilesets/tower-pillar/9.2bpp"
+TowerPillarTile10: INCBIN "gfx/tilesets/tower-pillar/10.2bpp"
+; fca98
+
+
+WhirlpoolFrames1: dw vTiles2 tile $32, WhirlpoolTiles1
+WhirlpoolFrames2: dw vTiles2 tile $33, WhirlpoolTiles2
+WhirlpoolFrames3: dw vTiles2 tile $42, WhirlpoolTiles3
+WhirlpoolFrames4: dw vTiles2 tile $43, WhirlpoolTiles4
+; fcaa8
+
+WhirlpoolTiles1: INCBIN "gfx/tilesets/whirlpool/1.2bpp"
+WhirlpoolTiles2: INCBIN "gfx/tilesets/whirlpool/2.2bpp"
+WhirlpoolTiles3: INCBIN "gfx/tilesets/whirlpool/3.2bpp"
+WhirlpoolTiles4: INCBIN "gfx/tilesets/whirlpool/4.2bpp"
+; fcba8
diff --git a/engine/gfx/tileset_palettes.asm b/engine/gfx/tileset_palettes.asm
new file mode 100644
index 000000000..e2c39c0ab
--- /dev/null
+++ b/engine/gfx/tileset_palettes.asm
@@ -0,0 +1,151 @@
+LoadSpecialMapPalette: ; 494ac
+ ld a, [wMapTileset]
+ cp TILESET_POKECOM_CENTER
+ jr z, .pokecom_2f
+ cp TILESET_BATTLE_TOWER
+ jr z, .battle_tower
+ cp TILESET_ICE_PATH
+ jr z, .ice_path
+ cp TILESET_HOUSE
+ jr z, .house
+ cp TILESET_RADIO_TOWER
+ jr z, .radio_tower
+ cp TILESET_MANSION
+ jr z, .mansion_mobile
+ jr .do_nothing
+
+.pokecom_2f
+ call LoadPokeComPalette
+ scf
+ ret
+
+.battle_tower
+ call LoadBattleTowerPalette
+ scf
+ ret
+
+.ice_path
+ ld a, [wEnvironment]
+ and $7
+ cp INDOOR ; Hall of Fame
+ jr z, .do_nothing
+ call LoadIcePathPalette
+ scf
+ ret
+
+.house
+ call LoadHousePalette
+ scf
+ ret
+
+.radio_tower
+ call LoadRadioTowerPalette
+ scf
+ ret
+
+.mansion_mobile
+ call LoadMansionPalette
+ scf
+ ret
+
+.do_nothing
+ and a
+ ret
+; 494f2
+
+LoadPokeComPalette: ; 494f2
+ ld a, BANK(wBGPals1)
+ ld de, wBGPals1
+ ld hl, PokeComPalette
+ ld bc, 8 palettes
+ call FarCopyWRAM
+ ret
+; 49501
+
+PokeComPalette: ; 49501
+INCLUDE "gfx/tilesets/pokecom_center.pal"
+; 49541
+
+LoadBattleTowerPalette: ; 49541
+ ld a, BANK(wBGPals1)
+ ld de, wBGPals1
+ ld hl, BattleTowerPalette
+ ld bc, 8 palettes
+ call FarCopyWRAM
+ ret
+; 49550
+
+BattleTowerPalette: ; 49550
+INCLUDE "gfx/tilesets/battle_tower.pal"
+; 49590
+
+LoadIcePathPalette: ; 49590
+ ld a, BANK(wBGPals1)
+ ld de, wBGPals1
+ ld hl, IcePathPalette
+ ld bc, 8 palettes
+ call FarCopyWRAM
+ ret
+; 4959f
+
+IcePathPalette: ; 4959f
+INCLUDE "gfx/tilesets/ice_path.pal"
+; 495df
+
+LoadHousePalette: ; 495df
+ ld a, BANK(wBGPals1)
+ ld de, wBGPals1
+ ld hl, HousePalette
+ ld bc, 8 palettes
+ call FarCopyWRAM
+ ret
+; 495ee
+
+HousePalette: ; 495ee
+INCLUDE "gfx/tilesets/house.pal"
+; 4962e
+
+LoadRadioTowerPalette: ; 4962e
+ ld a, BANK(wBGPals1)
+ ld de, wBGPals1
+ ld hl, RadioTowerPalette
+ ld bc, 8 palettes
+ call FarCopyWRAM
+ ret
+; 4963d
+
+RadioTowerPalette: ; 4963d
+INCLUDE "gfx/tilesets/radio_tower.pal"
+; 4967d
+
+MansionPalette1: ; 4967d
+INCLUDE "gfx/tilesets/mansion_1.pal"
+; 496c5
+
+LoadMansionPalette: ; 496c5
+ ld a, BANK(wBGPals1)
+ ld de, wBGPals1
+ ld hl, MansionPalette1
+ ld bc, 8 palettes
+ call FarCopyWRAM
+ ld a, BANK(wBGPals1)
+ ld de, wBGPals1 palette PAL_BG_YELLOW
+ ld hl, MansionPalette2
+ ld bc, 1 palettes
+ call FarCopyWRAM
+ ld a, BANK(wBGPals1)
+ ld de, wBGPals1 palette PAL_BG_WATER
+ ld hl, MansionPalette1 + 6 palettes
+ ld bc, 1 palettes
+ call FarCopyWRAM
+ ld a, BANK(wBGPals1)
+ ld de, wBGPals1 palette PAL_BG_ROOF
+ ld hl, MansionPalette1 + 8 palettes
+ ld bc, 1 palettes
+ call FarCopyWRAM
+ ret
+; 496fe
+
+MansionPalette2: ; 496fe
+INCLUDE "gfx/tilesets/mansion_2.pal"
+; 49706
diff --git a/engine/gfx/timeofdaypals.asm b/engine/gfx/timeofdaypals.asm
new file mode 100644
index 000000000..b8d43d252
--- /dev/null
+++ b/engine/gfx/timeofdaypals.asm
@@ -0,0 +1,415 @@
+DummyPredef35: ; 8c000
+DummyPredef36:
+ ret
+
+UpdateTimeOfDayPal:: ; 8c001
+ call UpdateTime
+ ld a, [wTimeOfDay]
+ ld [wCurTimeOfDay], a
+ call GetTimePalette
+ ld [wTimeOfDayPal], a
+ ret
+; 8c011
+
+
+_TimeOfDayPals:: ; 8c011
+; return carry if pals are changed
+
+; forced pals?
+ ld hl, wTimeOfDayPalFlags
+ bit 7, [hl]
+ jr nz, .dontchange
+
+; do we need to bother updating?
+ ld a, [wTimeOfDay]
+ ld hl, wCurTimeOfDay
+ cp [hl]
+ jr z, .dontchange
+
+; if so, the time of day has changed
+ ld a, [wTimeOfDay]
+ ld [wCurTimeOfDay], a
+
+; get palette id
+ call GetTimePalette
+
+; same palette as before?
+ ld hl, wTimeOfDayPal
+ cp [hl]
+ jr z, .dontchange
+
+; update palette id
+ ld [wTimeOfDayPal], a
+
+; save bg palette 7
+ ld hl, wBGPals1 palette PAL_BG_TEXT
+
+; save wram bank
+ ld a, [rSVBK]
+ ld b, a
+
+ ld a, BANK(wBGPals1)
+ ld [rSVBK], a
+
+; push palette
+ ld c, NUM_PAL_COLORS
+.push
+ ld d, [hl]
+ inc hl
+ ld e, [hl]
+ inc hl
+ push de
+ dec c
+ jr nz, .push
+
+; restore wram bank
+ ld a, b
+ ld [rSVBK], a
+
+
+; update sgb pals
+ ld b, SCGB_MAPPALS
+ call GetSGBLayout
+
+
+; restore bg palette 7
+ ld hl, wOBPals1 - 1 ; last byte in wBGPals1
+
+; save wram bank
+ ld a, [rSVBK]
+ ld d, a
+
+ ld a, BANK(wOBPals1)
+ ld [rSVBK], a
+
+; pop palette
+ ld e, NUM_PAL_COLORS
+.pop
+ pop bc
+ ld [hl], c
+ dec hl
+ ld [hl], b
+ dec hl
+ dec e
+ jr nz, .pop
+
+; restore wram bank
+ ld a, d
+ ld [rSVBK], a
+
+; update palettes
+ call _UpdateTimePals
+ call DelayFrame
+
+; successful change
+ scf
+ ret
+
+.dontchange
+; no change occurred
+ and a
+ ret
+; 8c070
+
+
+_UpdateTimePals:: ; 8c070
+ ld c, $9 ; normal
+ call GetTimePalFade
+ call DmgToCgbTimePals
+ ret
+; 8c079
+
+FadeInPalettes:: ; 8c079
+ ld c, $12
+ call GetTimePalFade
+ ld b, $4
+ call ConvertTimePalsDecHL
+ ret
+; 8c084
+
+FadeOutPalettes:: ; 8c084
+ call FillWhiteBGColor
+ ld c, $9
+ call GetTimePalFade
+ ld b, $4
+ call ConvertTimePalsIncHL
+ ret
+; 8c092
+
+BattleTowerFade: ; 8c092
+ call FillWhiteBGColor
+ ld c, $9
+ call GetTimePalFade
+ ld b, $4
+.asm_8c09c
+ call DmgToCgbTimePals
+ inc hl
+ inc hl
+ inc hl
+ ld c, $7
+ call DelayFrames
+ dec b
+ jr nz, .asm_8c09c
+ ret
+; 8c0ab
+
+FadeInQuickly: ; 8c0ab
+ ld c, $0
+ call GetTimePalFade
+ ld b, $4
+ call ConvertTimePalsIncHL
+ ret
+; 8c0b6
+
+FadeBlackQuickly: ; 8c0b6
+ ld c, $9
+ call GetTimePalFade
+ ld b, $4
+ call ConvertTimePalsDecHL
+ ret
+; 8c0c1
+
+
+FillWhiteBGColor: ; 8c0c1
+ ld a, [rSVBK]
+ push af
+ ld a, BANK(wBGPals1)
+ ld [rSVBK], a
+
+ ld hl, wBGPals1
+ ld a, [hli]
+ ld e, a
+ ld a, [hli]
+ ld d, a
+ ld hl, wBGPals1 + 1 palettes
+ ld c, 6
+.loop
+ ld a, e
+ ld [hli], a
+ ld a, d
+ ld [hli], a
+rept 6
+ inc hl
+endr
+ dec c
+ jr nz, .loop
+
+ pop af
+ ld [rSVBK], a
+ ret
+; 8c0e5
+
+ReplaceTimeOfDayPals: ; 8c0e5
+ ld hl, .BrightnessLevels
+ ld a, [wMapTimeOfDay]
+ cp $4 ; Dark cave, needs Flash
+ jr z, .DarkCave
+ and $7
+ add l
+ ld l, a
+ ld a, $0
+ adc h
+ ld h, a
+ ld a, [hl]
+ ld [wTimeOfDayPalset], a
+ ret
+
+.DarkCave:
+ ld a, [wStatusFlags]
+ bit STATUSFLAGS_FLASH_F, a
+ jr nz, .UsedFlash
+ ld a, %11111111 ; 3, 3, 3, 3
+ ld [wTimeOfDayPalset], a
+ ret
+
+.UsedFlash:
+ ld a, %10101010 ; 2, 2, 2, 2
+ ld [wTimeOfDayPalset], a
+ ret
+; 8c10f (23:410f)
+
+.BrightnessLevels: ; 8c10f
+ dc 3, 2, 1, 0
+ dc 1, 1, 1, 1
+ dc 2, 2, 2, 2
+ dc 0, 0, 0, 0
+ dc 3, 3, 3, 3
+ dc 3, 2, 1, 0
+ dc 3, 2, 1, 0
+ dc 3, 2, 1, 0
+; 8c117
+
+GetTimePalette: ; 8c117
+ ld a, [wTimeOfDay]
+ ld e, a
+ ld d, 0
+ ld hl, .TimePalettes
+ add hl, de
+ add hl, de
+ ld a, [hli]
+ ld h, [hl]
+ ld l, a
+ jp hl
+; 8c126
+
+.TimePalettes:
+ dw .MorningPalette
+ dw .DayPalette
+ dw .NitePalette
+ dw .DarknessPalette
+
+.MorningPalette:
+ ld a, [wTimeOfDayPalset]
+ and %00000011 ; 0
+ ret
+
+.DayPalette:
+ ld a, [wTimeOfDayPalset]
+ and %00001100 ; 1
+ srl a
+ srl a
+ ret
+
+.NitePalette:
+ ld a, [wTimeOfDayPalset]
+ and %00110000 ; 2
+ swap a
+ ret
+
+.DarknessPalette:
+ ld a, [wTimeOfDayPalset]
+ and %11000000 ; 3
+ rlca
+ rlca
+ ret
+; 8c14e
+
+
+DmgToCgbTimePals: ; 8c14e
+ push hl
+ push de
+ ld a, [hli]
+ call DmgToCgbBGPals
+ ld a, [hli]
+ ld e, a
+ ld a, [hli]
+ ld d, a
+ call DmgToCgbObjPals
+ pop de
+ pop hl
+ ret
+; 8c15e
+
+ConvertTimePalsIncHL: ; 8c15e
+.loop
+ call DmgToCgbTimePals
+ inc hl
+ inc hl
+ inc hl
+ ld c, 2
+ call DelayFrames
+ dec b
+ jr nz, .loop
+ ret
+; 8c16d
+
+ConvertTimePalsDecHL: ; 8c16d
+.loop
+ call DmgToCgbTimePals
+ dec hl
+ dec hl
+ dec hl
+ ld c, 2
+ call DelayFrames
+ dec b
+ jr nz, .loop
+ ret
+; 8c17c
+
+
+GetTimePalFade: ; 8c17c
+; check cgb
+ ld a, [hCGB]
+ and a
+ jr nz, .cgb
+
+; else: dmg
+
+; index
+ ld a, [wTimeOfDayPal]
+ and %11
+
+; get fade table
+ push bc
+ ld c, a
+ ld b, $0
+ ld hl, .dmgfades
+ add hl, bc
+ add hl, bc
+ ld a, [hli]
+ ld h, [hl]
+ ld l, a
+ pop bc
+
+; get place in fade table
+ ld b, $0
+ add hl, bc
+ ret
+
+.cgb
+ ld hl, .cgbfade
+ ld b, $0
+ add hl, bc
+ ret
+
+.dmgfades
+ dw .morn
+ dw .day
+ dw .nite
+ dw .darkness
+
+.morn
+ db %11111111, %11111111, %11111111
+ db %11111110, %11111110, %11111110
+ db %11111001, %11100100, %11100100
+ db %11100100, %11010000, %11010000
+ db %10010000, %10000000, %10000000
+ db %01000000, %01000000, %01000000
+ db %00000000, %00000000, %00000000
+
+.day
+ db %11111111, %11111111, %11111111
+ db %11111110, %11111110, %11111110
+ db %11111001, %11100100, %11100100
+ db %11100100, %11010000, %11010000
+ db %10010000, %10000000, %10000000
+ db %01000000, %01000000, %01000000
+ db %00000000, %00000000, %00000000
+
+.nite
+ db %11111111, %11111111, %11111111
+ db %11111110, %11111110, %11111110
+ db %11111001, %11100100, %11100100
+ db %11101001, %11010000, %11010000
+ db %10010000, %10000000, %10000000
+ db %01000000, %01000000, %01000000
+ db %00000000, %00000000, %00000000
+
+.darkness
+ db %11111111, %11111111, %11111111
+ db %11111110, %11111110, %11111111
+ db %11111110, %11100100, %11111111
+ db %11111101, %11010000, %11111111
+ db %11111101, %10000000, %11111111
+ db %00000000, %01000000, %00000000
+ db %00000000, %00000000, %00000000
+
+.cgbfade
+ db %11111111, %11111111, %11111111
+ db %11111110, %11111110, %11111110
+ db %11111001, %11111001, %11111001
+ db %11100100, %11100100, %11100100
+ db %10010000, %10010000, %10010000
+ db %01000000, %01000000, %01000000
+ db %00000000, %00000000, %00000000
+; 8c20f
diff --git a/engine/gfx/trade_animation.asm b/engine/gfx/trade_animation.asm
new file mode 100755
index 000000000..04c31df80
--- /dev/null
+++ b/engine/gfx/trade_animation.asm
@@ -0,0 +1,1646 @@
+TRADEANIM_RIGHT_ARROW EQU $ed
+TRADEANIM_LEFT_ARROW EQU $ee
+
+; TradeAnim_TubeAnimJumptable.Jumptable indexes
+ const_def
+ const TRADEANIMSTATE_0 ; 0
+ const TRADEANIMSTATE_1 ; 1
+ const TRADEANIMSTATE_2 ; 2
+ const TRADEANIMSTATE_3 ; 3
+TRADEANIMJUMPTABLE_LENGTH EQU const_value
+
+TradeAnimation: ; 28f24
+ xor a
+ ld [wcf66], a
+ ld hl, wPlayerTrademonSenderName
+ ld de, wOTTrademonSenderName
+ call LinkTradeAnim_LoadTradePlayerNames
+ ld hl, wPlayerTrademonSpecies
+ ld de, wOTTrademonSpecies
+ call LinkTradeAnim_LoadTradeMonSpecies
+ ld de, .script
+ jr RunTradeAnimScript
+
+.script
+ tradeanim_setup_givemon_scroll
+ tradeanim_show_givemon_data
+ tradeanim_do_givemon_scroll
+ tradeanim_wait_80
+ tradeanim_wait_96
+ tradeanim_poof
+ tradeanim_rocking_ball
+ tradeanim_enter_link_tube
+ tradeanim_wait_anim
+ tradeanim_bulge_through_tube
+ tradeanim_wait_anim
+ tradeanim_textbox_scroll
+ tradeanim_give_trademon_sfx
+ tradeanim_tube_to_ot
+ tradeanim_sent_to_ot_text
+ tradeanim_scroll_out_right
+
+ tradeanim_ot_sends_text_1
+ tradeanim_ot_bids_farewell
+ tradeanim_wait_40
+ tradeanim_scroll_out_right
+ tradeanim_get_trademon_sfx
+ tradeanim_tube_to_player
+ tradeanim_enter_link_tube
+ tradeanim_drop_ball
+ tradeanim_exit_link_tube
+ tradeanim_wait_anim
+ tradeanim_show_getmon_data
+ tradeanim_poof
+ tradeanim_wait_anim
+ tradeanim_frontpic_scroll
+ tradeanim_animate_frontpic
+ tradeanim_wait_80_if_ot_egg
+ tradeanim_textbox_scroll
+ tradeanim_take_care_of_text
+ tradeanim_scroll_out_right
+ tradeanim_end
+
+TradeAnimationPlayer2: ; 28f63
+ xor a
+ ld [wcf66], a
+ ld hl, wOTTrademonSenderName
+ ld de, wPlayerTrademonSenderName
+ call LinkTradeAnim_LoadTradePlayerNames
+ ld hl, wOTTrademonSpecies
+ ld de, wPlayerTrademonSpecies
+ call LinkTradeAnim_LoadTradeMonSpecies
+ ld de, .script
+ jr RunTradeAnimScript
+
+.script
+ tradeanim_ot_sends_text_2
+ tradeanim_ot_bids_farewell
+ tradeanim_wait_40
+ tradeanim_scroll_out_right
+ tradeanim_get_trademon_sfx
+ tradeanim_tube_to_ot
+ tradeanim_enter_link_tube
+ tradeanim_drop_ball
+ tradeanim_exit_link_tube
+ tradeanim_wait_anim
+ tradeanim_show_getmon_data
+ tradeanim_poof
+ tradeanim_wait_anim
+ tradeanim_frontpic_scroll
+ tradeanim_animate_frontpic
+ tradeanim_wait_180_if_ot_egg
+ tradeanim_textbox_scroll
+ tradeanim_take_care_of_text
+ tradeanim_scroll_out_right
+
+ tradeanim_setup_givemon_scroll
+ tradeanim_show_givemon_data
+ tradeanim_do_givemon_scroll
+ tradeanim_wait_40
+ tradeanim_poof
+ tradeanim_rocking_ball
+ tradeanim_enter_link_tube
+ tradeanim_wait_anim
+ tradeanim_bulge_through_tube
+ tradeanim_wait_anim
+ tradeanim_textbox_scroll
+ tradeanim_give_trademon_sfx
+ tradeanim_tube_to_player
+ tradeanim_sent_to_ot_text
+ tradeanim_scroll_out_right
+ tradeanim_end
+
+RunTradeAnimScript: ; 28fa1
+ ld hl, wTradeAnimAddress
+ ld [hl], e
+ inc hl
+ ld [hl], d
+ ld a, [hMapAnims]
+ push af
+ xor a
+ ld [hMapAnims], a
+ ld hl, wVramState
+ ld a, [hl]
+ push af
+ res 0, [hl]
+ ld hl, wOptions
+ ld a, [hl]
+ push af
+ set 4, [hl]
+ call .TradeAnimLayout
+ ld a, [wcf66]
+ and a
+ jr nz, .anim_loop
+ ld de, MUSIC_EVOLUTION
+ call PlayMusic2
+.anim_loop
+ call DoTradeAnimation
+ jr nc, .anim_loop
+ pop af
+ ld [wOptions], a
+ pop af
+ ld [wVramState], a
+ pop af
+ ld [hMapAnims], a
+ ret
+
+; 28fdb
+
+.TradeAnimLayout: ; 28fdb
+ xor a
+ ld [wJumptableIndex], a
+ call ClearBGPalettes
+ call ClearSprites
+ call ClearTileMap
+ call DisableLCD
+ call LoadFontsBattleExtra
+ callfar ClearSpriteAnims
+ ld a, [hCGB]
+ and a
+ jr z, .NotCGB
+ ld a, $1
+ ld [rVBK], a
+ ld hl, vTiles0
+ ld bc, sScratch - vTiles0
+ xor a
+ call ByteFill
+ ld a, $0
+ ld [rVBK], a
+
+.NotCGB:
+ hlbgcoord 0, 0
+ ld bc, sScratch - vBGMap0
+ ld a, " "
+ call ByteFill
+ ld hl, TradeGameBoyLZ
+ ld de, vTiles2 tile $31
+ call Decompress
+ ld hl, TradeArrowGFX
+ ld de, vTiles0 tile TRADEANIM_RIGHT_ARROW
+ ld bc, 1 tiles
+ ld a, BANK(TradeArrowGFX)
+ call FarCopyBytes
+ ld hl, TradeArrowGFX + 1 tiles
+ ld de, vTiles0 tile TRADEANIM_LEFT_ARROW
+ ld bc, 1 tiles
+ ld a, BANK(TradeArrowGFX)
+ call FarCopyBytes
+ xor a
+ ld [hSCX], a
+ ld [hSCY], a
+ ld a, $7
+ ld [hWX], a
+ ld a, $90
+ ld [hWY], a
+ farcall GetTrademonFrontpic
+ call EnableLCD
+ call LoadTradeBallAndCableGFX
+ ld a, [wPlayerTrademonSpecies]
+ ld hl, wPlayerTrademonDVs
+ ld de, vTiles0
+ call TradeAnim_GetFrontpic
+ ld a, [wOTTrademonSpecies]
+ ld hl, wOTTrademonDVs
+ ld de, vTiles0 tile $31
+ call TradeAnim_GetFrontpic
+ ld a, [wPlayerTrademonSpecies]
+ ld de, wPlayerTrademonSpeciesName
+ call TradeAnim_GetNickname
+ ld a, [wOTTrademonSpecies]
+ ld de, wOTTrademonSpeciesName
+ call TradeAnim_GetNickname
+ call TradeAnim_NormalPals
+ ret
+
+; 29082
+
+DoTradeAnimation: ; 29082
+ ld a, [wJumptableIndex]
+ bit 7, a
+ jr nz, .finished
+ call .DoTradeAnimCommand
+ callfar PlaySpriteAnimations
+ ld hl, wcf65
+ inc [hl]
+ call DelayFrame
+ and a
+ ret
+
+.finished
+ call LoadStandardFont
+ scf
+ ret
+
+; 290a0
+
+.DoTradeAnimCommand: ; 290a0
+ ld a, [wJumptableIndex]
+ ld e, a
+ ld d, 0
+ ld hl, .JumpTable
+ add hl, de
+ add hl, de
+ ld a, [hli]
+ ld h, [hl]
+ ld l, a
+ jp hl
+; 290af
+
+.JumpTable: ; 290af
+; entries correspond to macros/scripts/trade_anims.asm enumeration
+ dw TradeAnim_AdvanceScriptPointer ; 00
+ dw TradeAnim_ShowGivemonData ; 01
+ dw TradeAnim_ShowGetmonData ; 02
+ dw TradeAnim_EnterLinkTube1 ; 03
+ dw TradeAnim_EnterLinkTube2 ; 04
+ dw TradeAnim_ExitLinkTube ; 05
+ dw TradeAnim_TubeToOT1 ; 06
+ dw TradeAnim_TubeToOT2 ; 07
+ dw TradeAnim_TubeToOT3 ; 08
+ dw TradeAnim_TubeToOT4 ; 09
+ dw TradeAnim_TubeToOT5 ; 0a
+ dw TradeAnim_TubeToOT6 ; 0b
+ dw TradeAnim_TubeToOT7 ; 0c
+ dw TradeAnim_TubeToOT8 ; 0d
+ dw TradeAnim_TubeToPlayer1 ; 0e
+ dw TradeAnim_TubeToPlayer2 ; 0f
+ dw TradeAnim_TubeToPlayer3 ; 10
+ dw TradeAnim_TubeToPlayer4 ; 11
+ dw TradeAnim_TubeToPlayer5 ; 12
+ dw TradeAnim_TubeToPlayer6 ; 13
+ dw TradeAnim_TubeToPlayer7 ; 14
+ dw TradeAnim_TubeToPlayer8 ; 15
+ dw TradeAnim_SentToOTText ; 16
+ dw TradeAnim_OTBidsFarewell ; 17
+ dw TradeAnim_TakeCareOfText ; 18
+ dw TradeAnim_OTSendsText1 ; 19
+ dw TradeAnim_OTSendsText2 ; 1a
+ dw TradeAnim_SetupGivemonScroll ; 1b
+ dw TradeAnim_DoGivemonScroll ; 1c
+ dw TradeAnim_FrontpicScrollStart ; 1d
+ dw TradeAnim_TextboxScrollStart ; 1e
+ dw TradeAnim_ScrollOutRight ; 1f
+ dw TradeAnim_ScrollOutRight2 ; 20
+ dw TraideAnim_Wait80 ; 21
+ dw TraideAnim_Wait40 ; 22
+ dw TradeAnim_RockingBall ; 23
+ dw TradeAnim_DropBall ; 24
+ dw TradeAnim_WaitAnim ; 25
+ dw TradeAnim_WaitAnim2 ; 26
+ dw TradeAnim_Poof ; 27
+ dw TradeAnim_BulgeThroughTube ; 28
+ dw TradeAnim_GiveTrademonSFX ; 29
+ dw TradeAnim_GetTrademonSFX ; 2a
+ dw TradeAnim_End ; 2b
+ dw TradeAnim_AnimateFrontpic ; 2c
+ dw TraideAnim_Wait96 ; 2d
+ dw TraideAnim_Wait80IfOTEgg ; 2e
+ dw TraideAnim_Wait180IfOTEgg ; 2f
+; 2910f
+
+TradeAnim_IncrementJumptableIndex: ; 2910f
+ ld hl, wJumptableIndex
+ inc [hl]
+ ret
+
+; 29114
+
+TradeAnim_AdvanceScriptPointer: ; 29114
+ ld hl, wTradeAnimAddress
+ ld e, [hl]
+ inc hl
+ ld d, [hl]
+ ld a, [de]
+ ld [wJumptableIndex], a
+ inc de
+ ld [hl], d
+ dec hl
+ ld [hl], e
+ ret
+
+; 29123
+
+TradeAnim_End: ; 29123
+ ld hl, wJumptableIndex
+ set 7, [hl]
+ ret
+
+; 29129
+
+TradeAnim_TubeToOT1: ; 29129
+ ld a, TRADEANIM_RIGHT_ARROW
+ call TradeAnim_PlaceTrademonStatsOnTubeAnim
+ ld a, [wLinkTradeSendmonSpecies]
+ ld [wd265], a
+ xor a
+ depixel 5, 11, 4, 0
+ ld b, $0
+ jr TradeAnim_InitTubeAnim
+
+TradeAnim_TubeToPlayer1: ; 2913c
+ ld a, TRADEANIM_LEFT_ARROW
+ call TradeAnim_PlaceTrademonStatsOnTubeAnim
+ ld a, [wLinkTradeGetmonSpecies]
+ ld [wd265], a
+ ld a, TRADEANIMSTATE_2
+ depixel 9, 18, 4, 4
+ ld b, $4
+TradeAnim_InitTubeAnim: ; 2914e
+ push bc
+ push de
+ push bc
+ push de
+
+ push af
+ call DisableLCD
+ callfar ClearSpriteAnims
+ hlbgcoord 20, 3
+ ld bc, 12
+ ld a, $60
+ call ByteFill
+ pop af
+
+ call TradeAnim_TubeAnimJumptable
+
+ xor a
+ ld [hSCX], a
+ ld a, $7
+ ld [hWX], a
+ ld a, $70
+ ld [hWY], a
+ call EnableLCD
+ call LoadTradeBubbleGFX
+
+ pop de
+ ld a, SPRITE_ANIM_INDEX_TRADEMON_ICON
+ call _InitSpriteAnimStruct
+
+ ld hl, SPRITEANIMSTRUCT_JUMPTABLE_INDEX
+ add hl, bc
+ pop bc
+ ld [hl], b
+
+ pop de
+ ld a, SPRITE_ANIM_INDEX_TRADEMON_BUBBLE
+ call _InitSpriteAnimStruct
+
+ ld hl, SPRITEANIMSTRUCT_JUMPTABLE_INDEX
+ add hl, bc
+ pop bc
+ ld [hl], b
+
+ call WaitBGMap
+ ld b, SCGB_TRADE_TUBE
+ call GetSGBLayout
+ ld a, %11100100 ; 3,2,1,0
+ call DmgToCgbBGPals
+ ld a, %11010000
+ call DmgToCgbObjPal0
+
+ call TradeAnim_IncrementJumptableIndex
+ ld a, 92
+ ld [wFrameCounter], a
+ ret
+
+; 291af
+
+TradeAnim_TubeToOT2: ; 291af
+ call TradeAnim_FlashBGPals
+ ld a, [hSCX]
+ add $2
+ ld [hSCX], a
+ cp $50
+ ret nz
+ ld a, TRADEANIMSTATE_1
+ call TradeAnim_TubeAnimJumptable
+ call TradeAnim_IncrementJumptableIndex
+ ret
+
+; 291c4
+
+TradeAnim_TubeToOT3: ; 291c4
+ call TradeAnim_FlashBGPals
+ ld a, [hSCX]
+ add $2
+ ld [hSCX], a
+ cp $a0
+ ret nz
+ ld a, TRADEANIMSTATE_2
+ call TradeAnim_TubeAnimJumptable
+ call TradeAnim_IncrementJumptableIndex
+ ret
+
+; 291d9
+
+TradeAnim_TubeToOT4: ; 291d9
+ call TradeAnim_FlashBGPals
+ ld a, [hSCX]
+ add $2
+ ld [hSCX], a
+ and a
+ ret nz
+ call TradeAnim_IncrementJumptableIndex
+ ret
+
+; 291e8
+
+TradeAnim_TubeToPlayer3: ; 291e8
+ call TradeAnim_FlashBGPals
+ ld a, [hSCX]
+ sub $2
+ ld [hSCX], a
+ cp $b0
+ ret nz
+ ld a, TRADEANIMSTATE_1
+ call TradeAnim_TubeAnimJumptable
+ call TradeAnim_IncrementJumptableIndex
+ ret
+
+; 291fd
+
+TradeAnim_TubeToPlayer4: ; 291fd
+ call TradeAnim_FlashBGPals
+ ld a, [hSCX]
+ sub $2
+ ld [hSCX], a
+ cp $60
+ ret nz
+ xor a ; TRADEANIMSTATE_0
+ call TradeAnim_TubeAnimJumptable
+ call TradeAnim_IncrementJumptableIndex
+ ret
+
+; 29211
+
+TradeAnim_TubeToPlayer5: ; 29211
+ call TradeAnim_FlashBGPals
+ ld a, [hSCX]
+ sub $2
+ ld [hSCX], a
+ and a
+ ret nz
+ call TradeAnim_IncrementJumptableIndex
+ ret
+
+; 29220
+
+TradeAnim_TubeToOT6:
+TradeAnim_TubeToPlayer6: ; 29220
+ ld a, 128
+ ld [wFrameCounter], a
+ call TradeAnim_IncrementJumptableIndex
+ ret
+
+; 29229
+
+TradeAnim_TubeToOT8:
+TradeAnim_TubeToPlayer8: ; 29229
+ call ClearBGPalettes
+ call ClearTileMap
+ call ClearSprites
+ call DisableLCD
+ callfar ClearSpriteAnims
+ hlbgcoord 0, 0
+ ld bc, sScratch - vBGMap0
+ ld a, " "
+ call ByteFill
+ xor a
+ ld [hSCX], a
+ ld a, $90
+ ld [hWY], a
+ call EnableLCD
+ call LoadTradeBallAndCableGFX
+ call WaitBGMap
+ call TradeAnim_NormalPals
+ call TradeAnim_AdvanceScriptPointer
+ ret
+
+; 2925d
+
+TradeAnim_TubeToOT5:
+TradeAnim_TubeToOT7:
+TradeAnim_TubeToPlayer2:
+TradeAnim_TubeToPlayer7: ; 2925d
+ call TradeAnim_FlashBGPals
+ ld hl, wFrameCounter
+ ld a, [hl]
+ and a
+ jr z, .done
+ dec [hl]
+ ret
+
+.done
+ call TradeAnim_IncrementJumptableIndex
+ ret
+
+; 2926d
+
+TradeAnim_GiveTrademonSFX: ; 2926d
+ call TradeAnim_AdvanceScriptPointer
+ ld de, SFX_GIVE_TRADEMON
+ call PlaySFX
+ ret
+
+; 29277
+
+TradeAnim_GetTrademonSFX: ; 29277
+ call TradeAnim_AdvanceScriptPointer
+ ld de, SFX_GET_TRADEMON
+ call PlaySFX
+ ret
+
+; 29281
+
+TradeAnim_TubeAnimJumptable: ; 29281
+ maskbits TRADEANIMJUMPTABLE_LENGTH
+ ld e, a
+ ld d, 0
+ ld hl, .Jumptable
+ add hl, de
+ add hl, de
+ ld a, [hli]
+ ld h, [hl]
+ ld l, a
+ jp hl
+; 2928f
+
+.Jumptable: ; 2928f
+; entries correspond to TRADEANIMSTATE_* constants
+ dw .Zero
+ dw .One
+ dw .Two
+ dw .Three
+; 29297
+
+.Zero: ; 29297
+.Three: ; 29297
+ call TradeAnim_BlankTileMap
+ hlcoord 9, 3
+ ld [hl], $5b
+ inc hl
+ ld bc, 10
+ ld a, $60
+ call ByteFill
+ hlcoord 3, 2
+ call TradeAnim_CopyTradeGameBoyTilemap
+ ret
+
+; 292af
+
+.One: ; 292af
+ call TradeAnim_BlankTileMap
+ hlcoord 0, 3
+ ld bc, SCREEN_WIDTH
+ ld a, $60
+ call ByteFill
+ ret
+
+; 292be
+
+.Two: ; 292be
+ call TradeAnim_BlankTileMap
+ hlcoord 0, 3
+ ld bc, $11
+ ld a, $60
+ call ByteFill
+ hlcoord 17, 3
+ ld a, $5d
+ ld [hl], a
+
+ ld a, $61
+ ld de, SCREEN_WIDTH
+ ld c, $3
+.loop
+ add hl, de
+ ld [hl], a
+ dec c
+ jr nz, .loop
+
+ add hl, de
+ ld a, $5f
+ ld [hld], a
+ ld a, $5b
+ ld [hl], a
+ hlcoord 10, 6
+ call TradeAnim_CopyTradeGameBoyTilemap
+ ret
+
+; 292ec
+
+TradeAnim_CopyTradeGameBoyTilemap: ; 292ec
+ ld de, TradeGameBoyTilemap
+ lb bc, 8, 6
+ call TradeAnim_CopyBoxFromDEtoHL
+ ret
+
+; 292f6
+
+TradeAnim_PlaceTrademonStatsOnTubeAnim: ; 292f6
+ push af
+ call ClearBGPalettes
+ call WaitTop
+ ld a, HIGH(vBGMap1)
+ ld [hBGMapAddress + 1], a
+ call ClearTileMap
+ hlcoord 0, 0
+ ld bc, SCREEN_WIDTH
+ ld a, "─"
+ call ByteFill
+ hlcoord 0, 1
+ ld de, wLinkPlayer1Name
+ call PlaceString
+ ld hl, wLinkPlayer2Name
+ ld de, 0
+.find_name_end_loop
+ ld a, [hli]
+ cp "@"
+ jr z, .done
+ dec de
+ jr .find_name_end_loop
+
+.done
+ hlcoord 0, 4
+ add hl, de
+ ld de, wLinkPlayer2Name
+ call PlaceString
+ hlcoord 7, 2
+ ld bc, 6
+ pop af
+ call ByteFill
+ call WaitBGMap
+ call WaitTop
+ ld a, HIGH(vBGMap0)
+ ld [hBGMapAddress + 1], a
+ call ClearTileMap
+ ret
+
+; 29348
+
+TradeAnim_EnterLinkTube1: ; 29348
+ call ClearTileMap
+ call WaitTop
+ ld a, $a0
+ ld [hSCX], a
+ call DelayFrame
+ hlcoord 8, 2
+ ld de, TradeLinkTubeTilemap
+ lb bc, 3, 12
+ call TradeAnim_CopyBoxFromDEtoHL
+ call WaitBGMap
+ ld b, SCGB_TRADE_TUBE
+ call GetSGBLayout
+ ld a, %11100100 ; 3,2,1,0
+ call DmgToCgbBGPals
+ lb de, %11100100, %11100100 ; 3,2,1,0, 3,2,1,0
+ call DmgToCgbObjPals
+ ld de, SFX_POTION
+ call PlaySFX
+ call TradeAnim_IncrementJumptableIndex
+ ret
+
+; 2937e
+
+TradeAnim_EnterLinkTube2: ; 2937e
+ ld a, [hSCX]
+ and a
+ jr z, .done
+ add $4
+ ld [hSCX], a
+ ret
+
+.done
+ ld c, 80
+ call DelayFrames
+ call TradeAnim_AdvanceScriptPointer
+ ret
+
+; 29391
+
+TradeAnim_ExitLinkTube: ; 29391
+ ld a, [hSCX]
+ cp $a0
+ jr z, .done
+ sub $4
+ ld [hSCX], a
+ ret
+
+.done
+ call ClearTileMap
+ xor a
+ ld [hSCX], a
+ call TradeAnim_AdvanceScriptPointer
+ ret
+
+; 293a6
+
+TradeAnim_SetupGivemonScroll: ; 293a6
+ ld a, $8f
+ ld [hWX], a
+ ld a, $88
+ ld [hSCX], a
+ ld a, $50
+ ld [hWY], a
+ call TradeAnim_AdvanceScriptPointer
+ ret
+
+; 293b6
+
+TradeAnim_DoGivemonScroll: ; 293b6
+ ld a, [hWX]
+ cp $7
+ jr z, .done
+ sub $4
+ ld [hWX], a
+ ld a, [hSCX]
+ sub $4
+ ld [hSCX], a
+ ret
+
+.done
+ ld a, $7
+ ld [hWX], a
+ xor a
+ ld [hSCX], a
+ call TradeAnim_AdvanceScriptPointer
+ ret
+
+; 293d2
+
+TradeAnim_FrontpicScrollStart: ; 293d2
+ ld a, $7
+ ld [hWX], a
+ ld a, $50
+ ld [hWY], a
+ call TradeAnim_AdvanceScriptPointer
+ ret
+
+; 293de
+
+TradeAnim_TextboxScrollStart: ; 293de
+ ld a, $7
+ ld [hWX], a
+ ld a, $90
+ ld [hWY], a
+ call TradeAnim_AdvanceScriptPointer
+ ret
+
+; 293ea
+
+TradeAnim_ScrollOutRight: ; 293ea
+ call WaitTop
+ ld a, HIGH(vBGMap1)
+ ld [hBGMapAddress + 1], a
+ call WaitBGMap
+ ld a, $7
+ ld [hWX], a
+ xor a
+ ld [hWY], a
+ call DelayFrame
+ call WaitTop
+ ld a, HIGH(vBGMap0)
+ ld [hBGMapAddress + 1], a
+ call ClearTileMap
+ call TradeAnim_IncrementJumptableIndex
+ ret
+
+; 2940c
+
+TradeAnim_ScrollOutRight2: ; 2940c
+ ld a, [hWX]
+ cp $a1
+ jr nc, .done
+ add $4
+ ld [hWX], a
+ ret
+
+.done
+ ld a, HIGH(vBGMap1)
+ ld [hBGMapAddress + 1], a
+ call WaitBGMap
+ ld a, $7
+ ld [hWX], a
+ ld a, $90
+ ld [hWY], a
+ ld a, HIGH(vBGMap0)
+ ld [hBGMapAddress + 1], a
+ call TradeAnim_AdvanceScriptPointer
+ ret
+
+; 2942e
+
+TradeAnim_ShowGivemonData: ; 2942e
+ call ShowPlayerTrademonStats
+ ld a, [wPlayerTrademonSpecies]
+ ld [wCurPartySpecies], a
+ ld a, [wPlayerTrademonDVs]
+ ld [wTempMonDVs], a
+ ld a, [wPlayerTrademonDVs + 1]
+ ld [wTempMonDVs + 1], a
+ ld b, SCGB_PLAYER_OR_MON_FRONTPIC_PALS
+ call GetSGBLayout
+ ld a, %11100100 ; 3,2,1,0
+ call DmgToCgbBGPals
+ call TradeAnim_ShowGivemonFrontpic
+
+ ld a, [wPlayerTrademonSpecies]
+ call GetCryIndex
+ jr c, .skip_cry
+ ld e, c
+ ld d, b
+ call PlayCry
+.skip_cry
+
+ call TradeAnim_AdvanceScriptPointer
+ ret
+
+; 29461
+
+TradeAnim_ShowGetmonData: ; 29461
+ call ShowOTTrademonStats
+ ld a, [wOTTrademonSpecies]
+ ld [wCurPartySpecies], a
+ ld a, [wOTTrademonDVs]
+ ld [wTempMonDVs], a
+ ld a, [wOTTrademonDVs + 1]
+ ld [wTempMonDVs + 1], a
+ ld b, SCGB_PLAYER_OR_MON_FRONTPIC_PALS
+ call GetSGBLayout
+ ld a, %11100100 ; 3,2,1,0
+ call DmgToCgbBGPals
+ call TradeAnim_ShowGetmonFrontpic
+ call TradeAnim_AdvanceScriptPointer
+ ret
+
+; 29487
+
+TradeAnim_AnimateFrontpic: ; 29487
+ farcall AnimateTrademonFrontpic
+ call TradeAnim_AdvanceScriptPointer
+ ret
+
+; 29491
+
+TradeAnim_GetFrontpic: ; 29491
+ push de
+ push af
+ predef GetUnownLetter
+ pop af
+ ld [wCurPartySpecies], a
+ ld [wCurSpecies], a
+ call GetBaseData
+ pop de
+ predef GetMonFrontpic
+ ret
+
+; 294a9
+
+TradeAnim_GetNickname: ; 294a9
+ push de
+ ld [wd265], a
+ call GetPokemonName
+ ld hl, wStringBuffer1
+ pop de
+ ld bc, NAME_LENGTH
+ call CopyBytes
+ ret
+
+; 294bb
+
+TradeAnim_ShowGivemonFrontpic: ; 294bb
+ ld de, vTiles0
+ jr TradeAnim_ShowFrontpic
+
+TradeAnim_ShowGetmonFrontpic: ; 294c0
+ ld de, vTiles0 tile $31
+TradeAnim_ShowFrontpic: ; 294c3
+ call DelayFrame
+ ld hl, vTiles2
+ lb bc, 10, $31
+ call Request2bpp
+ call WaitTop
+ call TradeAnim_BlankTileMap
+ hlcoord 7, 2
+ xor a
+ ld [hGraphicStartTile], a
+ lb bc, 7, 7
+ predef PlaceGraphic
+ call WaitBGMap
+ ret
+
+; 294e7
+
+TraideAnim_Wait80: ; 294e7
+ ld c, 80
+ call DelayFrames
+ call TradeAnim_AdvanceScriptPointer
+ ret
+
+; 294f0
+
+TraideAnim_Wait40: ; 294f0
+ ld c, 40
+ call DelayFrames
+ call TradeAnim_AdvanceScriptPointer
+ ret
+
+; 294f9
+
+TraideAnim_Wait96: ; 294f9
+ ld c, 96
+ call DelayFrames
+ call TradeAnim_AdvanceScriptPointer
+ ret
+
+; 29502
+
+TraideAnim_Wait80IfOTEgg: ; 29502
+ call IsOTTrademonEgg
+ ret nz
+ ld c, 80
+ call DelayFrames
+ ret
+
+; 2950c
+
+TraideAnim_Wait180IfOTEgg: ; 2950c
+ call IsOTTrademonEgg
+ ret nz
+ ld c, 180
+ call DelayFrames
+ ret
+
+; 29516
+
+IsOTTrademonEgg: ; 29516
+ call TradeAnim_AdvanceScriptPointer
+ ld a, [wOTTrademonSpecies]
+ cp EGG
+ ret
+
+; 2951f
+ShowPlayerTrademonStats: ; 2951f
+ ld de, wPlayerTrademonSpecies
+ ld a, [de]
+ cp EGG
+ jr z, TrademonStats_Egg
+ call TrademonStats_MonTemplate
+ ld de, wPlayerTrademonSpecies
+ call TrademonStats_PrintSpeciesNumber
+ ld de, wPlayerTrademonSpeciesName
+ call TrademonStats_PrintSpeciesName
+ ld a, [wPlayerTrademonCaughtData]
+ ld de, wPlayerTrademonOTName
+ call TrademonStats_PrintOTName
+ ld de, wPlayerTrademonID
+ call TrademonStats_PrintTrademonID
+ call TrademonStats_WaitBGMap
+ ret
+
+; 29549
+
+ShowOTTrademonStats: ; 29549
+ ld de, wOTTrademonSpecies
+ ld a, [de]
+ cp EGG
+ jr z, TrademonStats_Egg
+ call TrademonStats_MonTemplate
+ ld de, wOTTrademonSpecies
+ call TrademonStats_PrintSpeciesNumber
+ ld de, wOTTrademonSpeciesName
+ call TrademonStats_PrintSpeciesName
+ ld a, [wOTTrademonCaughtData]
+ ld de, wOTTrademonOTName
+ call TrademonStats_PrintOTName
+ ld de, wOTTrademonID
+ call TrademonStats_PrintTrademonID
+ call TrademonStats_WaitBGMap
+ ret
+
+; 29573
+
+TrademonStats_MonTemplate: ; 29573
+ call WaitTop
+ call TradeAnim_BlankTileMap
+ ld a, HIGH(vBGMap1)
+ ld [hBGMapAddress + 1], a
+ hlcoord 3, 0
+ ld b, $6
+ ld c, $d
+ call TextBox
+ hlcoord 4, 0
+ ld de, .OTMonData
+ call PlaceString
+ ret
+
+; 29591
+
+.OTMonData: ; 29591
+ db "─── №."
+ next ""
+ next "OT/"
+ next "<ID>№.@"
+; 295a1
+
+TrademonStats_Egg: ; 295a1
+ call WaitTop
+ call TradeAnim_BlankTileMap
+ ld a, HIGH(vBGMap1)
+ ld [hBGMapAddress + 1], a
+ hlcoord 3, 0
+ ld b, 6
+ ld c, 13
+ call TextBox
+ hlcoord 4, 2
+ ld de, .EggData
+ call PlaceString
+ call TrademonStats_WaitBGMap
+ ret
+
+; 295c2
+
+.EggData: ; 295c2
+ db "EGG"
+ next "OT/?????"
+ next "<ID>№.?????@"
+; 295d8
+
+TrademonStats_WaitBGMap: ; 295d8
+ call WaitBGMap
+ call WaitTop
+ ld a, HIGH(vBGMap0)
+ ld [hBGMapAddress + 1], a
+ ret
+
+; 295e3
+
+TrademonStats_PrintSpeciesNumber: ; 295e3
+ hlcoord 10, 0
+ lb bc, PRINTNUM_LEADINGZEROS | 1, 3
+ call PrintNum
+ ld [hl], " "
+ ret
+
+; 295ef
+
+TrademonStats_PrintSpeciesName: ; 295ef
+ hlcoord 4, 2
+ call PlaceString
+ ret
+
+; 295f6
+
+TrademonStats_PrintOTName: ; 295f6
+ cp 3
+ jr c, .caught_gender_okay
+ xor a
+.caught_gender_okay
+ push af
+ hlcoord 7, 4
+ call PlaceString
+ inc bc
+ pop af
+ ld hl, .Gender
+ ld d, 0
+ ld e, a
+ add hl, de
+ ld a, [hl]
+ ld [bc], a
+ ret
+
+; 2960e
+
+.Gender: ; 2960e
+ db " ", "♂", "♀"
+; 29611
+
+TrademonStats_PrintTrademonID: ; 29611
+ hlcoord 7, 6
+ lb bc, PRINTNUM_LEADINGZEROS | 2, 5
+ call PrintNum
+ ret
+
+; 2961b
+
+TradeAnim_RockingBall: ; 2961b
+ depixel 10, 11, 4, 0
+ ld a, SPRITE_ANIM_INDEX_TRADE_POKE_BALL
+ call _InitSpriteAnimStruct
+ call TradeAnim_AdvanceScriptPointer
+ ld a, 32
+ ld [wFrameCounter], a
+ ret
+
+; 2962c
+
+TradeAnim_DropBall: ; 2962c
+ depixel 10, 11, 4, 0
+ ld a, SPRITE_ANIM_INDEX_TRADE_POKE_BALL
+ call _InitSpriteAnimStruct
+ ld hl, SPRITEANIMSTRUCT_JUMPTABLE_INDEX
+ add hl, bc
+ ld [hl], $1
+ ld hl, SPRITEANIMSTRUCT_YOFFSET
+ add hl, bc
+ ld [hl], $dc
+ call TradeAnim_AdvanceScriptPointer
+ ld a, 56
+ ld [wFrameCounter], a
+ ret
+
+; 29649
+
+TradeAnim_Poof: ; 29649
+ depixel 10, 11, 4, 0
+ ld a, SPRITE_ANIM_INDEX_TRADE_POOF
+ call _InitSpriteAnimStruct
+ call TradeAnim_AdvanceScriptPointer
+ ld a, 16
+ ld [wFrameCounter], a
+ ld de, SFX_BALL_POOF
+ call PlaySFX
+ ret
+
+; 29660
+
+TradeAnim_BulgeThroughTube: ; 29660
+ ld a, %11100100 ; 3,2,1,0
+ call DmgToCgbObjPal0
+ depixel 5, 11
+ ld a, SPRITE_ANIM_INDEX_TRADE_TUBE_BULGE
+ call _InitSpriteAnimStruct
+ call TradeAnim_AdvanceScriptPointer
+ ld a, 64
+ ld [wFrameCounter], a
+ ret
+
+; 29676
+
+TradeAnim_AnimateTrademonInTube: ; 29676 (a:5676)
+ ld hl, SPRITEANIMSTRUCT_JUMPTABLE_INDEX
+ add hl, bc
+ ld e, [hl]
+ ld d, 0
+ ld hl, .Jumptable
+ add hl, de
+ add hl, de
+ ld a, [hli]
+ ld h, [hl]
+ ld l, a
+ jp hl
+; 29686
+
+.Jumptable: ; 29686 (a:5686)
+ dw .InitTimer
+ dw .WaitTimer1
+ dw .MoveRight
+ dw .MoveDown
+ dw .MoveUp
+ dw .MoveLeft
+ dw .WaitTimer2
+; 2969a
+
+.JumptableNext: ; 29694 (a:5694)
+ ld hl, SPRITEANIMSTRUCT_JUMPTABLE_INDEX
+ add hl, bc
+ inc [hl]
+ ret
+
+.InitTimer: ; 2969a (a:569a)
+ call .JumptableNext
+ ld hl, SPRITEANIMSTRUCT_0C
+ add hl, bc
+ ld [hl], $80
+ ret
+
+.WaitTimer1: ; 296a4 (a:56a4)
+ ld hl, SPRITEANIMSTRUCT_0C
+ add hl, bc
+ ld a, [hl]
+ dec [hl]
+ and a
+ ret nz
+ call .JumptableNext
+
+.MoveRight: ; 296af (a:56af)
+ ld hl, SPRITEANIMSTRUCT_XCOORD
+ add hl, bc
+ ld a, [hl]
+ cp $94
+ jr nc, .done_move_right
+ inc [hl]
+ ret
+
+.done_move_right
+ call .JumptableNext
+
+.MoveDown: ; 296bd (a:56bd)
+ ld hl, SPRITEANIMSTRUCT_YCOORD
+ add hl, bc
+ ld a, [hl]
+ cp $4c
+ jr nc, .done_move_down
+ inc [hl]
+ ret
+
+.done_move_down
+ ld hl, SPRITEANIMSTRUCT_INDEX
+ add hl, bc
+ ld [hl], $0
+ ret
+
+.MoveUp: ; 296cf (a:56cf)
+ ld hl, SPRITEANIMSTRUCT_YCOORD
+ add hl, bc
+ ld a, [hl]
+ cp $2c
+ jr z, .done_move_up
+ dec [hl]
+ ret
+
+.done_move_up
+ call .JumptableNext
+
+.MoveLeft: ; 296dd (a:56dd)
+ ld hl, SPRITEANIMSTRUCT_XCOORD
+ add hl, bc
+ ld a, [hl]
+ cp $58
+ jr z, .done_move_left
+ dec [hl]
+ ret
+
+.done_move_left
+ call .JumptableNext
+ ld hl, SPRITEANIMSTRUCT_0C
+ add hl, bc
+ ld [hl], $80
+ ret
+
+.WaitTimer2: ; 296f2 (a:56f2)
+ ld hl, SPRITEANIMSTRUCT_0C
+ add hl, bc
+ ld a, [hl]
+ dec [hl]
+ and a
+ ret nz
+ ld hl, SPRITEANIMSTRUCT_INDEX
+ add hl, bc
+ ld [hl], $0
+ ret
+
+; 29701 (a:5701)
+
+TradeAnim_SentToOTText: ; 29701
+ ld a, [wLinkMode]
+ cp LINK_TIMECAPSULE
+ jr z, .time_capsule
+ ld hl, .Text_MonName
+ call PrintText
+ ld c, 189
+ call DelayFrames
+ ld hl, .Text_WasSentTo
+ call PrintText
+ call TradeAnim_Wait80Frames
+ ld c, 128
+ call DelayFrames
+ call TradeAnim_AdvanceScriptPointer
+ ret
+
+.time_capsule
+ ld hl, .Text_WasSentTo
+ call PrintText
+ call TradeAnim_Wait80Frames
+ call TradeAnim_AdvanceScriptPointer
+ ret
+
+; 29732
+
+.Text_WasSentTo: ; 0x29732
+ ; was sent to @ .
+ text_jump UnknownText_0x1bc6e9
+ db "@"
+; 0x29737
+
+.Text_MonName: ; 0x29737
+ ;
+ text_jump UnknownText_0x1bc701
+ db "@"
+; 0x2973c
+
+TradeAnim_OTBidsFarewell: ; 2973c
+ ld hl, .Text_BidsFarewellToMon
+ call PrintText
+ call TradeAnim_Wait80Frames
+ ld hl, .Text_MonName
+ call PrintText
+ call TradeAnim_Wait80Frames
+ call TradeAnim_AdvanceScriptPointer
+ ret
+
+; 29752
+
+.Text_BidsFarewellToMon: ; 0x29752
+ ; bids farewell to
+ text_jump UnknownText_0x1bc703
+ db "@"
+; 0x29757
+
+.Text_MonName: ; 0x29757
+ ; .
+ text_jump UnknownText_0x1bc719
+ db "@"
+; 0x2975c
+
+TradeAnim_TakeCareOfText: ; 2975c
+ call WaitTop
+ hlcoord 0, 10
+ ld bc, 8 * SCREEN_WIDTH
+ ld a, " "
+ call ByteFill
+ call WaitBGMap
+ ld hl, .Text_TakeGoodCareOfMon
+ call PrintText
+ call TradeAnim_Wait80Frames
+ call TradeAnim_AdvanceScriptPointer
+ ret
+
+; 2977a
+
+.Text_TakeGoodCareOfMon: ; 0x2977a
+ ; Take good care of @ .
+ text_jump UnknownText_0x1bc71f
+ db "@"
+; 0x2977f
+
+TradeAnim_OTSendsText1: ; 2977f
+ ld hl, .Text_ForYourMon
+ call PrintText
+ call TradeAnim_Wait80Frames
+ ld hl, .Text_OTSends
+ call PrintText
+ call TradeAnim_Wait80Frames
+ ld c, 14
+ call DelayFrames
+ call TradeAnim_AdvanceScriptPointer
+ ret
+
+; 2979a
+
+.Text_ForYourMon: ; 0x2979a
+ ; For @ 's @ ,
+ text_jump UnknownText_0x1bc739
+ db "@"
+; 0x2979f
+
+.Text_OTSends: ; 0x2979f
+ ; sends @ .
+ text_jump UnknownText_0x1bc74c
+ db "@"
+; 0x297a4
+
+TradeAnim_OTSendsText2: ; 297a4
+ ld hl, .Text_WillTrade
+ call PrintText
+ call TradeAnim_Wait80Frames
+ ld hl, .Text_ForYourMon
+ call PrintText
+ call TradeAnim_Wait80Frames
+ ld c, 14
+ call DelayFrames
+ call TradeAnim_AdvanceScriptPointer
+ ret
+
+; 297bf
+
+.Text_WillTrade: ; 0x297bf
+ ; will trade @ @
+ text_jump UnknownText_0x1bc75e
+ db "@"
+; 0x297c4
+
+.Text_ForYourMon: ; 0x297c4
+ ; for @ 's @ .
+ text_jump UnknownText_0x1bc774
+ db "@"
+; 0x297c9
+
+TradeAnim_Wait80Frames: ; 297c9
+ ld c, 80
+ call DelayFrames
+ ret
+
+; 297cf
+
+TradeAnim_BlankTileMap: ; 297cf
+ hlcoord 0, 0
+ ld bc, SCREEN_WIDTH * SCREEN_HEIGHT
+ ld a, " "
+ call ByteFill
+ ret
+
+; 297db
+
+TradeAnim_CopyBoxFromDEtoHL: ; 297db
+.row
+ push bc
+ push hl
+.col
+ ld a, [de]
+ inc de
+ ld [hli], a
+ dec c
+ jr nz, .col
+ pop hl
+ ld bc, SCREEN_WIDTH
+ add hl, bc
+ pop bc
+ dec b
+ jr nz, .row
+ ret
+
+; 297ed
+
+TradeAnim_NormalPals: ; 297ed
+ ld a, [hSGB]
+ and a
+ ld a, %11100100 ; 3,2,1,0
+ jr z, .not_sgb
+ ld a, $f0
+
+.not_sgb
+ call DmgToCgbObjPal0
+ ld a, %11100100 ; 3,2,1,0
+ call DmgToCgbBGPals
+ ret
+
+; 297ff
+
+LinkTradeAnim_LoadTradePlayerNames: ; 297ff
+ push de
+ ld de, wLinkPlayer1Name
+ ld bc, NAME_LENGTH
+ call CopyBytes
+ pop hl
+ ld de, wLinkPlayer2Name
+ ld bc, NAME_LENGTH
+ call CopyBytes
+ ret
+
+; 29814
+
+LinkTradeAnim_LoadTradeMonSpecies: ; 29814
+ ld a, [hl]
+ ld [wLinkTradeSendmonSpecies], a
+ ld a, [de]
+ ld [wLinkTradeGetmonSpecies], a
+ ret
+
+; 2981d
+
+TradeAnim_FlashBGPals: ; 2981d
+ ld a, [wcf65]
+ and $7
+ ret nz
+ ld a, [rBGP]
+ xor %00111100
+ call DmgToCgbBGPals
+ ret
+
+; 2982b
+
+LoadTradeBallAndCableGFX: ; 2982b
+ call DelayFrame
+ ld de, TradeBallGFX
+ ld hl, vTiles0 tile $62
+ lb bc, BANK(TradeBallGFX), 6
+ call Request2bpp
+ ld de, TradePoofGFX
+ ld hl, vTiles0 tile $68
+ lb bc, BANK(TradePoofGFX), 12
+ call Request2bpp
+ ld de, TradeCableGFX
+ ld hl, vTiles0 tile $74
+ lb bc, BANK(TradeCableGFX), 4
+ call Request2bpp
+ xor a
+ ld hl, wSpriteAnimDict
+ ld [hli], a
+ ld [hl], $62
+ ret
+
+; 2985a
+
+LoadTradeBubbleGFX: ; 2985a
+ call DelayFrame
+ ld e, $3
+ callfar LoadMenuMonIcon
+ ld de, TradeBubbleGFX
+ ld hl, vTiles0 tile $72
+ lb bc, BANK(TradeBubbleGFX), 4
+ call Request2bpp
+ xor a
+ ld hl, wSpriteAnimDict
+ ld [hli], a
+ ld [hl], $62
+ ret
+
+; 29879
+
+TradeAnim_WaitAnim: ; 29879
+ ld hl, wFrameCounter
+ ld a, [hl]
+ and a
+ jr z, .done
+ dec [hl]
+ ret
+
+.done
+ call TradeAnim_AdvanceScriptPointer
+ ret
+
+; 29886
+
+TradeAnim_WaitAnim2: ; 29886
+ ld hl, wFrameCounter
+ ld a, [hl]
+ and a
+ jr z, .done
+ dec [hl]
+ ret
+
+.done
+ call TradeAnim_AdvanceScriptPointer
+ ret
+
+; 29893
+
+
+Unreferenced_DebugTrade: ; 29893
+; This function is not referenced.
+; It was meant for use in Japanese versions, so the
+; constant used for copy length was changed by accident.
+
+ ld hl, .DebugTradeData
+
+ ld a, [hli]
+ ld [wPlayerTrademonSpecies], a
+ ld de, wPlayerTrademonSenderName
+ ld c, NAME_LENGTH + 2 ; JP: NAME_LENGTH_JAPANESE + 2
+.loop1
+ ld a, [hli]
+ ld [de], a
+ inc de
+ dec c
+ jr nz, .loop1
+
+ ld a, [hli]
+ ld [wOTTrademonSpecies], a
+ ld de, wOTTrademonSenderName
+ ld c, NAME_LENGTH + 2 ; JP: NAME_LENGTH_JAPANESE + 2
+.loop2
+ ld a, [hli]
+ ld [de], a
+ inc de
+ dec c
+ jr nz, .loop2
+ ret
+
+; 298b5
+
+debugtrade: MACRO
+; species, ot name, ot id (?)
+ db \1, \2
+ dw \3
+ENDM
+
+.DebugTradeData: ; 298b5
+ debugtrade VENUSAUR, "ゲーフり@@", $0123 ; GAME FREAK
+ debugtrade CHARIZARD, "クりーチャ@", $0456 ; Creatures Inc.
+; 298c7
+
+
+TradeGameBoyTilemap: ; 298c7
+; 6x8
+ db $31, $32, $32, $32, $32, $33
+ db $34, $35, $36, $36, $37, $38
+ db $34, $39, $3a, $3a, $3b, $38
+ db $3c, $3d, $3e, $3e, $3f, $40
+ db $41, $42, $43, $43, $44, $45
+ db $46, $47, $43, $48, $49, $4a
+ db $41, $43, $4b, $4c, $4d, $4e
+ db $4f, $50, $50, $50, $51, $52
+; 297f7
+
+TradeLinkTubeTilemap: ; 297f7
+; 12x3
+ db $43, $55, $56, $53, $53, $53, $53, $53, $53, $53, $53, $53
+ db $43, $57, $58, $54, $54, $54, $54, $54, $54, $54, $54, $54
+ db $43, $59, $5a, $43, $43, $43, $43, $43, $43, $43, $43, $43
+; 2991b
+
+TradeArrowGFX: INCBIN "gfx/trade/arrow.2bpp"
+TradeCableGFX: INCBIN "gfx/trade/cable.2bpp"
+TradeBubbleGFX: INCBIN "gfx/trade/bubble.2bpp"
+TradeGameBoyLZ: INCBIN "gfx/trade/game_boy.2bpp.lz"
+TradeBallGFX: INCBIN "gfx/trade/ball.2bpp"
+TradePoofGFX: INCBIN "gfx/trade/poof.2bpp"