summaryrefslogtreecommitdiff
path: root/engine
diff options
context:
space:
mode:
authorentrpntr <entrpntr@gmail.com>2020-05-01 20:56:15 -0400
committerentrpntr <entrpntr@gmail.com>2020-05-01 20:56:15 -0400
commit9b5b2ac809338ab4f45a3460c98eb30b14910d91 (patch)
treea53f832df3b5afc3d9210eaf2ed446ab0cfbc91b /engine
parenta0ebc7fbaecc787929b8143f0e01b7d929e01852 (diff)
Disassemble bank $0b.
Diffstat (limited to 'engine')
-rw-r--r--engine/battle/trainer_huds.asm257
-rw-r--r--engine/events/move_deleter.asm150
-rw-r--r--engine/events/pokerus/pokerus.asm161
-rwxr-xr-xengine/items/items.asm12
-rwxr-xr-xengine/items/pack.asm8
-rw-r--r--engine/items/print_item_description.asm32
-rw-r--r--engine/items/tmhm.asm552
-rw-r--r--engine/link/mystery_gift_2.asm150
-rw-r--r--engine/pokemon/print_move_description.asm16
9 files changed, 1328 insertions, 10 deletions
diff --git a/engine/battle/trainer_huds.asm b/engine/battle/trainer_huds.asm
new file mode 100644
index 00000000..7fd57571
--- /dev/null
+++ b/engine/battle/trainer_huds.asm
@@ -0,0 +1,257 @@
+BattleStart_TrainerHuds:
+ ld a, $e4
+ ldh [rOBP0], a
+ call LoadBallIconGFX
+ call ShowPlayerMonsRemaining
+ ld a, [wBattleMode]
+ dec a
+ ret z
+ jp ShowOTTrainerMonsRemaining
+
+EnemySwitch_TrainerHud:
+ ld a, $e4
+ ldh [rOBP0], a
+ call LoadBallIconGFX
+ jp ShowOTTrainerMonsRemaining
+
+ShowPlayerMonsRemaining:
+ call DrawPlayerPartyIconHUDBorder
+ ld hl, wPartyMon1HP
+ ld de, wPartyCount
+ call StageBallTilesData
+ ; ldpixel wPlaceBallsX, 12, 12
+ ld a, 12 * 8
+ ld hl, wPlaceBallsX
+ ld [hli], a
+ ld [hl], a
+ ld a, 8
+ ld [wPlaceBallsDirection], a
+ ld hl, wVirtualOAMSprite00
+ jp LoadTrainerHudOAM
+
+ShowOTTrainerMonsRemaining:
+ call DrawEnemyHUDBorder
+ ld hl, wOTPartyMon1HP
+ ld de, wOTPartyCount
+ call StageBallTilesData
+ ; ldpixel wPlaceBallsX, 9, 4
+ ld hl, wPlaceBallsX
+ ld a, 9 * 8
+ ld [hli], a
+ ld [hl], 4 * 8
+ ld a, -8
+ ld [wPlaceBallsDirection], a
+ ld hl, wVirtualOAMSprite00 + PARTY_LENGTH * SPRITEOAMSTRUCT_LENGTH
+ jp LoadTrainerHudOAM
+
+StageBallTilesData:
+ ld a, [de]
+ push af
+ ld de, wBuffer1
+ ld c, PARTY_LENGTH
+ ld a, $34 ; empty slot
+.loop1
+ ld [de], a
+ inc de
+ dec c
+ jr nz, .loop1
+ pop af
+ ld de, wBuffer1
+.loop2
+ push af
+ call .GetHUDTile
+ inc de
+ pop af
+ dec a
+ jr nz, .loop2
+ ret
+
+.GetHUDTile:
+ ld a, [hli]
+ and a
+ jr nz, .got_hp
+ ld a, [hl]
+ and a
+ ld b, $33 ; fainted
+ jr z, .fainted
+
+.got_hp
+ dec hl
+ dec hl
+ dec hl
+ ld a, [hl]
+ and a
+ ld b, $32 ; statused
+ jr nz, .load
+ dec b ; normal
+ jr .load
+
+.fainted
+ dec hl
+ dec hl
+ dec hl
+
+.load
+ ld a, b
+ ld [de], a
+ ld bc, PARTYMON_STRUCT_LENGTH + MON_HP - MON_STATUS
+ add hl, bc
+ ret
+
+DrawPlayerHUDBorder:
+ ld hl, .tiles
+ ld de, wTrainerHUDTiles
+ ld bc, .tiles_end - .tiles
+ call CopyBytes
+ hlcoord 18, 10
+ ld de, -1 ; start on right
+ jr PlaceHUDBorderTiles
+
+.tiles
+ db $73 ; right side
+ db $77 ; bottom right
+ db $6f ; bottom left
+ db $76 ; bottom side
+.tiles_end
+
+DrawPlayerPartyIconHUDBorder:
+ ld hl, .tiles
+ ld de, wTrainerHUDTiles
+ ld bc, .tiles_end - .tiles
+ call CopyBytes
+ hlcoord 18, 10
+ ld de, -1 ; start on right
+ jr PlaceHUDBorderTiles
+
+.tiles
+ db $73 ; right side
+ db $5c ; bottom right
+ db $6f ; bottom left
+ db $76 ; bottom side
+.tiles_end
+
+DrawEnemyHUDBorder:
+ ld hl, .tiles
+ ld de, wTrainerHUDTiles
+ ld bc, .tiles_end - .tiles
+ call CopyBytes
+ hlcoord 1, 2
+ ld de, 1 ; start on left
+ call PlaceHUDBorderTiles
+ ld a, [wBattleMode]
+ dec a
+ ret nz
+ ld a, [wTempEnemyMonSpecies]
+ dec a
+ call CheckCaughtMon
+ ret z
+ hlcoord 1, 1
+ ld [hl], $5d
+ ret
+
+.tiles
+ db $6d ; left side
+ db $74 ; bottom left
+ db $78 ; bottom right
+ db $76 ; bottom side
+.tiles_end
+
+PlaceHUDBorderTiles:
+ ld a, [wTrainerHUDTiles + 0]
+ ld [hl], a
+ ld bc, SCREEN_WIDTH
+ add hl, bc
+ ld a, [wTrainerHUDTiles + 1]
+ ld [hl], a
+ ld b, 8
+.loop
+ add hl, de
+ ld a, [wTrainerHUDTiles + 3]
+ ld [hl], a
+ dec b
+ jr nz, .loop
+ add hl, de
+ ld a, [wTrainerHUDTiles + 2]
+ ld [hl], a
+ ret
+
+LinkBattle_TrainerHuds:
+ call LoadBallIconGFX
+ ld hl, wPartyMon1HP
+ ld de, wPartyCount
+ call StageBallTilesData
+ ld hl, wPlaceBallsX
+ ld a, 10 * 8
+ ld [hli], a
+ ld [hl], 8 * 8
+ ld a, 8
+ ld [wPlaceBallsDirection], a
+ ld hl, wVirtualOAMSprite00
+ call LoadTrainerHudOAM
+
+ ld hl, wOTPartyMon1HP
+ ld de, wOTPartyCount
+ call StageBallTilesData
+ ld hl, wPlaceBallsX
+ ld a, 10 * 8
+ ld [hli], a
+ ld [hl], 13 * 8
+ ld hl, wVirtualOAMSprite00 + PARTY_LENGTH * SPRITEOAMSTRUCT_LENGTH
+ jp LoadTrainerHudOAM
+
+LoadTrainerHudOAM:
+ ld de, wBuffer1
+ ld c, PARTY_LENGTH
+.loop
+ ld a, [wPlaceBallsY]
+ ld [hli], a ; y
+ ld a, [wPlaceBallsX]
+ ld [hli], a ; x
+ ld a, [de]
+ ld [hli], a ; tile id
+ ld a, PAL_BATTLE_OB_YELLOW
+ ld [hli], a ; attributes
+ ld a, [wPlaceBallsX]
+ ld b, a
+ ld a, [wPlaceBallsDirection]
+ add b
+ ld [wPlaceBallsX], a
+ inc de
+ dec c
+ jr nz, .loop
+ ret
+
+LoadBallIconGFX:
+ ld de, .gfx
+ ld hl, vTiles0 tile $31
+ lb bc, BANK(LoadBallIconGFX), 4
+ jp Request2bpp
+
+.gfx
+INCBIN "gfx/battle/balls.2bpp"
+
+_ShowLinkBattleParticipants:
+ call ClearBGPalettes
+ call LoadFontsExtra
+ hlcoord 3, 3
+ ld b, 9
+ ld c, 12
+ call Textbox
+ hlcoord 4, 5
+ ld de, wPlayerName
+ call PlaceString
+ hlcoord 4, 10
+ ld de, wOTPlayerName
+ call PlaceString
+ hlcoord 9, 8
+ ld a, "<BOLD_V>"
+ ld [hli], a
+ ld [hl], "<BOLD_S>"
+ farcall LinkBattle_TrainerHuds ; no need to farcall
+ ld b, SCGB_DIPLOMA
+ call GetSGBLayout
+ call SetPalettes
+ ld a, $e4
+ ldh [rOBP0], a
+ ld c, 150
+ jp DelayFrames
diff --git a/engine/events/move_deleter.asm b/engine/events/move_deleter.asm
new file mode 100644
index 00000000..f9f83fab
--- /dev/null
+++ b/engine/events/move_deleter.asm
@@ -0,0 +1,150 @@
+MoveDeletion:
+ ld hl, .DeleterIntroText
+ call PrintText
+ call YesNoBox
+ jr c, .declined
+ ld hl, .DeleterAskWhichMonText
+ call PrintText
+ farcall SelectMonFromParty
+ jr c, .declined
+ ld a, [wCurPartySpecies]
+ cp EGG
+ jr z, .egg
+ ld a, [wCurPartyMon]
+ ld hl, wPartyMon1Moves + 1
+ ld bc, PARTYMON_STRUCT_LENGTH
+ call AddNTimes
+ ld a, [hl]
+ and a
+ jr z, .onlyonemove
+ ld hl, .DeleterAskWhichMoveText
+ call PrintText
+ call LoadStandardMenuHeader
+ farcall ChooseMoveToDelete
+ push af
+ call ReturnToMapWithSpeechTextbox
+ pop af
+ jr c, .declined
+ ld a, [wMenuCursorY]
+ push af
+ ld a, [wCurSpecies]
+ ld [wNamedObjectIndexBuffer], a
+ call GetMoveName
+ ld hl, .AskDeleteMoveText
+ call PrintText
+ call YesNoBox
+ pop bc
+ jr c, .declined
+ call .DeleteMove
+ call WaitSFX
+ ld de, SFX_MOVE_DELETED
+ call PlaySFX
+ call WaitSFX
+ ld hl, .DeleterForgotMoveText
+ call PrintText
+ ret
+
+.egg
+ ld hl, .MailEggText
+ call PrintText
+ ret
+
+.declined
+ ld hl, .DeleterNoComeAgainText
+ call PrintText
+ ret
+
+.onlyonemove
+ ld hl, .MoveKnowsOneText
+ call PrintText
+ ret
+
+.MoveKnowsOneText:
+ text_far _MoveKnowsOneText
+ text_end
+
+.AskDeleteMoveText:
+ text_far _AskDeleteMoveText
+ text_end
+
+.DeleterForgotMoveText:
+ text_far _DeleterForgotMoveText
+ text_end
+
+.MailEggText:
+ text_far _DeleterEggText
+ text_end
+
+.DeleterNoComeAgainText:
+ text_far _DeleterNoComeAgainText
+ text_end
+
+.DeleterAskWhichMoveText:
+ text_far _DeleterAskWhichMoveText
+ text_end
+
+.DeleterIntroText:
+ text_far _DeleterIntroText
+ text_end
+
+.DeleterAskWhichMonText:
+ text_far _DeleterAskWhichMonText
+ text_end
+
+.DeleteMove:
+ ld a, b
+ push bc
+ dec a
+ ld c, a
+ ld b, 0
+ ld hl, wPartyMon1Moves
+ add hl, bc
+ ld a, [wCurPartyMon]
+ ld bc, PARTYMON_STRUCT_LENGTH
+ call AddNTimes
+ pop bc
+ push bc
+ inc b
+.loop
+ ld a, b
+ cp NUM_MOVES + 1
+ jr z, .okay
+ inc hl
+ ld a, [hld]
+ ld [hl], a
+ inc hl
+ inc b
+ jr .loop
+
+.okay
+ xor a
+ ld [hl], a
+ pop bc
+
+ ld a, b
+ push bc
+ dec a
+ ld c, a
+ ld b, 0
+ ld hl, wPartyMon1PP
+ add hl, bc
+ ld a, [wCurPartyMon]
+ ld bc, PARTYMON_STRUCT_LENGTH
+ call AddNTimes
+ pop bc
+ inc b
+.loop2
+ ld a, b
+ cp NUM_MOVES + 1
+ jr z, .done
+ inc hl
+ ld a, [hld]
+ ld [hl], a
+ inc hl
+ inc b
+ jr .loop2
+
+.done
+ xor a
+ ld [hl], a
+ ret
diff --git a/engine/events/pokerus/pokerus.asm b/engine/events/pokerus/pokerus.asm
new file mode 100644
index 00000000..63eb7fe1
--- /dev/null
+++ b/engine/events/pokerus/pokerus.asm
@@ -0,0 +1,161 @@
+GivePokerusAndConvertBerries:
+ call ConvertBerriesToBerryJuice
+ ld hl, wPartyMon1PokerusStatus
+ ld a, [wPartyCount]
+ ld b, a
+ ld de, PARTYMON_STRUCT_LENGTH
+; Check to see if any of your Pokemon already has Pokerus.
+; If so, sample its spread through your party.
+; This means that you cannot get Pokerus de novo while
+; a party member has an active infection.
+.loopMons
+ ld a, [hl]
+ and $f
+ jr nz, .TrySpreadPokerus
+ add hl, de
+ dec b
+ jr nz, .loopMons
+
+; If we haven't been to Goldenrod City at least once,
+; prevent the contraction of Pokerus.
+ ld hl, wStatusFlags2
+ bit STATUSFLAGS2_REACHED_GOLDENROD_F, [hl]
+ ret z
+ call Random
+ ldh a, [hRandomAdd]
+ and a
+ ret nz
+ ldh a, [hRandomSub]
+ cp $3
+ ret nc ; 3/65536 chance (00 00, 00 01 or 00 02)
+ ld a, [wPartyCount]
+ ld b, a
+.randomMonSelectLoop
+ call Random
+ and $7
+ cp b
+ jr nc, .randomMonSelectLoop
+ ld hl, wPartyMon1PokerusStatus
+ call GetPartyLocation ; get pokerus byte of random mon
+ ld a, [hl]
+ and $f0
+ ret nz ; if it already has pokerus, do nothing
+.randomPokerusLoop ; Simultaneously sample the strain and duration
+ call Random
+ and a
+ jr z, .randomPokerusLoop
+ ld b, a
+ and $f0
+ jr z, .load_pkrs
+ ld a, b
+ and $7
+ inc a
+.load_pkrs
+ ld b, a ; this should come before the label
+ swap b
+ and $3
+ inc a
+ add b
+ ld [hl], a
+ ret
+
+.TrySpreadPokerus:
+ call Random
+ cp 33 percent + 1
+ ret nc ; 1/3 chance
+
+ ld a, [wPartyCount]
+ cp 1
+ ret z ; only one mon, nothing to do
+
+ ld c, [hl]
+ ld a, b
+ cp 2
+ jr c, .checkPreviousMonsLoop ; no more mons after this one, go backwards
+
+ call Random
+ cp 50 percent + 1
+ jr c, .checkPreviousMonsLoop ; 1/2 chance, go backwards
+.checkFollowingMonsLoop
+ add hl, de
+ ld a, [hl]
+ and a
+ jr z, .infectMon
+ ld c, a
+ and $3
+ ret z ; if mon has cured pokerus, stop searching
+ dec b ; go on to next mon
+ ld a, b
+ cp 1
+ jr nz, .checkFollowingMonsLoop ; no more mons left
+ ret
+
+.checkPreviousMonsLoop
+ ld a, [wPartyCount]
+ cp b
+ ret z ; no more mons
+ ld a, l
+ sub e
+ ld l, a
+ ld a, h
+ sbc d
+ ld h, a
+ ld a, [hl]
+ and a
+ jr z, .infectMon
+ ld c, a
+ and $3
+ ret z ; if mon has cured pokerus, stop searching
+ inc b ; go on to next mon
+ jr .checkPreviousMonsLoop
+
+.infectMon
+ ld a, c
+ and $f0
+ ld b, a
+ ld a, c
+ swap a
+ and $3
+ inc a
+ add b
+ ld [hl], a
+ ret
+
+ConvertBerriesToBerryJuice:
+; If we haven't been to Goldenrod City at least once,
+; prevent Shuckle from turning held Berry into Berry Juice.
+ ld hl, wStatusFlags2
+ bit STATUSFLAGS2_REACHED_GOLDENROD_F, [hl]
+ ret z
+ call Random
+ cp 6 percent + 1 ; 1/16 chance
+ ret nc
+ ld hl, wPartyMons
+ ld a, [wPartyCount]
+.partyMonLoop
+ push af
+ push hl
+ ld a, [hl]
+ cp SHUCKLE
+ jr nz, .loopMon
+ ld bc, MON_ITEM
+ add hl, bc
+ ld a, [hl]
+ cp BERRY
+ jr z, .convertToJuice
+
+.loopMon
+ pop hl
+ ld bc, PARTYMON_STRUCT_LENGTH
+ add hl, bc
+ pop af
+ dec a
+ jr nz, .partyMonLoop
+ ret
+
+.convertToJuice
+ ld a, BERRY_JUICE
+ ld [hl], a
+ pop hl
+ pop af
+ ret
diff --git a/engine/items/items.asm b/engine/items/items.asm
index 748b3d46..5ab48b2a 100755
--- a/engine/items/items.asm
+++ b/engine/items/items.asm
@@ -35,7 +35,7 @@ ReceiveTMHM:
ld l, e
ld a, [wCurItem]
ld c, a
- call GetTMHMNumber
+ call GetNumberedTMHM
jp PutItemInTMPocket
_TossItem:: ; d21a (3:521a)
@@ -65,7 +65,7 @@ RemoveTMHM:
ld l, e
ld a, [wCurItem]
ld c, a
- call GetTMHMNumber
+ call GetNumberedTMHM
jp RemoveTMorHM
RemoveKeyItem:
@@ -106,7 +106,7 @@ CheckTMHM:
ld l, e
ld a, [wCurItem]
ld c, a
- call GetTMHMNumber
+ call GetNumberedTMHM
jp CheckTMorHM
CheckKeyItem:
@@ -419,11 +419,11 @@ RemoveTMorHM: ; d3e5 (3:53e5)
ld [hl], a
ld [wItemQuantityBuffer], a
jr nz, .asm_d404
- ld a, [wcfd2]
+ ld a, [wTMHMPocketScrollPosition]
and a
jr z, .asm_d404
dec a
- ld [wcfd2], a
+ ld [wTMHMPocketScrollPosition], a
.asm_d404
scf
ret
@@ -443,7 +443,7 @@ CheckTMorHM: ; d408 (3:5408)
scf
ret
-GetTMHMNumber:: ; d414 (3:5414)
+GetNumberedTMHM:: ; d414 (3:5414)
ld a, c
cp ITEM_C3
jr c, .asm_d41f
diff --git a/engine/items/pack.asm b/engine/items/pack.asm
index 5225362a..76b0f5e7 100755
--- a/engine/items/pack.asm
+++ b/engine/items/pack.asm
@@ -115,7 +115,7 @@ Pack_InitTMHMPocket:
ret
Pack_TMHMPocketMenu:
- farcall Pack_TMHMPocketMenu_
+ farcall TMHMPocket
ld b, $5
ld c, $1
call Function10cef
@@ -733,7 +733,7 @@ BattlePack_InitTMHMPocket:
ret
BattlePack_TMHMPocketMenu:
- farcall Pack_TMHMPocketMenu_ ; b:457a
+ farcall TMHMPocket ; b:457a
ld b, $5
ld c, $1
call Function10cef
@@ -973,7 +973,7 @@ DepositOrSell_TMHMPocket:
ld a, $3
call Function10b92
call Function10cca
- farcall Pack_TMHMPocketMenu_ ; b:457a
+ farcall TMHMPocket ; b:457a
ld a, [wCurItem]
ld [wCurItem], a
ret
@@ -1126,7 +1126,7 @@ TutorialTMHM:
ld a, $3
call Function10b92
call Function10cca
- farcall Pack_TMHMPocketMenu_
+ farcall TMHMPocket
ld a, [wCurItem]
ld [wCurItem], a
ret
diff --git a/engine/items/print_item_description.asm b/engine/items/print_item_description.asm
new file mode 100644
index 00000000..89a949ad
--- /dev/null
+++ b/engine/items/print_item_description.asm
@@ -0,0 +1,32 @@
+PrintItemDescription:
+; Print the description for item [wCurSpecies] at de.
+
+ ld a, [wCurSpecies]
+ cp TM01
+ jr c, .not_a_tm
+
+ ld [wCurItem], a
+ push de
+ call GetTMHMItemMove
+ pop hl
+ ld a, [wTempTMHM]
+ ld [wCurSpecies], a
+ call PrintMoveDesc
+ ret
+
+.not_a_tm
+ push de
+ ld hl, ItemDescriptions
+ ld a, [wCurSpecies]
+ dec a
+ ld c, a
+ ld b, 0
+ add hl, bc
+ add hl, bc
+ ld a, BANK(ItemDescriptions)
+ call GetFarHalfword
+ ld d, h
+ ld e, l
+ pop hl
+ ld a, BANK(ItemDescriptions)
+ jp FarString
diff --git a/engine/items/tmhm.asm b/engine/items/tmhm.asm
new file mode 100644
index 00000000..4095be03
--- /dev/null
+++ b/engine/items/tmhm.asm
@@ -0,0 +1,552 @@
+TMHMPocket:
+ ld a, $1
+ ldh [hInMenu], a
+ call TMHM_PocketLoop
+ ld a, $0
+ ldh [hInMenu], a
+ ret nc
+ call PlaceHollowCursor
+ call WaitBGMap
+ ld a, [wCurItem]
+ dec a
+ ld [wCurItemQuantity], a
+ ld hl, wTMsHMs
+ ld c, a
+ ld b, 0
+ add hl, bc
+ ld a, [hl]
+ ld [wItemQuantityBuffer], a
+ call .ConvertItemToTMHMNumber
+ scf
+ ret
+
+.ConvertItemToTMHMNumber:
+ ld a, [wCurItem]
+ ld c, a
+ callfar GetNumberedTM
+ ld a, c
+ ld [wCurItem], a
+ ret
+
+ConvertCurItemIntoCurTMHM:
+ ld a, [wCurItem]
+ ld c, a
+ callfar GetNumberedTMHM
+ ld a, c
+ ld [wTempTMHM], a
+ ret
+
+GetTMHMItemMove:
+ call ConvertCurItemIntoCurTMHM
+ predef GetTMHMMove
+ ret
+
+AskTeachTMHM:
+ ld hl, wOptions
+ ld a, [hl]
+ push af
+ res NO_TEXT_SCROLL, [hl]
+ ld a, [wCurItem]
+ cp TM01
+ jr c, .NotTMHM
+ call GetTMHMItemMove
+ ld a, [wTempTMHM]
+ ld [wPutativeTMHMMove], a
+ call GetMoveName
+ call CopyName1
+ ld hl, BootedTMText ; Booted up a TM
+ ld a, [wCurItem]
+ cp HM01
+ jr c, .TM
+ ld hl, BootedHMText ; Booted up an HM
+.TM:
+ call PrintText
+ ld hl, ContainedMoveText
+ call PrintText
+ call YesNoBox
+.NotTMHM:
+ pop bc
+ ld a, b
+ ld [wOptions], a
+ ret
+
+ChooseMonToLearnTMHM:
+ ld hl, wStringBuffer2
+ ld de, wTMHMMoveNameBackup
+ ld bc, 12
+ call CopyBytes
+ call ClearBGPalettes
+ChooseMonToLearnTMHM_NoRefresh:
+ farcall LoadPartyMenuGFX
+ farcall InitPartyMenuWithCancel
+ farcall InitPartyMenuGFX
+ ld a, PARTYMENUACTION_TEACH_TMHM
+ ld [wPartyMenuActionText], a
+.loopback
+ farcall WritePartyMenuTilemap
+ farcall PrintPartyMenuText
+ call WaitBGMap
+ call SetPalettes
+ call DelayFrame
+ farcall PartyMenuSelect
+ push af
+ ld a, [wCurPartySpecies]
+ cp EGG
+ pop bc ; now contains the former contents of af
+ jr z, .egg
+ push bc
+ ld hl, wTMHMMoveNameBackup
+ ld de, wStringBuffer2
+ ld bc, 12
+ call CopyBytes
+ pop af ; now contains the original contents of af
+ ret
+
+.egg
+ push hl
+ push de
+ push bc
+ push af
+ ld de, SFX_WRONG
+ call PlaySFX
+ call WaitSFX
+ pop af
+ pop bc
+ pop de
+ pop hl
+ jr .loopback
+
+TeachTMHM:
+ predef CanLearnTMHMMove
+
+ push bc
+ ld a, [wCurPartyMon]
+ ld hl, wPartyMonNicknames
+ call GetNick
+ pop bc
+
+ ld a, c
+ and a
+ jr nz, .compatible
+ push de
+ ld de, SFX_WRONG
+ call PlaySFX
+ pop de
+ ld hl, TMHMNotCompatibleText
+ call PrintText
+ jr .nope
+
+.compatible
+ callfar KnowsMove
+ jr c, .nope
+
+ predef LearnMove
+ ld a, b
+ and a
+ jr z, .nope
+
+ ld a, [wCurItem]
+ call IsHM
+ ret c
+
+ ld c, HAPPINESS_LEARNMOVE
+ callfar ChangeHappiness
+ call ConsumeTM
+ jr .learned_move
+
+.nope
+ and a
+ ret
+
+.unused
+ ld a, 2
+ ld [wItemEffectSucceeded], a
+.learned_move
+ scf
+ ret
+
+BootedTMText:
+ text_far _BootedTMText
+ text_end
+
+BootedHMText:
+ text_far _BootedHMText
+ text_end
+
+ContainedMoveText:
+ text_far _ContainedMoveText
+ text_end
+
+TMHMNotCompatibleText:
+ text_far _TMHMNotCompatibleText
+ text_end
+
+TMHM_PocketLoop:
+ xor a
+ ldh [hBGMapMode], a
+ call TMHM_DisplayPocketItems
+ ld a, 2
+ ld [w2DMenuCursorInitY], a
+ ld a, 7
+ ld [w2DMenuCursorInitX], a
+ ld a, 1
+ ld [w2DMenuNumCols], a
+ ld a, 5
+ sub d
+ inc a
+ cp 6
+ jr nz, .okay
+ dec a
+.okay
+ ld [w2DMenuNumRows], a
+ ld a, $c
+ ld [w2DMenuFlags1], a
+ xor a
+ ld [w2DMenuFlags2], a
+ ld a, $20
+ ld [w2DMenuCursorOffsets], a
+ ld a, A_BUTTON | B_BUTTON | D_UP | D_DOWN | D_LEFT | D_RIGHT
+ ld [wMenuJoypadFilter], a
+ ld a, [wTMHMPocketCursor]
+ inc a
+ ld [wMenuCursorY], a
+ ld a, $1
+ ld [wMenuCursorX], a
+ jr TMHM_ShowTMMoveDescription
+
+TMHM_JoypadLoop:
+ call TMHM_DisplayPocketItems
+ call StaticMenuJoypad
+ ld b, a
+ ld a, [wMenuCursorY]
+ dec a
+ ld [wTMHMPocketCursor], a
+ xor a
+ ldh [hBGMapMode], a
+ ld a, [w2DMenuFlags2]
+ bit 7, a
+ jp nz, TMHM_ScrollPocket
+ ld a, b
+ ld [wMenuJoypad], a
+ bit A_BUTTON_F, a
+ jp nz, TMHM_ChooseTMorHM
+ bit B_BUTTON_F, a
+ jp nz, TMHM_ExitPack
+ bit D_RIGHT_F, a
+ jp nz, TMHM_ExitPocket
+ bit D_LEFT_F, a
+ jp nz, TMHM_ExitPocket
+TMHM_ShowTMMoveDescription:
+ call TMHM_CheckHoveringOverCancel
+ jp nc, TMHM_ExitPocket
+ hlcoord 0, 12
+ ld b, 4
+ ld c, SCREEN_WIDTH - 2
+ call Textbox
+ ld a, [wCurItem]
+ cp NUM_TMS + NUM_HMS + 1
+ jr nc, TMHM_JoypadLoop
+ ld [wTempTMHM], a
+ predef GetTMHMMove
+ ld a, [wTempTMHM]
+ ld [wCurSpecies], a
+ hlcoord 1, 14
+ call PrintMoveDesc
+ jp TMHM_JoypadLoop
+
+TMHM_ChooseTMorHM:
+ call TMHM_PlaySFX_ReadText2
+ call CountTMsHMs ; This stores the count to wTempTMHM.
+ ld a, [wMenuCursorY]
+ dec a
+ ld b, a
+ ld a, [wTMHMPocketScrollPosition]
+ add b
+ ld b, a
+ ld a, [wTempTMHM]
+ cp b
+ jr z, _TMHM_ExitPack ; our cursor was hovering over CANCEL
+TMHM_CheckHoveringOverCancel:
+ call TMHM_GetCurrentPocketPosition
+ ld a, [wMenuCursorY]
+ ld b, a
+.loop
+ inc c
+ ld a, c
+ cp NUM_TMS + NUM_HMS + 1
+ jr nc, .okay
+ ld a, [hli]
+ and a
+ jr z, .loop
+ dec b
+ jr nz, .loop
+ ld a, c
+.okay
+ ld [wCurItem], a
+ cp -1
+ ret
+
+TMHM_ExitPack:
+ call TMHM_PlaySFX_ReadText2
+_TMHM_ExitPack:
+ ld a, $2
+ ld [wMenuJoypad], a
+ and a
+ ret
+
+TMHM_ExitPocket:
+ and a
+ ret
+
+TMHM_ScrollPocket:
+ ld a, b
+ bit 7, a
+ jr nz, .skip
+ ld hl, wTMHMPocketScrollPosition
+ ld a, [hl]
+ and a
+ jp z, TMHM_JoypadLoop
+ dec [hl]
+ call TMHM_DisplayPocketItems
+ jp TMHM_ShowTMMoveDescription
+
+.skip
+ call TMHM_GetCurrentPocketPosition
+ ld b, 5
+.loop
+ inc c
+ ld a, c
+ cp NUM_TMS + NUM_HMS + 1
+ jp nc, TMHM_JoypadLoop
+ ld a, [hli]
+ and a
+ jr z, .loop
+ dec b
+ jr nz, .loop
+ ld hl, wTMHMPocketScrollPosition
+ inc [hl]
+ call TMHM_DisplayPocketItems
+ jp TMHM_ShowTMMoveDescription
+
+TMHM_DisplayPocketItems:
+ ld a, [wBattleType]
+ cp BATTLETYPE_TUTORIAL
+ jp z, Tutorial_TMHMPocket
+
+ hlcoord 5, 2
+ lb bc, 10, 15
+ ld a, " "
+ call ClearBox
+ call TMHM_GetCurrentPocketPosition
+ ld d, $5
+.loop2
+ inc c
+ ld a, c
+ cp NUM_TMS + NUM_HMS + 1
+ jr nc, .NotTMHM
+ ld a, [hli]
+ and a
+ jr z, .loop2
+ ld b, a
+ ld a, c
+ ld [wTempTMHM], a
+ push hl
+ push de
+ push bc
+ call TMHMPocket_GetCurrentLineCoord
+ push hl
+ ld a, [wTempTMHM]
+ cp NUM_TMS + 1
+ jr nc, .HM
+ ld de, wTempTMHM
+ lb bc, PRINTNUM_LEADINGZEROS | 1, 2
+ call PrintNum
+ jr .okay
+
+.HM:
+ push af
+ sub NUM_TMS
+ ld [wTempTMHM], a
+ ld [hl], "H"
+ inc hl
+ ld de, wTempTMHM
+ lb bc, PRINTNUM_LEFTALIGN | 1, 2
+ call PrintNum
+ pop af
+ ld [wTempTMHM], a
+.okay
+ predef GetTMHMMove
+ ld a, [wNamedObjectIndexBuffer]
+ ld [wPutativeTMHMMove], a
+ call GetMoveName
+ pop hl
+ ld bc, 3
+ add hl, bc
+ push hl
+ call PlaceString
+ pop hl
+ pop bc
+ ld a, c
+ push bc
+ cp NUM_TMS + 1
+ jr nc, .hm2
+ ld bc, SCREEN_WIDTH + 9
+ add hl, bc
+ ld [hl], "×"
+ inc hl
+ ld a, "0" ; why are we doing this?
+ pop bc
+ push bc
+ ld a, b
+ ld [wTempTMHM], a
+ ld de, wTempTMHM
+ lb bc, 1, 2
+ call PrintNum
+.hm2
+ pop bc
+ pop de
+ pop hl
+ dec d
+ jr nz, .loop2
+ jr .done
+
+.NotTMHM:
+ call TMHMPocket_GetCurrentLineCoord
+ inc hl
+ inc hl
+ inc hl
+ push de
+ ld de, TMHM_String_Cancel
+ call PlaceString
+ pop de
+.done
+ ret
+
+TMHMPocket_GetCurrentLineCoord:
+ hlcoord 5, 0
+ ld bc, 2 * SCREEN_WIDTH
+ ld a, 6
+ sub d
+ ld e, a
+ ; AddNTimes
+.loop
+ add hl, bc
+ dec e
+ jr nz, .loop
+ ret
+
+Unreferenced_Function2ca95:
+ pop hl
+ ld bc, 3
+ add hl, bc
+ predef GetTMHMMove
+ ld a, [wTempTMHM]
+ ld [wPutativeTMHMMove], a
+ call GetMoveName
+ push hl
+ call PlaceString
+ pop hl
+ ret
+
+TMHM_String_Cancel:
+ db "CANCEL@"
+
+TMHM_GetCurrentPocketPosition:
+ ld hl, wTMsHMs
+ ld a, [wTMHMPocketScrollPosition]
+ ld b, a
+ inc b
+ ld c, 0
+.loop
+ inc c
+ ld a, [hli]
+ and a
+ jr z, .loop
+ dec b
+ jr nz, .loop
+ dec hl
+ dec c
+ ret
+
+Tutorial_TMHMPocket:
+ hlcoord 9, 3
+ push de
+ ld de, TMHM_String_Cancel
+ call PlaceString
+ pop de
+ ret
+
+TMHM_PlaySFX_ReadText2:
+ push de
+ ld de, SFX_READ_TEXT_2
+ call PlaySFX
+ pop de
+ ret
+
+Unreferenced_Function2cadf:
+ call ConvertCurItemIntoCurTMHM
+ call .CheckHaveRoomForTMHM
+ ld hl, .NoRoomTMHMText
+ jr nc, .print
+ ld hl, .ReceivedTMHMText
+.print
+ jp PrintText
+
+.NoRoomTMHMText:
+ text_far _NoRoomTMHMText
+ text_end
+
+.ReceivedTMHMText:
+ text_far _ReceivedTMHMText
+ text_end
+
+.CheckHaveRoomForTMHM:
+ ld a, [wTempTMHM]
+ dec a
+ ld hl, wTMsHMs
+ ld b, 0
+ ld c, a
+ add hl, bc
+ ld a, [hl]
+ inc a
+ cp NUM_TMS * 2
+ ret nc
+ ld [hl], a
+ ret
+
+ConsumeTM:
+ call ConvertCurItemIntoCurTMHM
+ ld a, [wTempTMHM]
+ dec a
+ ld hl, wTMsHMs
+ ld b, 0
+ ld c, a
+ add hl, bc
+ ld a, [hl]
+ and a
+ ret z
+ dec a
+ ld [hl], a
+ ret nz
+ ld a, [wTMHMPocketScrollPosition]
+ and a
+ ret z
+ dec a
+ ld [wTMHMPocketScrollPosition], a
+ ret
+
+CountTMsHMs:
+ ld b, 0
+ ld c, NUM_TMS + NUM_HMS
+ ld hl, wTMsHMs
+.loop
+ ld a, [hli]
+ and a
+ jr z, .skip
+ inc b
+.skip
+ dec c
+ jr nz, .loop
+ ld a, b
+ ld [wTempTMHM], a
+ ret
diff --git a/engine/link/mystery_gift_2.asm b/engine/link/mystery_gift_2.asm
new file mode 100644
index 00000000..493db05c
--- /dev/null
+++ b/engine/link/mystery_gift_2.asm
@@ -0,0 +1,150 @@
+PrepMysteryGiftDataToSend:
+ ld de, wMysteryGiftStaging
+ ld a, $1 + GS_VERSION
+ ld [de], a
+ inc de ; wc701
+ ld a, BANK(sGameData)
+ call OpenSRAM
+ ld hl, sPlayerData + wPlayerID - wPlayerData
+ ld a, [hli]
+ ld [de], a
+ ld b, a
+ inc de ; wc702
+ ld a, [hl]
+ ld [de], a
+ ld c, a
+ inc de ; wc703
+ push bc
+ ld hl, sPlayerData + wPlayerName - wPlayerData
+ ld bc, NAME_LENGTH
+ call CopyBytes
+ push de ; wc70e
+ ld hl, sPokemonData + wPokedexCaught - wPokemonData
+ ld b, wEndPokedexCaught - wPokedexCaught
+ call CountSetBits
+ pop de
+ pop bc
+ ld a, [wNumSetBits]
+ ld [de], a
+ inc de ; wc70f
+ call CloseSRAM
+ call Random
+ and 1
+ ld [de], a
+ inc de ; wc710
+ call .RandomSample
+ ld [de], a
+ inc de ; wc711
+ ld a, c
+ ld c, b
+ ld b, a
+ call .RandomSample
+ ld [de], a
+ inc de ; wc712
+ ld a, BANK(sBackupMysteryGiftItem)
+ call OpenSRAM
+ ld a, [sBackupMysteryGiftItem]
+ ld [de], a
+ inc de
+ ld a, [sBackupMysteryGiftItem + 1]
+ ld [de], a
+ ld a, $14
+ ld [wc900], a
+ call CloseSRAM
+ ld hl, wMysteryGiftStaging
+ ld de, wMysteryGiftPlayerData
+ ld bc, wMysteryGiftPlayerDataEnd - wMysteryGiftPlayerData
+ jp CopyBytes
+
+.RandomSample:
+ push de
+ call Random
+ cp 10 percent
+ jr c, .tenpercent
+ call Random
+ and %111
+ ld d, a
+ rl d
+ ld e, $80
+.loop
+ rlc e
+ dec a
+ jr nz, .loop
+ ld a, e
+ and c
+ jr z, .skip
+ ld a, $1
+.skip
+ add d
+ jr .done
+
+.tenpercent
+ call Random
+ cp 20 percent - 1
+ jr c, .twopercent
+ call Random
+ and %011
+ ld d, a
+ rl d
+ ld e, $80
+.loop2
+ rlc e
+ dec a
+ jr nz, .loop2
+ ld a, e
+ and b
+ jr z, .skip2
+ ld a, $1
+.skip2
+ add d
+ add $10
+ jr .done
+
+.twopercent
+ call Random
+ cp 20 percent - 1
+ jr c, .pointfourpercent
+ ld a, b
+ swap a
+ and $7
+ add $18
+ jr .done
+
+.pointfourpercent
+ ld a, b
+ and $80
+ ld a, $20
+ jr z, .done
+ ld a, $21
+
+.done
+ pop de
+ ret
+
+MysteryGiftGetItemHeldEffect:
+ ld a, c
+ cp MysteryGiftItems.End - MysteryGiftItems
+ jr nc, MysteryGiftFallbackItem
+ ld hl, MysteryGiftItems
+ ld b, 0
+ add hl, bc
+ ld c, [hl]
+ ret
+
+MysteryGiftGetDecoration:
+ ld a, c
+ cp MysteryGiftDecos.End - MysteryGiftDecos
+ jr nc, MysteryGiftFallbackItem
+ ld hl, MysteryGiftDecos
+ ld b, 0
+ add hl, bc
+ ld c, [hl]
+ ret
+
+MysteryGiftFallbackItem:
+ ld c, DECO_POLKADOT_BED ; GREAT_BALL
+ ret
+
+INCLUDE "data/items/mystery_gift_items.asm"
+
+INCLUDE "data/decorations/mystery_gift_decos.asm"
diff --git a/engine/pokemon/print_move_description.asm b/engine/pokemon/print_move_description.asm
new file mode 100644
index 00000000..e002e3d1
--- /dev/null
+++ b/engine/pokemon/print_move_description.asm
@@ -0,0 +1,16 @@
+PrintMoveDesc:
+ push hl
+ ld hl, MoveDescriptions
+ ld a, [wCurSpecies]
+ dec a
+ ld c, a
+ ld b, 0
+ add hl, bc
+ add hl, bc
+ ld a, BANK(MoveDescriptions)
+ call GetFarHalfword
+ ld d, h
+ ld e, l
+ pop hl
+ ld a, BANK(MoveDescriptions)
+ jp FarString