summaryrefslogtreecommitdiff
path: root/home
diff options
context:
space:
mode:
authorPikalaxALT <PikalaxALT@gmail.com>2016-01-29 18:36:31 -0500
committerPikalaxALT <PikalaxALT@gmail.com>2016-01-29 18:36:31 -0500
commit2bf93c5905319e9181f87b3f83cd3bce7b9feeca (patch)
tree3ebf17c8879e5d6243d81aac8f1c36eb226fac26 /home
parented3f9395f6d45f6554ed9d9c49c41ea86a8e2447 (diff)
Import stuff from pokecrystal; diff gold and silver
Diffstat (limited to 'home')
-rw-r--r--home/audio.asm596
-rw-r--r--home/battle.asm361
-rw-r--r--home/copy.asm434
-rw-r--r--home/copy2.asm135
-rw-r--r--home/cry.asm108
-rw-r--r--home/decompress.asm343
-rw-r--r--home/delay.asm22
-rw-r--r--home/double_speed.asm30
-rw-r--r--home/fade.asm136
-rw-r--r--home/farcall.asm54
-rw-r--r--home/flag.asm112
-rw-r--r--home/game_time.asm131
-rw-r--r--home/handshake.asm50
-rw-r--r--home/init.asm222
-rw-r--r--home/item.asm75
-rw-r--r--home/joypad.asm496
-rw-r--r--home/lcd.asm81
-rw-r--r--home/map.asm2385
-rw-r--r--home/map_objects.asm670
-rw-r--r--home/math.asm86
-rw-r--r--home/menu.asm591
-rw-r--r--home/mobile.asm315
-rw-r--r--home/movement.asm208
-rw-r--r--home/palettes.asm365
-rw-r--r--home/pokedex_flags.asm38
-rw-r--r--home/predef.asm53
-rw-r--r--home/random.asm84
-rw-r--r--home/rtc.asm24
-rw-r--r--home/serial.asm410
-rw-r--r--home/sine.asm21
-rw-r--r--home/sram.asm20
-rw-r--r--home/string.asm38
-rw-r--r--home/text.asm1183
-rw-r--r--home/tilemap.asm257
-rw-r--r--home/time.asm312
-rw-r--r--home/vblank.asm442
-rw-r--r--home/video.asm486
-rw-r--r--home/window.asm99
38 files changed, 11473 insertions, 0 deletions
diff --git a/home/audio.asm b/home/audio.asm
new file mode 100644
index 00000000..c7bb7fed
--- /dev/null
+++ b/home/audio.asm
@@ -0,0 +1,596 @@
+; Audio interfaces.
+
+MapSetup_Sound_Off:: ; 3b4e
+
+ push hl
+ push de
+ push bc
+ push af
+
+ ld a, [hROMBank]
+ push af
+ ld a, BANK(_MapSetup_Sound_Off)
+ ld [hROMBank], a
+ ld [MBC3RomBank], a
+
+ call _MapSetup_Sound_Off
+
+ pop af
+ ld [hROMBank], a
+ ld [MBC3RomBank], a
+
+ pop af
+ pop bc
+ pop de
+ pop hl
+ ret
+; 3b6a
+
+
+UpdateSound:: ; 3b6a
+
+ push hl
+ push de
+ push bc
+ push af
+
+ ld a, [hROMBank]
+ push af
+ ld a, BANK(_UpdateSound)
+ ld [hROMBank], a
+ ld [MBC3RomBank], a
+
+ call _UpdateSound
+
+ pop af
+ ld [hROMBank], a
+ ld [MBC3RomBank], a
+
+ pop af
+ pop bc
+ pop de
+ pop hl
+ ret
+; 3b86
+
+
+_LoadMusicByte:: ; 3b86
+; CurMusicByte = [a:de]
+GLOBAL LoadMusicByte
+
+ ld [hROMBank], a
+ ld [MBC3RomBank], a
+
+ ld a, [de]
+ ld [CurMusicByte], a
+ ld a, BANK(LoadMusicByte)
+
+ ld [hROMBank], a
+ ld [MBC3RomBank], a
+ ret
+; 3b97
+
+
+PlayMusic:: ; 3b97
+; Play music de.
+
+ push hl
+ push de
+ push bc
+ push af
+
+ ld a, [hROMBank]
+ push af
+ ld a, BANK(_PlayMusic) ; and BANK(_MapSetup_Sound_Off)
+ ld [hROMBank], a
+ ld [MBC3RomBank], a
+
+ ld a, e
+ and a
+ jr z, .nomusic
+
+ call _PlayMusic
+ jr .end
+
+.nomusic
+ call _MapSetup_Sound_Off
+
+.end
+ pop af
+ ld [hROMBank], a
+ ld [MBC3RomBank], a
+ pop af
+ pop bc
+ pop de
+ pop hl
+ ret
+; 3bbc
+
+
+PlayMusic2:: ; 3bbc
+; Stop playing music, then play music de.
+
+ push hl
+ push de
+ push bc
+ push af
+
+ ld a, [hROMBank]
+ push af
+ ld a, BANK(_PlayMusic)
+ ld [hROMBank], a
+ ld [MBC3RomBank], a
+
+ push de
+ ld de, MUSIC_NONE
+ call _PlayMusic
+ call DelayFrame
+ pop de
+ call _PlayMusic
+
+ pop af
+ ld [hROMBank], a
+ ld [MBC3RomBank], a
+
+ pop af
+ pop bc
+ pop de
+ pop hl
+ ret
+
+; 3be3
+
+
+PlayCryHeader:: ; 3be3
+; Play cry header de.
+
+ push hl
+ push de
+ push bc
+ push af
+
+ ld a, [hROMBank]
+ push af
+
+ ; Cry headers are stuck in one bank.
+ ld a, BANK(CryHeaders)
+ ld [hROMBank], a
+ ld [MBC3RomBank], a
+
+ ld hl, CryHeaders
+rept 6
+ add hl, de
+endr
+
+ ld e, [hl]
+ inc hl
+ ld d, [hl]
+ inc hl
+
+ ld a, [hli]
+ ld [CryPitch], a
+ ld a, [hli]
+ ld [CryPitch + 1], a
+ ld a, [hli]
+ ld [CryLength], a
+ ld a, [hl]
+ ld [CryLength + 1], a
+
+ ld a, BANK(_PlayCryHeader)
+ ld [hROMBank], a
+ ld [MBC3RomBank], a
+
+ call _PlayCryHeader
+
+ pop af
+ ld [hROMBank], a
+ ld [MBC3RomBank], a
+
+ pop af
+ pop bc
+ pop de
+ pop hl
+ ret
+; 3c23
+
+
+PlaySFX:: ; 3c23
+; Play sound effect de.
+; Sound effects are ordered by priority (lowest to highest)
+
+ push hl
+ push de
+ push bc
+ push af
+
+ ; Is something already playing?
+ call CheckSFX
+ jr nc, .play
+
+ ; Does it have priority?
+ ld a, [CurSFX]
+ cp e
+ jr c, .done
+
+.play
+ ld a, [hROMBank]
+ push af
+ ld a, BANK(_PlaySFX)
+ ld [hROMBank], a
+ ld [MBC3RomBank], a
+
+ ld a, e
+ ld [CurSFX], a
+ call _PlaySFX
+
+ pop af
+ ld [hROMBank], a
+ ld [MBC3RomBank], a
+
+.done
+ pop af
+ pop bc
+ pop de
+ pop hl
+ ret
+; 3c4e
+
+
+WaitPlaySFX:: ; 3c4e
+ call WaitSFX
+ call PlaySFX
+ ret
+; 3c55
+
+
+WaitSFX:: ; 3c55
+; infinite loop until sfx is done playing
+
+ push hl
+
+.wait
+ ld hl, Channel5Flags
+ bit 0, [hl]
+ jr nz, .wait
+ ld hl, Channel6Flags
+ bit 0, [hl]
+ jr nz, .wait
+ ld hl, Channel7Flags
+ bit 0, [hl]
+ jr nz, .wait
+ ld hl, Channel8Flags
+ bit 0, [hl]
+ jr nz, .wait
+
+ pop hl
+ ret
+; 3c74
+
+IsSFXPlaying:: ; 3c74
+; Return carry if no sound effect is playing.
+; The inverse of CheckSFX.
+ push hl
+
+ ld hl, Channel5Flags
+ bit 0, [hl]
+ jr nz, .playing
+ ld hl, Channel6Flags
+ bit 0, [hl]
+ jr nz, .playing
+ ld hl, Channel7Flags
+ bit 0, [hl]
+ jr nz, .playing
+ ld hl, Channel8Flags
+ bit 0, [hl]
+ jr nz, .playing
+
+ pop hl
+ scf
+ ret
+
+.playing
+ pop hl
+ and a
+ ret
+; 3c97
+
+MaxVolume:: ; 3c97
+ ld a, $77 ; max
+ ld [Volume], a
+ ret
+; 3c9d
+
+LowVolume:: ; 3c9d
+ ld a, $33 ; 40%
+ ld [Volume], a
+ ret
+; 3ca3
+
+VolumeOff:: ; 3ca3
+ xor a
+ ld [Volume], a
+ ret
+; 3ca8
+
+Unused_FadeOutMusic:: ; 3ca8
+ ld a, 4
+ ld [MusicFade], a
+ ret
+; 3cae
+
+FadeInMusic:: ; 3cae
+ ld a, 4 | 1 << 7
+ ld [MusicFade], a
+ ret
+; 3cb4
+
+SkipMusic:: ; 3cb4
+; Skip a frames of music.
+.loop
+ and a
+ ret z
+ dec a
+ call UpdateSound
+ jr .loop
+; 3cbc
+
+FadeToMapMusic:: ; 3cbc
+ push hl
+ push de
+ push bc
+ push af
+
+ call GetMapMusic
+ ld a, [wMapMusic]
+ cp e
+ jr z, .done
+
+ ld a, 8
+ ld [MusicFade], a
+ ld a, e
+ ld [MusicFadeIDLo], a
+ ld a, d
+ ld [MusicFadeIDHi], a
+ ld a, e
+ ld [wMapMusic], a
+
+.done
+ pop af
+ pop bc
+ pop de
+ pop hl
+ ret
+; 3cdf
+
+PlayMapMusic:: ; 3cdf
+ push hl
+ push de
+ push bc
+ push af
+
+ call GetMapMusic
+ ld a, [wMapMusic]
+ cp e
+ jr z, .done
+
+ push de
+ ld de, MUSIC_NONE
+ call PlayMusic
+ call DelayFrame
+ pop de
+ ld a, e
+ ld [wMapMusic], a
+ call PlayMusic
+
+.done
+ pop af
+ pop bc
+ pop de
+ pop hl
+ ret
+; 3d03
+
+EnterMapMusic:: ; 3d03
+ push hl
+ push de
+ push bc
+ push af
+
+ xor a
+ ld [wDontPlayMapMusicOnReload], a
+ ld de, MUSIC_BICYCLE
+ ld a, [PlayerState]
+ cp PLAYER_BIKE
+ jr z, .play
+ call GetMapMusic
+.play
+ push de
+ ld de, MUSIC_NONE
+ call PlayMusic
+ call DelayFrame
+ pop de
+
+ ld a, e
+ ld [wMapMusic], a
+ call PlayMusic
+
+ pop af
+ pop bc
+ pop de
+ pop hl
+ ret
+; 3d2f
+
+TryRestartMapMusic:: ; 3d2f
+ ld a, [wDontPlayMapMusicOnReload]
+ and a
+ jr z, RestartMapMusic
+ xor a
+ ld [wMapMusic], a
+ ld de, MUSIC_NONE
+ call PlayMusic
+ call DelayFrame
+ xor a
+ ld [wDontPlayMapMusicOnReload], a
+ ret
+; 3d47
+
+RestartMapMusic:: ; 3d47
+ push hl
+ push de
+ push bc
+ push af
+ ld de, MUSIC_NONE
+ call PlayMusic
+ call DelayFrame
+ ld a, [wMapMusic]
+ ld e, a
+ ld d, 0
+ call PlayMusic
+ pop af
+ pop bc
+ pop de
+ pop hl
+ ret
+; 3d62
+
+SpecialMapMusic:: ; 3d62
+ ld a, [PlayerState]
+ cp PLAYER_SURF
+ jr z, .surf
+ cp PLAYER_SURF_PIKA
+ jr z, .surf
+
+ ld a, [StatusFlags2]
+ bit 2, a
+ jr nz, .contest
+
+.no
+ and a
+ ret
+
+.bike
+ ld de, MUSIC_BICYCLE
+ scf
+ ret
+
+.surf
+ ld de, MUSIC_SURF
+ scf
+ ret
+
+.contest
+ ld a, [MapGroup]
+ cp GROUP_ROUTE_35_NATIONAL_PARK_GATE
+ jr nz, .no
+ ld a, [MapNumber]
+ cp MAP_ROUTE_35_NATIONAL_PARK_GATE
+ jr z, .ranking
+ cp MAP_ROUTE_36_NATIONAL_PARK_GATE
+ jr nz, .no
+
+.ranking
+ ld de, MUSIC_BUG_CATCHING_CONTEST_RANKING
+ scf
+ ret
+; 3d97
+
+GetMapMusic:: ; 3d97
+ call SpecialMapMusic
+ ret c
+ call GetMapHeaderMusic
+ ret
+; 3d9f
+
+Function3d9f:: ; 3d9f
+; Places a BCD number at the
+; upper center of the screen.
+; Unreferenced.
+ ld a, 4 * 8
+ ld [Sprites + 38 * 4], a
+ ld [Sprites + 39 * 4], a
+ ld a, 10 * 8
+ ld [Sprites + 38 * 4 + 1], a
+ ld a, 11 * 8
+ ld [Sprites + 39 * 4 + 1], a
+ xor a
+ ld [Sprites + 38 * 4 + 3], a
+ ld [Sprites + 39 * 4 + 3], a
+ ld a, [wc296]
+ cp 100
+ jr nc, .max
+ add 1
+ daa
+ ld b, a
+ swap a
+ and $f
+ add "0"
+ ld [Sprites + 38 * 4 + 2], a
+ ld a, b
+ and $f
+ add "0"
+ ld [Sprites + 39 * 4 + 2], a
+ ret
+
+.max
+ ld a, "9"
+ ld [Sprites + 38 * 4 + 2], a
+ ld [Sprites + 39 * 4 + 2], a
+ ret
+; 3dde
+
+CheckSFX:: ; 3dde
+; Return carry if any SFX channels are active.
+ ld a, [Channel5Flags]
+ bit 0, a
+ jr nz, .playing
+ ld a, [Channel6Flags]
+ bit 0, a
+ jr nz, .playing
+ ld a, [Channel7Flags]
+ bit 0, a
+ jr nz, .playing
+ ld a, [Channel8Flags]
+ bit 0, a
+ jr nz, .playing
+ and a
+ ret
+.playing
+ scf
+ ret
+; 3dfe
+
+TerminateExpBarSound:: ; 3dfe
+ xor a
+ ld [Channel5Flags], a
+ ld [SoundInput], a
+ ld [rNR10], a
+ ld [rNR11], a
+ ld [rNR12], a
+ ld [rNR13], a
+ ld [rNR14], a
+ ret
+; 3e10
+
+
+ChannelsOff:: ; 3e10
+; Quickly turn off music channels
+ xor a
+ ld [Channel1Flags], a
+ ld [Channel2Flags], a
+ ld [Channel3Flags], a
+ ld [Channel4Flags], a
+ ld [SoundInput], a
+ ret
+; 3e21
+
+SFXChannelsOff:: ; 3e21
+; Quickly turn off sound effect channels
+ xor a
+ ld [Channel5Flags], a
+ ld [Channel6Flags], a
+ ld [Channel7Flags], a
+ ld [Channel8Flags], a
+ ld [SoundInput], a
+ ret
+; 3e32
diff --git a/home/battle.asm b/home/battle.asm
new file mode 100644
index 00000000..3fd59363
--- /dev/null
+++ b/home/battle.asm
@@ -0,0 +1,361 @@
+UserPartyAttr:: ; 3945
+ push af
+ ld a, [hBattleTurn]
+ and a
+ jr nz, .ot
+ pop af
+ jr BattlePartyAttr
+.ot
+ pop af
+ jr OTPartyAttr
+; 3951
+
+
+OpponentPartyAttr:: ; 3951
+ push af
+ ld a, [hBattleTurn]
+ and a
+ jr z, .ot
+ pop af
+ jr BattlePartyAttr
+.ot
+ pop af
+ jr OTPartyAttr
+; 395d
+
+
+BattlePartyAttr:: ; 395d
+; Get attribute a from the active BattleMon's party struct.
+ push bc
+ ld c, a
+ ld b, 0
+ ld hl, PartyMons
+ add hl, bc
+ ld a, [CurBattleMon]
+ call GetPartyLocation
+ pop bc
+ ret
+; 396d
+
+
+OTPartyAttr:: ; 396d
+; Get attribute a from the active EnemyMon's party struct.
+ push bc
+ ld c, a
+ ld b, 0
+ ld hl, OTPartyMon1Species
+ add hl, bc
+ ld a, [CurOTMon]
+ call GetPartyLocation
+ pop bc
+ ret
+; 397d
+
+
+ResetDamage:: ; 397d
+ xor a
+ ld [CurDamage], a
+ ld [CurDamage + 1], a
+ ret
+; 3985
+
+SetPlayerTurn:: ; 3985
+ xor a
+ ld [hBattleTurn], a
+ ret
+; 3989
+
+SetEnemyTurn:: ; 3989
+ ld a, 1
+ ld [hBattleTurn], a
+ ret
+; 398e
+
+
+UpdateOpponentInParty:: ; 398e
+ ld a, [hBattleTurn]
+ and a
+ jr z, UpdateEnemyMonInParty
+ jr UpdateBattleMonInParty
+; 3995
+
+UpdateUserInParty:: ; 3995
+ ld a, [hBattleTurn]
+ and a
+ jr z, UpdateBattleMonInParty
+ jr UpdateEnemyMonInParty
+; 399c
+
+UpdateBattleMonInParty:: ; 399c
+; Update level, status, current HP
+
+ ld a, [CurBattleMon]
+
+UpdateBattleMon:: ; 399f
+ ld hl, PartyMon1Level
+ call GetPartyLocation
+
+ ld d, h
+ ld e, l
+ ld hl, BattleMonLevel
+ ld bc, BattleMonMaxHP - BattleMonLevel
+ jp CopyBytes
+; 39b0
+
+UpdateEnemyMonInParty:: ; 39b0
+; Update level, status, current HP
+
+; No wildmons.
+ ld a, [wBattleMode]
+ dec a
+ ret z
+
+ ld a, [CurOTMon]
+ ld hl, OTPartyMon1Level
+ call GetPartyLocation
+
+ ld d, h
+ ld e, l
+ ld hl, EnemyMonLevel
+ ld bc, EnemyMonMaxHP - EnemyMonLevel
+ jp CopyBytes
+; 39c9
+
+
+RefreshBattleHuds:: ; 39c9
+ call UpdateBattleHuds
+ ld c, 3
+ call DelayFrames
+ jp WaitBGMap
+; 39d4
+
+UpdateBattleHuds:: ; 39d4
+ callba UpdatePlayerHUD
+ callba UpdateEnemyHUD
+ ret
+; 39e1
+
+
+GetBattleVar:: ; 39e1
+; Preserves hl.
+ push hl
+ call GetBattleVarAddr
+ pop hl
+ ret
+; 39e7
+
+GetBattleVarAddr:: ; 39e7
+; Get variable from pair a, depending on whose turn it is.
+; There are 21 variable pairs.
+
+ push bc
+
+ ld hl, .battlevarpairs
+ ld c, a
+ ld b, 0
+rept 2
+ add hl, bc
+endr
+
+ ld a, [hli]
+ ld h, [hl]
+ ld l, a
+
+; Enemy turn uses the second byte instead.
+; This lets battle variable calls be side-neutral.
+ ld a, [hBattleTurn]
+ and a
+ jr z, .getvar
+ inc hl
+
+.getvar
+; var id
+ ld a, [hl]
+ ld c, a
+ ld b, 0
+
+ ld hl, .vars
+rept 2
+ add hl, bc
+endr
+
+ ld a, [hli]
+ ld h, [hl]
+ ld l, a
+
+ ld a, [hl]
+
+ pop bc
+ ret
+
+.battlevarpairs
+ dw .substatus1, .substatus2, .substatus3, .substatus4, .substatus5
+ dw .substatus1opp, .substatus2opp, .substatus3opp, .substatus4opp, .substatus5opp
+ dw .status, .statusopp, .animation, .effect, .power, .type
+ dw .curmove, .lastcounter, .lastcounteropp, .lastmove, .lastmoveopp
+
+; player enemy
+.substatus1 db PLAYER_SUBSTATUS_1, ENEMY_SUBSTATUS_1
+.substatus1opp db ENEMY_SUBSTATUS_1, PLAYER_SUBSTATUS_1
+.substatus2 db PLAYER_SUBSTATUS_2, ENEMY_SUBSTATUS_2
+.substatus2opp db ENEMY_SUBSTATUS_2, PLAYER_SUBSTATUS_2
+.substatus3 db PLAYER_SUBSTATUS_3, ENEMY_SUBSTATUS_3
+.substatus3opp db ENEMY_SUBSTATUS_3, PLAYER_SUBSTATUS_3
+.substatus4 db PLAYER_SUBSTATUS_4, ENEMY_SUBSTATUS_4
+.substatus4opp db ENEMY_SUBSTATUS_4, PLAYER_SUBSTATUS_4
+.substatus5 db PLAYER_SUBSTATUS_5, ENEMY_SUBSTATUS_5
+.substatus5opp db ENEMY_SUBSTATUS_5, PLAYER_SUBSTATUS_5
+.status db PLAYER_STATUS, ENEMY_STATUS
+.statusopp db ENEMY_STATUS, PLAYER_STATUS
+.animation db PLAYER_MOVE_ANIMATION, ENEMY_MOVE_ANIMATION
+.effect db PLAYER_MOVE_EFFECT, ENEMY_MOVE_EFFECT
+.power db PLAYER_MOVE_POWER, ENEMY_MOVE_POWER
+.type db PLAYER_MOVE_TYPE, ENEMY_MOVE_TYPE
+.curmove db PLAYER_CUR_MOVE, ENEMY_CUR_MOVE
+.lastcounter db PLAYER_COUNTER_MOVE, ENEMY_COUNTER_MOVE
+.lastcounteropp db ENEMY_COUNTER_MOVE, PLAYER_COUNTER_MOVE
+.lastmove db PLAYER_LAST_MOVE, ENEMY_LAST_MOVE
+.lastmoveopp db ENEMY_LAST_MOVE, PLAYER_LAST_MOVE
+
+.vars
+ dw PlayerSubStatus1, EnemySubStatus1
+ dw PlayerSubStatus2, EnemySubStatus2
+ dw PlayerSubStatus3, EnemySubStatus3
+ dw PlayerSubStatus4, EnemySubStatus4
+ dw PlayerSubStatus5, EnemySubStatus5
+ dw BattleMonStatus, EnemyMonStatus
+ dw wPlayerMoveStructAnimation, wEnemyMoveStructAnimation
+ dw wPlayerMoveStructEffect, wEnemyMoveStructEffect
+ dw wPlayerMoveStructPower, wEnemyMoveStructPower
+ dw wPlayerMoveStructType, wEnemyMoveStructType
+ dw CurPlayerMove, CurEnemyMove
+ dw LastEnemyCounterMove, LastPlayerCounterMove
+ dw LastPlayerMove, LastEnemyMove
+; 3a90
+
+
+FarCopyRadioText:: ; 3a90
+ inc hl
+ ld a, [hROMBank]
+ push af
+ ld a, [hli]
+ ld e, a
+ ld a, [hli]
+ ld d, a
+ ld a, [hli]
+ ld [hROMBank], a
+ ld [MBC3RomBank], a
+ ld a, e
+ ld l, a
+ ld a, d
+ ld h, a
+ ld de, wRadioText
+ ld bc, 2 * SCREEN_WIDTH
+ call CopyBytes
+ pop af
+ ld [hROMBank], a
+ ld [MBC3RomBank], a
+ ret
+; 3ab2
+
+
+MobileTextBorder:: ; 3ab2
+
+CELL_PHONE_TOP EQU $5e
+CELL_PHONE_BOTTOM EQU $5f
+
+ ; For mobile link battles only.
+ ld a, [wLinkMode]
+ cp LINK_MOBILE
+ ret c
+
+ ; Draw a cell phone icon at the
+ ; top right corner of the border.
+ hlcoord 19, 12
+ ld [hl], CELL_PHONE_TOP
+ hlcoord 19, 13
+ ld [hl], CELL_PHONE_BOTTOM
+ ret
+; 3ac3
+
+
+BattleTextBox:: ; 3ac3
+; Open a textbox and print text at hl.
+ push hl
+ call SpeechTextBox
+ call MobileTextBorder
+ call UpdateSprites
+ call ApplyTilemap
+ pop hl
+ call PrintTextBoxText
+ ret
+; 3ad5
+
+
+StdBattleTextBox:: ; 3ad5
+; Open a textbox and print battle text at 20:hl.
+
+GLOBAL BattleText
+
+ ld a, [hROMBank]
+ push af
+
+ ld a, BANK(BattleText)
+ rst Bankswitch
+
+ call BattleTextBox
+
+ pop af
+ rst Bankswitch
+ ret
+; 3ae1
+
+GetBattleAnimPointer:: ; 3ae1
+
+GLOBAL BattleAnimations
+GLOBAL BattleAnimCommands
+
+ ld a, BANK(BattleAnimations)
+ rst Bankswitch
+
+ ld a, [hli]
+ ld [BattleAnimAddress], a
+ ld a, [hl]
+ ld [BattleAnimAddress + 1], a
+
+ ld a, BANK(BattleAnimCommands)
+ rst Bankswitch
+
+ ret
+; 3af0
+
+GetBattleAnimByte:: ; 3af0
+
+ push hl
+ push de
+
+ ld hl, BattleAnimAddress
+ ld e, [hl]
+ inc hl
+ ld d, [hl]
+
+ ld a, BANK(BattleAnimations)
+ rst Bankswitch
+
+ ld a, [de]
+ ld [BattleAnimByte], a
+ inc de
+
+ ld a, BANK(BattleAnimCommands)
+ rst Bankswitch
+
+ ld [hl], d
+ dec hl
+ ld [hl], e
+
+ pop de
+ pop hl
+
+ ld a, [BattleAnimByte]
+ ret
+; 3b0c
diff --git a/home/copy.asm b/home/copy.asm
new file mode 100644
index 00000000..08eb5c10
--- /dev/null
+++ b/home/copy.asm
@@ -0,0 +1,434 @@
+; Functions to copy data from ROM.
+
+
+Get2bpp_2:: ; dc9
+ ld a, [rLCDC]
+ bit 7, a
+ jp z, Copy2bpp
+
+ ld a, [hROMBank]
+ push af
+ ld a, BANK(_Get2bpp)
+ rst Bankswitch
+ call _Get2bpp
+ pop af
+ rst Bankswitch
+
+ ret
+; ddc
+
+Get1bpp_2:: ; ddc
+ ld a, [rLCDC]
+ bit 7, a
+ jp z, Copy1bpp
+
+ ld a, [hROMBank]
+ push af
+ ld a, BANK(_Get1bpp)
+ rst Bankswitch
+ call _Get1bpp
+ pop af
+ rst Bankswitch
+
+ ret
+; def
+
+FarCopyBytesDouble_DoubleBankSwitch:: ; def
+ ld [hBuffer], a
+ ld a, [hROMBank]
+ push af
+ ld a, [hBuffer]
+ rst Bankswitch
+
+ call FarCopyBytesDouble
+
+ pop af
+ rst Bankswitch
+ ret
+; dfd
+
+OldDMATransfer:: ; dfd
+ dec c
+ ld a, [hBGMapMode]
+ push af
+ xor a
+ ld [hBGMapMode], a
+ ld a, [hROMBank]
+ push af
+ ld a, b
+ rst Bankswitch
+
+.loop
+; load the source and target MSB and LSB
+ ld a, d
+ ld [rHDMA1], a ; source MSB
+ ld a, e
+ and $f0
+ ld [rHDMA2], a ; source LSB
+ ld a, h
+ and $1f
+ ld [rHDMA3], a ; target MSB
+ ld a, l
+ and $f0
+ ld [rHDMA4], a ; target LSB
+; stop when c < 8
+ ld a, c
+ cp $8
+ jr c, .done
+; decrease c by 8
+ sub $8
+ ld c, a
+; DMA transfer state
+ ld a, $f
+ ld [hDMATransfer], a
+ call DelayFrame
+; add $100 to hl and de
+ ld a, l
+ add $100 % $100
+ ld l, a
+ ld a, h
+ adc $100 / $100
+ ld h, a
+ ld a, e
+ add $100 % $100
+ ld e, a
+ ld a, d
+ adc $100 / $100
+ ld d, a
+ jr .loop
+
+.done
+ ld a, c
+ and $7f ; pretty silly, considering at most bits 0-2 would be set
+ ld [hDMATransfer], a
+ call DelayFrame
+ pop af
+ rst Bankswitch
+
+ pop af
+ ld [hBGMapMode], a
+ ret
+; e4a
+
+
+
+ReplaceKrisSprite:: ; e4a
+ callba _ReplaceKrisSprite
+ ret
+; e51
+
+
+
+LoadStandardFont:: ; e51
+ callba _LoadStandardFont
+ ret
+; e58
+
+LoadFontsBattleExtra:: ; e58
+ callba _LoadFontsBattleExtra
+ ret
+; e5f
+
+
+
+LoadFontsExtra:: ; e5f
+ callba _LoadFontsExtra1
+ callba _LoadFontsExtra2
+ ret
+; e6c
+
+LoadFontsExtra2:: ; e6c
+ callba _LoadFontsExtra2
+ ret
+; e73
+
+DecompressRequest2bpp:: ; e73
+ push de
+ ld a, BANK(sScratch)
+ call GetSRAMBank
+ push bc
+
+ ld de, sScratch
+ ld a, b
+ call FarDecompress
+
+ pop bc
+ pop hl
+
+ ld de, sScratch
+ call Request2bpp
+ call CloseSRAM
+ ret
+; e8d
+
+
+
+FarCopyBytes:: ; e8d
+; copy bc bytes from a:hl to de
+
+ ld [hBuffer], a
+ ld a, [hROMBank]
+ push af
+ ld a, [hBuffer]
+ rst Bankswitch
+
+ call CopyBytes
+
+ pop af
+ rst Bankswitch
+ ret
+; 0xe9b
+
+
+FarCopyBytesDouble:: ; e9b
+; Copy bc bytes from a:hl to bc*2 bytes at de,
+; doubling each byte in the process.
+
+ ld [hBuffer], a
+ ld a, [hROMBank]
+ push af
+ ld a, [hBuffer]
+ rst Bankswitch
+
+; switcheroo, de <> hl
+ ld a, h
+ ld h, d
+ ld d, a
+ ld a, l
+ ld l, e
+ ld e, a
+
+ inc b
+ inc c
+ jr .dec
+
+.loop
+ ld a, [de]
+ inc de
+rept 2
+ ld [hli], a
+endr
+.dec
+ dec c
+ jr nz, .loop
+ dec b
+ jr nz, .loop
+
+ pop af
+ rst Bankswitch
+ ret
+; 0xeba
+
+
+Request2bpp:: ; eba
+; Load 2bpp at b:de to occupy c tiles of hl.
+ ld a, [hBGMapMode]
+ push af
+ xor a
+ ld [hBGMapMode], a
+
+ ld a, [hROMBank]
+ push af
+ ld a, b
+ rst Bankswitch
+
+ ld a, [hTilesPerCycle]
+ push af
+ ld a, $8
+ ld [hTilesPerCycle], a
+
+ ld a, [wLinkMode]
+ cp LINK_MOBILE
+ jr nz, .NotMobile
+ ld a, [hMobile]
+ and a
+ jr nz, .NotMobile
+ ld a, $6
+ ld [hTilesPerCycle], a
+
+.NotMobile
+ ld a, e
+ ld [Requested2bppSource], a
+ ld a, d
+ ld [Requested2bppSource + 1], a
+ ld a, l
+ ld [Requested2bppDest], a
+ ld a, h
+ ld [Requested2bppDest + 1], a
+.loop
+ ld a, c
+ ld hl, hTilesPerCycle
+ cp [hl]
+ jr nc, .iterate
+
+ ld [Requested2bpp], a
+.wait
+ call DelayFrame
+ ld a, [Requested2bpp]
+ and a
+ jr nz, .wait
+
+ pop af
+ ld [hTilesPerCycle], a
+
+ pop af
+ rst Bankswitch
+
+ pop af
+ ld [hBGMapMode], a
+ ret
+
+.iterate
+ ld a, [hTilesPerCycle]
+ ld [Requested2bpp], a
+
+.wait2
+ call DelayFrame
+ ld a, [Requested2bpp]
+ and a
+ jr nz, .wait2
+
+ ld a, c
+ ld hl, hTilesPerCycle
+ sub [hl]
+ ld c, a
+ jr .loop
+; f1e
+
+
+Request1bpp:: ; f1e
+; Load 1bpp at b:de to occupy c tiles of hl.
+ ld a, [hBGMapMode]
+ push af
+ xor a
+ ld [hBGMapMode], a
+
+ ld a, [hROMBank]
+ push af
+ ld a, b
+ rst Bankswitch
+
+ ld a, [hTilesPerCycle]
+ push af
+
+ ld a, $8
+ ld [hTilesPerCycle], a
+ ld a, [wLinkMode]
+ cp LINK_MOBILE
+ jr nz, .NotMobile
+ ld a, [hMobile]
+ and a
+ jr nz, .NotMobile
+ ld a, $6
+ ld [hTilesPerCycle], a
+
+.NotMobile
+ ld a, e
+ ld [Requested1bppSource], a
+ ld a, d
+ ld [Requested1bppSource + 1], a
+ ld a, l
+ ld [Requested1bppDest], a
+ ld a, h
+ ld [Requested1bppDest + 1], a
+.loop
+ ld a, c
+ ld hl, hTilesPerCycle
+ cp [hl]
+ jr nc, .iterate
+
+ ld [Requested1bpp], a
+.wait
+ call DelayFrame
+ ld a, [Requested1bpp]
+ and a
+ jr nz, .wait
+
+ pop af
+ ld [hTilesPerCycle], a
+
+ pop af
+ rst Bankswitch
+
+ pop af
+ ld [hBGMapMode], a
+ ret
+
+.iterate
+ ld a, [hTilesPerCycle]
+ ld [Requested1bpp], a
+
+.wait2
+ call DelayFrame
+ ld a, [Requested1bpp]
+ and a
+ jr nz, .wait2
+
+ ld a, c
+ ld hl, hTilesPerCycle
+ sub [hl]
+ ld c, a
+ jr .loop
+; f82
+
+
+Get2bpp:: ; f82
+ ld a, [rLCDC]
+ bit 7, a
+ jp nz, Request2bpp
+
+Copy2bpp:: ; f89
+; copy c 2bpp tiles from b:de to hl
+
+ push hl
+ ld h, d
+ ld l, e
+ pop de
+
+; bank
+ ld a, b
+
+; bc = c * $10
+ push af
+ swap c
+ ld a, $f
+ and c
+ ld b, a
+ ld a, $f0
+ and c
+ ld c, a
+ pop af
+
+ jp FarCopyBytes
+; f9d
+
+
+Get1bpp:: ; f9d
+ ld a, [rLCDC]
+ bit 7, a
+ jp nz, Request1bpp
+
+Copy1bpp:: ; fa4
+; copy c 1bpp tiles from b:de to hl
+
+ push de
+ ld d, h
+ ld e, l
+
+; bank
+ ld a, b
+
+; bc = c * $10 / 2
+ push af
+ ld h, 0
+ ld l, c
+rept 3
+ add hl, hl
+endr
+ ld b, h
+ ld c, l
+ pop af
+
+ pop hl
+ jp FarCopyBytesDouble
+; fb6
diff --git a/home/copy2.asm b/home/copy2.asm
new file mode 100644
index 00000000..538be572
--- /dev/null
+++ b/home/copy2.asm
@@ -0,0 +1,135 @@
+CopyBytes:: ; 0x3026
+; copy bc bytes from hl to de
+ inc b ; we bail the moment b hits 0, so include the last run
+ inc c ; same thing; include last byte
+ jr .HandleLoop
+.CopyByte
+ ld a, [hli]
+ ld [de], a
+ inc de
+.HandleLoop
+ dec c
+ jr nz, .CopyByte
+ dec b
+ jr nz, .CopyByte
+ ret
+
+SwapBytes:: ; 0x3034
+; swap bc bytes between hl and de
+.Loop
+ ; stash [hl] away on the stack
+ ld a, [hl]
+ push af
+
+ ; copy a byte from [de] to [hl]
+ ld a, [de]
+ ld [hli], a
+
+ ; retrieve the previous value of [hl]; put it in [de]
+ pop af
+ ld [de], a
+ inc de
+
+ ; handle loop stuff
+ dec bc
+ ld a, b
+ or c
+ jr nz, .Loop
+ ret
+
+ByteFill:: ; 0x3041
+; fill bc bytes with the value of a, starting at hl
+ inc b ; we bail the moment b hits 0, so include the last run
+ inc c ; same thing; include last byte
+ jr .HandleLoop
+.PutByte
+ ld [hli], a
+.HandleLoop
+ dec c
+ jr nz, .PutByte
+ dec b
+ jr nz, .PutByte
+ ret
+
+GetFarByte:: ; 0x304d
+; retrieve a single byte from a:hl, and return it in a.
+ ; bankswitch to new bank
+ ld [hBuffer], a
+ ld a, [hROMBank]
+ push af
+ ld a, [hBuffer]
+ rst Bankswitch
+
+ ; get byte from new bank
+ ld a, [hl]
+ ld [hBuffer], a
+
+ ; bankswitch to previous bank
+ pop af
+ rst Bankswitch
+
+ ; return retrieved value in a
+ ld a, [hBuffer]
+ ret
+
+GetFarHalfword:: ; 0x305d
+; retrieve a halfword from a:hl, and return it in hl.
+ ; bankswitch to new bank
+ ld [hBuffer], a
+ ld a, [hROMBank]
+ push af
+ ld a, [hBuffer]
+ rst Bankswitch
+
+ ; get halfword from new bank, put it in hl
+ ld a, [hli]
+ ld h, [hl]
+ ld l, a
+
+ ; bankswitch to previous bank and return
+ pop af
+ rst Bankswitch
+ ret
+; 0x306b
+
+FarCopyWRAM:: ; 306b
+ ld [hBuffer], a
+ ld a, [rSVBK]
+ push af
+ ld a, [hBuffer]
+ ld [rSVBK], a
+
+ call CopyBytes
+
+ pop af
+ ld [rSVBK], a
+ ret
+; 307b
+
+GetFarWRAMByte:: ; 307b
+ ld [hBuffer], a
+ ld a, [rSVBK]
+ push af
+ ld a, [hBuffer]
+ ld [rSVBK], a
+ ld a, [hl]
+ ld [hBuffer], a
+ pop af
+ ld [rSVBK], a
+ ld a, [hBuffer]
+ ret
+; 308d
+
+GetFarWRAMWord:: ; 308d
+ ld [hBuffer], a
+ ld a, [rSVBK]
+ push af
+ ld a, [hBuffer]
+ ld [rSVBK], a
+ ld a, [hli]
+ ld h, [hl]
+ ld l, a
+ pop af
+ ld [rSVBK], a
+ ret
+; 309d
diff --git a/home/cry.asm b/home/cry.asm
new file mode 100644
index 00000000..aea7af03
--- /dev/null
+++ b/home/cry.asm
@@ -0,0 +1,108 @@
+PlayStereoCry:: ; 37b6
+ push af
+ ld a, 1
+ ld [wStereoPanningMask], a
+ pop af
+ call _PlayCry
+ call WaitSFX
+ ret
+; 37c4
+
+PlayStereoCry2:: ; 37c4
+; Don't wait for the cry to end.
+; Used during pic animations.
+ push af
+ ld a, 1
+ ld [wStereoPanningMask], a
+ pop af
+ jp _PlayCry
+; 37ce
+
+PlayCry:: ; 37ce
+ call PlayCry2
+ call WaitSFX
+ ret
+; 37d5
+
+PlayCry2:: ; 37d5
+; Don't wait for the cry to end.
+ push af
+ xor a
+ ld [wStereoPanningMask], a
+ ld [CryTracks], a
+ pop af
+ call _PlayCry
+ ret
+; 37e2
+
+_PlayCry:: ; 37e2
+ push hl
+ push de
+ push bc
+
+ call GetCryIndex
+ jr c, .done
+
+ ld e, c
+ ld d, b
+ call PlayCryHeader
+
+.done
+ pop bc
+ pop de
+ pop hl
+ ret
+; 37f3
+
+LoadCryHeader:: ; 37f3
+; Load cry header bc.
+
+ call GetCryIndex
+ ret c
+
+ ld a, [hROMBank]
+ push af
+ ld a, BANK(CryHeaders)
+ rst Bankswitch
+
+ ld hl, CryHeaders
+rept 6
+ add hl, bc
+endr
+
+ ld e, [hl]
+ inc hl
+ ld d, [hl]
+ inc hl
+
+ ld a, [hli]
+ ld [CryPitch], a
+ ld a, [hli]
+ ld [CryPitch + 1], a
+ ld a, [hli]
+ ld [CryLength], a
+ ld a, [hl]
+ ld [CryLength + 1], a
+
+ pop af
+ rst Bankswitch
+ and a
+ ret
+; 381e
+
+GetCryIndex:: ; 381e
+ and a
+ jr z, .no
+ cp NUM_POKEMON + 1
+ jr nc, .no
+
+ dec a
+ ld c, a
+ ld b, 0
+ and a
+ ret
+
+.no
+ scf
+ ret
+; 382d
diff --git a/home/decompress.asm b/home/decompress.asm
new file mode 100644
index 00000000..13613f64
--- /dev/null
+++ b/home/decompress.asm
@@ -0,0 +1,343 @@
+FarDecompress:: ; b40
+; Decompress graphics data from a:hl to de.
+
+ ld [wLZBank], a
+ ld a, [hROMBank]
+ push af
+ ld a, [wLZBank]
+ rst Bankswitch
+
+ call Decompress
+
+ pop af
+ rst Bankswitch
+ ret
+; b50
+
+
+Decompress:: ; b50
+; Pokemon Crystal uses an lz variant for compression.
+; This is mainly (but not necessarily) used for graphics.
+
+; This function decompresses lz-compressed data from hl to de.
+
+
+LZ_END EQU $ff ; Compressed data is terminated with $ff.
+
+
+; A typical control command consists of:
+
+LZ_CMD EQU %11100000 ; command id (bits 5-7)
+LZ_LEN EQU %00011111 ; length n (bits 0-4)
+
+; Additional parameters are read during command execution.
+
+
+; Commands:
+
+LZ_LITERAL EQU 0 << 5 ; Read literal data for n bytes.
+LZ_ITERATE EQU 1 << 5 ; Write the same byte for n bytes.
+LZ_ALTERNATE EQU 2 << 5 ; Alternate two bytes for n bytes.
+LZ_ZERO EQU 3 << 5 ; Write 0 for n bytes.
+
+
+; Another class of commands reuses data from the decompressed output.
+LZ_RW EQU 2 + 5 ; bit
+
+; These commands take a signed offset to start copying from.
+; Wraparound is simulated.
+; Positive offsets (15-bit) are added to the start address.
+; Negative offsets (7-bit) are subtracted from the current position.
+
+LZ_REPEAT EQU 4 << 5 ; Repeat n bytes from the offset.
+LZ_FLIP EQU 5 << 5 ; Repeat n bitflipped bytes.
+LZ_REVERSE EQU 6 << 5 ; Repeat n bytes in reverse.
+
+
+; If the value in the count needs to be larger than 5 bits,
+; LZ_LONG can be used to expand the count to 10 bits.
+LZ_LONG EQU 7 << 5
+
+; A new control command is read in bits 2-4.
+; The top two bits of the length are bits 0-1.
+; Another byte is read containing the bottom 8 bits.
+LZ_LONG_HI EQU %00000011
+
+; In other words, the structure of the command becomes
+; 111xxxyy yyyyyyyy
+; x: the new control command
+; y: the length
+
+
+; For more information, refer to the code below and in extras/gfx.py.
+
+
+ ; Save the output address
+ ; for rewrite commands.
+ ld a, e
+ ld [wLZAddress], a
+ ld a, d
+ ld [wLZAddress + 1], a
+
+.Main
+ ld a, [hl]
+ cp LZ_END
+ ret z
+
+ and LZ_CMD
+
+ cp LZ_LONG
+ jr nz, .short
+
+.long
+; The count is now 10 bits.
+
+ ; Read the next 3 bits.
+ ; %00011100 -> %11100000
+ ld a, [hl]
+ add a
+ add a ; << 3
+ add a
+
+ ; This is our new control code.
+ and LZ_CMD
+ push af
+
+ ld a, [hli]
+ and LZ_LONG_HI
+ ld b, a
+ ld a, [hli]
+ ld c, a
+
+ ; read at least 1 byte
+ inc bc
+ jr .command
+
+
+.short
+ push af
+
+ ld a, [hli]
+ and LZ_LEN
+ ld c, a
+ ld b, 0
+
+ ; read at least 1 byte
+ inc c
+
+
+.command
+ ; Increment loop counts.
+ ; We bail the moment they hit 0.
+ inc b
+ inc c
+
+ pop af
+
+ bit LZ_RW, a
+ jr nz, .rewrite
+
+ cp LZ_ITERATE
+ jr z, .Iter
+ cp LZ_ALTERNATE
+ jr z, .Alt
+ cp LZ_ZERO
+ jr z, .Zero
+
+
+.Literal
+; Read literal data for bc bytes.
+.lloop
+ dec c
+ jr nz, .lnext
+ dec b
+ jp z, .Main
+
+.lnext
+ ld a, [hli]
+ ld [de], a
+ inc de
+ jr .lloop
+
+
+.Iter
+; Write the same byte for bc bytes.
+ ld a, [hli]
+
+.iloop
+ dec c
+ jr nz, .inext
+ dec b
+ jp z, .Main
+
+.inext
+ ld [de], a
+ inc de
+ jr .iloop
+
+
+.Alt
+; Alternate two bytes for bc bytes.
+ dec c
+ jr nz, .anext1
+ dec b
+ jp z, .adone1
+.anext1
+ ld a, [hli]
+ ld [de], a
+ inc de
+
+ dec c
+ jr nz, .anext2
+ dec b
+ jp z, .adone2
+.anext2
+ ld a, [hld]
+ ld [de], a
+ inc de
+
+ jr .Alt
+
+ ; Skip past the bytes we were alternating.
+.adone1
+ inc hl
+.adone2
+ inc hl
+ jr .Main
+
+
+.Zero
+; Write 0 for bc bytes.
+ xor a
+
+.zloop
+ dec c
+ jr nz, .znext
+ dec b
+ jp z, .Main
+
+.znext
+ ld [de], a
+ inc de
+ jr .zloop
+
+
+.rewrite
+; Repeat decompressed data from output.
+ push hl
+ push af
+
+ ld a, [hli]
+ bit 7, a ; sign
+ jr z, .positive
+
+.negative
+; hl = de - a
+ ; Since we can't subtract a from de,
+ ; Make it negative and add de.
+ and %01111111
+ cpl
+ add e
+ ld l, a
+ ld a, -1
+ adc d
+ ld h, a
+ jr .ok
+
+.positive
+; Positive offsets are two bytes.
+ ld l, [hl]
+ ld h, a
+ ; add to starting output address
+ ld a, [wLZAddress]
+ add l
+ ld l, a
+ ld a, [wLZAddress + 1]
+ adc h
+ ld h, a
+
+.ok
+ pop af
+
+ cp LZ_REPEAT
+ jr z, .Repeat
+ cp LZ_FLIP
+ jr z, .Flip
+ cp LZ_REVERSE
+ jr z, .Reverse
+
+; Since LZ_LONG is command 7,
+; only commands 0-6 are passed in.
+; This leaves room for an extra command 7.
+; However, lengths longer than 768
+; would be interpreted as LZ_END.
+
+; More practically, LZ_LONG is not recursive.
+; For now, it defaults to LZ_REPEAT.
+
+
+.Repeat
+; Copy decompressed data for bc bytes.
+ dec c
+ jr nz, .rnext
+ dec b
+ jr z, .donerw
+
+.rnext
+ ld a, [hli]
+ ld [de], a
+ inc de
+ jr .Repeat
+
+
+.Flip
+; Copy bitflipped decompressed data for bc bytes.
+ dec c
+ jr nz, .fnext
+ dec b
+ jp z, .donerw
+
+.fnext
+ ld a, [hli]
+ push bc
+ lb bc, 0, 8
+
+.floop
+ rra
+ rl b
+ dec c
+ jr nz, .floop
+
+ ld a, b
+ pop bc
+
+ ld [de], a
+ inc de
+ jr .Flip
+
+
+.Reverse
+; Copy reversed decompressed data for bc bytes.
+ dec c
+ jr nz, .rvnext
+
+ dec b
+ jp z, .donerw
+
+.rvnext
+ ld a, [hld]
+ ld [de], a
+ inc de
+ jr .Reverse
+
+
+.donerw
+ pop hl
+
+ bit 7, [hl]
+ jr nz, .next
+ inc hl ; positive offset is two bytes
+.next
+ inc hl
+ jp .Main
+; c2f
diff --git a/home/delay.asm b/home/delay.asm
new file mode 100644
index 00000000..450b4190
--- /dev/null
+++ b/home/delay.asm
@@ -0,0 +1,22 @@
+DelayFrame:: ; 45a
+; Wait for one frame
+ ld a, 1
+ ld [VBlankOccurred], a
+
+; Wait for the next VBlank, halting to conserve battery
+.halt
+ halt ; rgbasm adds a nop after this instruction by default
+ ld a, [VBlankOccurred]
+ and a
+ jr nz, .halt
+ ret
+; 468
+
+
+DelayFrames:: ; 468
+; Wait c frames
+ call DelayFrame
+ dec c
+ jr nz, DelayFrames
+ ret
+; 46f
diff --git a/home/double_speed.asm b/home/double_speed.asm
new file mode 100644
index 00000000..c07dc9ce
--- /dev/null
+++ b/home/double_speed.asm
@@ -0,0 +1,30 @@
+; The CGB hardware introduces Double Speed Mode.
+; While active, the clock speed is doubled.
+
+; The hardware can switch between normal speed
+; and double speed at any time, but LCD output
+; collapses during the switch.
+
+DoubleSpeed:: ; 2fef
+ ld hl, rKEY1
+ bit 7, [hl]
+ jr z, SwitchSpeed
+ ret
+; 2ff7
+
+NormalSpeed:: ; 2ff7
+ ld hl, rKEY1
+ bit 7, [hl]
+ ret z
+; 2ffd
+
+SwitchSpeed:: ; 2ffd
+ set 0, [hl]
+ xor a
+ ld [rIF], a
+ ld [rIE], a
+ ld a, $30
+ ld [rJOYP], a
+ stop ; rgbasm adds a nop after this instruction by default
+ ret
+; 300b
diff --git a/home/fade.asm b/home/fade.asm
new file mode 100644
index 00000000..579a4125
--- /dev/null
+++ b/home/fade.asm
@@ -0,0 +1,136 @@
+; Functions to fade the screen in and out.
+
+
+Function48c:: ; 48c
+ ld a, [TimeOfDayPal]
+ ld b, a
+ ld hl, IncGradGBPalTable_11
+ ld a, l
+ sub b
+ ld l, a
+ jr nc, .okay
+ dec h
+
+.okay
+ ld a, [hli]
+ ld [rBGP], a
+ ld a, [hli]
+ ld [rOBP0], a
+ ld a, [hli]
+ ld [rOBP1], a
+ ret
+; 4a3
+
+
+RotateFourPalettesRight:: ; 4a3
+ ld a, [hCGB]
+ and a
+ jr z, .dmg
+ ld hl, IncGradGBPalTable_00
+ ld b, 4
+ jr RotatePalettesRight
+
+.dmg
+ ld hl, IncGradGBPalTable_08
+ ld b, 4
+ jr RotatePalettesRight
+; 4b6
+
+RotateThreePalettesRight:: ; 4b6
+ ld a, [hCGB]
+ and a
+ jr z, .dmg
+ ld hl, IncGradGBPalTable_05
+ ld b, 3
+ jr RotatePalettesRight
+
+.dmg
+ ld hl, IncGradGBPalTable_13
+ ld b, 3
+RotatePalettesRight:: ; 4c7
+; Rotate palettes to the right and fill with loaded colors from the left
+; If we're already at the leftmost color, fill with the leftmost color
+ push de
+ ld a, [hli]
+ call DmgToCgbBGPals
+ ld a, [hli]
+ ld e, a
+ ld a, [hli]
+ ld d, a
+ call DmgToCgbObjPals
+ ld c, 8
+ call DelayFrames
+ pop de
+ dec b
+ jr nz, RotatePalettesRight
+ ret
+; 4dd
+
+RotateFourPalettesLeft:: ; 4dd
+ ld a, [hCGB]
+ and a
+ jr z, .dmg
+ ld hl, IncGradGBPalTable_04 - 1
+ ld b, 4
+ jr RotatePalettesLeft
+
+.dmg
+ ld hl, IncGradGBPalTable_12 - 1
+ ld b, 4
+ jr RotatePalettesLeft
+; 4f0
+
+RotateThreePalettesLeft:: ; 4f0
+ ld a, [hCGB]
+ and a
+ jr z, .dmg
+ ld hl, IncGradGBPalTable_07 - 1
+ ld b, 3
+ jr RotatePalettesLeft
+
+.dmg
+ ld hl, IncGradGBPalTable_15 - 1
+ ld b, 3
+RotatePalettesLeft:: ; 501
+; Rotate palettes to the left and fill with loaded colors from the right
+; If we're already at the rightmost color, fill with the rightmost color
+ push de
+ ld a, [hld]
+ ld d, a
+ ld a, [hld]
+ ld e, a
+ call DmgToCgbObjPals
+ ld a, [hld]
+ call DmgToCgbBGPals
+ ld c, 8
+ call DelayFrames
+ pop de
+ dec b
+ jr nz, RotatePalettesLeft
+ ret
+; 517
+
+
+; 517
+IncGradGBPalTable_00:: db %11111111, %11111111, %11111111
+IncGradGBPalTable_01:: db %11111110, %11111110, %11111110
+IncGradGBPalTable_02:: db %11111001, %11111001, %11111001
+IncGradGBPalTable_03:: db %11100100, %11100100, %11100100
+
+IncGradGBPalTable_04:: db %11100100, %11100100, %11100100
+IncGradGBPalTable_05:: db %10010000, %10010000, %10010000
+IncGradGBPalTable_06:: db %01000000, %01000000, %01000000
+
+IncGradGBPalTable_07:: db %00000000, %00000000, %00000000
+; bgp obp1 obp2
+IncGradGBPalTable_08:: db %11111111, %11111111, %11111111
+IncGradGBPalTable_09:: db %11111110, %11111110, %11111000
+IncGradGBPalTable_10:: db %11111001, %11100100, %11100100
+IncGradGBPalTable_11:: db %11100100, %11010000, %11100000
+
+IncGradGBPalTable_12:: db %11100100, %11010000, %11100000
+IncGradGBPalTable_13:: db %10010000, %10000000, %10010000
+IncGradGBPalTable_14:: db %01000000, %01000000, %01000000
+
+IncGradGBPalTable_15:: db %00000000, %00000000, %00000000
+; 547
diff --git a/home/farcall.asm b/home/farcall.asm
new file mode 100644
index 00000000..7c9fe105
--- /dev/null
+++ b/home/farcall.asm
@@ -0,0 +1,54 @@
+FarCall_de:: ; 2d54
+; Call a:de.
+; Preserves other registers.
+
+ ld [hBuffer], a
+ ld a, [hROMBank]
+ push af
+ ld a, [hBuffer]
+ rst Bankswitch
+ call .de
+ jr ReturnFarCall
+
+.de
+ push de
+ ret
+; 2d63
+
+
+FarCall_hl:: ; 2d63
+; Call a:hl.
+; Preserves other registers.
+
+ ld [hBuffer], a
+ ld a, [hROMBank]
+ push af
+ ld a, [hBuffer]
+ rst Bankswitch
+ call FarJump_hl
+; 2d6e
+
+ReturnFarCall:: ; 2d6e
+; We want to retain the contents of f.
+; To do this, we can pop to bc instead of af.
+
+ ld a, b
+ ld [wFarCallBCBuffer], a
+ ld a, c
+ ld [wFarCallBCBuffer + 1], a
+
+; Restore the working bank.
+ pop bc
+ ld a, b
+ rst Bankswitch
+
+ ld a, [wFarCallBCBuffer]
+ ld b, a
+ ld a, [wFarCallBCBuffer + 1]
+ ld c, a
+ ret
+; 2d82
+
+FarJump_hl:: ; 2d82
+ jp [hl]
+; 2d83
diff --git a/home/flag.asm b/home/flag.asm
new file mode 100644
index 00000000..099f4bf0
--- /dev/null
+++ b/home/flag.asm
@@ -0,0 +1,112 @@
+ResetMapBufferEventFlags:: ; 2e50
+ xor a
+ ld hl, EventFlags
+ ld [hli], a
+ ret
+; 2e56
+
+ResetBikeFlags:: ; 2e56
+ xor a
+ ld hl, BikeFlags
+ ld [hli], a
+ ld [hl], a
+ ret
+; 2e5d
+
+ResetFlashIfOutOfCave:: ; 2e5d
+ ld a, [wPermission]
+ cp $2
+ jr z, .asm_2e69
+ cp $1
+ jr z, .asm_2e69
+ ret
+
+.asm_2e69
+ ld hl, StatusFlags
+ res 2, [hl]
+ ret
+; 2e6f
+
+
+EventFlagAction:: ; 0x2e6f
+ ld hl, EventFlags
+ call FlagAction
+ ret
+
+FlagAction:: ; 0x2e76
+; Perform action b on bit de in flag array hl.
+
+; inputs:
+; b: function
+; 0 clear bit
+; 1 set bit
+; 2 check bit
+; de: bit number
+; hl: index within bit table
+
+ ; get index within the byte
+ ld a, e
+ and 7
+
+ ; shift de right by three bits (get the index within memory)
+ srl d
+ rr e
+ srl d
+ rr e
+ srl d
+ rr e
+ add hl, de
+
+ ; implement a decoder
+ ld c, 1
+ rrca
+ jr nc, .one
+ rlc c
+.one
+ rrca
+ jr nc, .two
+ rlc c
+ rlc c
+.two
+ rrca
+ jr nc, .three
+ swap c
+.three
+
+ ; check b's value: 0, 1, 2
+ ld a, b
+ cp 1
+ jr c, .clearbit ; 0
+ jr z, .setbit ; 1
+
+ ; check bit
+ ld a, [hl]
+ and c
+ ld c, a
+ ret
+
+.setbit
+ ; set bit
+ ld a, [hl]
+ or c
+ ld [hl], a
+ ret
+
+.clearbit
+ ; clear bit
+ ld a, c
+ cpl
+ and [hl]
+ ld [hl], a
+ ret
+; 0x2ead
+
+
+CheckReceivedDex:: ; 2ead
+ ld de, ENGINE_POKEDEX
+ ld b, CHECK_FLAG
+ callba EngineFlagAction
+ ld a, c
+ and a
+ ret
+; 2ebb
diff --git a/home/game_time.asm b/home/game_time.asm
new file mode 100644
index 00000000..54cad89c
--- /dev/null
+++ b/home/game_time.asm
@@ -0,0 +1,131 @@
+ResetGameTime:: ; 208a
+ xor a
+ ld [GameTimeCap], a
+ ld [GameTimeHours], a
+ ld [GameTimeHours + 1], a
+ ld [GameTimeMinutes], a
+ ld [GameTimeSeconds], a
+ ld [GameTimeFrames], a
+ ret
+; 209e
+
+
+GameTimer:: ; 209e
+
+ nop
+
+ ld a, [rSVBK]
+ push af
+ ld a, 1
+ ld [rSVBK], a
+
+ call UpdateGameTimer
+
+ pop af
+ ld [rSVBK], a
+ ret
+; 20ad
+
+
+UpdateGameTimer:: ; 20ad
+; Increment the game timer by one frame.
+; The game timer is capped at 999:59:59.00.
+
+
+; Don't update if game logic is paused.
+ ld a, [wc2cd]
+ and a
+ ret nz
+
+; Is the timer paused?
+ ld hl, GameTimerPause
+ bit 0, [hl]
+ ret z
+
+; Is the timer already capped?
+ ld hl, GameTimeCap
+ bit 0, [hl]
+ ret nz
+
+
+; +1 frame
+ ld hl, GameTimeFrames
+ ld a, [hl]
+ inc a
+
+ cp 60 ; frames/second
+ jr nc, .second
+
+ ld [hl], a
+ ret
+
+
+.second
+ xor a
+ ld [hl], a
+
+; +1 second
+ ld hl, GameTimeSeconds
+ ld a, [hl]
+ inc a
+
+ cp 60 ; seconds/minute
+ jr nc, .minute
+
+ ld [hl], a
+ ret
+
+
+.minute
+ xor a
+ ld [hl], a
+
+; +1 minute
+ ld hl, GameTimeMinutes
+ ld a, [hl]
+ inc a
+
+ cp 60 ; minutes/hour
+ jr nc, .hour
+
+ ld [hl], a
+ ret
+
+
+.hour
+ xor a
+ ld [hl], a
+
+; +1 hour
+ ld a, [GameTimeHours]
+ ld h, a
+ ld a, [GameTimeHours + 1]
+ ld l, a
+ inc hl
+
+
+; Cap the timer after 1000 hours.
+ ld a, h
+ cp 1000 / $100
+ jr c, .ok
+
+ ld a, l
+ cp 1000 % $100
+ jr c, .ok
+
+ ld hl, GameTimeCap
+ set 0, [hl]
+
+ ld a, 59 ; 999:59:59.00
+ ld [GameTimeMinutes], a
+ ld [GameTimeSeconds], a
+ ret
+
+
+.ok
+ ld a, h
+ ld [GameTimeHours], a
+ ld a, l
+ ld [GameTimeHours + 1], a
+ ret
+; 210f
diff --git a/home/handshake.asm b/home/handshake.asm
new file mode 100644
index 00000000..e53e78a5
--- /dev/null
+++ b/home/handshake.asm
@@ -0,0 +1,50 @@
+PrinterReceive:: ; 2057
+ ld a, [hROMBank]
+ push af
+ ld a, BANK(_PrinterReceive)
+ rst Bankswitch
+
+ call _PrinterReceive
+ pop af
+ rst Bankswitch
+
+ ret
+; 2063
+
+AskSerial:: ; 2063
+; send out a handshake while serial int is off
+ ld a, [wc2d4]
+ bit 0, a
+ ret z
+
+ ld a, [wc2d5]
+ and a
+ ret nz
+
+; once every 6 frames
+ ld hl, wca8a
+ inc [hl]
+ ld a, [hl]
+ cp 6
+ ret c
+
+ xor a
+ ld [hl], a
+
+ ld a, $c
+ ld [wc2d5], a
+
+; handshake
+ ld a, $88
+ ld [rSB], a
+
+; switch to internal clock
+ ld a, %00000001
+ ld [rSC], a
+
+; start transfer
+ ld a, %10000001
+ ld [rSC], a
+
+ ret
+; 208a
diff --git a/home/init.asm b/home/init.asm
new file mode 100644
index 00000000..dacc5ff7
--- /dev/null
+++ b/home/init.asm
@@ -0,0 +1,222 @@
+Reset:: ; 150
+ di
+ call MapSetup_Sound_Off
+ xor a
+ ld [hMapAnims], a
+ call ClearPalettes
+ xor a
+ ld [rIF], a
+ ld a, 1 ; VBlank int
+ ld [rIE], a
+ ei
+
+ ld hl, wcfbe
+ set 7, [hl]
+
+ ld c, 32
+ call DelayFrames
+
+ jr Init
+; 16e
+
+
+_Start:: ; 16e
+ cp $11
+ jr z, .cgb
+ xor a
+ jr .load
+
+.cgb
+ ld a, $1
+
+.load
+ ld [hCGB], a
+ ld a, $1
+ ld [hFFEA], a
+; 17d
+
+
+Init:: ; 17d
+
+ di
+
+ xor a
+ ld [rIF], a
+ ld [rIE], a
+ ld [rRP], a
+ ld [rSCX], a
+ ld [rSCY], a
+ ld [rSB], a
+ ld [rSC], a
+ ld [rWX], a
+ ld [rWY], a
+ ld [rBGP], a
+ ld [rOBP0], a
+ ld [rOBP1], a
+ ld [rTMA], a
+ ld [rTAC], a
+ ld [$d000], a
+
+ ld a, %100 ; Start timer at 4096Hz
+ ld [rTAC], a
+
+.wait
+ ld a, [rLY]
+ cp 145
+ jr nz, .wait
+
+ xor a
+ ld [rLCDC], a
+
+; Clear WRAM bank 0
+ ld hl, wc000
+ ld bc, wd000 - wc000
+.ByteFill
+ ld [hl], 0
+ inc hl
+ dec bc
+ ld a, b
+ or c
+ jr nz, .ByteFill
+
+ ld sp, Stack
+
+; Clear HRAM
+ ld a, [hCGB]
+ push af
+ ld a, [hFFEA]
+ push af
+ xor a
+ ld hl, HRAM_START
+ ld bc, HRAM_END - HRAM_START
+ call ByteFill
+ pop af
+ ld [hFFEA], a
+ pop af
+ ld [hCGB], a
+
+ call ClearWRAM
+ ld a, 1
+ ld [rSVBK], a
+ call ClearVRAM
+ call ClearSprites
+ call Function270
+
+
+ ld a, BANK(LoadPushOAM)
+ rst Bankswitch
+
+ call LoadPushOAM
+
+ xor a
+ ld [hMapAnims], a
+ ld [hSCX], a
+ ld [hSCY], a
+ ld [rJOYP], a
+
+ ld a, $8 ; HBlank int enable
+ ld [rSTAT], a
+
+ ld a, $90
+ ld [hWY], a
+ ld [rWY], a
+
+ ld a, 7
+ ld [hWX], a
+ ld [rWX], a
+
+ ld a, %11100011
+ ; LCD on
+ ; Win tilemap 1
+ ; Win on
+ ; BG/Win tiledata 0
+ ; BG Tilemap 0
+ ; OBJ 8x8
+ ; OBJ on
+ ; BG on
+ ld [rLCDC], a
+
+ ld a, -1
+ ld [hLinkPlayerNumber], a
+
+ callba Function9890
+
+ ld a, VBGMap1 / $100
+ ld [hBGMapAddress + 1], a
+ xor a ; VBGMap1 % $100
+ ld [hBGMapAddress], a
+
+ callba StartClock
+
+ xor a
+ ld [MBC3LatchClock], a
+ ld [MBC3SRamEnable], a
+
+ ld a, [hCGB]
+ and a
+ jr z, .asm_22b
+ call NormalSpeed
+.asm_22b
+
+ xor a
+ ld [rIF], a
+ ld a, %1111 ; VBlank, LCDStat, Timer, Serial interrupts
+ ld [rIE], a
+ ei
+
+ call DelayFrame
+
+ predef Function9853
+
+ call MapSetup_Sound_Off
+ xor a
+ ld [wMapMusic], a
+ jp GameInit
+; 245
+
+
+ClearVRAM:: ; 245
+; Wipe VRAM banks 0 and 1
+
+ ld a, 1
+ ld [rVBK], a
+ call .clear
+
+ xor a
+ ld [rVBK], a
+.clear
+ ld hl, VTiles0
+ ld bc, $2000
+ xor a
+ call ByteFill
+ ret
+; 25a
+
+ClearWRAM:: ; 25a
+; Wipe swappable WRAM banks (1-7)
+
+ ld a, 1
+.asm_25c
+ push af
+ ld [rSVBK], a
+ xor a
+ ld hl, $d000
+ ld bc, $1000
+ call ByteFill
+ pop af
+ inc a
+ cp 8
+ jr nc, .asm_25c
+ ret
+; 270
+
+Function270:: ; 270
+ ld a, $0
+ call GetSRAMBank
+ ld hl, $a000
+ ld bc, $0020
+ xor a
+ call ByteFill
+ call CloseSRAM
+ ret
+; 283
diff --git a/home/item.asm b/home/item.asm
new file mode 100644
index 00000000..92d74c35
--- /dev/null
+++ b/home/item.asm
@@ -0,0 +1,75 @@
+DoItemEffect:: ; 2f3f
+ callba _DoItemEffect
+ ret
+; 2f46
+
+CheckTossableItem:: ; 2f46
+ push hl
+ push de
+ push bc
+ callba _CheckTossableItem
+ pop bc
+ pop de
+ pop hl
+ ret
+; 2f53
+
+TossItem:: ; 2f53
+ push hl
+ push de
+ push bc
+ ld a, [hROMBank]
+ push af
+ ld a, BANK(_TossItem)
+ rst Bankswitch
+
+ call _TossItem
+
+ pop bc
+ ld a, b
+ rst Bankswitch
+ pop bc
+ pop de
+ pop hl
+ ret
+; 2f66
+
+ReceiveItem:: ; 2f66
+ push bc
+ ld a, [hROMBank]
+ push af
+ ld a, BANK(_ReceiveItem)
+ rst Bankswitch
+ push hl
+ push de
+
+ call _ReceiveItem
+
+ pop de
+ pop hl
+ pop bc
+ ld a, b
+ rst Bankswitch
+ pop bc
+ ret
+; 2f79
+
+CheckItem:: ; 2f79
+ push hl
+ push de
+ push bc
+ ld a, [hROMBank]
+ push af
+ ld a, BANK(_CheckItem)
+ rst Bankswitch
+
+ call _CheckItem
+
+ pop bc
+ ld a, b
+ rst Bankswitch
+ pop bc
+ pop de
+ pop hl
+ ret
+; 2f8c
diff --git a/home/joypad.asm b/home/joypad.asm
new file mode 100644
index 00000000..390166be
--- /dev/null
+++ b/home/joypad.asm
@@ -0,0 +1,496 @@
+JoypadInt:: ; 92e
+; Replaced by Joypad, called from VBlank instead of the useless
+; joypad interrupt.
+
+; This is a placeholder in case the interrupt is somehow enabled.
+ reti
+; 92f
+
+ClearJoypad:: ; 92f
+ xor a
+; Pressed this frame (delta)
+ ld [hJoyPressed], a
+; Currently pressed
+ ld [hJoyDown], a
+ ret
+; 935
+
+Joypad:: ; 935
+; Read the joypad register and translate it to something more
+; workable for use in-game. There are 8 buttons, so we can use
+; one byte to contain all player input.
+
+; Updates:
+
+; hJoypadReleased: released this frame (delta)
+; hJoypadPressed: pressed this frame (delta)
+; hJoypadDown: currently pressed
+; hJoypadSum: pressed so far
+
+; Any of these three bits can be used to disable input.
+ ld a, [wcfbe]
+ and %11010000
+ ret nz
+
+; If we're saving, input is disabled.
+ ld a, [wc2cd]
+ and a
+ ret nz
+
+; We can only get four inputs at a time.
+; We take d-pad first for no particular reason.
+ ld a, R_DPAD
+ ld [rJOYP], a
+; Read twice to give the request time to take.
+rept 2
+ ld a, [rJOYP]
+endr
+
+; The Joypad register output is in the lo nybble (inversed).
+; We make the hi nybble of our new container d-pad input.
+ cpl
+ and $f
+ swap a
+
+; We'll keep this in b for now.
+ ld b, a
+
+; Buttons make 8 total inputs (A, B, Select, Start).
+; We can fit this into one byte.
+ ld a, R_BUTTONS
+ ld [rJOYP], a
+; Wait for input to stabilize.
+rept 6
+ ld a, [rJOYP]
+endr
+; Buttons take the lo nybble.
+ cpl
+ and $f
+ or b
+ ld b, a
+
+; Reset the joypad register since we're done with it.
+ ld a, $30
+ ld [rJOYP], a
+
+; To get the delta we xor the last frame's input with the new one.
+ ld a, [hJoypadDown] ; last frame
+ ld e, a
+ xor b
+ ld d, a
+; Released this frame:
+ and e
+ ld [hJoypadReleased], a
+; Pressed this frame:
+ ld a, d
+ and b
+ ld [hJoypadPressed], a
+
+; Add any new presses to the list of collective presses:
+ ld c, a
+ ld a, [hJoypadSum]
+ or c
+ ld [hJoypadSum], a
+
+; Currently pressed:
+ ld a, b
+ ld [hJoypadDown], a
+
+; Now that we have the input, we can do stuff with it.
+
+; For example, soft reset:
+ and A_BUTTON | B_BUTTON | SELECT | START
+ cp A_BUTTON | B_BUTTON | SELECT | START
+ jp z, Reset
+
+ ret
+; 984
+
+
+GetJoypad:: ; 984
+; Update mirror joypad input from hJoypadDown (real input)
+
+; hJoyReleased: released this frame (delta)
+; hJoyPressed: pressed this frame (delta)
+; hJoyDown: currently pressed
+
+; bit 0 A
+; 1 B
+; 2 SELECT
+; 3 START
+; 4 RIGHT
+; 5 LEFT
+; 6 UP
+; 7 DOWN
+
+ push af
+ push hl
+ push de
+ push bc
+
+; The player input can be automated using an input stream.
+; See more below.
+ ld a, [InputType]
+ cp a, AUTO_INPUT
+ jr z, .auto
+
+; To get deltas, take this and last frame's input.
+ ld a, [hJoypadDown] ; real input
+ ld b, a
+ ld a, [hJoyDown] ; last frame mirror
+ ld e, a
+
+; Released this frame:
+ xor b
+ ld d, a
+ and e
+ ld [hJoyReleased], a
+
+; Pressed this frame:
+ ld a, d
+ and b
+ ld [hJoyPressed], a
+
+; It looks like the collective presses got commented out here.
+ ld c, a
+
+; Currently pressed:
+ ld a, b
+ ld [hJoyDown], a ; frame input
+
+.quit
+ pop bc
+ pop de
+ pop hl
+ pop af
+ ret
+
+.auto
+; Use a predetermined input stream (used in the catching tutorial).
+
+; Stream format: [input][duration]
+; A value of $ff will immediately end the stream.
+
+; Read from the input stream.
+ ld a, [hROMBank]
+ push af
+ ld a, [AutoInputBank]
+ rst Bankswitch
+
+ ld hl, AutoInputAddress
+ ld a, [hli]
+ ld h, [hl]
+ ld l, a
+
+; We only update when the input duration has expired.
+ ld a, [AutoInputLength]
+ and a
+ jr z, .updateauto
+
+; Until then, don't change anything.
+ dec a
+ ld [AutoInputLength], a
+ pop af
+ rst Bankswitch
+ jr .quit
+
+
+.updateauto
+; An input of $ff will end the stream.
+ ld a, [hli]
+ cp a, -1
+ jr z, .stopauto
+ ld b, a
+
+; A duration of $ff will end the stream indefinitely.
+ ld a, [hli]
+ ld [AutoInputLength], a
+ cp a, -1
+ jr nz, .next
+
+; The current input is overwritten.
+rept 2
+ dec hl
+endr
+ ld b, NO_INPUT
+ jr .finishauto
+
+.next
+; On to the next input...
+ ld a, l
+ ld [AutoInputAddress], a
+ ld a, h
+ ld [AutoInputAddress+1], a
+ jr .finishauto
+
+.stopauto
+ call StopAutoInput
+ ld b, NO_INPUT
+
+.finishauto
+ pop af
+ rst Bankswitch
+ ld a, b
+ ld [hJoyPressed], a ; pressed
+ ld [hJoyDown], a ; input
+ jr .quit
+; 9ee
+
+
+StartAutoInput:: ; 9ee
+; Start reading automated input stream at a:hl.
+
+ ld [AutoInputBank], a
+ ld a, l
+ ld [AutoInputAddress], a
+ ld a, h
+ ld [AutoInputAddress+1], a
+; Start reading the stream immediately.
+ xor a
+ ld [AutoInputLength], a
+; Reset input mirrors.
+ xor a
+ ld [hJoyPressed], a ; pressed this frame
+ ld [hJoyReleased], a ; released this frame
+ ld [hJoyDown], a ; currently pressed
+
+ ld a, AUTO_INPUT
+ ld [InputType], a
+ ret
+; a0a
+
+
+StopAutoInput:: ; a0a
+; Clear variables related to automated input.
+ xor a
+ ld [AutoInputBank], a
+ ld [AutoInputAddress], a
+ ld [AutoInputAddress+1], a
+ ld [AutoInputLength], a
+; Back to normal input.
+ ld [InputType], a
+ ret
+; a1b
+
+
+JoyTitleScreenInput:: ; a1b
+.loop
+
+ call DelayFrame
+
+ push bc
+ call JoyTextDelay
+ pop bc
+
+ ld a, [hJoyDown]
+ cp D_UP | SELECT | B_BUTTON
+ jr z, .keycombo
+
+ ld a, [hJoyLast]
+ and START | A_BUTTON
+ jr nz, .keycombo
+
+ dec c
+ jr nz, .loop
+
+ and a
+ ret
+
+.keycombo
+ scf
+ ret
+; a36
+
+
+JoyWaitAorB:: ; a36
+.loop
+ call DelayFrame
+ call GetJoypad
+ ld a, [hJoyPressed]
+ and A_BUTTON | B_BUTTON
+ ret nz
+ call RTC
+ jr .loop
+; a46
+
+WaitButton:: ; a46
+ ld a, [hOAMUpdate]
+ push af
+ ld a, 1
+ ld [hOAMUpdate], a
+ call WaitBGMap
+ call JoyWaitAorB
+ pop af
+ ld [hOAMUpdate], a
+ ret
+; a57
+
+JoyTextDelay:: ; a57
+ call GetJoypad
+ ld a, [hInMenu]
+ and a
+ ld a, [hJoyPressed]
+ jr z, .ok
+ ld a, [hJoyDown]
+.ok
+ ld [hJoyLast], a
+ ld a, [hJoyPressed]
+ and a
+ jr z, .checkframedelay
+ ld a, 15
+ ld [TextDelayFrames], a
+ ret
+
+.checkframedelay
+ ld a, [TextDelayFrames]
+ and a
+ jr z, .restartframedelay
+ xor a
+ ld [hJoyLast], a
+ ret
+
+.restartframedelay
+ ld a, 5
+ ld [TextDelayFrames], a
+ ret
+; a80
+
+WaitPressAorB_BlinkCursor:: ; a80
+ ld a, [hMapObjectIndexBuffer]
+ push af
+ ld a, [hObjectStructIndexBuffer]
+ push af
+ xor a
+ ld [hMapObjectIndexBuffer], a
+ ld a, 6
+ ld [hObjectStructIndexBuffer], a
+
+.loop
+ push hl
+ hlcoord 18, 17
+ call BlinkCursor
+ pop hl
+
+ call JoyTextDelay
+ ld a, [hJoyLast]
+ and A_BUTTON | B_BUTTON
+ jr z, .loop
+
+ pop af
+ ld [hObjectStructIndexBuffer], a
+ pop af
+ ld [hMapObjectIndexBuffer], a
+ ret
+; aa5
+
+SimpleWaitPressAorB:: ; aa5
+.loop
+ call JoyTextDelay
+ ld a, [hJoyLast]
+ and A_BUTTON | B_BUTTON
+ jr z, .loop
+ ret
+; aaf
+
+ButtonSound:: ; aaf
+ ld a, [wLinkMode]
+ and a
+ jr nz, .link
+ call .wait_input
+ push de
+ ld de, SFX_READ_TEXT_2
+ call PlaySFX
+ pop de
+ ret
+
+.link
+ ld c, 65
+ jp DelayFrames
+; ac6
+
+.wait_input: ; ac6
+ ld a, [hOAMUpdate]
+ push af
+ ld a, $1
+ ld [hOAMUpdate], a
+ ld a, [InputType]
+ or a
+ jr z, .input_wait_loop
+ callba _DudeAutoInput_A
+
+.input_wait_loop
+ call .blink_cursor
+ call JoyTextDelay
+ ld a, [hJoyPressed]
+ and A_BUTTON | B_BUTTON
+ jr nz, .received_input
+ call RTC
+ ld a, $1
+ ld [hBGMapMode], a
+ call DelayFrame
+ jr .input_wait_loop
+
+.received_input
+ pop af
+ ld [hOAMUpdate], a
+ ret
+; af5
+
+.blink_cursor: ; af5
+ ld a, [hVBlankCounter]
+ and %00010000 ; bit 4, a
+ jr z, .cursor_off
+ ld a, "▼"
+ jr .load_cursor_state
+
+.cursor_off
+ ld a, [TileMap + 17 + 17 * SCREEN_WIDTH]
+
+.load_cursor_state
+ ld [TileMap + 18 + 17 * SCREEN_WIDTH], a
+ ret
+; b06
+
+BlinkCursor:: ; b06
+ push bc
+ ld a, [hl]
+ ld b, a
+ ld a, "▼"
+ cp b
+ pop bc
+ jr nz, .place_arrow
+ ld a, [hMapObjectIndexBuffer]
+ dec a
+ ld [hMapObjectIndexBuffer], a
+ ret nz
+ ld a, [hObjectStructIndexBuffer]
+ dec a
+ ld [hObjectStructIndexBuffer], a
+ ret nz
+ ld a, "─"
+ ld [hl], a
+ ld a, -1
+ ld [hMapObjectIndexBuffer], a
+ ld a, 6
+ ld [hObjectStructIndexBuffer], a
+ ret
+
+.place_arrow
+ ld a, [hMapObjectIndexBuffer]
+ and a
+ ret z
+ dec a
+ ld [hMapObjectIndexBuffer], a
+ ret nz
+ dec a
+ ld [hMapObjectIndexBuffer], a
+ ld a, [hObjectStructIndexBuffer]
+ dec a
+ ld [hObjectStructIndexBuffer], a
+ ret nz
+ ld a, 6
+ ld [hObjectStructIndexBuffer], a
+ ld a, "▼"
+ ld [hl], a
+ ret
+; b40
diff --git a/home/lcd.asm b/home/lcd.asm
new file mode 100644
index 00000000..875043bc
--- /dev/null
+++ b/home/lcd.asm
@@ -0,0 +1,81 @@
+; LCD handling
+
+
+Function547:: ; 547
+; Unreferenced
+ ld a, [hFFC6]
+ cp rSCX - $ff00
+ ret nz
+ ld c, a
+ ld a, [LYOverrides]
+ ld [$ff00+c], a
+ ret
+; 552
+
+
+LCD:: ; 552
+ push af
+ ld a, [hFFC6]
+ and a
+ jr z, .done
+
+; At this point it's assumed we're in WRAM bank 5!
+ push bc
+ ld a, [rLY]
+ ld c, a
+ ld b, LYOverrides >> 8
+ ld a, [bc]
+ ld b, a
+ ld a, [hFFC6]
+ ld c, a
+ ld a, b
+ ld [$ff00+c], a
+ pop bc
+
+.done
+ pop af
+ reti
+; 568
+
+
+DisableLCD:: ; 568
+; Turn the LCD off
+
+; Don't need to do anything if the LCD is already off
+ ld a, [rLCDC]
+ bit 7, a ; lcd enable
+ ret z
+
+ xor a
+ ld [rIF], a
+ ld a, [rIE]
+ ld b, a
+
+; Disable VBlank
+ res 0, a ; vblank
+ ld [rIE], a
+
+.wait
+; Wait until VBlank would normally happen
+ ld a, [rLY]
+ cp 145
+ jr nz, .wait
+
+ ld a, [rLCDC]
+ and %01111111 ; lcd enable off
+ ld [rLCDC], a
+
+ xor a
+ ld [rIF], a
+ ld a, b
+ ld [rIE], a
+ ret
+; 58a
+
+
+EnableLCD:: ; 58a
+ ld a, [rLCDC]
+ set 7, a ; lcd enable
+ ld [rLCDC], a
+ ret
+; 591
diff --git a/home/map.asm b/home/map.asm
new file mode 100644
index 00000000..c51f9c48
--- /dev/null
+++ b/home/map.asm
@@ -0,0 +1,2385 @@
+; Functions dealing with rendering and interacting with maps.
+
+Clearwc7e8:: ; 210f
+ ld hl, wc7e8
+ ld bc, 24
+ ld a, $0
+ call ByteFill
+ ret
+; 211b
+
+CheckTriggers:: ; 211b
+; Checks wCurrentMapTriggerPointer. If it's empty, returns -1 in a. Otherwise, returns the active trigger ID in a.
+ push hl
+ ld hl, wCurrentMapTriggerPointer
+ ld a, [hli]
+ ld h, [hl]
+ ld l, a
+ or h
+ ld a, [hl]
+ jr nz, .triggerexists
+ ld a, -1
+
+.triggerexists
+ pop hl
+ ret
+; 212a
+
+GetCurrentMapTrigger:: ; 212a
+; Grabs the wram map trigger pointer for the current map and loads it into wCurrentMapTriggerPointer.
+; If there are no triggers, both bytes of wCurrentMapTriggerPointer are wiped clean.
+; Copy the current map group and number into bc. This is needed for GetMapTrigger.
+ ld a, [MapGroup]
+ ld b, a
+ ld a, [MapNumber]
+ ld c, a
+; Blank out wCurrentMapTriggerPointer; this is the default scenario.
+ xor a
+ ld [wCurrentMapTriggerPointer], a
+ ld [wCurrentMapTriggerPointer + 1], a
+ call GetMapTrigger
+ ret c ; The map is not in the trigger table
+; Load the trigger table pointer from de into wCurrentMapTriggerPointer
+ ld a, e
+ ld [wCurrentMapTriggerPointer], a
+ ld a, d
+ ld [wCurrentMapTriggerPointer + 1], a
+ xor a
+ ret
+; 2147
+
+GetMapTrigger:: ; 2147
+; Searches the trigger table for the map group and number loaded in bc, and returns the wram pointer in de.
+; If the map is not in the trigger table, returns carry.
+ push bc
+ ld a, [hROMBank]
+ push af
+ ld a, BANK(MapTriggers)
+ rst Bankswitch
+
+ ld hl, MapTriggers
+.loop
+ push hl
+ ld a, [hli] ; map group, or terminator
+ cp -1
+ jr z, .end ; the current map is not in the trigger table
+ cp b
+ jr nz, .next ; map group did not match
+ ld a, [hli] ; map number
+ cp c
+ jr nz, .next ; map number did not match
+ jr .found ; we found our map
+
+.next
+ pop hl
+ ld de, 4 ; size of an entry in the trigger table
+ add hl, de
+ jr .loop
+
+.end
+ scf
+ jr .done
+
+.found
+ ld e, [hl]
+ inc hl
+ ld d, [hl]
+
+.done
+ pop hl
+ pop bc
+ ld a, b
+ rst Bankswitch
+
+ pop bc
+ ret
+; 2173
+
+OverworldTextModeSwitch:: ; 2173
+ call LoadMapPart
+ call FarCallSwapTextboxPalettes
+ ret
+; 217a
+
+LoadMapPart:: ; 217a
+ ld a, [hROMBank]
+ push af
+
+ ld a, [TilesetBlocksBank]
+ rst Bankswitch
+
+ call LoadMetatiles
+ ld a, $60
+ hlcoord 0, 0
+ ld bc, SCREEN_WIDTH * SCREEN_HEIGHT
+ call ByteFill
+
+ ld a, BANK(_LoadMapPart)
+ rst Bankswitch
+ call _LoadMapPart
+
+ pop af
+ rst Bankswitch
+ ret
+; 2198
+
+LoadMetatiles:: ; 2198
+ ; de <- wOverworldMapAnchor
+ ld a, [wOverworldMapAnchor]
+ ld e, a
+ ld a, [wOverworldMapAnchor + 1]
+ ld d, a
+ ld hl, wMisc
+ ld b, WMISC_HEIGHT / 4 ; 5
+
+.row
+ push de
+ push hl
+ ld c, WMISC_WIDTH / 4 ; 6
+
+.col
+ push de
+ push hl
+ ; Load the current map block.
+ ; If the current map block is a border block, load the border block.
+ ld a, [de]
+ and a
+ jr nz, .ok
+ ld a, [MapBorderBlock]
+
+.ok
+ ; Load the current wMisc address into de.
+ ld e, l
+ ld d, h
+ ; Set hl to the address of the current metatile data ([TilesetBlocksAddress] + (a) tiles).
+ add a
+ ld l, a
+ ld h, 0
+rept 3
+ add hl, hl
+endr
+ ld a, [TilesetBlocksAddress]
+ add l
+ ld l, a
+ ld a, [TilesetBlocksAddress + 1]
+ adc h
+ ld h, a
+
+ ; copy the 4x4 metatile
+rept 3
+rept 4
+ ld a, [hli]
+ ld [de], a
+ inc de
+endr
+ ld a, e
+ add WMISC_WIDTH - 4
+ ld e, a
+ jr nc, .next\@
+ inc d
+.next\@
+endr
+rept 4
+ ld a, [hli]
+ ld [de], a
+ inc de
+endr
+ ; Next metatile
+ pop hl
+ ld de, 4
+ add hl, de
+ pop de
+ inc de
+ dec c
+ jp nz, .col
+ ; Next metarow
+ pop hl
+ ld de, WMISC_WIDTH * 4
+ add hl, de
+ pop de
+ ld a, [MapWidth]
+ add 6
+ add e
+ ld e, a
+ jr nc, .ok2
+ inc d
+.ok2
+ dec b
+ jp nz, .row
+ ret
+; 222a
+
+ReturnToMapFromSubmenu:: ; 222a
+ ld a, MAPSETUP_SUBMENU
+ ld [hMapEntryMethod], a
+ callba RunMapSetupScript
+ xor a
+ ld [hMapEntryMethod], a
+ ret
+; 2238
+
+CheckWarpTile:: ; 2238
+ call GetDestinationWarpNumber
+ ret nc
+
+ push bc
+ callba CheckDirectionalWarp
+ pop bc
+ ret nc
+
+ call CopyWarpData
+ scf
+ ret
+; 224a
+
+WarpCheck:: ; 224a
+ call GetDestinationWarpNumber
+ ret nc
+ call CopyWarpData
+ ret
+; 2252
+
+GetDestinationWarpNumber:: ; 2252
+ callba CheckWarpCollision
+ ret nc
+
+ ld a, [hROMBank]
+ push af
+
+ call SwitchToMapScriptHeaderBank
+ call .GetDestinationWarpNumber
+
+ pop de
+ ld a, d
+ rst Bankswitch
+ ret
+; 2266
+
+.GetDestinationWarpNumber ; 2266
+ ld a, [PlayerStandingMapY]
+ sub $4
+ ld e, a
+ ld a, [PlayerStandingMapX]
+ sub $4
+ ld d, a
+ ld a, [wCurrMapWarpCount]
+ and a
+ ret z
+
+ ld c, a
+ ld hl, wCurrMapWarpHeaderPointer
+ ld a, [hli]
+ ld h, [hl]
+ ld l, a
+.loop
+ push hl
+ ld a, [hli]
+ cp e
+ jr nz, .next
+ ld a, [hli]
+ cp d
+ jr nz, .next
+ jr .found_warp
+
+.next
+ pop hl
+ ld a, 5
+ add l
+ ld l, a
+ jr nc, .okay
+ inc h
+
+.okay
+ dec c
+ jr nz, .loop
+ xor a
+ ret
+
+.found_warp
+ pop hl
+ call .IncreaseHLTwice
+ ret nc ; never encountered
+
+ ld a, [wCurrMapWarpCount]
+ inc a
+ sub c
+ ld c, a
+ scf
+ ret
+
+.IncreaseHLTwice
+ inc hl
+ inc hl
+ scf
+ ret
+; 22a7
+
+CopyWarpData:: ; 22a7
+ ld a, [hROMBank]
+ push af
+
+ call SwitchToMapScriptHeaderBank
+ call .CopyWarpData
+
+ pop af
+ rst Bankswitch
+ scf
+ ret
+; 22b4
+
+.CopyWarpData ; 22b4
+ push bc
+ ld hl, wCurrMapWarpHeaderPointer
+ ld a, [hli]
+ ld h, [hl]
+ ld l, a
+ ld a, c
+ dec a
+ ld bc, 5 ; warp size
+ call AddNTimes
+ ld bc, 2 ; warp number
+ add hl, bc
+ ld a, [hli]
+ cp $ff
+ jr nz, .skip
+ ld hl, BackupWarpNumber
+ ld a, [hli]
+
+.skip
+ pop bc
+ ld [wNextWarp], a
+ ld a, [hli]
+ ld [wNextMapGroup], a
+ ld a, [hli]
+ ld [wNextMapNumber], a
+
+ ld a, c
+ ld [wPrevWarp], a
+ ld a, [MapGroup]
+ ld [wPrevMapGroup], a
+ ld a, [MapNumber]
+ ld [wPrevMapNumber], a
+ scf
+ ret
+; 22ee
+
+CheckOutdoorMap:: ; 22ee
+ cp ROUTE
+ ret z
+ cp TOWN
+ ret
+; 22f4
+
+CheckIndoorMap:: ; 22f4
+ cp INDOOR
+ ret z
+ cp CAVE
+ ret z
+ cp DUNGEON
+ ret z
+ cp GATE
+ ret
+; 2300
+
+; XXX
+ cp INDOOR
+ ret z
+ cp GATE
+ ret z
+ cp PERM_5
+ ret
+; 2309
+
+LoadMapAttributes:: ; 2309
+ call CopyMapHeaders
+ call SwitchToMapScriptHeaderBank
+ call ReadMapScripts
+ xor a
+ call ReadMapEventHeader
+ ret
+; 2317
+
+LoadMapAttributes_SkipPeople:: ; 2317
+ call CopyMapHeaders
+ call SwitchToMapScriptHeaderBank
+ call ReadMapScripts
+ ld a, $1
+ call ReadMapEventHeader
+ ret
+; 2326
+
+CopyMapHeaders:: ; 2326
+ call PartiallyCopyMapHeader
+ call SwitchToMapBank
+ call GetSecondaryMapHeaderPointer
+ call CopySecondMapHeader
+ call GetMapConnections
+ ret
+; 2336
+
+ReadMapEventHeader:: ; 2336
+ push af
+ ld hl, MapEventHeaderPointer
+ ld a, [hli]
+ ld h, [hl]
+ ld l, a
+ inc hl
+ inc hl
+ call ReadWarps
+ call ReadCoordEvents
+ call ReadSignposts
+
+ pop af
+ and a
+ ret nz
+
+ call ReadObjectEvents
+ ret
+; 234f
+
+ReadMapScripts:: ; 234f
+ ld hl, MapScriptHeaderPointer
+ ld a, [hli]
+ ld h, [hl]
+ ld l, a
+ call ReadMapTriggers
+ call ReadMapCallbacks
+ ret
+; 235c
+
+CopySecondMapHeader:: ; 235c
+ ld de, MapHeader
+ ld c, 12 ; size of the second map header
+.loop
+ ld a, [hli]
+ ld [de], a
+ inc de
+ dec c
+ jr nz, .loop
+ ret
+; 2368
+
+GetMapConnections:: ; 2368
+ ld a, $ff
+ ld [NorthConnectedMapGroup], a
+ ld [SouthConnectedMapGroup], a
+ ld [WestConnectedMapGroup], a
+ ld [EastConnectedMapGroup], a
+
+ ld a, [MapConnections]
+ ld b, a
+
+ bit NORTH_F, b
+ jr z, .no_north
+ ld de, NorthMapConnection
+ call GetMapConnection
+.no_north
+
+ bit SOUTH_F, b
+ jr z, .no_south
+ ld de, SouthMapConnection
+ call GetMapConnection
+.no_south
+
+ bit WEST_F, b
+ jr z, .no_west
+ ld de, WestMapConnection
+ call GetMapConnection
+.no_west
+
+ bit EAST_F, b
+ jr z, .no_east
+ ld de, EastMapConnection
+ call GetMapConnection
+.no_east
+
+ ret
+; 23a3
+
+GetMapConnection:: ; 23a3
+; Load map connection struct at hl into de.
+ ld c, SouthMapConnection - NorthMapConnection
+.loop
+ ld a, [hli]
+ ld [de], a
+ inc de
+ dec c
+ jr nz, .loop
+ ret
+; 23ac
+
+ReadMapTriggers:: ; 23ac
+ ld a, [hli] ; trigger count
+ ld c, a
+ ld [wCurrMapTriggerCount], a ; current map trigger count
+ ld a, l
+ ld [wCurrMapTriggerHeaderPointer], a ; map trigger pointer
+ ld a, h
+ ld [wCurrMapTriggerHeaderPointer + 1], a
+ ld a, c
+ and a
+ ret z
+
+ ld bc, 4 ; size of a map trigger header entry
+ call AddNTimes
+ ret
+; 23c3
+
+ReadMapCallbacks:: ; 23c3
+ ld a, [hli]
+ ld c, a
+ ld [wCurrMapCallbackCount], a
+ ld a, l
+ ld [wCurrMapCallbackHeaderPointer], a
+ ld a, h
+ ld [wCurrMapCallbackHeaderPointer + 1], a
+ ld a, c
+ and a
+ ret z
+
+ ld bc, 3
+ call AddNTimes
+ ret
+; 23da
+
+ReadWarps:: ; 23da
+ ld a, [hli]
+ ld c, a
+ ld [wCurrMapWarpCount], a
+ ld a, l
+ ld [wCurrMapWarpHeaderPointer], a
+ ld a, h
+ ld [wCurrMapWarpHeaderPointer + 1], a
+ ld a, c
+ and a
+ ret z
+ ld bc, 5
+ call AddNTimes
+ ret
+; 23f1
+
+ReadCoordEvents:: ; 23f1
+ ld a, [hli]
+ ld c, a
+ ld [wCurrentMapXYTriggerCount], a
+ ld a, l
+ ld [wCurrentMapXYTriggerHeaderPointer], a
+ ld a, h
+ ld [wCurrentMapXYTriggerHeaderPointer + 1], a
+
+ ld a, c
+ and a
+ ret z
+
+ ld bc, 8
+ call AddNTimes
+ ret
+; 2408
+
+ReadSignposts:: ; 2408
+ ld a, [hli]
+ ld c, a
+ ld [wCurrentMapSignpostCount], a
+ ld a, l
+ ld [wCurrentMapSignpostHeaderPointer], a
+ ld a, h
+ ld [wCurrentMapSignpostHeaderPointer + 1], a
+
+ ld a, c
+ and a
+ ret z
+
+ ld bc, 5
+ call AddNTimes
+ ret
+; 241f
+
+ReadObjectEvents:: ; 241f
+ push hl
+ call ClearObjectStructs
+ pop de
+ ld hl, Map1Object
+ ld a, [de]
+ inc de
+ ld [wCurrentMapPersonEventCount], a
+ ld a, e
+ ld [wCurrentMapPersonEventHeaderPointer], a
+ ld a, d
+ ld [wCurrentMapPersonEventHeaderPointer + 1], a
+
+ ld a, [wCurrentMapPersonEventCount]
+ call CopyMapObjectHeaders
+
+; get NUM_OBJECTS - [wCurrentMapPersonEventCount]
+ ld a, [wCurrentMapPersonEventCount]
+ ld c, a
+ ld a, NUM_OBJECTS ; - 1
+ sub c
+ jr z, .skip
+ ; jr c, .skip
+
+; stupid waste of time and space
+ ld bc, 1
+ add hl, bc
+; Fill the remaining sprite IDs and y coords with 0 and -1, respectively.
+; Bleeds into wObjectMasks due to a bug. Uncomment the above subtraction
+; to fix.
+ ld bc, OBJECT_LENGTH
+.loop
+ ld [hl], 0
+ inc hl
+ ld [hl], -1
+ dec hl
+ add hl, bc
+ dec a
+ jr nz, .loop
+
+.skip
+ ld h, d
+ ld l, e
+ ret
+; 2457
+
+CopyMapObjectHeaders:: ; 2457
+ and a
+ ret z
+
+ ld c, a
+.loop
+ push bc
+ push hl
+ ld a, $ff
+ ld [hli], a
+ ld b, MAPOBJECT_E - MAPOBJECT_SPRITE
+.loop2
+ ld a, [de]
+ inc de
+ ld [hli], a
+ dec b
+ jr nz, .loop2
+
+ pop hl
+ ld bc, OBJECT_LENGTH
+ add hl, bc
+ pop bc
+ dec c
+ jr nz, .loop
+ ret
+; 2471
+
+ClearObjectStructs:: ; 2471
+ ld hl, Object1Struct
+ ld bc, OBJECT_STRUCT_LENGTH * (NUM_OBJECT_STRUCTS - 1)
+ xor a
+ call ByteFill
+
+; Just to make sure (this is rather pointless)
+ ld hl, Object1Struct
+ ld de, OBJECT_STRUCT_LENGTH
+ ld c, NUM_OBJECT_STRUCTS - 1
+ xor a
+.loop
+ ld [hl], a
+ add hl, de
+ dec c
+ jr nz, .loop
+ ret
+; 248a
+
+RestoreFacingAfterWarp:: ; 248a
+ call GetMapScriptHeaderBank
+ rst Bankswitch
+
+ ld hl, MapEventHeaderPointer
+ ld a, [hli]
+ ld h, [hl]
+ ld l, a
+rept 3
+ inc hl ; get to the warp coords
+endr
+ ld a, [WarpNumber]
+ dec a
+ ld c, a
+ ld b, 0
+ ld a, 5
+ call AddNTimes
+ ld a, [hli]
+ ld [YCoord], a
+ ld a, [hli]
+ ld [XCoord], a
+ ; destination warp number
+ ld a, [hli]
+ cp $ff
+ jr nz, .skip
+ call .backup
+
+.skip
+ callba GetCoordOfUpperLeftCorner
+ ret
+; 24ba
+
+.backup
+ ld a, [wPrevWarp]
+ ld [BackupWarpNumber], a
+ ld a, [wPrevMapGroup]
+ ld [BackupMapGroup], a
+ ld a, [wPrevMapNumber]
+ ld [BackupMapNumber], a
+ ret
+; 24cd
+
+LoadBlockData:: ; 24cd
+ ld hl, OverworldMap
+ ld bc, OverworldMapEnd - OverworldMap
+ ld a, 0
+ call ByteFill
+ call ChangeMap
+ call FillMapConnections
+ ld a, MAPCALLBACK_TILES
+ call RunMapCallback
+ ret
+; 24e4
+
+ChangeMap:: ; 24e4
+ ld a, [hROMBank]
+ push af
+
+ ld hl, OverworldMap
+ ld a, [MapWidth]
+ ld [hConnectedMapWidth], a
+ add $6
+ ld [hConnectionStripLength], a
+ ld c, a
+ ld b, 0
+rept 3
+ add hl, bc
+endr
+ ld c, 3
+ add hl, bc
+ ld a, [MapBlockDataBank]
+ rst Bankswitch
+
+ ld a, [MapBlockDataPointer]
+ ld e, a
+ ld a, [MapBlockDataPointer+1]
+ ld d, a
+ ld a, [MapHeight]
+ ld b, a
+.row
+ push hl
+ ld a, [hConnectedMapWidth]
+ ld c, a
+.col
+ ld a, [de]
+ inc de
+ ld [hli], a
+ dec c
+ jr nz, .col
+ pop hl
+ ld a, [hConnectionStripLength]
+ add l
+ ld l, a
+ jr nc, .okay
+ inc h
+.okay
+ dec b
+ jr nz, .row
+
+ pop af
+ rst Bankswitch
+ ret
+; 2524
+
+FillMapConnections:: ; 2524
+
+; North
+ ld a, [NorthConnectedMapGroup]
+ cp $ff
+ jr z, .South
+ ld b, a
+ ld a, [NorthConnectedMapNumber]
+ ld c, a
+ call GetAnyMapBlockdataBank
+
+ ld a, [NorthConnectionStripPointer]
+ ld l, a
+ ld a, [NorthConnectionStripPointer + 1]
+ ld h, a
+ ld a, [NorthConnectionStripLocation]
+ ld e, a
+ ld a, [NorthConnectionStripLocation + 1]
+ ld d, a
+ ld a, [NorthConnectionStripLength]
+ ld [hConnectionStripLength], a
+ ld a, [NorthConnectedMapWidth]
+ ld [hConnectedMapWidth], a
+ call FillNorthConnectionStrip
+
+.South
+ ld a, [SouthConnectedMapGroup]
+ cp $ff
+ jr z, .West
+ ld b, a
+ ld a, [SouthConnectedMapNumber]
+ ld c, a
+ call GetAnyMapBlockdataBank
+
+ ld a, [SouthConnectionStripPointer]
+ ld l, a
+ ld a, [SouthConnectionStripPointer + 1]
+ ld h, a
+ ld a, [SouthConnectionStripLocation]
+ ld e, a
+ ld a, [SouthConnectionStripLocation + 1]
+ ld d, a
+ ld a, [SouthConnectionStripLength]
+ ld [hConnectionStripLength], a
+ ld a, [SouthConnectedMapWidth]
+ ld [hConnectedMapWidth], a
+ call FillSouthConnectionStrip
+
+.West
+ ld a, [WestConnectedMapGroup]
+ cp $ff
+ jr z, .East
+ ld b, a
+ ld a, [WestConnectedMapNumber]
+ ld c, a
+ call GetAnyMapBlockdataBank
+
+ ld a, [WestConnectionStripPointer]
+ ld l, a
+ ld a, [WestConnectionStripPointer + 1]
+ ld h, a
+ ld a, [WestConnectionStripLocation]
+ ld e, a
+ ld a, [WestConnectionStripLocation + 1]
+ ld d, a
+ ld a, [WestConnectionStripLength]
+ ld b, a
+ ld a, [WestConnectedMapWidth]
+ ld [hConnectionStripLength], a
+ call FillWestConnectionStrip
+
+.East
+ ld a, [EastConnectedMapGroup]
+ cp $ff
+ jr z, .Done
+ ld b, a
+ ld a, [EastConnectedMapNumber]
+ ld c, a
+ call GetAnyMapBlockdataBank
+
+ ld a, [EastConnectionStripPointer]
+ ld l, a
+ ld a, [EastConnectionStripPointer + 1]
+ ld h, a
+ ld a, [EastConnectionStripLocation]
+ ld e, a
+ ld a, [EastConnectionStripLocation + 1]
+ ld d, a
+ ld a, [EastConnectionStripLength]
+ ld b, a
+ ld a, [EastConnectedMapWidth]
+ ld [hConnectionStripLength], a
+ call FillEastConnectionStrip
+
+.Done
+ ret
+; 25d3
+
+FillNorthConnectionStrip::
+FillSouthConnectionStrip:: ; 25d3
+
+ ld c, 3
+.y
+ push de
+
+ push hl
+ ld a, [hConnectionStripLength]
+ ld b, a
+.x
+ ld a, [hli]
+ ld [de], a
+ inc de
+ dec b
+ jr nz, .x
+ pop hl
+
+ ld a, [hConnectedMapWidth]
+ ld e, a
+ ld d, 0
+ add hl, de
+ pop de
+
+ ld a, [MapWidth]
+ add 6
+ add e
+ ld e, a
+ jr nc, .okay
+ inc d
+.okay
+ dec c
+ jr nz, .y
+ ret
+; 25f6
+
+FillWestConnectionStrip::
+FillEastConnectionStrip:: ; 25f6
+
+.loop
+ ld a, [MapWidth]
+ add 6
+ ld [hConnectedMapWidth], a
+
+ push de
+
+ push hl
+ ld a, [hli]
+ ld [de], a
+ inc de
+ ld a, [hli]
+ ld [de], a
+ inc de
+ ld a, [hli]
+ ld [de], a
+ inc de
+ pop hl
+
+ ld a, [hConnectionStripLength]
+ ld e, a
+ ld d, 0
+ add hl, de
+ pop de
+
+ ld a, [hConnectedMapWidth]
+ add e
+ ld e, a
+ jr nc, .okay
+ inc d
+.okay
+ dec b
+ jr nz, .loop
+ ret
+; 261b
+
+LoadMapStatus:: ; 261b
+ ld [MapStatus], a
+ ret
+; 261f
+
+CallScript:: ; 261f
+; Call a script at a:hl.
+
+ ld [ScriptBank], a
+ ld a, l
+ ld [ScriptPos], a
+ ld a, h
+ ld [ScriptPos + 1], a
+
+ ld a, PLAYEREVENT_MAPSCRIPT
+ ld [ScriptRunning], a
+
+ scf
+ ret
+; 2631
+
+CallMapScript:: ; 2631
+; Call a script at hl in the current bank if there isn't already a script running
+ ld a, [ScriptRunning]
+ and a
+ ret nz
+ call GetMapScriptHeaderBank
+ jr CallScript
+; 263b
+
+RunMapCallback:: ; 263b
+; Will run the first callback found in the map header with execution index equal to a.
+ ld b, a
+ ld a, [hROMBank]
+ push af
+ call SwitchToMapScriptHeaderBank
+ call .FindCallback
+ jr nc, .done
+
+ call GetMapScriptHeaderBank
+ ld b, a
+ ld d, h
+ ld e, l
+ call ExecuteCallbackScript
+
+.done
+ pop af
+ rst Bankswitch
+ ret
+; 2653
+
+.FindCallback: ; 2653
+ ld a, [wCurrMapCallbackCount]
+ ld c, a
+ and a
+ ret z
+ ld hl, wCurrMapCallbackHeaderPointer
+ ld a, [hli]
+ ld h, [hl]
+ ld l, a
+ or h
+ ret z
+ ld de, 3
+.loop
+ ld a, [hl]
+ cp b
+ jr z, .found
+ add hl, de
+ dec c
+ jr nz, .loop
+ xor a
+ ret
+
+.found
+ inc hl
+ ld a, [hli]
+ ld h, [hl]
+ ld l, a
+ scf
+ ret
+; 2674
+
+ExecuteCallbackScript:: ; 2674
+; Do map callback de and return to script bank b.
+ callba CallCallback
+ ld a, [ScriptMode]
+ push af
+ ld hl, ScriptFlags
+ ld a, [hl]
+ push af
+ set 1, [hl]
+ callba EnableScriptMode
+ callba ScriptEvents
+ pop af
+ ld [ScriptFlags], a
+ pop af
+ ld [ScriptMode], a
+ ret
+; 269a
+
+MapTextbox:: ; 269a
+ ld a, [hROMBank]
+ push af
+
+ ld a, b
+ rst Bankswitch
+
+ push hl
+ call SpeechTextBox
+ call Function2e31
+ ld a, 1
+ ld [hOAMUpdate], a
+ call ApplyTilemap
+ pop hl
+ call PrintTextBoxText
+ xor a
+ ld [hOAMUpdate], a
+
+ pop af
+ rst Bankswitch
+ ret
+; 26b7
+
+Call_a_de:: ; 26b7
+; Call a:de.
+
+ ld [hBuffer], a
+ ld a, [hROMBank]
+ push af
+ ld a, [hBuffer]
+ rst Bankswitch
+
+ call .de
+
+ pop af
+ rst Bankswitch
+ ret
+
+.de
+ push de
+ ret
+; 26c7
+
+GetMovementData:: ; 26c7
+; Initialize the movement data for person c at b:hl
+ ld a, [hROMBank]
+ push af
+ ld a, b
+ rst Bankswitch
+
+ ld a, c
+ call LoadMovementDataPointer
+
+ pop hl
+ ld a, h
+ rst Bankswitch
+ ret
+; 26d4
+
+GetScriptByte:: ; 0x26d4
+; Return byte at ScriptBank:ScriptPos in a.
+
+ push hl
+ push bc
+ ld a, [hROMBank]
+ push af
+ ld a, [ScriptBank]
+ rst Bankswitch
+
+ ld hl, ScriptPos
+ ld c, [hl]
+ inc hl
+ ld b, [hl]
+
+ ld a, [bc]
+
+ inc bc
+ ld [hl], b
+ dec hl
+ ld [hl], c
+
+ ld b, a
+ pop af
+ rst Bankswitch
+ ld a, b
+ pop bc
+ pop hl
+ ret
+; 0x26ef
+
+ObjectEvent:: ; 0x26ef
+ jumptextfaceplayer ObjectEventText
+; 0x26f2
+
+ObjectEventText::
+ text_jump _ObjectEventText
+ db "@"
+; 0x26f7
+
+BGEvent:: ; 26f7
+ jumptext BGEventText
+; 26fa
+
+BGEventText:: ; 26fa
+ text_jump UnknownText_0x1c46fc
+ db "@"
+; 26ff
+
+CoordinatesEvent:: ; 26ff
+ jumptext CoordinatesEventText
+; 2702
+
+CoordinatesEventText:: ; 2702
+ text_jump UnknownText_0x1c4706
+ db "@"
+; 2707
+
+CheckObjectMask:: ; 2707
+ ld a, [hMapObjectIndexBuffer]
+ ld e, a
+ ld d, $0
+ ld hl, wObjectMasks
+ add hl, de
+ ld a, [hl]
+ ret
+; 2712
+
+MaskObject:: ; 2712
+ ld a, [hMapObjectIndexBuffer]
+ ld e, a
+ ld d, $0
+ ld hl, wObjectMasks
+ add hl, de
+ ld [hl], -1 ; , masked
+ ret
+; 271e
+
+UnmaskObject:: ; 271e
+ ld a, [hMapObjectIndexBuffer]
+ ld e, a
+ ld d, $0
+ ld hl, wObjectMasks
+ add hl, de
+ ld [hl], 0 ; unmasked
+ ret
+; 272a
+
+ScrollMapDown:: ; 272a
+ hlcoord 0, 0
+ ld de, BGMapBuffer
+ call BackupBGMapRow
+ ld c, 2 * SCREEN_WIDTH
+ call FarCallScrollBGMapPalettes
+ ld a, [wBGMapAnchor]
+ ld e, a
+ ld a, [wBGMapAnchor + 1]
+ ld d, a
+ call UpdateBGMapRow
+ ld a, $1
+ ld [hBGMapUpdate], a
+ ret
+; 2748
+
+ScrollMapUp:: ; 2748
+ hlcoord 0, SCREEN_HEIGHT - 2
+ ld de, BGMapBuffer
+ call BackupBGMapRow
+ ld c, 2 * SCREEN_WIDTH
+ call FarCallScrollBGMapPalettes
+ ld a, [wBGMapAnchor]
+ ld l, a
+ ld a, [wBGMapAnchor + 1]
+ ld h, a
+ ld bc, $0200
+ add hl, bc
+; cap d at VBGMap1 / $100
+ ld a, h
+ and %00000011
+ or VBGMap0 / $100
+ ld e, l
+ ld d, a
+ call UpdateBGMapRow
+ ld a, $1
+ ld [hBGMapUpdate], a
+ ret
+; 2771
+
+ScrollMapRight:: ; 2771
+ hlcoord 0, 0
+ ld de, BGMapBuffer
+ call BackupBGMapColumn
+ ld c, 2 * SCREEN_HEIGHT
+ call FarCallScrollBGMapPalettes
+ ld a, [wBGMapAnchor]
+ ld e, a
+ ld a, [wBGMapAnchor + 1]
+ ld d, a
+ call UpdateBGMapColumn
+ ld a, $1
+ ld [hBGMapUpdate], a
+ ret
+; 278f
+
+ScrollMapLeft:: ; 278f
+ hlcoord SCREEN_WIDTH - 2, 0
+ ld de, BGMapBuffer
+ call BackupBGMapColumn
+ ld c, 2 * SCREEN_HEIGHT
+ call FarCallScrollBGMapPalettes
+ ld a, [wBGMapAnchor]
+ ld e, a
+ and %11100000
+ ld b, a
+ ld a, e
+ add SCREEN_HEIGHT
+ and %00011111
+ or b
+ ld e, a
+ ld a, [wBGMapAnchor + 1]
+ ld d, a
+ call UpdateBGMapColumn
+ ld a, $1
+ ld [hBGMapUpdate], a
+ ret
+; 27b7
+
+BackupBGMapRow:: ; 27b7
+ ld c, 2 * SCREEN_WIDTH
+.loop
+ ld a, [hli]
+ ld [de], a
+ inc de
+ dec c
+ jr nz, .loop
+ ret
+; 27c0
+
+BackupBGMapColumn:: ; 27c0
+ ld c, SCREEN_HEIGHT
+.loop
+ ld a, [hli]
+ ld [de], a
+ inc de
+ ld a, [hl]
+ ld [de], a
+ inc de
+ ld a, SCREEN_WIDTH - 1
+ add l
+ ld l, a
+ jr nc, .skip
+ inc h
+
+.skip
+ dec c
+ jr nz, .loop
+ ret
+; 27d3
+
+UpdateBGMapRow:: ; 27d3
+ ld hl, BGMapBufferPtrs
+ push de
+ call .iteration
+ pop de
+ ld a, $20
+ add e
+ ld e, a
+
+.iteration
+ ld c, 10
+.loop
+ ld a, e
+ ld [hli], a
+ ld a, d
+ ld [hli], a
+ ld a, e
+ inc a
+ inc a
+ and $1f
+ ld b, a
+ ld a, e
+ and $e0
+ or b
+ ld e, a
+ dec c
+ jr nz, .loop
+ ld a, SCREEN_WIDTH
+ ld [hFFDC], a
+ ret
+; 27f8
+
+UpdateBGMapColumn:: ; 27f8
+ ld hl, BGMapBufferPtrs
+ ld c, SCREEN_HEIGHT
+.loop
+ ld a, e
+ ld [hli], a
+ ld a, d
+ ld [hli], a
+ ld a, $20
+ add e
+ ld e, a
+ jr nc, .skip
+ inc d
+; cap d at VBGMap1 / $100
+ ld a, d
+ and $3
+ or VBGMap0 / $100
+ ld d, a
+
+.skip
+ dec c
+ jr nz, .loop
+ ld a, SCREEN_HEIGHT
+ ld [hFFDC], a
+ ret
+; 2816
+
+; unreferenced
+ ld hl, BGMapBuffer
+ ld bc, SGBPredef - BGMapBuffer
+ xor a
+ call ByteFill
+ ret
+; 2821
+
+LoadTileset:: ; 2821
+ ld hl, TilesetAddress
+ ld a, [hli]
+ ld h, [hl]
+ ld l, a
+ ld a, [TilesetBank]
+ ld e, a
+
+ ld a, [rSVBK]
+ push af
+ ld a, $6
+ ld [rSVBK], a
+
+ ld a, e
+ ld de, wDecompressScratch
+ call FarDecompress
+
+ ld hl, wDecompressScratch
+ ld de, VTiles2
+ ld bc, $60 tiles
+ call CopyBytes
+
+ ld a, [rVBK]
+ push af
+ ld a, $1
+ ld [rVBK], a
+
+ ld hl, w6_d600
+ ld de, VTiles2
+ ld bc, $60 tiles
+ call CopyBytes
+
+ pop af
+ ld [rVBK], a
+
+ pop af
+ ld [rSVBK], a
+
+ ld a, [wTileset]
+ cp TILESET_JOHTO_1
+ jr z, .load_roof
+ cp TILESET_JOHTO_2
+ jr z, .load_roof
+ cp TILESET_BATTLE_TOWER_OUTSIDE
+ jr z, .load_roof
+ jr .skip_roof
+
+.load_roof
+ callba LoadMapGroupRoof
+
+.skip_roof
+ xor a
+ ld [hTileAnimFrame], a
+ ret
+; 2879
+
+BufferScreen:: ; 2879
+ ld hl, wOverworldMapAnchor
+ ld a, [hli]
+ ld h, [hl]
+ ld l, a
+ ld de, wScreenSave
+ ld c, $5
+ ld b, $6
+.row
+ push bc
+ push hl
+.col
+ ld a, [hli]
+ ld [de], a
+ inc de
+ dec b
+ jr nz, .col
+ pop hl
+ ld a, [MapWidth]
+ add $6
+ ld c, a
+ ld b, $0
+ add hl, bc
+ pop bc
+ dec c
+ jr nz, .row
+ ret
+; 289d
+
+SaveScreen:: ; 289d
+ ld hl, wOverworldMapAnchor
+ ld a, [hli]
+ ld h, [hl]
+ ld l, a
+ ld de, wScreenSave
+ ld a, [MapWidth]
+ add 6
+ ld [hMapObjectIndexBuffer], a
+ ld a, [wPlayerStepDirection]
+ and a
+ jr z, .down
+ cp UP
+ jr z, .up
+ cp LEFT
+ jr z, .left
+ cp RIGHT
+ jr z, .right
+ ret
+
+.up
+ ld de, wScreenSave + 6
+ ld a, [hMapObjectIndexBuffer]
+ ld c, a
+ ld b, $0
+ add hl, bc
+ jr .vertical
+
+.down
+ ld de, wScreenSave
+.vertical
+ ld b, 6
+ ld c, 4
+ jr SaveScreen_LoadNeighbor
+
+.left
+ ld de, wScreenSave + 1
+ inc hl
+ jr .horizontal
+
+.right
+ ld de, wScreenSave
+.horizontal
+ ld b, 5
+ ld c, 5
+ jr SaveScreen_LoadNeighbor
+
+LoadNeighboringBlockData:: ; 28e3
+ ld hl, wOverworldMapAnchor
+ ld a, [hli]
+ ld h, [hl]
+ ld l, a
+ ld a, [MapWidth]
+ add 6
+ ld [hConnectionStripLength], a
+ ld de, wScreenSave
+ ld b, 6
+ ld c, 5
+
+SaveScreen_LoadNeighbor:: ; 28f7
+.row
+ push bc
+ push hl
+ push de
+.col
+ ld a, [de]
+ inc de
+ ld [hli], a
+ dec b
+ jr nz, .col
+ pop de
+ ld a, e
+ add 6
+ ld e, a
+ jr nc, .okay
+ inc d
+
+.okay
+ pop hl
+ ld a, [hConnectionStripLength]
+ ld c, a
+ ld b, 0
+ add hl, bc
+ pop bc
+ dec c
+ jr nz, .row
+ ret
+; 2914
+
+GetMovementPermissions:: ; 2914
+ xor a
+ ld [TilePermissions], a
+ call .LeftRight
+ call .UpDown
+; get coords of current tile
+ ld a, [PlayerStandingMapX]
+ ld d, a
+ ld a, [PlayerStandingMapY]
+ ld e, a
+ call GetCoordTile
+ ld [PlayerStandingTile], a
+ call .CheckHiNybble
+ ret nz
+
+ ld a, [PlayerStandingTile]
+ and 7
+ ld hl, .MovementPermissionsData
+ add l
+ ld l, a
+ ld a, 0
+ adc h
+ ld h, a
+ ld a, [hl]
+ ld hl, TilePermissions
+ or [hl]
+ ld [hl], a
+ ret
+; 2945
+
+.MovementPermissionsData ; 2945
+ db 1, 2, 4, 8, 9, 10, 5, 6
+; 294d
+
+.UpDown
+ ld a, [PlayerStandingMapX]
+ ld d, a
+ ld a, [PlayerStandingMapY]
+ ld e, a
+
+ push de
+ inc e
+ call GetCoordTile
+ ld [TileDown], a
+ call .Down
+
+ pop de
+ dec e
+ call GetCoordTile
+ ld [TileUp], a
+ call .Up
+ ret
+; 296c
+
+.LeftRight
+ ld a, [PlayerStandingMapX]
+ ld d, a
+ ld a, [PlayerStandingMapY]
+ ld e, a
+
+ push de
+ dec d
+ call GetCoordTile
+ ld [TileLeft], a
+ call .Left
+
+ pop de
+ inc d
+ call GetCoordTile
+ ld [TileRight], a
+ call .Right
+ ret
+; 298b
+
+.Down
+ call .CheckHiNybble
+ ret nz
+ ld a, [TileDown]
+ and 7
+ cp $2
+ jr z, .ok_down
+ cp $6
+ jr z, .ok_down
+ cp $7
+ ret nz
+
+.ok_down
+ ld a, [TilePermissions]
+ or FACE_DOWN
+ ld [TilePermissions], a
+ ret
+; 29a8
+
+.Up
+ call .CheckHiNybble
+ ret nz
+ ld a, [TileUp]
+ and 7
+ cp $3
+ jr z, .ok_up
+ cp $4
+ jr z, .ok_up
+ cp $5
+ ret nz
+
+.ok_up
+ ld a, [TilePermissions]
+ or FACE_UP
+ ld [TilePermissions], a
+ ret
+; 29c5
+
+.Right
+ call .CheckHiNybble
+ ret nz
+ ld a, [TileRight]
+ and 7
+ cp $1
+ jr z, .ok_right
+ cp $5
+ jr z, .ok_right
+ cp $7
+ ret nz
+
+.ok_right
+ ld a, [TilePermissions]
+ or FACE_RIGHT
+ ld [TilePermissions], a
+ ret
+; 29e2
+
+.Left
+ call .CheckHiNybble
+ ret nz
+ ld a, [TileLeft]
+ and 7
+ cp $0
+ jr z, .ok_left
+ cp $4
+ jr z, .ok_left
+ cp $6
+ ret nz
+
+.ok_left
+ ld a, [TilePermissions]
+ or FACE_LEFT
+ ld [TilePermissions], a
+ ret
+; 29ff
+
+.CheckHiNybble
+ and $f0
+ cp $b0
+ ret z
+ cp $c0
+ ret
+; 2a07
+
+GetFacingTileCoord:: ; 2a07
+; Return map coordinates in (d, e) and tile id in a
+; of the tile the player is facing.
+
+ ld a, [PlayerDirection]
+ and %1100
+ srl a
+ srl a
+ ld l, a
+ ld h, 0
+ add hl, hl
+ add hl, hl
+ ld de, .Directions
+ add hl, de
+
+ ld d, [hl]
+ inc hl
+ ld e, [hl]
+ inc hl
+
+ ld a, [hli]
+ ld h, [hl]
+ ld l, a
+
+ ld a, [PlayerStandingMapX]
+ add d
+ ld d, a
+ ld a, [PlayerStandingMapY]
+ add e
+ ld e, a
+ ld a, [hl]
+ ret
+
+.Directions
+ ; x, y
+ db 0, 1
+ dw TileDown
+ db 0, -1
+ dw TileUp
+ db -1, 0
+ dw TileLeft
+ db 1, 0
+ dw TileRight
+; 2a3c
+
+GetCoordTile:: ; 2a3c
+; Get the collision byte for tile d, e
+ call GetBlockLocation
+ ld a, [hl]
+ and a
+ jr z, .nope
+ ld l, a
+ ld h, $0
+ add hl, hl
+ add hl, hl
+ ld a, [TilesetCollisionAddress]
+ ld c, a
+ ld a, [TilesetCollisionAddress + 1]
+ ld b, a
+ add hl, bc
+ rr d
+ jr nc, .nocarry
+ inc hl
+
+.nocarry
+ rr e
+ jr nc, .nocarry2
+ inc hl
+ inc hl
+
+.nocarry2
+ ld a, [TilesetCollisionBank]
+ call GetFarByte
+ ret
+
+.nope
+ ld a, -1
+ ret
+; 2a66
+
+GetBlockLocation:: ; 2a66
+ ld a, [MapWidth]
+ add 6
+ ld c, a
+ ld b, 0
+ ld hl, wc801
+ add hl, bc
+ ld a, e
+ srl a
+ jr z, .nope
+ and a
+.loop
+ srl a
+ jr nc, .ok
+ add hl, bc
+
+.ok
+ sla c
+ rl b
+ and a
+ jr nz, .loop
+
+.nope
+ ld c, d
+ srl c
+ ld b, 0
+ add hl, bc
+ ret
+; 2a8b
+
+CheckFacingSign:: ; 2a8b
+ call GetFacingTileCoord
+; Load facing into b.
+ ld b, a
+; Convert the coordinates at de to within-boundaries coordinates.
+ ld a, d
+ sub 4
+ ld d, a
+ ld a, e
+ sub 4
+ ld e, a
+; If there are no signposts, we don't need to be here.
+ ld a, [wCurrentMapSignpostCount]
+ and a
+ ret z
+
+ ld c, a
+ ld a, [hROMBank]
+ push af
+ call SwitchToMapScriptHeaderBank
+ call CheckIfFacingTileCoordIsSign
+ pop hl
+ ld a, h
+ rst Bankswitch
+ ret
+; 2aaa
+
+CheckIfFacingTileCoordIsSign:: ; 2aaa
+; Checks to see if you are facing a signpost. If so, copies it into EngineBuffer1 and sets carry.
+ ld hl, wCurrentMapSignpostHeaderPointer
+ ld a, [hli]
+ ld h, [hl]
+ ld l, a
+.loop
+ push hl
+ ld a, [hli]
+ cp e
+ jr nz, .next
+ ld a, [hli]
+ cp d
+ jr nz, .next
+ jr .copysign
+
+.next
+ pop hl
+ ld a, 5 ; signpost event length
+ add l
+ ld l, a
+ jr nc, .nocarry
+ inc h
+
+.nocarry
+ dec c
+ jr nz, .loop
+ xor a
+ ret
+
+.copysign
+ pop hl
+ ld de, wCurSignpostYCoord
+ ld bc, 5 ; signpost event length
+ call CopyBytes
+ scf
+ ret
+; 2ad4
+
+CheckCurrentMapXYTriggers:: ; 2ad4
+; If there are no xy triggers, we don't need to be here.
+ ld a, [wCurrentMapXYTriggerCount]
+ and a
+ ret z
+; Copy the trigger count into c.
+ ld c, a
+ ld a, [hROMBank]
+ push af
+ call SwitchToMapScriptHeaderBank
+ call .TriggerCheck
+ pop hl
+ ld a, h
+ rst Bankswitch
+ ret
+
+.TriggerCheck
+; Checks to see if you are standing on an xy-trigger. If yes, copies the trigger to EngineBuffer1 and sets carry.
+ ld hl, wCurrentMapXYTriggerHeaderPointer
+ ld a, [hli]
+ ld h, [hl]
+ ld l, a
+; Load the active trigger ID into b
+ call CheckTriggers
+ ld b, a
+; Load your current coordinates into de. This will be used to check if your position is in the xy-trigger table for the current map.
+ ld a, [PlayerStandingMapX]
+ sub 4
+ ld d, a
+ ld a, [PlayerStandingMapY]
+ sub 4
+ ld e, a
+
+.loop
+ push hl
+ ld a, [hli]
+ cp b
+ jr z, .got_id
+ cp -1
+ jr nz, .next
+
+.got_id
+ ld a, [hli]
+ cp e
+ jr nz, .next
+ ld a, [hli]
+ cp d
+ jr nz, .next
+ jr .copytrigger
+
+.next
+ pop hl
+ ld a, $8 ; xy-trigger size
+ add l
+ ld l, a
+ jr nc, .nocarry
+ inc h
+
+.nocarry
+ dec c
+ jr nz, .loop
+ xor a
+ ret
+
+.copytrigger
+ pop hl
+ ld de, wCurCoordEventTriggerID
+ ld bc, 8 ; xy-trigger size
+ call CopyBytes
+ scf
+ ret
+; 2b29
+
+FadeToMenu:: ; 2b29
+ xor a
+ ld [hBGMapMode], a
+ call LoadStandardMenuDataHeader
+ callba FadeOutPalettes
+ call ClearSprites
+ call DisableSpriteUpdates
+ ret
+; 2b3c
+
+CloseSubmenu:: ; 2b3c
+ call ClearBGPalettes
+ call ReloadTilesetAndPalettes
+ call UpdateSprites
+ call Call_ExitMenu
+ call ret_d90
+ jr FinishExitMenu
+; 2b4d
+
+ExitAllMenus:: ; 2b4d
+ call ClearBGPalettes
+ call Call_ExitMenu
+ call ReloadTilesetAndPalettes
+ call UpdateSprites
+ call ret_d90
+FinishExitMenu:: ; 2b5c
+ ld b, SCGB_MAPPALS
+ call GetSGBLayout
+ callba LoadOW_BGPal7
+ call WaitBGMap2
+ callba FadeInPalettes
+ call EnableSpriteUpdates
+ ret
+; 2b74
+
+ReturnToMapWithSpeechTextbox:: ; 0x2b74
+ push af
+ ld a, $1
+ ld [wSpriteUpdatesEnabled], a
+ call ClearBGPalettes
+ call ClearSprites
+ call ReloadTilesetAndPalettes
+ hlcoord 0, 12
+ lb bc, 4, 18
+ call TextBox
+ ld hl, VramState
+ set 0, [hl]
+ call UpdateSprites
+ call WaitBGMap2
+ ld b, SCGB_MAPPALS
+ call GetSGBLayout
+ callba LoadOW_BGPal7
+ call UpdateTimePals
+ call DelayFrame
+ ld a, $1
+ ld [hMapAnims], a
+ pop af
+ ret
+; 0x2bae
+
+ReloadTilesetAndPalettes:: ; 2bae
+ call DisableLCD
+ call ClearSprites
+ callba RefreshSprites
+ call LoadStandardFont
+ call LoadFontsExtra
+ ld a, [hROMBank]
+ push af
+ ld a, [MapGroup]
+ ld b, a
+ ld a, [MapNumber]
+ ld c, a
+ call SwitchToAnyMapBank
+ callba UpdateTimeOfDayPal
+ call OverworldTextModeSwitch
+ call LoadTileset
+ ld a, 9
+ call SkipMusic
+ pop af
+ rst Bankswitch
+
+ call EnableLCD
+ ret
+; 2be5
+
+GetMapHeaderPointer:: ; 2be5
+ ld a, [MapGroup]
+ ld b, a
+ ld a, [MapNumber]
+ ld c, a
+GetAnyMapHeaderPointer:: ; 0x2bed
+; Prior to calling this function, you must have switched banks so that
+; MapGroupPointers is visible.
+
+; inputs:
+; b = map group, c = map number
+; XXX de = ???
+
+; outputs:
+; hl points to the map header
+ push bc ; save map number for later
+
+ ; get pointer to map group
+ dec b
+ ld c, b
+ ld b, 0
+ ld hl, MapGroupPointers
+ add hl, bc
+ add hl, bc
+
+ ld a, [hli]
+ ld h, [hl]
+ ld l, a
+ pop bc ; restore map number
+
+ ; find the cth map header
+ dec c
+ ld b, 0
+ ld a, 9
+ call AddNTimes
+ ret
+; 0x2c04
+
+GetMapHeaderMember:: ; 0x2c04
+; Extract data from the current map's header.
+
+; inputs:
+; de = offset of desired data within the mapheader
+
+; outputs:
+; bc = data from the current map's header
+; (e.g., de = $0003 would return a pointer to the secondary map header)
+
+ ld a, [MapGroup]
+ ld b, a
+ ld a, [MapNumber]
+ ld c, a
+GetAnyMapHeaderMember:: ; 0x2c0c
+ ; bankswitch
+ ld a, [hROMBank]
+ push af
+ ld a, BANK(MapGroupPointers)
+ rst Bankswitch
+
+ call GetAnyMapHeaderPointer
+ add hl, de
+ ld c, [hl]
+ inc hl
+ ld b, [hl]
+
+ ; bankswitch back
+ pop af
+ rst Bankswitch
+ ret
+; 0x2c1c
+
+SwitchToMapBank:: ; 2c1c
+ ld a, [MapGroup]
+ ld b, a
+ ld a, [MapNumber]
+ ld c, a
+SwitchToAnyMapBank:: ; 2c24
+ call GetAnyMapBank
+ rst Bankswitch
+ ret
+; 2c29
+
+GetMapBank:: ; 2c29
+ ld a, [MapGroup]
+ ld b, a
+ ld a, [MapNumber]
+ ld c, a
+GetAnyMapBank:: ; 2c31
+ push hl
+ push de
+ ld de, 0
+ call GetAnyMapHeaderMember
+ ld a, c
+ pop de
+ pop hl
+ ret
+; 2c3d
+
+PartiallyCopyMapHeader:: ; 2c3d
+; Copy second map header bank, tileset, permission, and second map header address
+; from the current map's map header.
+ ld a, [hROMBank]
+ push af
+ ld a, BANK(MapGroupPointers)
+ rst Bankswitch
+
+ call GetMapHeaderPointer
+ ld de, wSecondMapHeaderBank
+ ld bc, MapHeader - wSecondMapHeaderBank
+ call CopyBytes
+
+ pop af
+ rst Bankswitch
+ ret
+; 2c52
+
+SwitchToMapScriptHeaderBank:: ; 2c52
+ ld a, [MapScriptHeaderBank]
+ rst Bankswitch
+ ret
+; 2c57
+
+GetMapScriptHeaderBank:: ; 2c57
+ ld a, [MapScriptHeaderBank]
+ ret
+; 2c5b
+
+GetAnyMapBlockdataBank:: ; 2c5b
+; Return the blockdata bank for group b map c.
+ push hl
+ push de
+ push bc
+
+ push bc
+ ld de, 3 ; second map header pointer
+ call GetAnyMapHeaderMember
+ ld l, c
+ ld h, b
+ pop bc
+
+ push hl
+ ld de, 0 ; second map header bank
+ call GetAnyMapHeaderMember
+ pop hl
+
+ ld de, 3 ; blockdata bank
+ add hl, de
+ ld a, c
+ call GetFarByte
+ rst Bankswitch
+
+ pop bc
+ pop de
+ pop hl
+ ret
+; 2c7d
+
+GetSecondaryMapHeaderPointer:: ; 0x2c7d
+; returns the current map's secondary map header pointer in hl.
+ push bc
+ push de
+ ld de, 3 ; secondary map header pointer (offset within header)
+ call GetMapHeaderMember
+ ld l, c
+ ld h, b
+ pop de
+ pop bc
+ ret
+; 2c8a
+
+GetMapPermission:: ; 2c8a
+ push hl
+ push de
+ push bc
+ ld de, 2 ; permission
+ call GetMapHeaderMember
+ ld a, c
+ pop bc
+ pop de
+ pop hl
+ ret
+; 2c98
+
+ ret ; XXX
+; 2c99
+
+GetAnyMapPermission:: ; 2c99
+ push hl
+ push de
+ push bc
+ ld de, 2 ; permission
+ call GetAnyMapHeaderMember
+ ld a, c
+ pop bc
+ pop de
+ pop hl
+ ret
+; 2ca7
+
+GetAnyMapTileset:: ; 2ca7
+ ld de, 1 ; tileset
+ call GetAnyMapHeaderMember
+ ld a, c
+ ret
+; 2caf
+
+GetWorldMapLocation:: ; 0x2caf
+; given a map group/id in bc, return its location on the Pokégear map.
+ push hl
+ push de
+ push bc
+
+ ld de, 5 ; landmark
+ call GetAnyMapHeaderMember
+ ld a, c
+
+ pop bc
+ pop de
+ pop hl
+ ret
+; 0x2cbd
+
+GetMapHeaderMusic:: ; 2cbd
+RADIO_TOWER_MUSIC EQU 7
+
+ push hl
+ push bc
+ ld de, 6 ; music
+ call GetMapHeaderMember
+ ld a, c
+ cp MUSIC_MAHOGANY_MART
+ jr z, .mahoganymart
+ bit RADIO_TOWER_MUSIC, c
+ jr nz, .radiotower
+ callba Function8b342
+ ld e, c
+ ld d, 0
+.done
+ pop bc
+ pop hl
+ ret
+
+.radiotower
+ ld a, [StatusFlags2]
+ bit 0, a
+ jr z, .clearedradiotower
+ ld de, MUSIC_ROCKET_OVERTURE
+ jr .done
+
+.clearedradiotower
+ ; the rest of the byte
+ ld a, c
+ and 1 << RADIO_TOWER_MUSIC - 1
+ ld e, a
+ ld d, 0
+ jr .done
+
+.mahoganymart
+ ld a, [StatusFlags2]
+ bit 7, a
+ jr z, .clearedmahogany
+ ld de, MUSIC_ROCKET_HIDEOUT
+ jr .done
+
+.clearedmahogany
+ ld de, MUSIC_CHERRYGROVE_CITY
+ jr .done
+; 2cff
+
+GetMapHeaderTimeOfDayNybble:: ; 2cff
+ call GetPhoneServiceTimeOfDayByte
+ and $f
+ ret
+; 2d05
+
+GetMapHeaderPhoneServiceNybble:: ; 2d05
+ call GetPhoneServiceTimeOfDayByte
+ and $f0
+ swap a
+ ret
+; 2d0d
+
+GetPhoneServiceTimeOfDayByte:: ; 2d0d
+ push hl
+ push bc
+
+ ld de, 7 ; phone service and time of day
+ call GetMapHeaderMember
+ ld a, c
+
+ pop bc
+ pop hl
+ ret
+; 2d19
+
+GetFishingGroup:: ; 2d19
+ push de
+ push hl
+ push bc
+
+ ld de, 8 ; fishing group
+ call GetMapHeaderMember
+ ld a, c
+
+ pop bc
+ pop hl
+ pop de
+ ret
+; 2d27
+
+LoadTilesetHeader:: ; 2d27
+ push hl
+ push bc
+
+ ld hl, Tilesets
+ ld bc, Tileset01 - Tileset00
+ ld a, [wTileset]
+ call AddNTimes
+
+ ld de, TilesetBank
+ ld bc, Tileset01 - Tileset00
+
+ ld a, BANK(Tilesets)
+ call FarCopyBytes
+
+ pop bc
+ pop hl
+ ret
+; 2d43
diff --git a/home/map_objects.asm b/home/map_objects.asm
new file mode 100644
index 00000000..f4a4d6d5
--- /dev/null
+++ b/home/map_objects.asm
@@ -0,0 +1,670 @@
+; Functions handling map objects.
+
+GetSpritePalette:: ; 17ff
+ push hl
+ push de
+ push bc
+ ld c, a
+
+ callba _GetSpritePalette
+
+ ld a, c
+ pop bc
+ pop de
+ pop hl
+ ret
+; 180e
+
+GetSpriteVTile:: ; 180e
+ push hl
+ push bc
+ ld hl, UsedSprites + 2
+ ld c, SPRITE_GFX_LIST_CAPACITY - 1
+ ld b, a
+ ld a, [hMapObjectIndexBuffer]
+ cp 0
+ jr z, .nope
+ ld a, b
+.loop
+ cp [hl]
+ jr z, .found
+rept 2
+ inc hl
+endr
+ dec c
+ jr nz, .loop
+ ld a, [UsedSprites + 1]
+ scf
+ jr .done
+
+.nope
+ ld a, [UsedSprites + 1]
+ jr .done
+
+.found
+ inc hl
+ xor a
+ ld a, [hl]
+
+.done
+ pop bc
+ pop hl
+ ret
+; 1836
+
+DoesSpriteHaveFacings:: ; 1836
+ push de
+ push hl
+
+ ld b, a
+ ld a, [hROMBank]
+ push af
+ ld a, BANK(_DoesSpriteHaveFacings)
+ rst Bankswitch
+
+ ld a, b
+ call _DoesSpriteHaveFacings
+ ld c, a
+
+ pop de
+ ld a, d
+ rst Bankswitch
+
+ pop hl
+ pop de
+ ret
+; 184a
+
+GetPlayerStandingTile:: ; 184a
+ ld a, [PlayerStandingTile]
+ call GetTileCollision
+ ld b, a
+ ret
+; 1852
+
+CheckOnWater:: ; 1852
+ ld a, [PlayerStandingTile]
+ call GetTileCollision
+ sub 1
+ ret z
+ and a
+ ret
+; 185d
+
+GetTileCollision:: ; 185d
+; Get the collision type of tile a.
+
+ push de
+ push hl
+
+ ld hl, TileCollisionTable
+ ld e, a
+ ld d, 0
+ add hl, de
+
+ ld a, [hROMBank]
+ push af
+ ld a, BANK(TileCollisionTable)
+ rst Bankswitch
+ ld e, [hl]
+ pop af
+ rst Bankswitch
+
+ ld a, e
+ and $f ; lo nybble only
+
+ pop hl
+ pop de
+ ret
+; 1875
+
+CheckGrassTile:: ; 1875
+ ld d, a
+ and $f0
+ cp $10
+ jr z, .ok_10
+ cp $20
+ jr z, .ok_20
+ scf
+ ret
+
+.ok_10
+ ld a, d
+ and 7
+ ret z
+ scf
+ ret
+; For some reason, the above code is duplicated down here.
+.ok_20
+ ld a, d
+ and 7
+ ret z
+ scf
+ ret
+; 188e
+
+CheckSuperTallGrassTile:: ; 188e
+ cp $14
+ ret z
+ cp $1c
+ ret
+; 1894
+
+CheckCutTreeTile:: ; 1894
+ cp $12
+ ret z
+ cp $1a
+ ret
+; 189a
+
+CheckHeadbuttTreeTile:: ; 189a
+ cp $15
+ ret z
+ cp $1d
+ ret
+; 18a0
+
+CheckCounterTile:: ; 18a0
+ cp $90
+ ret z
+ cp $98
+ ret
+; 18a6
+
+CheckPitTile:: ; 18a6
+ cp $60
+ ret z
+ cp $68
+ ret
+; 18ac
+
+CheckIceTile:: ; 18ac
+ cp $23
+ ret z
+ cp $2b
+ ret z
+ scf
+ ret
+; 18b4
+
+CheckWhirlpoolTile:: ; 18b4
+ nop
+ cp $24
+ ret z
+ cp $2c
+ ret z
+ scf
+ ret
+; 18bd
+
+CheckWaterfallTile:: ; 18bd
+ cp $33
+ ret z
+ cp $3b
+ ret
+; 18c3
+
+CheckStandingOnEntrance:: ; 18c3
+ ld a, [PlayerStandingTile]
+ cp $71 ; door
+ ret z
+ cp $79
+ ret z
+ cp $7a ; stairs
+ ret z
+ cp $7b ; cave
+ ret
+; 18d2
+
+GetMapObject:: ; 18d2
+; Return the location of map object a in bc.
+ ld hl, MapObjects
+ ld bc, OBJECT_LENGTH
+ call AddNTimes
+ ld b, h
+ ld c, l
+ ret
+; 18de
+
+CheckObjectVisibility:: ; 18de
+; Sets carry if the object is not visible on the screen.
+ ld [hMapObjectIndexBuffer], a
+ call GetMapObject
+ ld hl, MAPOBJECT_OBJECT_STRUCT_ID
+ add hl, bc
+ ld a, [hl]
+ cp -1
+ jr z, .not_visible
+ ld [hObjectStructIndexBuffer], a
+ call GetObjectStruct
+ and a
+ ret
+
+.not_visible
+ scf
+ ret
+; 18f5
+
+CheckObjectTime:: ; 18f5
+ ld hl, MAPOBJECT_HOUR
+ add hl, bc
+ ld a, [hl]
+ cp -1
+ jr nz, .check_hour
+ ld hl, MAPOBJECT_TIMEOFDAY
+ add hl, bc
+ ld a, [hl]
+ cp -1
+ jr z, .timeofday_always
+ ld hl, .TimeOfDayValues_191e
+ ld a, [TimeOfDay]
+ add l
+ ld l, a
+ jr nc, .ok
+ inc h
+
+.ok
+ ld a, [hl]
+ ld hl, MAPOBJECT_TIMEOFDAY
+ add hl, bc
+ and [hl]
+ jr nz, .timeofday_always
+ scf
+ ret
+
+.timeofday_always
+ and a
+ ret
+
+.TimeOfDayValues_191e
+ db 1 << MORN ; 1
+ db 1 << DAY ; 2
+ db 1 << NITE ; 4
+
+.check_hour
+ ld hl, MAPOBJECT_HOUR
+ add hl, bc
+ ld d, [hl]
+ ld hl, MAPOBJECT_TIMEOFDAY
+ add hl, bc
+ ld e, [hl]
+ ld hl, hHours
+ ld a, d
+ cp e
+ jr z, .yes
+ jr c, .check_timeofday
+ ld a, [hl]
+ cp d
+ jr nc, .yes
+ cp e
+ jr c, .yes
+ jr z, .yes
+ jr .no
+
+.check_timeofday
+ ld a, e
+ cp [hl]
+ jr c, .no
+ ld a, [hl]
+ cp d
+ jr nc, .yes
+ jr .no
+
+.yes
+ and a
+ ret
+
+.no
+ scf
+ ret
+; 194d
+
+; XXX
+ ld [hMapObjectIndexBuffer], a
+ call GetMapObject
+ call CopyObjectStruct
+ ret
+; 1956
+
+_CopyObjectStruct:: ; 1956
+ ld [hMapObjectIndexBuffer], a
+ call UnmaskObject
+ ld a, [hMapObjectIndexBuffer]
+ call GetMapObject
+ callba CopyObjectStruct
+ ret
+; 1967
+
+ApplyDeletionToMapObject:: ; 1967
+ ld [hMapObjectIndexBuffer], a
+ call GetMapObject
+ ld hl, MAPOBJECT_OBJECT_STRUCT_ID
+ add hl, bc
+ ld a, [hl]
+ cp -1
+ ret z ; already hidden
+ ld [hl], -1
+ push af
+ call .CheckStopFollow
+ pop af
+ call GetObjectStruct
+ callba DeleteMapObject
+ ret
+
+.CheckStopFollow
+ ld hl, wObjectFollow_Leader
+ cp [hl]
+ jr z, .ok
+ ld hl, wObjectFollow_Follower
+ cp [hl]
+ ret nz
+.ok
+ callba StopFollow
+ ld a, -1
+ ld [wObjectFollow_Leader], a
+ ld [wObjectFollow_Follower], a
+ ret
+; 199f
+
+DeleteObjectStruct:: ; 199f
+ call ApplyDeletionToMapObject
+ call MaskObject
+ ret
+; 19a6
+
+CopyPlayerObjectTemplate:: ; 19a6
+ push hl
+ call GetMapObject
+ ld d, b
+ ld e, c
+ ld a, -1
+ ld [de], a
+ inc de
+ pop hl
+ ld bc, OBJECT_LENGTH - 1
+ call CopyBytes
+ ret
+; 19b8
+
+; XXX
+ call GetMapObject
+ ld hl, MAPOBJECT_OBJECT_STRUCT_ID
+ add hl, bc
+ ld a, [hl]
+ push af
+ ld [hl], -1
+ inc hl
+ ld bc, OBJECT_LENGTH - 1
+ xor a
+ call ByteFill
+ pop af
+ cp -1
+ ret z
+ cp $d
+ ret nc
+ ld b, a
+ ld a, [wObjectFollow_Leader]
+ cp b
+ jr nz, .ok
+ ld a, -1
+ ld [wObjectFollow_Leader], a
+
+.ok
+ ld a, b
+ call GetObjectStruct
+ callba DeleteMapObject
+ ret
+; 19e9
+
+LoadMovementDataPointer:: ; 19e9
+; Load the movement data pointer for person a.
+ ld [wMovementPerson], a
+ ld a, [hROMBank]
+ ld [wMovementDataPointer], a
+ ld a, l
+ ld [wMovementDataPointer + 1], a
+ ld a, h
+ ld [wMovementDataPointer + 2], a
+ ld a, [wMovementPerson]
+ call CheckObjectVisibility
+ ret c
+
+ ld hl, OBJECT_MOVEMENTTYPE
+ add hl, bc
+ ld [hl], SPRITEMOVEDATA_SCRIPTED
+
+ ld hl, OBJECT_STEP_TYPE
+ add hl, bc
+ ld [hl], STEP_TYPE_00
+
+ ld hl, VramState
+ set 7, [hl]
+ and a
+ ret
+; 1a13
+
+FindFirstEmptyObjectStruct:: ; 1a13
+; Returns the index of the first empty object struct in A and its address in HL, then sets carry.
+; If all object structs are occupied, A = 0 and Z is set.
+; Preserves BC and DE.
+ push bc
+ push de
+ ld hl, ObjectStructs
+ ld de, OBJECT_STRUCT_LENGTH
+ ld c, NUM_OBJECT_STRUCTS
+.loop
+ ld a, [hl]
+ and a
+ jr z, .break
+ add hl, de
+ dec c
+ jr nz, .loop
+ xor a
+ jr .done
+
+.break
+ ld a, NUM_OBJECT_STRUCTS
+ sub c
+ scf
+
+.done
+ pop de
+ pop bc
+ ret
+; 1a2f
+
+GetSpriteMovementFunction:: ; 1a2f
+ ld hl, OBJECT_MOVEMENTTYPE
+ add hl, bc
+ ld a, [hl]
+ cp NUM_SPRITEMOVEDATA
+ jr c, .ok
+ xor a
+
+.ok
+ ld hl, SpriteMovementData
+ ld e, a
+ ld d, 0
+rept SPRITEMOVEDATA_FIELDS
+ add hl,de
+endr
+ ld a, [hl]
+ ret
+; 1a47
+
+GetInitialFacing:: ; 1a47
+ push bc
+ push de
+ ld e, a
+ ld d, 0
+ ld hl, SpriteMovementData + 1 ; init facing
+rept SPRITEMOVEDATA_FIELDS
+ add hl,de
+endr
+ ld a, BANK(SpriteMovementData)
+ call GetFarByte
+rept 2
+ add a
+endr
+ and $c
+ pop de
+ pop bc
+ ret
+; 1a61
+
+CopySpriteMovementData:: ; 1a61
+ ld l, a
+ ld a, [hROMBank]
+ push af
+ ld a, BANK(SpriteMovementData)
+ rst Bankswitch
+ ld a, l
+ push bc
+
+ call .CopyData
+
+ pop bc
+ pop af
+ rst Bankswitch
+
+ ret
+; 1a71
+
+.CopyData ; 1a71
+ ld hl, OBJECT_MOVEMENTTYPE
+ add hl, de
+ ld [hl], a
+
+ push de
+ ld e, a
+ ld d, 0
+ ld hl, SpriteMovementData + 1 ; init facing
+rept SPRITEMOVEDATA_FIELDS
+ add hl, de
+endr
+ ld b, h
+ ld c, l
+ pop de
+
+ ld a, [bc]
+ inc bc
+ rlca
+ rlca
+ and %00001100
+ ld hl, OBJECT_FACING
+ add hl, de
+ ld [hl], a
+
+ ld a, [bc]
+ inc bc
+ ld hl, OBJECT_ACTION
+ add hl, de
+ ld [hl], a
+
+ ld a, [bc]
+ inc bc
+ ld hl, OBJECT_FLAGS1
+ add hl, de
+ ld [hl], a
+
+ ld a, [bc]
+ inc bc
+ ld hl, OBJECT_FLAGS2
+ add hl, de
+ ld [hl], a
+
+ ld a, [bc]
+ inc bc
+ ld hl, OBJECT_PALETTE
+ add hl, de
+ ld [hl], a
+ ret
+; 1aae
+
+_GetMovementByte:: ; 1aae
+; Switch to the movement data bank
+ ld a, [hROMBank]
+ push af
+ ld a, [hli]
+ rst Bankswitch
+; Load the current script byte as given by OBJECT_MOVEMENT_BYTE_INDEX, and increment OBJECT_MOVEMENT_BYTE_INDEX
+ ld a, [hli]
+ ld d, [hl]
+ ld hl, OBJECT_MOVEMENT_BYTE_INDEX
+ add hl, bc
+ add [hl]
+ ld e, a
+ ld a, d
+ adc 0
+ ld d, a
+ inc [hl]
+ ld a, [de]
+ ld h, a
+ pop af
+ rst Bankswitch
+
+ ld a, h
+ ret
+; 1ac6
+
+SetVramState_Bit0:: ; 1ac6
+ ld hl, VramState
+ set 0, [hl]
+ ret
+; 1acc
+
+ResetVramState_Bit0:: ; 1acc
+ ld hl, VramState
+ res 0, [hl]
+ ret
+; 1ad2
+
+UpdateSprites:: ; 1ad2
+ ld a, [VramState]
+ bit 0, a
+ ret z
+
+ callba Function55e0
+ callba _UpdateSprites
+ ret
+; 1ae5
+
+GetObjectStruct:: ; 1ae5
+ ld bc, OBJECT_STRUCT_LENGTH
+ ld hl, ObjectStructs
+ call AddNTimes
+ ld b, h
+ ld c, l
+ ret
+; 1af1
+
+GetObjectSprite:: ; 1af1
+ ld hl, OBJECT_SPRITE
+ add hl, bc
+ ld a, [hl]
+ and a
+ ret
+; 1af8
+
+SetSpriteDirection:: ; 1af8
+ ; preserves other flags
+ push af
+ ld hl, OBJECT_FACING
+ add hl, bc
+ ld a, [hl]
+ and %11110011
+ ld e, a
+ pop af
+ and %00001100
+ or e
+ ld [hl], a
+ ret
+; 1b07
+
+GetSpriteDirection:: ; 1b07
+ ld hl, OBJECT_FACING
+ add hl, bc
+ ld a, [hl]
+ and %00001100
+ ret
+; 1b0f
diff --git a/home/math.asm b/home/math.asm
new file mode 100644
index 00000000..c320fd15
--- /dev/null
+++ b/home/math.asm
@@ -0,0 +1,86 @@
+AddNTimes:: ; 0x30fe
+; Add bc * a to hl.
+ and a
+ ret z
+.loop
+ add hl, bc
+ dec a
+ jr nz, .loop
+ ret
+; 0x3105
+
+SimpleMultiply:: ; 3105
+; Return a * c.
+ and a
+ ret z
+
+ push bc
+ ld b, a
+ xor a
+.loop
+ add c
+ dec b
+ jr nz, .loop
+ pop bc
+ ret
+; 3110
+
+
+SimpleDivide:: ; 3110
+; Divide a by c. Return quotient b and remainder a.
+ ld b, 0
+.loop
+ inc b
+ sub c
+ jr nc, .loop
+ dec b
+ add c
+ ret
+; 3119
+
+
+Multiply:: ; 3119
+; Multiply hMultiplicand (3 bytes) by hMultiplier. Result in hProduct.
+; All values are big endian.
+ push hl
+ push bc
+
+ callab _Multiply
+
+ pop bc
+ pop hl
+ ret
+; 3124
+
+
+Divide:: ; 3124
+; Divide hDividend length b (max 4 bytes) by hDivisor. Result in hQuotient.
+; All values are big endian.
+ push hl
+ push de
+ push bc
+ ld a, [hROMBank]
+ push af
+ ld a, BANK(_Divide)
+ rst Bankswitch
+
+ call _Divide
+
+ pop af
+ rst Bankswitch
+ pop bc
+ pop de
+ pop hl
+ ret
+; 3136
+
+
+SubtractSigned:: ; 3136
+; Return a - b, sign in carry.
+ sub b
+ ret nc
+ cpl
+ add 1
+ scf
+ ret
+; 313d
diff --git a/home/menu.asm b/home/menu.asm
new file mode 100644
index 00000000..3e04af8c
--- /dev/null
+++ b/home/menu.asm
@@ -0,0 +1,591 @@
+; Functions used in displaying and handling menus.
+
+
+LoadMenuDataHeader::
+ call CopyMenuDataHeader
+ call PushWindow
+ ret
+
+CopyMenuDataHeader::
+ ld de, wMenuDataHeader
+ ld bc, wMenuDataHeaderEnd - wMenuDataHeader
+ call CopyBytes
+ ld a, [hROMBank]
+ ld [wMenuDataBank], a
+ ret
+; 0x1d4b
+
+StoreTo_wMenuCursorBuffer:: ; 1d4b
+ ld [wMenuCursorBuffer], a
+ ret
+; 1d4f
+
+
+MenuTextBox:: ; 1d4f
+ push hl
+ call LoadMenuTextBox
+ pop hl
+ jp PrintText
+; 1d57
+
+ret_1d57:: ; 1d57
+; unreferenced
+ ret
+; 1d58
+
+LoadMenuTextBox:: ; 1d58
+ ld hl, .MenuDataHeader
+ call LoadMenuDataHeader
+ ret
+; 1d5f
+
+.MenuDataHeader ; 1d5f
+ db $40 ; tile backup
+ db 12, 0 ; start coords
+ db 17, 19 ; end coords
+ dw VTiles0
+ db 0 ; default option
+; 1d67
+
+MenuTextBoxBackup:: ; 1d67
+ call MenuTextBox
+ call CloseWindow
+ ret
+; 1d6e
+
+LoadStandardMenuDataHeader:: ; 1d6e
+ ld hl, .MenuDataHeader
+ call LoadMenuDataHeader
+ ret
+; 1d75
+
+.MenuDataHeader ; 1d75
+ db $40 ; tile backup
+ db 0, 0 ; start coords
+ db 17, 19 ; end coords
+ dw 0
+ db 1 ; default option
+; 1d7d
+
+Call_ExitMenu:: ; 1d7d
+ call ExitMenu
+ ret
+; 1d81
+
+VerticalMenu::
+ xor a
+ ld [hBGMapMode], a
+ call MenuBox
+ call UpdateSprites
+ call PlaceVerticalMenuItems
+ call ApplyTilemap
+ call CopyMenuData2
+ ld a, [wMenuData2Flags]
+ bit 7, a
+ jr z, .cancel
+ call InitVerticalMenuCursor
+ call StaticMenuJoypad
+ call MenuClickSound
+ bit 1, a
+ jr z, .okay
+.cancel
+ scf
+ ret
+
+.okay
+ and a
+ ret
+; 0x1dab
+
+GetMenu2:: ; 1dab
+ call LoadMenuDataHeader
+ call VerticalMenu
+ call CloseWindow
+ ld a, [wMenuCursorY]
+ ret
+; 1db8
+
+CopyNameFromMenu::
+ push hl
+ push bc
+ push af
+ ld hl, wMenuData2Pointer
+ ld a, [hli]
+ ld h, [hl]
+ ld l, a
+ inc hl
+ inc hl
+ pop af
+ call GetNthString
+ ld d, h
+ ld e, l
+ call CopyName1
+ pop bc
+ pop hl
+ ret
+; 0x1dcf
+
+
+YesNoBox:: ; 1dcf
+ lb bc, SCREEN_WIDTH - 6, 7
+
+PlaceYesNoBox:: ; 1dd2
+ jr _YesNoBox
+
+PlaceGenericTwoOptionBox:: ; 1dd4
+ call LoadMenuDataHeader
+ jr InterpretTwoOptionMenu
+
+_YesNoBox:: ; 1dd9
+; Return nc (yes) or c (no).
+ push bc
+ ld hl, YesNoMenuDataHeader
+ call CopyMenuDataHeader
+ pop bc
+; This seems to be an overflow prevention, but
+; it was coded wrong.
+ ld a, b
+ cp SCREEN_WIDTH - 6
+ jr nz, .okay ; should this be "jr nc"?
+ ld a, SCREEN_WIDTH - 6
+ ld b, a
+
+.okay
+ ld a, b
+ ld [wMenuBorderLeftCoord], a
+ add 5
+ ld [wMenuBorderRightCoord], a
+ ld a, c
+ ld [wMenuBorderTopCoord], a
+ add 4
+ ld [wMenuBorderBottomCoord], a
+ call PushWindow
+
+InterpretTwoOptionMenu:: ; 1dfe
+ call VerticalMenu
+ push af
+ ld c, $f
+ call DelayFrames
+ call CloseWindow
+ pop af
+ jr c, .no
+ ld a, [wMenuCursorY]
+ cp 2 ; no
+ jr z, .no
+ and a
+ ret
+
+.no
+ ld a, 2
+ ld [wMenuCursorY], a
+ scf
+ ret
+; 1e1d
+
+YesNoMenuDataHeader:: ; 1e1d
+ db $40 ; tile backup
+ db 5, 10 ; start coords
+ db 9, 15 ; end coords
+ dw .MenuData2
+ db 1 ; default option
+; 1e25
+
+.MenuData2 ; 1e25
+ db $c0 ; flags
+ db 2
+ db "YES@"
+ db "NO@"
+; 1e2e
+
+OffsetMenuDataHeader:: ; 1e2e
+ call _OffsetMenuDataHeader
+ call PushWindow
+ ret
+; 1e35
+
+_OffsetMenuDataHeader:: ; 1e35
+ push de
+ call CopyMenuDataHeader
+ pop de
+ ld a, [wMenuBorderLeftCoord]
+ ld h, a
+ ld a, [wMenuBorderRightCoord]
+ sub h
+ ld h, a
+ ld a, d
+ ld [wMenuBorderLeftCoord], a
+ add h
+ ld [wMenuBorderRightCoord], a
+ ld a, [wMenuBorderTopCoord]
+ ld l, a
+ ld a, [wMenuBorderBottomCoord]
+ sub l
+ ld l, a
+ ld a, e
+ ld [wMenuBorderTopCoord], a
+ add l
+ ld [wMenuBorderBottomCoord], a
+ ret
+; 1e5d
+
+DoNthMenu:: ; 1e5d
+ call MenuFunc_1e7f
+ call MenuWriteText
+ call Function1eff
+ call Function1f23
+ call GetMenuJoypad
+ call MenuClickSound
+ ret
+; 1e70
+
+SetUpMenu:: ; 1e70
+ call MenuFunc_1e7f ; ???
+ call MenuWriteText
+ call Function1eff ; set up selection pointer
+ ld hl, w2DMenuFlags1
+ set 7, [hl]
+ ret
+
+MenuFunc_1e7f::
+ call CopyMenuData2
+ call GetMenuIndexSet
+ call Function1ea6
+ call MenuBox
+ ret
+
+MenuWriteText::
+ xor a
+ ld [hBGMapMode], a
+ call GetMenuIndexSet ; sort out the text
+ call Function1eda ; actually write it
+ call Function2e31
+ ld a, [hOAMUpdate]
+ push af
+ ld a, $1
+ ld [hOAMUpdate], a
+ call ApplyTilemap
+ pop af
+ ld [hOAMUpdate], a
+ ret
+; 0x1ea6
+
+Function1ea6:: ; 1ea6
+ ld a, [wMenuBorderLeftCoord]
+ ld c, a
+ ld a, [wMenuBorderRightCoord]
+ sub c
+ ld c, a
+ ld a, [wMenuData2Items]
+ add a
+ inc a
+ ld b, a
+ ld a, [wMenuBorderTopCoord]
+ add b
+ ld [wMenuBorderBottomCoord], a
+ ret
+; 1ebd
+
+GetMenuIndexSet:: ; 1ebd
+ ld hl, wMenuData2IndicesPointer
+ ld a, [hli]
+ ld h, [hl]
+ ld l, a
+ ld a, [wWhichIndexSet]
+ and a
+ jr z, .skip
+ ld b, a
+ ld c, -1
+.loop
+ ld a, [hli]
+ cp c
+ jr nz, .loop
+ dec b
+ jr nz, .loop
+
+.skip
+ ld d, h
+ ld e, l
+ ld a, [hl]
+ ld [wMenuData2Items], a
+ ret
+; 1eda
+
+Function1eda:: ; 1eda
+ call MenuBoxCoord2Tile
+ ld bc, 2 * SCREEN_WIDTH + 2
+ add hl, bc
+.loop
+ inc de
+ ld a, [de]
+ cp -1
+ ret z
+ ld [MenuSelection], a
+ push de
+ push hl
+ ld d, h
+ ld e, l
+ ld hl, wMenuData2DisplayFunctionPointer
+ call .__wMenuData2DisplayFunction__
+ pop hl
+ ld de, 2 * SCREEN_WIDTH
+ add hl, de
+ pop de
+ jr .loop
+; 1efb
+
+.__wMenuData2DisplayFunction__ ; 1efb
+ ld a, [hli]
+ ld h, [hl]
+ ld l, a
+ jp [hl]
+; 1eff
+
+Function1eff:: ; 1eff
+ call InitVerticalMenuCursor
+ ld hl, wMenuJoypadFilter
+ ld a, [wMenuData2Flags]
+ bit 3, a
+ jr z, .disallow_select
+ set START_F, [hl]
+
+.disallow_select
+ ld a, [wMenuData2Flags]
+ bit 2, a
+ jr z, .disallow_left_right
+ set D_LEFT_F, [hl]
+ set D_RIGHT_F, [hl]
+
+.disallow_left_right
+ ret
+; 1f1a
+
+
+Function1f1a:: ; 1f1a
+ call ScrollingMenuJoypad
+ ld hl, wMenuJoypadFilter
+ and [hl]
+ jr Function1f2a
+; 1f23
+
+Function1f23:: ; 1f23
+ xor a
+ ld [wMenuJoypad], a
+ call StaticMenuJoypad
+; 1f2a
+
+Function1f2a:: ; 1f2a
+ bit A_BUTTON_F, a
+ jr nz, .a_button
+ bit B_BUTTON_F, a
+ jr nz, .b_start
+ bit START_F, a
+ jr nz, .b_start
+ bit D_RIGHT_F, a
+ jr nz, .d_right
+ bit D_LEFT_F, a
+ jr nz, .d_left
+ xor a
+ ld [wMenuJoypad], a
+ jr .done
+
+.d_right
+ ld a, D_RIGHT
+ ld [wMenuJoypad], a
+ jr .done
+
+.d_left
+ ld a, D_LEFT
+ ld [wMenuJoypad], a
+ jr .done
+
+.a_button
+ ld a, A_BUTTON
+ ld [wMenuJoypad], a
+
+.done
+ call GetMenuIndexSet
+ ld a, [wMenuCursorY]
+ ld l, a
+ ld h, $0
+ add hl, de
+ ld a, [hl]
+ ld [MenuSelection], a
+ ld a, [wMenuCursorY]
+ ld [wMenuCursorBuffer], a
+ and a
+ ret
+
+.b_start
+ ld a, B_BUTTON
+ ld [wMenuJoypad], a
+ ld a, -1
+ ld [MenuSelection], a
+ scf
+ ret
+; 1f79
+
+PlaceMenuStrings:: ; 1f79
+ push de
+ ld hl, wMenuData2PointerTableAddr
+ ld a, [hli]
+ ld h, [hl]
+ ld l, a
+ ld a, [MenuSelection]
+ call GetNthString
+ ld d, h
+ ld e, l
+ pop hl
+ call PlaceString
+ ret
+; 1f8d
+
+PlaceNthMenuStrings:: ; 1f8d
+ push de
+ ld a, [MenuSelection]
+ call GetMenuDataPointerTableEntry
+ inc hl
+ inc hl
+ ld a, [hli]
+ ld d, [hl]
+ ld e, a
+ pop hl
+ call PlaceString
+ ret
+; 1f9e
+
+Function1f9e:: ; 1f9e
+; unreferenced
+ call GetMenuDataPointerTableEntry
+ inc hl
+ inc hl
+ ld a, [hli]
+ ld d, [hl]
+ ld e, a
+ ret
+; 1fa7
+
+MenuJumptable:: ; 1fa7
+ ld a, [MenuSelection]
+ call GetMenuDataPointerTableEntry
+ ld a, [hli]
+ ld h, [hl]
+ ld l, a
+ jp [hl]
+; 1fb1
+
+GetMenuDataPointerTableEntry:: ; 1fb1
+ ld e, a
+ ld d, $0
+ ld hl, wMenuData2PointerTableAddr
+ ld a, [hli]
+ ld h, [hl]
+ ld l, a
+ add hl, de
+ add hl, de
+ add hl, de
+ add hl, de
+ ret
+; 1fbf
+
+ClearWindowData:: ; 1fbf
+ ld hl, wWindowStackPointer
+ call .bytefill
+ ld hl, wMenuDataHeader
+ call .bytefill
+ ld hl, wMenuData2Flags
+ call .bytefill
+ ld hl, w2DMenuCursorInitY
+ call .bytefill
+
+ ld a, [rSVBK]
+ push af
+ ld a, $7
+ ld [rSVBK], a
+
+ xor a
+ ld hl, wWindowStackBottom
+ ld [hld], a
+ ld [hld], a
+ ld a, l
+ ld [wWindowStackPointer], a
+ ld a, h
+ ld [wWindowStackPointer + 1], a
+
+ pop af
+ ld [rSVBK], a
+ ret
+; 1ff0
+
+.bytefill: ; 1ff0
+ ld bc, $0010
+ xor a
+ call ByteFill
+ ret
+; 1ff8
+
+MenuClickSound:: ; 1ff8
+ push af
+ and A_BUTTON | B_BUTTON
+ jr z, .nosound
+ ld hl, wMenuFlags
+ bit 3, [hl]
+ jr nz, .nosound
+ call PlayClickSFX
+.nosound
+ pop af
+ ret
+; 2009
+
+
+PlayClickSFX:: ; 2009
+ push de
+ ld de, SFX_READ_TEXT_2
+ call PlaySFX
+ pop de
+ ret
+; 0x2012
+
+MenuTextBoxWaitButton:: ; 2012
+ call MenuTextBox
+ call WaitButton
+ call ExitMenu
+ ret
+; 201c
+
+Place2DMenuItemName:: ; 201c
+ ld [hBuffer], a
+ ld a, [hROMBank]
+ push af
+ ld a, [hBuffer]
+ rst Bankswitch
+
+ call PlaceString
+ pop af
+ rst Bankswitch
+
+ ret
+; 202a
+
+_2DMenu:: ; 202a
+ ld a, [hROMBank]
+ ld [wMenuData2_2DMenuItemStringsBank], a
+ callba _2DMenu_
+ ld a, [wMenuCursorBuffer]
+ ret
+; 2039
+
+InterpretBattleMenu:: ; 2039
+ ld a, [hROMBank]
+ ld [wMenuData2_2DMenuItemStringsBank], a
+ callba _InterpretBattleMenu
+ ld a, [wMenuCursorBuffer]
+ ret
+; 2048
+
+InterpretMobileMenu:: ; 2048
+ ld a, [hROMBank]
+ ld [wMenuData2_2DMenuItemStringsBank], a
+ callba _InterpretMobileMenu
+ ld a, [wMenuCursorBuffer]
+ ret
+; 2057
diff --git a/home/mobile.asm b/home/mobile.asm
new file mode 100644
index 00000000..32692f6a
--- /dev/null
+++ b/home/mobile.asm
@@ -0,0 +1,315 @@
+Function3e32:: ; 3e32
+; Mobile
+ cp $2
+ ld [$c988], a
+ ld a, l
+ ld [$c986], a
+ ld a, h
+ ld [$c987], a
+ jr nz, .asm_3e4f
+
+ ld [$c982], a
+ ld a, l
+ ld [$c981], a
+ ld hl, $c983
+ ld a, c
+ ld [hli], a
+ ld a, b
+ ld [hl], a
+
+.asm_3e4f
+ ld hl, $c822
+ set 6, [hl]
+ ld a, [hROMBank]
+ push af
+ ld a, BANK(Function110030)
+ ld [$c981], a
+ rst Bankswitch
+
+ jp Function110030
+; 3e60
+
+Function3e60:: ; 3e60
+ ld [$c986], a
+ ld a, l
+ ld [$c987], a
+ ld a, h
+ ld [$c988], a
+
+ pop bc
+ ld a, b
+ ld [$c981], a
+ rst Bankswitch
+
+ ld hl, $c822
+ res 6, [hl]
+ ld hl, $c987
+ ld a, [hli]
+ ld h, [hl]
+ ld l, a
+ ld a, [$c986]
+ ret
+; 3e80
+
+MobileReceive:: ; 3e80
+ ld a, [hROMBank]
+ push af
+ ld a, BANK(_MobileReceive)
+ ld [$c981], a
+ rst Bankswitch
+
+ call _MobileReceive
+ pop bc
+ ld a, b
+ ld [$c981], a
+ rst Bankswitch
+
+ ret
+; 3e93
+
+
+Timer:: ; 3e93
+ push af
+ push bc
+ push de
+ push hl
+
+ ld a, [hMobile]
+ and a
+ jr z, .pop_ret
+
+ xor a
+ ld [rTAC], a
+
+; Turn off timer interrupt
+ ld a, [rIF]
+ and 1 << VBLANK | 1 << LCD_STAT | 1 << SERIAL | 1 << JOYPAD
+ ld [rIF], a
+
+ ld a, [$c86a]
+ or a
+ jr z, .pop_ret
+
+ ld a, [$c822]
+ bit 1, a
+ jr nz, .skip_Timer
+
+ ld a, [rSC]
+ and 1 << rSC_ON
+ jr nz, .skip_Timer
+
+ ld a, [hROMBank]
+ push af
+ ld a, BANK(_Timer)
+ ld [$c981], a
+ rst Bankswitch
+
+ call _Timer
+
+ pop bc
+ ld a, b
+ ld [$c981], a
+ rst Bankswitch
+
+.skip_Timer
+ ld a, [rTMA]
+ ld [rTIMA], a
+
+ ld a, 1 << rTAC_ON | rTAC_65536_HZ
+ ld [rTAC], a
+
+.pop_ret
+ pop hl
+ pop de
+ pop bc
+ pop af
+ reti
+; 3ed7
+
+Function3ed7:: ; 3ed7
+; unreferenced
+ ld [$dc02], a
+ ld a, [hROMBank]
+ push af
+ ld a, BANK(Function114243)
+ rst Bankswitch
+
+ call Function114243
+ pop bc
+ ld a, b
+ rst Bankswitch
+
+ ld a, [$dc02]
+ ret
+; 3eea
+
+Function3eea:: ; 3eea
+ push hl
+ push bc
+ ld de, AttrMap - TileMap
+ add hl, de
+ inc b
+ inc b
+ inc c
+ inc c
+ call Function3f35
+ pop bc
+ pop hl
+ call MobileHome_PlaceBox
+ ret
+; 3efd
+
+Function3efd:: ; 3efd
+; unreferenced
+ push hl
+ hlcoord 0, 12
+ ld b, 4
+ ld c, 18
+ call .fill_attr
+ pop hl
+ call PrintTextBoxText
+ ret
+; 3f0d
+
+.fill_attr
+ push hl
+ push bc
+ ld de, AttrMap - TileMap
+ add hl, de
+ inc b
+ inc b
+ inc c
+ inc c
+ call Function3f35
+ pop bc
+ pop hl
+ call TextBoxBorder
+ ret
+; 3f20
+
+Function3f20:: ; 3f20
+ hlcoord 0, 0, AttrMap
+ ld b, 6
+ ld c, 20
+ call Function3f35
+ hlcoord 0, 0
+ ld b, 4
+ ld c, 18
+ call MobileHome_PlaceBox
+ ret
+; 3f35
+
+Function3f35:: ; 3f35
+ ld a, 6
+ ld de, SCREEN_WIDTH
+.row
+ push bc
+ push hl
+.col
+ ld [hli], a
+ dec c
+ jr nz, .col
+ pop hl
+ add hl, de
+ pop bc
+ dec b
+ jr nz, .row
+ ret
+; 3f47
+
+MobileHome_PlaceBox: ; 3f47
+ push bc
+ call .FillTop
+ pop bc
+.RowLoop
+ push bc
+ call .FillMiddle
+ pop bc
+ dec b
+ jr nz, .RowLoop
+ call .FillBottom
+ ret
+; 3f58
+
+.FillTop
+ ld a, $63
+ ld d, $62
+ ld e, $64
+ jr .FillRow
+
+.FillBottom
+ ld a, $68
+ ld d, $67
+ ld e, $69
+ jr .FillRow
+
+.FillMiddle
+ ld a, $7f
+ ld d, $65
+ ld e, $66
+
+.FillRow
+ push hl
+ ld [hl], d
+ inc hl
+.FillLoop
+ ld [hli], a
+ dec c
+ jr nz, .FillLoop
+ ld [hl], e
+ pop hl
+ ld de, SCREEN_WIDTH
+ add hl, de
+ ret
+; 3f7c
+
+Function3f7c:: ; 3f7c
+ call MenuBoxCoord2Tile
+ call GetMenuBoxDims
+ dec b
+ dec c
+ call Function3eea
+ ret
+; 3f88
+
+Function3f88:: ; 3f88
+ ld hl, wDecompressScratch
+ ld b, 0
+.row
+ push bc
+ ld c, 1 tiles / 2
+.col
+ ld a, [de]
+ inc de
+ cpl
+ ld [hl], 0
+ inc hl
+ ld [hli], a
+ dec c
+ jr nz, .col
+ pop bc
+ dec c
+ jr nz, .row
+ ret
+; 3f9f
+
+Function3f9f:: ; 3f9f
+ ld hl, wDecompressScratch
+.row
+ push bc
+ ld c, 1 tiles / 2
+.col
+ ld a, [de]
+ inc de
+ inc de
+ cpl
+ ld [hl], $0
+ inc hl
+ ld [hli], a
+ dec c
+ jr nz, .col
+ pop bc
+ dec c
+ jr nz, .row
+ ret
+; 3fb5
diff --git a/home/movement.asm b/home/movement.asm
new file mode 100644
index 00000000..f962c831
--- /dev/null
+++ b/home/movement.asm
@@ -0,0 +1,208 @@
+InitMovementBuffer:: ; 1b1e
+ ld [wMovementBufferPerson], a
+ xor a
+ ld [wMovementBufferCount], a
+ ld a, $0 ; useless
+ ld [wd004], a
+ ld a, $7
+ ld [wd005], a
+ ld a, $d0
+ ld [wd006], a
+ ret
+; 1b35
+
+DecrementMovementBufferCount:: ; 1b35
+ ld a, [wMovementBufferCount]
+ and a
+ ret z
+ dec a
+ ld [wMovementBufferCount], a
+ ret
+; 1b3f
+
+AppendToMovementBuffer:: ; 1b3f
+ push hl
+ push de
+ ld hl, wMovementBufferCount
+ ld e, [hl]
+ inc [hl]
+ ld d, 0
+ ld hl, MovementBuffer
+ add hl, de
+ ld [hl], a
+ pop de
+ pop hl
+ ret
+; 1b50
+
+AppendToMovementBufferNTimes:: ; 1b50
+ push af
+ ld a, c
+ and a
+ jr nz, .okay
+ pop af
+ ret
+
+.okay
+ pop af
+.loop
+ call AppendToMovementBuffer
+ dec c
+ jr nz, .loop
+ ret
+; 1b5f
+
+ComputePathToWalkToPlayer:: ; 1b5f
+ push af
+; compare x coords, load left/right into h, and x distance into d
+ ld a, b
+ sub d
+ ld h, LEFT
+ jr nc, .got_x_distance
+ dec a
+ cpl
+ ld h, RIGHT
+
+.got_x_distance
+ ld d, a
+; compare y coords, load up/down into l, and y distance into e
+ ld a, c
+ sub e
+ ld l, UP
+ jr nc, .got_y_distance
+ dec a
+ cpl
+ ld l, DOWN
+
+.got_y_distance
+ ld e, a
+; if the x distance is less than the y distance, swap h and l, and swap d and e
+ cp d
+ jr nc, .done
+ ld a, h
+ ld h, l
+ ld l, a
+ ld a, d
+ ld d, e
+ ld e, a
+
+.done
+ pop af
+ ld b, a
+; Add movement in the longer direction first...
+ ld a, h
+ call .GetMovementData
+ ld c, d
+ call AppendToMovementBufferNTimes
+; ... then add the shorter direction.
+ ld a, l
+ call .GetMovementData
+ ld c, e
+ call AppendToMovementBufferNTimes
+ ret
+; 1b92
+
+.GetMovementData: ; 1b92
+ push de
+ push hl
+ ld l, b
+ ld h, 0
+rept 2
+ add hl, hl
+endr
+ ld e, a
+ ld d, 0
+ add hl, de
+ ld de, .MovementData
+ add hl, de
+ ld a, [hl]
+ pop hl
+ pop de
+ ret
+; 1ba5
+
+.MovementData
+ slow_step_down
+ slow_step_up
+ slow_step_left
+ slow_step_right
+ step_down
+ step_up
+ step_left
+ step_right
+ big_step_down
+ big_step_up
+ big_step_left
+ big_step_right
+; 1bb1
+
+SetMenuAttributes:: ; 1bb1
+ push hl
+ push bc
+ ld hl, w2DMenuCursorInitY
+ ld b, $8
+.loop
+ ld a, [de]
+ inc de
+ ld [hli], a
+ dec b
+ jr nz, .loop
+ ld a, $1
+rept 2
+ ld [hli], a
+endr
+ xor a
+rept 3
+ ld [hli], a
+endr
+ pop bc
+ pop hl
+ ret
+; 1bc9
+
+StaticMenuJoypad:: ; 1bc9
+ callab _StaticMenuJoypad
+ call GetMenuJoypad
+ ret
+; 1bd3
+
+ScrollingMenuJoypad:: ; 1bd3
+ callab _ScrollingMenuJoypad
+ call GetMenuJoypad
+ ret
+; 1bdd
+
+GetMenuJoypad:: ; 1bdd
+ push bc
+ push af
+ ld a, [hJoyLast]
+ and D_PAD
+ ld b, a
+ ld a, [hJoyPressed]
+ and BUTTONS
+ or b
+ ld b, a
+ pop af
+ ld a, b
+ pop bc
+ ret
+; 1bee
+
+PlaceHollowCursor:: ; 1bee
+ ld hl, wCursorCurrentTile
+ ld a, [hli]
+ ld h, [hl]
+ ld l, a
+ ld [hl], "▷"
+ ret
+; 1bf7
+
+HideCursor:: ; 1bf7
+ ld hl, wCursorCurrentTile
+ ld a, [hli]
+ ld h, [hl]
+ ld l, a
+ ld [hl], " "
+ ret
+; 1c00
+
diff --git a/home/palettes.asm b/home/palettes.asm
new file mode 100644
index 00000000..2f179209
--- /dev/null
+++ b/home/palettes.asm
@@ -0,0 +1,365 @@
+; Functions dealing with palettes.
+
+
+UpdatePalsIfCGB:: ; c2f
+; update bgp data from BGPals
+; update obp data from OBPals
+; return carry if successful
+
+; check cgb
+ ld a, [hCGB]
+ and a
+ ret z
+
+
+UpdateCGBPals:: ; c33
+; return carry if successful
+; any pals to update?
+ ld a, [hCGBPalUpdate]
+ and a
+ ret z
+
+
+ForceUpdateCGBPals:: ; c37
+
+ ld a, [rSVBK]
+ push af
+ ld a, 5 ; BANK(BGPals)
+ ld [rSVBK], a
+
+ ld hl, BGPals ; 5:d080
+
+; copy 8 pals to bgpd
+ ld a, %10000000 ; auto increment, index 0
+ ld [rBGPI], a
+ ld c, rBGPD % $100
+ ld b, 4 ; NUM_PALS / 2
+.bgp
+rept 2 palettes
+ ld a, [hli]
+ ld [$ff00+c], a
+endr
+
+ dec b
+ jr nz, .bgp
+
+; hl is now 5:d0c0 OBPals
+
+; copy 8 pals to obpd
+ ld a, %10000000 ; auto increment, index 0
+ ld [rOBPI], a
+ ld c, rOBPD % $100
+ ld b, 4 ; NUM_PALS / 2
+.obp
+rept 2 palettes
+ ld a, [hli]
+ ld [$ff00+c], a
+endr
+
+ dec b
+ jr nz, .obp
+
+ pop af
+ ld [rSVBK], a
+
+; clear pal update queue
+ xor a
+ ld [hCGBPalUpdate], a
+
+ scf
+ ret
+; c9f
+
+
+DmgToCgbBGPals:: ; c9f
+; exists to forego reinserting cgb-converted image data
+
+; input: a -> bgp
+
+ ld [rBGP], a
+ push af
+
+; Don't need to be here if DMG
+ ld a, [hCGB]
+ and a
+ jr z, .end
+
+ push hl
+ push de
+ push bc
+ ld a, [rSVBK]
+ push af
+
+ ld a, 5 ; gfx
+ ld [rSVBK], a
+
+; copy & reorder bg pal buffer
+ ld hl, BGPals ; to
+ ld de, UnknBGPals ; from
+; order
+ ld a, [rBGP]
+ ld b, a
+; all pals
+ ld c, 8
+ call CopyPals
+; request pal update
+ ld a, 1
+ ld [hCGBPalUpdate], a
+
+ pop af
+ ld [rSVBK], a
+ pop bc
+ pop de
+ pop hl
+.end
+ pop af
+ ret
+; ccb
+
+
+DmgToCgbObjPals:: ; ccb
+; exists to forego reinserting cgb-converted image data
+
+; input: d -> obp1
+; e -> obp2
+
+ ld a, e
+ ld [rOBP0], a
+ ld a, d
+ ld [rOBP1], a
+
+ ld a, [hCGB]
+ and a
+ ret z
+
+ push hl
+ push de
+ push bc
+ ld a, [rSVBK]
+ push af
+
+ ld a, 5
+ ld [rSVBK], a
+
+; copy & reorder obj pal buffer
+ ld hl, OBPals ; to
+ ld de, UnknOBPals ; from
+; order
+ ld a, [rOBP0]
+ ld b, a
+; all pals
+ ld c, 8
+ call CopyPals
+; request pal update
+ ld a, 1
+ ld [hCGBPalUpdate], a
+
+ pop af
+ ld [rSVBK], a
+ pop bc
+ pop de
+ pop hl
+ ret
+; cf8
+
+
+DmgToCgbObjPal0:: ; cf8
+ ld [rOBP0], a
+ push af
+
+; Don't need to be here if not CGB
+ ld a, [hCGB]
+ and a
+ jr z, .dmg
+
+ push hl
+ push de
+ push bc
+
+ ld a, [rSVBK]
+ push af
+ ld a, 5 ; gfx
+ ld [rSVBK], a
+
+ ld hl, OBPals
+ ld de, UnknOBPals
+ ld a, [rOBP0]
+ ld b, a
+ ld c, 1
+ call CopyPals
+ ld a, 1
+ ld [hCGBPalUpdate], a
+
+ pop af
+ ld [rSVBK], a
+
+ pop bc
+ pop de
+ pop hl
+
+.dmg
+ pop af
+ ret
+; d24
+
+DmgToCgbObjPal1:: ; d24
+ ld [rOBP1], a
+ push af
+
+ ld a, [hCGB]
+ and a
+ jr z, .dmg
+
+ push hl
+ push de
+ push bc
+
+ ld a, [rSVBK]
+ push af
+ ld a, 5 ; gfx
+ ld [rSVBK], a
+
+ ld hl, OBPals + 1 palettes
+ ld de, UnknOBPals + 1 palettes
+ ld a, [rOBP1]
+ ld b, a
+ ld c, 1
+ call CopyPals
+ ld a, 1
+ ld [hCGBPalUpdate], a
+
+ pop af
+ ld [rSVBK], a
+
+ pop bc
+ pop de
+ pop hl
+
+.dmg
+ pop af
+ ret
+; d50
+
+
+
+CopyPals:: ; d50
+; copy c palettes in order b from de to hl
+
+ push bc
+ ld c, 4 ; NUM_PAL_COLORS
+.loop
+ push de
+ push hl
+
+; get pal color
+ ld a, b
+ and %11 ; color
+; 2 bytes per color
+ add a
+ ld l, a
+ ld h, 0
+ add hl, de
+ ld e, [hl]
+ inc hl
+ ld d, [hl]
+
+; dest
+ pop hl
+; write color
+ ld [hl], e
+ inc hl
+ ld [hl], d
+ inc hl
+; next pal color
+ srl b
+ srl b
+; source
+ pop de
+; done pal?
+ dec c
+ jr nz, .loop
+
+; de += 8 (next pal)
+ ld a, 1 palettes ; NUM_PAL_COLORS * 2 ; bytes per pal
+ add e
+ jr nc, .ok
+ inc d
+.ok
+ ld e, a
+
+; how many more pals?
+ pop bc
+ dec c
+ jr nz, CopyPals
+ ret
+; d79
+
+
+ClearVBank1:: ; d79
+ ld a, [hCGB]
+ and a
+ ret z
+
+ ld a, 1
+ ld [rVBK], a
+
+ ld hl, VTiles0
+ ld bc, VRAM_End - VTiles0
+ xor a
+ call ByteFill
+
+ ld a, 0
+ ld [rVBK], a
+ ret
+; d90
+
+
+ret_d90:: ; d90
+ ret
+; d91
+
+
+Special_ReloadSpritesNoPalettes:: ; d91
+ ld a, [hCGB]
+ and a
+ ret z
+ ld a, [rSVBK]
+ push af
+ ld a, 5 ; BANK(BGPals)
+ ld [rSVBK], a
+ ld hl, BGPals
+ ld bc, $40 + $10
+ xor a
+ call ByteFill
+ pop af
+ ld [rSVBK], a
+ ld a, 1
+ ld [hCGBPalUpdate], a
+ call DelayFrame
+ ret
+; db1
+
+
+FarCallSwapTextboxPalettes:: ; db1
+ ld a, [hROMBank]
+ push af
+ ld a, BANK(SwapTextboxPalettes)
+ rst Bankswitch
+ call SwapTextboxPalettes
+ pop af
+ rst Bankswitch
+ ret
+; dbd
+
+FarCallScrollBGMapPalettes:: ; dbd
+ ld a, [hROMBank]
+ push af
+ ld a, BANK(ScrollBGMapPalettes)
+ rst Bankswitch
+
+ call ScrollBGMapPalettes
+
+ pop af
+ rst Bankswitch
+ ret
+; dc9
diff --git a/home/pokedex_flags.asm b/home/pokedex_flags.asm
new file mode 100644
index 00000000..7aacd498
--- /dev/null
+++ b/home/pokedex_flags.asm
@@ -0,0 +1,38 @@
+SetSeenAndCaughtMon:: ; 3380
+ push af
+ ld c, a
+ ld hl, PokedexCaught
+ ld b, SET_FLAG
+ call PokedexFlagAction
+ pop af
+ ; fallthrough
+; 338b
+
+SetSeenMon:: ; 338b
+ ld c, a
+ ld hl, PokedexSeen
+ ld b, SET_FLAG
+ jr PokedexFlagAction
+; 3393
+
+CheckCaughtMon:: ; 3393
+ ld c, a
+ ld hl, PokedexCaught
+ ld b, CHECK_FLAG
+ jr PokedexFlagAction
+; 339b
+
+CheckSeenMon:: ; 339b
+ ld c, a
+ ld hl, PokedexSeen
+ ld b, CHECK_FLAG
+ ; fallthrough
+; 33a1
+
+PokedexFlagAction:: ; 33a1
+ ld d, 0
+ predef FlagPredef
+ ld a, c
+ and a
+ ret
+; 33ab
diff --git a/home/predef.asm b/home/predef.asm
new file mode 100644
index 00000000..03f74146
--- /dev/null
+++ b/home/predef.asm
@@ -0,0 +1,53 @@
+Predef:: ; 2d83
+; Call predefined function a.
+; Preserves bc, de, hl and f.
+
+ ld [PredefID], a
+ ld a, [hROMBank]
+ push af
+
+ ld a, BANK(GetPredefPointer)
+ rst Bankswitch
+ call GetPredefPointer ; stores hl in PredefTemp
+
+; Switch to the new function's bank
+ rst Bankswitch
+
+; Instead of directly calling stuff,
+; push it to the stack in reverse.
+
+ ld hl, .Return
+ push hl
+
+; Call the Predef function
+ ld a, [PredefAddress]
+ ld h, a
+ ld a, [PredefAddress + 1]
+ ld l, a
+ push hl
+
+; Get hl back
+ ld a, [PredefTemp]
+ ld h, a
+ ld a, [PredefTemp + 1]
+ ld l, a
+ ret
+
+.Return
+; Clean up after the Predef call
+
+ ld a, h
+ ld [PredefTemp], a
+ ld a, l
+ ld [PredefTemp+1], a
+
+ pop hl
+ ld a, h
+ rst Bankswitch
+
+ ld a, [PredefTemp]
+ ld h, a
+ ld a, [PredefTemp + 1]
+ ld l, a
+ ret
+; 2dba
diff --git a/home/random.asm b/home/random.asm
new file mode 100644
index 00000000..ae39f439
--- /dev/null
+++ b/home/random.asm
@@ -0,0 +1,84 @@
+Random:: ; 2f8c
+; A simple hardware-based random number generator (RNG).
+
+; Two random numbers are generated by adding and subtracting
+; the divider to the respective values every time it's called.
+
+; The divider is a register that increments at a rate of 16384Hz.
+; For comparison, the Game Boy operates at a clock speed of 4.2MHz.
+
+; Additionally, an equivalent function is executed in VBlank.
+
+; This leaves a with the value in hRandomSub.
+
+ push bc
+
+ ld a, [rDIV]
+ ld b, a
+ ld a, [hRandomAdd]
+ adc b
+ ld [hRandomAdd], a
+
+ ld a, [rDIV]
+ ld b, a
+ ld a, [hRandomSub]
+ sbc b
+ ld [hRandomSub], a
+
+ pop bc
+ ret
+; 2f9f
+
+BattleRandom:: ; 2f9f
+; _BattleRandom lives in another bank.
+
+; It handles all RNG calls in the battle engine, allowing
+; link battles to remain in sync using a shared PRNG.
+
+ ld a, [hROMBank]
+ push af
+ ld a, BANK(_BattleRandom)
+ rst Bankswitch
+
+ call _BattleRandom
+
+ ld [PredefTemp + 1], a
+ pop af
+ rst Bankswitch
+ ld a, [PredefTemp + 1]
+ ret
+; 2fb1
+
+
+RandomRange:: ; 2fb1
+; Return a random number between 0 and a (non-inclusive).
+
+ push bc
+ ld c, a
+
+ ; b = $100 % c
+ xor a
+ sub c
+.mod
+ sub c
+ jr nc, .mod
+ add c
+ ld b, a
+
+ ; Get a random number
+ ; from 0 to $ff - b.
+ push bc
+.loop
+ call Random
+ ld a, [hRandomAdd]
+ ld c, a
+ add b
+ jr c, .loop
+ ld a, c
+ pop bc
+
+ call SimpleDivide
+
+ pop bc
+ ret
+; 2fcb
diff --git a/home/rtc.asm b/home/rtc.asm
new file mode 100644
index 00000000..9fb71c0b
--- /dev/null
+++ b/home/rtc.asm
@@ -0,0 +1,24 @@
+RTC:: ; 46f
+; update time and time-sensitive palettes
+
+; rtc enabled?
+ ld a, [wSpriteUpdatesEnabled]
+ cp 0
+ ret z
+
+ call UpdateTime
+
+; obj update on?
+ ld a, [VramState]
+ bit 0, a ; obj update
+ ret z
+
+TimeOfDayPals:: ; 47e
+ callab _TimeOfDayPals
+ ret
+; 485
+
+UpdateTimePals:: ; 485
+ callab _UpdateTimePals
+ ret
+; 48c
diff --git a/home/serial.asm b/home/serial.asm
new file mode 100644
index 00000000..ad7d9610
--- /dev/null
+++ b/home/serial.asm
@@ -0,0 +1,410 @@
+Serial:: ; 6ef
+; The serial interrupt.
+
+ push af
+ push bc
+ push de
+ push hl
+
+ ld a, [hMobileReceive]
+ and a
+ jr nz, .mobile
+
+ ld a, [wc2d4]
+ bit 0, a
+ jr nz, .printer
+
+ ld a, [hLinkPlayerNumber]
+ inc a ; is it equal to -1?
+ jr z, .init_player_number
+
+ ld a, [rSB]
+ ld [hSerialReceive], a
+
+ ld a, [hSerialSend]
+ ld [rSB], a
+
+ ld a, [hLinkPlayerNumber]
+ cp $2
+ jr z, .player2
+
+ ld a, 0 << rSC_ON
+ ld [rSC], a
+ ld a, 1 << rSC_ON
+ ld [rSC], a
+ jr .player2
+
+.mobile
+ call MobileReceive
+ jr .end
+
+.printer
+ call PrinterReceive
+ jr .end
+
+.init_player_number
+ ld a, [rSB]
+ cp $1
+ jr z, .player1
+ cp $2
+ jr nz, .player2
+
+.player1
+ ld [hSerialReceive], a
+ ld [hLinkPlayerNumber], a
+ cp $2
+ jr z, ._player2
+
+ xor a
+ ld [rSB], a
+ ld a, $3
+ ld [rDIV], a
+
+.wait_bit_7
+ ld a, [rDIV]
+ bit 7, a
+ jr nz, .wait_bit_7
+
+ ld a, 0 << rSC_ON
+ ld [rSC], a
+ ld a, 1 << rSC_ON
+ ld [rSC], a
+ jr .player2
+
+._player2
+ xor a
+ ld [rSB], a
+
+.player2
+ ld a, $1
+ ld [hFFCA], a
+ ld a, -2
+ ld [hSerialSend], a
+
+.end
+ pop hl
+ pop de
+ pop bc
+ pop af
+ reti
+; 75f
+
+Function75f:: ; 75f
+ ld a, $1
+ ld [hFFCC], a
+.loop
+ ld a, [hl]
+ ld [hSerialSend], a
+ call Function78a
+ push bc
+ ld b, a
+ inc hl
+ ld a, $30
+.wait
+ dec a
+ jr nz, .wait
+ ld a, [hFFCC]
+ and a
+ ld a, b
+ pop bc
+ jr z, .load
+ dec hl
+ cp $fd
+ jr nz, .loop
+ xor a
+ ld [hFFCC], a
+ jr .loop
+
+.load
+ ld [de], a
+ inc de
+ dec bc
+ ld a, b
+ or c
+ jr nz, .loop
+ ret
+; 78a
+
+Function78a:: ; 78a
+ xor a
+ ld [hFFCA], a
+ ld a, [hLinkPlayerNumber]
+ cp $2
+ jr nz, .asm_79b
+ ld a, $1
+ ld [rSC], a
+ ld a, $81
+ ld [rSC], a
+
+.asm_79b
+ ld a, [hFFCA]
+ and a
+ jr nz, .asm_7e5
+ ld a, [hLinkPlayerNumber]
+ cp $1
+ jr nz, .asm_7c0
+ call Function82b
+ jr z, .asm_7c0
+ call .asm_825
+ push hl
+ ld hl, wcf5c
+ inc [hl]
+ jr nz, .asm_7b7
+ dec hl
+ inc [hl]
+
+.asm_7b7
+ pop hl
+ call Function82b
+ jr nz, .asm_79b
+ jp Function833
+
+.asm_7c0
+ ld a, [rIE]
+ and $f
+ cp $8
+ jr nz, .asm_79b
+ ld a, [wcf5d]
+ dec a
+ ld [wcf5d], a
+ jr nz, .asm_79b
+ ld a, [wcf5d + 1]
+ dec a
+ ld [wcf5d + 1], a
+ jr nz, .asm_79b
+ ld a, [hLinkPlayerNumber]
+ cp $1
+ jr z, .asm_7e5
+ ld a, $ff
+.asm_7e2
+ dec a
+ jr nz, .asm_7e2
+
+.asm_7e5
+ xor a
+ ld [hFFCA], a
+ ld a, [rIE]
+ and $f
+ sub $8
+ jr nz, .asm_7f8
+ ld [wcf5d], a
+ ld a, $50
+ ld [wcf5d + 1], a
+
+.asm_7f8
+ ld a, [hSerialReceive]
+ cp $fe
+ ret nz
+ call Function82b
+ jr z, .asm_813
+ push hl
+ ld hl, wcf5c
+ ld a, [hl]
+ dec a
+ ld [hld], a
+ inc a
+ jr nz, .asm_80d
+ dec [hl]
+
+.asm_80d
+ pop hl
+ call Function82b
+ jr z, Function833
+
+.asm_813
+ ld a, [rIE]
+ and $f
+ cp $8
+ ld a, $fe
+ ret z
+ ld a, [hl]
+ ld [hSerialSend], a
+ call DelayFrame
+ jp Function78a
+
+.asm_825
+ ld a, $f
+.asm_827
+ dec a
+ jr nz, .asm_827
+ ret
+; 82b
+
+Function82b:: ; 82b
+ push hl
+ ld hl, wcf5b
+ ld a, [hli]
+ or [hl]
+ pop hl
+ ret
+; 833
+
+Function833:: ; 833
+ dec a
+ ld [wcf5b], a
+ ld [wcf5c], a
+ ret
+; 83b
+
+Function83b:: ; 83b
+ ld hl, wPlayerLinkAction
+ ld de, wOtherPlayerLinkMode
+ ld c, $2
+ ld a, $1
+ ld [hFFCC], a
+.asm_847
+ call DelayFrame
+ ld a, [hl]
+ ld [hSerialSend], a
+ call Function78a
+ ld b, a
+ inc hl
+ ld a, [hFFCC]
+ and a
+ ld a, $0
+ ld [hFFCC], a
+ jr nz, .asm_847
+ ld a, b
+ ld [de], a
+ inc de
+ dec c
+ jr nz, .asm_847
+ ret
+; 862
+
+Function862:: ; 862
+ call LoadTileMapToTempTileMap
+ callab PlaceWaitingText
+ call Function87d
+ jp Call_LoadTempTileMapToTileMap
+; 871
+
+
+Function871:: ; 871
+ call LoadTileMapToTempTileMap
+ callab PlaceWaitingText
+ jp Function87d
+; 87d
+
+; One "giant" leap for machinekind
+
+Function87d:: ; 87d
+ ld a, $ff
+ ld [wOtherPlayerLinkAction], a
+.loop
+ call LinkTransfer
+ call DelayFrame
+ call Function82b
+ jr z, .check
+ push hl
+ ld hl, wcf5c
+ dec [hl]
+ jr nz, .skip
+ dec hl
+ dec [hl]
+ jr nz, .skip
+ pop hl
+ xor a
+ jp Function833
+
+.skip
+ pop hl
+
+.check
+ ld a, [wOtherPlayerLinkAction]
+ inc a
+ jr z, .loop
+
+ ld b, 10
+.receive
+ call DelayFrame
+ call LinkTransfer
+ dec b
+ jr nz, .receive
+
+ ld b, 10
+.acknowledge
+ call DelayFrame
+ call LinkDataReceived
+ dec b
+ jr nz, .acknowledge
+
+ ld a, [wOtherPlayerLinkAction]
+ ld [wOtherPlayerLinkMode], a
+ ret
+; 8c1
+
+LinkTransfer:: ; 8c1
+ push bc
+ ld b, SERIAL_TIMECAPSULE
+ ld a, [wLinkMode]
+ cp LINK_TIMECAPSULE
+ jr z, .got_high_nybble
+ ld b, SERIAL_TIMECAPSULE
+ jr c, .got_high_nybble
+ cp LINK_TRADECENTER
+ ld b, SERIAL_TRADECENTER
+ jr z, .got_high_nybble
+ ld b, SERIAL_BATTLE
+
+.got_high_nybble
+ call .Receive
+ ld a, [wPlayerLinkAction]
+ add b
+ ld [hSerialSend], a
+ ld a, [hLinkPlayerNumber]
+ cp $2
+ jr nz, .player_1
+ ld a, $1
+ ld [rSC], a
+ ld a, $81
+ ld [rSC], a
+
+.player_1
+ call .Receive
+ pop bc
+ ret
+; 8f3
+
+.Receive ; 8f3
+ ld a, [hSerialReceive]
+ ld [wOtherPlayerLinkMode], a
+ and $f0
+ cp b
+ ret nz
+ xor a
+ ld [hSerialReceive], a
+ ld a, [wOtherPlayerLinkMode]
+ and $f
+ ld [wOtherPlayerLinkAction], a
+ ret
+; 908
+
+LinkDataReceived:: ; 908
+; Let the other system know that the data has been received.
+ xor a
+ ld [hSerialSend], a
+ ld a, [hLinkPlayerNumber]
+ cp $2
+ ret nz
+ ld a, $1
+ ld [rSC], a
+ ld a, $81
+ ld [rSC], a
+ ret
+; 919
+
+Function919:: ; 919
+ ld a, [wLinkMode]
+ and a
+ ret nz
+ ld a, $2
+ ld [rSB], a
+ xor a
+ ld [hSerialReceive], a
+ ld a, $0
+ ld [rSC], a
+ ld a, $80
+ ld [rSC], a
+ ret
+; 92e
diff --git a/home/sine.asm b/home/sine.asm
new file mode 100644
index 00000000..e1552db2
--- /dev/null
+++ b/home/sine.asm
@@ -0,0 +1,21 @@
+Cosine:: ; 1b0f
+; Return d * cos(a) in hl
+ add $10 ; 90 degrees
+
+Sine:: ; 1b11
+; Return d * sin(a) in hl
+; a is a signed 6-bit value.
+
+ ld e, a
+
+ ld a, [hROMBank]
+ push af
+ ld a, BANK(_Sine)
+ rst Bankswitch
+
+ call _Sine
+
+ pop af
+ rst Bankswitch
+ ret
+; 1b1e
diff --git a/home/sram.asm b/home/sram.asm
new file mode 100644
index 00000000..05d4fdb6
--- /dev/null
+++ b/home/sram.asm
@@ -0,0 +1,20 @@
+
+OpenSRAM::
+ push af ; 30e1
+ ld a, $1 ; 30e2
+ ld [MBC3LatchClock], a ; 30e4
+ ld a, $a ; 30e7
+ ld [MBC3SRamEnable], a ; 30e9
+ pop af ; 30ec
+ ld [MBC3SRamBank], a ; 30ed
+ ret ; 30f0
+; 30f1
+
+CloseSRAM::
+ push af ; 30f1
+ ld a, $0 ; 30f2
+ ld [MBC3LatchClock], a ; 30f4
+ ld [MBC3SRamEnable], a ; 30f7
+ pop af ; 30fa
+ ret ; 30fb
+; 30fc
diff --git a/home/string.asm b/home/string.asm
new file mode 100644
index 00000000..70a0f2dd
--- /dev/null
+++ b/home/string.asm
@@ -0,0 +1,38 @@
+InitString:: ; 2ef6
+; Init a string of length c.
+ push hl
+ jr _InitString
+; 2ef9
+
+InitName:: ; 2ef9
+; Intended for names, so this function is limited to ten characters.
+ push hl
+ ld c, 10
+; 2efc
+
+_InitString:: ; 2efc
+; if the string pointed to by hl is empty (defined as "zero or more spaces
+; followed by a null"), then initialize it to the string pointed to by de.
+ push bc
+.loop
+ ld a, [hli]
+ cp "@"
+ jr z, .blank
+ cp " "
+ jr nz, .notblank
+ dec c
+ jr nz, .loop
+.blank
+ pop bc
+ ld l, e
+ ld h, d
+ pop de
+ ld b, 0
+ inc c
+ call CopyBytes
+ ret
+.notblank
+ pop bc
+ pop hl
+ ret
+; 2f17
diff --git a/home/text.asm b/home/text.asm
new file mode 100644
index 00000000..e3dacb47
--- /dev/null
+++ b/home/text.asm
@@ -0,0 +1,1183 @@
+BORDER_WIDTH EQU 2
+TEXTBOX_WIDTH EQU SCREEN_WIDTH
+TEXTBOX_INNERW EQU TEXTBOX_WIDTH - BORDER_WIDTH
+TEXTBOX_HEIGHT EQU 6
+TEXTBOX_INNERH EQU TEXTBOX_HEIGHT - BORDER_WIDTH
+TEXTBOX_X EQU 0
+TEXTBOX_INNERX EQU TEXTBOX_X + 1
+TEXTBOX_Y EQU SCREEN_HEIGHT - TEXTBOX_HEIGHT
+TEXTBOX_INNERY EQU TEXTBOX_Y + 2
+
+TEXTBOX_PAL EQU 7
+
+
+ClearBox:: ; fb6
+; Fill a c*b box at hl with blank tiles.
+
+ ld a, " "
+
+FillBoxWithByte::
+.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
+; fc8
+
+
+ClearTileMap:: ; fc8
+; Fill TileMap with blank tiles.
+
+ hlcoord 0, 0
+ ld a, " "
+ ld bc, TileMapEnd - TileMap
+ call ByteFill
+
+ ; Update the BG Map.
+ ld a, [rLCDC]
+ bit 7, a
+ ret z
+ jp WaitBGMap
+; fdb
+
+
+ClearScreen:: ; fdb
+ ld a, TEXTBOX_PAL
+ hlcoord 0, 0, AttrMap
+ ld bc, SCREEN_WIDTH * SCREEN_HEIGHT
+ call ByteFill
+ jr ClearTileMap
+; fe8
+
+
+
+TextBox:: ; fe8
+; Draw a text box at hl with room for
+; b lines of c characters each.
+; Places a border around the textbox,
+; then switches the palette to the
+; text black-and-white scheme.
+ push bc
+ push hl
+ call TextBoxBorder
+ pop hl
+ pop bc
+ jr TextBoxPalette
+; ff1
+
+
+TextBoxBorder:: ; ff1
+
+ ; Top
+ push hl
+ ld a, "┌"
+ ld [hli], a
+ inc a ; "─"
+ call .PlaceChars
+ inc a ; "┐"
+ ld [hl], a
+ pop hl
+
+ ; Middle
+ ld de, SCREEN_WIDTH
+ add hl, de
+.row
+ push hl
+ ld a, "│"
+ ld [hli], a
+ ld a, " "
+ call .PlaceChars
+ ld [hl], "│"
+ pop hl
+
+ ld de, SCREEN_WIDTH
+ add hl, de
+ dec b
+ jr nz, .row
+
+ ; Bottom
+ ld a, "└"
+ ld [hli], a
+ ld a, "─"
+ call .PlaceChars
+ ld [hl], "┘"
+
+ ret
+; 101e
+
+.PlaceChars: ; 101e
+; Place char a c times.
+ ld d, c
+.loop
+ ld [hli], a
+ dec d
+ jr nz, .loop
+ ret
+; 1024
+
+
+TextBoxPalette:: ; 1024
+; Fill text box width c height b at hl with pal 7
+ ld de, AttrMap - TileMap
+ add hl, de
+rept 2
+ inc b
+endr
+rept 2
+ inc c
+endr
+ ld a, TEXTBOX_PAL
+.col
+ push bc
+ push hl
+.row
+ ld [hli], a
+ dec c
+ jr nz, .row
+ pop hl
+ ld de, SCREEN_WIDTH
+ add hl, de
+ pop bc
+ dec b
+ jr nz, .col
+ ret
+; 103e
+
+
+SpeechTextBox:: ; 103e
+; Standard textbox.
+ hlcoord TEXTBOX_X, TEXTBOX_Y
+ ld b, TEXTBOX_INNERH
+ ld c, TEXTBOX_INNERW
+ jp TextBox
+; 1048
+
+TestText:: ; 1048
+ text "ゲームフりーク!"
+ done
+; 1052
+
+RadioTerminator:: ; 1052
+ ld hl, .stop
+ ret
+.stop db "@"
+; 1057
+
+
+PrintText:: ; 1057
+ call SetUpTextBox
+BuenaPrintText:: ; 105a
+ push hl
+ hlcoord TEXTBOX_INNERX, TEXTBOX_INNERY
+ lb bc, TEXTBOX_INNERH - 1, TEXTBOX_INNERW
+ call ClearBox
+ pop hl
+
+PrintTextBoxText:: ; 1065
+ bccoord TEXTBOX_INNERX, TEXTBOX_INNERY
+ call PlaceWholeStringInBoxAtOnce
+ ret
+; 106c
+
+SetUpTextBox:: ; 106c
+ push hl
+ call SpeechTextBox
+ call UpdateSprites
+ call ApplyTilemap
+ pop hl
+ ret
+; 1078
+
+
+PlaceString:: ; 1078
+ push hl
+
+PlaceNextChar:: ; 1079
+ ld a, [de]
+ cp "@"
+ jr nz, CheckDict
+ ld b, h
+ ld c, l
+ pop hl
+ ret
+ pop de
+
+NextChar:: ; 1083
+ inc de
+ jp PlaceNextChar
+
+CheckDict:: ; 1087
+dict: macro
+if \1 == 0
+ and a
+else
+ cp \1
+endc
+ jp z, \2
+endm
+
+dict2: macro
+if \1 == 0
+ and a
+else
+ cp \1
+endc
+ jr nz, \@
+ ld a, \2
+\@:
+endm
+
+dict3: macro
+if \1 == 0
+ and a
+else
+ cp \1
+endc
+ jr z, \2
+endm
+
+ dict "<DAY>", Char15
+ dict "<LINE>", LineChar
+ dict "<NEXT>", NextLineChar
+ dict TX_FAR, TextFar
+ dict $00, NullChar
+ dict $4c, Char4C
+ dict $4b, Char4B
+ dict "<PARA>", Paragraph
+ dict "<MOM>", PrintMomsName
+ dict "<PLAYER>", PrintPlayerName
+ dict "<RIVAL>", PrintRivalName
+ dict $35, Char35
+ dict $36, Char36
+ dict $37, Char37
+ dict "<RED>", PrintRedsName
+ dict "<GREEN>", PrintGreensName
+ dict "#", PlacePOKe
+ dict "<PC>", PCChar
+ dict "<ROCKET>", RocketChar
+ dict "<TM>", TMChar
+ dict "<TRNER>", TrainerChar
+ dict $23, PlaceKougeki
+ dict "<LNBRK>", Char22
+ dict "<CONT>", ContText
+ dict "<......>", SixDotsChar
+ dict "<DONE>", DoneText
+ dict "<PROMPT>", PromptText
+ dict "<PKMN>", PlacePKMN
+ dict "<POKE>", PlacePOKE
+ dict $25, NextChar
+ dict2 $1f, " "
+ dict "<DEXEND>", PlaceDexEnd
+ dict "<TARGET>", PlaceMoveTargetsName
+ dict "<USER>", PlaceMoveUsersName
+ dict "<ENEMY>", PlaceEnemysName
+ dict "<PLAY_G>", PlaceGenderedPlayerName
+ dict3 $e4, .place
+ dict3 $e5, .place
+
+ jr .nope
+ ld b, a
+ call Diacritic
+ jp NextChar
+.nope
+
+ cp $60
+ jr nc, .place
+
+ cp $40
+ jr nc, .handakuten
+
+.dakuten
+
+ cp $20
+ jr nc, .daku1
+ add $80
+ jr .daku2
+.daku1
+ add $90
+.daku2
+ ld b, $e5 ; dakuten
+ call Diacritic
+ jr .place
+
+.handakuten
+ cp "ぱ"
+ jr nc, .han1
+ add "ハ" - "パ"
+ jr .han2
+.han1
+ add "は" - "ぱ"
+.han2
+ ld b, $e4 ; handakuten
+ call Diacritic
+
+.place
+ ld [hli], a
+ call PrintLetterDelay
+ jp NextChar
+; 0x117b
+
+
+Char15:: ; 117b
+ ld c, l
+ ld b, h
+ callba Function17f036
+ jp PlaceNextChar
+; 1186
+
+
+print_name: macro
+ push de
+ ld de, \1
+ jp PlaceCommandCharacter
+endm
+
+PrintMomsName: print_name MomsName ; 1186
+PrintPlayerName: print_name PlayerName ; 118d
+PrintRivalName: print_name RivalName ; 1194
+PrintRedsName: print_name RedsName ; 119b
+PrintGreensName: print_name GreensName ; 11a2
+
+TrainerChar: print_name TrainerCharText ; 11a9
+TMChar: print_name TMCharText ; 11b0
+PCChar: print_name PCCharText ; 11b7
+RocketChar: print_name RocketCharText ; 11be
+PlacePOKe: print_name PlacePOKeText ; 11c5
+PlaceKougeki: print_name KougekiText ; 11cc
+SixDotsChar: print_name SixDotsCharText ; 11d3
+PlacePKMN: print_name PlacePKMNText ; 11da
+PlacePOKE: print_name PlacePOKEText ; 11e1
+Char35: print_name Char35Text ; 11e8
+Char36: print_name Char36Text ; 11ef
+Char37: print_name Char37Text ; 11f6
+
+
+PlaceMoveTargetsName:: ; 11fd
+ ld a, [hBattleTurn]
+ xor 1
+ jr PlaceMoveTargetsName_5A
+
+PlaceMoveUsersName:: ; 1203
+ ld a, [hBattleTurn]
+
+PlaceMoveTargetsName_5A: ; 1205
+ push de
+ and a
+ jr nz, .enemy
+
+ ld de, BattleMonNick
+ jr PlaceCommandCharacter
+
+.enemy
+ ld de, EnemyText ; Enemy
+ call PlaceString
+ ld h, b
+ ld l, c
+ ld de, EnemyMonNick
+ jr PlaceCommandCharacter
+
+
+PlaceEnemysName:: ; 121b
+ push de
+
+ ld a, [wLinkMode]
+ and a
+ jr nz, .linkbattle
+
+ ld a, [TrainerClass]
+ cp RIVAL1
+ jr z, .rival
+ cp RIVAL2
+ jr z, .rival
+
+ ld de, OTClassName
+ call PlaceString
+ ld h, b
+ ld l, c
+ ld de, String12a2
+ call PlaceString
+ push bc
+ callab Battle_GetTrainerName
+ pop hl
+ ld de, StringBuffer1
+ jr PlaceCommandCharacter
+
+.rival
+ ld de, RivalName
+ jr PlaceCommandCharacter
+
+.linkbattle
+ ld de, OTClassName
+ jr PlaceCommandCharacter
+
+
+PlaceGenderedPlayerName:: ; 1252
+ push de
+ ld de, PlayerName
+ call PlaceString
+ ld h, b
+ ld l, c
+ ld a, [PlayerGender]
+ bit 0, a
+ ld de, String_kun
+ jr z, PlaceCommandCharacter
+ ld de, String_chan
+ jr PlaceCommandCharacter
+
+
+PlaceCommandCharacter:: ; 126a
+ call PlaceString
+ ld h, b
+ ld l, c
+ pop de
+ jp NextChar
+; 0x1273
+
+TMCharText:: db "TM@" ; 1273
+TrainerCharText:: db "TRAINER@" ; 1276
+PCCharText:: db "PC@" ; 127e
+RocketCharText:: db "ROCKET@" ; 1281
+PlacePOKeText:: db "POKé@" ; 1288
+KougekiText:: db "こうげき@" ; 128d
+SixDotsCharText:: db "……@" ; 1292
+EnemyText:: db "Enemy @" ; 1295
+PlacePKMNText:: db "<PK><MN>@" ; PK MN ; 129c
+PlacePOKEText:: db "<PO><KE>@" ; PO KE ; 129f
+String12a2:: db " @" ; 12a2
+Char35Text::
+Char36Text::
+Char37Text:: db "@" ; 12a4
+String_kun:: db "@" ; 12a5
+String_chan:: db "@" ; 12a6
+; 12a7
+
+NextLineChar:: ; 12a7
+ pop hl
+ ld bc, SCREEN_WIDTH * 2
+ add hl, bc
+ push hl
+ jp NextChar
+; 12b0
+
+Char22:: ; 12b0
+ pop hl
+ ld bc, SCREEN_WIDTH
+ add hl, bc
+ push hl
+ jp NextChar
+; 12b9
+
+TextFar:: ; 12b9
+ pop hl
+ push de
+ ld bc, -TileMap + $10000
+ add hl, bc
+ ld de, -SCREEN_WIDTH
+ ld c, 1
+.loop
+ ld a, h
+ and a
+ jr nz, .next
+ ld a, l
+ cp SCREEN_WIDTH
+ jr c, .done
+
+.next
+ add hl, de
+ inc c
+ jr .loop
+
+.done
+ hlcoord 0, 0
+ ld de, SCREEN_WIDTH
+ ld a, c
+.loop2
+ and a
+ jr z, .done2
+ add hl, de
+ dec a
+ jr .loop2
+
+.done2
+ pop de
+ inc de
+ ld a, [de]
+ ld c, a
+ ld b, 0
+ add hl, bc
+ push hl
+ jp NextChar
+; 12ea
+
+
+LineChar:: ; 12ea
+ pop hl
+ hlcoord TEXTBOX_INNERX, TEXTBOX_INNERY + 2
+ push hl
+ jp NextChar
+; 0x12f2
+
+Paragraph:: ; 12f2
+ push de
+
+ ld a, [wLinkMode]
+ cp LINK_COLOSSEUM
+ jr z, .linkbattle
+ cp LINK_MOBILE
+ jr z, .linkbattle
+ call LoadBlinkingCursor
+
+.linkbattle
+ call Function13b6
+ call ButtonSound
+ hlcoord TEXTBOX_INNERX, TEXTBOX_INNERY
+ lb bc, TEXTBOX_INNERH - 1, TEXTBOX_INNERW
+ call ClearBox
+ call UnloadBlinkingCursor
+ ld c, 20
+ call DelayFrames
+ hlcoord TEXTBOX_INNERX, TEXTBOX_INNERY
+ pop de
+ jp NextChar
+; 131f
+
+
+Char4B:: ; 131f
+ ld a, [wLinkMode]
+ or a
+ jr nz, .communication
+ call LoadBlinkingCursor
+
+.communication
+ call Function13b6
+
+ push de
+ call ButtonSound
+ pop de
+
+ ld a, [wLinkMode]
+ or a
+ call z, UnloadBlinkingCursor
+
+Char4C:: ; 1337
+ push de
+ call TextScroll
+ call TextScroll
+ hlcoord TEXTBOX_INNERX, TEXTBOX_INNERY + 2
+ pop de
+ jp NextChar
+; 1345
+
+
+ContText:: ; 1345
+ push de
+ ld de, .cont
+ ld b, h
+ ld c, l
+ call PlaceString
+ ld h, b
+ ld l, c
+ pop de
+ jp NextChar
+
+.cont db $4b, "@"
+; 1356
+
+
+PlaceDexEnd:: ; 1356
+; Legacy: ends a Pokédex entry (Red).
+; Dex entries are now regular strings.
+ ld [hl], "."
+ pop hl
+ ret
+; 135a
+
+PromptText:: ; 135a
+ ld a, [wLinkMode]
+ cp LINK_COLOSSEUM
+ jr z, .ok
+ cp LINK_MOBILE
+ jr z, .ok
+ call LoadBlinkingCursor
+
+.ok
+ call Function13b6
+ call ButtonSound
+ ld a, [wLinkMode]
+ cp LINK_COLOSSEUM
+ jr z, DoneText
+ cp LINK_MOBILE
+ jr z, DoneText
+ call UnloadBlinkingCursor
+
+DoneText:: ; 137c
+ pop hl
+ ld de, .stop
+ dec de
+ ret
+.stop db "@"
+; 1383
+
+NullChar:: ; 1383
+ ld a, "?"
+ ld [hli], a
+ call PrintLetterDelay
+ jp NextChar
+; 138c
+
+TextScroll:: ; 138c
+ hlcoord TEXTBOX_INNERX, TEXTBOX_INNERY
+ decoord TEXTBOX_INNERX, TEXTBOX_INNERY - 1
+ ld a, TEXTBOX_INNERH - 1
+
+.col
+ push af
+ ld c, TEXTBOX_INNERW
+
+.row
+ ld a, [hli]
+ ld [de], a
+ inc de
+ dec c
+ jr nz, .row
+
+rept 2
+ inc de
+endr
+rept 2
+ inc hl
+endr
+ pop af
+ dec a
+ jr nz, .col
+
+ hlcoord TEXTBOX_INNERX, TEXTBOX_INNERY + 2
+ ld a, " "
+ ld bc, TEXTBOX_INNERW
+ call ByteFill
+ ld c, 5
+ call DelayFrames
+ ret
+; 13b6
+
+Function13b6:: ; 13b6
+ push bc
+ ld a, [hOAMUpdate]
+ push af
+ ld a, 1
+ ld [hOAMUpdate], a
+
+ call WaitBGMap
+
+ pop af
+ ld [hOAMUpdate], a
+ pop bc
+ ret
+; 13c6
+
+Diacritic:: ; 13c6
+ ret
+; 13c7
+
+LoadBlinkingCursor:: ; 13c7
+ ld a, "▼"
+ ldcoord_a 18, 17
+ ret
+; 13cd
+
+UnloadBlinkingCursor:: ; 13cd
+ lda_coord 17, 17
+ ldcoord_a 18, 17
+ ret
+; 13d4
+
+FarString:: ; 13d4
+ ld b, a
+ ld a, [hROMBank]
+ push af
+
+ ld a, b
+ rst Bankswitch
+ call PlaceString
+
+ pop af
+ rst Bankswitch
+ ret
+; 13e0
+
+PokeFluteTerminatorCharacter:: ; 13e0
+ ld hl, .stop
+ ret
+
+.stop db "@"
+; 13e5
+
+
+PlaceWholeStringInBoxAtOnce:: ; 13e5
+ ld a, [TextBoxFlags]
+ push af
+ set 1, a
+ ld [TextBoxFlags], a
+
+ call DoTextUntilTerminator
+
+ pop af
+ ld [TextBoxFlags], a
+ ret
+; 13f6
+
+DoTextUntilTerminator:: ; 13f6
+ ld a, [hli]
+ cp "@"
+ ret z
+ call .TextCommand
+ jr DoTextUntilTerminator
+
+.TextCommand:
+ push hl
+ push bc
+ ld c, a
+ ld b, 0
+ ld hl, TextCommands
+rept 2
+ add hl, bc
+endr
+ ld e, [hl]
+ inc hl
+ ld d, [hl]
+ pop bc
+ pop hl
+
+ ; jp de
+ push de
+ ret
+; 1410
+
+TextCommands:: ; 1410
+ dw Text_TX
+ dw Text_TX_RAM
+ dw Text_TX_BCD
+ dw Text_TX_MOVE
+ dw Text_TX_BOX
+ dw Text_TX_LOW
+ dw Text_WAIT_BUTTON
+ dw Text_TX_SCROLL
+ dw Text_START_ASM
+ dw Text_TX_NUM
+ dw Text_TX_EXIT
+ dw Text_PlaySound ; $0b
+ dw Text_TX_DOTS
+ dw Text_0D
+ dw Text_PlaySound ; $0e
+ dw Text_PlaySound ; $0f
+ dw Text_PlaySound ; $10
+ dw Text_PlaySound ; $11
+ dw Text_PlaySound ; $12
+ dw Text_PlaySound ; $13
+ dw Text_TX_STRINGBUFFER
+ dw Text_TX_DAY
+ dw Text_TX_FAR
+; 143e
+
+Text_TX:: ; 143e
+; TX
+; write text until "@"
+; [$00]["...@"]
+
+ ld d, h
+ ld e, l
+ ld h, b
+ ld l, c
+ call PlaceString
+ ld h, d
+ ld l, e
+ inc hl
+ ret
+; 1449
+
+Text_TX_RAM:: ; 1449
+; text_from_ram
+; write text from a ram address
+; little endian
+; [$01][addr]
+
+ ld a, [hli]
+ ld e, a
+ ld a, [hli]
+ ld d, a
+ push hl
+ ld h, b
+ ld l, c
+ call PlaceString
+ pop hl
+ ret
+; 1455
+
+Text_TX_FAR:: ; 1455
+; text_jump
+; write text from a different bank
+; little endian
+; [$16][addr][bank]
+
+ ld a, [hROMBank]
+ push af
+
+ ld a, [hli]
+ ld e, a
+ ld a, [hli]
+ ld d, a
+ ld a, [hli]
+
+ ld [hROMBank], a
+ ld [MBC3RomBank], a
+
+ push hl
+ ld h, d
+ ld l, e
+ call DoTextUntilTerminator
+ pop hl
+
+ pop af
+ ld [hROMBank], a
+ ld [MBC3RomBank], a
+ ret
+; 1470
+
+Text_TX_BCD:: ; 1470
+; TX_BCD
+; write bcd from address, typically ram
+; [$02][addr][flags]
+; flags: see PrintBCDNumber
+
+ ld a, [hli]
+ ld e, a
+ ld a, [hli]
+ ld d, a
+ ld a, [hli]
+ push hl
+ ld h, b
+ ld l, c
+ ld c, a
+ call PrintBCDNumber
+ ld b, h
+ ld c, l
+ pop hl
+ ret
+; 1480
+
+Text_TX_MOVE:: ; 1480
+; TX_MOVE
+; move to a new tile
+; [$03][addr]
+
+ ld a, [hli]
+ ld [wMenuScrollPosition + 2], a
+ ld c, a
+ ld a, [hli]
+ ld [wMenuScrollPosition + 2 + 1], a
+ ld b, a
+ ret
+; 148b
+
+Text_TX_BOX:: ; 148b
+; TX_BOX
+; draw a box
+; little endian
+; [$04][addr][height][width]
+
+ ld a, [hli]
+ ld e, a
+ ld a, [hli]
+ ld d, a
+ ld a, [hli]
+ ld b, a
+ ld a, [hli]
+ ld c, a
+ push hl
+ ld h, d
+ ld l, e
+ call TextBox
+ pop hl
+ ret
+; 149b
+
+Text_TX_LOW:: ; 149b
+; TX_LOW
+; write text at (1,16)
+; [$05]
+
+ bccoord TEXTBOX_INNERX, TEXTBOX_INNERY + 2
+ ret
+; 149f
+
+Text_WAIT_BUTTON:: ; 149f
+; TX_WAITBUTTON
+; wait for button press
+; show arrow
+; [06]
+
+ ld a, [wLinkMode]
+ cp LINK_COLOSSEUM
+ jp z, Text_0D
+ cp LINK_MOBILE
+ jp z, Text_0D
+
+ push hl
+ call LoadBlinkingCursor
+ push bc
+ call ButtonSound
+ pop bc
+ call UnloadBlinkingCursor
+ pop hl
+ ret
+; 14ba
+
+Text_TX_SCROLL:: ; 14ba
+; pushes text up two lines and sets the BC cursor to the border tile
+; below the first character column of the text box.
+ push hl
+ call UnloadBlinkingCursor
+ call TextScroll
+ call TextScroll
+ pop hl
+ bccoord TEXTBOX_INNERX, TEXTBOX_INNERY + 2
+ ret
+; 14c9
+
+Text_START_ASM:: ; 14c9
+; TX_ASM
+
+ bit 7, h
+ jr nz, .not_rom
+ jp [hl]
+
+.not_rom
+ ld a, "@"
+ ld [hl], a
+ ret
+; 14d2
+
+Text_TX_NUM:: ; 14d2
+; TX_NUM
+; [$09][addr][hi:bytes lo:digits]
+ ld a, [hli]
+ ld e, a
+ ld a, [hli]
+ ld d, a
+ ld a, [hli]
+ push hl
+ ld h, b
+ ld l, c
+ ld b, a
+ and $f
+ ld c, a
+ ld a, b
+ and $f0
+ swap a
+ set PRINTNUM_RIGHTALIGN_F, a
+ ld b, a
+ call PrintNum
+ ld b, h
+ ld c, l
+ pop hl
+ ret
+; 14ed
+
+Text_TX_EXIT:: ; 14ed
+ push hl
+ push bc
+ call GetJoypad
+ ld a, [hJoyDown]
+ and A_BUTTON | B_BUTTON
+ jr nz, .done
+ ld c, 30
+ call DelayFrames
+.done
+ pop bc
+ pop hl
+ ret
+; 1500
+
+Text_PlaySound:: ; 1500
+; chars:
+; $0b, $0e, $0f, $10, $11, $12, $13
+; see TextSFX
+
+ push bc
+ dec hl
+ ld a, [hli]
+ ld b, a
+ push hl
+ ld hl, TextSFX
+.loop
+ ld a, [hli]
+ cp -1
+ jr z, .done
+ cp b
+ jr z, .play
+rept 2
+ inc hl
+endr
+ jr .loop
+
+.play
+ push de
+ ld e, [hl]
+ inc hl
+ ld d, [hl]
+ call PlaySFX
+ call WaitSFX
+ pop de
+
+.done
+ pop hl
+ pop bc
+ ret
+; 1522
+
+Function1522:: ; 1522
+ push de
+ ld e, [hl]
+ inc hl
+ ld d, [hl]
+ call PlayCry
+ pop de
+ pop hl
+ pop bc
+ ret
+; 152d
+
+TextSFX:: ; 152d
+ dbw TX_SOUND_0B, SFX_DEX_FANFARE_50_79
+ dbw TX_SOUND_12, SFX_FANFARE
+ dbw TX_SOUND_0E, SFX_DEX_FANFARE_20_49
+ dbw TX_SOUND_0F, SFX_ITEM
+ dbw TX_SOUND_10, SFX_CAUGHT_MON
+ dbw TX_SOUND_11, SFX_DEX_FANFARE_80_109
+ dbw TX_SOUND_13, SFX_SLOT_MACHINE_START
+ db -1
+; 1543
+
+Text_TX_DOTS:: ; 1543
+; [$0C][num]
+ ld a, [hli]
+ ld d, a
+ push hl
+ ld h, b
+ ld l, c
+
+.loop
+ push de
+ ld a, "…"
+ ld [hli], a
+ call GetJoypad
+ ld a, [hJoyDown]
+ and A_BUTTON | B_BUTTON
+ jr nz, .next
+ ld c, 10
+ call DelayFrames
+.next
+ pop de
+ dec d
+ jr nz, .loop
+
+ ld b, h
+ ld c, l
+ pop hl
+ ret
+; 1562
+
+Text_0D:: ; 1562
+; wait for key down
+; display arrow
+ push hl
+ push bc
+ call ButtonSound
+ pop bc
+ pop hl
+ ret
+; 156a
+
+Text_TX_STRINGBUFFER:: ; 156a
+; Print a string from one of the following:
+; 0: StringBuffer3
+; 1: StringBuffer4
+; 2: StringBuffer5
+; 3: StringBuffer2
+; 4: StringBuffer1
+; 5: EnemyMonNick
+; 6: BattleMonNick
+; [$14][id]
+
+ ld a, [hli]
+ push hl
+ ld e, a
+ ld d, 0
+ ld hl, StringBufferPointers
+rept 2
+ add hl, de
+endr
+ ld a, BANK(StringBufferPointers)
+ call GetFarHalfword
+ ld d, h
+ ld e, l
+ ld h, b
+ ld l, c
+ call PlaceString
+ pop hl
+ ret
+; 1582
+
+Text_TX_DAY:: ; 1582
+; TX_DAY
+
+ call GetWeekday
+ push hl
+ push bc
+ ld c, a
+ ld b, 0
+ ld hl, .Days
+rept 2
+ add hl, bc
+endr
+ ld a, [hli]
+ ld h, [hl]
+ ld l, a
+ ld d, h
+ ld e, l
+ pop hl
+ call PlaceString
+ ld h, b
+ ld l, c
+ ld de, .Day
+ call PlaceString
+ pop hl
+ ret
+
+.Days ; 15a2
+ dw .Sun
+ dw .Mon
+ dw .Tues
+ dw .Wednes
+ dw .Thurs
+ dw .Fri
+ dw .Satur
+
+.Sun db "SUN@"
+.Mon db "MON@"
+.Tues db "TUES@"
+.Wednes db "WEDNES@"
+.Thurs db "THURS@"
+.Fri db "FRI@"
+.Satur db "SATUR@"
+.Day db "DAY@"
+; 15d8
diff --git a/home/tilemap.asm b/home/tilemap.asm
new file mode 100644
index 00000000..152f7568
--- /dev/null
+++ b/home/tilemap.asm
@@ -0,0 +1,257 @@
+PushWindow:: ; 1c00
+ callab _PushWindow
+ ret
+; 1c07
+
+ExitMenu:: ; 0x1c07
+ push af
+ callab _ExitMenu
+ pop af
+ ret
+
+InitVerticalMenuCursor:: ; 0x1c10
+ callab _InitVerticalMenuCursor
+ ret
+
+CloseWindow:: ; 0x1c17
+ push af
+ call ExitMenu
+ call ApplyTilemap
+ call UpdateSprites
+ pop af
+ ret
+
+RestoreTileBackup:: ; 0x1c23
+ call MenuBoxCoord2Tile
+ call .copy
+ call MenuBoxCoord2Attr
+ call .copy
+ ret
+; 0x1c30
+
+.copy: ; 0x1c30
+ call GetMenuBoxDims
+ inc b
+ inc c
+
+.row
+ push bc
+ push hl
+
+.col
+ ld a, [de]
+ ld [hli], a
+ dec de
+ dec c
+ jr nz, .col ; 0x1c3b $fa
+
+ pop hl
+ ld bc, SCREEN_WIDTH
+ add hl, bc
+ pop bc
+ dec b
+ jr nz, .row ; 0x1c44 $ef
+
+ ret
+
+PopWindow:: ; 0x1c47
+ ld b, $10
+ ld de, wMenuFlags
+.loop
+ ld a, [hld]
+ ld [de], a
+ inc de
+ dec b
+ jr nz, .loop ; 0x1c50 $fa
+ ret
+
+GetMenuBoxDims:: ; 0x1c53
+ ld a, [wMenuBorderTopCoord] ; top
+ ld b, a
+ ld a, [wMenuBorderBottomCoord] ; bottom
+ sub b
+ ld b, a
+ ld a, [wMenuBorderLeftCoord] ; left
+ ld c, a
+ ld a, [wMenuBorderRightCoord] ; right
+ sub c
+ ld c, a
+ ret
+; 0x1c66
+
+CopyMenuData2:: ; 1c66
+ push hl
+ push de
+ push bc
+ push af
+ ld hl, wMenuData2Pointer
+ ld a, [hli]
+ ld h, [hl]
+ ld l, a
+ ld de, wMenuData2Flags
+ ld bc, wMenuData2End - wMenuData2Flags
+ call CopyBytes
+ pop af
+ pop bc
+ pop de
+ pop hl
+ ret
+; 1c7e
+
+GetWindowStackTop:: ; 1c7e
+ ld hl, wWindowStackPointer
+ ld a, [hli]
+ ld h, [hl]
+ ld l, a
+ inc hl
+ ld a, [hli]
+ ld h, [hl]
+ ld l, a
+ ret
+; 1c89
+
+PlaceVerticalMenuItems:: ; 1c89
+ call CopyMenuData2
+ ld hl, wMenuData2Pointer
+ ld e, [hl]
+ inc hl
+ ld d, [hl]
+ call GetMenuTextStartCoord
+ call Coord2Tile ; hl now contains the TileMap address where we will start printing text.
+ inc de
+ ld a, [de] ; Number of items
+ inc de
+ ld b, a
+.loop
+ push bc
+ call PlaceString
+ inc de
+ ld bc, 2 * SCREEN_WIDTH
+ add hl, bc
+ pop bc
+ dec b
+ jr nz, .loop
+
+ ld a, [wMenuData2Flags]
+ bit 4, a
+ ret z
+
+ call MenuBoxCoord2Tile
+ ld a, [de]
+ ld c, a
+ inc de
+ ld b, $0
+ add hl, bc
+ jp PlaceString
+; 1cbb
+
+MenuBox:: ; 1cbb
+ call MenuBoxCoord2Tile
+ call GetMenuBoxDims
+ dec b
+ dec c
+ jp TextBox
+; 1cc6
+
+GetMenuTextStartCoord:: ; 1cc6
+ ld a, [wMenuBorderTopCoord]
+ ld b, a
+ inc b
+ ld a, [wMenuBorderLeftCoord]
+ ld c, a
+ inc c
+; bit 6: if not set, leave extra room on top
+ ld a, [wMenuData2Flags]
+ bit 6, a
+ jr nz, .bit_6_set
+ inc b
+
+.bit_6_set
+; bit 7: if set, leave extra room on the left
+ ld a, [wMenuData2Flags]
+ bit 7, a
+ jr z, .bit_7_clear
+ inc c
+
+.bit_7_clear
+ ret
+; 1ce1
+
+ClearMenuBoxInterior:: ; 1ce1
+ call MenuBoxCoord2Tile
+ ld bc, SCREEN_WIDTH + 1
+ add hl, bc
+ call GetMenuBoxDims
+ dec b
+ dec c
+ call ClearBox
+ ret
+; 1cf1
+
+ClearWholeMenuBox:: ; 1cf1
+ call MenuBoxCoord2Tile
+ call GetMenuBoxDims
+ inc c
+ inc b
+ call ClearBox
+ ret
+; 1cfd
+
+
+MenuBoxCoord2Tile:: ; 1cfd
+ ld a, [wMenuBorderLeftCoord]
+ ld c, a
+ ld a, [wMenuBorderTopCoord]
+ ld b, a
+; 1d05
+
+
+Coord2Tile:: ; 1d05
+; Return the address of TileMap(c, b) in hl.
+ xor a
+ ld h, a
+ ld l, b
+ ld a, c
+ ld b, h
+ ld c, l
+ add hl, hl
+ add hl, hl
+ add hl, bc
+ add hl, hl
+ add hl, hl
+ ld c, a
+ xor a
+ ld b, a
+ add hl, bc
+ bccoord 0, 0
+ add hl, bc
+ ret
+; 1d19
+
+MenuBoxCoord2Attr:: ; 1d19
+ ld a, [wMenuBorderLeftCoord]
+ ld c, a
+ ld a, [wMenuBorderTopCoord]
+ ld b, a
+
+Coord2Attr:: ; 1d21
+; Return the address of AttrMap(c, b) in hl.
+ xor a
+ ld h, a
+ ld l, b
+ ld a, c
+ ld b, h
+ ld c, l
+ add hl, hl
+ add hl, hl
+ add hl, bc
+ add hl, hl
+ add hl, hl
+ ld c, a
+ xor a
+ ld b, a
+ add hl, bc
+ bccoord 0, 0, AttrMap
+ add hl, bc
+ ret
+; 1d35
diff --git a/home/time.asm b/home/time.asm
new file mode 100644
index 00000000..2d432be3
--- /dev/null
+++ b/home/time.asm
@@ -0,0 +1,312 @@
+; Functions relating to the timer interrupt and the real-time-clock.
+
+
+AskTimer:: ; 591
+ push af
+ ld a, [hMobile]
+ and a
+ jr z, .not_mobile
+ call Timer
+
+.not_mobile
+ pop af
+ reti
+; 59c
+
+
+LatchClock:: ; 59c
+; latch clock counter data
+ ld a, 0
+ ld [MBC3LatchClock], a
+ ld a, 1
+ ld [MBC3LatchClock], a
+ ret
+; 5a7
+
+
+UpdateTime:: ; 5a7
+ call GetClock
+ call FixDays
+ call FixTime
+ callba GetTimeOfDay
+ ret
+; 5b7
+
+
+GetClock:: ; 5b7
+; store clock data in hRTCDayHi-hRTCSeconds
+
+; enable clock r/w
+ ld a, SRAM_ENABLE
+ ld [MBC3SRamEnable], a
+
+; clock data is 'backwards' in hram
+
+ call LatchClock
+ ld hl, MBC3SRamBank
+ ld de, MBC3RTC
+
+ ld [hl], RTC_S
+ ld a, [de]
+ and $3f
+ ld [hRTCSeconds], a
+
+ ld [hl], RTC_M
+ ld a, [de]
+ and $3f
+ ld [hRTCMinutes], a
+
+ ld [hl], RTC_H
+ ld a, [de]
+ and $1f
+ ld [hRTCHours], a
+
+ ld [hl], RTC_DL
+ ld a, [de]
+ ld [hRTCDayLo], a
+
+ ld [hl], RTC_DH
+ ld a, [de]
+ ld [hRTCDayHi], a
+
+; unlatch clock / disable clock r/w
+ call CloseSRAM
+ ret
+; 5e8
+
+
+FixDays:: ; 5e8
+; fix day count
+; mod by 140
+
+; check if day count > 255 (bit 8 set)
+ ld a, [hRTCDayHi] ; DH
+ bit 0, a
+ jr z, .daylo
+; reset dh (bit 8)
+ res 0, a
+ ld [hRTCDayHi], a ; DH
+
+; mod 140
+; mod twice since bit 8 (DH) was set
+ ld a, [hRTCDayLo] ; DL
+.modh
+ sub 140
+ jr nc, .modh
+.modl
+ sub 140
+ jr nc, .modl
+ add 140
+
+; update dl
+ ld [hRTCDayLo], a ; DL
+
+; flag for sRTCStatusFlags
+ ld a, %01000000
+ jr .set
+
+.daylo
+; quit if fewer than 140 days have passed
+ ld a, [hRTCDayLo] ; DL
+ cp 140
+ jr c, .quit
+
+; mod 140
+.mod
+ sub 140
+ jr nc, .mod
+ add 140
+
+; update dl
+ ld [hRTCDayLo], a ; DL
+
+; flag for sRTCStatusFlags
+ ld a, %00100000
+
+.set
+; update clock with modded day value
+ push af
+ call SetClock
+ pop af
+ scf
+ ret
+
+.quit
+ xor a
+ ret
+; 61d
+
+
+FixTime:: ; 61d
+; add ingame time (set at newgame) to current time
+; day hr min sec
+; store time in CurDay, hHours, hMinutes, hSeconds
+
+; second
+ ld a, [hRTCSeconds] ; S
+ ld c, a
+ ld a, [StartSecond]
+ add c
+ sub 60
+ jr nc, .updatesec
+ add 60
+.updatesec
+ ld [hSeconds], a
+
+; minute
+ ccf ; carry is set, so turn it off
+ ld a, [hRTCMinutes] ; M
+ ld c, a
+ ld a, [StartMinute]
+ adc c
+ sub 60
+ jr nc, .updatemin
+ add 60
+.updatemin
+ ld [hMinutes], a
+
+; hour
+ ccf ; carry is set, so turn it off
+ ld a, [hRTCHours] ; H
+ ld c, a
+ ld a, [StartHour]
+ adc c
+ sub 24
+ jr nc, .updatehr
+ add 24
+.updatehr
+ ld [hHours], a
+
+; day
+ ccf ; carry is set, so turn it off
+ ld a, [hRTCDayLo] ; DL
+ ld c, a
+ ld a, [StartDay]
+ adc c
+ ld [CurDay], a
+ ret
+; 658
+
+SetTimeOfDay:: ; 658
+ xor a
+ ld [StringBuffer2], a
+ ld a, $0 ; useless
+ ld [StringBuffer2 + 3], a
+ jr InitTime
+
+SetDayOfWeek:: ; 663
+ call UpdateTime
+ ld a, [hHours]
+ ld [StringBuffer2 + 1], a
+ ld a, [hMinutes]
+ ld [StringBuffer2 + 2], a
+ ld a, [hSeconds]
+ ld [StringBuffer2 + 3], a
+ jr InitTime ; useless
+
+InitTime:: ; 677
+ callba _InitTime
+ ret
+; 67e
+
+
+
+PanicResetClock:: ; 67e
+ call .ClearhRTC
+ call SetClock
+ ret
+; 685
+
+.ClearhRTC ; 685
+ xor a
+ ld [hRTCSeconds], a
+ ld [hRTCMinutes], a
+ ld [hRTCHours], a
+ ld [hRTCDayLo], a
+ ld [hRTCDayHi], a
+ ret
+; 691
+
+
+SetClock:: ; 691
+; set clock data from hram
+
+; enable clock r/w
+ ld a, SRAM_ENABLE
+ ld [MBC3SRamEnable], a
+
+; set clock data
+; stored 'backwards' in hram
+
+ call LatchClock
+ ld hl, MBC3SRamBank
+ ld de, MBC3RTC
+
+; seems to be a halt check that got partially commented out
+; this block is totally pointless
+ ld [hl], RTC_DH
+ ld a, [de]
+ bit 6, a ; halt
+ ld [de], a
+
+; seconds
+ ld [hl], RTC_S
+ ld a, [hRTCSeconds]
+ ld [de], a
+; minutes
+ ld [hl], RTC_M
+ ld a, [hRTCMinutes]
+ ld [de], a
+; hours
+ ld [hl], RTC_H
+ ld a, [hRTCHours]
+ ld [de], a
+; day lo
+ ld [hl], RTC_DL
+ ld a, [hRTCDayLo]
+ ld [de], a
+; day hi
+ ld [hl], RTC_DH
+ ld a, [hRTCDayHi]
+ res 6, a ; make sure timer is active
+ ld [de], a
+
+; cleanup
+ call CloseSRAM ; unlatch clock, disable clock r/w
+ ret
+; 6c4
+
+
+ClearRTCStatus:: ; 6c4
+; clear sRTCStatusFlags
+ xor a
+ push af
+ ld a, BANK(sRTCStatusFlags)
+ call GetSRAMBank
+ pop af
+ ld [sRTCStatusFlags], a
+ call CloseSRAM
+ ret
+; 6d3
+
+RecordRTCStatus:: ; 6d3
+; append flags to sRTCStatusFlags
+ ld hl, sRTCStatusFlags
+ push af
+ ld a, BANK(sRTCStatusFlags)
+ call GetSRAMBank
+ pop af
+ or [hl]
+ ld [hl], a
+ call CloseSRAM
+ ret
+; 6e3
+
+CheckRTCStatus:: ; 6e3
+; check sRTCStatusFlags
+ ld a, BANK(sRTCStatusFlags)
+ call GetSRAMBank
+ ld a, [sRTCStatusFlags]
+ call CloseSRAM
+ ret
+; 6ef
diff --git a/home/vblank.asm b/home/vblank.asm
new file mode 100644
index 00000000..1c0824c5
--- /dev/null
+++ b/home/vblank.asm
@@ -0,0 +1,442 @@
+; VBlank is the interrupt responsible for updating VRAM.
+
+; In Pokemon Crystal, VBlank has been hijacked to act as the
+; main loop. After time-sensitive graphics operations have been
+; performed, joypad input and sound functions are executed.
+
+; This prevents the display and audio output from lagging.
+
+
+VBlank:: ; 283
+ push af
+ push bc
+ push de
+ push hl
+
+ ld a, [hVBlank]
+ and 7
+
+ ld e, a
+ ld d, 0
+ ld hl, .VBlanks
+rept 2
+ add hl, de
+endr
+ ld a, [hli]
+ ld h, [hl]
+ ld l, a
+
+ call _hl_
+
+ call GameTimer
+
+ pop hl
+ pop de
+ pop bc
+ pop af
+ reti
+; 2a1
+
+.VBlanks ; 2a1
+ dw VBlank0
+ dw VBlank1
+ dw VBlank2
+ dw VBlank3
+ dw VBlank4
+ dw VBlank5
+ dw VBlank6
+ dw VBlank0 ; just in case
+; 2b1
+
+
+VBlank0:: ; 2b1
+; normal operation
+
+; rng
+; scx, scy, wy, wx
+; bg map buffer
+; palettes
+; dma transfer
+; bg map
+; tiles
+; oam
+; joypad
+; sound
+
+ ; inc frame counter
+ ld hl, hVBlankCounter
+ inc [hl]
+
+ ; advance random variables
+ ld a, [rDIV]
+ ld b, a
+ ld a, [hRandomAdd]
+ adc b
+ ld [hRandomAdd], a
+
+ ld a, [rDIV]
+ ld b, a
+ ld a, [hRandomSub]
+ sbc b
+ ld [hRandomSub], a
+
+ ld a, [hROMBank]
+ ld [hROMBankBackup], a
+
+ ld a, [hSCX]
+ ld [rSCX], a
+ ld a, [hSCY]
+ ld [rSCY], a
+ ld a, [hWY]
+ ld [rWY], a
+ ld a, [hWX]
+ ld [rWX], a
+
+ ; There's only time to call one of these in one vblank.
+ ; Calls are in order of priority.
+
+ call UpdateBGMapBuffer
+ jr c, .done
+ call UpdatePalsIfCGB
+ jr c, .done
+ call DMATransfer
+ jr c, .done
+ call UpdateBGMap
+
+ ; These have their own timing checks.
+
+ call Serve2bppRequest
+ call Serve1bppRequest
+ call AnimateTileset
+
+.done
+
+ ld a, [hOAMUpdate]
+ and a
+ jr nz, .done_oam
+ call hPushOAM
+.done_oam
+
+
+ ; vblank-sensitive operations are done
+
+ xor a
+ ld [VBlankOccurred], a
+
+ ld a, [OverworldDelay]
+ and a
+ jr z, .ok
+ dec a
+ ld [OverworldDelay], a
+.ok
+
+ ld a, [TextDelayFrames]
+ and a
+ jr z, .ok2
+ dec a
+ ld [TextDelayFrames], a
+.ok2
+
+ call Joypad
+
+ ld a, BANK(_UpdateSound)
+ rst Bankswitch
+ call _UpdateSound
+ ld a, [hROMBankBackup]
+ rst Bankswitch
+
+ ld a, [hSeconds]
+ ld [hSecondsBackup], a
+
+ ret
+; 325
+
+
+VBlank2:: ; 325
+; sound only
+
+ ld a, [hROMBank]
+ ld [hROMBankBackup], a
+
+ ld a, BANK(_UpdateSound)
+ rst Bankswitch
+ call _UpdateSound
+
+ ld a, [hROMBankBackup]
+ rst Bankswitch
+
+ xor a
+ ld [VBlankOccurred], a
+ ret
+; 337
+
+
+VBlank1:: ; 337
+; scx, scy
+; palettes
+; bg map
+; tiles
+; oam
+; sound / lcd stat
+
+ ld a, [hROMBank]
+ ld [hROMBankBackup], a
+
+ ld a, [hSCX]
+ ld [rSCX], a
+ ld a, [hSCY]
+ ld [rSCY], a
+
+ call UpdatePals
+ jr c, .done
+
+ call UpdateBGMap
+ call Serve2bppRequest@VBlank
+
+ call hPushOAM
+.done
+
+ xor a
+ ld [VBlankOccurred], a
+
+ ; get requested ints
+ ld a, [rIF]
+ ld b, a
+ ; discard requested ints
+ xor a
+ ld [rIF], a
+ ; enable lcd stat
+ ld a, %10 ; lcd stat
+ ld [rIE], a
+ ; rerequest serial int if applicable (still disabled)
+ ; request lcd stat
+ ld a, b
+ and %1000 ; serial
+ or %10 ; lcd stat
+ ld [rIF], a
+
+ ei
+ ld a, BANK(_UpdateSound)
+ rst Bankswitch
+ call _UpdateSound
+ ld a, [hROMBankBackup]
+ rst Bankswitch
+ di
+
+ ; get requested ints
+ ld a, [rIF]
+ ld b, a
+ ; discard requested ints
+ xor a
+ ld [rIF], a
+ ; enable ints besides joypad
+ ld a, %1111 ; serial timer lcdstat vblank
+ ld [rIE], a
+ ; rerequest ints
+ ld a, b
+ ld [rIF], a
+ ret
+; 37f
+
+
+UpdatePals:: ; 37f
+; update pals for either dmg or cgb
+
+ ld a, [hCGB]
+ and a
+ jp nz, UpdateCGBPals
+
+ ; update gb pals
+ ld a, [wBGP]
+ ld [rBGP], a
+ ld a, [wOBP0]
+ ld [rOBP0], a
+ ld a, [wOBP1]
+ ld [rOBP1], a
+
+ and a
+ ret
+; 396
+
+
+VBlank3:: ; 396
+; scx, scy
+; palettes
+; bg map
+; tiles
+; oam
+; sound / lcd stat
+
+ ld a, [hROMBank]
+ ld [hROMBankBackup], a
+
+ ld a, [hSCX]
+ ld [rSCX], a
+ ld a, [hSCY]
+ ld [rSCY], a
+
+ ld a, [hCGBPalUpdate]
+ and a
+ call nz, ForceUpdateCGBPals
+ jr c, .done
+
+ call UpdateBGMap
+ call Serve2bppRequest@VBlank
+
+ call hPushOAM
+.done
+
+ xor a
+ ld [VBlankOccurred], a
+
+ ld a, [rIF]
+ push af
+ xor a
+ ld [rIF], a
+ ld a, %10 ; lcd stat
+ ld [rIE], a
+ ld [rIF], a
+
+ ei
+ ld a, BANK(_UpdateSound)
+ rst Bankswitch
+ call _UpdateSound
+ ld a, [hROMBankBackup]
+ rst Bankswitch
+ di
+
+ ; request lcdstat
+ ld a, [rIF]
+ ld b, a
+ ; and any other ints
+ pop af
+ or b
+ ld b, a
+ ; reset ints
+ xor a
+ ld [rIF], a
+ ; enable ints besides joypad
+ ld a, %1111 ; serial timer lcdstat vblank
+ ld [rIE], a
+ ; request ints
+ ld a, b
+ ld [rIF], a
+ ret
+; 3df
+
+
+VBlank4:: ; 3df
+; bg map
+; tiles
+; oam
+; joypad
+; serial
+; sound
+
+ ld a, [hROMBank]
+ ld [hROMBankBackup], a
+
+ call UpdateBGMap
+ call Serve2bppRequest
+
+ call hPushOAM
+
+ call Joypad
+
+ xor a
+ ld [VBlankOccurred], a
+
+ call AskSerial
+
+ ld a, BANK(_UpdateSound)
+ rst Bankswitch
+ call _UpdateSound
+
+ ld a, [hROMBankBackup]
+ rst Bankswitch
+ ret
+; 400
+
+
+VBlank5:: ; 400
+; scx
+; palettes
+; bg map
+; tiles
+; joypad
+;
+
+ ld a, [hROMBank]
+ ld [hROMBankBackup], a
+
+ ld a, [hSCX]
+ ld [rSCX], a
+
+ call UpdatePalsIfCGB
+ jr c, .done
+
+ call UpdateBGMap
+ call Serve2bppRequest
+.done
+
+ xor a
+ ld [VBlankOccurred], a
+
+ call Joypad
+
+ xor a
+ ld [rIF], a
+ ld a, %10 ; lcd stat
+ ld [rIE], a
+ ; request lcd stat
+ ld [rIF], a
+
+ ei
+ ld a, BANK(_UpdateSound)
+ rst Bankswitch
+ call _UpdateSound
+ ld a, [hROMBankBackup]
+ rst Bankswitch
+ di
+
+ xor a
+ ld [rIF], a
+ ; enable ints besides joypad
+ ld a, %1111 ; serial timer lcdstat vblank
+ ld [rIE], a
+ ret
+; 436
+
+
+VBlank6:: ; 436
+; palettes
+; tiles
+; dma transfer
+; sound
+
+ ld a, [hROMBank]
+ ld [hROMBankBackup], a
+
+ ; inc frame counter
+ ld hl, hVBlankCounter
+ inc [hl]
+
+ call UpdateCGBPals
+ jr c, .done
+
+ call Serve2bppRequest
+ call Serve1bppRequest
+ call DMATransfer
+.done
+
+ xor a
+ ld [VBlankOccurred], a
+
+ ld a, BANK(_UpdateSound)
+ rst Bankswitch
+ call _UpdateSound
+
+ ld a, [hROMBankBackup]
+ rst Bankswitch
+ ret
+; 45a
diff --git a/home/video.asm b/home/video.asm
new file mode 100644
index 00000000..c88e0e55
--- /dev/null
+++ b/home/video.asm
@@ -0,0 +1,486 @@
+; Functions dealing with VRAM.
+
+DMATransfer:: ; 15d8
+; Return carry if the transfer is completed.
+
+ ld a, [hDMATransfer]
+ and a
+ ret z
+
+; Start transfer
+ ld [rHDMA5], a
+
+; Execution is halted until the transfer is complete.
+
+ xor a
+ ld [hDMATransfer], a
+ scf
+ ret
+; 15e3
+
+
+UpdateBGMapBuffer:: ; 15e3
+; Copy [hFFDC] 16x8 tiles from BGMapBuffer
+; to bg map addresses in BGMapBufferPtrs.
+
+; [hFFDC] must be even since this is done in pairs.
+
+; Return carry on success.
+
+ ld a, [hBGMapUpdate]
+ and a
+ ret z
+
+ ld a, [rVBK]
+ push af
+ ld [hSPBuffer], sp
+
+ ld hl, BGMapBufferPtrs
+ ld sp, hl
+
+; We can now pop the addresses of affected spots on the BG Map
+
+ ld hl, BGMapPalBuffer
+ ld de, BGMapBuffer
+
+
+.next
+; Copy a pair of 16x8 blocks (one 16x16 block)
+
+rept 2
+; Get our BG Map address
+ pop bc
+
+; Palettes
+ ld a, 1
+ ld [rVBK], a
+
+ ld a, [hli]
+ ld [bc], a
+ inc c
+ ld a, [hli]
+ ld [bc], a
+ dec c
+
+; Tiles
+ ld a, 0
+ ld [rVBK], a
+
+ ld a, [de]
+ inc de
+ ld [bc], a
+ inc c
+ ld a, [de]
+ inc de
+ ld [bc], a
+endr
+
+; We've done 2 16x8 blocks
+ ld a, [hFFDC]
+ dec a
+ dec a
+ ld [hFFDC], a
+
+ jr nz, .next
+
+
+ ld a, [hSPBuffer]
+ ld l, a
+ ld a, [hSPBuffer + 1]
+ ld h, a
+ ld sp, hl
+
+ pop af
+ ld [rVBK], a
+
+ xor a
+ ld [hBGMapUpdate], a
+ scf
+ ret
+; 163a
+
+
+WaitTop:: ; 163a
+; Wait until the top third of the BG Map is being updated.
+
+ ld a, [hBGMapMode]
+ and a
+ ret z
+
+ ld a, [hBGMapThird]
+ and a
+ jr z, .done
+
+ call DelayFrame
+ jr WaitTop
+
+.done
+ xor a
+ ld [hBGMapMode], a
+ ret
+; 164c
+
+
+UpdateBGMap:: ; 164c
+; Update the BG Map, in thirds, from TileMap and AttrMap.
+
+ ld a, [hBGMapMode]
+ and a
+ ret z
+
+; BG Map 0
+ dec a ; 1
+ jr z, .Tiles
+ dec a ; 2
+ jr z, .Attr
+
+; BG Map 1
+ dec a
+
+ ld a, [hBGMapAddress]
+ ld l, a
+ ld a, [hBGMapAddress + 1]
+ ld h, a
+ push hl
+
+ xor a
+ ld [hBGMapAddress], a
+ ld a, VBGMap1 >> 8
+ ld [hBGMapAddress + 1], a
+
+ ld a, [hBGMapMode]
+ push af
+ cp 3
+ call z, .Tiles
+ pop af
+ cp 4
+ call z, .Attr
+
+ pop hl
+ ld a, l
+ ld [hBGMapAddress], a
+ ld a, h
+ ld [hBGMapAddress + 1], a
+ ret
+
+
+.Attr
+ ld a, 1
+ ld [rVBK], a
+
+ hlcoord 0, 0, AttrMap
+ call .update
+
+ ld a, 0
+ ld [rVBK], a
+ ret
+
+
+.Tiles
+ hlcoord 0, 0
+
+
+.update
+ ld [hSPBuffer], sp
+
+; Which third?
+ ld a, [hBGMapThird]
+ and a ; 0
+ jr z, .top
+ dec a ; 1
+ jr z, .middle
+ ; 2
+
+
+THIRD_HEIGHT EQU SCREEN_HEIGHT / 3
+
+
+.bottom
+ ld de, 2 * THIRD_HEIGHT * SCREEN_WIDTH
+ add hl, de
+ ld sp, hl
+
+ ld a, [hBGMapAddress + 1]
+ ld h, a
+ ld a, [hBGMapAddress]
+ ld l, a
+
+ ld de, 2 * THIRD_HEIGHT * BG_MAP_WIDTH
+ add hl, de
+
+; Next time: top third
+ xor a
+ jr .start
+
+
+.middle
+ ld de, THIRD_HEIGHT * SCREEN_WIDTH
+ add hl, de
+ ld sp, hl
+
+ ld a, [hBGMapAddress + 1]
+ ld h, a
+ ld a, [hBGMapAddress]
+ ld l, a
+
+ ld de, THIRD_HEIGHT * BG_MAP_WIDTH
+ add hl, de
+
+; Next time: bottom third
+ ld a, 2
+ jr .start
+
+
+.top
+ ld sp, hl
+
+ ld a, [hBGMapAddress + 1]
+ ld h, a
+ ld a, [hBGMapAddress]
+ ld l, a
+
+; Next time: middle third
+ ld a, 1
+
+
+.start
+; Which third to update next time
+ ld [hBGMapThird], a
+
+; Rows of tiles in a third
+ ld a, SCREEN_HEIGHT / 3
+
+; Discrepancy between TileMap and BGMap
+ ld bc, BG_MAP_WIDTH - (SCREEN_WIDTH - 1)
+
+
+.row
+; Copy a row of 20 tiles
+rept SCREEN_WIDTH / 2 - 1
+ pop de
+ ld [hl], e
+ inc l
+ ld [hl], d
+ inc l
+endr
+ pop de
+ ld [hl], e
+ inc l
+ ld [hl], d
+
+ add hl, bc
+ dec a
+ jr nz, .row
+
+
+ ld a, [hSPBuffer]
+ ld l, a
+ ld a, [hSPBuffer + 1]
+ ld h, a
+ ld sp, hl
+ ret
+; 170a
+
+
+Serve1bppRequest:: ; 170a
+; Only call during the first fifth of VBlank
+
+ ld a, [Requested1bpp]
+ and a
+ ret z
+
+; Back out if we're too far into VBlank
+ ld a, [rLY]
+ cp 144
+ ret c
+ cp 146
+ ret nc
+
+; Copy [Requested1bpp] 1bpp tiles from [Requested1bppSource] to [Requested1bppDest]
+
+ ld [hSPBuffer], sp
+
+; Source
+ ld hl, Requested1bppSource
+ ld a, [hli]
+ ld h, [hl]
+ ld l, a
+ ld sp, hl
+
+; Destination
+ ld hl, Requested1bppDest
+ ld a, [hli]
+ ld h, [hl]
+ ld l, a
+
+; # tiles to copy
+ ld a, [Requested1bpp]
+ ld b, a
+
+ xor a
+ ld [Requested1bpp], a
+
+.next
+
+rept 3
+ pop de
+ ld [hl], e
+ inc l
+ ld [hl], e
+ inc l
+ ld [hl], d
+ inc l
+ ld [hl], d
+ inc l
+endr
+ pop de
+ ld [hl], e
+ inc l
+ ld [hl], e
+ inc l
+ ld [hl], d
+ inc l
+ ld [hl], d
+
+ inc hl
+ dec b
+ jr nz, .next
+
+
+ ld a, l
+ ld [Requested1bppDest], a
+ ld a, h
+ ld [Requested1bppDest + 1], a
+
+ ld [Requested1bppSource], sp
+
+ ld a, [hSPBuffer]
+ ld l, a
+ ld a, [hSPBuffer + 1]
+ ld h, a
+ ld sp, hl
+ ret
+; 1769
+
+
+Serve2bppRequest:: ; 1769
+; Only call during the first fifth of VBlank
+
+ ld a, [Requested2bpp]
+ and a
+ ret z
+
+; Back out if we're too far into VBlank
+ ld a, [rLY]
+ cp 144
+ ret c
+ cp 146
+ ret nc
+ jr _Serve2bppRequest
+
+
+Serve2bppRequest@VBlank:: ; 1778
+
+ ld a, [Requested2bpp]
+ and a
+ ret z
+
+_Serve2bppRequest:: ; 177d
+; Copy [Requested2bpp] 2bpp tiles from [Requested2bppSource] to [Requested2bppDest]
+
+ ld [hSPBuffer], sp
+
+; Source
+ ld hl, Requested2bppSource
+ ld a, [hli]
+ ld h, [hl]
+ ld l, a
+ ld sp, hl
+
+; Destination
+ ld hl, Requested2bppDest
+ ld a, [hli]
+ ld h, [hl]
+ ld l, a
+
+; # tiles to copy
+ ld a, [Requested2bpp]
+ ld b, a
+
+ xor a
+ ld [Requested2bpp], a
+
+.next
+
+rept 7
+ pop de
+ ld [hl], e
+ inc l
+ ld [hl], d
+ inc l
+endr
+ pop de
+ ld [hl], e
+ inc l
+ ld [hl], d
+
+ inc hl
+ dec b
+ jr nz, .next
+
+
+ ld a, l
+ ld [Requested2bppDest], a
+ ld a, h
+ ld [Requested2bppDest + 1], a
+
+ ld [Requested2bppSource], sp
+
+ ld a, [hSPBuffer]
+ ld l, a
+ ld a, [hSPBuffer + 1]
+ ld h, a
+ ld sp, hl
+ ret
+; 17d3
+
+
+AnimateTileset:: ; 17d3
+; Only call during the first fifth of VBlank
+
+ ld a, [hMapAnims]
+ and a
+ ret z
+
+; Back out if we're too far into VBlank
+ ld a, [rLY]
+ cp 144
+ ret c
+ cp 151
+ ret nc
+
+ ld a, [hROMBank]
+ push af
+ ld a, BANK(_AnimateTileset)
+ rst Bankswitch
+
+ ld a, [rSVBK]
+ push af
+ ld a, 1
+ ld [rSVBK], a
+
+ ld a, [rVBK]
+ push af
+ ld a, 0
+ ld [rVBK], a
+
+ call _AnimateTileset
+
+ pop af
+ ld [rVBK], a
+ pop af
+ ld [rSVBK], a
+ pop af
+ rst Bankswitch
+ ret
+; 17ff
diff --git a/home/window.asm b/home/window.asm
new file mode 100644
index 00000000..32494ee3
--- /dev/null
+++ b/home/window.asm
@@ -0,0 +1,99 @@
+RefreshScreen:: ; 2dba
+
+ call ClearWindowData
+ ld a, [hROMBank]
+ push af
+ ld a, BANK(Function6454) ; and BANK(Function64bf)
+ rst Bankswitch
+
+ call Function6454
+ call Function2e20
+ call Function64bf
+
+ pop af
+ rst Bankswitch
+ ret
+; 2dcf
+
+
+CloseText:: ; 2dcf
+ ld a, [hOAMUpdate]
+ push af
+ ld a, $1
+ ld [hOAMUpdate], a
+
+ call .CloseText
+
+ pop af
+ ld [hOAMUpdate], a
+ ld hl, VramState
+ res 6, [hl]
+ ret
+; 2de2
+
+.CloseText ; 2de2
+ call ClearWindowData
+ xor a
+ ld [hBGMapMode], a
+ call OverworldTextModeSwitch
+ call Function2e20
+ xor a
+ ld [hBGMapMode], a
+ call Function2e31
+ ld a, $90
+ ld [hWY], a
+ call ReplaceKrisSprite
+ callba ReturnFromMapSetupScript
+ callba LoadOverworldFont
+ ret
+; 2e08
+
+OpenText:: ; 2e08
+ call ClearWindowData
+ ld a, [hROMBank]
+ push af
+ ld a, BANK(Function6454) ; and BANK(Function64bf)
+ rst Bankswitch
+
+ call Function6454 ; clear bgmap
+ call SpeechTextBox
+ call Function2e20 ; anchor bgmap
+ call Function64bf ; load font
+ pop af
+ rst Bankswitch
+
+ ret
+; 2e20
+
+Function2e20:: ; 2e20
+ ld a, [hOAMUpdate]
+ push af
+ ld a, $1
+ ld [hOAMUpdate], a
+
+ callba Function104110
+
+ pop af
+ ld [hOAMUpdate], a
+ ret
+; 2e31
+
+Function2e31:: ; 2e31
+ ld a, [hOAMUpdate]
+ push af
+ ld a, [hBGMapMode]
+ push af
+ xor a
+ ld [hBGMapMode], a
+ ld a, $1
+ ld [hOAMUpdate], a
+ call UpdateSprites
+ xor a
+ ld [hOAMUpdate], a
+ call DelayFrame
+ pop af
+ ld [hBGMapMode], a
+ pop af
+ ld [hOAMUpdate], a
+ ret
+; 2e4e