summaryrefslogtreecommitdiff
path: root/engine/items
diff options
context:
space:
mode:
Diffstat (limited to 'engine/items')
-rw-r--r--engine/items/buy_sell_toss.asm220
-rw-r--r--engine/items/item_effects.asm2958
-rw-r--r--engine/items/items.asm581
-rw-r--r--engine/items/mart.asm895
-rw-r--r--engine/items/pack.asm1608
-rw-r--r--engine/items/pack_kris.asm20
-rw-r--r--engine/items/print_item_description.asm32
-rw-r--r--engine/items/switch_items.asm271
-rw-r--r--engine/items/tmhm.asm574
-rw-r--r--engine/items/tmhm2.asm46
-rw-r--r--engine/items/update_item_description.asm13
11 files changed, 7218 insertions, 0 deletions
diff --git a/engine/items/buy_sell_toss.asm b/engine/items/buy_sell_toss.asm
new file mode 100644
index 000000000..3303f4319
--- /dev/null
+++ b/engine/items/buy_sell_toss.asm
@@ -0,0 +1,220 @@
+SelectQuantityToToss:
+ ld hl, TossItem_MenuHeader
+ call LoadMenuHeader
+ call Toss_Sell_Loop
+ ret
+
+SelectQuantityToBuy:
+ farcall GetItemPrice
+RooftopSale_SelectQuantityToBuy:
+ ld a, d
+ ld [wBuffer1], a
+ ld a, e
+ ld [wBuffer2], a
+ ld hl, BuyItem_MenuHeader
+ call LoadMenuHeader
+ call Toss_Sell_Loop
+ ret
+
+SelectQuantityToSell:
+ farcall GetItemPrice
+ ld a, d
+ ld [wBuffer1], a
+ ld a, e
+ ld [wBuffer2], a
+ ld hl, SellItem_MenuHeader
+ call LoadMenuHeader
+ call Toss_Sell_Loop
+ ret
+
+Toss_Sell_Loop:
+ ld a, 1
+ ld [wItemQuantityChangeBuffer], a
+.loop
+ call BuySellToss_UpdateQuantityDisplay ; update display
+ call BuySellToss_InterpretJoypad ; joy action
+ jr nc, .loop
+ cp -1
+ jr nz, .nope ; pressed B
+ scf
+ ret
+
+.nope
+ and a
+ ret
+
+BuySellToss_InterpretJoypad:
+ call JoyTextDelay_ForcehJoyDown ; get joypad
+ bit B_BUTTON_F, c
+ jr nz, .b
+ bit A_BUTTON_F, c
+ jr nz, .a
+ bit D_DOWN_F, c
+ jr nz, .down
+ bit D_UP_F, c
+ jr nz, .up
+ bit D_LEFT_F, c
+ jr nz, .left
+ bit D_RIGHT_F, c
+ jr nz, .right
+ and a
+ ret
+
+.b
+ ld a, -1
+ scf
+ ret
+
+.a
+ ld a, 0
+ scf
+ ret
+
+.down
+ ld hl, wItemQuantityChangeBuffer
+ dec [hl]
+ jr nz, .finish_down
+ ld a, [wItemQuantityBuffer]
+ ld [hl], a
+
+.finish_down
+ and a
+ ret
+
+.up
+ ld hl, wItemQuantityChangeBuffer
+ inc [hl]
+ ld a, [wItemQuantityBuffer]
+ cp [hl]
+ jr nc, .finish_up
+ ld [hl], 1
+
+.finish_up
+ and a
+ ret
+
+.left
+ ld a, [wItemQuantityChangeBuffer]
+ sub 10
+ jr c, .load_1
+ jr z, .load_1
+ jr .finish_left
+
+.load_1
+ ld a, 1
+
+.finish_left
+ ld [wItemQuantityChangeBuffer], a
+ and a
+ ret
+
+.right
+ ld a, [wItemQuantityChangeBuffer]
+ add 10
+ ld b, a
+ ld a, [wItemQuantityBuffer]
+ cp b
+ jr nc, .finish_right
+ ld b, a
+
+.finish_right
+ ld a, b
+ ld [wItemQuantityChangeBuffer], a
+ and a
+ ret
+
+BuySellToss_UpdateQuantityDisplay:
+ call MenuBox
+ call MenuBoxCoord2Tile
+ ld de, SCREEN_WIDTH + 1
+ add hl, de
+ ld [hl], "×"
+ inc hl
+ ld de, wItemQuantityChangeBuffer
+ lb bc, PRINTNUM_LEADINGZEROS | 1, 2
+ call PrintNum
+ ld a, [wMenuDataPointer]
+ ld e, a
+ ld a, [wMenuDataPointer + 1]
+ ld d, a
+ ld a, [wMenuDataBank]
+ call FarCall_de
+ ret
+
+ret_25097:
+ ret
+
+DisplayPurchasePrice:
+ call BuySell_MultiplyPrice
+ call BuySell_DisplaySubtotal
+ ret
+
+DisplaySellingPrice:
+ call BuySell_MultiplyPrice
+ call Sell_HalvePrice
+ call BuySell_DisplaySubtotal
+ ret
+
+BuySell_MultiplyPrice:
+ xor a
+ ld [hMultiplicand + 0], a
+ ld a, [wBuffer1]
+ ld [hMultiplicand + 1], a
+ ld a, [wBuffer2]
+ ld [hMultiplicand + 2], a
+ ld a, [wItemQuantityChangeBuffer]
+ ld [hMultiplier], a
+ push hl
+ call Multiply
+ pop hl
+ ret
+
+Sell_HalvePrice:
+ push hl
+ ld hl, hProduct + 1
+ ld a, [hl]
+ srl a
+ ld [hli], a
+ ld a, [hl]
+ rra
+ ld [hli], a
+ ld a, [hl]
+ rra
+ ld [hl], a
+ pop hl
+ ret
+
+BuySell_DisplaySubtotal:
+ push hl
+ ld hl, hMoneyTemp
+ ld a, [hProduct + 1]
+ ld [hli], a
+ ld a, [hProduct + 2]
+ ld [hli], a
+ ld a, [hProduct + 3]
+ ld [hl], a
+ pop hl
+ inc hl
+ ld de, hMoneyTemp
+ lb bc, PRINTNUM_MONEY | 3, 6
+ call PrintNum
+ call WaitBGMap
+ ret
+
+TossItem_MenuHeader:
+ db MENU_BACKUP_TILES ; flags
+ menu_coords 15, 9, SCREEN_WIDTH - 1, TEXTBOX_Y - 1
+ dw ret_25097
+ db 0 ; default option
+
+BuyItem_MenuHeader:
+ db MENU_BACKUP_TILES ; flags
+ menu_coords 7, 15, SCREEN_WIDTH - 1, SCREEN_HEIGHT - 1
+ dw DisplayPurchasePrice
+ db -1 ; default option
+
+SellItem_MenuHeader:
+ db MENU_BACKUP_TILES ; flags
+ menu_coords 7, 15, SCREEN_WIDTH - 1, SCREEN_HEIGHT - 1
+ dw DisplaySellingPrice
+ db 0 ; default option
diff --git a/engine/items/item_effects.asm b/engine/items/item_effects.asm
new file mode 100644
index 000000000..1439b2c6d
--- /dev/null
+++ b/engine/items/item_effects.asm
@@ -0,0 +1,2958 @@
+_DoItemEffect::
+ ld a, [wCurItem]
+ ld [wd265], a
+ call GetItemName
+ call CopyName1
+ ld a, 1
+ ld [wItemEffectSucceeded], a
+ ld a, [wCurItem]
+ dec a
+ ld hl, ItemEffects
+ rst JumpTable
+ ret
+
+ItemEffects:
+; entries correspond to item ids
+ dw PokeBallEffect ; MASTER_BALL
+ dw PokeBallEffect ; ULTRA_BALL
+ dw NoEffect ; BRIGHTPOWDER
+ dw PokeBallEffect ; GREAT_BALL
+ dw PokeBallEffect ; POKE_BALL
+ dw TownMapEffect ; TOWN_MAP
+ dw BicycleEffect ; BICYCLE
+ dw EvoStoneEffect ; MOON_STONE
+ dw StatusHealingEffect ; ANTIDOTE
+ dw StatusHealingEffect ; BURN_HEAL
+ dw StatusHealingEffect ; ICE_HEAL
+ dw StatusHealingEffect ; AWAKENING
+ dw StatusHealingEffect ; PARLYZ_HEAL
+ dw FullRestoreEffect ; FULL_RESTORE
+ dw RestoreHPEffect ; MAX_POTION
+ dw RestoreHPEffect ; HYPER_POTION
+ dw RestoreHPEffect ; SUPER_POTION
+ dw RestoreHPEffect ; POTION
+ dw EscapeRopeEffect ; ESCAPE_ROPE
+ dw RepelEffect ; REPEL
+ dw RestorePPEffect ; MAX_ELIXER
+ dw EvoStoneEffect ; FIRE_STONE
+ dw EvoStoneEffect ; THUNDERSTONE
+ dw EvoStoneEffect ; WATER_STONE
+ dw NoEffect ; ITEM_19
+ dw VitaminEffect ; HP_UP
+ dw VitaminEffect ; PROTEIN
+ dw VitaminEffect ; IRON
+ dw VitaminEffect ; CARBOS
+ dw NoEffect ; LUCKY_PUNCH
+ dw VitaminEffect ; CALCIUM
+ dw RareCandyEffect ; RARE_CANDY
+ dw XAccuracyEffect ; X_ACCURACY
+ dw EvoStoneEffect ; LEAF_STONE
+ dw NoEffect ; METAL_POWDER
+ dw NoEffect ; NUGGET
+ dw PokeDollEffect ; POKE_DOLL
+ dw StatusHealingEffect ; FULL_HEAL
+ dw ReviveEffect ; REVIVE
+ dw ReviveEffect ; MAX_REVIVE
+ dw GuardSpecEffect ; GUARD_SPEC
+ dw SuperRepelEffect ; SUPER_REPEL
+ dw MaxRepelEffect ; MAX_REPEL
+ dw DireHitEffect ; DIRE_HIT
+ dw NoEffect ; ITEM_2D
+ dw RestoreHPEffect ; FRESH_WATER
+ dw RestoreHPEffect ; SODA_POP
+ dw RestoreHPEffect ; LEMONADE
+ dw XItemEffect ; X_ATTACK
+ dw NoEffect ; ITEM_32
+ dw XItemEffect ; X_DEFEND
+ dw XItemEffect ; X_SPEED
+ dw XItemEffect ; X_SPECIAL
+ dw CoinCaseEffect ; COIN_CASE
+ dw ItemfinderEffect ; ITEMFINDER
+ dw PokeFluteEffect ; POKE_FLUTE
+ dw NoEffect ; EXP_SHARE
+ dw OldRodEffect ; OLD_ROD
+ dw GoodRodEffect ; GOOD_ROD
+ dw NoEffect ; SILVER_LEAF
+ dw SuperRodEffect ; SUPER_ROD
+ dw RestorePPEffect ; PP_UP
+ dw RestorePPEffect ; ETHER
+ dw RestorePPEffect ; MAX_ETHER
+ dw RestorePPEffect ; ELIXER
+ dw NoEffect ; RED_SCALE
+ dw NoEffect ; SECRETPOTION
+ dw NoEffect ; S_S_TICKET
+ dw NoEffect ; MYSTERY_EGG
+ dw NoEffect ; CLEAR_BELL
+ dw NoEffect ; SILVER_WING
+ dw RestoreHPEffect ; MOOMOO_MILK
+ dw NoEffect ; QUICK_CLAW
+ dw StatusHealingEffect ; PSNCUREBERRY
+ dw NoEffect ; GOLD_LEAF
+ dw NoEffect ; SOFT_SAND
+ dw NoEffect ; SHARP_BEAK
+ dw StatusHealingEffect ; PRZCUREBERRY
+ dw StatusHealingEffect ; BURNT_BERRY
+ dw StatusHealingEffect ; ICE_BERRY
+ dw NoEffect ; POISON_BARB
+ dw NoEffect ; KINGS_ROCK
+ dw BitterBerryEffect ; BITTER_BERRY
+ dw StatusHealingEffect ; MINT_BERRY
+ dw NoEffect ; RED_APRICORN
+ dw NoEffect ; TINYMUSHROOM
+ dw NoEffect ; BIG_MUSHROOM
+ dw NoEffect ; SILVERPOWDER
+ dw NoEffect ; BLU_APRICORN
+ dw NoEffect ; ITEM_5A
+ dw NoEffect ; AMULET_COIN
+ dw NoEffect ; YLW_APRICORN
+ dw NoEffect ; GRN_APRICORN
+ dw NoEffect ; CLEANSE_TAG
+ dw NoEffect ; MYSTIC_WATER
+ dw NoEffect ; TWISTEDSPOON
+ dw NoEffect ; WHT_APRICORN
+ dw NoEffect ; BLACKBELT
+ dw NoEffect ; BLK_APRICORN
+ dw NoEffect ; ITEM_64
+ dw NoEffect ; PNK_APRICORN
+ dw NoEffect ; BLACKGLASSES
+ dw NoEffect ; SLOWPOKETAIL
+ dw NoEffect ; PINK_BOW
+ dw NoEffect ; STICK
+ dw NoEffect ; SMOKE_BALL
+ dw NoEffect ; NEVERMELTICE
+ dw NoEffect ; MAGNET
+ dw StatusHealingEffect ; MIRACLEBERRY
+ dw NoEffect ; PEARL
+ dw NoEffect ; BIG_PEARL
+ dw NoEffect ; EVERSTONE
+ dw NoEffect ; SPELL_TAG
+ dw RestoreHPEffect ; RAGECANDYBAR
+ dw NoEffect ; GS_BALL
+ dw BlueCardEffect ; BLUE_CARD
+ dw NoEffect ; MIRACLE_SEED
+ dw NoEffect ; THICK_CLUB
+ dw NoEffect ; FOCUS_BAND
+ dw NoEffect ; ITEM_78
+ dw EnergypowderEffect ; ENERGYPOWDER
+ dw EnergyRootEffect ; ENERGY_ROOT
+ dw HealPowderEffect ; HEAL_POWDER
+ dw RevivalHerbEffect ; REVIVAL_HERB
+ dw NoEffect ; HARD_STONE
+ dw NoEffect ; LUCKY_EGG
+ dw CardKeyEffect ; CARD_KEY
+ dw NoEffect ; MACHINE_PART
+ dw NoEffect ; EGG_TICKET
+ dw NoEffect ; LOST_ITEM
+ dw NoEffect ; STARDUST
+ dw NoEffect ; STAR_PIECE
+ dw BasementKeyEffect ; BASEMENT_KEY
+ dw NoEffect ; PASS
+ dw NoEffect ; ITEM_87
+ dw NoEffect ; ITEM_88
+ dw NoEffect ; ITEM_89
+ dw NoEffect ; CHARCOAL
+ dw RestoreHPEffect ; BERRY_JUICE
+ dw NoEffect ; SCOPE_LENS
+ dw NoEffect ; ITEM_8D
+ dw NoEffect ; ITEM_8E
+ dw NoEffect ; METAL_COAT
+ dw NoEffect ; DRAGON_FANG
+ dw NoEffect ; ITEM_91
+ dw NoEffect ; LEFTOVERS
+ dw NoEffect ; ITEM_93
+ dw NoEffect ; ITEM_94
+ dw NoEffect ; ITEM_95
+ dw RestorePPEffect ; MYSTERYBERRY
+ dw NoEffect ; DRAGON_SCALE
+ dw NoEffect ; BERSERK_GENE
+ dw NoEffect ; ITEM_99
+ dw NoEffect ; ITEM_9A
+ dw NoEffect ; ITEM_9B
+ dw SacredAshEffect ; SACRED_ASH
+ dw PokeBallEffect ; HEAVY_BALL
+ dw NoEffect ; FLOWER_MAIL
+ dw PokeBallEffect ; LEVEL_BALL
+ dw PokeBallEffect ; LURE_BALL
+ dw PokeBallEffect ; FAST_BALL
+ dw NoEffect ; ITEM_A2
+ dw NoEffect ; LIGHT_BALL
+ dw PokeBallEffect ; FRIEND_BALL
+ dw PokeBallEffect ; MOON_BALL
+ dw PokeBallEffect ; LOVE_BALL
+ dw NormalBoxEffect ; NORMAL_BOX
+ dw GorgeousBoxEffect ; GORGEOUS_BOX
+ dw EvoStoneEffect ; SUN_STONE
+ dw NoEffect ; POLKADOT_BOW
+ dw NoEffect ; ITEM_AB
+ dw NoEffect ; UP_GRADE
+ dw RestoreHPEffect ; BERRY
+ dw RestoreHPEffect ; GOLD_BERRY
+ dw SquirtbottleEffect ; SQUIRTBOTTLE
+ dw NoEffect ; ITEM_B0
+ dw PokeBallEffect ; PARK_BALL
+ dw NoEffect ; RAINBOW_WING
+ dw NoEffect ; ITEM_B3
+
+PokeBallEffect:
+ ld a, [wBattleMode]
+ dec a
+ jp nz, UseBallInTrainerBattle
+
+ ld a, [wPartyCount]
+ cp PARTY_LENGTH
+ jr nz, .room_in_party
+
+ ld a, BANK(sBoxCount)
+ call GetSRAMBank
+ ld a, [sBoxCount]
+ cp MONS_PER_BOX
+ call CloseSRAM
+ jp z, Ball_BoxIsFullMessage
+
+.room_in_party
+ xor a
+ ld [wWildMon], a
+ ld a, [wCurItem]
+ cp PARK_BALL
+ call nz, ReturnToBattle_UseBall
+
+ ld hl, wOptions
+ res NO_TEXT_SCROLL, [hl]
+ ld hl, UsedItemText
+ call PrintText
+
+ ld a, [wEnemyMonCatchRate]
+ ld b, a
+ ld a, [wBattleType]
+ cp BATTLETYPE_TUTORIAL
+ jp z, .catch_without_fail
+ ld a, [wCurItem]
+ cp MASTER_BALL
+ jp z, .catch_without_fail
+ ld a, [wCurItem]
+ ld c, a
+ ld hl, BallMultiplierFunctionTable
+
+.get_multiplier_loop
+ ld a, [hli]
+ cp $ff
+ jr z, .skip_or_return_from_ball_fn
+ cp c
+ jr z, .call_ball_function
+ inc hl
+ inc hl
+ jr .get_multiplier_loop
+
+.call_ball_function
+ ld a, [hli]
+ ld h, [hl]
+ ld l, a
+ ld de, .skip_or_return_from_ball_fn
+ push de
+ jp hl
+
+.skip_or_return_from_ball_fn
+ ld a, [wCurItem]
+ cp LEVEL_BALL
+ ld a, b
+ jp z, .skip_hp_calc
+
+ ld a, b
+ ld [hMultiplicand + 2], a
+
+ ld hl, wEnemyMonHP
+ ld b, [hl]
+ inc hl
+ ld c, [hl]
+ inc hl
+ ld d, [hl]
+ inc hl
+ ld e, [hl]
+ sla c
+ rl b
+
+ ld h, d
+ ld l, e
+ add hl, de
+ add hl, de
+ ld d, h
+ ld e, l
+ ld a, d
+ and a
+ jr z, .okay_1
+
+ srl d
+ rr e
+ srl d
+ rr e
+ srl b
+ rr c
+ srl b
+ rr c
+
+ ld a, c
+ and a
+ jr nz, .okay_1
+ ld c, $1
+.okay_1
+ ld b, e
+
+ push bc
+ ld a, b
+ sub c
+ ld [hMultiplier], a
+ xor a
+ ld [hDividend + 0], a
+ ld [hMultiplicand + 0], a
+ ld [hMultiplicand + 1], a
+ call Multiply
+ pop bc
+
+ ld a, b
+ ld [hDivisor], a
+ ld b, $4
+ call Divide
+
+ ld a, [hQuotient + 2]
+ and a
+ jr nz, .statuscheck
+ ld a, 1
+.statuscheck
+; This routine is buggy. It was intended that SLP and FRZ provide a higher
+; catch rate than BRN/PSN/PAR, which in turn provide a higher catch rate than
+; no status effect at all. But instead, it makes BRN/PSN/PAR provide no
+; benefit.
+; Uncomment the line below to fix this.
+ ld b, a
+ ld a, [wEnemyMonStatus]
+ and 1 << FRZ | SLP
+ ld c, 10
+ jr nz, .addstatus
+ ; ld a, [wEnemyMonStatus]
+ and a
+ ld c, 5
+ jr nz, .addstatus
+ ld c, 0
+.addstatus
+ ld a, b
+ add c
+ jr nc, .max_1
+ ld a, $ff
+.max_1
+
+ ; BUG: farcall overwrites a, and GetItemHeldEffect takes b anyway.
+ ; This is probably the reason the HELD_CATCH_CHANCE effect is never used.
+ ; Uncomment the line below to fix.
+ ld d, a
+ push de
+ ld a, [wBattleMonItem]
+ ; ld b, a
+ farcall GetItemHeldEffect
+ ld a, b
+ cp HELD_CATCH_CHANCE
+ pop de
+ ld a, d
+ jr nz, .max_2
+ add c
+ jr nc, .max_2
+ ld a, $ff
+.max_2
+
+.skip_hp_calc
+ ld b, a
+ ld [wBuffer1], a
+ call Random
+
+ cp b
+ ld a, 0
+ jr z, .catch_without_fail
+ jr nc, .fail_to_catch
+
+.catch_without_fail
+ ld a, [wEnemyMonSpecies]
+
+.fail_to_catch
+ ld [wWildMon], a
+ ld c, 20
+ call DelayFrames
+
+ ld a, [wCurItem]
+ cp POKE_BALL + 1 ; Assumes Master/Ultra/Great come before
+ jr c, .not_kurt_ball
+ ld a, POKE_BALL
+.not_kurt_ball
+ ld [wBattleAnimParam], a
+
+ ld de, ANIM_THROW_POKE_BALL
+ ld a, e
+ ld [wFXAnimID], a
+ ld a, d
+ ld [wFXAnimID + 1], a
+ xor a
+ ld [hBattleTurn], a
+ ld [wBuffer2], a
+ ld [wNumHits], a
+ predef PlayBattleAnim
+
+ ld a, [wWildMon]
+ and a
+ jr nz, .caught
+ ld a, [wBuffer2]
+ cp $1
+ ld hl, Text_NoShake
+ jp z, .shake_and_break_free
+ cp $2
+ ld hl, Text_OneShake
+ jp z, .shake_and_break_free
+ cp $3
+ ld hl, Text_TwoShakes
+ jp z, .shake_and_break_free
+ cp $4
+ ld hl, Text_ThreeShakes
+ jp z, .shake_and_break_free
+.caught
+
+ ld hl, wEnemyMonStatus
+ ld a, [hli]
+ push af
+ inc hl
+ ld a, [hli]
+ push af
+ ld a, [hl]
+ push af
+ push hl
+ ld hl, wEnemyMonItem
+ ld a, [hl]
+ push af
+ push hl
+ ld hl, wEnemySubStatus5
+ ld a, [hl]
+ push af
+ set SUBSTATUS_TRANSFORMED, [hl]
+
+; This code is buggy. Any wild Pokémon that has Transformed will be
+; caught as a Ditto, even if it was something else like Mew.
+; To fix, do not set [wTempEnemyMonSpecies] to DITTO.
+ bit SUBSTATUS_TRANSFORMED, a
+ jr nz, .ditto
+ jr .not_ditto
+
+.ditto
+ ld a, DITTO
+ ld [wTempEnemyMonSpecies], a
+ jr .load_data
+
+.not_ditto
+ set SUBSTATUS_TRANSFORMED, [hl]
+ ld hl, wEnemyBackupDVs
+ ld a, [wEnemyMonDVs]
+ ld [hli], a
+ ld a, [wEnemyMonDVs + 1]
+ ld [hl], a
+
+.load_data
+ ld a, [wTempEnemyMonSpecies]
+ ld [wCurPartySpecies], a
+ ld a, [wEnemyMonLevel]
+ ld [wCurPartyLevel], a
+ farcall LoadEnemyMon
+
+ pop af
+ ld [wEnemySubStatus5], a
+
+ pop hl
+ pop af
+ ld [hl], a
+ pop hl
+ pop af
+ ld [hld], a
+ pop af
+ ld [hld], a
+ dec hl
+ pop af
+ ld [hl], a
+
+ ld hl, wEnemySubStatus5
+ bit SUBSTATUS_TRANSFORMED, [hl]
+ jr nz, .Transformed
+ ld hl, wWildMonMoves
+ ld de, wEnemyMonMoves
+ ld bc, NUM_MOVES
+ call CopyBytes
+
+ ld hl, wWildMonPP
+ ld de, wEnemyMonPP
+ ld bc, NUM_MOVES
+ call CopyBytes
+
+.Transformed:
+ ld a, [wEnemyMonSpecies]
+ ld [wWildMon], a
+ ld [wCurPartySpecies], a
+ ld [wd265], a
+ ld a, [wBattleType]
+ cp BATTLETYPE_TUTORIAL
+ jp z, .FinishTutorial
+
+ farcall StubbedTrainerRankings_WildMonsCaught
+
+ ld hl, Text_GotchaMonWasCaught
+ call PrintText
+
+ call ClearSprites
+
+ ld a, [wd265]
+ dec a
+ call CheckCaughtMon
+
+ ld a, c
+ push af
+ ld a, [wd265]
+ dec a
+ call SetSeenAndCaughtMon
+ pop af
+ and a
+ jr nz, .skip_pokedex
+
+ call CheckReceivedDex
+ jr z, .skip_pokedex
+
+ ld hl, Text_AddedToPokedex
+ call PrintText
+
+ call ClearSprites
+
+ ld a, [wEnemyMonSpecies]
+ ld [wd265], a
+ predef NewPokedexEntry
+
+.skip_pokedex
+ ld a, [wBattleType]
+ cp BATTLETYPE_CONTEST
+ jp z, .catch_bug_contest_mon
+ cp BATTLETYPE_CELEBI
+ jr nz, .not_celebi
+ ld hl, wBattleResult
+ set BATTLERESULT_CAUGHT_CELEBI, [hl]
+.not_celebi
+
+ ld a, [wPartyCount]
+ cp PARTY_LENGTH
+ jr z, .SendToPC
+
+ xor a ; PARTYMON
+ ld [wMonType], a
+ call ClearSprites
+
+ predef TryAddMonToParty
+
+ farcall SetCaughtData
+
+ ld a, [wCurItem]
+ cp FRIEND_BALL
+ jr nz, .SkipPartyMonFriendBall
+
+ ld a, [wPartyCount]
+ dec a
+ ld hl, wPartyMon1Happiness
+ ld bc, PARTYMON_STRUCT_LENGTH
+ call AddNTimes
+
+ ld a, FRIEND_BALL_HAPPINESS
+ ld [hl], a
+
+.SkipPartyMonFriendBall:
+ ld hl, Text_AskNicknameNewlyCaughtMon
+ call PrintText
+
+ ld a, [wCurPartySpecies]
+ ld [wd265], a
+ call GetPokemonName
+
+ call YesNoBox
+ jp c, .return_from_capture
+
+ ld a, [wPartyCount]
+ dec a
+ ld [wCurPartyMon], a
+ ld hl, wPartyMonNicknames
+ ld bc, MON_NAME_LENGTH
+ call AddNTimes
+
+ ld d, h
+ ld e, l
+ push de
+ xor a ; PARTYMON
+ ld [wMonType], a
+ ld b, 0
+ farcall NamingScreen
+
+ call RotateThreePalettesRight
+
+ call LoadStandardFont
+
+ pop hl
+ ld de, wStringBuffer1
+ call InitName
+
+ jp .return_from_capture
+
+.SendToPC:
+ call ClearSprites
+
+ predef SendMonIntoBox
+
+ farcall SetBoxMonCaughtData
+
+ ld a, BANK(sBoxCount)
+ call GetSRAMBank
+
+ ld a, [sBoxCount]
+ cp MONS_PER_BOX
+ jr nz, .BoxNotFullYet
+ ld hl, wBattleResult
+ set BATTLERESULT_BOX_FULL, [hl]
+.BoxNotFullYet:
+ ld a, [wCurItem]
+ cp FRIEND_BALL
+ jr nz, .SkipBoxMonFriendBall
+ ; The captured mon is now first in the box
+ ld a, FRIEND_BALL_HAPPINESS
+ ld [sBoxMon1Happiness], a
+.SkipBoxMonFriendBall:
+ call CloseSRAM
+
+ ld hl, Text_AskNicknameNewlyCaughtMon
+ call PrintText
+
+ ld a, [wCurPartySpecies]
+ ld [wd265], a
+ call GetPokemonName
+
+ call YesNoBox
+ jr c, .SkipBoxMonNickname
+
+ xor a
+ ld [wCurPartyMon], a
+ ld a, BOXMON
+ ld [wMonType], a
+ ld de, wMonOrItemNameBuffer
+ ld b, $0
+ farcall NamingScreen
+
+ ld a, BANK(sBoxMonNicknames)
+ call GetSRAMBank
+
+ ld hl, wMonOrItemNameBuffer
+ ld de, sBoxMonNicknames
+ ld bc, MON_NAME_LENGTH
+ call CopyBytes
+
+ ld hl, sBoxMonNicknames
+ ld de, wStringBuffer1
+ call InitName
+
+ call CloseSRAM
+
+.SkipBoxMonNickname:
+ ld a, BANK(sBoxMonNicknames)
+ call GetSRAMBank
+
+ ld hl, sBoxMonNicknames
+ ld de, wMonOrItemNameBuffer
+ ld bc, MON_NAME_LENGTH
+ call CopyBytes
+
+ call CloseSRAM
+
+ ld hl, Text_SentToBillsPC
+ call PrintText
+
+ call RotateThreePalettesRight
+ call LoadStandardFont
+ jr .return_from_capture
+
+.catch_bug_contest_mon
+ farcall BugContest_SetCaughtContestMon
+ jr .return_from_capture
+
+.FinishTutorial:
+ ld hl, Text_GotchaMonWasCaught
+
+.shake_and_break_free
+ call PrintText
+ call ClearSprites
+
+.return_from_capture
+ ld a, [wBattleType]
+ cp BATTLETYPE_TUTORIAL
+ ret z
+ cp BATTLETYPE_DEBUG
+ ret z
+ cp BATTLETYPE_CONTEST
+ jr z, .used_park_ball
+
+ ld a, [wWildMon]
+ and a
+ jr z, .toss
+
+ call ClearBGPalettes
+ call ClearTileMap
+
+.toss
+ ld hl, wNumItems
+ inc a
+ ld [wItemQuantityChangeBuffer], a
+ jp TossItem
+
+.used_park_ball
+ ld hl, wParkBallsRemaining
+ dec [hl]
+ ret
+
+BallMultiplierFunctionTable:
+; table of routines that increase or decrease the catch rate based on
+; which ball is used in a certain situation.
+ dbw ULTRA_BALL, UltraBallMultiplier
+ dbw GREAT_BALL, GreatBallMultiplier
+ dbw SAFARI_BALL, SafariBallMultiplier ; Safari Ball, leftover from RBY
+ dbw HEAVY_BALL, HeavyBallMultiplier
+ dbw LEVEL_BALL, LevelBallMultiplier
+ dbw LURE_BALL, LureBallMultiplier
+ dbw FAST_BALL, FastBallMultiplier
+ dbw MOON_BALL, MoonBallMultiplier
+ dbw LOVE_BALL, LoveBallMultiplier
+ dbw PARK_BALL, ParkBallMultiplier
+ db -1 ; end
+
+UltraBallMultiplier:
+; multiply catch rate by 2
+ sla b
+ ret nc
+ ld b, $ff
+ ret
+
+SafariBallMultiplier:
+GreatBallMultiplier:
+ParkBallMultiplier:
+; multiply catch rate by 1.5
+ ld a, b
+ srl a
+ add b
+ ld b, a
+ ret nc
+ ld b, $ff
+ ret
+
+GetPokedexEntryBank:
+ push hl
+ push de
+ ld a, [wEnemyMonSpecies]
+ rlca
+ rlca
+ maskbits NUM_DEX_ENTRY_BANKS
+ ld hl, .PokedexEntryBanks
+ ld d, 0
+ ld e, a
+ add hl, de
+ ld a, [hl]
+ pop de
+ pop hl
+ ret
+
+.PokedexEntryBanks:
+ db BANK("Pokedex Entries 001-064")
+ db BANK("Pokedex Entries 065-128")
+ db BANK("Pokedex Entries 129-192")
+ db BANK("Pokedex Entries 193-251")
+
+HeavyBallMultiplier:
+; subtract 20 from catch rate if weight < 102.4 kg
+; else add 0 to catch rate if weight < 204.8 kg
+; else add 20 to catch rate if weight < 307.2 kg
+; else add 30 to catch rate if weight < 409.6 kg
+; else add 40 to catch rate (never happens)
+ ld a, [wEnemyMonSpecies]
+ ld hl, PokedexDataPointerTable
+ dec a
+ ld e, a
+ ld d, 0
+ add hl, de
+ add hl, de
+ ld a, BANK(PokedexDataPointerTable)
+ call GetFarHalfword
+
+.SkipText:
+ call GetPokedexEntryBank
+ call GetFarByte
+ inc hl
+ cp "@"
+ jr nz, .SkipText
+
+ call GetPokedexEntryBank
+ push bc
+ inc hl
+ inc hl
+ call GetFarHalfword
+
+ srl h
+ rr l
+ ld b, h
+ ld c, l
+
+rept 4
+ srl b
+ rr c
+endr
+ call .subbc
+
+ srl b
+ rr c
+ call .subbc
+
+ ld a, h
+ pop bc
+ jr .compare
+
+.subbc
+ ; subtract bc from hl
+ push bc
+ ld a, b
+ cpl
+ ld b, a
+ ld a, c
+ cpl
+ ld c, a
+ inc bc
+ add hl, bc
+ pop bc
+ ret
+
+.compare
+ ld c, a
+ cp HIGH(1024) ; 102.4 kg
+ jr c, .lightmon
+
+ ld hl, .WeightsTable
+.lookup
+ ld a, c
+ cp [hl]
+ jr c, .heavymon
+ inc hl
+ inc hl
+ jr .lookup
+
+.heavymon
+ inc hl
+ ld a, b
+ add [hl]
+ ld b, a
+ ret nc
+ ld b, $ff
+ ret
+
+.lightmon
+ ld a, b
+ sub 20
+ ld b, a
+ ret nc
+ ld b, $1
+ ret
+
+.WeightsTable:
+; weight factor, boost
+ db HIGH(2048), 0
+ db HIGH(3072), 20
+ db HIGH(4096), 30
+ db HIGH(65280), 40
+
+LureBallMultiplier:
+; multiply catch rate by 3 if this is a fishing rod battle
+ ld a, [wBattleType]
+ cp BATTLETYPE_FISH
+ ret nz
+
+ ld a, b
+ add a
+ jr c, .max
+
+ add b
+ jr nc, .done
+.max
+ ld a, $ff
+.done
+ ld b, a
+ ret
+
+MoonBallMultiplier:
+; This function is buggy.
+; Intent: multiply catch rate by 4 if mon evolves with moon stone
+; Reality: no boost
+ push bc
+ ld a, [wTempEnemyMonSpecies]
+ dec a
+ ld c, a
+ ld b, 0
+ ld hl, EvosAttacksPointers
+ add hl, bc
+ add hl, bc
+ ld a, BANK(EvosAttacksPointers)
+ call GetFarHalfword
+ pop bc
+
+ push bc
+ ld a, BANK("Evolutions and Attacks")
+ call GetFarByte
+ cp EVOLVE_ITEM
+ pop bc
+ ret nz
+
+ inc hl
+ inc hl
+ inc hl
+
+; Moon Stone's constant from Pokémon Red is used.
+; No Pokémon evolve with Burn Heal,
+; so Moon Balls always have a catch rate of 1×.
+ push bc
+ ld a, BANK("Evolutions and Attacks")
+ call GetFarByte
+ cp MOON_STONE_RED ; BURN_HEAL
+ pop bc
+ ret nz
+
+ sla b
+ jr c, .max
+ sla b
+ jr nc, .done
+.max
+ ld b, $ff
+.done
+ ret
+
+LoveBallMultiplier:
+; This function is buggy.
+; Intent: multiply catch rate by 8 if mons are of same species, different sex
+; Reality: multiply catch rate by 8 if mons are of same species, same sex
+
+ ; does species match?
+ ld a, [wTempEnemyMonSpecies]
+ ld c, a
+ ld a, [wTempBattleMonSpecies]
+ cp c
+ ret nz
+
+ ; check player mon species
+ push bc
+ ld a, [wTempBattleMonSpecies]
+ ld [wCurPartySpecies], a
+ xor a ; PARTYMON
+ ld [wMonType], a
+ ld a, [wCurBattleMon]
+ ld [wCurPartyMon], a
+ farcall GetGender
+ jr c, .done1 ; no effect on genderless
+
+ ld d, 0 ; male
+ jr nz, .playermale
+ inc d ; female
+.playermale
+
+ ; check wild mon species
+ push de
+ ld a, [wTempEnemyMonSpecies]
+ ld [wCurPartySpecies], a
+ ld a, WILDMON
+ ld [wMonType], a
+ farcall GetGender
+ jr c, .done2 ; no effect on genderless
+
+ ld d, 0 ; male
+ jr nz, .wildmale
+ inc d ; female
+.wildmale
+
+ ld a, d
+ pop de
+ cp d
+ pop bc
+ ret nz ; for the intended effect, this should be "ret z"
+
+ sla b
+ jr c, .max
+ sla b
+ jr c, .max
+ sla b
+ ret nc
+.max
+ ld b, $ff
+ ret
+
+.done2
+ pop de
+
+.done1
+ pop bc
+ ret
+
+FastBallMultiplier:
+; This function is buggy.
+; Intent: multiply catch rate by 4 if enemy mon is in one of the three
+; FleeMons tables.
+; Reality: multiply catch rate by 4 if enemy mon is one of the first three in
+; the first FleeMons table.
+ ld a, [wTempEnemyMonSpecies]
+ ld c, a
+ ld hl, FleeMons
+ ld d, 3
+
+.loop
+ ld a, BANK(FleeMons)
+ call GetFarByte
+
+ inc hl
+ cp -1
+ jr z, .next
+ cp c
+ jr nz, .next ; for the intended effect, this should be "jr nz, .loop"
+ sla b
+ jr c, .max
+
+ sla b
+ ret nc
+
+.max
+ ld b, $ff
+ ret
+
+.next
+ dec d
+ jr nz, .loop
+ ret
+
+LevelBallMultiplier:
+; multiply catch rate by 8 if player mon level / 4 > enemy mon level
+; multiply catch rate by 4 if player mon level / 2 > enemy mon level
+; multiply catch rate by 2 if player mon level > enemy mon level
+ ld a, [wBattleMonLevel]
+ ld c, a
+ ld a, [wEnemyMonLevel]
+ cp c
+ ret nc ; if player is lower level, we're done here
+ sla b
+ jr c, .max
+
+ srl c
+ cp c
+ ret nc ; if player/2 is lower level, we're done here
+ sla b
+ jr c, .max
+
+ srl c
+ cp c
+ ret nc ; if player/4 is lower level, we're done here
+ sla b
+ ret nc
+
+.max
+ ld b, $ff
+ ret
+
+; These two texts were carried over from gen 1.
+; They are not used in gen 2, and are dummied out.
+
+Text_RBY_CatchMarowak:
+ ; It dodged the thrown BALL! This #MON can't be caught!
+ text_jump UnknownText_0x1c5a5a
+ db "@"
+
+Text_RBY_NoShake:
+ ; You missed the #MON!
+ text_jump UnknownText_0x1c5a90
+ db "@"
+
+Text_NoShake:
+ ; Oh no! The #MON broke free!
+ text_jump UnknownText_0x1c5aa6
+ db "@"
+
+Text_OneShake:
+ ; Aww! It appeared to be caught!
+ text_jump UnknownText_0x1c5ac3
+ db "@"
+
+Text_TwoShakes:
+ ; Aargh! Almost had it!
+ text_jump UnknownText_0x1c5ae3
+ db "@"
+
+Text_ThreeShakes:
+ ; Shoot! It was so close too!
+ text_jump UnknownText_0x1c5afa
+ db "@"
+
+Text_GotchaMonWasCaught:
+ ; Gotcha! @ was caught!@ @
+ text_jump UnknownText_0x1c5b17
+ start_asm
+ call WaitSFX
+ push bc
+ ld de, MUSIC_NONE
+ call PlayMusic
+ call DelayFrame
+ ld de, MUSIC_CAPTURE
+ call PlayMusic
+ pop bc
+ ld hl, TextJump_Waitbutton
+ ret
+
+TextJump_Waitbutton:
+ ; @
+ text_jump Text_Waitbutton_2
+ db "@"
+
+Text_SentToBillsPC:
+ ; was sent to BILL's PC.
+ text_jump UnknownText_0x1c5b38
+ db "@"
+
+Text_AddedToPokedex:
+ ; 's data was newly added to the #DEX.@ @
+ text_jump UnknownText_0x1c5b53
+ db "@"
+
+Text_AskNicknameNewlyCaughtMon:
+ ; Give a nickname to @ ?
+ text_jump UnknownText_0x1c5b7f
+ db "@"
+
+ReturnToBattle_UseBall:
+ farcall _ReturnToBattle_UseBall
+ ret
+
+TownMapEffect:
+ farcall PokegearMap
+ ret
+
+BicycleEffect:
+ farcall BikeFunction
+ ret
+
+EvoStoneEffect:
+ ld b, PARTYMENUACTION_EVO_STONE
+ call UseItem_SelectMon
+
+ jp c, .DecidedNotToUse
+
+ ld a, MON_ITEM
+ call GetPartyParamLocation
+
+ ld a, [hl]
+ cp EVERSTONE
+ jr z, .NoEffect
+
+ ld a, $1
+ ld [wForceEvolution], a
+ farcall EvolvePokemon
+
+ ld a, [wMonTriedToEvolve]
+ and a
+ jr z, .NoEffect
+
+ jp UseDisposableItem
+
+.NoEffect:
+ call WontHaveAnyEffectMessage
+
+.DecidedNotToUse:
+ xor a
+ ld [wItemEffectSucceeded], a
+ ret
+
+VitaminEffect:
+ ld b, PARTYMENUACTION_HEALING_ITEM
+ call UseItem_SelectMon
+
+ jp c, RareCandy_StatBooster_ExitMenu
+
+ call RareCandy_StatBooster_GetParameters
+
+ call GetStatExpRelativePointer
+
+ ld a, MON_STAT_EXP
+ call GetPartyParamLocation
+
+ add hl, bc
+ ld a, [hl]
+ cp 100
+ jr nc, NoEffectMessage
+
+ add 10
+ ld [hl], a
+ call UpdateStatsAfterItem
+
+ call GetStatExpRelativePointer
+
+ ld hl, StatStrings
+ add hl, bc
+ ld a, [hli]
+ ld h, [hl]
+ ld l, a
+ ld de, wStringBuffer2
+ ld bc, ITEM_NAME_LENGTH
+ call CopyBytes
+
+ call Play_SFX_FULL_HEAL
+
+ ld hl, Text_StatRose
+ call PrintText
+
+ ld c, HAPPINESS_USEDITEM
+ farcall ChangeHappiness
+
+ jp UseDisposableItem
+
+NoEffectMessage:
+ ld hl, WontHaveAnyEffectText
+ call PrintText
+ jp ClearPalettes
+
+UpdateStatsAfterItem:
+ ld a, MON_MAXHP
+ call GetPartyParamLocation
+ ld d, h
+ ld e, l
+ ld a, MON_STAT_EXP - 1
+ call GetPartyParamLocation
+ ld b, TRUE
+ predef_jump CalcMonStats
+
+RareCandy_StatBooster_ExitMenu:
+ xor a
+ ld [wItemEffectSucceeded], a
+ jp ClearPalettes
+
+Text_StatRose:
+ ; 's @ rose.
+ text_jump UnknownText_0x1c5b9a
+ db "@"
+
+StatStrings:
+ dw .health
+ dw .attack
+ dw .defense
+ dw .speed
+ dw .special
+
+.health db "HEALTH@"
+.attack db "ATTACK@"
+.defense db "DEFENSE@"
+.speed db "SPEED@"
+.special db "SPECIAL@"
+
+GetStatExpRelativePointer:
+ ld a, [wCurItem]
+ ld hl, Table_eeeb
+.next
+ cp [hl]
+ inc hl
+ jr z, .got_it
+ inc hl
+ jr .next
+
+.got_it
+ ld a, [hl]
+ ld c, a
+ ld b, 0
+ ret
+
+Table_eeeb:
+ db HP_UP, MON_HP_EXP - MON_STAT_EXP
+ db PROTEIN, MON_ATK_EXP - MON_STAT_EXP
+ db IRON, MON_DEF_EXP - MON_STAT_EXP
+ db CARBOS, MON_SPD_EXP - MON_STAT_EXP
+ db CALCIUM, MON_SPC_EXP - MON_STAT_EXP
+
+RareCandy_StatBooster_GetParameters:
+ ld a, [wCurPartySpecies]
+ ld [wCurSpecies], a
+ ld [wd265], a
+ ld a, MON_LEVEL
+ call GetPartyParamLocation
+ ld a, [hl]
+ ld [wCurPartyLevel], a
+ call GetBaseData
+ ld a, [wCurPartyMon]
+ ld hl, wPartyMonNicknames
+ call GetNick
+ ret
+
+RareCandyEffect:
+ ld b, PARTYMENUACTION_HEALING_ITEM
+ call UseItem_SelectMon
+
+ jp c, RareCandy_StatBooster_ExitMenu
+
+ call RareCandy_StatBooster_GetParameters
+
+ ld a, MON_LEVEL
+ call GetPartyParamLocation
+
+ ld a, [hl]
+ cp MAX_LEVEL
+ jp nc, NoEffectMessage
+
+ inc a
+ ld [hl], a
+ ld [wCurPartyLevel], a
+ push de
+ ld d, a
+ farcall CalcExpAtLevel
+
+ pop de
+ ld a, MON_EXP
+ call GetPartyParamLocation
+
+ ld a, [hMultiplicand]
+ ld [hli], a
+ ld a, [hMultiplicand + 1]
+ ld [hli], a
+ ld a, [hMultiplicand + 2]
+ ld [hl], a
+
+ ld a, MON_MAXHP
+ call GetPartyParamLocation
+ ld a, [hli]
+ ld b, a
+ ld c, [hl]
+ push bc
+ call UpdateStatsAfterItem
+
+ ld a, MON_MAXHP + 1
+ call GetPartyParamLocation
+
+ pop bc
+ ld a, [hld]
+ sub c
+ ld c, a
+ ld a, [hl]
+ sbc b
+ ld b, a
+ dec hl
+ ld a, [hl]
+ add c
+ ld [hld], a
+ ld a, [hl]
+ adc b
+ ld [hl], a
+ farcall LevelUpHappinessMod
+
+ ld a, PARTYMENUTEXT_LEVEL_UP
+ call ItemActionText
+
+ xor a ; PARTYMON
+ ld [wMonType], a
+ predef CopyMonToTempMon
+
+ hlcoord 9, 0
+ ld b, 10
+ ld c, 9
+ call TextBox
+
+ hlcoord 11, 1
+ ld bc, 4
+ predef PrintTempMonStats
+
+ call WaitPressAorB_BlinkCursor
+
+ xor a ; PARTYMON
+ ld [wMonType], a
+ ld a, [wCurPartySpecies]
+ ld [wd265], a
+ predef LearnLevelMoves
+
+ xor a
+ ld [wForceEvolution], a
+ farcall EvolvePokemon
+
+ jp UseDisposableItem
+
+HealPowderEffect:
+ ld b, PARTYMENUACTION_HEALING_ITEM
+ call UseItem_SelectMon
+
+ jp c, StatusHealer_ExitMenu
+
+ call UseStatusHealer
+
+ cp $0
+ jr nz, .asm_efc9
+ ld c, HAPPINESS_BITTERPOWDER
+ farcall ChangeHappiness
+
+ call LooksBitterMessage
+
+ ld a, $0
+
+.asm_efc9
+ jp StatusHealer_Jumptable
+
+StatusHealingEffect:
+ ld b, PARTYMENUACTION_HEALING_ITEM
+ call UseItem_SelectMon
+ jp c, StatusHealer_ExitMenu
+
+FullyHealStatus:
+ call UseStatusHealer
+ jp StatusHealer_Jumptable
+
+UseStatusHealer:
+ call IsMonFainted
+ ld a, $1
+ ret z
+ call GetItemHealingAction
+ ld a, MON_STATUS
+ call GetPartyParamLocation
+ ld a, [hl]
+ and c
+ jr nz, .good
+ call IsItemUsedOnConfusedMon
+ ld a, $1
+ ret nc
+ ld b, PARTYMENUTEXT_HEAL_CONFUSION
+.good
+ xor a
+ ld [hl], a
+ ld a, b
+ ld [wPartyMenuActionText], a
+ call HealStatus
+ call Play_SFX_FULL_HEAL
+ call ItemActionTextWaitButton
+ call UseDisposableItem
+ ld a, $0
+ ret
+
+IsItemUsedOnConfusedMon:
+ call IsItemUsedOnBattleMon
+ jr nc, .nope
+ ld a, [wPlayerSubStatus3]
+ bit SUBSTATUS_CONFUSED, a
+ jr z, .nope
+ ld a, c
+ cp $ff
+ jr nz, .nope
+ scf
+ ret
+
+.nope
+ and a
+ ret
+
+BattlemonRestoreHealth:
+ call IsItemUsedOnBattleMon
+ ret nc
+ ld a, MON_HP
+ call GetPartyParamLocation
+ ld a, [hli]
+ ld [wBattleMonHP], a
+ ld a, [hld]
+ ld [wBattleMonHP + 1], a
+ ret
+
+HealStatus:
+ call IsItemUsedOnBattleMon
+ ret nc
+ xor a
+ ld [wBattleMonStatus], a
+ ld hl, wPlayerSubStatus5
+ res SUBSTATUS_TOXIC, [hl]
+ ld hl, wPlayerSubStatus1
+ res SUBSTATUS_NIGHTMARE, [hl]
+ call GetItemHealingAction
+ ld a, c
+ cp %11111111
+ jr nz, .not_full_heal
+ ld hl, wPlayerSubStatus3
+ res SUBSTATUS_CONFUSED, [hl]
+.not_full_heal
+ push bc
+ farcall CalcPlayerStats
+ pop bc
+ ret
+
+GetItemHealingAction:
+ push hl
+ ld a, [wCurItem]
+ ld hl, StatusHealingActions
+ ld bc, 3
+.next
+ cp [hl]
+ jr z, .found_it
+ add hl, bc
+ jr .next
+
+.found_it
+ inc hl
+ ld b, [hl]
+ inc hl
+ ld a, [hl]
+ ld c, a
+ cp %11111111
+ pop hl
+ ret
+
+INCLUDE "data/items/heal_status.asm"
+
+StatusHealer_Jumptable:
+ ld hl, .dw
+ rst JumpTable
+ ret
+
+.dw
+ dw StatusHealer_ClearPalettes
+ dw StatusHealer_NoEffect
+ dw StatusHealer_ExitMenu
+
+RevivalHerbEffect:
+ ld b, PARTYMENUACTION_HEALING_ITEM
+ call UseItem_SelectMon
+ jp c, StatusHealer_ExitMenu
+
+ call RevivePokemon
+ cp 0
+ jr nz, .asm_f0c5
+
+ ld c, HAPPINESS_REVIVALHERB
+ farcall ChangeHappiness
+ call LooksBitterMessage
+ ld a, 0
+
+.asm_f0c5
+ jp StatusHealer_Jumptable
+
+ReviveEffect:
+ ld b, PARTYMENUACTION_HEALING_ITEM
+ call UseItem_SelectMon
+ jp c, StatusHealer_ExitMenu
+
+ call RevivePokemon
+ jp StatusHealer_Jumptable
+
+RevivePokemon:
+ call IsMonFainted
+ ld a, 1
+ ret nz
+ ld a, [wBattleMode]
+ and a
+ jr z, .skip_to_revive
+
+ ld a, [wCurPartyMon]
+ ld c, a
+ ld d, 0
+ ld hl, wBattleParticipantsIncludingFainted
+ ld b, CHECK_FLAG
+ predef SmallFarFlagAction
+ ld a, c
+ and a
+ jr z, .skip_to_revive
+
+ ld a, [wCurPartyMon]
+ ld c, a
+ ld hl, wBattleParticipantsNotFainted
+ ld b, SET_FLAG
+ predef SmallFarFlagAction
+
+.skip_to_revive
+ xor a
+ ld [wLowHealthAlarm], a
+ ld a, [wCurItem]
+ cp REVIVE
+ jr z, .revive_half_hp
+
+ call ReviveFullHP
+ jr .finish_revive
+
+.revive_half_hp
+ call ReviveHalfHP
+
+.finish_revive
+ call HealHP_SFX_GFX
+ ld a, PARTYMENUTEXT_REVIVE
+ ld [wPartyMenuActionText], a
+ call ItemActionTextWaitButton
+ call UseDisposableItem
+ ld a, 0
+ ret
+
+FullRestoreEffect:
+ ld b, PARTYMENUACTION_HEALING_ITEM
+ call UseItem_SelectMon
+ jp c, StatusHealer_ExitMenu
+
+ call IsMonFainted
+ jp z, StatusHealer_NoEffect
+
+ call IsMonAtFullHealth
+ jr c, .NotAtFullHealth
+
+ jp FullyHealStatus
+
+.NotAtFullHealth:
+ call .FullRestore
+ jp StatusHealer_Jumptable
+
+.FullRestore:
+ xor a
+ ld [wLowHealthAlarm], a
+ call ReviveFullHP
+ ld a, MON_STATUS
+ call GetPartyParamLocation
+ xor a
+ ld [hli], a
+ ld [hl], a
+ call HealStatus
+ call BattlemonRestoreHealth
+ call HealHP_SFX_GFX
+ ld a, PARTYMENUTEXT_HEAL_HP
+ ld [wPartyMenuActionText], a
+ call ItemActionTextWaitButton
+ call UseDisposableItem
+ ld a, 0
+ ret
+
+BitterBerryEffect:
+ ld hl, wPlayerSubStatus3
+ bit SUBSTATUS_CONFUSED, [hl]
+ ld a, 1
+ jr z, .done
+
+ res SUBSTATUS_CONFUSED, [hl]
+ xor a
+ ld [hBattleTurn], a
+ call UseItemText
+
+ ld hl, ConfusedNoMoreText
+ call StdBattleTextBox
+
+ ld a, 0
+
+.done
+ jp StatusHealer_Jumptable
+
+RestoreHPEffect:
+ call ItemRestoreHP
+ jp StatusHealer_Jumptable
+
+EnergypowderEffect:
+ ld c, HAPPINESS_BITTERPOWDER
+ jr EnergypowderEnergyRootCommon
+
+EnergyRootEffect:
+ ld c, HAPPINESS_ENERGYROOT
+
+EnergypowderEnergyRootCommon:
+ push bc
+ call ItemRestoreHP
+ pop bc
+ cp 0
+ jr nz, .skip_happiness
+
+ farcall ChangeHappiness
+ call LooksBitterMessage
+ ld a, 0
+
+.skip_happiness
+ jp StatusHealer_Jumptable
+
+ItemRestoreHP:
+ ld b, PARTYMENUACTION_HEALING_ITEM
+ call UseItem_SelectMon
+ ld a, 2
+ ret c
+
+ call IsMonFainted
+ ld a, 1
+ ret z
+
+ call IsMonAtFullHealth
+ ld a, 1
+ ret nc
+
+ xor a
+ ld [wLowHealthAlarm], a
+ call GetHealingItemAmount
+ call RestoreHealth
+ call BattlemonRestoreHealth
+ call HealHP_SFX_GFX
+ ld a, PARTYMENUTEXT_HEAL_HP
+ ld [wPartyMenuActionText], a
+ call ItemActionTextWaitButton
+ call UseDisposableItem
+ ld a, 0
+ ret
+
+HealHP_SFX_GFX:
+ push de
+ ld de, SFX_POTION
+ call WaitPlaySFX
+ pop de
+ ld a, [wCurPartyMon]
+ hlcoord 11, 0
+ ld bc, SCREEN_WIDTH * 2
+ call AddNTimes
+ ld a, $2
+ ld [wWhichHPBar], a
+ predef_jump AnimateHPBar
+
+UseItem_SelectMon:
+ call .SelectMon
+ ret c
+
+ ld a, [wCurPartySpecies]
+ cp EGG
+ jr nz, .not_egg
+
+ call CantUseOnEggMessage
+ scf
+ ret
+
+.not_egg
+ and a
+ ret
+
+.SelectMon:
+ ld a, b
+ ld [wPartyMenuActionText], a
+ push hl
+ push de
+ push bc
+ call ClearBGPalettes
+ call ChooseMonToUseItemOn
+ pop bc
+ pop de
+ pop hl
+ ret
+
+ChooseMonToUseItemOn:
+ farcall LoadPartyMenuGFX
+ farcall InitPartyMenuWithCancel
+ farcall InitPartyMenuGFX
+ farcall WritePartyMenuTilemap
+ farcall PrintPartyMenuText
+ call WaitBGMap
+ call SetPalettes
+ call DelayFrame
+ farcall PartyMenuSelect
+ ret
+
+ItemActionText:
+ ld [wPartyMenuActionText], a
+ ld a, [wCurPartySpecies]
+ push af
+ ld a, [wCurPartyMon]
+ push af
+ push hl
+ push de
+ push bc
+ farcall WritePartyMenuTilemap
+ farcall PrintPartyMenuActionText
+ call WaitBGMap
+ call SetPalettes
+ call DelayFrame
+ pop bc
+ pop de
+ pop hl
+ pop af
+ ld [wCurPartyMon], a
+ pop af
+ ld [wCurPartySpecies], a
+ ret
+
+ItemActionTextWaitButton:
+ xor a
+ ld [hBGMapMode], a
+ hlcoord 0, 0
+ ld bc, wTileMapEnd - wTileMap
+ ld a, " "
+ call ByteFill
+ ld a, [wPartyMenuActionText]
+ call ItemActionText
+ ld a, $1
+ ld [hBGMapMode], a
+ ld c, 50
+ call DelayFrames
+ jp WaitPressAorB_BlinkCursor
+
+StatusHealer_NoEffect:
+ call WontHaveAnyEffectMessage
+ jr StatusHealer_ClearPalettes
+
+StatusHealer_ExitMenu:
+ xor a
+ ld [wItemEffectSucceeded], a
+StatusHealer_ClearPalettes:
+ call ClearPalettes
+ ret
+
+IsItemUsedOnBattleMon:
+ ld a, [wBattleMode]
+ and a
+ ret z
+ ld a, [wCurPartyMon]
+ push hl
+ ld hl, wCurBattleMon
+ cp [hl]
+ pop hl
+ jr nz, .nope
+ scf
+ ret
+
+.nope
+ xor a
+ ret
+
+ReviveHalfHP:
+ call LoadHPFromBuffer1
+ srl d
+ rr e
+ jr ContinueRevive
+
+ReviveFullHP:
+ call LoadHPFromBuffer1
+ContinueRevive:
+ ld a, MON_HP
+ call GetPartyParamLocation
+ ld [hl], d
+ inc hl
+ ld [hl], e
+ jp LoadCurHPIntoBuffer5
+
+RestoreHealth:
+ ld a, MON_HP + 1
+ call GetPartyParamLocation
+ ld a, [hl]
+ add e
+ ld [hld], a
+ ld a, [hl]
+ adc d
+ ld [hl], a
+ jr c, .full_hp
+ call LoadCurHPIntoBuffer5
+ ld a, MON_HP + 1
+ call GetPartyParamLocation
+ ld d, h
+ ld e, l
+ ld a, MON_MAXHP + 1
+ call GetPartyParamLocation
+ ld a, [de]
+ sub [hl]
+ dec de
+ dec hl
+ ld a, [de]
+ sbc [hl]
+ jr c, .finish
+.full_hp
+ call ReviveFullHP
+.finish
+ ret
+
+RemoveHP:
+ ld a, MON_HP + 1
+ call GetPartyParamLocation
+ ld a, [hl]
+ sub e
+ ld [hld], a
+ ld a, [hl]
+ sbc d
+ ld [hl], a
+ jr nc, .okay
+ xor a
+ ld [hld], a
+ ld [hl], a
+.okay
+ call LoadCurHPIntoBuffer5
+ ret
+
+IsMonFainted:
+ push de
+ call LoadMaxHPToBuffer1
+ call LoadCurHPToBuffer3
+ call LoadHPFromBuffer3
+ ld a, d
+ or e
+ pop de
+ ret
+
+IsMonAtFullHealth:
+ call LoadHPFromBuffer3
+ ld h, d
+ ld l, e
+ call LoadHPFromBuffer1
+ ld a, l
+ sub e
+ ld a, h
+ sbc d
+ ret
+
+LoadCurHPIntoBuffer5:
+ ld a, MON_HP
+ call GetPartyParamLocation
+ ld a, [hli]
+ ld [wBuffer6], a
+ ld a, [hl]
+ ld [wBuffer5], a
+ ret
+
+LoadHPIntoBuffer5:
+ ld a, d
+ ld [wBuffer6], a
+ ld a, e
+ ld [wBuffer5], a
+ ret
+
+LoadHPFromBuffer5:
+ ld a, [wBuffer6]
+ ld d, a
+ ld a, [wBuffer5]
+ ld e, a
+ ret
+
+LoadCurHPToBuffer3:
+ ld a, MON_HP
+ call GetPartyParamLocation
+ ld a, [hli]
+ ld [wBuffer4], a
+ ld a, [hl]
+ ld [wBuffer3], a
+ ret
+
+LoadHPFromBuffer3:
+ ld a, [wBuffer4]
+ ld d, a
+ ld a, [wBuffer3]
+ ld e, a
+ ret
+
+LoadMaxHPToBuffer1:
+ push hl
+ ld a, MON_MAXHP
+ call GetPartyParamLocation
+ ld a, [hli]
+ ld [wBuffer2], a
+ ld a, [hl]
+ ld [wBuffer1], a
+ pop hl
+ ret
+
+LoadHPFromBuffer1:
+ ld a, [wBuffer2]
+ ld d, a
+ ld a, [wBuffer1]
+ ld e, a
+ ret
+
+GetOneFifthMaxHP:
+ push bc
+ ld a, MON_MAXHP
+ call GetPartyParamLocation
+ ld a, [hli]
+ ld [hDividend + 0], a
+ ld a, [hl]
+ ld [hDividend + 1], a
+ ld a, 5
+ ld [hDivisor], a
+ ld b, 2
+ call Divide
+ ld a, [hQuotient + 1]
+ ld d, a
+ ld a, [hQuotient + 2]
+ ld e, a
+ pop bc
+ ret
+
+GetHealingItemAmount:
+ push hl
+ ld a, [wCurItem]
+ ld hl, HealingHPAmounts
+ ld d, a
+.next
+ ld a, [hli]
+ cp -1
+ jr z, .NotFound
+ cp d
+ jr z, .done
+ inc hl
+ inc hl
+ jr .next
+
+.NotFound:
+ scf
+.done
+ ld e, [hl]
+ inc hl
+ ld d, [hl]
+ pop hl
+ ret
+
+INCLUDE "data/items/heal_hp.asm"
+
+Softboiled_MilkDrinkFunction:
+; Softboiled/Milk Drink in the field
+ ld a, [wPartyMenuCursor]
+ dec a
+ ld b, a
+ call .SelectMilkDrinkRecipient ; select pokemon
+ jr c, .skip
+ ld a, b
+ ld [wCurPartyMon], a
+ call IsMonFainted
+ call GetOneFifthMaxHP
+ call RemoveHP
+ push bc
+ call HealHP_SFX_GFX
+ pop bc
+ call GetOneFifthMaxHP
+ ld a, c
+ ld [wCurPartyMon], a
+ call IsMonFainted
+ call RestoreHealth
+ call HealHP_SFX_GFX
+ ld a, PARTYMENUTEXT_HEAL_HP
+ call ItemActionText
+ call JoyWaitAorB
+.skip
+ ld a, b
+ inc a
+ ld [wPartyMenuCursor], a
+ ret
+
+.SelectMilkDrinkRecipient:
+.loop
+ push bc
+ ld a, PARTYMENUACTION_HEALING_ITEM
+ ld [wPartyMenuActionText], a
+ call ChooseMonToUseItemOn
+ pop bc
+ jr c, .set_carry
+ ld a, [wPartyMenuCursor]
+ dec a
+ ld c, a
+ ld a, b
+ cp c
+ jr z, .cant_use ; chose the same mon as user
+ ld a, c
+ ld [wCurPartyMon], a
+ call IsMonFainted
+ jr z, .cant_use
+ call IsMonAtFullHealth
+ jr nc, .cant_use
+ xor a
+ ret
+
+.set_carry
+ scf
+ ret
+
+.cant_use
+ push bc
+ ld hl, .Text_CantBeUsed
+ call MenuTextBoxBackup
+ pop bc
+ jr .loop
+
+.Text_CantBeUsed:
+ ; That can't be used on this #MON.
+ text_jump UnknownText_0x1c5bac
+ db "@"
+
+EscapeRopeEffect:
+ xor a
+ ld [wItemEffectSucceeded], a
+ farcall EscapeRopeFunction
+
+ ld a, [wItemEffectSucceeded]
+ cp 1
+ call z, UseDisposableItem
+ ret
+
+SuperRepelEffect:
+ ld b, 200
+ jr UseRepel
+
+MaxRepelEffect:
+ ld b, 250
+ jr UseRepel
+
+RepelEffect:
+ ld b, 100
+
+UseRepel:
+ ld a, [wRepelEffect]
+ and a
+ ld hl, TextJump_RepelUsedEarlierIsStillInEffect
+ jp nz, PrintText
+
+ ld a, b
+ ld [wRepelEffect], a
+ jp UseItemText
+
+TextJump_RepelUsedEarlierIsStillInEffect:
+ ; The REPEL used earlier is still in effect.
+ text_jump Text_RepelUsedEarlierIsStillInEffect
+ db "@"
+
+XAccuracyEffect:
+ ld hl, wPlayerSubStatus4
+ bit SUBSTATUS_X_ACCURACY, [hl]
+ jp nz, WontHaveAnyEffect_NotUsedMessage
+ set SUBSTATUS_X_ACCURACY, [hl]
+ jp UseItemText
+
+PokeDollEffect:
+ ld a, [wBattleMode]
+ dec a
+ jr nz, .asm_f4a6
+ inc a
+ ld [wForcedSwitch], a
+ ld a, [wBattleResult]
+ and BATTLERESULT_BITMASK
+ or DRAW
+ ld [wBattleResult], a
+ jp UseItemText
+
+.asm_f4a6
+ xor a
+ ld [wItemEffectSucceeded], a
+ ret
+
+GuardSpecEffect:
+ ld hl, wPlayerSubStatus4
+ bit SUBSTATUS_MIST, [hl]
+ jp nz, WontHaveAnyEffect_NotUsedMessage
+ set SUBSTATUS_MIST, [hl]
+ jp UseItemText
+
+DireHitEffect:
+ ld hl, wPlayerSubStatus4
+ bit SUBSTATUS_FOCUS_ENERGY, [hl]
+ jp nz, WontHaveAnyEffect_NotUsedMessage
+ set SUBSTATUS_FOCUS_ENERGY, [hl]
+ jp UseItemText
+
+XItemEffect:
+ call UseItemText
+
+ ld a, [wCurItem]
+ ld hl, XItemStats
+
+.loop
+ cp [hl]
+ jr z, .got_it
+ inc hl
+ inc hl
+ jr .loop
+
+.got_it
+ inc hl
+ ld b, [hl]
+ xor a
+ ld [hBattleTurn], a
+ ld [wAttackMissed], a
+ ld [wEffectFailed], a
+ farcall CheckIfStatCanBeRaised
+ call WaitSFX
+
+ farcall BattleCommand_StatUpMessage
+ farcall BattleCommand_StatUpFailText
+
+ ld a, [wCurBattleMon]
+ ld [wCurPartyMon], a
+ ld c, HAPPINESS_USEDXITEM
+ farcall ChangeHappiness
+ ret
+
+INCLUDE "data/items/x_stats.asm"
+
+PokeFluteEffect:
+ ld a, [wBattleMode]
+ and a
+ jr nz, .dummy
+.dummy
+
+ xor a
+ ld [wd002], a
+
+ ld b, $ff ^ SLP
+
+ ld hl, wPartyMon1Status
+ call .CureSleep
+
+ ld a, [wBattleMode]
+ cp WILD_BATTLE
+ jr z, .skip_otrainer
+ ld hl, wOTPartyMon1Status
+ call .CureSleep
+.skip_otrainer
+
+ ld hl, wBattleMonStatus
+ ld a, [hl]
+ and b
+ ld [hl], a
+ ld hl, wEnemyMonStatus
+ ld a, [hl]
+ and b
+ ld [hl], a
+
+ ld a, [wd002]
+ and a
+ ld hl, .CatchyTune
+ jp z, PrintText
+ ld hl, .PlayedTheFlute
+ call PrintText
+
+ ld a, [wLowHealthAlarm]
+ and 1 << DANGER_ON_F
+ jr nz, .dummy2
+.dummy2
+ ld hl, .AllSleepingMonWokeUp
+ jp PrintText
+
+.CureSleep:
+ ld de, PARTYMON_STRUCT_LENGTH
+ ld c, PARTY_LENGTH
+
+.loop
+ ld a, [hl]
+ push af
+ and SLP
+ jr z, .not_asleep
+ ld a, 1
+ ld [wd002], a
+.not_asleep
+ pop af
+ and b
+ ld [hl], a
+ add hl, de
+ dec c
+ jr nz, .loop
+ ret
+
+.CatchyTune:
+ ; Played the # FLUTE. Now, that's a catchy tune!
+ text_jump UnknownText_0x1c5bf9
+ db "@"
+
+.AllSleepingMonWokeUp:
+ ; All sleeping #MON woke up.
+ text_jump UnknownText_0x1c5c28
+ db "@"
+
+.PlayedTheFlute:
+ ; played the # FLUTE.@ @
+ text_jump UnknownText_0x1c5c44
+ start_asm
+ ld a, [wBattleMode]
+ and a
+ jr nz, .battle
+
+ push de
+ ld de, SFX_POKEFLUTE
+ call WaitPlaySFX
+ call WaitSFX
+ pop de
+
+.battle
+ jp PokeFluteTerminatorCharacter
+
+BlueCardEffect:
+ ld hl, .bluecardtext
+ jp MenuTextBoxWaitButton
+
+.bluecardtext
+ text_jump UnknownText_0x1c5c5e
+ db "@"
+
+CoinCaseEffect:
+ ld hl, .coincasetext
+ jp MenuTextBoxWaitButton
+
+.coincasetext
+ text_jump UnknownText_0x1c5c7b
+ db "@"
+
+OldRodEffect:
+ ld e, $0
+ jr UseRod
+
+GoodRodEffect:
+ ld e, $1
+ jr UseRod
+
+SuperRodEffect:
+ ld e, $2
+ jr UseRod
+
+UseRod:
+ farcall FishFunction
+ ret
+
+ItemfinderEffect:
+ farcall ItemFinder
+ ret
+
+RestorePPEffect:
+ ld a, [wCurItem]
+ ld [wd002], a
+
+.loop
+ ; Party Screen opens to choose on which mon to use the Item
+ ld b, PARTYMENUACTION_HEALING_ITEM
+ call UseItem_SelectMon
+ jp c, PPRestoreItem_Cancel
+
+.loop2
+ ld a, [wd002]
+ cp MAX_ELIXER
+ jp z, Elixer_RestorePPofAllMoves
+ cp ELIXER
+ jp z, Elixer_RestorePPofAllMoves
+
+ ld hl, TextJump_RaiseThePPOfWhichMove
+ ld a, [wd002]
+ cp PP_UP
+ jr z, .ppup
+ ld hl, TextJump_RestoreThePPOfWhichMove
+
+.ppup
+ call PrintText
+
+ ld a, [wCurMoveNum]
+ push af
+ xor a
+ ld [wCurMoveNum], a
+ ld a, $2
+ ld [wMoveSelectionMenuType], a
+ farcall MoveSelectionScreen
+ pop bc
+
+ ld a, b
+ ld [wCurMoveNum], a
+ jr nz, .loop
+ ld hl, wPartyMon1Moves
+ ld bc, PARTYMON_STRUCT_LENGTH
+ call GetMthMoveOfNthPartymon
+
+ push hl
+ ld a, [hl]
+ ld [wd265], a
+ call GetMoveName
+ call CopyName1
+ pop hl
+
+ ld a, [wd002]
+ cp PP_UP
+ jp nz, Not_PP_Up
+
+ ld a, [hl]
+ cp SKETCH
+ jr z, .CantUsePPUpOnSketch
+
+ ld bc, MON_PP - MON_MOVES
+ add hl, bc
+ ld a, [hl]
+ cp PP_UP_MASK
+ jr c, .do_ppup
+
+.CantUsePPUpOnSketch:
+.pp_is_maxed_out
+ ld hl, TextJump_PPIsMaxedOut
+ call PrintText
+ jr .loop2
+
+.do_ppup
+ ld a, [hl]
+ add PP_UP_ONE
+ ld [hl], a
+ ld a, $1
+ ld [wd265], a
+ call ApplyPPUp
+ call Play_SFX_FULL_HEAL
+
+ ld hl, TextJump_PPsIncreased
+ call PrintText
+
+FinishPPRestore:
+ call ClearPalettes
+ jp UseDisposableItem
+
+BattleRestorePP:
+ ld a, [wBattleMode]
+ and a
+ jr z, .not_in_battle
+ ld a, [wCurPartyMon]
+ ld b, a
+ ld a, [wCurBattleMon]
+ cp b
+ jr nz, .not_in_battle
+ ld a, [wPlayerSubStatus5]
+ bit SUBSTATUS_TRANSFORMED, a
+ jr nz, .not_in_battle
+ call .UpdateBattleMonPP
+
+.not_in_battle
+ call Play_SFX_FULL_HEAL
+ ld hl, UnknownText_0xf739
+ call PrintText
+ jr FinishPPRestore
+
+.UpdateBattleMonPP:
+ ld a, [wCurPartyMon]
+ ld hl, wPartyMon1Moves
+ ld bc, PARTYMON_STRUCT_LENGTH
+ call AddNTimes
+ ld de, wBattleMonMoves
+ ld b, NUM_MOVES
+.loop
+ ld a, [de]
+ and a
+ jr z, .done
+ cp [hl]
+ jr nz, .next
+ push hl
+ push de
+ push bc
+rept NUM_MOVES + 2 ; wBattleMonPP - wBattleMonMoves
+ inc de
+endr
+ ld bc, MON_PP - MON_MOVES
+ add hl, bc
+ ld a, [hl]
+ ld [de], a
+ pop bc
+ pop de
+ pop hl
+
+.next
+ inc hl
+ inc de
+ dec b
+ jr nz, .loop
+
+.done
+ ret
+
+Not_PP_Up:
+ call RestorePP
+ jr nz, BattleRestorePP
+ jp PPRestoreItem_NoEffect
+
+Elixer_RestorePPofAllMoves:
+ xor a
+ ld hl, wMenuCursorY
+ ld [hli], a
+ ld [hl], a
+ ld b, NUM_MOVES
+.moveLoop
+ push bc
+ ld hl, wPartyMon1Moves
+ ld bc, PARTYMON_STRUCT_LENGTH
+ call GetMthMoveOfNthPartymon
+ ld a, [hl]
+ and a
+ jr z, .next
+
+ call RestorePP
+ jr z, .next
+ ld hl, wMenuCursorX
+ inc [hl]
+
+.next
+ ld hl, wMenuCursorY
+ inc [hl]
+ pop bc
+ dec b
+ jr nz, .moveLoop
+ ld a, [wMenuCursorX]
+ and a
+ jp nz, BattleRestorePP
+
+PPRestoreItem_NoEffect:
+ call WontHaveAnyEffectMessage
+
+PPRestoreItem_Cancel:
+ call ClearPalettes
+ xor a
+ ld [wItemEffectSucceeded], a
+ ret
+
+RestorePP:
+ xor a ; PARTYMON
+ ld [wMonType], a
+ call GetMaxPPOfMove
+ ld hl, wPartyMon1PP
+ ld bc, PARTYMON_STRUCT_LENGTH
+ call GetMthMoveOfNthPartymon
+ ld a, [wd265]
+ ld b, a
+ ld a, [hl]
+ and PP_MASK
+ cp b
+ jr nc, .dont_restore
+
+ ld a, [wd002]
+ cp MAX_ELIXER
+ jr z, .restore_all
+ cp MAX_ETHER
+ jr z, .restore_all
+
+ ld c, 5
+ cp MYSTERYBERRY
+ jr z, .restore_some
+
+ ld c, 10
+
+.restore_some
+ ld a, [hl]
+ and PP_MASK
+ add c
+ cp b
+ jr nc, .restore_all
+ ld b, a
+
+.restore_all
+ ld a, [hl]
+ and PP_UP_MASK
+ or b
+ ld [hl], a
+ ret
+
+.dont_restore
+ xor a
+ ret
+
+TextJump_RaiseThePPOfWhichMove:
+ ; Raise the PP of which move?
+ text_jump Text_RaiseThePPOfWhichMove
+ db "@"
+
+TextJump_RestoreThePPOfWhichMove:
+ ; Restore the PP of which move?
+ text_jump Text_RestoreThePPOfWhichMove
+ db "@"
+
+TextJump_PPIsMaxedOut:
+ ; 's PP is maxed out.
+ text_jump Text_PPIsMaxedOut
+ db "@"
+
+TextJump_PPsIncreased:
+ ; 's PP increased.
+ text_jump Text_PPsIncreased
+ db "@"
+
+UnknownText_0xf739:
+ ; PP was restored.
+ text_jump UnknownText_0x1c5cf1
+ db "@"
+
+SquirtbottleEffect:
+ farcall _Squirtbottle
+ ret
+
+CardKeyEffect:
+ farcall _CardKey
+ ret
+
+BasementKeyEffect:
+ farcall _BasementKey
+ ret
+
+SacredAshEffect:
+ farcall _SacredAsh
+ ld a, [wItemEffectSucceeded]
+ cp $1
+ ret nz
+ call UseDisposableItem
+ ret
+
+NormalBoxEffect:
+ ld c, DECOFLAG_SILVER_TROPHY_DOLL
+ jr OpenBox
+
+GorgeousBoxEffect:
+ ld c, DECOFLAG_GOLD_TROPHY_DOLL
+OpenBox:
+ farcall SetSpecificDecorationFlag
+
+ ld hl, .text
+ call PrintText
+
+ jp UseDisposableItem
+
+.text
+ ; There was a trophy inside!
+ text_jump UnknownText_0x1c5d03
+ db "@"
+
+NoEffect:
+ jp IsntTheTimeMessage
+
+Play_SFX_FULL_HEAL:
+ push de
+ ld de, SFX_FULL_HEAL
+ call WaitPlaySFX
+ pop de
+ ret
+
+UseItemText:
+ ld hl, UsedItemText
+ call PrintText
+ call Play_SFX_FULL_HEAL
+ call WaitPressAorB_BlinkCursor
+UseDisposableItem:
+ ld hl, wNumItems
+ ld a, 1
+ ld [wItemQuantityChangeBuffer], a
+ jp TossItem
+
+UseBallInTrainerBattle:
+ call ReturnToBattle_UseBall
+ ld de, ANIM_THROW_POKE_BALL
+ ld a, e
+ ld [wFXAnimID], a
+ ld a, d
+ ld [wFXAnimID + 1], a
+ xor a
+ ld [wBattleAnimParam], a
+ ld [hBattleTurn], a
+ ld [wNumHits], a
+ predef PlayBattleAnim
+ ld hl, BlockedTheBallText
+ call PrintText
+ ld hl, DontBeAThiefText
+ call PrintText
+ jr UseDisposableItem
+
+WontHaveAnyEffect_NotUsedMessage:
+ ld hl, WontHaveAnyEffectText
+ call PrintText
+
+ ; Item wasn't used.
+ ld a, $2
+ ld [wItemEffectSucceeded], a
+ ret
+
+LooksBitterMessage:
+ ld hl, LooksBitterText
+ jp PrintText
+
+Ball_BoxIsFullMessage:
+ ld hl, Ball_BoxIsFullText
+ call PrintText
+
+ ; Item wasn't used.
+ ld a, $2
+ ld [wItemEffectSucceeded], a
+ ret
+
+CantUseOnEggMessage:
+ ld hl, CantUseOnEggText
+ jr CantUseItemMessage
+
+IsntTheTimeMessage:
+ ld hl, IsntTheTimeText
+ jr CantUseItemMessage
+
+WontHaveAnyEffectMessage:
+ ld hl, WontHaveAnyEffectText
+ jr CantUseItemMessage
+
+BelongsToSomeoneElseMessage:
+ ld hl, BelongsToSomeoneElseText
+ jr CantUseItemMessage
+
+CyclingIsntAllowedMessage:
+ ld hl, CyclingIsntAllowedText
+ jr CantUseItemMessage
+
+CantGetOnYourBikeMessage:
+ ld hl, CantGetOnYourBikeText
+
+CantUseItemMessage:
+; Item couldn't be used.
+ xor a
+ ld [wItemEffectSucceeded], a
+ jp PrintText
+
+LooksBitterText:
+ ; It looks bitter…
+ text_jump UnknownText_0x1c5d3e
+ db "@"
+
+CantUseOnEggText:
+ ; That can't be used on an EGG.
+ text_jump UnknownText_0x1c5d50
+ db "@"
+
+IsntTheTimeText:
+ ; OAK: ! This isn't the time to use that!
+ text_jump UnknownText_0x1c5d6e
+ db "@"
+
+BelongsToSomeoneElseText:
+ ; That belongs to someone else!
+ text_jump UnknownText_0x1c5d97
+ db "@"
+
+WontHaveAnyEffectText:
+ ; It won't have any effect.
+ text_jump UnknownText_0x1c5db6
+ db "@"
+
+BlockedTheBallText:
+ ; The trainer blocked the BALL!
+ text_jump UnknownText_0x1c5dd0
+ db "@"
+
+DontBeAThiefText:
+ ; Don't be a thief!
+ text_jump UnknownText_0x1c5def
+ db "@"
+
+CyclingIsntAllowedText:
+ ; Cycling isn't allowed here.
+ text_jump UnknownText_0x1c5e01
+ db "@"
+
+CantGetOnYourBikeText:
+ ; Can't get on your @ now.
+ text_jump UnknownText_0x1c5e1d
+ db "@"
+
+Ball_BoxIsFullText:
+ ; The #MON BOX is full. That can't be used now.
+ text_jump UnknownText_0x1c5e3a
+ db "@"
+
+UsedItemText:
+ ; used the@ .
+ text_jump UnknownText_0x1c5e68
+ db "@"
+
+GotOnTheItemText:
+ ; got on the@ .
+ text_jump UnknownText_0x1c5e7b
+ db "@"
+
+GotOffTheItemText:
+ ; got off@ the @ .
+ text_jump UnknownText_0x1c5e90
+ db "@"
+
+ApplyPPUp:
+ ld a, MON_MOVES
+ call GetPartyParamLocation
+ push hl
+ ld de, wBuffer1
+ predef FillPP
+ pop hl
+ ld bc, MON_PP - MON_MOVES
+ add hl, bc
+ ld de, wBuffer1
+ ld b, 0
+.loop
+ inc b
+ ld a, b
+ cp NUM_MOVES + 1
+ ret z
+ ld a, [wd265]
+ dec a
+ jr nz, .use
+ ld a, [wMenuCursorY]
+ inc a
+ cp b
+ jr nz, .skip
+
+.use
+ ld a, [hl]
+ and PP_UP_MASK
+ ld a, [de] ; wasted cycle
+ call nz, ComputeMaxPP
+
+.skip
+ inc hl
+ inc de
+ jr .loop
+
+ComputeMaxPP:
+ push bc
+ ; Divide the base PP by 5.
+ ld a, [de]
+ ld [hDividend + 3], a
+ xor a
+ ld [hDividend], a
+ ld [hDividend + 1], a
+ ld [hDividend + 2], a
+ ld a, 5
+ ld [hDivisor], a
+ ld b, 4
+ call Divide
+ ; Get the number of PP, which are bits 6 and 7 of the PP value stored in RAM.
+ ld a, [hl]
+ ld b, a
+ swap a
+ and $f
+ srl a
+ srl a
+ ld c, a
+ ; If this value is 0, we are done
+ and a
+ jr z, .NoPPUp
+
+.loop
+ ; Normally, a move with 40 PP would have 64 PP with three PP Ups.
+ ; Since this would overflow into bit 6, we prevent that from happening
+ ; by decreasing the extra amount of PP each PP Up provides, resulting
+ ; in a maximum of 61.
+ ld a, [hQuotient + 2]
+ cp $8
+ jr c, .okay
+ ld a, $7
+
+.okay
+ add b
+ ld b, a
+ ld a, [wd265]
+ dec a
+ jr z, .NoPPUp
+ dec c
+ jr nz, .loop
+
+.NoPPUp:
+ ld [hl], b
+ pop bc
+ ret
+
+RestoreAllPP:
+ ld a, MON_PP
+ call GetPartyParamLocation
+ push hl
+ ld a, MON_MOVES
+ call GetPartyParamLocation
+ pop de
+ xor a ; PARTYMON
+ ld [wMenuCursorY], a
+ ld [wMonType], a
+ ld c, NUM_MOVES
+.loop
+ ld a, [hli]
+ and a
+ ret z
+ push hl
+ push de
+ push bc
+ call GetMaxPPOfMove
+ pop bc
+ pop de
+ ld a, [de]
+ and PP_UP_MASK
+ ld b, a
+ ld a, [wd265]
+ add b
+ ld [de], a
+ inc de
+ ld hl, wMenuCursorY
+ inc [hl]
+ pop hl
+ dec c
+ jr nz, .loop
+ ret
+
+GetMaxPPOfMove:
+ ld a, [wStringBuffer1 + 0]
+ push af
+ ld a, [wStringBuffer1 + 1]
+ push af
+
+ ld a, [wMonType]
+ and a
+
+ ld hl, wPartyMon1Moves
+ ld bc, PARTYMON_STRUCT_LENGTH
+ jr z, .got_partymon ; PARTYMON
+
+ ld hl, wOTPartyMon1Moves
+ dec a
+ jr z, .got_partymon ; OTPARTYMON
+
+ ld hl, wTempMonMoves
+ dec a
+ jr z, .got_nonpartymon ; BOXMON
+
+ ld hl, wTempMonMoves ; Wasted cycles
+ dec a
+ jr z, .got_nonpartymon ; TEMPMON
+
+ ld hl, wBattleMonMoves ; WILDMON
+
+.got_nonpartymon ; BOXMON, TEMPMON, WILDMON
+ call GetMthMoveOfCurrentMon
+ jr .gotdatmove
+
+.got_partymon ; PARTYMON, OTPARTYMON
+ call GetMthMoveOfNthPartymon
+
+.gotdatmove
+ ld a, [hl]
+ dec a
+
+ push hl
+ ld hl, Moves + MOVE_PP
+ ld bc, MOVE_LENGTH
+ call AddNTimes
+ ld a, BANK(Moves)
+ call GetFarByte
+ ld b, a
+ ld de, wStringBuffer1
+ ld [de], a
+ pop hl
+
+ push bc
+ ld bc, MON_PP - MON_MOVES
+ ld a, [wMonType]
+ cp WILDMON
+ jr nz, .notwild
+ ld bc, wEnemyMonPP - wEnemyMonMoves
+.notwild
+ add hl, bc
+ ld a, [hl]
+ and PP_UP_MASK
+ pop bc
+
+ or b
+ ld hl, wStringBuffer1 + 1
+ ld [hl], a
+ xor a
+ ld [wd265], a
+ ld a, b ; this gets lost anyway
+ call ComputeMaxPP
+ ld a, [hl]
+ and PP_MASK
+ ld [wd265], a
+
+ pop af
+ ld [wStringBuffer1 + 1], a
+ pop af
+ ld [wStringBuffer1 + 0], a
+ ret
+
+GetMthMoveOfNthPartymon:
+ ld a, [wCurPartyMon]
+ call AddNTimes
+
+GetMthMoveOfCurrentMon:
+ ld a, [wMenuCursorY]
+ ld c, a
+ ld b, 0
+ add hl, bc
+ ret
diff --git a/engine/items/items.asm b/engine/items/items.asm
new file mode 100644
index 000000000..28c79f4cc
--- /dev/null
+++ b/engine/items/items.asm
@@ -0,0 +1,581 @@
+_ReceiveItem::
+ call DoesHLEqualNumItems
+ jp nz, PutItemInPocket
+ push hl
+ call CheckItemPocket
+ pop de
+ ld a, [wItemAttributeParamBuffer]
+ dec a
+ ld hl, .Pockets
+ rst JumpTable
+ ret
+
+.Pockets:
+; entries correspond to item types
+ dw .Item
+ dw .KeyItem
+ dw .Ball
+ dw .TMHM
+
+.Item:
+ ld h, d
+ ld l, e
+ jp PutItemInPocket
+
+.KeyItem:
+ ld h, d
+ ld l, e
+ jp ReceiveKeyItem
+
+.Ball:
+ ld hl, wNumBalls
+ jp PutItemInPocket
+
+.TMHM:
+ ld h, d
+ ld l, e
+ ld a, [wCurItem]
+ ld c, a
+ call GetTMHMNumber
+ jp ReceiveTMHM
+
+_TossItem::
+ call DoesHLEqualNumItems
+ jr nz, .remove
+ push hl
+ call CheckItemPocket
+ pop de
+ ld a, [wItemAttributeParamBuffer]
+ dec a
+ ld hl, .Pockets
+ rst JumpTable
+ ret
+
+.Pockets:
+; entries correspond to item types
+ dw .Item
+ dw .KeyItem
+ dw .Ball
+ dw .TMHM
+
+.Ball:
+ ld hl, wNumBalls
+ jp RemoveItemFromPocket
+
+.TMHM:
+ ld h, d
+ ld l, e
+ ld a, [wCurItem]
+ ld c, a
+ call GetTMHMNumber
+ jp TossTMHM
+
+.KeyItem:
+ ld h, d
+ ld l, e
+ jp TossKeyItem
+
+.Item:
+ ld h, d
+ ld l, e
+
+.remove
+ jp RemoveItemFromPocket
+
+_CheckItem::
+ call DoesHLEqualNumItems
+ jr nz, .nope
+ push hl
+ call CheckItemPocket
+ pop de
+ ld a, [wItemAttributeParamBuffer]
+ dec a
+ ld hl, .Pockets
+ rst JumpTable
+ ret
+
+.Pockets:
+; entries correspond to item types
+ dw .Item
+ dw .KeyItem
+ dw .Ball
+ dw .TMHM
+
+.Ball:
+ ld hl, wNumBalls
+ jp CheckTheItem
+
+.TMHM:
+ ld h, d
+ ld l, e
+ ld a, [wCurItem]
+ ld c, a
+ call GetTMHMNumber
+ jp CheckTMHM
+
+.KeyItem:
+ ld h, d
+ ld l, e
+ jp CheckKeyItems
+
+.Item:
+ ld h, d
+ ld l, e
+
+.nope
+ jp CheckTheItem
+
+DoesHLEqualNumItems:
+ ld a, l
+ cp LOW(wNumItems)
+ ret nz
+ ld a, h
+ cp HIGH(wNumItems)
+ ret
+
+GetPocketCapacity:
+ ld c, MAX_ITEMS
+ ld a, e
+ cp LOW(wNumItems)
+ jr nz, .not_bag
+ ld a, d
+ cp HIGH(wNumItems)
+ ret z
+
+.not_bag
+ ld c, MAX_PC_ITEMS
+ ld a, e
+ cp LOW(wPCItems)
+ jr nz, .not_pc
+ ld a, d
+ cp HIGH(wPCItems)
+ ret z
+
+.not_pc
+ ld c, MAX_BALLS
+ ret
+
+PutItemInPocket:
+ ld d, h
+ ld e, l
+ inc hl
+ ld a, [wCurItem]
+ ld c, a
+ ld b, 0
+.loop
+ ld a, [hli]
+ cp -1
+ jr z, .terminator
+ cp c
+ jr nz, .next
+ ld a, 99
+ sub [hl]
+ add b
+ ld b, a
+ ld a, [wItemQuantityChangeBuffer]
+ cp b
+ jr z, .ok
+ jr c, .ok
+
+.next
+ inc hl
+ jr .loop
+
+.terminator
+ call GetPocketCapacity
+ ld a, [de]
+ cp c
+ jr c, .ok
+ and a
+ ret
+
+.ok
+ ld h, d
+ ld l, e
+ ld a, [wCurItem]
+ ld c, a
+ ld a, [wItemQuantityChangeBuffer]
+ ld [wItemQuantityBuffer], a
+.loop2
+ inc hl
+ ld a, [hli]
+ cp -1
+ jr z, .terminator2
+ cp c
+ jr nz, .loop2
+ ld a, [wItemQuantityBuffer]
+ add [hl]
+ cp 100
+ jr nc, .newstack
+ ld [hl], a
+ jr .done
+
+.newstack
+ ld [hl], 99
+ sub 99
+ ld [wItemQuantityBuffer], a
+ jr .loop2
+
+.terminator2
+ dec hl
+ ld a, [wCurItem]
+ ld [hli], a
+ ld a, [wItemQuantityBuffer]
+ ld [hli], a
+ ld [hl], -1
+ ld h, d
+ ld l, e
+ inc [hl]
+
+.done
+ scf
+ ret
+
+RemoveItemFromPocket:
+ ld d, h
+ ld e, l
+ ld a, [hli]
+ ld c, a
+ ld a, [wCurItemQuantity]
+ cp c
+ jr nc, .ok ; memory
+ ld c, a
+ ld b, $0
+ add hl, bc
+ add hl, bc
+ ld a, [wCurItem]
+ cp [hl]
+ inc hl
+ jr z, .skip
+ ld h, d
+ ld l, e
+ inc hl
+
+.ok
+ ld a, [wCurItem]
+ ld b, a
+.loop
+ ld a, [hli]
+ cp b
+ jr z, .skip
+ cp -1
+ jr z, .nope
+ inc hl
+ jr .loop
+
+.skip
+ ld a, [wItemQuantityChangeBuffer]
+ ld b, a
+ ld a, [hl]
+ sub b
+ jr c, .nope
+ ld [hl], a
+ ld [wItemQuantityBuffer], a
+ and a
+ jr nz, .yup
+ dec hl
+ ld b, h
+ ld c, l
+ inc hl
+ inc hl
+.loop2
+ ld a, [hli]
+ ld [bc], a
+ inc bc
+ cp -1
+ jr nz, .loop2
+ ld h, d
+ ld l, e
+ dec [hl]
+
+.yup
+ scf
+ ret
+
+.nope
+ and a
+ ret
+
+CheckTheItem:
+ ld a, [wCurItem]
+ ld c, a
+.loop
+ inc hl
+ ld a, [hli]
+ cp -1
+ jr z, .done
+ cp c
+ jr nz, .loop
+ scf
+ ret
+
+.done
+ and a
+ ret
+
+ReceiveKeyItem:
+ ld hl, wNumKeyItems
+ ld a, [hli]
+ cp MAX_KEY_ITEMS
+ jr nc, .nope
+ ld c, a
+ ld b, 0
+ add hl, bc
+ ld a, [wCurItem]
+ ld [hli], a
+ ld [hl], -1
+ ld hl, wNumKeyItems
+ inc [hl]
+ scf
+ ret
+
+.nope
+ and a
+ ret
+
+TossKeyItem:
+ ld a, [wCurItemQuantity]
+ ld e, a
+ ld d, 0
+ ld hl, wNumKeyItems
+ ld a, [hl]
+ cp e
+ jr nc, .ok
+ call .Toss
+ ret nc
+ jr .ok2
+
+.ok
+ dec [hl]
+ inc hl
+ add hl, de
+
+.ok2
+ ld d, h
+ ld e, l
+ inc hl
+.loop
+ ld a, [hli]
+ ld [de], a
+ inc de
+ cp -1
+ jr nz, .loop
+ scf
+ ret
+
+.Toss:
+ ld hl, wNumKeyItems
+ ld a, [wCurItem]
+ ld c, a
+.loop3
+ inc hl
+ ld a, [hl]
+ cp c
+ jr z, .ok3
+ cp -1
+ jr nz, .loop3
+ xor a
+ ret
+
+.ok3
+ ld a, [wNumKeyItems]
+ dec a
+ ld [wNumKeyItems], a
+ scf
+ ret
+
+CheckKeyItems:
+ ld a, [wCurItem]
+ ld c, a
+ ld hl, wKeyItems
+.loop
+ ld a, [hli]
+ cp c
+ jr z, .done
+ cp -1
+ jr nz, .loop
+ and a
+ ret
+
+.done
+ scf
+ ret
+
+ReceiveTMHM:
+ dec c
+ ld b, 0
+ ld hl, wTMsHMs
+ add hl, bc
+ ld a, [wItemQuantityChangeBuffer]
+ add [hl]
+ cp 100
+ jr nc, .toomany
+ ld [hl], a
+ scf
+ ret
+
+.toomany
+ and a
+ ret
+
+TossTMHM:
+ dec c
+ ld b, 0
+ ld hl, wTMsHMs
+ add hl, bc
+ ld a, [wItemQuantityChangeBuffer]
+ ld b, a
+ ld a, [hl]
+ sub b
+ jr c, .nope
+ ld [hl], a
+ ld [wItemQuantityBuffer], a
+ jr nz, .yup
+ ld a, [wTMHMPocketScrollPosition]
+ and a
+ jr z, .yup
+ dec a
+ ld [wTMHMPocketScrollPosition], a
+
+.yup
+ scf
+ ret
+
+.nope
+ and a
+ ret
+
+CheckTMHM:
+ dec c
+ ld b, $0
+ ld hl, wTMsHMs
+ add hl, bc
+ ld a, [hl]
+ and a
+ ret z
+ scf
+ ret
+
+GetTMHMNumber::
+; Return the number of a TM/HM by item id c.
+ ld a, c
+; Skip any dummy items.
+ cp ITEM_C3 ; TM04-05
+ jr c, .done
+ cp ITEM_DC ; TM28-29
+ jr c, .skip
+ dec a
+.skip
+ dec a
+.done
+ sub TM01
+ inc a
+ ld c, a
+ ret
+
+GetNumberedTMHM:
+; Return the item id of a TM/HM by number c.
+ ld a, c
+; Skip any gaps.
+ cp ITEM_C3 - (TM01 - 1)
+ jr c, .done
+ cp ITEM_DC - (TM01 - 1) - 1
+ jr c, .skip_one
+.skip_two
+ inc a
+.skip_one
+ inc a
+.done
+ add TM01
+ dec a
+ ld c, a
+ ret
+
+_CheckTossableItem::
+; Return 1 in wItemAttributeParamBuffer and carry if wCurItem can't be removed from the bag.
+ ld a, ITEMATTR_PERMISSIONS
+ call GetItemAttr
+ bit CANT_TOSS_F, a
+ jr nz, ItemAttr_ReturnCarry
+ and a
+ ret
+
+CheckSelectableItem:
+; Return 1 in wItemAttributeParamBuffer and carry if wCurItem can't be selected.
+ ld a, ITEMATTR_PERMISSIONS
+ call GetItemAttr
+ bit CANT_SELECT_F, a
+ jr nz, ItemAttr_ReturnCarry
+ and a
+ ret
+
+CheckItemPocket::
+; Return the pocket for wCurItem in wItemAttributeParamBuffer.
+ ld a, ITEMATTR_POCKET
+ call GetItemAttr
+ and $f
+ ld [wItemAttributeParamBuffer], a
+ ret
+
+CheckItemContext:
+; Return the context for wCurItem in wItemAttributeParamBuffer.
+ ld a, ITEMATTR_HELP
+ call GetItemAttr
+ and $f
+ ld [wItemAttributeParamBuffer], a
+ ret
+
+CheckItemMenu:
+; Return the menu for wCurItem in wItemAttributeParamBuffer.
+ ld a, ITEMATTR_HELP
+ call GetItemAttr
+ swap a
+ and $f
+ ld [wItemAttributeParamBuffer], a
+ ret
+
+GetItemAttr:
+; Get attribute a of wCurItem.
+
+ push hl
+ push bc
+
+ ld hl, ItemAttributes
+ ld c, a
+ ld b, 0
+ add hl, bc
+
+ xor a
+ ld [wItemAttributeParamBuffer], a
+
+ ld a, [wCurItem]
+ dec a
+ ld c, a
+ ld a, ITEMATTR_STRUCT_LENGTH
+ call AddNTimes
+ ld a, BANK(ItemAttributes)
+ call GetFarByte
+
+ pop bc
+ pop hl
+ ret
+
+ItemAttr_ReturnCarry:
+ ld a, 1
+ ld [wItemAttributeParamBuffer], a
+ scf
+ ret
+
+GetItemPrice:
+; Return the price of wCurItem in de.
+ push hl
+ push bc
+ ld a, ITEMATTR_PRICE
+ call GetItemAttr
+ ld e, a
+ ld a, ITEMATTR_PRICE_HI
+ call GetItemAttr
+ ld d, a
+ pop bc
+ pop hl
+ ret
diff --git a/engine/items/mart.asm b/engine/items/mart.asm
new file mode 100644
index 000000000..7e185662b
--- /dev/null
+++ b/engine/items/mart.asm
@@ -0,0 +1,895 @@
+ const_def
+ const MARTTEXT_HOW_MANY
+ const MARTTEXT_COSTS_THIS_MUCH
+ const MARTTEXT_NOT_ENOUGH_MONEY
+ const MARTTEXT_BAG_FULL
+ const MARTTEXT_HERE_YOU_GO
+ const MARTTEXT_SOLD_OUT
+
+OpenMartDialog::
+ call GetMart
+ ld a, c
+ ld [wEngineBuffer1], a
+ call LoadMartPointer
+ ld a, [wEngineBuffer1]
+ ld hl, .dialogs
+ rst JumpTable
+ ret
+
+.dialogs
+ dw MartDialog
+ dw HerbShop
+ dw BargainShop
+ dw Pharmacist
+ dw RooftopSale
+
+MartDialog:
+ ld a, 0
+ ld [wEngineBuffer1], a
+ xor a ; STANDARDMART_HOWMAYIHELPYOU
+ ld [wEngineBuffer5], a
+ call StandardMart
+ ret
+
+HerbShop:
+ call FarReadMart
+ call LoadStandardMenuHeader
+ ld hl, Text_HerbShop_Intro
+ call MartTextBox
+ call BuyMenu
+ ld hl, Text_HerbShop_ComeAgain
+ call MartTextBox
+ ret
+
+BargainShop:
+ ld b, BANK(BargainShopData)
+ ld de, BargainShopData
+ call LoadMartPointer
+ call ReadMart
+ call LoadStandardMenuHeader
+ ld hl, Text_BargainShop_Intro
+ call MartTextBox
+ call BuyMenu
+ ld hl, wBargainShopFlags
+ ld a, [hli]
+ or [hl]
+ jr z, .skip_set
+ ld hl, wDailyFlags
+ set DAILYFLAGS_GOLDENROD_UNDERGROUND_BARGAIN_F, [hl]
+
+.skip_set
+ ld hl, Text_BargainShop_ComeAgain
+ call MartTextBox
+ ret
+
+Pharmacist:
+ call FarReadMart
+ call LoadStandardMenuHeader
+ ld hl, Text_Pharmacist_Intro
+ call MartTextBox
+ call BuyMenu
+ ld hl, Text_Pharmacist_ComeAgain
+ call MartTextBox
+ ret
+
+RooftopSale:
+ ld b, BANK(RooftopSaleMart1)
+ ld de, RooftopSaleMart1
+ ld hl, wStatusFlags
+ bit STATUSFLAGS_HALL_OF_FAME_F, [hl]
+ jr z, .ok
+ ld b, BANK(RooftopSaleMart2)
+ ld de, RooftopSaleMart2
+
+.ok
+ call LoadMartPointer
+ call ReadMart
+ call LoadStandardMenuHeader
+ ld hl, Text_Mart_HowMayIHelpYou
+ call MartTextBox
+ call BuyMenu
+ ld hl, Text_Mart_ComeAgain
+ call MartTextBox
+ ret
+
+INCLUDE "data/items/rooftop_sale.asm"
+
+LoadMartPointer:
+ ld a, b
+ ld [wMartPointerBank], a
+ ld a, e
+ ld [wMartPointer], a
+ ld a, d
+ ld [wMartPointer + 1], a
+ ld hl, wCurMart
+ xor a
+ ld bc, wCurMartEnd - wCurMart
+ call ByteFill
+ xor a
+ ld [wEngineBuffer5], a
+ ld [wBargainShopFlags], a
+ ld [wFacingDirection], a
+ ret
+
+GetMart:
+ ld a, e
+ cp (Marts.End - Marts) / 2
+ jr c, .IsAMart
+ ld b, BANK(DefaultMart)
+ ld de, DefaultMart
+ ret
+
+.IsAMart:
+ ld hl, Marts
+ add hl, de
+ add hl, de
+ ld e, [hl]
+ inc hl
+ ld d, [hl]
+ ld b, BANK(Marts)
+ ret
+
+; StandardMart.MartFunctions indexes
+ const_def
+ const STANDARDMART_HOWMAYIHELPYOU ; 0
+ const STANDARDMART_TOPMENU ; 1
+ const STANDARDMART_BUY ; 2
+ const STANDARDMART_SELL ; 3
+ const STANDARDMART_QUIT ; 4
+ const STANDARDMART_ANYTHINGELSE ; 5
+
+StandardMart:
+.loop
+ ld a, [wEngineBuffer5]
+ ld hl, .MartFunctions
+ rst JumpTable
+ ld [wEngineBuffer5], a
+ cp -1
+ jr nz, .loop
+ ret
+
+.MartFunctions:
+; entries correspond to STANDARDMART_* constants
+ dw .HowMayIHelpYou
+ dw .TopMenu
+ dw .Buy
+ dw .Sell
+ dw .Quit
+ dw .AnythingElse
+
+.HowMayIHelpYou:
+ call LoadStandardMenuHeader
+ ld hl, Text_Mart_HowMayIHelpYou
+ call PrintText
+ ld a, STANDARDMART_TOPMENU
+ ret
+
+.TopMenu:
+ ld hl, MenuHeader_BuySell
+ call CopyMenuHeader
+ call VerticalMenu
+ jr c, .quit
+ ld a, [wMenuCursorY]
+ cp $1
+ jr z, .buy
+ cp $2
+ jr z, .sell
+.quit
+ ld a, STANDARDMART_QUIT
+ ret
+.buy
+ ld a, STANDARDMART_BUY
+ ret
+.sell
+ ld a, STANDARDMART_SELL
+ ret
+
+.Buy:
+ call ExitMenu
+ call FarReadMart
+ call BuyMenu
+ and a
+ ld a, STANDARDMART_ANYTHINGELSE
+ ret
+
+.Sell:
+ call ExitMenu
+ call SellMenu
+ ld a, STANDARDMART_ANYTHINGELSE
+ ret
+
+.Quit:
+ call ExitMenu
+ ld hl, Text_Mart_ComeAgain
+ call MartTextBox
+ ld a, -1
+ ret
+
+.AnythingElse:
+ call LoadStandardMenuHeader
+ ld hl, Text_Mart_AnythingElse
+ call PrintText
+ ld a, STANDARDMART_TOPMENU
+ ret
+
+FarReadMart:
+ ld hl, wMartPointer
+ ld a, [hli]
+ ld h, [hl]
+ ld l, a
+ ld de, wCurMart
+.CopyMart:
+ ld a, [wMartPointerBank]
+ call GetFarByte
+ ld [de], a
+ inc hl
+ inc de
+ cp -1
+ jr nz, .CopyMart
+ ld hl, wMartItem1BCD
+ ld de, wCurMart + 1
+.ReadMartItem:
+ ld a, [de]
+ inc de
+ cp -1
+ jr z, .done
+ push de
+ call GetMartItemPrice
+ pop de
+ jr .ReadMartItem
+
+.done
+ ret
+
+GetMartItemPrice:
+; Return the price of item a in BCD at hl and in tiles at wStringBuffer1.
+ push hl
+ ld [wCurItem], a
+ farcall GetItemPrice
+ pop hl
+
+GetMartPrice:
+; Return price de in BCD at hl and in tiles at wStringBuffer1.
+ push hl
+ ld a, d
+ ld [wStringBuffer2], a
+ ld a, e
+ ld [wStringBuffer2 + 1], a
+ ld hl, wStringBuffer1
+ ld de, wStringBuffer2
+ lb bc, PRINTNUM_LEADINGZEROS | 2, 6 ; 6 digits
+ call PrintNum
+ pop hl
+
+ ld de, wStringBuffer1
+ ld c, 6 / 2 ; 6 digits
+.loop
+ call .CharToNybble
+ swap a
+ ld b, a
+ call .CharToNybble
+ or b
+ ld [hli], a
+ dec c
+ jr nz, .loop
+ ret
+
+.CharToNybble:
+ ld a, [de]
+ inc de
+ cp " "
+ jr nz, .not_space
+ ld a, "0"
+
+.not_space
+ sub "0"
+ ret
+
+ReadMart:
+; Load the mart pointer. Mart data is local (no need for bank).
+ ld hl, wMartPointer
+ ld a, [hli]
+ ld h, [hl]
+ ld l, a
+ push hl
+; set hl to the first item
+ inc hl
+ ld bc, wMartItem1BCD
+ ld de, wCurMart + 1
+.loop
+; copy the item to wCurMart + (ItemIndex)
+ ld a, [hli]
+ ld [de], a
+ inc de
+; -1 is the terminator
+ cp -1
+ jr z, .done
+
+ push de
+; copy the price to de
+ ld a, [hli]
+ ld e, a
+ ld a, [hli]
+ ld d, a
+; convert the price to 3-byte BCD at [bc]
+ push hl
+ ld h, b
+ ld l, c
+ call GetMartPrice
+ ld b, h
+ ld c, l
+ pop hl
+
+ pop de
+ jr .loop
+
+.done
+ pop hl
+ ld a, [hl]
+ ld [wCurMart], a
+ ret
+
+INCLUDE "data/items/bargain_shop.asm"
+
+BuyMenu:
+ call FadeToMenu
+ farcall BlankScreen
+ xor a
+ ld [wMenuScrollPositionBackup], a
+ ld a, 1
+ ld [wMenuCursorBufferBackup], a
+.loop
+ call BuyMenuLoop ; menu loop
+ jr nc, .loop
+ call CloseSubmenu
+ ret
+
+LoadBuyMenuText:
+; load text from a nested table
+; which table is in wEngineBuffer1
+; which entry is in register a
+ push af
+ call GetMartDialogGroup ; gets a pointer from GetMartDialogGroup.MartTextFunctionPointers
+ ld a, [hli]
+ ld h, [hl]
+ ld l, a
+ pop af
+ ld e, a
+ ld d, 0
+ add hl, de
+ add hl, de
+ ld a, [hli]
+ ld h, [hl]
+ ld l, a
+ call PrintText
+ ret
+
+MartAskPurchaseQuantity:
+ call GetMartDialogGroup ; gets a pointer from GetMartDialogGroup.MartTextFunctionPointers
+ inc hl
+ inc hl
+ ld a, [hl]
+ and a
+ jp z, StandardMartAskPurchaseQuantity
+ cp 1
+ jp z, BargainShopAskPurchaseQuantity
+ jp RooftopSaleAskPurchaseQuantity
+
+GetMartDialogGroup:
+ ld a, [wEngineBuffer1]
+ ld e, a
+ ld d, 0
+ ld hl, .MartTextFunctionPointers
+ add hl, de
+ add hl, de
+ add hl, de
+ ret
+
+.MartTextFunctionPointers:
+ dwb .StandardMartPointers, 0
+ dwb .HerbShopPointers, 0
+ dwb .BargainShopPointers, 1
+ dwb .PharmacyPointers, 0
+ dwb .StandardMartPointers, 2
+
+.StandardMartPointers:
+ dw Text_Mart_HowMany
+ dw Text_Mart_CostsThisMuch
+ dw Text_Mart_InsufficientFunds
+ dw Text_Mart_BagFull
+ dw Text_Mart_HereYouGo
+ dw BuyMenuLoop
+
+.HerbShopPointers:
+ dw Text_HerbShop_HowMany
+ dw Text_HerbShop_CostsThisMuch
+ dw Text_HerbShop_InsufficientFunds
+ dw Text_HerbShop_BagFull
+ dw Text_HerbShop_HereYouGo
+ dw BuyMenuLoop
+
+.BargainShopPointers:
+ dw BuyMenuLoop
+ dw Text_BargainShop_CostsThisMuch
+ dw Text_BargainShop_InsufficientFunds
+ dw Text_BargainShop_BagFull
+ dw Text_BargainShop_HereYouGo
+ dw Text_BargainShop_SoldOut
+
+.PharmacyPointers:
+ dw Text_Pharmacy_HowMany
+ dw Text_Pharmacy_CostsThisMuch
+ dw Text_Pharmacy_InsufficientFunds
+ dw Text_Pharmacy_BagFull
+ dw Text_Pharmacy_HereYouGo
+ dw BuyMenuLoop
+
+BuyMenuLoop:
+ farcall PlaceMoneyTopRight
+ call UpdateSprites
+ ld hl, MenuHeader_Buy
+ call CopyMenuHeader
+ ld a, [wMenuCursorBufferBackup]
+ ld [wMenuCursorBuffer], a
+ ld a, [wMenuScrollPositionBackup]
+ ld [wMenuScrollPosition], a
+ call ScrollingMenu
+ ld a, [wMenuScrollPosition]
+ ld [wMenuScrollPositionBackup], a
+ ld a, [wMenuCursorY]
+ ld [wMenuCursorBufferBackup], a
+ call SpeechTextBox
+ ld a, [wMenuJoypad]
+ cp B_BUTTON
+ jr z, .set_carry
+ cp A_BUTTON
+ jr z, .useless_pointer
+
+.useless_pointer
+ call MartAskPurchaseQuantity
+ jr c, .cancel
+ call MartConfirmPurchase
+ jr c, .cancel
+ ld de, wMoney
+ ld bc, hMoneyTemp
+ ld a, 3 ; useless load
+ call CompareMoney
+ jr c, .insufficient_funds
+ ld hl, wNumItems
+ call ReceiveItem
+ jr nc, .insufficient_bag_space
+ ld a, [wMartItemID]
+ ld e, a
+ ld d, 0
+ ld b, SET_FLAG
+ ld hl, wBargainShopFlags
+ call FlagAction
+ call PlayTransactionSound
+ ld de, wMoney
+ ld bc, hMoneyTemp
+ call TakeMoney
+ ld a, MARTTEXT_HERE_YOU_GO
+ call LoadBuyMenuText
+ call JoyWaitAorB
+
+.cancel
+ call SpeechTextBox
+ and a
+ ret
+
+.set_carry
+ scf
+ ret
+
+.insufficient_bag_space
+ ld a, MARTTEXT_BAG_FULL
+ call LoadBuyMenuText
+ call JoyWaitAorB
+ and a
+ ret
+
+.insufficient_funds
+ ld a, MARTTEXT_NOT_ENOUGH_MONEY
+ call LoadBuyMenuText
+ call JoyWaitAorB
+ and a
+ ret
+
+StandardMartAskPurchaseQuantity:
+ ld a, 99
+ ld [wItemQuantityBuffer], a
+ ld a, MARTTEXT_HOW_MANY
+ call LoadBuyMenuText
+ farcall SelectQuantityToBuy
+ call ExitMenu
+ ret
+
+MartConfirmPurchase:
+ predef PartyMonItemName
+ ld a, MARTTEXT_COSTS_THIS_MUCH
+ call LoadBuyMenuText
+ call YesNoBox
+ ret
+
+BargainShopAskPurchaseQuantity:
+ ld a, 1
+ ld [wItemQuantityChangeBuffer], a
+ ld a, [wMartItemID]
+ ld e, a
+ ld d, 0
+ ld b, CHECK_FLAG
+ ld hl, wBargainShopFlags
+ call FlagAction
+ ld a, c
+ and a
+ jr nz, .SoldOut
+ ld a, [wMartItemID]
+ ld e, a
+ ld d, 0
+ ld hl, wMartPointer
+ ld a, [hli]
+ ld h, [hl]
+ ld l, a
+ inc hl
+ add hl, de
+ add hl, de
+ add hl, de
+ inc hl
+ ld a, [hli]
+ ld [hMoneyTemp + 2], a
+ ld a, [hl]
+ ld [hMoneyTemp + 1], a
+ xor a
+ ld [hMoneyTemp], a
+ and a
+ ret
+
+.SoldOut:
+ ld a, MARTTEXT_SOLD_OUT
+ call LoadBuyMenuText
+ call JoyWaitAorB
+ scf
+ ret
+
+RooftopSaleAskPurchaseQuantity:
+ ld a, MARTTEXT_HOW_MANY
+ call LoadBuyMenuText
+ call .GetSalePrice
+ ld a, 99
+ ld [wItemQuantityBuffer], a
+ farcall RooftopSale_SelectQuantityToBuy
+ call ExitMenu
+ ret
+
+.GetSalePrice:
+ ld a, [wMartItemID]
+ ld e, a
+ ld d, 0
+ ld hl, wMartPointer
+ ld a, [hli]
+ ld h, [hl]
+ ld l, a
+ inc hl
+ add hl, de
+ add hl, de
+ add hl, de
+ inc hl
+ ld e, [hl]
+ inc hl
+ ld d, [hl]
+ ret
+
+Text_Mart_HowMany:
+ ; How many?
+ text_jump UnknownText_0x1c4bfd
+ db "@"
+
+Text_Mart_CostsThisMuch:
+ ; @ (S) will be ¥@ .
+ text_jump UnknownText_0x1c4c08
+ db "@"
+
+MenuHeader_Buy:
+ db MENU_BACKUP_TILES ; flags
+ menu_coords 1, 3, SCREEN_WIDTH - 1, TEXTBOX_Y - 1
+ dw .MenuData
+ db 1 ; default option
+
+.MenuData
+ db SCROLLINGMENU_DISPLAY_ARROWS | SCROLLINGMENU_ENABLE_FUNCTION3 ; flags
+ db 4, 8 ; rows, columns
+ db 1 ; horizontal spacing
+ dbw 0, wCurMart
+ dba PlaceMenuItemName
+ dba .PrintBCDPrices
+ dba UpdateItemDescription
+
+.PrintBCDPrices:
+ ld a, [wScrollingMenuCursorPosition]
+ ld c, a
+ ld b, 0
+ ld hl, wMartItem1BCD
+ add hl, bc
+ add hl, bc
+ add hl, bc
+ push de
+ ld d, h
+ ld e, l
+ pop hl
+ ld bc, SCREEN_WIDTH
+ add hl, bc
+ ld c, PRINTNUM_LEADINGZEROS | PRINTNUM_MONEY | 3
+ call PrintBCDNumber
+ ret
+
+Text_HerbShop_Intro:
+ ; Hello, dear. I sell inexpensive herbal medicine. They're good, but a trifle bitter. Your #MON may not like them. Hehehehe…
+ text_jump UnknownText_0x1c4c28
+ db "@"
+
+Text_HerbShop_HowMany:
+ ; How many?
+ text_jump UnknownText_0x1c4ca3
+ db "@"
+
+Text_HerbShop_CostsThisMuch:
+ ; @ (S) will be ¥@ .
+ text_jump UnknownText_0x1c4cae
+ db "@"
+
+Text_HerbShop_HereYouGo:
+ ; Thank you, dear. Hehehehe…
+ text_jump UnknownText_0x1c4cce
+ db "@"
+
+Text_HerbShop_BagFull:
+ ; Oh? Your PACK is full, dear.
+ text_jump UnknownText_0x1c4cea
+ db "@"
+
+Text_HerbShop_InsufficientFunds:
+ ; Hehehe… You don't have the money.
+ text_jump UnknownText_0x1c4d08
+ db "@"
+
+Text_HerbShop_ComeAgain:
+ ; Come again, dear. Hehehehe…
+ text_jump UnknownText_0x1c4d2a
+ db "@"
+
+Text_BargainShop_Intro:
+ ; Hiya! Care to see some bargains? I sell rare items that nobody else carries--but only one of each item.
+ text_jump UnknownText_0x1c4d47
+ db "@"
+
+Text_BargainShop_CostsThisMuch:
+ ; costs ¥@ . Want it?
+ text_jump UnknownText_0x1c4db0
+ db "@"
+
+Text_BargainShop_HereYouGo:
+ ; Thanks.
+ text_jump UnknownText_0x1c4dcd
+ db "@"
+
+Text_BargainShop_BagFull:
+ ; Uh-oh, your PACK is chock-full.
+ text_jump UnknownText_0x1c4dd6
+ db "@"
+
+Text_BargainShop_SoldOut:
+ ; You bought that already. I'm all sold out of it.
+ text_jump UnknownText_0x1c4df7
+ db "@"
+
+Text_BargainShop_InsufficientFunds:
+ ; Uh-oh, you're short on funds.
+ text_jump UnknownText_0x1c4e28
+ db "@"
+
+Text_BargainShop_ComeAgain:
+ ; Come by again sometime.
+ text_jump UnknownText_0x1c4e46
+ db "@"
+
+Text_Pharmacist_Intro:
+ ; What's up? Need some medicine?
+ text_jump UnknownText_0x1c4e5f
+ db "@"
+
+Text_Pharmacy_HowMany:
+ ; How many?
+ text_jump UnknownText_0x1c4e7e
+ db "@"
+
+Text_Pharmacy_CostsThisMuch:
+ ; @ (S) will cost ¥@ .
+ text_jump UnknownText_0x1c4e89
+ db "@"
+
+Text_Pharmacy_HereYouGo:
+ ; Thanks much!
+ text_jump UnknownText_0x1c4eab
+ db "@"
+
+Text_Pharmacy_BagFull:
+ ; You don't have any more space.
+ text_jump UnknownText_0x1c4eb9
+ db "@"
+
+Text_Pharmacy_InsufficientFunds:
+ ; Huh? That's not enough money.
+ text_jump UnknownText_0x1c4ed8
+ db "@"
+
+Text_Pharmacist_ComeAgain:
+ ; All right. See you around.
+ text_jump UnknownText_0x1c4ef6
+ db "@"
+
+SellMenu:
+ call DisableSpriteUpdates
+ farcall DepositSellInitPackBuffers
+.loop
+ farcall DepositSellPack
+ ld a, [wPackUsedItem]
+ and a
+ jp z, .quit
+ call .TryToSellItem
+ jr .loop
+
+.quit
+ call ReturnToMapWithSpeechTextbox
+ and a
+ ret
+
+.Unreferenced_NothingToSell:
+ ld hl, .NothingToSellText
+ call MenuTextBoxBackup
+ and a
+ ret
+
+.NothingToSellText:
+ ; You don't have anything to sell.
+ text_jump UnknownText_0x1c4f12
+ db "@"
+
+.TryToSellItem:
+ farcall CheckItemMenu
+ ld a, [wItemAttributeParamBuffer]
+ ld hl, .dw
+ rst JumpTable
+ ret
+
+.dw
+ dw .try_sell
+ dw .cant_buy
+ dw .cant_buy
+ dw .cant_buy
+ dw .try_sell
+ dw .try_sell
+ dw .try_sell
+
+.cant_buy
+ ret
+
+.try_sell
+ farcall _CheckTossableItem
+ ld a, [wItemAttributeParamBuffer]
+ and a
+ jr z, .okay_to_sell
+ ld hl, TextMart_CantBuyFromYou
+ call PrintText
+ and a
+ ret
+
+.okay_to_sell
+ ld hl, Text_Mart_SellHowMany
+ call PrintText
+ farcall PlaceMoneyAtTopLeftOfTextbox
+ farcall SelectQuantityToSell
+ call ExitMenu
+ jr c, .declined
+ hlcoord 1, 14
+ lb bc, 3, 18
+ call ClearBox
+ ld hl, Text_Mart_ICanPayThisMuch
+ call PrintTextBoxText
+ call YesNoBox
+ jr c, .declined
+ ld de, wMoney
+ ld bc, hMoneyTemp
+ call GiveMoney
+ ld a, [wMartItemID]
+ ld hl, wNumItems
+ call TossItem
+ predef PartyMonItemName
+ hlcoord 1, 14
+ lb bc, 3, 18
+ call ClearBox
+ ld hl, Text_Mart_SoldForAmount
+ call PrintTextBoxText
+ call PlayTransactionSound
+ farcall PlaceMoneyBottomLeft
+ call JoyWaitAorB
+
+.declined
+ call ExitMenu
+ and a
+ ret
+
+Text_Mart_SellHowMany:
+ ; How many?
+ text_jump UnknownText_0x1c4f33
+ db "@"
+
+Text_Mart_ICanPayThisMuch:
+ ; I can pay you ¥@ . Is that OK?
+ text_jump UnknownText_0x1c4f3e
+ db "@"
+
+.UnusedString15f7d:
+ db "!ダミー!@"
+
+Text_Mart_HowMayIHelpYou:
+ ; Welcome! How may I help you?
+ text_jump UnknownText_0x1c4f62
+ db "@"
+
+MenuHeader_BuySell:
+ db MENU_BACKUP_TILES ; flags
+ menu_coords 0, 0, 7, 8
+ dw .MenuData
+ db 1 ; default option
+
+.MenuData
+ db STATICMENU_CURSOR ; strings
+ db 3 ; items
+ db "BUY@"
+ db "SELL@"
+ db "QUIT@"
+
+Text_Mart_HereYouGo:
+ ; Here you are. Thank you!
+ text_jump UnknownText_0x1c4f80
+ db "@"
+
+Text_Mart_InsufficientFunds:
+ ; You don't have enough money.
+ text_jump UnknownText_0x1c4f9a
+ db "@"
+
+Text_Mart_BagFull:
+ ; You can't carry any more items.
+ text_jump UnknownText_0x1c4fb7
+ db "@"
+
+TextMart_CantBuyFromYou:
+ ; Sorry, I can't buy that from you.
+ text_jump UnknownText_0x1c4fd7
+ db "@"
+
+Text_Mart_ComeAgain:
+ ; Please come again!
+ text_jump UnknownText_0x1c4ff9
+ db "@"
+
+Text_Mart_AnythingElse:
+ text_jump UnknownText_0x1c500d
+ db "@"
+
+Text_Mart_SoldForAmount:
+ text_jump UnknownText_0x1c502e
+ db "@"
+
+PlayTransactionSound:
+ call WaitSFX
+ ld de, SFX_TRANSACTION
+ call PlaySFX
+ ret
+
+MartTextBox:
+ call MenuTextBox
+ call JoyWaitAorB
+ call ExitMenu
+ ret
diff --git a/engine/items/pack.asm b/engine/items/pack.asm
new file mode 100644
index 000000000..67e9fe900
--- /dev/null
+++ b/engine/items/pack.asm
@@ -0,0 +1,1608 @@
+; Pack.Jumptable and BattlePack.Jumptable indexes
+ const_def
+ const PACKSTATE_INITGFX ; 0
+ const PACKSTATE_INITITEMSPOCKET ; 1
+ const PACKSTATE_ITEMSPOCKETMENU ; 2
+ const PACKSTATE_INITBALLSPOCKET ; 3
+ const PACKSTATE_BALLSPOCKETMENU ; 4
+ const PACKSTATE_INITKEYITEMSPOCKET ; 5
+ const PACKSTATE_KEYITEMSPOCKETMENU ; 6
+ const PACKSTATE_INITTMHMPOCKET ; 7
+ const PACKSTATE_TMHMPOCKETMENU ; 8
+ const PACKSTATE_QUITNOSCRIPT ; 9
+ const PACKSTATE_QUITRUNSCRIPT ; 10
+
+Pack:
+ ld hl, wOptions
+ set NO_TEXT_SCROLL, [hl]
+ call InitPackBuffers
+.loop
+ call JoyTextDelay
+ ld a, [wJumptableIndex]
+ bit 7, a
+ jr nz, .done
+ call .RunJumptable
+ call DelayFrame
+ jr .loop
+
+.done
+ ld a, [wCurrPocket]
+ ld [wLastPocket], a
+ ld hl, wOptions
+ res NO_TEXT_SCROLL, [hl]
+ ret
+
+.RunJumptable:
+ ld a, [wJumptableIndex]
+ ld hl, .Jumptable
+ call Pack_GetJumptablePointer
+ jp hl
+
+.Jumptable:
+; entries correspond to PACKSTATE_* constants
+ dw .InitGFX ; 0
+ dw .InitItemsPocket ; 1
+ dw .ItemsPocketMenu ; 2
+ dw .InitBallsPocket ; 3
+ dw .BallsPocketMenu ; 4
+ dw .InitKeyItemsPocket ; 5
+ dw .KeyItemsPocketMenu ; 6
+ dw .InitTMHMPocket ; 7
+ dw .TMHMPocketMenu ; 8
+ dw Pack_QuitNoScript ; 9
+ dw Pack_QuitRunScript ; 10
+
+.InitGFX:
+ xor a
+ ld [hBGMapMode], a
+ call Pack_InitGFX
+ ld a, [wPackJumptableIndex]
+ ld [wJumptableIndex], a
+ call Pack_InitColors
+ ret
+
+.InitItemsPocket:
+ xor a ; ITEM_POCKET
+ ld [wCurrPocket], a
+ call ClearPocketList
+ call DrawPocketName
+ call WaitBGMap_DrawPackGFX
+ call Pack_JumptableNext
+ ret
+
+.ItemsPocketMenu:
+ ld hl, ItemsPocketMenuHeader
+ call CopyMenuHeader
+ ld a, [wItemsPocketCursor]
+ ld [wMenuCursorBuffer], a
+ ld a, [wItemsPocketScrollPosition]
+ ld [wMenuScrollPosition], a
+ call ScrollingMenu
+ ld a, [wMenuScrollPosition]
+ ld [wItemsPocketScrollPosition], a
+ ld a, [wMenuCursorY]
+ ld [wItemsPocketCursor], a
+ ld b, PACKSTATE_INITTMHMPOCKET ; left
+ ld c, PACKSTATE_INITBALLSPOCKET ; right
+ call Pack_InterpretJoypad
+ ret c
+ call .ItemBallsKey_LoadSubmenu
+ ret
+
+.InitKeyItemsPocket:
+ ld a, KEY_ITEM_POCKET
+ ld [wCurrPocket], a
+ call ClearPocketList
+ call DrawPocketName
+ call WaitBGMap_DrawPackGFX
+ call Pack_JumptableNext
+ ret
+
+.KeyItemsPocketMenu:
+ ld hl, KeyItemsPocketMenuHeader
+ call CopyMenuHeader
+ ld a, [wKeyItemsPocketCursor]
+ ld [wMenuCursorBuffer], a
+ ld a, [wKeyItemsPocketScrollPosition]
+ ld [wMenuScrollPosition], a
+ call ScrollingMenu
+ ld a, [wMenuScrollPosition]
+ ld [wKeyItemsPocketScrollPosition], a
+ ld a, [wMenuCursorY]
+ ld [wKeyItemsPocketCursor], a
+ ld b, PACKSTATE_INITBALLSPOCKET ; left
+ ld c, PACKSTATE_INITTMHMPOCKET ; right
+ call Pack_InterpretJoypad
+ ret c
+ call .ItemBallsKey_LoadSubmenu
+ ret
+
+.InitTMHMPocket:
+ ld a, TM_HM_POCKET
+ ld [wCurrPocket], a
+ call ClearPocketList
+ call DrawPocketName
+ xor a
+ ld [hBGMapMode], a
+ call WaitBGMap_DrawPackGFX
+ call Pack_JumptableNext
+ ret
+
+.TMHMPocketMenu:
+ farcall TMHMPocket
+ ld b, PACKSTATE_INITKEYITEMSPOCKET ; left
+ ld c, PACKSTATE_INITITEMSPOCKET ; right
+ call Pack_InterpretJoypad
+ ret c
+ farcall _CheckTossableItem
+ ld a, [wItemAttributeParamBuffer]
+ and a
+ jr nz, .use_quit
+ ld hl, .MenuHeader2
+ ld de, .Jumptable2
+ jr .load_jump
+
+.use_quit
+ ld hl, .MenuHeader1
+ ld de, .Jumptable1
+.load_jump
+ push de
+ call LoadMenuHeader
+ call VerticalMenu
+ call ExitMenu
+ pop hl
+ ret c
+ ld a, [wMenuCursorY]
+ dec a
+ call Pack_GetJumptablePointer
+ jp hl
+
+.MenuHeader1:
+ db MENU_BACKUP_TILES ; flags
+ menu_coords 13, 7, SCREEN_WIDTH - 1, TEXTBOX_Y - 1
+ dw .MenuData_1
+ db 1 ; default option
+
+.MenuData_1:
+ db STATICMENU_CURSOR | STATICMENU_NO_TOP_SPACING ; flags
+ db 2 ; items
+ db "USE@"
+ db "QUIT@"
+
+.Jumptable1:
+ dw .UseItem
+ dw QuitItemSubmenu
+
+.MenuHeader2:
+ db MENU_BACKUP_TILES ; flags
+ menu_coords 13, 5, SCREEN_WIDTH - 1, TEXTBOX_Y - 1
+ dw .MenuData_2
+ db 1 ; default option
+
+.MenuData_2:
+ db STATICMENU_CURSOR | STATICMENU_NO_TOP_SPACING ; flags
+ db 3 ; items
+ db "USE@"
+ db "GIVE@"
+ db "QUIT@"
+
+.Jumptable2:
+ dw .UseItem
+ dw GiveItem
+ dw QuitItemSubmenu
+
+.UseItem:
+ farcall AskTeachTMHM
+ ret c
+ farcall ChooseMonToLearnTMHM
+ jr c, .declined
+ ld hl, wOptions
+ ld a, [hl]
+ push af
+ res NO_TEXT_SCROLL, [hl]
+ farcall TeachTMHM
+ pop af
+ ld [wOptions], a
+.declined
+ xor a
+ ld [hBGMapMode], a
+ call Pack_InitGFX
+ call WaitBGMap_DrawPackGFX
+ call Pack_InitColors
+ ret
+
+.InitBallsPocket:
+ ld a, BALL_POCKET
+ ld [wCurrPocket], a
+ call ClearPocketList
+ call DrawPocketName
+ call WaitBGMap_DrawPackGFX
+ call Pack_JumptableNext
+ ret
+
+.BallsPocketMenu:
+ ld hl, BallsPocketMenuHeader
+ call CopyMenuHeader
+ ld a, [wBallsPocketCursor]
+ ld [wMenuCursorBuffer], a
+ ld a, [wBallsPocketScrollPosition]
+ ld [wMenuScrollPosition], a
+ call ScrollingMenu
+ ld a, [wMenuScrollPosition]
+ ld [wBallsPocketScrollPosition], a
+ ld a, [wMenuCursorY]
+ ld [wBallsPocketCursor], a
+ ld b, PACKSTATE_INITITEMSPOCKET ; left
+ ld c, PACKSTATE_INITKEYITEMSPOCKET ; right
+ call Pack_InterpretJoypad
+ ret c
+ call .ItemBallsKey_LoadSubmenu
+ ret
+
+.ItemBallsKey_LoadSubmenu:
+ farcall _CheckTossableItem
+ ld a, [wItemAttributeParamBuffer]
+ and a
+ jr nz, .tossable
+ farcall CheckSelectableItem
+ ld a, [wItemAttributeParamBuffer]
+ and a
+ jr nz, .selectable
+ farcall CheckItemMenu
+ ld a, [wItemAttributeParamBuffer]
+ and a
+ jr nz, .usable
+ jr .unusable
+
+.selectable
+ farcall CheckItemMenu
+ ld a, [wItemAttributeParamBuffer]
+ and a
+ jr nz, .selectable_usable
+ jr .selectable_unusable
+
+.tossable
+ farcall CheckSelectableItem
+ ld a, [wItemAttributeParamBuffer]
+ and a
+ jr nz, .tossable_selectable
+ jr .tossable_unselectable
+
+.usable
+ ld hl, MenuHeader_UsableKeyItem
+ ld de, Jumptable_UseGiveTossRegisterQuit
+ jr .build_menu
+
+.selectable_usable
+ ld hl, MenuHeader_UsableItem
+ ld de, Jumptable_UseGiveTossQuit
+ jr .build_menu
+
+.tossable_selectable
+ ld hl, MenuHeader_UnusableItem
+ ld de, Jumptable_UseQuit
+ jr .build_menu
+
+.tossable_unselectable
+ ld hl, MenuHeader_UnusableKeyItem
+ ld de, Jumptable_UseRegisterQuit
+ jr .build_menu
+
+.unusable
+ ld hl, MenuHeader_HoldableKeyItem
+ ld de, Jumptable_GiveTossRegisterQuit
+ jr .build_menu
+
+.selectable_unusable
+ ld hl, MenuHeader_HoldableItem
+ ld de, Jumptable_GiveTossQuit
+.build_menu
+ push de
+ call LoadMenuHeader
+ call VerticalMenu
+ call ExitMenu
+ pop hl
+ ret c
+ ld a, [wMenuCursorY]
+ dec a
+ call Pack_GetJumptablePointer
+ jp hl
+
+MenuHeader_UsableKeyItem:
+ db MENU_BACKUP_TILES ; flags
+ menu_coords 13, 1, SCREEN_WIDTH - 1, TEXTBOX_Y - 1
+ dw .MenuData
+ db 1 ; default option
+
+.MenuData:
+ db STATICMENU_CURSOR | STATICMENU_NO_TOP_SPACING ; flags
+ db 5 ; items
+ db "USE@"
+ db "GIVE@"
+ db "TOSS@"
+ db "SEL@"
+ db "QUIT@"
+
+Jumptable_UseGiveTossRegisterQuit:
+ dw UseItem
+ dw GiveItem
+ dw TossMenu
+ dw RegisterItem
+ dw QuitItemSubmenu
+
+MenuHeader_UsableItem:
+ db MENU_BACKUP_TILES ; flags
+ menu_coords 13, 3, SCREEN_WIDTH - 1, TEXTBOX_Y - 1
+ dw .MenuData
+ db 1 ; default option
+
+.MenuData:
+ db STATICMENU_CURSOR | STATICMENU_NO_TOP_SPACING ; flags
+ db 4 ; items
+ db "USE@"
+ db "GIVE@"
+ db "TOSS@"
+ db "QUIT@"
+
+Jumptable_UseGiveTossQuit:
+ dw UseItem
+ dw GiveItem
+ dw TossMenu
+ dw QuitItemSubmenu
+
+MenuHeader_UnusableItem:
+ db MENU_BACKUP_TILES ; flags
+ menu_coords 13, 7, SCREEN_WIDTH - 1, TEXTBOX_Y - 1
+ dw .MenuData
+ db 1 ; default option
+
+.MenuData:
+ db STATICMENU_CURSOR | STATICMENU_NO_TOP_SPACING ; flags
+ db 2 ; items
+ db "USE@"
+ db "QUIT@"
+
+Jumptable_UseQuit:
+ dw UseItem
+ dw QuitItemSubmenu
+
+MenuHeader_UnusableKeyItem:
+ db MENU_BACKUP_TILES ; flags
+ menu_coords 13, 5, SCREEN_WIDTH - 1, TEXTBOX_Y - 1
+ dw .MenuData
+ db 1 ; default option
+
+.MenuData:
+ db STATICMENU_CURSOR | STATICMENU_NO_TOP_SPACING ; flags
+ db 3 ; items
+ db "USE@"
+ db "SEL@"
+ db "QUIT@"
+
+Jumptable_UseRegisterQuit:
+ dw UseItem
+ dw RegisterItem
+ dw QuitItemSubmenu
+
+MenuHeader_HoldableKeyItem:
+ db MENU_BACKUP_TILES ; flags
+ menu_coords 13, 3, SCREEN_WIDTH - 1, TEXTBOX_Y - 1
+ dw .MenuData
+ db 1 ; default option
+
+.MenuData:
+ db STATICMENU_CURSOR | STATICMENU_NO_TOP_SPACING ; flags
+ db 4 ; items
+ db "GIVE@"
+ db "TOSS@"
+ db "SEL@"
+ db "QUIT@"
+
+Jumptable_GiveTossRegisterQuit:
+ dw GiveItem
+ dw TossMenu
+ dw RegisterItem
+ dw QuitItemSubmenu
+
+MenuHeader_HoldableItem:
+ db MENU_BACKUP_TILES ; flags
+ menu_coords 13, 5, SCREEN_WIDTH - 1, TEXTBOX_Y - 1
+ dw .MenuData
+ db 1 ; default option
+
+.MenuData:
+ db STATICMENU_CURSOR | STATICMENU_NO_TOP_SPACING ; flags
+ db 3 ; items
+ db "GIVE@"
+ db "TOSS@"
+ db "QUIT@"
+
+Jumptable_GiveTossQuit:
+ dw GiveItem
+ dw TossMenu
+ dw QuitItemSubmenu
+
+UseItem:
+ farcall CheckItemMenu
+ ld a, [wItemAttributeParamBuffer]
+ ld hl, .dw
+ rst JumpTable
+ ret
+
+.dw
+; entries correspond to ITEMMENU_* constants
+ dw .Oak ; ITEMMENU_NOUSE
+ dw .Oak
+ dw .Oak
+ dw .Oak
+ dw .Current ; ITEMMENU_CURRENT
+ dw .Party ; ITEMMENU_PARTY
+ dw .Field ; ITEMMENU_CLOSE
+
+.Oak:
+ ld hl, Text_ThisIsntTheTime
+ call Pack_PrintTextNoScroll
+ ret
+
+.Current:
+ call DoItemEffect
+ ret
+
+.Party:
+ ld a, [wPartyCount]
+ and a
+ jr z, .NoPokemon
+ call DoItemEffect
+ xor a
+ ld [hBGMapMode], a
+ call Pack_InitGFX
+ call WaitBGMap_DrawPackGFX
+ call Pack_InitColors
+ ret
+
+.NoPokemon:
+ ld hl, TextJump_YouDontHaveAMon
+ call Pack_PrintTextNoScroll
+ ret
+
+.Field:
+ call DoItemEffect
+ ld a, [wItemEffectSucceeded]
+ and a
+ jr z, .Oak
+ ld a, PACKSTATE_QUITRUNSCRIPT
+ ld [wJumptableIndex], a
+ ret
+
+TossMenu:
+ ld hl, Text_ThrowAwayHowMany
+ call Pack_PrintTextNoScroll
+ farcall SelectQuantityToToss
+ push af
+ call ExitMenu
+ pop af
+ jr c, .finish
+ call Pack_GetItemName
+ ld hl, Text_ConfirmThrowAway
+ call MenuTextBox
+ call YesNoBox
+ push af
+ call ExitMenu
+ pop af
+ jr c, .finish
+ ld hl, wNumItems
+ ld a, [wCurItemQuantity]
+ call TossItem
+ call Pack_GetItemName
+ ld hl, Text_ThrewAway
+ call Pack_PrintTextNoScroll
+.finish
+ ret
+
+Unreferenced_ResetPocketCursorPositions:
+ ld a, [wCurrPocket]
+ and a ; ITEM_POCKET
+ jr z, .items
+ dec a ; BALL_POCKET
+ jr z, .balls
+ dec a ; KEY_ITEM_POCKET
+ jr z, .key
+ ret
+
+.balls
+ xor a
+ ld [wBallsPocketCursor], a
+ ld [wBallsPocketScrollPosition], a
+ ret
+
+.items
+ xor a
+ ld [wItemsPocketCursor], a
+ ld [wItemsPocketScrollPosition], a
+ ret
+
+.key
+ xor a
+ ld [wKeyItemsPocketCursor], a
+ ld [wKeyItemsPocketScrollPosition], a
+ ret
+
+RegisterItem:
+ farcall CheckSelectableItem
+ ld a, [wItemAttributeParamBuffer]
+ and a
+ jr nz, .cant_register
+ ld a, [wCurrPocket]
+ rrca
+ rrca
+ and REGISTERED_POCKET
+ ld b, a
+ ld a, [wCurItemQuantity]
+ inc a
+ and REGISTERED_NUMBER
+ or b
+ ld [wWhichRegisteredItem], a
+ ld a, [wCurItem]
+ ld [wRegisteredItem], a
+ call Pack_GetItemName
+ ld de, SFX_FULL_HEAL
+ call WaitPlaySFX
+ ld hl, Text_RegisteredItem
+ call Pack_PrintTextNoScroll
+ ret
+
+.cant_register
+ ld hl, Text_CantRegister
+ call Pack_PrintTextNoScroll
+ ret
+
+GiveItem:
+ ld a, [wPartyCount]
+ and a
+ jp z, .NoPokemon
+ ld a, [wOptions]
+ push af
+ res NO_TEXT_SCROLL, a
+ ld [wOptions], a
+ ld a, PARTYMENUACTION_GIVE_ITEM
+ ld [wPartyMenuActionText], a
+ call ClearBGPalettes
+ farcall LoadPartyMenuGFX
+ farcall InitPartyMenuWithCancel
+ farcall InitPartyMenuGFX
+.loop
+ farcall WritePartyMenuTilemap
+ farcall PrintPartyMenuText
+ call WaitBGMap
+ call SetPalettes
+ call DelayFrame
+ farcall PartyMenuSelect
+ jr c, .finish
+ ld a, [wCurPartySpecies]
+ cp EGG
+ jr nz, .give
+ ld hl, .Egg
+ call PrintText
+ jr .loop
+
+.give
+ ld a, [wJumptableIndex]
+ push af
+ ld a, [wPackJumptableIndex]
+ push af
+ call GetCurNick
+ ld hl, wStringBuffer1
+ ld de, wMonOrItemNameBuffer
+ ld bc, MON_NAME_LENGTH
+ call CopyBytes
+ call TryGiveItemToPartymon
+ pop af
+ ld [wPackJumptableIndex], a
+ pop af
+ ld [wJumptableIndex], a
+.finish
+ pop af
+ ld [wOptions], a
+ xor a
+ ld [hBGMapMode], a
+ call Pack_InitGFX
+ call WaitBGMap_DrawPackGFX
+ call Pack_InitColors
+ ret
+
+.NoPokemon:
+ ld hl, TextJump_YouDontHaveAMon
+ call Pack_PrintTextNoScroll
+ ret
+.Egg:
+ ; An EGG can't hold an item.
+ text_jump Text_AnEGGCantHoldAnItem
+ db "@"
+
+QuitItemSubmenu:
+ ret
+
+BattlePack:
+ ld hl, wOptions
+ set NO_TEXT_SCROLL, [hl]
+ call InitPackBuffers
+.loop
+ call JoyTextDelay
+ ld a, [wJumptableIndex]
+ bit 7, a
+ jr nz, .end
+ call .RunJumptable
+ call DelayFrame
+ jr .loop
+
+.end
+ ld a, [wCurrPocket]
+ ld [wLastPocket], a
+ ld hl, wOptions
+ res NO_TEXT_SCROLL, [hl]
+ ret
+
+.RunJumptable:
+ ld a, [wJumptableIndex]
+ ld hl, .Jumptable
+ call Pack_GetJumptablePointer
+ jp hl
+
+.Jumptable:
+; entries correspond to PACKSTATE_* constants
+ dw .InitGFX ; 0
+ dw .InitItemsPocket ; 1
+ dw .ItemsPocketMenu ; 2
+ dw .InitBallsPocket ; 3
+ dw .BallsPocketMenu ; 4
+ dw .InitKeyItemsPocket ; 5
+ dw .KeyItemsPocketMenu ; 6
+ dw .InitTMHMPocket ; 7
+ dw .TMHMPocketMenu ; 8
+ dw Pack_QuitNoScript ; 9
+ dw Pack_QuitRunScript ; 10
+
+.InitGFX:
+ xor a
+ ld [hBGMapMode], a
+ call Pack_InitGFX
+ ld a, [wPackJumptableIndex]
+ ld [wJumptableIndex], a
+ call Pack_InitColors
+ ret
+
+.InitItemsPocket:
+ xor a ; ITEM_POCKET
+ ld [wCurrPocket], a
+ call ClearPocketList
+ call DrawPocketName
+ call WaitBGMap_DrawPackGFX
+ call Pack_JumptableNext
+ ret
+
+.ItemsPocketMenu:
+ ld hl, ItemsPocketMenuHeader
+ call CopyMenuHeader
+ ld a, [wItemsPocketCursor]
+ ld [wMenuCursorBuffer], a
+ ld a, [wItemsPocketScrollPosition]
+ ld [wMenuScrollPosition], a
+ call ScrollingMenu
+ ld a, [wMenuScrollPosition]
+ ld [wItemsPocketScrollPosition], a
+ ld a, [wMenuCursorY]
+ ld [wItemsPocketCursor], a
+ ld b, PACKSTATE_INITTMHMPOCKET ; left
+ ld c, PACKSTATE_INITBALLSPOCKET ; right
+ call Pack_InterpretJoypad
+ ret c
+ call ItemSubmenu
+ ret
+
+.InitKeyItemsPocket:
+ ld a, KEY_ITEM_POCKET
+ ld [wCurrPocket], a
+ call ClearPocketList
+ call DrawPocketName
+ call WaitBGMap_DrawPackGFX
+ call Pack_JumptableNext
+ ret
+
+.KeyItemsPocketMenu:
+ ld hl, KeyItemsPocketMenuHeader
+ call CopyMenuHeader
+ ld a, [wKeyItemsPocketCursor]
+ ld [wMenuCursorBuffer], a
+ ld a, [wKeyItemsPocketScrollPosition]
+ ld [wMenuScrollPosition], a
+ call ScrollingMenu
+ ld a, [wMenuScrollPosition]
+ ld [wKeyItemsPocketScrollPosition], a
+ ld a, [wMenuCursorY]
+ ld [wKeyItemsPocketCursor], a
+ ld b, PACKSTATE_INITBALLSPOCKET ; left
+ ld c, PACKSTATE_INITTMHMPOCKET ; right
+ call Pack_InterpretJoypad
+ ret c
+ call ItemSubmenu
+ ret
+
+.InitTMHMPocket:
+ ld a, TM_HM_POCKET
+ ld [wCurrPocket], a
+ call ClearPocketList
+ call DrawPocketName
+ xor a
+ ld [hBGMapMode], a
+ call WaitBGMap_DrawPackGFX
+ ld hl, Text_PackEmptyString
+ call Pack_PrintTextNoScroll
+ call Pack_JumptableNext
+ ret
+
+.TMHMPocketMenu:
+ farcall TMHMPocket
+ ld b, PACKSTATE_INITKEYITEMSPOCKET ; left
+ ld c, PACKSTATE_INITITEMSPOCKET ; right
+ call Pack_InterpretJoypad
+ ret c
+ xor a
+ call TMHMSubmenu
+ ret
+
+.InitBallsPocket:
+ ld a, BALL_POCKET
+ ld [wCurrPocket], a
+ call ClearPocketList
+ call DrawPocketName
+ call WaitBGMap_DrawPackGFX
+ call Pack_JumptableNext
+ ret
+
+.BallsPocketMenu:
+ ld hl, BallsPocketMenuHeader
+ call CopyMenuHeader
+ ld a, [wBallsPocketCursor]
+ ld [wMenuCursorBuffer], a
+ ld a, [wBallsPocketScrollPosition]
+ ld [wMenuScrollPosition], a
+ call ScrollingMenu
+ ld a, [wMenuScrollPosition]
+ ld [wBallsPocketScrollPosition], a
+ ld a, [wMenuCursorY]
+ ld [wBallsPocketCursor], a
+ ld b, PACKSTATE_INITITEMSPOCKET ; left
+ ld c, PACKSTATE_INITKEYITEMSPOCKET ; right
+ call Pack_InterpretJoypad
+ ret c
+ call ItemSubmenu
+ ret
+
+ItemSubmenu:
+ farcall CheckItemContext
+ ld a, [wItemAttributeParamBuffer]
+TMHMSubmenu:
+ and a
+ jr z, .NoUse
+ ld hl, .UsableMenuHeader
+ ld de, .UsableJumptable
+ jr .proceed
+
+.NoUse:
+ ld hl, .UnusableMenuHeader
+ ld de, .UnusableJumptable
+.proceed
+ push de
+ call LoadMenuHeader
+ call VerticalMenu
+ call ExitMenu
+ pop hl
+ ret c
+ ld a, [wMenuCursorY]
+ dec a
+ call Pack_GetJumptablePointer
+ jp hl
+
+.UsableMenuHeader:
+ db MENU_BACKUP_TILES ; flags
+ menu_coords 13, 7, SCREEN_WIDTH - 1, TEXTBOX_Y - 1
+ dw .UsableMenuData
+ db 1 ; default option
+
+.UsableMenuData:
+ db STATICMENU_CURSOR | STATICMENU_NO_TOP_SPACING ; flags
+ db 2 ; items
+ db "USE@"
+ db "QUIT@"
+
+.UsableJumptable:
+ dw .Use
+ dw .Quit
+
+.UnusableMenuHeader:
+ db MENU_BACKUP_TILES ; flags
+ menu_coords 13, 9, SCREEN_WIDTH - 1, TEXTBOX_Y - 1
+ dw .UnusableMenuData
+ db 1 ; default option
+
+.UnusableMenuData:
+ db STATICMENU_CURSOR | STATICMENU_NO_TOP_SPACING ; flags
+ db 1 ; items
+ db "QUIT@"
+
+.UnusableJumptable:
+ dw .Quit
+
+.Use:
+ farcall CheckItemContext
+ ld a, [wItemAttributeParamBuffer]
+ ld hl, .ItemFunctionJumptable
+ rst JumpTable
+ ret
+
+.ItemFunctionJumptable:
+; entries correspond to ITEMMENU_* constants
+ dw .Oak ; ITEMMENU_NOUSE
+ dw .Oak
+ dw .Oak
+ dw .Oak
+ dw .Unused ; ITEMMENU_CURRENT
+ dw .BattleField ; ITEMMENU_PARTY
+ dw .BattleOnly ; ITEMMENU_CLOSE
+
+.Oak:
+ ld hl, Text_ThisIsntTheTime
+ call Pack_PrintTextNoScroll
+ ret
+
+.Unused:
+ call DoItemEffect
+ ld a, [wItemEffectSucceeded]
+ and a
+ jr nz, .ReturnToBattle
+ ret
+
+.BattleField:
+ call DoItemEffect
+ ld a, [wItemEffectSucceeded]
+ and a
+ jr nz, .quit_run_script
+ xor a
+ ld [hBGMapMode], a
+ call Pack_InitGFX
+ call WaitBGMap_DrawPackGFX
+ call Pack_InitColors
+ ret
+
+.ReturnToBattle:
+ call ClearBGPalettes
+ jr .quit_run_script
+
+.BattleOnly:
+ call DoItemEffect
+ ld a, [wItemEffectSucceeded]
+ and a
+ jr z, .Oak
+ cp $2
+ jr z, .didnt_use_item
+.quit_run_script
+ ld a, PACKSTATE_QUITRUNSCRIPT
+ ld [wJumptableIndex], a
+ ret
+
+.didnt_use_item
+ xor a
+ ld [wItemEffectSucceeded], a
+ ret
+.Quit:
+ ret
+
+InitPackBuffers:
+ xor a
+ ld [wJumptableIndex], a
+ ; pocket id -> jumptable index
+ ld a, [wLastPocket]
+ maskbits NUM_POCKETS
+ ld [wCurrPocket], a
+ inc a
+ add a
+ dec a
+ ld [wPackJumptableIndex], a
+ xor a ; FALSE
+ ld [wPackUsedItem], a
+ xor a
+ ld [wSwitchItem], a
+ ret
+
+DepositSellInitPackBuffers:
+ xor a
+ ld [hBGMapMode], a
+ ld [wJumptableIndex], a ; PACKSTATE_INITGFX
+ ld [wPackJumptableIndex], a ; PACKSTATE_INITGFX
+ ld [wCurrPocket], a ; ITEM_POCKET
+ ld [wPackUsedItem], a
+ ld [wSwitchItem], a
+ call Pack_InitGFX
+ call Pack_InitColors
+ ret
+
+DepositSellPack:
+.loop
+ call .RunJumptable
+ call DepositSellTutorial_InterpretJoypad
+ jr c, .loop
+ ret
+
+.RunJumptable:
+ ld a, [wJumptableIndex]
+ ld hl, .Jumptable
+ call Pack_GetJumptablePointer
+ jp hl
+
+.Jumptable:
+; entries correspond to *_POCKET constants
+ dw .ItemsPocket
+ dw .BallsPocket
+ dw .KeyItemsPocket
+ dw .TMHMPocket
+
+.ItemsPocket:
+ xor a ; ITEM_POCKET
+ call InitPocket
+ ld hl, PC_Mart_ItemsPocketMenuHeader
+ call CopyMenuHeader
+ ld a, [wItemsPocketCursor]
+ ld [wMenuCursorBuffer], a
+ ld a, [wItemsPocketScrollPosition]
+ ld [wMenuScrollPosition], a
+ call ScrollingMenu
+ ld a, [wMenuScrollPosition]
+ ld [wItemsPocketScrollPosition], a
+ ld a, [wMenuCursorY]
+ ld [wItemsPocketCursor], a
+ ret
+
+.KeyItemsPocket:
+ ld a, KEY_ITEM_POCKET
+ call InitPocket
+ ld hl, PC_Mart_KeyItemsPocketMenuHeader
+ call CopyMenuHeader
+ ld a, [wKeyItemsPocketCursor]
+ ld [wMenuCursorBuffer], a
+ ld a, [wKeyItemsPocketScrollPosition]
+ ld [wMenuScrollPosition], a
+ call ScrollingMenu
+ ld a, [wMenuScrollPosition]
+ ld [wKeyItemsPocketScrollPosition], a
+ ld a, [wMenuCursorY]
+ ld [wKeyItemsPocketCursor], a
+ ret
+
+.TMHMPocket:
+ ld a, TM_HM_POCKET
+ call InitPocket
+ call WaitBGMap_DrawPackGFX
+ farcall TMHMPocket
+ ld a, [wCurItem]
+ ld [wCurItem], a
+ ret
+
+.BallsPocket:
+ ld a, BALL_POCKET
+ call InitPocket
+ ld hl, PC_Mart_BallsPocketMenuHeader
+ call CopyMenuHeader
+ ld a, [wBallsPocketCursor]
+ ld [wMenuCursorBuffer], a
+ ld a, [wBallsPocketScrollPosition]
+ ld [wMenuScrollPosition], a
+ call ScrollingMenu
+ ld a, [wMenuScrollPosition]
+ ld [wBallsPocketScrollPosition], a
+ ld a, [wMenuCursorY]
+ ld [wBallsPocketCursor], a
+ ret
+
+InitPocket:
+ ld [wCurrPocket], a
+ call ClearPocketList
+ call DrawPocketName
+ call WaitBGMap_DrawPackGFX
+ ret
+
+DepositSellTutorial_InterpretJoypad:
+ ld hl, wMenuJoypad
+ ld a, [hl]
+ and A_BUTTON
+ jr nz, .a_button
+ ld a, [hl]
+ and B_BUTTON
+ jr nz, .b_button
+ ld a, [hl]
+ and D_LEFT
+ jr nz, .d_left
+ ld a, [hl]
+ and D_RIGHT
+ jr nz, .d_right
+ scf
+ ret
+
+.a_button
+ ld a, TRUE
+ ld [wPackUsedItem], a
+ and a
+ ret
+
+.b_button
+ xor a ; FALSE
+ ld [wPackUsedItem], a
+ and a
+ ret
+
+.d_left
+ ld a, [wJumptableIndex]
+ dec a
+ maskbits NUM_POCKETS
+ ld [wJumptableIndex], a
+ push de
+ ld de, SFX_SWITCH_POCKETS
+ call PlaySFX
+ pop de
+ scf
+ ret
+
+.d_right
+ ld a, [wJumptableIndex]
+ inc a
+ maskbits NUM_POCKETS
+ ld [wJumptableIndex], a
+ push de
+ ld de, SFX_SWITCH_POCKETS
+ call PlaySFX
+ pop de
+ scf
+ ret
+
+TutorialPack:
+ call DepositSellInitPackBuffers
+ ld a, [wInputType]
+ or a
+ jr z, .loop
+ farcall _DudeAutoInput_RightA
+.loop
+ call .RunJumptable
+ call DepositSellTutorial_InterpretJoypad
+ jr c, .loop
+ xor a ; FALSE
+ ld [wPackUsedItem], a
+ ret
+
+.RunJumptable:
+ ld a, [wJumptableIndex]
+ ld hl, .dw
+ call Pack_GetJumptablePointer
+ jp hl
+
+.dw
+; entries correspond to *_POCKET constants
+ dw .Items
+ dw .Balls
+ dw .KeyItems
+ dw .TMHM
+
+.Items:
+ xor a ; ITEM_POCKET
+ ld hl, .ItemsMenuHeader
+ jr .DisplayPocket
+
+.ItemsMenuHeader:
+ db MENU_BACKUP_TILES ; flags
+ menu_coords 7, 1, SCREEN_WIDTH - 1, TEXTBOX_Y - 1
+ dw .ItemsMenuData
+ db 1 ; default option
+
+.ItemsMenuData:
+ db STATICMENU_ENABLE_SELECT | STATICMENU_ENABLE_LEFT_RIGHT | STATICMENU_ENABLE_START | STATICMENU_WRAP | STATICMENU_CURSOR ; flags
+ db 5, 8 ; rows, columns
+ db 2 ; horizontal spacing
+ dbw 0, wDudeNumItems
+ dba PlaceMenuItemName
+ dba PlaceMenuItemQuantity
+ dba UpdateItemDescription
+
+.KeyItems:
+ ld a, KEY_ITEM_POCKET
+ ld hl, .KeyItemsMenuHeader
+ jr .DisplayPocket
+
+.KeyItemsMenuHeader:
+ db MENU_BACKUP_TILES ; flags
+ menu_coords 7, 1, SCREEN_WIDTH - 1, TEXTBOX_Y - 1
+ dw .KeyItemsMenuData
+ db 1 ; default option
+
+.KeyItemsMenuData:
+ db STATICMENU_ENABLE_SELECT | STATICMENU_ENABLE_LEFT_RIGHT | STATICMENU_ENABLE_START | STATICMENU_WRAP | STATICMENU_CURSOR ; flags
+ db 5, 8 ; rows, columns
+ db 1 ; horizontal spacing
+ dbw 0, wDudeNumKeyItems
+ dba PlaceMenuItemName
+ dba PlaceMenuItemQuantity
+ dba UpdateItemDescription
+
+.TMHM:
+ ld a, TM_HM_POCKET
+ call InitPocket
+ call WaitBGMap_DrawPackGFX
+ farcall TMHMPocket
+ ld a, [wCurItem]
+ ld [wCurItem], a
+ ret
+
+.Balls:
+ ld a, BALL_POCKET
+ ld hl, .BallsMenuHeader
+ jr .DisplayPocket
+
+.BallsMenuHeader:
+ db MENU_BACKUP_TILES ; flags
+ menu_coords 7, 1, SCREEN_WIDTH - 1, TEXTBOX_Y - 1
+ dw .BallsMenuData
+ db 1 ; default option
+
+.BallsMenuData:
+ db STATICMENU_ENABLE_SELECT | STATICMENU_ENABLE_LEFT_RIGHT | STATICMENU_ENABLE_START | STATICMENU_WRAP | STATICMENU_CURSOR ; flags
+ db 5, 8 ; rows, columns
+ db 2 ; horizontal spacing
+ dbw 0, wDudeNumBalls
+ dba PlaceMenuItemName
+ dba PlaceMenuItemQuantity
+ dba UpdateItemDescription
+
+.DisplayPocket:
+ push hl
+ call InitPocket
+ pop hl
+ call CopyMenuHeader
+ call ScrollingMenu
+ ret
+
+Pack_JumptableNext:
+ ld hl, wJumptableIndex
+ inc [hl]
+ ret
+
+Pack_GetJumptablePointer:
+ ld e, a
+ ld d, 0
+ add hl, de
+ add hl, de
+ ld a, [hli]
+ ld h, [hl]
+ ld l, a
+ ret
+
+Pack_QuitNoScript:
+ ld hl, wJumptableIndex
+ set 7, [hl]
+ xor a ; FALSE
+ ld [wPackUsedItem], a
+ ret
+
+Pack_QuitRunScript:
+ ld hl, wJumptableIndex
+ set 7, [hl]
+ ld a, TRUE
+ ld [wPackUsedItem], a
+ ret
+
+Pack_PrintTextNoScroll:
+ ld a, [wOptions]
+ push af
+ set NO_TEXT_SCROLL, a
+ ld [wOptions], a
+ call PrintText
+ pop af
+ ld [wOptions], a
+ ret
+
+WaitBGMap_DrawPackGFX:
+ call WaitBGMap
+DrawPackGFX:
+ ld a, [wCurrPocket]
+ maskbits NUM_POCKETS
+ ld e, a
+ ld d, 0
+ ld a, [wBattleType]
+ cp BATTLETYPE_TUTORIAL
+ jr z, .male_dude
+ ld a, [wPlayerGender]
+ bit PLAYERGENDER_FEMALE_F, a
+ jr nz, .female
+.male_dude
+ ld hl, PackGFXPointers
+ add hl, de
+ add hl, de
+ ld a, [hli]
+ ld e, a
+ ld d, [hl]
+ ld hl, vTiles2 tile $50
+ lb bc, BANK(PackGFX), 15
+ call Request2bpp
+ ret
+
+.female
+ farcall DrawKrisPackGFX
+ ret
+
+PackGFXPointers:
+ dw PackGFX + (15 tiles) * 1 ; ITEM_POCKET
+ dw PackGFX + (15 tiles) * 3 ; BALL_POCKET
+ dw PackGFX + (15 tiles) * 0 ; KEY_ITEM_POCKET
+ dw PackGFX + (15 tiles) * 2 ; TM_HM_POCKET
+
+Pack_InterpretJoypad:
+ ld hl, wMenuJoypad
+ ld a, [wSwitchItem]
+ and a
+ jr nz, .switching_item
+ ld a, [hl]
+ and A_BUTTON
+ jr nz, .a_button
+ ld a, [hl]
+ and B_BUTTON
+ jr nz, .b_button
+ ld a, [hl]
+ and D_LEFT
+ jr nz, .d_left
+ ld a, [hl]
+ and D_RIGHT
+ jr nz, .d_right
+ ld a, [hl]
+ and SELECT
+ jr nz, .select
+ scf
+ ret
+
+.a_button
+ and a
+ ret
+
+.b_button
+ ld a, PACKSTATE_QUITNOSCRIPT
+ ld [wJumptableIndex], a
+ scf
+ ret
+
+.d_left
+ ld a, b
+ ld [wJumptableIndex], a
+ ld [wPackJumptableIndex], a
+ push de
+ ld de, SFX_SWITCH_POCKETS
+ call PlaySFX
+ pop de
+ scf
+ ret
+
+.d_right
+ ld a, c
+ ld [wJumptableIndex], a
+ ld [wPackJumptableIndex], a
+ push de
+ ld de, SFX_SWITCH_POCKETS
+ call PlaySFX
+ pop de
+ scf
+ ret
+
+.select
+ farcall SwitchItemsInBag
+ ld hl, Text_MoveItemWhere
+ call Pack_PrintTextNoScroll
+ scf
+ ret
+
+.switching_item
+ ld a, [hl]
+ and A_BUTTON | SELECT
+ jr nz, .place_insert
+ ld a, [hl]
+ and B_BUTTON
+ jr nz, .end_switch
+ scf
+ ret
+
+.place_insert
+ farcall SwitchItemsInBag
+ ld de, SFX_SWITCH_POKEMON
+ call WaitPlaySFX
+ ld de, SFX_SWITCH_POKEMON
+ call WaitPlaySFX
+.end_switch
+ xor a
+ ld [wSwitchItem], a
+ scf
+ ret
+
+Pack_InitGFX:
+ call ClearBGPalettes
+ call ClearTileMap
+ call ClearSprites
+ call DisableLCD
+ ld hl, PackMenuGFX
+ ld de, vTiles2
+ ld bc, $60 tiles
+ ld a, BANK(PackMenuGFX)
+ call FarCopyBytes
+; Background (blue if male, pink if female)
+ hlcoord 0, 1
+ ld bc, 11 * SCREEN_WIDTH
+ ld a, $24
+ call ByteFill
+; This is where the items themselves will be listed.
+ hlcoord 5, 1
+ lb bc, 11, 15
+ call ClearBox
+; ◀▶ POCKET ▼▲ ITEMS
+ hlcoord 0, 0
+ ld a, $28
+ ld c, SCREEN_WIDTH
+.loop
+ ld [hli], a
+ inc a
+ dec c
+ jr nz, .loop
+ call DrawPocketName
+ call PlacePackGFX
+; Place the textbox for displaying the item description
+ hlcoord 0, SCREEN_HEIGHT - 4 - 2
+ lb bc, 4, SCREEN_WIDTH - 2
+ call TextBox
+ call EnableLCD
+ call DrawPackGFX
+ ret
+
+PlacePackGFX:
+ hlcoord 0, 3
+ ld a, $50
+ ld de, SCREEN_WIDTH - 5
+ ld b, 3
+.row
+ ld c, 5
+.column
+ ld [hli], a
+ inc a
+ dec c
+ jr nz, .column
+ add hl, de
+ dec b
+ jr nz, .row
+ ret
+
+DrawPocketName:
+ ld a, [wCurrPocket]
+ ; * 15
+ ld d, a
+ swap a
+ sub d
+ ld d, 0
+ ld e, a
+ ld hl, .tilemap
+ add hl, de
+ ld d, h
+ ld e, l
+ hlcoord 0, 7
+ ld c, 3
+.row
+ ld b, 5
+.col
+ ld a, [de]
+ inc de
+ ld [hli], a
+ dec b
+ jr nz, .col
+ ld a, c
+ ld c, SCREEN_WIDTH - 5
+ add hl, bc
+ ld c, a
+ dec c
+ jr nz, .row
+ ret
+
+.tilemap
+; ITEM_POCKET
+ db $00, $04, $04, $04, $01 ; top border
+ db $06, $07, $08, $09, $0a ; Items
+ db $02, $05, $05, $05, $03 ; bottom border
+; BALL_POCKET
+ db $00, $04, $04, $04, $01 ; top border
+ db $15, $16, $17, $18, $19 ; Balls
+ db $02, $05, $05, $05, $03 ; bottom border
+; KEY_ITEM_POCKET
+ db $00, $04, $04, $04, $01 ; top border
+ db $0b, $0c, $0d, $0e, $0f ; Key Items
+ db $02, $05, $05, $05, $03 ; bottom border
+; TM_HM_POCKET
+ db $00, $04, $04, $04, $01 ; top border
+ db $10, $11, $12, $13, $14 ; TM/HM
+ db $02, $05, $05, $05, $03 ; bottom border
+
+Pack_GetItemName:
+ ld a, [wCurItem]
+ ld [wNamedObjectIndexBuffer], a
+ call GetItemName
+ call CopyName1
+ ret
+
+Unreferenced_Pack_ClearTilemap:
+ hlcoord 0, 0
+ ld bc, SCREEN_WIDTH * SCREEN_HEIGHT
+ ld a, " "
+ call ByteFill
+ ret
+
+ClearPocketList:
+ hlcoord 5, 2
+ lb bc, 10, SCREEN_WIDTH - 5
+ call ClearBox
+ ret
+
+Pack_InitColors:
+ call WaitBGMap
+ ld b, SCGB_PACKPALS
+ call GetSGBLayout
+ call SetPalettes
+ call DelayFrame
+ ret
+
+ItemsPocketMenuHeader:
+ db MENU_BACKUP_TILES ; flags
+ menu_coords 7, 1, SCREEN_WIDTH - 1, TEXTBOX_Y - 1
+ dw .MenuData
+ db 1 ; default option
+
+.MenuData:
+ db STATICMENU_ENABLE_SELECT | STATICMENU_ENABLE_LEFT_RIGHT | STATICMENU_ENABLE_START | STATICMENU_WRAP | STATICMENU_CURSOR ; flags
+ db 5, 8 ; rows, columns
+ db 2 ; horizontal spacing
+ dbw 0, wNumItems
+ dba PlaceMenuItemName
+ dba PlaceMenuItemQuantity
+ dba UpdateItemDescription
+
+PC_Mart_ItemsPocketMenuHeader:
+ db MENU_BACKUP_TILES ; flags
+ menu_coords 7, 1, SCREEN_WIDTH - 1, TEXTBOX_Y - 1
+ dw .MenuData
+ db 1 ; default option
+
+.MenuData:
+ db STATICMENU_ENABLE_SELECT | STATICMENU_ENABLE_LEFT_RIGHT | STATICMENU_ENABLE_START | STATICMENU_WRAP ; flags
+ db 5, 8 ; rows, columns
+ db 2 ; horizontal spacing
+ dbw 0, wNumItems
+ dba PlaceMenuItemName
+ dba PlaceMenuItemQuantity
+ dba UpdateItemDescription
+
+KeyItemsPocketMenuHeader:
+ db MENU_BACKUP_TILES ; flags
+ menu_coords 7, 1, SCREEN_WIDTH - 1, TEXTBOX_Y - 1
+ dw .MenuData
+ db 1 ; default option
+
+.MenuData:
+ db STATICMENU_ENABLE_SELECT | STATICMENU_ENABLE_LEFT_RIGHT | STATICMENU_ENABLE_START | STATICMENU_WRAP | STATICMENU_CURSOR ; flags
+ db 5, 8 ; rows, columns
+ db 1 ; horizontal spacing
+ dbw 0, wNumKeyItems
+ dba PlaceMenuItemName
+ dba PlaceMenuItemQuantity
+ dba UpdateItemDescription
+
+PC_Mart_KeyItemsPocketMenuHeader:
+ db MENU_BACKUP_TILES ; flags
+ menu_coords 7, 1, SCREEN_WIDTH - 1, TEXTBOX_Y - 1
+ dw .MenuData
+ db 1 ; default option
+
+.MenuData:
+ db STATICMENU_ENABLE_SELECT | STATICMENU_ENABLE_LEFT_RIGHT | STATICMENU_ENABLE_START | STATICMENU_WRAP ; flags
+ db 5, 8 ; rows, columns
+ db 1 ; horizontal spacing
+ dbw 0, wNumKeyItems
+ dba PlaceMenuItemName
+ dba PlaceMenuItemQuantity
+ dba UpdateItemDescription
+
+BallsPocketMenuHeader:
+ db MENU_BACKUP_TILES ; flags
+ menu_coords 7, 1, SCREEN_WIDTH - 1, TEXTBOX_Y - 1
+ dw .MenuData
+ db 1 ; default option
+
+.MenuData:
+ db STATICMENU_ENABLE_SELECT | STATICMENU_ENABLE_LEFT_RIGHT | STATICMENU_ENABLE_START | STATICMENU_WRAP | STATICMENU_CURSOR ; flags
+ db 5, 8 ; rows, columns
+ db 2 ; horizontal spacing
+ dbw 0, wNumBalls
+ dba PlaceMenuItemName
+ dba PlaceMenuItemQuantity
+ dba UpdateItemDescription
+
+PC_Mart_BallsPocketMenuHeader:
+ db MENU_BACKUP_TILES ; flags
+ menu_coords 7, 1, SCREEN_WIDTH - 1, TEXTBOX_Y - 1
+ dw .MenuData
+ db 1 ; default option
+
+.MenuData:
+ db STATICMENU_ENABLE_SELECT | STATICMENU_ENABLE_LEFT_RIGHT | STATICMENU_ENABLE_START | STATICMENU_WRAP ; flags
+ db 5, 8 ; rows, columns
+ db 2 ; horizontal spacing
+ dbw 0, wNumBalls
+ dba PlaceMenuItemName
+ dba PlaceMenuItemQuantity
+ dba UpdateItemDescription
+
+Text_PackNoItems:
+ ; No items.
+ text_jump UnknownText_0x1c0b9a
+ db "@"
+
+Text_ThrowAwayHowMany:
+ ; Throw away how many?
+ text_jump UnknownText_0x1c0ba5
+ db "@"
+
+Text_ConfirmThrowAway:
+ ; Throw away @ @ (S)?
+ text_jump UnknownText_0x1c0bbb
+ db "@"
+
+Text_ThrewAway:
+ ; Threw away @ (S).
+ text_jump UnknownText_0x1c0bd8
+ db "@"
+
+Text_ThisIsntTheTime:
+ ; OAK: ! This isn't the time to use that!
+ text_jump UnknownText_0x1c0bee
+ db "@"
+
+TextJump_YouDontHaveAMon:
+ ; You don't have a #MON!
+ text_jump Text_YouDontHaveAMon
+ db "@"
+
+Text_RegisteredItem:
+ ; Registered the @ .
+ text_jump UnknownText_0x1c0c2e
+ db "@"
+
+Text_CantRegister:
+ ; You can't register that item.
+ text_jump UnknownText_0x1c0c45
+ db "@"
+
+Text_MoveItemWhere:
+ ; Where should this be moved to?
+ text_jump UnknownText_0x1c0c63
+ db "@"
+
+Text_PackEmptyString:
+ ;
+ text_jump UnknownText_0x1c0c83
+ db "@"
+
+TextJump_YouCantUseItInABattle:
+ ; Doesn't seem to be used anywhere
+ ; "You can't use it in a battle."
+ text_jump Text_YouCantUseItInABattle
+ db "@"
+
+PackMenuGFX:
+INCBIN "gfx/pack/pack_menu.2bpp"
+PackGFX:
+INCBIN "gfx/pack/pack.2bpp"
diff --git a/engine/items/pack_kris.asm b/engine/items/pack_kris.asm
new file mode 100644
index 000000000..1a169ea6e
--- /dev/null
+++ b/engine/items/pack_kris.asm
@@ -0,0 +1,20 @@
+DrawKrisPackGFX:
+ ld hl, PackFGFXPointers
+ add hl, de
+ add hl, de
+ ld a, [hli]
+ ld e, a
+ ld d, [hl]
+ ld hl, vTiles2 tile $50
+ lb bc, BANK(PackFGFX), 15
+ call Request2bpp
+ ret
+
+PackFGFXPointers:
+ dw PackFGFX + (15 tiles) * 1 ; ITEM_POCKET
+ dw PackFGFX + (15 tiles) * 3 ; BALL_POCKET
+ dw PackFGFX + (15 tiles) * 0 ; KEY_ITEM_POCKET
+ dw PackFGFX + (15 tiles) * 2 ; TM_HM_POCKET
+
+PackFGFX:
+INCBIN "gfx/pack/pack_f.2bpp"
diff --git a/engine/items/print_item_description.asm b/engine/items/print_item_description.asm
new file mode 100644
index 000000000..b0a3a0b33
--- /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
+ farcall GetTMHMItemMove
+ pop hl
+ ld a, [wd265]
+ ld [wCurSpecies], a
+ predef 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 e, [hl]
+ inc hl
+ ld d, [hl]
+ pop hl
+ jp PlaceString
+
+INCLUDE "data/items/descriptions.asm"
diff --git a/engine/items/switch_items.asm b/engine/items/switch_items.asm
new file mode 100644
index 000000000..81b5ac6a5
--- /dev/null
+++ b/engine/items/switch_items.asm
@@ -0,0 +1,271 @@
+SwitchItemsInBag:
+ ld a, [wSwitchItem]
+ and a
+ jr z, .init
+ ld b, a
+ ld a, [wScrollingMenuCursorPosition]
+ inc a
+ cp b
+ jr z, .trivial
+ ld a, [wScrollingMenuCursorPosition]
+ call ItemSwitch_GetNthItem
+ ld a, [hl]
+ cp -1
+ ret z
+ ld a, [wSwitchItem]
+ dec a
+ ld [wSwitchItem], a
+ call Function249a7
+ jp c, Function249d1
+ ld a, [wScrollingMenuCursorPosition]
+ ld c, a
+ ld a, [wSwitchItem]
+ cp c
+ jr c, .asm_2497a
+ jr .asm_2494a
+
+.init
+ ld a, [wScrollingMenuCursorPosition]
+ inc a
+ ld [wSwitchItem], a
+ ret
+
+.trivial
+ xor a
+ ld [wSwitchItem], a
+ ret
+
+.asm_2494a
+ ld a, [wSwitchItem]
+ call Function24a40
+ ld a, [wScrollingMenuCursorPosition]
+ ld d, a
+ ld a, [wSwitchItem]
+ ld e, a
+ call Function24a6c
+ push bc
+ ld a, [wSwitchItem]
+ call ItemSwitch_GetNthItem
+ dec hl
+ push hl
+ call ItemSwitch_ConvertSpacingToDW
+ add hl, bc
+ ld d, h
+ ld e, l
+ pop hl
+ pop bc
+ call Function24aab
+ ld a, [wScrollingMenuCursorPosition]
+ call Function24a4d
+ xor a
+ ld [wSwitchItem], a
+ ret
+
+.asm_2497a
+ ld a, [wSwitchItem]
+ call Function24a40
+ ld a, [wScrollingMenuCursorPosition]
+ ld d, a
+ ld a, [wSwitchItem]
+ ld e, a
+ call Function24a6c
+ push bc
+ ld a, [wSwitchItem]
+ call ItemSwitch_GetNthItem
+ ld d, h
+ ld e, l
+ call ItemSwitch_ConvertSpacingToDW
+ add hl, bc
+ pop bc
+ call CopyBytes
+ ld a, [wScrollingMenuCursorPosition]
+ call Function24a4d
+ xor a
+ ld [wSwitchItem], a
+ ret
+
+Function249a7:
+ ld a, [wSwitchItem]
+ call ItemSwitch_GetNthItem
+ ld d, h
+ ld e, l
+ ld a, [wScrollingMenuCursorPosition]
+ call ItemSwitch_GetNthItem
+ ld a, [de]
+ cp [hl]
+ jr nz, .asm_249cd
+ ld a, [wScrollingMenuCursorPosition]
+ call Function24a97
+ cp 99
+ jr z, .asm_249cd
+ ld a, [wSwitchItem]
+ call Function24a97
+ cp 99
+ jr nz, .asm_249cf
+.asm_249cd
+ and a
+ ret
+
+.asm_249cf
+ scf
+ ret
+
+Function249d1:
+ ld a, [wSwitchItem]
+ call ItemSwitch_GetNthItem
+ inc hl
+ push hl
+ ld a, [wScrollingMenuCursorPosition]
+ call ItemSwitch_GetNthItem
+ inc hl
+ ld a, [hl]
+ pop hl
+ add [hl]
+ cp 100
+ jr c, .asm_24a01
+ sub 99
+ push af
+ ld a, [wScrollingMenuCursorPosition]
+ call ItemSwitch_GetNthItem
+ inc hl
+ ld [hl], 99
+ ld a, [wSwitchItem]
+ call ItemSwitch_GetNthItem
+ inc hl
+ pop af
+ ld [hl], a
+ xor a
+ ld [wSwitchItem], a
+ ret
+
+.asm_24a01
+ push af
+ ld a, [wScrollingMenuCursorPosition]
+ call ItemSwitch_GetNthItem
+ inc hl
+ pop af
+ ld [hl], a
+ ld hl, wMenuData_ItemsPointerAddr
+ ld a, [hli]
+ ld h, [hl]
+ ld l, a
+ ld a, [wSwitchItem]
+ cp [hl]
+ jr nz, .asm_24a25
+ dec [hl]
+ ld a, [wSwitchItem]
+ call ItemSwitch_GetNthItem
+ ld [hl], $ff
+ xor a
+ ld [wSwitchItem], a
+ ret
+
+.asm_24a25
+ dec [hl]
+ call ItemSwitch_ConvertSpacingToDW
+ push bc
+ ld a, [wSwitchItem]
+ call ItemSwitch_GetNthItem
+ pop bc
+ push hl
+ add hl, bc
+ pop de
+.asm_24a34
+ ld a, [hli]
+ ld [de], a
+ inc de
+ cp $ff
+ jr nz, .asm_24a34
+ xor a
+ ld [wSwitchItem], a
+ ret
+
+Function24a40:
+ call ItemSwitch_GetNthItem
+ ld de, wd002
+ call ItemSwitch_ConvertSpacingToDW
+ call CopyBytes
+ ret
+
+Function24a4d:
+ call ItemSwitch_GetNthItem
+ ld d, h
+ ld e, l
+ ld hl, wd002
+ call ItemSwitch_ConvertSpacingToDW
+ call CopyBytes
+ ret
+
+ItemSwitch_GetNthItem:
+ push af
+ call ItemSwitch_ConvertSpacingToDW
+ ld hl, wMenuData_ItemsPointerAddr
+ ld a, [hli]
+ ld h, [hl]
+ ld l, a
+ inc hl
+ pop af
+ call AddNTimes
+ ret
+
+Function24a6c:
+ push hl
+ call ItemSwitch_ConvertSpacingToDW
+ ld a, d
+ sub e
+ jr nc, .dont_negate
+ dec a
+ cpl
+.dont_negate
+ ld hl, 0
+ call AddNTimes
+ ld b, h
+ ld c, l
+ pop hl
+ ret
+
+ItemSwitch_ConvertSpacingToDW:
+; This function is absolutely idiotic.
+ push hl
+ ld a, [wMenuData_ScrollingMenuSpacing]
+ ld c, a
+ ld b, 0
+ ld hl, .spacing_dws
+ add hl, bc
+ add hl, bc
+ ld c, [hl]
+ inc hl
+ ld b, [hl]
+ pop hl
+ ret
+
+.spacing_dws
+ dw 0, 1, 2
+
+Function24a97:
+ push af
+ call ItemSwitch_ConvertSpacingToDW
+ ld a, c
+ cp 2
+ jr nz, .not_2
+ pop af
+ call ItemSwitch_GetNthItem
+ inc hl
+ ld a, [hl]
+ ret
+
+.not_2
+ pop af
+ ld a, $1
+ ret
+
+Function24aab:
+.loop
+ ld a, [hld]
+ ld [de], a
+ dec de
+ dec bc
+ ld a, b
+ or c
+ jr nz, .loop
+ ret
diff --git a/engine/items/tmhm.asm b/engine/items/tmhm.asm
new file mode 100644
index 000000000..4958d2afc
--- /dev/null
+++ b/engine/items/tmhm.asm
@@ -0,0 +1,574 @@
+TMHMPocket:
+ ld a, $1
+ ld [hInMenu], a
+ call TMHM_PocketLoop
+ ld a, $0
+ ld [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 GetNumberedTMHM
+ ld a, c
+ ld [wCurItem], a
+ ret
+
+ConvertCurItemIntoCurTMHM:
+ ld a, [wCurItem]
+ ld c, a
+ callfar GetTMHMNumber
+ ld a, c
+ ld [wCurTMHM], 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, [wCurTMHM]
+ ld [wPutativeTMHMMove], a
+ call GetMoveName
+ call CopyName1
+ ld hl, Text_BootedTM ; Booted up a TM
+ ld a, [wCurItem]
+ cp HM01
+ jr c, .TM
+ ld hl, Text_BootedHM ; Booted up an HM
+.TM:
+ call PrintText
+ ld hl, Text_ItContained
+ 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, Text_TMHMNotCompatible
+ call PrintText
+ jr .nope
+
+.compatible
+ callfar KnowsMove
+ jr c, .nope
+
+ predef LearnMove
+ ld a, b
+ and a
+ jr z, .nope
+
+ farcall StubbedTrainerRankings_TMsHMsTaught
+ 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
+
+Text_BootedTM:
+ ; Booted up a TM.
+ text_jump UnknownText_0x1c0373
+ db "@"
+
+Text_BootedHM:
+ ; Booted up an HM.
+ text_jump UnknownText_0x1c0384
+ db "@"
+
+Text_ItContained:
+ ; It contained @ . Teach @ to a #MON?
+ text_jump UnknownText_0x1c0396
+ db "@"
+
+Text_TMHMNotCompatible:
+ ; is not compatible with @ . It can't learn @ .
+ text_jump UnknownText_0x1c03c2
+ db "@"
+
+TMHM_PocketLoop:
+ xor a
+ ld [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
+ ld [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 [wd265], a
+ predef GetTMHMMove
+ ld a, [wd265]
+ ld [wCurSpecies], a
+ hlcoord 1, 14
+ call PrintMoveDesc
+ jp TMHM_JoypadLoop
+
+TMHM_ChooseTMorHM:
+ call TMHM_PlaySFX_ReadText2
+ call CountTMsHMs ; This stores the count to wd265.
+ ld a, [wMenuCursorY]
+ dec a
+ ld b, a
+ ld a, [wTMHMPocketScrollPosition]
+ add b
+ ld b, a
+ ld a, [wd265]
+ 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 [wd265], a
+ push hl
+ push de
+ push bc
+ call TMHMPocket_GetCurrentLineCoord
+ push hl
+ ld a, [wd265]
+ cp NUM_TMS + 1
+ jr nc, .HM
+ ld de, wd265
+ lb bc, PRINTNUM_LEADINGZEROS | 1, 2
+ call PrintNum
+ jr .okay
+
+.HM:
+ push af
+ sub NUM_TMS
+ ld [wd265], a
+ ld [hl], "H"
+ inc hl
+ ld de, wd265
+ lb bc, PRINTNUM_RIGHTALIGN | 1, 2
+ call PrintNum
+ pop af
+ ld [wd265], a
+.okay
+ predef GetTMHMMove
+ ld a, [wd265]
+ 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 [wd265], a
+ ld de, wd265
+ 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, [wd265]
+ 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, .NoRoomText
+ jr nc, .print
+ ld hl, .ReceivedText
+.print
+ jp PrintText
+
+.NoRoomText:
+ ; You have no room for any more @ S.
+ text_jump UnknownText_0x1c03fa
+ db "@"
+
+.ReceivedText:
+ ; You received @ !
+ text_jump UnknownText_0x1c0421
+ db "@"
+
+.CheckHaveRoomForTMHM:
+ ld a, [wd265]
+ 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, [wd265]
+ 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 [wd265], a
+ ret
+
+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, [hli]
+ ld e, a
+ ld d, [hl]
+ pop hl
+ jp PlaceString
diff --git a/engine/items/tmhm2.asm b/engine/items/tmhm2.asm
new file mode 100644
index 000000000..10206d36b
--- /dev/null
+++ b/engine/items/tmhm2.asm
@@ -0,0 +1,46 @@
+CanLearnTMHMMove:
+ ld a, [wCurPartySpecies]
+ ld [wCurSpecies], a
+ call GetBaseData
+ ld hl, wBaseTMHM
+ push hl
+
+ ld a, [wPutativeTMHMMove]
+ ld b, a
+ ld c, 0
+ ld hl, TMHMMoves
+.loop
+ ld a, [hli]
+ and a
+ jr z, .end
+ cp b
+ jr z, .asm_11659
+ inc c
+ jr .loop
+
+.asm_11659
+ pop hl
+ ld b, CHECK_FLAG
+ push de
+ ld d, 0
+ predef SmallFarFlagAction
+ pop de
+ ret
+
+.end
+ pop hl
+ ld c, 0
+ ret
+
+GetTMHMMove:
+ ld a, [wd265]
+ dec a
+ ld hl, TMHMMoves
+ ld b, 0
+ ld c, a
+ add hl, bc
+ ld a, [hl]
+ ld [wd265], a
+ ret
+
+INCLUDE "data/moves/tmhm_moves.asm"
diff --git a/engine/items/update_item_description.asm b/engine/items/update_item_description.asm
new file mode 100644
index 000000000..d4bc731a1
--- /dev/null
+++ b/engine/items/update_item_description.asm
@@ -0,0 +1,13 @@
+UpdateItemDescription:
+ ld a, [wMenuSelection]
+ ld [wCurSpecies], a
+ hlcoord 0, 12
+ ld b, 4
+ ld c, SCREEN_WIDTH - 2
+ call TextBox
+ ld a, [wMenuSelection]
+ cp -1
+ ret z
+ decoord 1, 14
+ farcall PrintItemDescription
+ ret