summaryrefslogtreecommitdiff
path: root/engine
diff options
context:
space:
mode:
Diffstat (limited to 'engine')
-rw-r--r--engine/battle/ai/items.asm824
-rw-r--r--engine/battle/ai/move.asm208
-rw-r--r--engine/battle/ai/redundant.asm198
-rw-r--r--engine/battle/ai/scoring.asm3208
-rw-r--r--engine/battle/ai/switch.asm658
-rwxr-xr-xengine/battle/anim_hp_bar.asm (renamed from engine/anim_hp_bar.asm)235
-rw-r--r--engine/battle/consume_held_item.asm57
-rw-r--r--engine/battle/core.asm8732
-rw-r--r--engine/battle/effect_commands.asm6865
-rw-r--r--engine/battle/menu.asm94
-rw-r--r--engine/battle/move_effects/attract.asm76
-rw-r--r--engine/battle/move_effects/baton_pass.asm194
-rw-r--r--engine/battle/move_effects/beat_up.asm220
-rw-r--r--engine/battle/move_effects/belly_drum.asm30
-rw-r--r--engine/battle/move_effects/bide.asm100
-rw-r--r--engine/battle/move_effects/conversion.asm96
-rw-r--r--engine/battle/move_effects/conversion2.asm64
-rw-r--r--engine/battle/move_effects/counter.asm59
-rw-r--r--engine/battle/move_effects/curse.asm93
-rw-r--r--engine/battle/move_effects/destiny_bond.asm9
-rw-r--r--engine/battle/move_effects/disable.asm72
-rw-r--r--engine/battle/move_effects/encore.asm120
-rw-r--r--engine/battle/move_effects/endure.asm16
-rw-r--r--engine/battle/move_effects/false_swipe.asm48
-rw-r--r--engine/battle/move_effects/focus_energy.asm15
-rw-r--r--engine/battle/move_effects/foresight.asm22
-rw-r--r--engine/battle/move_effects/frustration.asm27
-rw-r--r--engine/battle/move_effects/fury_cutter.asm55
-rw-r--r--engine/battle/move_effects/future_sight.asm81
-rw-r--r--engine/battle/move_effects/heal_bell.asm34
-rw-r--r--engine/battle/move_effects/hidden_power.asm8
-rw-r--r--engine/battle/move_effects/leech_seed.asm40
-rw-r--r--engine/battle/move_effects/lock_on.asm21
-rw-r--r--engine/battle/move_effects/magnitude.asm29
-rw-r--r--engine/battle/move_effects/metronome.asm43
-rw-r--r--engine/battle/move_effects/mimic.asm50
-rw-r--r--engine/battle/move_effects/mirror_coat.asm60
-rw-r--r--engine/battle/move_effects/mirror_move.asm51
-rw-r--r--engine/battle/move_effects/mist.asm15
-rw-r--r--engine/battle/move_effects/nightmare.asm37
-rw-r--r--engine/battle/move_effects/pain_split.asm92
-rw-r--r--engine/battle/move_effects/pay_day.asm26
-rw-r--r--engine/battle/move_effects/perish_song.asm38
-rw-r--r--engine/battle/move_effects/present.asm75
-rw-r--r--engine/battle/move_effects/protect.asm75
-rw-r--r--engine/battle/move_effects/psych_up.asm47
-rw-r--r--engine/battle/move_effects/pursuit.asm24
-rw-r--r--engine/battle/move_effects/rage.asm6
-rw-r--r--engine/battle/move_effects/rain_dance.asm9
-rw-r--r--engine/battle/move_effects/rapid_spin.asm36
-rw-r--r--engine/battle/move_effects/return.asm25
-rw-r--r--engine/battle/move_effects/rollout.asm95
-rw-r--r--engine/battle/move_effects/safeguard.asm23
-rw-r--r--engine/battle/move_effects/sandstorm.asm18
-rw-r--r--engine/battle/move_effects/selfdestruct.asm30
-rw-r--r--engine/battle/move_effects/sketch.asm117
-rw-r--r--engine/battle/move_effects/sleep_talk.asm143
-rw-r--r--engine/battle/move_effects/snore.asm11
-rw-r--r--engine/battle/move_effects/spikes.asm26
-rw-r--r--engine/battle/move_effects/spite.asm86
-rw-r--r--engine/battle/move_effects/splash.asm3
-rw-r--r--engine/battle/move_effects/substitute.asm90
-rw-r--r--engine/battle/move_effects/sunny_day.asm9
-rw-r--r--engine/battle/move_effects/teleport.asm87
-rw-r--r--engine/battle/move_effects/thief.asm112
-rw-r--r--engine/battle/move_effects/thunder.asm18
-rw-r--r--engine/battle/move_effects/transform.asm155
-rw-r--r--engine/battle/move_effects/triple_kick.asm34
-rw-r--r--engine/battle/read_trainer_attributes.asm66
-rw-r--r--engine/battle/read_trainer_party.asm374
-rw-r--r--engine/battle/returntobattle_useball.asm19
-rw-r--r--engine/battle/sliding_intro.asm57
-rw-r--r--engine/battle/trainer_huds.asm257
-rw-r--r--engine/battle/used_move_text.asm235
-rw-r--r--engine/battle_anims/pokeball_wobble.asm45
-rwxr-xr-xengine/color.asm1903
-rwxr-xr-xengine/engine_flags.asm195
-rw-r--r--engine/events/bug_contest/caught_mon.asm37
-rwxr-xr-xengine/events/bug_contest/contest.asm18
-rw-r--r--engine/events/bug_contest/contest_2.asm116
-rw-r--r--engine/events/bug_contest/judging.asm373
-rw-r--r--engine/events/checkforhiddenitems.asm83
-rw-r--r--engine/events/checktime.asm19
-rw-r--r--engine/events/daycare.asm6
-rw-r--r--engine/events/elevator.asm215
-rwxr-xr-xengine/events/engine_flags.asm83
-rw-r--r--engine/events/fish.asm121
-rwxr-xr-xengine/events/forced_movement.asm2
-rwxr-xr-xengine/events/haircut.asm8
-rwxr-xr-xengine/events/happiness_egg.asm171
-rwxr-xr-xengine/events/heal_machine_anim.asm42
-rw-r--r--[-rwxr-xr-x]engine/events/hidden_item.asm (renamed from engine/events/misc_scripts_2.asm)25
-rw-r--r--engine/events/itemfinder.asm50
-rwxr-xr-xengine/events/misc_scripts.asm16
-rw-r--r--engine/events/mom.asm676
-rw-r--r--engine/events/money.asm209
-rw-r--r--engine/events/move_deleter.asm150
-rwxr-xr-xengine/events/overworld.asm1385
-rw-r--r--engine/events/pokecenter_pc.asm658
-rw-r--r--engine/events/pokepic.asm48
-rw-r--r--engine/events/pokerus/apply_pokerus_tick.asm26
-rw-r--r--engine/events/pokerus/pokerus.asm161
-rw-r--r--engine/events/print_photo.asm50
-rw-r--r--engine/events/print_unown.asm209
-rw-r--r--engine/events/prof_oaks_pc.asm193
-rw-r--r--engine/events/repel.asm10
-rwxr-xr-xengine/events/shuckle.asm6
-rwxr-xr-xengine/events/specials.asm463
-rwxr-xr-xengine/events/std_collision.asm8
-rw-r--r--engine/events/trainer_scripts.asm31
-rw-r--r--engine/events/treemons.asm273
-rwxr-xr-xengine/events/whiteout.asm19
-rw-r--r--engine/facings.asm265
-rw-r--r--engine/games/slot_machine.asm2208
-rwxr-xr-xengine/gfx/cgb_layouts.asm865
-rwxr-xr-xengine/gfx/color.asm1260
-rw-r--r--engine/gfx/load_pics.asm428
-rw-r--r--engine/gfx/load_push_oam.asm21
-rwxr-xr-xengine/gfx/sgb_layouts.asm577
-rwxr-xr-xengine/gfx/sprite_anims.asm (renamed from engine/sprite_anims.asm)0
-rwxr-xr-xengine/gfx/sprites.asm (renamed from engine/sprites.asm)0
-rwxr-xr-xengine/items.asm551
-rw-r--r--engine/items/buy_sell_toss.asm218
-rwxr-xr-xengine/items/item_effects.asm2891
-rwxr-xr-xengine/items/items.asm581
-rw-r--r--engine/items/mart.asm811
-rwxr-xr-xengine/items/pack.asm1584
-rw-r--r--engine/items/print_item_description.asm32
-rw-r--r--engine/items/switch_items.asm272
-rw-r--r--engine/items/tmhm.asm552
-rwxr-xr-xengine/items/tmhm2.asm46
-rw-r--r--engine/items/update_item_description.asm13
-rw-r--r--engine/learn.asm220
-rwxr-xr-xengine/learn_tm.asm107
-rw-r--r--engine/link/link.asm2345
-rw-r--r--engine/link/mystery_gift.asm1077
-rw-r--r--engine/link/mystery_gift_2.asm150
-rwxr-xr-xengine/link/place_waiting_text.asm3
-rwxr-xr-xengine/main_menu.asm1093
-rwxr-xr-xengine/math/math.asm (renamed from engine/math.asm)23
-rw-r--r--engine/math/sine.asm7
-rw-r--r--engine/menus/empty_sram.asm19
-rw-r--r--engine/menus/intro_menu.asm1133
-rw-r--r--engine/menus/main_menu.asm253
-rw-r--r--engine/menus/menu.asm675
-rw-r--r--engine/menus/menu_2.asm298
-rw-r--r--engine/menus/naming_screen.asm1377
-rw-r--r--engine/menus/save.asm1092
-rw-r--r--engine/menus/scrolling_menu.asm519
-rw-r--r--engine/menus/start_menu.asm541
-rw-r--r--engine/menus/trainer_card.asm624
-rwxr-xr-xengine/movement_pattern.asm651
-rw-r--r--engine/movie/gamefreak_presents.asm28
-rw-r--r--engine/movie/title.asm192
-rw-r--r--engine/movie/trade_animation.asm1389
-rw-r--r--engine/namingscreen.asm1391
-rw-r--r--engine/overworld/decorations.asm1168
-rw-r--r--engine/overworld/events.asm1585
-rw-r--r--engine/overworld/init_map.asm96
-rw-r--r--engine/overworld/landmarks.asm82
-rw-r--r--engine/overworld/load_map_part.asm155
-rwxr-xr-xengine/overworld/map_object_action.asm276
-rwxr-xr-xengine/overworld/map_objects.asm2677
-rw-r--r--engine/overworld/map_objects_2.asm70
-rw-r--r--engine/overworld/map_setup.asm256
-rwxr-xr-xengine/overworld/movement.asm1081
-rwxr-xr-xengine/overworld/npc_movement.asm440
-rw-r--r--engine/overworld/overworld.asm494
-rwxr-xr-xengine/overworld/player_movement.asm874
-rwxr-xr-xengine/overworld/player_object.asm642
-rwxr-xr-xengine/overworld/player_step.asm241
-rw-r--r--engine/overworld/scripting.asm2673
-rw-r--r--engine/overworld/select_menu.asm172
-rw-r--r--engine/overworld/spawn_points.asm56
-rw-r--r--engine/overworld/tile_events.asm101
-rwxr-xr-xengine/overworld/time.asm275
-rwxr-xr-xengine/overworld/variables.asm122
-rw-r--r--engine/overworld/wildmons.asm971
-rwxr-xr-xengine/pack.asm1572
-rw-r--r--engine/phone/phone.asm732
-rw-r--r--engine/pokedex/pokedex_2.asm275
-rw-r--r--engine/pokegear/pokegear.asm2878
-rw-r--r--engine/pokegear/radio.asm1417
-rw-r--r--engine/pokemon/bills_pc_top.asm (renamed from engine/billspctop.asm)248
-rw-r--r--engine/pokemon/breeding.asm935
-rw-r--r--engine/pokemon/breedmon_level_growth.asm27
-rw-r--r--engine/pokemon/correct_nick_errors.asm74
-rwxr-xr-xengine/pokemon/health.asm (renamed from engine/health.asm)60
-rw-r--r--engine/pokemon/knows_move.asm24
-rw-r--r--engine/pokemon/learn.asm239
-rw-r--r--engine/pokemon/mail_2.asm901
-rw-r--r--engine/pokemon/mon_menu.asm1293
-rw-r--r--engine/pokemon/mon_submenu.asm290
-rwxr-xr-xengine/pokemon/move_mon.asm (renamed from engine/move_mon.asm)946
-rw-r--r--engine/pokemon/move_mon_wo_mail.asm133
-rw-r--r--engine/pokemon/print_move_description.asm16
-rw-r--r--engine/pokemon/search2.asm134
-rwxr-xr-xengine/predef.asm2
-rw-r--r--engine/rtc/rtc.asm210
-rw-r--r--engine/rtc/timeset.asm722
-rw-r--r--engine/sine.asm40
-rw-r--r--engine/smallflag.asm71
-rwxr-xr-xengine/specials.asm572
-rwxr-xr-xengine/step_types.asm719
-rw-r--r--engine/tilesets/map_palettes.asm110
-rwxr-xr-xengine/title.asm450
-rwxr-xr-xengine/variables.asm119
207 files changed, 77791 insertions, 13792 deletions
diff --git a/engine/battle/ai/items.asm b/engine/battle/ai/items.asm
new file mode 100644
index 00000000..0f30199e
--- /dev/null
+++ b/engine/battle/ai/items.asm
@@ -0,0 +1,824 @@
+AI_SwitchOrTryItem:
+ and a
+
+ ld a, [wBattleMode]
+ dec a
+ ret z
+
+ ld a, [wLinkMode]
+ and a
+ ret nz
+
+ farcall CheckEnemyLockedIn
+ ret nz
+
+ ld a, [wPlayerSubStatus5]
+ bit SUBSTATUS_CANT_RUN, a
+ jr nz, DontSwitch
+
+ ld a, [wEnemyWrapCount]
+ and a
+ jr nz, DontSwitch
+
+ ld a, [wTrainerClass]
+ dec a
+ ld hl, TrainerClassAttributes + TRNATTR_AI_ITEM_SWITCH
+ ld bc, NUM_TRAINER_ATTRIBUTES
+ call AddNTimes
+.ok
+ bit SWITCH_OFTEN_F, [hl]
+ jp nz, SwitchOften
+ bit SWITCH_RARELY_F, [hl]
+ jp nz, SwitchRarely
+ bit SWITCH_SOMETIMES_F, [hl]
+ jp nz, SwitchSometimes
+ ; fallthrough
+
+DontSwitch:
+ call AI_TryItem
+ ret
+
+SwitchOften:
+ callfar CheckAbleToSwitch
+ ld a, [wEnemySwitchMonParam]
+ and $f0
+ jp z, DontSwitch
+
+ cp $10
+ jr nz, .not_10
+ call Random
+ cp 50 percent + 1
+ jr c, .switch
+ jp DontSwitch
+.not_10
+
+ cp $20
+ jr nz, .not_20
+ call Random
+ cp 79 percent - 1
+ jr c, .switch
+ jp DontSwitch
+.not_20
+
+ ; $30
+ call Random
+ cp 4 percent
+ jp c, DontSwitch
+
+.switch
+ ld a, [wEnemySwitchMonParam]
+ and $f
+ inc a
+ ; In register 'a' is the number (1-6) of the mon to switch to
+ ld [wEnemySwitchMonIndex], a
+ jp AI_TrySwitch
+
+SwitchRarely:
+ callfar CheckAbleToSwitch
+ ld a, [wEnemySwitchMonParam]
+ and $f0
+ jp z, DontSwitch
+
+ cp $10
+ jr nz, .not_10
+ call Random
+ cp 8 percent
+ jr c, .switch
+ jp DontSwitch
+.not_10
+
+ cp $20
+ jr nz, .not_20
+ call Random
+ cp 12 percent
+ jr c, .switch
+ jp DontSwitch
+.not_20
+
+ ; $30
+ call Random
+ cp 79 percent - 1
+ jp c, DontSwitch
+
+.switch
+ ld a, [wEnemySwitchMonParam]
+ and $f
+ inc a
+ ld [wEnemySwitchMonIndex], a
+ jp AI_TrySwitch
+
+SwitchSometimes:
+ callfar CheckAbleToSwitch
+ ld a, [wEnemySwitchMonParam]
+ and $f0
+ jp z, DontSwitch
+
+ cp $10
+ jr nz, .not_10
+ call Random
+ cp 20 percent - 1
+ jr c, .switch
+ jp DontSwitch
+.not_10
+
+ cp $20
+ jr nz, .not_20
+ call Random
+ cp 50 percent + 1
+ jr c, .switch
+ jp DontSwitch
+.not_20
+
+ ; $30
+ call Random
+ cp 20 percent - 1
+ jp c, DontSwitch
+
+.switch
+ ld a, [wEnemySwitchMonParam]
+ and $f
+ inc a
+ ld [wEnemySwitchMonIndex], a
+ jp AI_TrySwitch
+
+CheckSubstatusCantRun:
+ ld a, [wEnemySubStatus5]
+ bit SUBSTATUS_CANT_RUN, a
+ ret
+
+AI_TryItem:
+ ld a, [wEnemyTrainerItem1]
+ ld b, a
+ ld a, [wEnemyTrainerItem2]
+ or b
+ ret z
+
+ call .IsHighestLevel
+ ret nc
+
+ ld a, [wTrainerClass]
+ dec a
+ ld hl, TrainerClassAttributes + TRNATTR_AI_ITEM_SWITCH
+ ld bc, NUM_TRAINER_ATTRIBUTES
+ call AddNTimes
+ ld b, h
+ ld c, l
+ ld hl, AI_Items
+ ld de, wEnemyTrainerItem1
+.loop
+ ld a, [hl]
+ and a
+ inc a
+ ret z
+
+ ld a, [de]
+ cp [hl]
+ jr z, .has_item
+ inc de
+ ld a, [de]
+ cp [hl]
+ jr z, .has_item
+
+ dec de
+ inc hl
+ inc hl
+ inc hl
+ jr .loop
+
+.has_item
+ inc hl
+
+ push hl
+ push de
+ ld de, .callback
+ push de
+ ld a, [hli]
+ ld h, [hl]
+ ld l, a
+ jp hl
+.callback
+ pop de
+ pop hl
+
+ inc hl
+ inc hl
+ jr c, .loop
+
+.used_item
+ xor a
+ ld [de], a
+ inc a
+ ld [wEnemyGoesFirst], a
+
+ ld hl, wEnemySubStatus3
+ res SUBSTATUS_BIDE, [hl]
+
+ xor a
+ ld [wEnemyFuryCutterCount], a
+ ld [wEnemyProtectCount], a
+ ld [wEnemyRageCounter], a
+
+ ld hl, wEnemySubStatus4
+ res SUBSTATUS_RAGE, [hl]
+
+ scf
+ ret
+
+.IsHighestLevel:
+ ld a, [wOTPartyCount]
+ ld d, a
+ ld e, 0
+ ld hl, wOTPartyMon1Level
+ ld bc, PARTYMON_STRUCT_LENGTH
+.next
+ ld a, [hl]
+ cp e
+ jr c, .ok
+ ld e, a
+.ok
+ add hl, bc
+ dec d
+ jr nz, .next
+
+ ld a, [wCurOTMon]
+ ld hl, wOTPartyMon1Level
+ call AddNTimes
+ ld a, [hl]
+ cp e
+ jr nc, .yes
+
+.no
+ and a
+ ret
+
+.yes
+ scf
+ ret
+
+AI_Items:
+ dbw FULL_RESTORE, .FullRestore
+ dbw MAX_POTION, .MaxPotion
+ dbw HYPER_POTION, .HyperPotion
+ dbw SUPER_POTION, .SuperPotion
+ dbw POTION, .Potion
+ dbw X_ACCURACY, .XAccuracy
+ dbw FULL_HEAL, .FullHeal
+ dbw GUARD_SPEC, .GuardSpec
+ dbw DIRE_HIT, .DireHit
+ dbw X_ATTACK, .XAttack
+ dbw X_DEFEND, .XDefend
+ dbw X_SPEED, .XSpeed
+ dbw X_SPECIAL, .XSpecial
+ db -1 ; end
+
+.FullHeal:
+ call .Status
+ jp c, .DontUse
+ call EnemyUsedFullHeal
+ jp .Use
+
+.Status:
+ ld a, [wEnemyMonStatus]
+ and a
+ jp z, .DontUse
+
+ ld a, [bc]
+ bit CONTEXT_USE_F, a
+ jr nz, .StatusCheckContext
+ ld a, [bc]
+ bit ALWAYS_USE_F, a
+ jp nz, .Use
+ call Random
+ cp 20 percent - 1
+ jp c, .Use
+ jp .DontUse
+
+.StatusCheckContext:
+ ld a, [wEnemySubStatus5]
+ bit SUBSTATUS_TOXIC, a
+ jr z, .FailToxicCheck
+ ld a, [wEnemyToxicCount]
+ cp 4
+ jr c, .FailToxicCheck
+ call Random
+ cp 50 percent + 1
+ jp c, .Use
+.FailToxicCheck:
+ ld a, [wEnemyMonStatus]
+ and 1 << FRZ | SLP
+ jp z, .DontUse
+ jp .Use
+
+.FullRestore:
+ call .HealItem
+ jp nc, .UseFullRestore
+ ld a, [bc]
+ bit CONTEXT_USE_F, a
+ jp z, .DontUse
+ call .Status
+ jp c, .DontUse
+
+.UseFullRestore:
+ call EnemyUsedFullRestore
+ jp .Use
+
+.MaxPotion:
+ call .HealItem
+ jp c, .DontUse
+ call EnemyUsedMaxPotion
+ jp .Use
+
+.HealItem:
+ ld a, [bc]
+ bit CONTEXT_USE_F, a
+ jr nz, .CheckHalfOrQuarterHP
+ callfar AICheckEnemyHalfHP
+ jp c, .DontUse
+ ld a, [bc]
+ bit UNKNOWN_USE_F, a
+ jp nz, .CheckQuarterHP
+ callfar AICheckEnemyQuarterHP
+ jp nc, .UseHealItem
+ call Random
+ cp 50 percent + 1
+ jp c, .UseHealItem
+ jp .DontUse
+
+.CheckQuarterHP:
+ callfar AICheckEnemyQuarterHP
+ jp c, .DontUse
+ call Random
+ cp 20 percent - 1
+ jp c, .DontUse
+ jr .UseHealItem
+
+.CheckHalfOrQuarterHP:
+ callfar AICheckEnemyHalfHP
+ jp c, .DontUse
+ callfar AICheckEnemyQuarterHP
+ jp nc, .UseHealItem
+ call Random
+ cp 20 percent - 1
+ jp nc, .DontUse
+
+.UseHealItem:
+ jp .Use
+
+.HyperPotion:
+ call .HealItem
+ jp c, .DontUse
+ ld b, 200
+ call EnemyUsedHyperPotion
+ jp .Use
+
+.SuperPotion:
+ call .HealItem
+ jp c, .DontUse
+ ld b, 50
+ call EnemyUsedSuperPotion
+ jp .Use
+
+.Potion:
+ call .HealItem
+ jp c, .DontUse
+ ld b, 20
+ call EnemyUsedPotion
+ jp .Use
+
+.asm_3829f ; This appears to be unused
+ callfar AICheckEnemyMaxHP
+ jr c, .dont_use
+ push bc
+ ld de, wEnemyMonMaxHP + 1
+ ld hl, wEnemyMonHP + 1
+ ld a, [de]
+ sub [hl]
+ jr z, .check_40_percent
+ dec hl
+ dec de
+ ld c, a
+ sbc [hl]
+ and a
+ jr nz, .check_40_percent
+ ld a, c
+ cp b
+ jp c, .check_50_percent
+ callfar AICheckEnemyQuarterHP
+ jr c, .check_40_percent
+
+.check_50_percent
+ pop bc
+ ld a, [bc]
+ bit UNKNOWN_USE_F, a
+ jp z, .Use
+ call Random
+ cp 50 percent + 1
+ jp c, .Use
+
+.dont_use
+ jp .DontUse
+
+.check_40_percent
+ pop bc
+ ld a, [bc]
+ bit UNKNOWN_USE_F, a
+ jp z, .DontUse
+ call Random
+ cp 39 percent + 1
+ jp c, .Use
+ jp .DontUse
+
+.XAccuracy:
+ call .XItem
+ jp c, .DontUse
+ call EnemyUsedXAccuracy
+ jp .Use
+
+.GuardSpec:
+ call .XItem
+ jp c, .DontUse
+ call EnemyUsedGuardSpec
+ jp .Use
+
+.DireHit:
+ call .XItem
+ jp c, .DontUse
+ call EnemyUsedDireHit
+ jp .Use
+
+.XAttack:
+ call .XItem
+ jp c, .DontUse
+ call EnemyUsedXAttack
+ jp .Use
+
+.XDefend:
+ call .XItem
+ jp c, .DontUse
+ call EnemyUsedXDefend
+ jp .Use
+
+.XSpeed:
+ call .XItem
+ jp c, .DontUse
+ call EnemyUsedXSpeed
+ jp .Use
+
+.XSpecial:
+ call .XItem
+ jp c, .DontUse
+ call EnemyUsedXSpecial
+ jp .Use
+
+.XItem:
+ ld a, [wEnemyTurnsTaken]
+ and a
+ jr nz, .notfirstturnout
+ ld a, [bc]
+ bit ALWAYS_USE_F, a
+ jp nz, .Use
+ call Random
+ cp 50 percent + 1
+ jp c, .DontUse
+ ld a, [bc]
+ bit CONTEXT_USE_F, a
+ jp nz, .Use
+ call Random
+ cp 50 percent + 1
+ jp c, .DontUse
+ jp .Use
+.notfirstturnout
+ ld a, [bc]
+ bit ALWAYS_USE_F, a
+ jp z, .DontUse
+ call Random
+ cp 20 percent - 1
+ jp nc, .DontUse
+ jp .Use
+
+.DontUse:
+ scf
+ ret
+
+.Use:
+ and a
+ ret
+
+AIUpdateHUD:
+ call UpdateEnemyMonInParty
+ farcall UpdateEnemyHUD
+ ld a, $1
+ ldh [hBGMapMode], a
+ ld hl, wEnemyItemState
+ dec [hl]
+ scf
+ ret
+
+AIUsedItemSound:
+ push de
+ ld de, SFX_FULL_HEAL
+ call PlaySFX
+ pop de
+ ret
+
+EnemyUsedFullHeal:
+ call AIUsedItemSound
+ call AI_HealStatus
+ ld a, FULL_HEAL
+ jp PrintText_UsedItemOn_AND_AIUpdateHUD
+
+EnemyUsedMaxPotion:
+ ld a, MAX_POTION
+ ld [wCurEnemyItem], a
+ jr FullRestoreContinue
+
+EnemyUsedFullRestore:
+ call AI_HealStatus
+ ld a, FULL_RESTORE
+ ld [wCurEnemyItem], a
+ ld hl, wEnemySubStatus3
+ res SUBSTATUS_CONFUSED, [hl]
+ xor a
+ ld [wEnemyConfuseCount], a
+
+FullRestoreContinue:
+ ld de, wCurHPAnimOldHP
+ ld hl, wEnemyMonHP + 1
+ ld a, [hld]
+ ld [de], a
+ inc de
+ ld a, [hl]
+ ld [de], a
+ inc de
+ ld hl, wEnemyMonMaxHP + 1
+ ld a, [hld]
+ ld [de], a
+ inc de
+ ld [wCurHPAnimMaxHP], a
+ ld [wEnemyMonHP + 1], a
+ ld a, [hl]
+ ld [de], a
+ ld [wCurHPAnimMaxHP + 1], a
+ ld [wEnemyMonHP], a
+ jr EnemyPotionFinish
+
+EnemyUsedPotion:
+ ld a, POTION
+ ld b, 20
+ jr EnemyPotionContinue
+
+EnemyUsedSuperPotion:
+ ld a, SUPER_POTION
+ ld b, 50
+ jr EnemyPotionContinue
+
+EnemyUsedHyperPotion:
+ ld a, HYPER_POTION
+ ld b, 200
+
+EnemyPotionContinue:
+ ld [wCurEnemyItem], a
+ ld hl, wEnemyMonHP + 1
+ ld a, [hl]
+ ld [wCurHPAnimOldHP], a
+ add b
+ ld [hld], a
+ ld [wCurHPAnimNewHP], a
+ ld a, [hl]
+ ld [wCurHPAnimOldHP + 1], a
+ ld [wCurHPAnimNewHP + 1], a
+ jr nc, .ok
+ inc a
+ ld [hl], a
+ ld [wCurHPAnimNewHP + 1], a
+.ok
+ inc hl
+ ld a, [hld]
+ ld b, a
+ ld de, wEnemyMonMaxHP + 1
+ ld a, [de]
+ dec de
+ ld [wCurHPAnimMaxHP], a
+ sub b
+ ld a, [hli]
+ ld b, a
+ ld a, [de]
+ ld [wCurHPAnimMaxHP + 1], a
+ sbc b
+ jr nc, EnemyPotionFinish
+ inc de
+ ld a, [de]
+ dec de
+ ld [hld], a
+ ld [wCurHPAnimNewHP], a
+ ld a, [de]
+ ld [hl], a
+ ld [wCurHPAnimNewHP + 1], a
+
+EnemyPotionFinish:
+ call PrintText_UsedItemOn
+ hlcoord 2, 2
+ xor a
+ ld [wWhichHPBar], a
+ call AIUsedItemSound
+ predef AnimateHPBar
+ jp AIUpdateHUD
+
+AI_TrySwitch:
+; Determine whether the AI can switch based on how many Pokemon are still alive.
+; If it can switch, it will.
+ ld a, [wOTPartyCount]
+ ld c, a
+ ld hl, wOTPartyMon1HP
+ ld d, 0
+.SwitchLoop:
+ ld a, [hli]
+ ld b, a
+ ld a, [hld]
+ or b
+ jr z, .fainted
+ inc d
+.fainted
+ push bc
+ ld bc, PARTYMON_STRUCT_LENGTH
+ add hl, bc
+ pop bc
+ dec c
+ jr nz, .SwitchLoop
+
+ ld a, d
+ cp 2
+ jp nc, AI_Switch
+ and a
+ ret
+
+AI_Switch:
+ ld a, $1
+ ld [wEnemyIsSwitching], a
+ ld [wEnemyGoesFirst], a
+ ld hl, wEnemySubStatus4
+ res SUBSTATUS_RAGE, [hl]
+ xor a
+ ldh [hBattleTurn], a
+ callfar PursuitSwitch
+
+ push af
+ ld a, [wCurOTMon]
+ ld hl, wOTPartyMon1Status
+ ld bc, PARTYMON_STRUCT_LENGTH
+ call AddNTimes
+ ld d, h
+ ld e, l
+ ld hl, wEnemyMonStatus
+ ld bc, MON_MAXHP - MON_STATUS
+ call CopyBytes
+ pop af
+
+ jr c, .skiptext
+ ld hl, EnemyWithdrewText
+ call PrintText
+
+.skiptext
+ ld a, 1
+ ld [wBattleHasJustStarted], a
+ callfar NewEnemyMonStatus
+ callfar ResetEnemyStatLevels
+ ld hl, wPlayerSubStatus1
+ res SUBSTATUS_IN_LOVE, [hl]
+ farcall EnemySwitch
+ farcall ResetBattleParticipants
+ xor a
+ ld [wBattleHasJustStarted], a
+ ld a, [wLinkMode]
+ cp LINK_COLOSSEUM
+ ret z
+ scf
+ ret
+
+EnemyWithdrewText:
+ text_far _EnemyWithdrewText
+ text_end
+
+Function384c7: ; This appears to be unused
+ call AIUsedItemSound
+ call AI_HealStatus
+ ld a, FULL_HEAL_RED ; X_SPEED
+ jp PrintText_UsedItemOn_AND_AIUpdateHUD
+
+AI_HealStatus:
+ ld a, [wCurOTMon]
+ ld hl, wOTPartyMon1Status
+ ld bc, PARTYMON_STRUCT_LENGTH
+ call AddNTimes
+ xor a
+ ld [hl], a
+ ld [wEnemyMonStatus], a
+ ; Bug: this should reset SUBSTATUS_NIGHTMARE
+ ; Uncomment the 2 lines below to fix
+ ; ld hl, wEnemySubStatus1
+ ; res SUBSTATUS_NIGHTMARE, [hl]
+ ; Bug: this should reset SUBSTATUS_CONFUSED
+ ; Uncomment the 2 lines below to fix
+ ; ld hl, wEnemySubStatus3
+ ; res SUBSTATUS_CONFUSED, [hl]
+ ld hl, wEnemySubStatus5
+ res SUBSTATUS_TOXIC, [hl]
+ ret
+
+EnemyUsedXAccuracy:
+ call AIUsedItemSound
+ ld hl, wEnemySubStatus4
+ set SUBSTATUS_X_ACCURACY, [hl]
+ ld a, X_ACCURACY
+ jp PrintText_UsedItemOn_AND_AIUpdateHUD
+
+EnemyUsedGuardSpec:
+ call AIUsedItemSound
+ ld hl, wEnemySubStatus4
+ set SUBSTATUS_MIST, [hl]
+ ld a, GUARD_SPEC
+ jp PrintText_UsedItemOn_AND_AIUpdateHUD
+
+EnemyUsedDireHit:
+ call AIUsedItemSound
+ ld hl, wEnemySubStatus4
+ set SUBSTATUS_FOCUS_ENERGY, [hl]
+ ld a, DIRE_HIT
+ jp PrintText_UsedItemOn_AND_AIUpdateHUD
+
+Function38510: ; This appears to be unused
+ ldh [hDivisor], a
+ ld hl, wEnemyMonMaxHP
+ ld a, [hli]
+ ldh [hDividend], a
+ ld a, [hl]
+ ldh [hDividend + 1], a
+ ld b, 2
+ call Divide
+ ldh a, [hQuotient + 3]
+ ld c, a
+ ldh a, [hQuotient + 2]
+ ld b, a
+ ld hl, wEnemyMonHP + 1
+ ld a, [hld]
+ ld e, a
+ ld a, [hl]
+ ld d, a
+ ld a, d
+ sub b
+ ret nz
+ ld a, e
+ sub c
+ ret
+
+EnemyUsedXAttack:
+ ld b, ATTACK
+ ld a, X_ATTACK
+ jr EnemyUsedXItem
+
+EnemyUsedXDefend:
+ ld b, DEFENSE
+ ld a, X_DEFEND
+ jr EnemyUsedXItem
+
+EnemyUsedXSpeed:
+ ld b, SPEED
+ ld a, X_SPEED
+ jr EnemyUsedXItem
+
+EnemyUsedXSpecial:
+ ld b, SP_ATTACK
+ ld a, X_SPECIAL
+
+; Parameter
+; a = ITEM_CONSTANT
+; b = BATTLE_CONSTANT (ATTACK, DEFENSE, SPEED, SP_ATTACK, SP_DEFENSE, ACCURACY, EVASION)
+EnemyUsedXItem:
+ ld [wCurEnemyItem], a
+ push bc
+ call PrintText_UsedItemOn
+ pop bc
+ farcall RaiseStat
+ jp AIUpdateHUD
+
+; Parameter
+; a = ITEM_CONSTANT
+PrintText_UsedItemOn_AND_AIUpdateHUD:
+ ld [wCurEnemyItem], a
+ call PrintText_UsedItemOn
+ jp AIUpdateHUD
+
+PrintText_UsedItemOn:
+ ld a, [wCurEnemyItem]
+ ld [wNamedObjectIndexBuffer], a
+ call GetItemName
+ ld hl, wStringBuffer1
+ ld de, wMonOrItemNameBuffer
+ ld bc, ITEM_NAME_LENGTH
+ call CopyBytes
+ ld hl, EnemyUsedOnText
+ jp PrintText
+
+EnemyUsedOnText:
+ text_far _EnemyUsedOnText
+ text_end
diff --git a/engine/battle/ai/move.asm b/engine/battle/ai/move.asm
new file mode 100644
index 00000000..060761a0
--- /dev/null
+++ b/engine/battle/ai/move.asm
@@ -0,0 +1,208 @@
+AIChooseMove:
+; Score each move in wEnemyMonMoves starting from wBuffer1. Lower is better.
+; Pick the move with the lowest score.
+
+; Wildmons attack at random.
+ ld a, [wBattleMode]
+ dec a
+ ret z
+
+ ld a, [wLinkMode]
+ and a
+ ret nz
+
+; No use picking a move if there's no choice.
+ farcall CheckEnemyLockedIn
+ ret nz
+
+; The default score is 20. Unusable moves are given a score of 80.
+ ld a, 20
+ ld hl, wBuffer1
+ ld [hli], a
+ ld [hli], a
+ ld [hli], a
+ ld [hl], a
+
+; Don't pick disabled moves.
+ ld a, [wEnemyDisabledMove]
+ and a
+ jr z, .CheckPP
+
+ ld hl, wEnemyMonMoves
+ ld c, 0
+.CheckDisabledMove:
+ cp [hl]
+ jr z, .ScoreDisabledMove
+ inc c
+ inc hl
+ jr .CheckDisabledMove
+.ScoreDisabledMove:
+ ld hl, wBuffer1
+ ld b, 0
+ add hl, bc
+ ld [hl], 80
+
+; Don't pick moves with 0 PP.
+.CheckPP:
+ ld hl, wBuffer1 - 1
+ ld de, wEnemyMonPP
+ ld b, 0
+.CheckMovePP:
+ inc b
+ ld a, b
+ cp wEnemyMonMovesEnd - wEnemyMonMoves + 1
+ jr z, .ApplyLayers
+ inc hl
+ ld a, [de]
+ inc de
+ and PP_MASK
+ jr nz, .CheckMovePP
+ ld [hl], 80
+ jr .CheckMovePP
+
+; Apply AI scoring layers depending on the trainer class.
+.ApplyLayers:
+ ld hl, TrainerClassAttributes + TRNATTR_AI_MOVE_WEIGHTS
+ ld a, [wTrainerClass]
+ dec a
+ ld bc, 7 ; Trainer2AI - Trainer1AI
+ call AddNTimes
+ lb bc, CHECK_FLAG, 0
+ push bc
+ push hl
+
+.CheckLayer:
+ pop hl
+ pop bc
+
+ ld a, c
+ cp 16 ; up to 16 scoring layers
+ jr z, .DecrementScores
+
+ push bc
+ ld d, BANK(TrainerClassAttributes)
+ predef SmallFarFlagAction
+ ld d, c
+ pop bc
+
+ inc c
+ push bc
+ push hl
+
+ ld a, d
+ and a
+ jr z, .CheckLayer
+
+ ld hl, AIScoringPointers
+ dec c
+ ld b, 0
+ add hl, bc
+ add hl, bc
+ ld a, [hli]
+ ld h, [hl]
+ ld l, a
+ ld a, BANK(AIScoring)
+ call FarCall_hl
+
+ jr .CheckLayer
+
+; Decrement the scores of all moves one by one until one reaches 0.
+.DecrementScores:
+ ld hl, wBuffer1
+ ld de, wEnemyMonMoves
+ ld c, wEnemyMonMovesEnd - wEnemyMonMoves
+
+.DecrementNextScore:
+ ; If the enemy has no moves, this will infinite.
+ ld a, [de]
+ inc de
+ and a
+ jr z, .DecrementScores
+
+ ; We are done whenever a score reaches 0
+ dec [hl]
+ jr z, .PickLowestScoreMoves
+
+ ; If we just decremented the fourth move's score, go back to the first move
+ inc hl
+ dec c
+ jr z, .DecrementScores
+
+ jr .DecrementNextScore
+
+; In order to avoid bias towards the moves located first in memory, increment the scores
+; that were decremented one more time than the rest (in case there was a tie).
+; This means that the minimum score will be 1.
+.PickLowestScoreMoves:
+ ld a, c
+
+.move_loop
+ inc [hl]
+ dec hl
+ inc a
+ cp NUM_MOVES + 1
+ jr nz, .move_loop
+
+ ld hl, wBuffer1
+ ld de, wEnemyMonMoves
+ ld c, NUM_MOVES
+
+; Give a score of 0 to a blank move
+.loop2
+ ld a, [de]
+ and a
+ jr nz, .skip_load
+ ld [hl], a
+
+; Disregard the move if its score is not 1
+.skip_load
+ ld a, [hl]
+ dec a
+ jr z, .keep
+ xor a
+ ld [hli], a
+ jr .after_toss
+
+.keep
+ ld a, [de]
+ ld [hli], a
+.after_toss
+ inc de
+ dec c
+ jr nz, .loop2
+
+; Randomly choose one of the moves with a score of 1
+.ChooseMove:
+ ld hl, wBuffer1
+ call Random
+ maskbits NUM_MOVES
+ ld c, a
+ ld b, 0
+ add hl, bc
+ ld a, [hl]
+ and a
+ jr z, .ChooseMove
+
+ ld [wCurEnemyMove], a
+ ld a, c
+ ld [wCurEnemyMoveNum], a
+ ret
+
+AIScoringPointers:
+; entries correspond to AI_* constants
+ dw AI_Basic
+ dw AI_Setup
+ dw AI_Types
+ dw AI_Offensive
+ dw AI_Smart
+ dw AI_Opportunist
+ dw AI_Aggressive
+ dw AI_Cautious
+ dw AI_Status
+ dw AI_Risky
+ dw AI_None
+ dw AI_None
+ dw AI_None
+ dw AI_None
+ dw AI_None
+ dw AI_None
diff --git a/engine/battle/ai/redundant.asm b/engine/battle/ai/redundant.asm
new file mode 100644
index 00000000..d78fccb8
--- /dev/null
+++ b/engine/battle/ai/redundant.asm
@@ -0,0 +1,198 @@
+AI_Redundant:
+; Check if move effect c will fail because it's already been used.
+; Return z if the move is a good choice.
+; Return nz if the move is a bad choice.
+ ld a, c
+ ld de, 3
+ ld hl, .Moves
+ call IsInArray
+ jp nc, .NotRedundant
+ inc hl
+ ld a, [hli]
+ ld h, [hl]
+ ld l, a
+ jp hl
+
+.Moves:
+ dbw EFFECT_DREAM_EATER, .DreamEater
+ dbw EFFECT_HEAL, .Heal
+ dbw EFFECT_LIGHT_SCREEN, .LightScreen
+ dbw EFFECT_MIST, .Mist
+ dbw EFFECT_FOCUS_ENERGY, .FocusEnergy
+ dbw EFFECT_CONFUSE, .Confuse
+ dbw EFFECT_TRANSFORM, .Transform
+ dbw EFFECT_REFLECT, .Reflect
+ dbw EFFECT_SUBSTITUTE, .Substitute
+ dbw EFFECT_LEECH_SEED, .LeechSeed
+ dbw EFFECT_DISABLE, .Disable
+ dbw EFFECT_ENCORE, .Encore
+ dbw EFFECT_SNORE, .Snore
+ dbw EFFECT_SLEEP_TALK, .SleepTalk
+ dbw EFFECT_MEAN_LOOK, .MeanLook
+ dbw EFFECT_NIGHTMARE, .Nightmare
+ dbw EFFECT_SPIKES, .Spikes
+ dbw EFFECT_FORESIGHT, .Foresight
+ dbw EFFECT_PERISH_SONG, .PerishSong
+ dbw EFFECT_SANDSTORM, .Sandstorm
+ dbw EFFECT_ATTRACT, .Attract
+ dbw EFFECT_SAFEGUARD, .Safeguard
+ dbw EFFECT_RAIN_DANCE, .RainDance
+ dbw EFFECT_SUNNY_DAY, .SunnyDay
+ dbw EFFECT_TELEPORT, .Teleport
+ dbw EFFECT_MORNING_SUN, .MorningSun
+ dbw EFFECT_SYNTHESIS, .Synthesis
+ dbw EFFECT_MOONLIGHT, .Moonlight
+ dbw EFFECT_SWAGGER, .Swagger
+ dbw EFFECT_FUTURE_SIGHT, .FutureSight
+ db -1
+
+.LightScreen:
+ ld a, [wEnemyScreens]
+ bit SCREENS_LIGHT_SCREEN, a
+ ret
+
+.Mist:
+ ld a, [wEnemySubStatus4]
+ bit SUBSTATUS_MIST, a
+ ret
+
+.FocusEnergy:
+ ld a, [wEnemySubStatus4]
+ bit SUBSTATUS_FOCUS_ENERGY, a
+ ret
+
+.Confuse:
+ ld a, [wPlayerSubStatus3]
+ bit SUBSTATUS_CONFUSED, a
+ ret nz
+ ld a, [wPlayerScreens]
+ bit SCREENS_SAFEGUARD, a
+ ret
+
+.Transform:
+ ld a, [wEnemySubStatus5]
+ bit SUBSTATUS_TRANSFORMED, a
+ ret
+
+.Reflect:
+ ld a, [wEnemyScreens]
+ bit SCREENS_REFLECT, a
+ ret
+
+.Substitute:
+ ld a, [wEnemySubStatus4]
+ bit SUBSTATUS_SUBSTITUTE, a
+ ret
+
+.LeechSeed:
+ ld a, [wPlayerSubStatus4]
+ bit SUBSTATUS_LEECH_SEED, a
+ ret
+
+.Disable:
+ ld a, [wPlayerDisableCount]
+ and a
+ ret
+
+.Encore:
+ ld a, [wPlayerSubStatus5]
+ bit SUBSTATUS_ENCORED, a
+ ret
+
+.Snore:
+.SleepTalk:
+ ld a, [wEnemyMonStatus]
+ and SLP
+ jr z, .Redundant
+ jr .NotRedundant
+
+.MeanLook:
+ ld a, [wEnemySubStatus5]
+ bit SUBSTATUS_CANT_RUN, a
+ ret
+
+.Nightmare:
+ ld a, [wBattleMonStatus]
+ and a
+ jr z, .Redundant
+ ld a, [wPlayerSubStatus1]
+ bit SUBSTATUS_NIGHTMARE, a
+ ret
+
+.Spikes:
+ ld a, [wPlayerScreens]
+ bit SCREENS_SPIKES, a
+ ret
+
+.Foresight:
+ ld a, [wPlayerSubStatus1]
+ bit SUBSTATUS_IDENTIFIED, a
+ ret
+
+.PerishSong:
+ ld a, [wPlayerSubStatus1]
+ bit SUBSTATUS_PERISH, a
+ ret
+
+.Sandstorm:
+ ld a, [wBattleWeather]
+ cp WEATHER_SANDSTORM
+ jr z, .Redundant
+ jr .NotRedundant
+
+.Attract:
+ farcall CheckOppositeGender
+ jr c, .Redundant
+ ld a, [wPlayerSubStatus1]
+ bit SUBSTATUS_IN_LOVE, a
+ ret
+
+.Safeguard:
+ ld a, [wEnemyScreens]
+ bit SCREENS_SAFEGUARD, a
+ ret
+
+.RainDance:
+ ld a, [wBattleWeather]
+ cp WEATHER_RAIN
+ jr z, .Redundant
+ jr .NotRedundant
+
+.SunnyDay:
+ ld a, [wBattleWeather]
+ cp WEATHER_SUN
+ jr z, .Redundant
+ jr .NotRedundant
+
+.DreamEater:
+ ld a, [wBattleMonStatus]
+ and SLP
+ jr z, .Redundant
+ jr .NotRedundant
+
+.Swagger:
+ ld a, [wPlayerSubStatus3]
+ bit SUBSTATUS_CONFUSED, a
+ ret
+
+.FutureSight:
+ ld a, [wEnemyScreens]
+ bit 5, a
+ ret
+
+.Heal:
+.MorningSun:
+.Synthesis:
+.Moonlight:
+ farcall AICheckEnemyMaxHP
+ jr nc, .NotRedundant
+
+.Teleport:
+.Redundant:
+ ld a, 1
+ and a
+ ret
+
+.NotRedundant:
+ xor a
+ ret
diff --git a/engine/battle/ai/scoring.asm b/engine/battle/ai/scoring.asm
new file mode 100644
index 00000000..bfb9c282
--- /dev/null
+++ b/engine/battle/ai/scoring.asm
@@ -0,0 +1,3208 @@
+AIScoring: ; used only for BANK(AIScoring)
+
+
+AI_Basic:
+; Don't do anything redundant:
+; -Using status-only moves if the player can't be statused
+; -Using moves that fail if they've already been used
+
+ ld hl, wBuffer1 - 1
+ ld de, wEnemyMonMoves
+ ld b, wEnemyMonMovesEnd - wEnemyMonMoves + 1
+.checkmove
+ dec b
+ ret z
+
+ inc hl
+ ld a, [de]
+ and a
+ ret z
+
+ inc de
+ call AIGetEnemyMove
+
+ ld a, [wEnemyMoveStruct + MOVE_EFFECT]
+ ld c, a
+
+; Dismiss moves with special effects if they are
+; useless or not a good choice right now.
+; For example, healing moves, weather moves, Dream Eater...
+ push hl
+ push de
+ push bc
+ farcall AI_Redundant
+ pop bc
+ pop de
+ pop hl
+ jr nz, .discourage
+
+; Dismiss status-only moves if the player can't be statused.
+ ld a, [wEnemyMoveStruct + MOVE_EFFECT]
+ push hl
+ push de
+ push bc
+ ld hl, StatusOnlyEffects
+ ld de, 1
+ call IsInArray
+
+ pop bc
+ pop de
+ pop hl
+ jr nc, .checkmove
+
+ ld a, [wBattleMonStatus]
+ and a
+ jr nz, .discourage
+
+; Dismiss Safeguard if it's already active.
+ ld a, [wPlayerScreens]
+ bit SCREENS_SAFEGUARD, a
+ jr z, .checkmove
+
+.discourage
+ call AIDiscourageMove
+ jr .checkmove
+
+INCLUDE "data/battle/ai/status_only_effects.asm"
+
+
+AI_Setup:
+; Use stat-modifying moves on turn 1.
+
+; 50% chance to greatly encourage stat-up moves during the first turn of enemy's Pokemon.
+; 50% chance to greatly encourage stat-down moves during the first turn of player's Pokemon.
+; Almost 90% chance to greatly discourage stat-modifying moves otherwise.
+
+ ld hl, wBuffer1 - 1
+ ld de, wEnemyMonMoves
+ ld b, wEnemyMonMovesEnd - wEnemyMonMoves + 1
+.checkmove
+ dec b
+ ret z
+
+ inc hl
+ ld a, [de]
+ and a
+ ret z
+
+ inc de
+ call AIGetEnemyMove
+
+ ld a, [wEnemyMoveStruct + MOVE_EFFECT]
+
+ cp EFFECT_ATTACK_UP
+ jr c, .checkmove
+ cp EFFECT_EVASION_UP + 1
+ jr c, .statup
+
+; cp EFFECT_ATTACK_DOWN - 1
+ jr z, .checkmove
+ cp EFFECT_EVASION_DOWN + 1
+ jr c, .statdown
+
+ cp EFFECT_ATTACK_UP_2
+ jr c, .checkmove
+ cp EFFECT_EVASION_UP_2 + 1
+ jr c, .statup
+
+; cp EFFECT_ATTACK_DOWN_2 - 1
+ jr z, .checkmove
+ cp EFFECT_EVASION_DOWN_2 + 1
+ jr c, .statdown
+
+ jr .checkmove
+
+.statup
+ ld a, [wEnemyTurnsTaken]
+ and a
+ jr nz, .discourage
+
+ jr .encourage
+
+.statdown
+ ld a, [wPlayerTurnsTaken]
+ and a
+ jr nz, .discourage
+
+.encourage
+ call AI_50_50
+ jr c, .checkmove
+
+ dec [hl]
+ dec [hl]
+ jr .checkmove
+
+.discourage
+ call Random
+ cp 12 percent
+ jr c, .checkmove
+ inc [hl]
+ inc [hl]
+ jr .checkmove
+
+
+AI_Types:
+; Dismiss any move that the player is immune to.
+; Encourage super-effective moves.
+; Discourage not very effective moves unless
+; all damaging moves are of the same type.
+
+ ld hl, wBuffer1 - 1
+ ld de, wEnemyMonMoves
+ ld b, wEnemyMonMovesEnd - wEnemyMonMoves + 1
+.checkmove
+ dec b
+ ret z
+
+ inc hl
+ ld a, [de]
+ and a
+ ret z
+
+ inc de
+ call AIGetEnemyMove
+
+ push hl
+ push bc
+ push de
+ ld a, 1
+ ldh [hBattleTurn], a
+ callfar BattleCheckTypeMatchup
+ pop de
+ pop bc
+ pop hl
+
+ ld a, [wTypeMatchup]
+ and a
+ jr z, .immune
+ cp EFFECTIVE
+ jr z, .checkmove
+ jr c, .noteffective
+
+; effective
+ ld a, [wEnemyMoveStruct + MOVE_POWER]
+ and a
+ jr z, .checkmove
+ dec [hl]
+ jr .checkmove
+
+.noteffective
+; Discourage this move if there are any moves
+; that do damage of a different type.
+ push hl
+ push de
+ push bc
+ ld a, [wEnemyMoveStruct + MOVE_TYPE]
+ ld d, a
+ ld hl, wEnemyMonMoves
+ ld b, wEnemyMonMovesEnd - wEnemyMonMoves + 1
+ ld c, 0
+.checkmove2
+ dec b
+ jr z, .asm_38685
+
+ ld a, [hli]
+ and a
+ jr z, .asm_38685
+
+ call AIGetEnemyMove
+ ld a, [wEnemyMoveStruct + MOVE_TYPE]
+ cp d
+ jr z, .checkmove2
+ ld a, [wEnemyMoveStruct + MOVE_POWER]
+ and a
+ jr nz, .asm_38684
+ jr .checkmove2
+
+.asm_38684
+ ld c, a
+.asm_38685
+ ld a, c
+ pop bc
+ pop de
+ pop hl
+ and a
+ jr z, .checkmove
+ inc [hl]
+ jr .checkmove
+
+.immune
+ call AIDiscourageMove
+ jr .checkmove
+
+
+AI_Offensive:
+; Greatly discourage non-damaging moves.
+
+ ld hl, wBuffer1 - 1
+ ld de, wEnemyMonMoves
+ ld b, wEnemyMonMovesEnd - wEnemyMonMoves + 1
+.checkmove
+ dec b
+ ret z
+
+ inc hl
+ ld a, [de]
+ and a
+ ret z
+
+ inc de
+ call AIGetEnemyMove
+
+ ld a, [wEnemyMoveStruct + MOVE_POWER]
+ and a
+ jr nz, .checkmove
+
+ inc [hl]
+ inc [hl]
+ jr .checkmove
+
+
+AI_Smart:
+; Context-specific scoring.
+
+ ld hl, wBuffer1
+ ld de, wEnemyMonMoves
+ ld b, wEnemyMonMovesEnd - wEnemyMonMoves + 1
+.checkmove
+ dec b
+ ret z
+
+ ld a, [de]
+ inc de
+ and a
+ ret z
+
+ push de
+ push bc
+ push hl
+ call AIGetEnemyMove
+
+ ld a, [wEnemyMoveStruct + MOVE_EFFECT]
+ ld hl, .table_386e4
+ ld de, 3
+ call IsInArray
+
+ inc hl
+ jr nc, .nextmove
+
+ ld a, [hli]
+ ld e, a
+ ld d, [hl]
+
+ pop hl
+ push hl
+
+ ld bc, .nextmove
+ push bc
+
+ push de
+ ret
+
+.nextmove
+ pop hl
+ pop bc
+ pop de
+ inc hl
+ jr .checkmove
+
+.table_386e4
+ dbw EFFECT_SLEEP, AI_Smart_Sleep
+ dbw EFFECT_LEECH_HIT, AI_Smart_LeechHit
+ dbw EFFECT_SELFDESTRUCT, AI_Smart_Selfdestruct
+ dbw EFFECT_DREAM_EATER, AI_Smart_DreamEater
+ dbw EFFECT_MIRROR_MOVE, AI_Smart_MirrorMove
+ dbw EFFECT_EVASION_UP, AI_Smart_EvasionUp
+ dbw EFFECT_ALWAYS_HIT, AI_Smart_AlwaysHit
+ dbw EFFECT_ACCURACY_DOWN, AI_Smart_AccuracyDown
+ dbw EFFECT_RESET_STATS, AI_Smart_ResetStats
+ dbw EFFECT_BIDE, AI_Smart_Bide
+ dbw EFFECT_FORCE_SWITCH, AI_Smart_ForceSwitch
+ dbw EFFECT_HEAL, AI_Smart_Heal
+ dbw EFFECT_TOXIC, AI_Smart_Toxic
+ dbw EFFECT_LIGHT_SCREEN, AI_Smart_LightScreen
+ dbw EFFECT_OHKO, AI_Smart_Ohko
+ dbw EFFECT_RAZOR_WIND, AI_Smart_RazorWind
+ dbw EFFECT_SUPER_FANG, AI_Smart_SuperFang
+ dbw EFFECT_TRAP_TARGET, AI_Smart_TrapTarget
+ dbw EFFECT_UNUSED_2B, AI_Smart_Unused2B
+ dbw EFFECT_CONFUSE, AI_Smart_Confuse
+ dbw EFFECT_SP_DEF_UP_2, AI_Smart_SpDefenseUp2
+ dbw EFFECT_REFLECT, AI_Smart_Reflect
+ dbw EFFECT_PARALYZE, AI_Smart_Paralyze
+ dbw EFFECT_SPEED_DOWN_HIT, AI_Smart_SpeedDownHit
+ dbw EFFECT_SUBSTITUTE, AI_Smart_Substitute
+ dbw EFFECT_HYPER_BEAM, AI_Smart_HyperBeam
+ dbw EFFECT_RAGE, AI_Smart_Rage
+ dbw EFFECT_MIMIC, AI_Smart_Mimic
+ dbw EFFECT_LEECH_SEED, AI_Smart_LeechSeed
+ dbw EFFECT_DISABLE, AI_Smart_Disable
+ dbw EFFECT_COUNTER, AI_Smart_Counter
+ dbw EFFECT_ENCORE, AI_Smart_Encore
+ dbw EFFECT_PAIN_SPLIT, AI_Smart_PainSplit
+ dbw EFFECT_SNORE, AI_Smart_Snore
+ dbw EFFECT_CONVERSION2, AI_Smart_Conversion2
+ dbw EFFECT_LOCK_ON, AI_Smart_LockOn
+ dbw EFFECT_DEFROST_OPPONENT, AI_Smart_DefrostOpponent
+ dbw EFFECT_SLEEP_TALK, AI_Smart_SleepTalk
+ dbw EFFECT_DESTINY_BOND, AI_Smart_DestinyBond
+ dbw EFFECT_REVERSAL, AI_Smart_Reversal
+ dbw EFFECT_SPITE, AI_Smart_Spite
+ dbw EFFECT_HEAL_BELL, AI_Smart_HealBell
+ dbw EFFECT_PRIORITY_HIT, AI_Smart_PriorityHit
+ dbw EFFECT_THIEF, AI_Smart_Thief
+ dbw EFFECT_MEAN_LOOK, AI_Smart_MeanLook
+ dbw EFFECT_NIGHTMARE, AI_Smart_Nightmare
+ dbw EFFECT_FLAME_WHEEL, AI_Smart_FlameWheel
+ dbw EFFECT_CURSE, AI_Smart_Curse
+ dbw EFFECT_PROTECT, AI_Smart_Protect
+ dbw EFFECT_FORESIGHT, AI_Smart_Foresight
+ dbw EFFECT_PERISH_SONG, AI_Smart_PerishSong
+ dbw EFFECT_SANDSTORM, AI_Smart_Sandstorm
+ dbw EFFECT_ENDURE, AI_Smart_Endure
+ dbw EFFECT_ROLLOUT, AI_Smart_Rollout
+ dbw EFFECT_SWAGGER, AI_Smart_Swagger
+ dbw EFFECT_FURY_CUTTER, AI_Smart_FuryCutter
+ dbw EFFECT_ATTRACT, AI_Smart_Attract
+ dbw EFFECT_SAFEGUARD, AI_Smart_Safeguard
+ dbw EFFECT_MAGNITUDE, AI_Smart_Magnitude
+ dbw EFFECT_BATON_PASS, AI_Smart_BatonPass
+ dbw EFFECT_PURSUIT, AI_Smart_Pursuit
+ dbw EFFECT_RAPID_SPIN, AI_Smart_RapidSpin
+ dbw EFFECT_MORNING_SUN, AI_Smart_MorningSun
+ dbw EFFECT_SYNTHESIS, AI_Smart_Synthesis
+ dbw EFFECT_MOONLIGHT, AI_Smart_Moonlight
+ dbw EFFECT_HIDDEN_POWER, AI_Smart_HiddenPower
+ dbw EFFECT_RAIN_DANCE, AI_Smart_RainDance
+ dbw EFFECT_SUNNY_DAY, AI_Smart_SunnyDay
+ dbw EFFECT_BELLY_DRUM, AI_Smart_BellyDrum
+ dbw EFFECT_PSYCH_UP, AI_Smart_PsychUp
+ dbw EFFECT_MIRROR_COAT, AI_Smart_MirrorCoat
+ dbw EFFECT_SKULL_BASH, AI_Smart_SkullBash
+ dbw EFFECT_TWISTER, AI_Smart_Twister
+ dbw EFFECT_EARTHQUAKE, AI_Smart_Earthquake
+ dbw EFFECT_FUTURE_SIGHT, AI_Smart_FutureSight
+ dbw EFFECT_GUST, AI_Smart_Gust
+ dbw EFFECT_STOMP, AI_Smart_Stomp
+ dbw EFFECT_SOLARBEAM, AI_Smart_Solarbeam
+ dbw EFFECT_THUNDER, AI_Smart_Thunder
+ dbw EFFECT_FLY, AI_Smart_Fly
+ db -1 ; end
+
+AI_Smart_Sleep:
+; Greatly encourage sleep inducing moves if the enemy has either Dream Eater or Nightmare.
+; 50% chance to greatly encourage sleep inducing moves otherwise.
+
+ ld b, EFFECT_DREAM_EATER
+ call AIHasMoveEffect
+ jr c, .asm_387e2
+
+ ld b, EFFECT_NIGHTMARE
+ call AIHasMoveEffect
+ ret nc
+
+.asm_387e2
+ call AI_50_50
+ ret c
+ dec [hl]
+ dec [hl]
+ ret
+
+AI_Smart_LeechHit:
+ push hl
+ ld a, 1
+ ldh [hBattleTurn], a
+ callfar BattleCheckTypeMatchup
+ pop hl
+
+; 60% chance to discourage this move if not very effective.
+ ld a, [wTypeMatchup]
+ cp EFFECTIVE
+ jr c, .asm_38807
+
+; Do nothing if effectiveness is neutral.
+ ret z
+
+; Do nothing if enemy's HP is full.
+ call AICheckEnemyMaxHP
+ ret c
+
+; 80% chance to encourage this move otherwise.
+ call AI_80_20
+ ret c
+
+ dec [hl]
+ ret
+
+.asm_38807
+ call Random
+ cp 39 percent + 1
+ ret c
+
+ inc [hl]
+ ret
+
+AI_Smart_LockOn:
+ ld a, [wPlayerSubStatus5]
+ bit SUBSTATUS_LOCK_ON, a
+ jr nz, .asm_38874
+
+ push hl
+ call AICheckEnemyQuarterHP
+ jr nc, .asm_38869
+
+ call AICheckEnemyHalfHP
+ jr c, .asm_38826
+
+ call AICompareSpeed
+ jr nc, .asm_38869
+
+.asm_38826
+ ld a, [wPlayerEvaLevel]
+ cp BASE_STAT_LEVEL + 3
+ jr nc, .asm_3886c
+ cp BASE_STAT_LEVEL + 1
+ jr nc, .asm_38867
+
+ ld a, [wEnemyAccLevel]
+ cp BASE_STAT_LEVEL - 2
+ jr c, .asm_3886c
+ cp BASE_STAT_LEVEL
+ jr c, .asm_38867
+
+ ld hl, wEnemyMonMoves
+ ld c, wEnemyMonMovesEnd - wEnemyMonMoves + 1
+.asm_38841
+ dec c
+ jr z, .asm_38869
+
+ ld a, [hli]
+ and a
+ jr z, .asm_38869
+
+ call AIGetEnemyMove
+
+ ld a, [wEnemyMoveStruct + MOVE_ACC]
+ cp 180
+ jr nc, .asm_38841
+
+ ld a, $1
+ ldh [hBattleTurn], a
+
+ push hl
+ push bc
+ farcall BattleCheckTypeMatchup
+ ld a, [wTypeMatchup]
+ cp EFFECTIVE
+ pop bc
+ pop hl
+ jr c, .asm_38841
+
+.asm_38867
+ pop hl
+ ret
+
+.asm_38869
+ pop hl
+ inc [hl]
+ ret
+
+.asm_3886c
+ pop hl
+ call AI_50_50
+ ret c
+
+ dec [hl]
+ dec [hl]
+ ret
+
+.asm_38874
+ push hl
+ ld hl, wBuffer1 - 1
+ ld de, wEnemyMonMoves
+ ld c, wEnemyMonMovesEnd - wEnemyMonMoves + 1
+
+.asm_3887d
+ inc hl
+ dec c
+ jr z, .asm_38894
+
+ ld a, [de]
+ and a
+ jr z, .asm_38894
+
+ inc de
+ call AIGetEnemyMove
+
+ ld a, [wEnemyMoveStruct + MOVE_ACC]
+ cp 180
+ jr nc, .asm_3887d
+
+ dec [hl]
+ dec [hl]
+ jr .asm_3887d
+
+.asm_38894
+ pop hl
+ jp AIDiscourageMove
+
+AI_Smart_Selfdestruct:
+; Selfdestruct, Explosion
+
+; Greatly discourage this move if enemy's HP is above 50%.
+ call AICheckEnemyHalfHP
+ jr c, .asm_388a7
+
+; Do nothing if enemy's HP is below 25%.
+ call AICheckEnemyQuarterHP
+ ret nc
+
+; If enemy's HP is between 25% and 50%,
+; over 90% chance to greatly discourage this move.
+ call Random
+ cp 8 percent
+ ret c
+
+.asm_388a7
+ inc [hl]
+ inc [hl]
+ inc [hl]
+ ret
+
+AI_Smart_DreamEater:
+; 90% chance to greatly encourage this move.
+; The AI_Basic layer will make sure that
+; Dream Eater is only used against sleeping targets.
+ call Random
+ cp 10 percent
+ ret c
+ dec [hl]
+ dec [hl]
+ dec [hl]
+ ret
+
+AI_Smart_EvasionUp:
+; Dismiss this move if enemy's evasion can't raise anymore.
+ ld a, [wEnemyEvaLevel]
+ cp MAX_STAT_LEVEL
+ jp nc, AIDiscourageMove
+
+; If enemy's HP is full...
+ call AICheckEnemyMaxHP
+ jr nc, .asm_388d3
+
+; ...greatly encourage this move if player is badly poisoned.
+ ld a, [wPlayerSubStatus5]
+ bit SUBSTATUS_TOXIC, a
+ jr nz, .asm_388d0
+
+; ...70% chance to greatly encourage this move if player is not badly poisoned.
+ call Random
+ cp 70 percent
+ jr nc, .asm_388f2
+
+.asm_388d0
+ dec [hl]
+ dec [hl]
+ ret
+
+.asm_388d3
+
+; Greatly discourage this move if enemy's HP is below 25%.
+ call AICheckEnemyQuarterHP
+ jr nc, .asm_388f0
+
+; If enemy's HP is above 25% but not full, 4% chance to greatly encourage this move.
+ call Random
+ cp 4 percent
+ jr c, .asm_388d0
+
+; If enemy's HP is between 25% and 50%,...
+ call AICheckEnemyHalfHP
+ jr nc, .asm_388eb
+
+; If enemy's HP is above 50% but not full, 20% chance to greatly encourage this move.
+ call AI_80_20
+ jr c, .asm_388d0
+ jr .asm_388f2
+
+.asm_388eb
+; ...50% chance to greatly discourage this move.
+ call AI_50_50
+ jr c, .asm_388f2
+
+.asm_388f0
+ inc [hl]
+ inc [hl]
+
+; 30% chance to end up here if enemy's HP is full and player is not badly poisoned.
+; 77% chance to end up here if enemy's HP is above 50% but not full.
+; 96% chance to end up here if enemy's HP is between 25% and 50%.
+; 100% chance to end up here if enemy's HP is below 25%.
+; In other words, we only end up here if the move has not been encouraged or dismissed.
+.asm_388f2
+ ld a, [wPlayerSubStatus5]
+ bit SUBSTATUS_TOXIC, a
+ jr nz, .asm_38919
+
+ ld a, [wPlayerSubStatus4]
+ bit SUBSTATUS_LEECH_SEED, a
+ jr nz, .asm_38922
+
+; Discourage this move if enemy's evasion level is higher than player's accuracy level.
+ ld a, [wEnemyEvaLevel]
+ ld b, a
+ ld a, [wPlayerAccLevel]
+ cp b
+ jr c, .asm_38917
+
+; Greatly encourage this move if the player is in the middle of Fury Cutter or Rollout.
+ ld a, [wPlayerFuryCutterCount]
+ and a
+ jr nz, .asm_388d0
+
+ ld a, [wPlayerSubStatus1]
+ bit SUBSTATUS_ROLLOUT, a
+ jr nz, .asm_388d0
+
+.asm_38917
+ inc [hl]
+ ret
+
+; Player is badly poisoned.
+; 70% chance to greatly encourage this move.
+; This would counter any previous discouragement.
+.asm_38919
+ call Random
+ cp 31 percent + 1
+ ret c
+ dec [hl]
+ dec [hl]
+ ret
+
+; Player is seeded.
+; 50% chance to encourage this move.
+; This would partly counter any previous discouragement.
+.asm_38922
+ call AI_50_50
+ ret c
+
+ dec [hl]
+ ret
+
+AI_Smart_AlwaysHit:
+; 80% chance to greatly encourage this move if either...
+
+; ...enemy's accuracy level has been lowered three or more stages
+ ld a, [wEnemyAccLevel]
+ cp BASE_STAT_LEVEL - 2
+ jr c, .asm_38935
+
+; ...or player's evasion level has been raised three or more stages.
+ ld a, [wPlayerEvaLevel]
+ cp BASE_STAT_LEVEL + 3
+ ret c
+
+.asm_38935
+ call AI_80_20
+ ret c
+
+ dec [hl]
+ dec [hl]
+ ret
+
+AI_Smart_MirrorMove:
+; If the player did not use any move last turn...
+ ld a, [wLastPlayerCounterMove]
+ and a
+ jr nz, .asm_38949
+
+; ...do nothing if enemy is slower than player
+ call AICompareSpeed
+ ret nc
+
+; ...or dismiss this move if enemy is faster than player.
+ jp AIDiscourageMove
+
+; If the player did use a move last turn...
+.asm_38949
+ push hl
+ ld hl, UsefulMoves
+ ld de, 1
+ call IsInArray
+ pop hl
+
+; ...do nothing if he didn't use a useful move.
+ ret nc
+
+; If he did, 50% chance to encourage this move...
+ call AI_50_50
+ ret c
+
+ dec [hl]
+
+; ...and 90% chance to encourage this move again if the enemy is faster.
+ call AICompareSpeed
+ ret nc
+
+ call Random
+ cp 10 percent
+ ret c
+
+ dec [hl]
+ ret
+
+AI_Smart_AccuracyDown:
+; If player's HP is full...
+ call AICheckPlayerMaxHP
+ jr nc, .asm_38981
+
+; ...and enemy's HP is above 50%...
+ call AICheckEnemyHalfHP
+ jr nc, .asm_38981
+
+; ...greatly encourage this move if player is badly poisoned.
+ ld a, [wPlayerSubStatus5]
+ bit SUBSTATUS_TOXIC, a
+ jr nz, .asm_3897e
+
+; ...70% chance to greatly encourage this move if player is not badly poisoned.
+ call Random
+ cp 70 percent
+ jr nc, .asm_389a0
+
+.asm_3897e
+ dec [hl]
+ dec [hl]
+ ret
+
+.asm_38981
+
+; Greatly discourage this move if player's HP is below 25%.
+ call AICheckPlayerQuarterHP
+ jr nc, .asm_3899e
+
+; If player's HP is above 25% but not full, 4% chance to greatly encourage this move.
+ call Random
+ cp 4 percent
+ jr c, .asm_3897e
+
+; If player's HP is between 25% and 50%,...
+ call AICheckPlayerHalfHP
+ jr nc, .asm_38999
+
+; If player's HP is above 50% but not full, 20% chance to greatly encourage this move.
+ call AI_80_20
+ jr c, .asm_3897e
+ jr .asm_389a0
+
+; ...50% chance to greatly discourage this move.
+.asm_38999
+ call AI_50_50
+ jr c, .asm_389a0
+
+.asm_3899e
+ inc [hl]
+ inc [hl]
+
+; We only end up here if the move has not been already encouraged.
+.asm_389a0
+ ld a, [wPlayerSubStatus5]
+ bit SUBSTATUS_TOXIC, a
+ jr nz, .asm_389c7
+
+ ld a, [wPlayerSubStatus4]
+ bit SUBSTATUS_LEECH_SEED, a
+ jr nz, .asm_389d0
+
+; Discourage this move if enemy's evasion level is higher than player's accuracy level.
+ ld a, [wEnemyEvaLevel]
+ ld b, a
+ ld a, [wPlayerAccLevel]
+ cp b
+ jr c, .asm_389c5
+
+; Greatly encourage this move if the player is in the middle of Fury Cutter or Rollout.
+ ld a, [wPlayerFuryCutterCount]
+ and a
+ jr nz, .asm_3897e
+
+ ld a, [wPlayerSubStatus1]
+ bit SUBSTATUS_ROLLOUT, a
+ jr nz, .asm_3897e
+
+.asm_389c5
+ inc [hl]
+ ret
+
+; Player is badly poisoned.
+; 70% chance to greatly encourage this move.
+; This would counter any previous discouragement.
+.asm_389c7
+ call Random
+ cp 31 percent + 1
+ ret c
+ dec [hl]
+ dec [hl]
+ ret
+
+; Player is seeded.
+; 50% chance to encourage this move.
+; This would partly counter any previous discouragement.
+.asm_389d0
+ call AI_50_50
+ ret c
+
+ dec [hl]
+ ret
+
+AI_Smart_ResetStats:
+; 85% chance to encourage this move if any of enemy's stat levels is lower than -2.
+ push hl
+ ld hl, wEnemyAtkLevel
+ ld c, NUM_LEVEL_STATS
+.asm_389dc
+ dec c
+ jr z, .asm_389e6
+ ld a, [hli]
+ cp BASE_STAT_LEVEL - 2
+ jr c, .asm_389f3
+ jr .asm_389dc
+
+; 85% chance to encourage this move if any of player's stat levels is higher than +2.
+.asm_389e6
+ ld hl, wPlayerAtkLevel
+ ld c, $8
+.asm_389eb
+ dec c
+ jr z, .asm_389fc
+ ld a, [hli]
+ cp BASE_STAT_LEVEL + 3
+ jr c, .asm_389eb
+
+.asm_389f3
+ pop hl
+ call Random
+ cp 16 percent
+ ret c
+ dec [hl]
+ ret
+
+; Discourage this move if neither:
+; Any of enemy's stat levels is lower than -2.
+; Any of player's stat levels is higher than +2.
+.asm_389fc
+ pop hl
+ inc [hl]
+ ret
+
+AI_Smart_Bide:
+; 90% chance to discourage this move unless enemy's HP is full.
+
+ call AICheckEnemyMaxHP
+ ret c
+ call Random
+ cp 10 percent
+ ret c
+ inc [hl]
+ ret
+
+AI_Smart_ForceSwitch:
+; Whirlwind, Roar.
+
+; Discourage this move if the player has not shown
+; a super-effective move against the enemy.
+; Consider player's type(s) if its moves are unknown.
+
+ push hl
+ callfar CheckPlayerMoveTypeMatchups
+ ld a, [wEnemyAISwitchScore]
+ cp 10 ; neutral
+ pop hl
+ ret c
+ inc [hl]
+ ret
+
+AI_Smart_Heal:
+AI_Smart_MorningSun:
+AI_Smart_Synthesis:
+AI_Smart_Moonlight:
+; 90% chance to greatly encourage this move if enemy's HP is below 25%.
+; Discourage this move if enemy's HP is higher than 50%.
+; Do nothing otherwise.
+
+ call AICheckEnemyQuarterHP
+ jr nc, .asm_38a26
+ call AICheckEnemyHalfHP
+ ret nc
+ inc [hl]
+ ret
+
+.asm_38a26
+ call Random
+ cp 10 percent
+ ret c
+ dec [hl]
+ dec [hl]
+ ret
+
+AI_Smart_Toxic:
+AI_Smart_LeechSeed:
+; Discourage this move if player's HP is below 50%.
+
+ call AICheckPlayerHalfHP
+ ret c
+ inc [hl]
+ ret
+
+AI_Smart_LightScreen:
+AI_Smart_Reflect:
+; Over 90% chance to discourage this move unless enemy's HP is full.
+
+ call AICheckEnemyMaxHP
+ ret c
+ call Random
+ cp 8 percent
+ ret c
+ inc [hl]
+ ret
+
+AI_Smart_Ohko:
+; Dismiss this move if player's level is higher than enemy's level.
+; Else, discourage this move is player's HP is below 50%.
+
+ ld a, [wBattleMonLevel]
+ ld b, a
+ ld a, [wEnemyMonLevel]
+ cp b
+ jp c, AIDiscourageMove
+ call AICheckPlayerHalfHP
+ ret c
+ inc [hl]
+ ret
+
+AI_Smart_TrapTarget:
+; Bind, Wrap, Fire Spin, Clamp
+
+; 50% chance to discourage this move if the player is already trapped.
+ ld a, [wPlayerWrapCount]
+ and a
+ jr nz, .asm_38a6c
+
+; 50% chance to greatly encourage this move if player is either
+; badly poisoned, in love, identified, stuck in Rollout, or has a Nightmare.
+ ld a, [wPlayerSubStatus5]
+ bit SUBSTATUS_TOXIC, a
+ jr nz, .asm_38a72
+
+ ld a, [wPlayerSubStatus1]
+ and 1 << SUBSTATUS_IN_LOVE | 1 << SUBSTATUS_ROLLOUT | 1 << SUBSTATUS_IDENTIFIED | 1 << SUBSTATUS_NIGHTMARE
+ jr nz, .asm_38a72
+
+; Else, 50% chance to greatly encourage this move if it's the player's Pokemon first turn.
+ ld a, [wPlayerTurnsTaken]
+ and a
+ jr z, .asm_38a72
+
+; 50% chance to discourage this move otherwise.
+.asm_38a6c
+ call AI_50_50
+ ret c
+ inc [hl]
+ ret
+
+.asm_38a72
+ call AICheckEnemyQuarterHP
+ ret nc
+ call AI_50_50
+ ret c
+ dec [hl]
+ dec [hl]
+ ret
+
+AI_Smart_RazorWind:
+AI_Smart_Unused2B:
+ ld a, [wEnemySubStatus1]
+ bit SUBSTATUS_PERISH, a
+ jr z, .asm_38a8b
+
+ ld a, [wEnemyPerishCount]
+ cp 3
+ jr c, .asm_38ab4
+
+.asm_38a8b
+ push hl
+ ld hl, wPlayerUsedMoves
+ ld c, NUM_MOVES
+
+.asm_38a91
+ ld a, [hli]
+ and a
+ jr z, .asm_38aa2
+
+ call AIGetEnemyMove
+
+ ld a, [wEnemyMoveStruct + MOVE_EFFECT]
+ cp EFFECT_PROTECT
+ jr z, .asm_38ab6
+ dec c
+ jr nz, .asm_38a91
+
+.asm_38aa2
+ pop hl
+ ld a, [wEnemySubStatus3]
+ bit SUBSTATUS_CONFUSED, a
+ jr nz, .asm_38aae
+
+ call AICheckEnemyHalfHP
+ ret c
+
+.asm_38aae
+ call Random
+ cp 79 percent - 1
+ ret c
+
+.asm_38ab4
+ inc [hl]
+ ret
+
+.asm_38ab6
+ pop hl
+ ld a, [hl]
+ add 6
+ ld [hl], a
+ ret
+
+AI_Smart_Confuse:
+; 90% chance to discourage this move if player's HP is between 25% and 50%.
+ call AICheckPlayerHalfHP
+ ret c
+ call Random
+ cp 10 percent
+ jr c, .asm_38ac8
+ inc [hl]
+
+.asm_38ac8
+; Discourage again if player's HP is below 25%.
+ call AICheckPlayerQuarterHP
+ ret c
+ inc [hl]
+ ret
+
+AI_Smart_SpDefenseUp2:
+; Discourage this move if enemy's HP is lower than 50%.
+ call AICheckEnemyHalfHP
+ jr nc, .asm_38af1
+
+; Discourage this move if enemy's special defense level is higher than +3.
+ ld a, [wEnemySDefLevel]
+ cp BASE_STAT_LEVEL + 4
+ jr nc, .asm_38af1
+
+; 80% chance to greatly encourage this move if
+; enemy's Special Defense level is lower than +2, and the player is of a special type.
+ cp BASE_STAT_LEVEL + 2
+ ret nc
+
+ ld a, [wBattleMonType1]
+ cp SPECIAL
+ jr nc, .asm_38aea
+ ld a, [wBattleMonType2]
+ cp SPECIAL
+ ret c
+
+.asm_38aea
+ call AI_80_20
+ ret c
+ dec [hl]
+ dec [hl]
+ ret
+
+.asm_38af1
+ inc [hl]
+ ret
+
+AI_Smart_Fly:
+; Fly, Dig
+
+; Greatly encourage this move if the player is
+; flying or underground, and slower than the enemy.
+
+ ld a, [wPlayerSubStatus3]
+ and 1 << SUBSTATUS_FLYING | 1 << SUBSTATUS_UNDERGROUND
+ ret z
+
+ call AICompareSpeed
+ ret nc
+
+ dec [hl]
+ dec [hl]
+ dec [hl]
+ ret
+
+AI_Smart_SuperFang:
+; Discourage this move if player's HP is below 25%.
+
+ call AICheckPlayerQuarterHP
+ ret c
+ inc [hl]
+ ret
+
+AI_Smart_Paralyze:
+; 50% chance to discourage this move if player's HP is below 25%.
+ call AICheckPlayerQuarterHP
+ jr nc, .asm_38b1b
+
+; 80% chance to greatly encourage this move
+; if enemy is slower than player and its HP is above 25%.
+ call AICompareSpeed
+ ret c
+ call AICheckEnemyQuarterHP
+ ret nc
+ call AI_80_20
+ ret c
+ dec [hl]
+ dec [hl]
+ ret
+
+.asm_38b1b
+ call AI_50_50
+ ret c
+ inc [hl]
+ ret
+
+AI_Smart_SpeedDownHit:
+; Icy Wind
+
+; Almost 90% chance to greatly encourage this move if the following conditions all meet:
+; Enemy's HP is higher than 25%.
+; It's the first turn of player's Pokemon.
+; Player is faster than enemy.
+
+ ld a, [wEnemyMoveStruct + MOVE_ANIM]
+ cp ICY_WIND
+ ret nz
+ call AICheckEnemyQuarterHP
+ ret nc
+ ld a, [wPlayerTurnsTaken]
+ and a
+ ret nz
+ call AICompareSpeed
+ ret c
+ call Random
+ cp 12 percent
+ ret c
+ dec [hl]
+ dec [hl]
+ ret
+
+AI_Smart_Substitute:
+; Dismiss this move if enemy's HP is below 50%.
+
+ call AICheckEnemyHalfHP
+ ret c
+ jp AIDiscourageMove
+
+AI_Smart_HyperBeam:
+ call AICheckEnemyHalfHP
+ jr c, .asm_38b53
+
+; 50% chance to encourage this move if enemy's HP is below 25%.
+ call AICheckEnemyQuarterHP
+ ret c
+ call AI_50_50
+ ret c
+ dec [hl]
+ ret
+
+.asm_38b53
+; If enemy's HP is above 50%, discourage this move at random
+ call Random
+ cp 35 percent + 1
+ ret c
+ inc [hl]
+ call AI_50_50
+ ret c
+ inc [hl]
+ ret
+
+AI_Smart_Rage:
+ ld a, [wEnemySubStatus4]
+ bit SUBSTATUS_RAGE, a
+ jr z, .asm_38b7c
+
+; If enemy's Rage is building, 50% chance to encourage this move.
+ call AI_50_50
+ jr c, .asm_38b6d
+
+ dec [hl]
+
+; Encourage this move based on Rage's counter.
+.asm_38b6d
+ ld a, [wEnemyRageCounter]
+ cp 2
+ ret c
+ dec [hl]
+ ld a, [wEnemyRageCounter]
+ cp 3
+ ret c
+ dec [hl]
+ ret
+
+.asm_38b7c
+; If enemy's Rage is not building, discourage this move if enemy's HP is below 50%.
+ call AICheckEnemyHalfHP
+ jr nc, .asm_38b87
+
+; 50% chance to encourage this move otherwise.
+ call AI_80_20
+ ret nc
+ dec [hl]
+ ret
+
+.asm_38b87
+ inc [hl]
+ ret
+
+AI_Smart_Mimic:
+ ld a, [wLastPlayerCounterMove]
+ and a
+ jr z, .asm_38bca
+
+ call AICheckEnemyHalfHP
+ jr nc, .asm_38bd0
+
+ push hl
+ ld a, [wLastPlayerCounterMove]
+ call AIGetEnemyMove
+
+ ld a, $1
+ ldh [hBattleTurn], a
+ callfar BattleCheckTypeMatchup
+
+ ld a, [wTypeMatchup]
+ cp EFFECTIVE
+ pop hl
+ jr c, .asm_38bd0
+ jr z, .asm_38bb5
+
+ call AI_50_50
+ jr c, .asm_38bb5
+
+ dec [hl]
+
+.asm_38bb5
+ ld a, [wLastPlayerCounterMove]
+ push hl
+ ld hl, UsefulMoves
+ ld de, 1
+ call IsInArray
+
+ pop hl
+ ret nc
+ call AI_50_50
+ ret c
+ dec [hl]
+ ret
+
+.asm_38bca
+ call AICompareSpeed
+ jp c, AIDiscourageMove
+
+.asm_38bd0
+ inc [hl]
+ ret
+
+AI_Smart_Counter:
+ push hl
+ ld hl, wPlayerUsedMoves
+ ld c, NUM_MOVES
+ ld b, 0
+
+.asm_38bda
+ ld a, [hli]
+ and a
+ jr z, .asm_38c0e
+
+ call AIGetEnemyMove
+
+ ld a, [wEnemyMoveStruct + MOVE_POWER]
+ and a
+ jr z, .asm_38c0e
+
+ ld a, [wEnemyMoveStruct + MOVE_TYPE]
+ cp SPECIAL
+ jr nc, .asm_38c0e
+
+ inc b
+
+.asm_38c0e
+ dec c
+ jr nz, .asm_38bda
+
+ pop hl
+ ld a, b
+ and a
+ jr z, .asm_38c1a
+
+ cp $3
+ jr nc, .asm_38c11
+
+ ld a, [wLastPlayerCounterMove]
+ and a
+ jr z, .asm_38c19
+
+ call AIGetEnemyMove
+
+ ld a, [wEnemyMoveStruct + MOVE_POWER]
+ and a
+ jr z, .asm_38c19
+
+ ld a, [wEnemyMoveStruct + MOVE_TYPE]
+ cp SPECIAL
+ jr nc, .asm_38c19
+
+.asm_38c11
+ call Random
+ cp 39 percent + 1
+ jr c, .asm_38c19
+
+ dec [hl]
+
+.asm_38c19
+ ret
+
+.asm_38c1a
+ inc [hl]
+ ret
+
+AI_Smart_Encore:
+ call AICompareSpeed
+ jr nc, .asm_38c62
+
+ ld a, [wLastPlayerMove]
+ and a
+ jp z, AIDiscourageMove
+
+ call AIGetEnemyMove
+
+ ld a, [wEnemyMoveStruct + MOVE_POWER]
+ and a
+ jr z, .asm_38c49
+
+ push hl
+ ld a, [wEnemyMoveStruct + MOVE_TYPE]
+ ld hl, wEnemyMonType1
+ predef CheckTypeMatchup
+
+ pop hl
+ ld a, [wTypeMatchup]
+ cp EFFECTIVE
+ jr nc, .asm_38c49
+
+ and a
+ ret nz
+ jr .asm_38c59
+
+.asm_38c49
+ push hl
+ ld a, [wLastPlayerCounterMove]
+ ld hl, EncoreMoves
+ ld de, 1
+ call IsInArray
+ pop hl
+ jr nc, .asm_38c62
+
+.asm_38c59
+ call Random
+ cp 28 percent - 1
+ ret c
+ dec [hl]
+ dec [hl]
+ ret
+
+.asm_38c62
+ inc [hl]
+ inc [hl]
+ inc [hl]
+ ret
+
+INCLUDE "data/battle/ai/encore_moves.asm"
+
+AI_Smart_PainSplit:
+; Discourage this move if [enemy's current HP * 2 > player's current HP].
+
+ push hl
+ ld hl, wEnemyMonHP
+ ld b, [hl]
+ inc hl
+ ld c, [hl]
+ sla c
+ rl b
+ ld hl, wBattleMonHP + 1
+ ld a, [hld]
+ cp c
+ ld a, [hl]
+ sbc b
+ pop hl
+ ret nc
+ inc [hl]
+ ret
+
+AI_Smart_Snore:
+AI_Smart_SleepTalk:
+; Greatly encourage this move if enemy is fast asleep.
+; Greatly discourage this move otherwise.
+
+ ld a, [wEnemyMonStatus]
+ and SLP
+ cp 1
+ jr z, .asm_38ca8
+
+ dec [hl]
+ dec [hl]
+ dec [hl]
+ ret
+
+.asm_38ca8
+ inc [hl]
+ inc [hl]
+ inc [hl]
+ ret
+
+AI_Smart_DefrostOpponent:
+; Greatly encourage this move if enemy is frozen.
+; No move has EFFECT_DEFROST_OPPONENT, so this layer is unused.
+
+ ld a, [wEnemyMonStatus]
+ and 1 << FRZ
+ ret z
+ dec [hl]
+ dec [hl]
+ dec [hl]
+ ret
+
+AI_Smart_Spite:
+ ld a, [wLastPlayerCounterMove]
+ and a
+ jr nz, .asm_38cc8
+
+ call AICompareSpeed
+ jp c, AIDiscourageMove
+
+ call AI_50_50
+ ret c
+ inc [hl]
+ ret
+
+.asm_38cc8
+ push hl
+ ld b, a
+ ld c, NUM_MOVES
+ ld hl, wBattleMonMoves
+ ld de, wBattleMonPP
+
+.asm_38cd2
+ ld a, [hli]
+ cp b
+ jr z, .asm_38cdc
+
+ inc de
+ dec c
+ jr nz, .asm_38cd2
+
+ pop hl
+ ret
+
+.asm_38cdc
+ pop hl
+ ld a, [de]
+ cp 6
+ jr c, .asm_38cee
+ cp 15
+ jr nc, .asm_38cec
+
+ call Random
+ cp 39 percent + 1
+ ret nc
+
+.asm_38cec
+ inc [hl]
+ ret
+
+.asm_38cee
+ call Random
+ cp 39 percent + 1
+ ret c
+ dec [hl]
+ dec [hl]
+ ret
+
+Function_0x38cf7:
+ jp AIDiscourageMove
+
+AI_Smart_DestinyBond:
+AI_Smart_Reversal:
+AI_Smart_SkullBash:
+; Discourage this move if enemy's HP is above 25%.
+
+ call AICheckEnemyQuarterHP
+ ret nc
+ inc [hl]
+ ret
+
+AI_Smart_HealBell:
+; Dismiss this move if none of the opponent's Pokemon is statused.
+; Encourage this move if the enemy is statused.
+; 50% chance to greatly encourage this move if the enemy is fast asleep or frozen.
+
+ push hl
+ ld a, [wOTPartyCount]
+ ld b, a
+ ld c, 0
+ ld hl, wOTPartyMon1HP
+ ld de, PARTYMON_STRUCT_LENGTH
+
+.loop
+ push hl
+ ld a, [hli]
+ or [hl]
+ jr z, .next
+
+ ; status
+ dec hl
+ dec hl
+ dec hl
+ ld a, [hl]
+ or c
+ ld c, a
+
+.next
+ pop hl
+ add hl, de
+ dec b
+ jr nz, .loop
+
+ pop hl
+ ld a, c
+ and a
+ jr z, .no_status
+
+ ld a, [wEnemyMonStatus]
+ and a
+ jr z, .ok
+ dec [hl]
+.ok
+ and 1 << FRZ | SLP
+ ret z
+ call AI_50_50
+ ret c
+ dec [hl]
+ dec [hl]
+ ret
+
+.no_status
+ ld a, [wEnemyMonStatus]
+ and a
+ ret nz
+ jp AIDiscourageMove
+
+
+AI_Smart_PriorityHit:
+ call AICompareSpeed
+ ret c
+
+; Dismiss this move if the player is flying or underground.
+ ld a, [wPlayerSubStatus3]
+ and 1 << SUBSTATUS_FLYING | 1 << SUBSTATUS_UNDERGROUND
+ jp nz, AIDiscourageMove
+
+; Greatly encourage this move if it will KO the player.
+ ld a, $1
+ ldh [hBattleTurn], a
+ push hl
+ callfar EnemyAttackDamage
+ callfar BattleCommand_DamageCalc
+ callfar BattleCommand_Stab
+ pop hl
+ ld a, [wCurDamage + 1]
+ ld c, a
+ ld a, [wCurDamage]
+ ld b, a
+ ld a, [wBattleMonHP + 1]
+ cp c
+ ld a, [wBattleMonHP]
+ sbc b
+ ret nc
+ dec [hl]
+ dec [hl]
+ dec [hl]
+ ret
+
+AI_Smart_Thief:
+; Don't use Thief unless it's the only move available.
+
+ ld a, [hl]
+ add $1e
+ ld [hl], a
+ ret
+
+AI_Smart_Conversion2:
+ ld a, [wLastPlayerMove]
+ and a
+ jr nz, .asm_38daa
+
+ push hl
+ dec a
+ ld hl, Moves + MOVE_TYPE
+ ld bc, MOVE_LENGTH
+ call AddNTimes
+
+ ld a, BANK(Moves)
+ call GetFarByte
+ ld [wPlayerMoveStruct + MOVE_TYPE], a
+
+ xor a
+ ldh [hBattleTurn], a
+
+ callfar BattleCheckTypeMatchup
+
+ ld a, [wTypeMatchup]
+ cp EFFECTIVE
+ pop hl
+ jr c, .asm_38daa
+ ret z
+
+ call AI_50_50
+ ret c
+
+ dec [hl]
+ ret
+
+.asm_38daa
+ call Random
+ cp 10 percent
+ ret c
+ inc [hl]
+ ret
+
+AI_Smart_Disable:
+ call AICompareSpeed
+ jr nc, .asm_38dd4
+
+ push hl
+ ld a, [wLastPlayerCounterMove]
+ ld hl, UsefulMoves
+ ld de, 1
+ call IsInArray
+
+ pop hl
+ jr nc, .asm_38dcf
+
+ call Random
+ cp 39 percent + 1
+ ret c
+ dec [hl]
+ ret
+
+.asm_38dcf
+ ld a, [wEnemyMoveStruct + MOVE_POWER]
+ and a
+ ret nz
+
+.asm_38dd4
+ call Random
+ cp 8 percent
+ ret c
+ inc [hl]
+ ret
+
+AI_Smart_MeanLook:
+ call AICheckEnemyHalfHP
+ jr nc, .asm_38e05
+
+ push hl
+ call AICheckLastPlayerMon
+ pop hl
+ jp z, AIDiscourageMove
+
+; 80% chance to greatly encourage this move if the enemy is badly poisoned (buggy).
+; Should check wPlayerSubStatus5 instead.
+ ld a, [wEnemySubStatus5]
+ bit SUBSTATUS_TOXIC, a
+ jr nz, .asm_38e07
+
+; 80% chance to greatly encourage this move if the player is either
+; in love, identified, stuck in Rollout, or has a Nightmare.
+ ld a, [wPlayerSubStatus1]
+ and 1 << SUBSTATUS_IN_LOVE | 1 << SUBSTATUS_ROLLOUT | 1 << SUBSTATUS_IDENTIFIED | 1 << SUBSTATUS_NIGHTMARE
+ jr nz, .asm_38e07
+
+; Otherwise, discourage this move unless the player only has not very effective moves against the enemy.
+ push hl
+ callfar CheckPlayerMoveTypeMatchups
+ ld a, [wEnemyAISwitchScore]
+ cp $b ; not very effective
+ pop hl
+ ret nc
+
+.asm_38e05
+ inc [hl]
+ ret
+
+.asm_38e07
+ call AI_80_20
+ ret c
+ dec [hl]
+ dec [hl]
+ dec [hl]
+ ret
+
+AICheckLastPlayerMon:
+ ld a, [wPartyCount]
+ ld b, a
+ ld c, 0
+ ld hl, wPartyMon1HP
+ ld de, PARTYMON_STRUCT_LENGTH
+
+.loop
+ ld a, [wCurBattleMon]
+ cp c
+ jr z, .asm_38e25
+
+ ld a, [hli]
+ or [hl]
+ ret nz
+ dec hl
+
+.asm_38e25
+ add hl, de
+ inc c
+ dec b
+ jr nz, .loop
+
+ ret
+
+AI_Smart_Nightmare:
+; 50% chance to encourage this move.
+; The AI_Basic layer will make sure that
+; Dream Eater is only used against sleeping targets.
+
+ call AI_50_50
+ ret c
+ dec [hl]
+ ret
+
+AI_Smart_FlameWheel:
+; Use this move if the enemy is frozen.
+
+ ld a, [wEnemyMonStatus]
+ bit FRZ, a
+ ret z
+rept 5
+ dec [hl]
+endr
+ ret
+
+AI_Smart_Curse:
+ ld a, [wEnemyMonType1]
+ cp GHOST
+ jr z, .ghostcurse
+ ld a, [wEnemyMonType2]
+ cp GHOST
+ jr z, .ghostcurse
+
+ call AICheckEnemyHalfHP
+ jr nc, .asm_38e72
+
+ ld a, [wEnemyAtkLevel]
+ cp BASE_STAT_LEVEL + 4
+ jr nc, .asm_38e72
+ cp BASE_STAT_LEVEL + 2
+ ret nc
+
+ ld a, [wBattleMonType1]
+ cp GHOST
+ jr z, .asm_38e71
+ cp SPECIAL
+ ret nc
+ ld a, [wBattleMonType2]
+ cp SPECIAL
+ ret nc
+ call AI_80_20
+ ret c
+ dec [hl]
+ dec [hl]
+ ret
+
+.asm_38e71
+ inc [hl]
+.asm_38e72
+ inc [hl]
+ ret
+
+.ghostcurse
+ call AICheckEnemyQuarterHP
+ jp nc, AIDiscourageMove
+
+ call AICheckEnemyHalfHP
+ jr nc, .asm_38e72
+
+ ld a, [wPlayerSubStatus1]
+ bit SUBSTATUS_CURSE, a
+ jp nz, AIDiscourageMove
+
+ ld a, [wPlayerTurnsTaken]
+ and a
+ ret nz
+
+ call AI_50_50
+ ret c
+
+ dec [hl]
+ dec [hl]
+ ret
+
+AI_Smart_Protect:
+ ld a, [wEnemyProtectCount]
+ and a
+ jr nz, .asm_38ed4
+
+ ld a, [wPlayerSubStatus5]
+ bit SUBSTATUS_LOCK_ON, a
+ jr nz, .asm_38ed5
+
+ ld a, [wPlayerFuryCutterCount]
+ cp 3
+ jr nc, .asm_38ece
+
+ ld a, [wPlayerSubStatus3]
+ bit SUBSTATUS_CHARGED, a
+ jr nz, .asm_38ece
+
+ ld a, [wPlayerSubStatus5]
+ bit SUBSTATUS_TOXIC, a
+ jr nz, .asm_38ece
+ ld a, [wPlayerSubStatus4]
+ bit SUBSTATUS_LEECH_SEED, a
+ jr nz, .asm_38ece
+ ld a, [wPlayerSubStatus1]
+ bit SUBSTATUS_CURSE, a
+ jr nz, .asm_38ece
+
+ bit SUBSTATUS_ROLLOUT, a
+ jr z, .asm_38ed5
+
+ ld a, [wPlayerRolloutCount]
+ cp 3
+ jr c, .asm_38ed5
+
+.asm_38ece
+ call AI_80_20
+ ret c
+ dec [hl]
+ ret
+
+.asm_38ed4
+ inc [hl]
+
+.asm_38ed5
+ call Random
+ cp 8 percent
+ ret c
+ inc [hl]
+ inc [hl]
+ ret
+
+AI_Smart_Foresight:
+ ld a, [wEnemyAccLevel]
+ cp BASE_STAT_LEVEL - 2
+ jr c, .asm_38f02
+ ld a, [wPlayerEvaLevel]
+ cp BASE_STAT_LEVEL + 3
+ jr nc, .asm_38f02
+
+ ld a, [wBattleMonType1]
+ cp GHOST
+ jr z, .asm_38f02
+ ld a, [wBattleMonType2]
+ cp GHOST
+ jr z, .asm_38f02
+
+ call Random
+ cp 8 percent
+ ret c
+ inc [hl]
+ ret
+
+.asm_38f02
+ call Random
+ cp 39 percent + 1
+ ret c
+ dec [hl]
+ dec [hl]
+ ret
+
+AI_Smart_PerishSong:
+ push hl
+ callfar FindAliveEnemyMons
+ pop hl
+ jr c, .no
+
+ ld a, [wPlayerSubStatus5]
+ bit SUBSTATUS_CANT_RUN, a
+ jr nz, .yes
+
+ push hl
+ callfar CheckPlayerMoveTypeMatchups
+ ld a, [wEnemyAISwitchScore]
+ cp 10 ; 1.0
+ pop hl
+ ret c
+
+ call AI_50_50
+ ret c
+
+ inc [hl]
+ ret
+
+.yes
+ call AI_50_50
+ ret c
+
+ dec [hl]
+ ret
+
+.no
+ ld a, [hl]
+ add 5
+ ld [hl], a
+ ret
+
+AI_Smart_Sandstorm:
+; Greatly discourage this move if the player is immune to Sandstorm damage.
+ ld a, [wBattleMonType1]
+ push hl
+ ld hl, .SandstormImmuneTypes
+ ld de, 1
+ call IsInArray
+ pop hl
+ jr c, .asm_38f66
+
+ ld a, [wBattleMonType2]
+ push hl
+ ld hl, .SandstormImmuneTypes
+ ld de, 1
+ call IsInArray
+ pop hl
+ jr c, .asm_38f66
+
+; Discourage this move if player's HP is below 50%.
+ call AICheckPlayerHalfHP
+ jr nc, .asm_38f67
+
+; 50% chance to encourage this move otherwise.
+ call AI_50_50
+ ret c
+
+ dec [hl]
+ ret
+
+.asm_38f66
+ inc [hl]
+
+.asm_38f67
+ inc [hl]
+ ret
+
+.SandstormImmuneTypes:
+ db ROCK
+ db GROUND
+ db STEEL
+ db -1 ; end
+
+AI_Smart_Endure:
+ ld a, [wEnemyProtectCount]
+ and a
+ jr nz, .asm_38f99
+
+ call AICheckEnemyMaxHP
+ jr c, .asm_38f99
+
+ call AICheckEnemyQuarterHP
+ jr c, .asm_38f9a
+
+ ld b, EFFECT_REVERSAL
+ call AIHasMoveEffect
+ jr nc, .asm_38f8c
+
+ call AI_80_20
+ ret c
+
+ dec [hl]
+ dec [hl]
+ dec [hl]
+ ret
+
+.asm_38f8c
+ ld a, [wEnemySubStatus5]
+ bit SUBSTATUS_LOCK_ON, a
+ ret z
+
+ call AI_50_50
+ ret c
+
+ dec [hl]
+ dec [hl]
+ ret
+
+.asm_38f99
+ inc [hl]
+
+.asm_38f9a
+ inc [hl]
+ ret
+
+AI_Smart_FuryCutter:
+; Encourage this move based on Fury Cutter's count.
+
+ ld a, [wEnemyFuryCutterCount]
+ and a
+ jr z, .end
+ dec [hl]
+
+ cp 2
+ jr c, .end
+ dec [hl]
+ dec [hl]
+
+ cp 3
+ jr c, .end
+ dec [hl]
+ dec [hl]
+ dec [hl]
+
+.end
+
+ ; fallthrough
+
+AI_Smart_Rollout:
+; Rollout, Fury Cutter
+
+; 80% chance to discourage this move if the enemy is in love, confused, or paralyzed.
+ ld a, [wEnemySubStatus1]
+ bit SUBSTATUS_IN_LOVE, a
+ jr nz, .asm_38fe1
+
+ ld a, [wEnemySubStatus3]
+ bit SUBSTATUS_CONFUSED, a
+ jr nz, .asm_38fe1
+
+ ld a, [wEnemyMonStatus]
+ bit PAR, a
+ jr nz, .asm_38fe1
+
+; 80% chance to discourage this move if the enemy's HP is below 25%,
+; or if accuracy or evasion modifiers favour the player.
+ call AICheckEnemyQuarterHP
+ jr nc, .asm_38fe1
+
+ ld a, [wEnemyAccLevel]
+ cp BASE_STAT_LEVEL
+ jr c, .asm_38fe1
+ ld a, [wPlayerEvaLevel]
+ cp BASE_STAT_LEVEL + 1
+ jr nc, .asm_38fe1
+
+; Otherwise, 80% chance to greatly encourage this move.
+ call Random
+ cp 79 percent - 1
+ ret nc
+ dec [hl]
+ dec [hl]
+ ret
+
+.asm_38fe1
+ call AI_80_20
+ ret c
+ inc [hl]
+ ret
+
+AI_Smart_Swagger:
+AI_Smart_Attract:
+; 80% chance to encourage this move during the first turn of player's Pokemon.
+; 80% chance to discourage this move otherwise.
+
+ ld a, [wPlayerTurnsTaken]
+ and a
+ jr z, .first_turn
+
+ call AI_80_20
+ ret c
+ inc [hl]
+ ret
+
+.first_turn
+ call Random
+ cp 79 percent - 1
+ ret nc
+ dec [hl]
+ ret
+
+AI_Smart_Safeguard:
+; 80% chance to discourage this move if player's HP is below 50%.
+
+ call AICheckPlayerHalfHP
+ ret c
+ call AI_80_20
+ ret c
+ inc [hl]
+ ret
+
+AI_Smart_Magnitude:
+AI_Smart_Earthquake:
+; Greatly encourage this move if the player is underground and the enemy is faster.
+ ld a, [wLastPlayerCounterMove]
+ cp DIG
+ ret nz
+
+ ld a, [wPlayerSubStatus3]
+ bit SUBSTATUS_UNDERGROUND, a
+ jr z, .could_dig
+
+ call AICompareSpeed
+ ret nc
+ dec [hl]
+ dec [hl]
+ ret
+
+.could_dig
+ ; Try to predict if the player will use Dig this turn.
+
+ ; 50% chance to encourage this move if the enemy is slower than the player.
+ call AICompareSpeed
+ ret c
+
+ call AI_50_50
+ ret c
+
+ dec [hl]
+ ret
+
+AI_Smart_BatonPass:
+; Discourage this move if the player hasn't shown super-effective moves against the enemy.
+; Consider player's type(s) if its moves are unknown.
+
+ push hl
+ callfar CheckPlayerMoveTypeMatchups
+ ld a, [wEnemyAISwitchScore]
+ cp 10 ; neutral
+ pop hl
+ ret c
+ inc [hl]
+ ret
+
+AI_Smart_Pursuit:
+; 50% chance to greatly encourage this move if player's HP is below 25%.
+; 80% chance to discourage this move otherwise.
+
+ call AICheckPlayerQuarterHP
+ jr nc, .asm_3903e
+ call AI_80_20
+ ret c
+ inc [hl]
+ ret
+
+.asm_3903e
+ call AI_50_50
+ ret c
+ dec [hl]
+ dec [hl]
+ ret
+
+AI_Smart_RapidSpin:
+; 80% chance to greatly encourage this move if the enemy is
+; trapped (Bind effect), seeded, or scattered with spikes.
+
+ ld a, [wEnemyWrapCount]
+ and a
+ jr nz, .asm_39058
+
+ ld a, [wEnemySubStatus4]
+ bit SUBSTATUS_LEECH_SEED, a
+ jr nz, .asm_39058
+
+ ld a, [wEnemyScreens]
+ bit SCREENS_SPIKES, a
+ ret z
+
+.asm_39058
+ call AI_80_20
+ ret c
+
+ dec [hl]
+ dec [hl]
+ ret
+
+AI_Smart_HiddenPower:
+ push hl
+ ld a, 1
+ ldh [hBattleTurn], a
+
+; Calculate Hidden Power's type and base power based on enemy's DVs.
+ callfar HiddenPowerDamage
+ callfar BattleCheckTypeMatchup
+ pop hl
+
+; Discourage Hidden Power if not very effective.
+ ld a, [wTypeMatchup]
+ cp EFFECTIVE
+ jr c, .bad
+
+; Discourage Hidden Power if its base power is lower than 50.
+ ld a, d
+ cp 50
+ jr c, .bad
+
+; Encourage Hidden Power if super-effective.
+ ld a, [wTypeMatchup]
+ cp EFFECTIVE + 1
+ jr nc, .good
+
+; Encourage Hidden Power if its base power is 70.
+ ld a, d
+ cp 70
+ ret c
+
+.good
+ dec [hl]
+ ret
+
+.bad
+ inc [hl]
+ ret
+
+AI_Smart_RainDance:
+; Greatly discourage this move if it would favour the player type-wise.
+; Particularly, if the player is a Water-type.
+ ld a, [wBattleMonType1]
+ cp WATER
+ jr z, AIBadWeatherType
+ cp FIRE
+ jr z, AIGoodWeatherType
+
+ ld a, [wBattleMonType2]
+ cp WATER
+ jr z, AIBadWeatherType
+ cp FIRE
+ jr z, AIGoodWeatherType
+
+ push hl
+ ld hl, RainDanceMoves
+ jr AI_Smart_WeatherMove
+
+INCLUDE "data/battle/ai/rain_dance_moves.asm"
+
+AI_Smart_SunnyDay:
+; Greatly discourage this move if it would favour the player type-wise.
+; Particularly, if the player is a Fire-type.
+ ld a, [wBattleMonType1]
+ cp FIRE
+ jr z, AIBadWeatherType
+ cp WATER
+ jr z, AIGoodWeatherType
+
+ ld a, [wBattleMonType2]
+ cp FIRE
+ jr z, AIBadWeatherType
+ cp WATER
+ jr z, AIGoodWeatherType
+
+ push hl
+ ld hl, SunnyDayMoves
+
+ ; fallthrough
+
+AI_Smart_WeatherMove:
+; Rain Dance, Sunny Day
+
+; Greatly discourage this move if the enemy doesn't have
+; one of the useful Rain Dance or Sunny Day moves.
+ call AIHasMoveInArray
+ pop hl
+ jr nc, AIBadWeatherType
+
+; Greatly discourage this move if player's HP is below 50%.
+ call AICheckPlayerHalfHP
+ jr nc, AIBadWeatherType
+
+; 50% chance to encourage this move otherwise.
+ call AI_50_50
+ ret c
+
+ dec [hl]
+ ret
+
+AIBadWeatherType:
+ inc [hl]
+ inc [hl]
+ inc [hl]
+ ret
+
+AIGoodWeatherType:
+; Rain Dance, Sunny Day
+
+; Greatly encourage this move if it would disfavour the player type-wise and player's HP is above 50%...
+ call AICheckPlayerHalfHP
+ ret nc
+
+; ...as long as one of the following conditions meet:
+; It's the first turn of the player's Pokemon.
+ ld a, [wPlayerTurnsTaken]
+ and a
+ jr z, .good
+
+; Or it's the first turn of the enemy's Pokemon.
+ ld a, [wEnemyTurnsTaken]
+ and a
+ ret nz
+
+.good
+ dec [hl]
+ dec [hl]
+ ret
+
+INCLUDE "data/battle/ai/sunny_day_moves.asm"
+
+AI_Smart_BellyDrum:
+; Dismiss this move if enemy's attack is higher than +2 or if enemy's HP is below 50%.
+; Else, discourage this move if enemy's HP is not full.
+
+ ld a, [wEnemyAtkLevel]
+ cp BASE_STAT_LEVEL + 3
+ jr nc, .asm_3910e
+
+ call AICheckEnemyMaxHP
+ ret c
+
+ inc [hl]
+
+ call AICheckEnemyHalfHP
+ ret c
+
+.asm_3910e
+ ld a, [hl]
+ add $5
+ ld [hl], a
+ ret
+
+AI_Smart_PsychUp:
+ push hl
+ ld hl, wEnemyAtkLevel
+ ld b, $8
+ ld c, 100
+
+; Calculate the sum of all enemy's stat level modifiers. Add 100 first to prevent underflow.
+; Put the result in c. c will range between 58 and 142.
+.asm_3911b
+ ld a, [hli]
+ sub $7
+ add c
+ ld c, a
+ dec b
+ jr nz, .asm_3911b
+
+; Calculate the sum of all player's stat level modifiers. Add 100 first to prevent underflow.
+; Put the result in d. d will range between 58 and 142.
+ ld hl, wPlayerAtkLevel
+ ld b, $8
+ ld d, 100
+
+.asm_3912a
+ ld a, [hli]
+ sub $7
+ add d
+ ld d, a
+ dec b
+ jr nz, .asm_3912a
+
+; Greatly discourage this move if enemy's stat levels are higher than player's (if c>=d).
+ ld a, c
+ sub d
+ pop hl
+ jr nc, .asm_3914f
+
+; This block will always ret, since the comparisons to wPlayerEvaLevel capture every possible value
+ ld a, [wPlayerAccLevel]
+ cp BASE_STAT_LEVEL - 1
+ ret c
+
+ ld a, [wPlayerEvaLevel]
+ cp BASE_STAT_LEVEL + 2
+ ret c
+
+ ld a, [wPlayerEvaLevel]
+ cp BASE_STAT_LEVEL + 1
+ ret nc
+
+; unused
+ call AI_80_20
+ ret c
+
+ dec [hl]
+ ret
+
+.asm_3914f
+ inc [hl]
+ ret
+
+AI_Smart_MirrorCoat:
+ push hl
+ ld hl, wPlayerUsedMoves
+ ld c, NUM_MOVES
+ ld b, 0
+
+.asm_39159
+ ld a, [hli]
+ and a
+ jr z, .asm_3916e
+
+ call AIGetEnemyMove
+
+ ld a, [wEnemyMoveStruct + MOVE_POWER]
+ and a
+ jr z, .asm_3916e
+
+ ld a, [wEnemyMoveStruct + MOVE_TYPE]
+ cp SPECIAL
+ jr c, .asm_3916e
+
+ inc b
+
+.asm_3916e
+ dec c
+ jr nz, .asm_39159
+
+ pop hl
+ ld a, b
+ and a
+ jr z, .asm_39199
+
+ cp $3
+ jr nc, .asm_39190
+
+ ld a, [wLastPlayerCounterMove]
+ and a
+ jr z, .asm_39198
+
+ call AIGetEnemyMove
+
+ ld a, [wEnemyMoveStruct + MOVE_POWER]
+ and a
+ jr z, .asm_39198
+
+ ld a, [wEnemyMoveStruct + MOVE_TYPE]
+ cp SPECIAL
+ jr c, .asm_39198
+
+.asm_39190
+ call Random
+ cp 100
+ jr c, .asm_39198
+ dec [hl]
+
+.asm_39198
+ ret
+
+.asm_39199
+ inc [hl]
+ ret
+
+AI_Smart_Twister:
+AI_Smart_Gust:
+; Greatly encourage this move if the player is flying and the enemy is faster.
+ ld a, [wLastPlayerCounterMove]
+ cp FLY
+ ret nz
+
+ ld a, [wPlayerSubStatus3]
+ bit SUBSTATUS_FLYING, a
+ jr z, .couldFly
+
+ call AICompareSpeed
+ ret nc
+
+ dec [hl]
+ dec [hl]
+ ret
+
+; Try to predict if the player will use Fly this turn.
+.couldFly
+
+; 50% chance to encourage this move if the enemy is slower than the player.
+ call AICompareSpeed
+ ret c
+ call AI_50_50
+ ret c
+ dec [hl]
+ ret
+
+AI_Smart_FutureSight:
+; Greatly encourage this move if the player is
+; flying or underground, and slower than the enemy.
+
+ call AICompareSpeed
+ ret nc
+
+ ld a, [wPlayerSubStatus3]
+ and 1 << SUBSTATUS_FLYING | 1 << SUBSTATUS_UNDERGROUND
+ ret z
+
+ dec [hl]
+ dec [hl]
+ ret
+
+AI_Smart_Stomp:
+; 80% chance to encourage this move if the player has used Minimize.
+
+ ld a, [wPlayerMinimized]
+ and a
+ ret z
+
+ call AI_80_20
+ ret c
+
+ dec [hl]
+ ret
+
+AI_Smart_Solarbeam:
+; 80% chance to encourage this move when it's sunny.
+; 90% chance to discourage this move when it's raining.
+
+ ld a, [wBattleWeather]
+ cp WEATHER_SUN
+ jr z, .asm_391e4
+
+ cp WEATHER_RAIN
+ ret nz
+
+ call Random
+ cp 10 percent
+ ret c
+
+ inc [hl]
+ inc [hl]
+ ret
+
+.asm_391e4
+ call AI_80_20
+ ret c
+
+ dec [hl]
+ dec [hl]
+ ret
+
+AI_Smart_Thunder:
+; 90% chance to discourage this move when it's sunny.
+
+ ld a, [wBattleWeather]
+ cp WEATHER_SUN
+ ret nz
+
+ call Random
+ cp 10 percent
+ ret c
+
+ inc [hl]
+ ret
+
+AICompareSpeed:
+; Return carry if enemy is faster than player.
+
+ push bc
+ ld a, [wEnemyMonSpeed + 1]
+ ld b, a
+ ld a, [wBattleMonSpeed + 1]
+ cp b
+ ld a, [wEnemyMonSpeed]
+ ld b, a
+ ld a, [wBattleMonSpeed]
+ sbc b
+ pop bc
+ ret
+
+AICheckPlayerMaxHP:
+ push hl
+ push de
+ push bc
+ ld de, wBattleMonHP
+ ld hl, wBattleMonMaxHP
+ jr AICheckMaxHP
+
+AICheckEnemyMaxHP:
+ push hl
+ push de
+ push bc
+ ld de, wEnemyMonHP
+ ld hl, wEnemyMonMaxHP
+ ; fallthrough
+
+AICheckMaxHP:
+; Return carry if hp at de matches max hp at hl.
+
+ ld a, [de]
+ inc de
+ cp [hl]
+ jr nz, .asm_3922f
+
+ inc hl
+ ld a, [de]
+ cp [hl]
+ jr nz, .asm_3922f
+
+ pop bc
+ pop de
+ pop hl
+ scf
+ ret
+
+.asm_3922f
+ pop bc
+ pop de
+ pop hl
+ and a
+ ret
+
+AICheckPlayerHalfHP:
+ push hl
+ ld hl, wBattleMonHP
+ ld b, [hl]
+ inc hl
+ ld c, [hl]
+ sla c
+ rl b
+ inc hl
+ inc hl
+ ld a, [hld]
+ cp c
+ ld a, [hl]
+ sbc b
+ pop hl
+ ret
+
+AICheckEnemyHalfHP:
+ push hl
+ push de
+ push bc
+ ld hl, wEnemyMonHP
+ ld b, [hl]
+ inc hl
+ ld c, [hl]
+ sla c
+ rl b
+ inc hl
+ inc hl
+ ld a, [hld]
+ cp c
+ ld a, [hl]
+ sbc b
+ pop bc
+ pop de
+ pop hl
+ ret
+
+AICheckEnemyQuarterHP:
+ push hl
+ push de
+ push bc
+ ld hl, wEnemyMonHP
+ ld b, [hl]
+ inc hl
+ ld c, [hl]
+ sla c
+ rl b
+ sla c
+ rl b
+ inc hl
+ inc hl
+ ld a, [hld]
+ cp c
+ ld a, [hl]
+ sbc b
+ pop bc
+ pop de
+ pop hl
+ ret
+
+AICheckPlayerQuarterHP:
+ push hl
+ ld hl, wBattleMonHP
+ ld b, [hl]
+ inc hl
+ ld c, [hl]
+ sla c
+ rl b
+ sla c
+ rl b
+ inc hl
+ inc hl
+ ld a, [hld]
+ cp c
+ ld a, [hl]
+ sbc b
+ pop hl
+ ret
+
+AIHasMoveEffect:
+; Return carry if the enemy has move b.
+
+ push hl
+ ld hl, wEnemyMonMoves
+ ld c, wEnemyMonMovesEnd - wEnemyMonMoves
+
+.checkmove
+ ld a, [hli]
+ and a
+ jr z, .no
+
+ call AIGetEnemyMove
+
+ ld a, [wEnemyMoveStruct + MOVE_EFFECT]
+ cp b
+ jr z, .yes
+
+ dec c
+ jr nz, .checkmove
+
+.no
+ pop hl
+ and a
+ ret
+
+.yes
+ pop hl
+ scf
+ ret
+
+AIHasMoveInArray:
+; Return carry if the enemy has a move in array hl.
+
+ push hl
+ push de
+ push bc
+
+.next
+ ld a, [hli]
+ cp $ff
+ jr z, .done
+
+ ld b, a
+ ld c, wEnemyMonMovesEnd - wEnemyMonMoves + 1
+ ld de, wEnemyMonMoves
+
+.check
+ dec c
+ jr z, .next
+
+ ld a, [de]
+ inc de
+ cp b
+ jr nz, .check
+
+ scf
+
+.done
+ pop bc
+ pop de
+ pop hl
+ ret
+
+INCLUDE "data/battle/ai/useful_moves.asm"
+
+AI_Opportunist:
+; Discourage stall moves when the enemy's HP is low.
+
+; Do nothing if enemy's HP is above 50%.
+ call AICheckEnemyHalfHP
+ ret c
+
+; Discourage stall moves if enemy's HP is below 25%.
+ call AICheckEnemyQuarterHP
+ jr nc, .asm_392e8
+
+; 50% chance to discourage stall moves if enemy's HP is between 25% and 50%.
+ call AI_50_50
+ ret c
+
+.asm_392e8
+ ld hl, wBuffer1 - 1
+ ld de, wEnemyMonMoves
+ ld c, wEnemyMonMovesEnd - wEnemyMonMoves + 1
+.checkmove
+ inc hl
+ dec c
+ jr z, .asm_3930d
+
+ ld a, [de]
+ inc de
+ and a
+ jr z, .asm_3930d
+
+ push hl
+ push de
+ push bc
+ ld hl, StallMoves
+ ld de, 1
+ call IsInArray
+
+ pop bc
+ pop de
+ pop hl
+ jr nc, .checkmove
+
+ inc [hl]
+ jr .checkmove
+
+.asm_3930d
+ ret
+
+INCLUDE "data/battle/ai/stall_moves.asm"
+
+
+AI_Aggressive:
+; Use whatever does the most damage.
+
+; Discourage all damaging moves but the one that does the most damage.
+; If no damaging move deals damage to the player (immune),
+; no move will be discouraged
+
+; Figure out which attack does the most damage and put it in c.
+ ld hl, wEnemyMonMoves
+ ld bc, 0
+ ld de, 0
+.checkmove
+ inc b
+ ld a, b
+ cp wEnemyMonMovesEnd - wEnemyMonMoves + 1
+ jr z, .gotstrongestmove
+
+ ld a, [hli]
+ and a
+ jr z, .gotstrongestmove
+
+ push hl
+ push de
+ push bc
+ call AIGetEnemyMove
+ ld a, [wEnemyMoveStruct + MOVE_POWER]
+ and a
+ jr z, .nodamage
+ call AIDamageCalc
+ pop bc
+ pop de
+ pop hl
+
+; Update current move if damage is highest so far
+ ld a, [wCurDamage + 1]
+ cp e
+ ld a, [wCurDamage]
+ sbc d
+ jr c, .checkmove
+
+ ld a, [wCurDamage + 1]
+ ld e, a
+ ld a, [wCurDamage]
+ ld d, a
+ ld c, b
+ jr .checkmove
+
+.nodamage
+ pop bc
+ pop de
+ pop hl
+ jr .checkmove
+
+.gotstrongestmove
+; Nothing we can do if no attacks did damage.
+ ld a, c
+ and a
+ jr z, .done
+
+; Discourage moves that do less damage unless they're reckless too.
+ ld hl, wBuffer1 - 1
+ ld de, wEnemyMonMoves
+ ld b, 0
+.checkmove2
+ inc b
+ ld a, b
+ cp wEnemyMonMovesEnd - wEnemyMonMoves + 1
+ jr z, .done
+
+; Ignore this move if it is the highest damaging one.
+ cp c
+ ld a, [de]
+ inc de
+ inc hl
+ jr z, .checkmove2
+
+ call AIGetEnemyMove
+
+; Ignore this move if its power is 0 or 1.
+; Moves such as Seismic Toss, Hidden Power,
+; Counter and Fissure have a base power of 1.
+ ld a, [wEnemyMoveStruct + MOVE_POWER]
+ cp 2
+ jr c, .checkmove2
+
+; Ignore this move if it is reckless.
+ push hl
+ push de
+ push bc
+ ld a, [wEnemyMoveStruct + MOVE_EFFECT]
+ ld hl, RecklessMoves
+ ld de, 1
+ call IsInArray
+ pop bc
+ pop de
+ pop hl
+ jr c, .checkmove2
+
+; If we made it this far, discourage this move.
+ inc [hl]
+ jr .checkmove2
+
+.done
+ ret
+
+INCLUDE "data/battle/ai/reckless_moves.asm"
+
+AIDamageCalc:
+ ld a, 1
+ ldh [hBattleTurn], a
+ ld a, [wEnemyMoveStruct + MOVE_EFFECT]
+ ld de, 1
+ ld hl, ConstantDamageEffects
+ call IsInArray
+ jr nc, .asm_393c6
+ callfar BattleCommand_ConstantDamage
+ ret
+
+.asm_393c6
+ callfar EnemyAttackDamage
+ callfar BattleCommand_DamageCalc
+ callfar BattleCommand_Stab
+ ret
+
+INCLUDE "data/battle/ai/constant_damage_effects.asm"
+
+AI_Cautious:
+; 90% chance to discourage moves with residual effects after the first turn.
+
+ ld a, [wEnemyTurnsTaken]
+ and a
+ ret z
+
+ ld hl, wBuffer1 - 1
+ ld de, wEnemyMonMoves
+ ld c, wEnemyMonMovesEnd - wEnemyMonMoves + 1
+.asm_393eb
+ inc hl
+ dec c
+ ret z
+
+ ld a, [de]
+ inc de
+ and a
+ ret z
+
+ push hl
+ push de
+ push bc
+ ld hl, ResidualMoves
+ ld de, 1
+ call IsInArray
+
+ pop bc
+ pop de
+ pop hl
+ jr nc, .asm_393eb
+
+ call Random
+ cp 90 percent + 1
+ ret nc
+
+ inc [hl]
+ jr .asm_393eb
+
+INCLUDE "data/battle/ai/residual_moves.asm"
+
+
+AI_Status:
+; Dismiss status moves that don't affect the player.
+
+ ld hl, wBuffer1 - 1
+ ld de, wEnemyMonMoves
+ ld b, wEnemyMonMovesEnd - wEnemyMonMoves + 1
+.checkmove
+ dec b
+ ret z
+
+ inc hl
+ ld a, [de]
+ and a
+ ret z
+
+ inc de
+ call AIGetEnemyMove
+
+ ld a, [wEnemyMoveStruct + MOVE_EFFECT]
+ cp EFFECT_TOXIC
+ jr z, .poisonimmunity
+ cp EFFECT_POISON
+ jr z, .poisonimmunity
+ cp EFFECT_SLEEP
+ jr z, .typeimmunity
+ cp EFFECT_PARALYZE
+ jr z, .typeimmunity
+
+ ld a, [wEnemyMoveStruct + MOVE_POWER]
+ and a
+ jr z, .checkmove
+
+ jr .typeimmunity
+
+.poisonimmunity
+ ld a, [wBattleMonType1]
+ cp POISON
+ jr z, .immune
+ ld a, [wBattleMonType2]
+ cp POISON
+ jr z, .immune
+
+.typeimmunity
+ push hl
+ push bc
+ push de
+ ld a, 1
+ ldh [hBattleTurn], a
+ callfar BattleCheckTypeMatchup
+ pop de
+ pop bc
+ pop hl
+
+ ld a, [wTypeMatchup]
+ and a
+ jr nz, .checkmove
+
+.immune
+ call AIDiscourageMove
+ jr .checkmove
+
+
+AI_Risky:
+; Use any move that will KO the target.
+; Risky moves will often be an exception (see below).
+
+ ld hl, wBuffer1 - 1
+ ld de, wEnemyMonMoves
+ ld c, wEnemyMonMovesEnd - wEnemyMonMoves + 1
+.checkmove
+ inc hl
+ dec c
+ ret z
+
+ ld a, [de]
+ inc de
+ and a
+ ret z
+
+ push de
+ push bc
+ push hl
+ call AIGetEnemyMove
+
+ ld a, [wEnemyMoveStruct + MOVE_POWER]
+ and a
+ jr z, .nextmove
+
+; Don't use risky moves at max hp.
+ ld a, [wEnemyMoveStruct + MOVE_EFFECT]
+ ld de, 1
+ ld hl, RiskyEffects
+ call IsInArray
+ jr nc, .checkko
+
+ call AICheckEnemyMaxHP
+ jr c, .nextmove
+
+; Else, 80% chance to exclude them.
+ call Random
+ cp 79 percent - 1
+ jr c, .nextmove
+
+.checkko
+ call AIDamageCalc
+
+ ld a, [wCurDamage + 1]
+ ld e, a
+ ld a, [wCurDamage]
+ ld d, a
+ ld a, [wBattleMonHP + 1]
+ cp e
+ ld a, [wBattleMonHP]
+ sbc d
+ jr nc, .nextmove
+
+ pop hl
+rept 5
+ dec [hl]
+endr
+ push hl
+
+.nextmove
+ pop hl
+ pop bc
+ pop de
+ jr .checkmove
+
+INCLUDE "data/battle/ai/risky_effects.asm"
+
+
+AI_None:
+ ret
+
+AIDiscourageMove:
+ ld a, [hl]
+ add 10
+ ld [hl], a
+ ret
+
+AIGetEnemyMove:
+; Load attributes of move a into ram
+
+ push hl
+ push de
+ push bc
+ dec a
+ ld hl, Moves
+ ld bc, MOVE_LENGTH
+ call AddNTimes
+
+ ld de, wEnemyMoveStruct
+ ld a, BANK(Moves)
+ call FarCopyBytes
+
+ pop bc
+ pop de
+ pop hl
+ ret
+
+AI_80_20:
+ call Random
+ cp 20 percent - 1
+ ret
+
+AI_50_50:
+ call Random
+ cp 50 percent + 1
+ ret
diff --git a/engine/battle/ai/switch.asm b/engine/battle/ai/switch.asm
new file mode 100644
index 00000000..1998e7ec
--- /dev/null
+++ b/engine/battle/ai/switch.asm
@@ -0,0 +1,658 @@
+CheckPlayerMoveTypeMatchups:
+; Check how well the moves you've already used
+; fare against the enemy's Pokemon. Used to
+; score a potential switch.
+ push hl
+ push de
+ push bc
+ ld a, 10
+ ld [wEnemyAISwitchScore], a
+ ld hl, wPlayerUsedMoves
+ ld a, [hl]
+ and a
+ jr z, .unknown_moves
+
+ ld d, NUM_MOVES
+ ld e, 0
+.loop
+ ld a, [hli]
+ and a
+ jr z, .exit
+ push hl
+ dec a
+ ld hl, Moves + MOVE_POWER
+ call GetMoveAttr
+ and a
+ jr z, .next
+
+ inc hl
+ call GetMoveByte
+ ld hl, wEnemyMonType
+ call CheckTypeMatchup
+ ld a, [wTypeMatchup]
+ cp EFFECTIVE + 1 ; 1.0 + 0.1
+ jr nc, .super_effective
+ and a
+ jr z, .next
+ cp EFFECTIVE ; 1.0
+ jr nc, .neutral
+
+.not_very_effective
+ ld a, e
+ cp 1 ; 0.1
+ jr nc, .next
+ ld e, 1
+ jr .next
+
+.neutral
+ ld e, 2
+ jr .next
+
+.super_effective
+ call .DecreaseScore
+ pop hl
+ jr .done
+
+.next
+ pop hl
+ dec d
+ jr nz, .loop
+
+.exit
+ ld a, e
+ cp 2
+ jr z, .done
+ call .IncreaseScore
+ ld a, e
+ and a
+ jr nz, .done
+ call .IncreaseScore
+ jr .done
+
+.unknown_moves
+ ld a, [wBattleMonType1]
+ ld b, a
+ ld hl, wEnemyMonType1
+ call CheckTypeMatchup
+ ld a, [wTypeMatchup]
+ cp EFFECTIVE + 1 ; 1.0 + 0.1
+ jr c, .ok
+ call .DecreaseScore
+.ok
+ ld a, [wBattleMonType2]
+ cp b
+ jr z, .ok2
+ call CheckTypeMatchup
+ ld a, [wTypeMatchup]
+ cp EFFECTIVE + 1 ; 1.0 + 0.1
+ jr c, .ok2
+ call .DecreaseScore
+.ok2
+
+.done
+ call .CheckEnemyMoveMatchups
+ pop bc
+ pop de
+ pop hl
+ ret
+
+.CheckEnemyMoveMatchups:
+ ld de, wEnemyMonMoves
+ ld b, NUM_MOVES + 1
+ ld c, 0
+
+ ld a, [wTypeMatchup]
+ push af
+.loop2
+ dec b
+ jr z, .exit2
+
+ ld a, [de]
+ and a
+ jr z, .exit2
+
+ inc de
+ dec a
+ ld hl, Moves + MOVE_POWER
+ call GetMoveAttr
+ and a
+ jr z, .loop2
+
+ inc hl
+ call GetMoveByte
+ ld hl, wBattleMonType1
+ call CheckTypeMatchup
+
+ ld a, [wTypeMatchup]
+ ; immune
+ and a
+ jr z, .loop2
+
+ ; not very effective
+ inc c
+ cp EFFECTIVE
+ jr c, .loop2
+
+ ; neutral
+ inc c
+ inc c
+ inc c
+ inc c
+ inc c
+ cp EFFECTIVE
+ jr z, .loop2
+
+ ; super effective
+ ld c, 100
+ jr .loop2
+
+.exit2
+ pop af
+ ld [wTypeMatchup], a
+
+ ld a, c
+ and a
+ jr z, .doubledown ; double down
+ cp 5
+ jr c, .DecreaseScore ; down
+ cp 100
+ ret c
+ jr .IncreaseScore ; up
+
+.doubledown
+ call .DecreaseScore
+.DecreaseScore:
+ ld a, [wEnemyAISwitchScore]
+ dec a
+ ld [wEnemyAISwitchScore], a
+ ret
+
+.IncreaseScore:
+ ld a, [wEnemyAISwitchScore]
+ inc a
+ ld [wEnemyAISwitchScore], a
+ ret
+
+CheckAbleToSwitch:
+ xor a
+ ld [wEnemySwitchMonParam], a
+ call FindAliveEnemyMons
+ ret c
+
+ ld a, [wEnemySubStatus1]
+ bit SUBSTATUS_PERISH, a
+ jr z, .no_perish
+
+ ld a, [wEnemyPerishCount]
+ cp 1
+ jr nz, .no_perish
+
+ ; Perish count is 1
+
+ call FindAliveEnemyMons
+ call FindEnemyMonsWithAtLeastQuarterMaxHP
+ call FindEnemyMonsThatResistPlayer
+ call FindAliveEnemyMonsWithASuperEffectiveMove
+
+ ld a, e
+ cp 2
+ jr nz, .not_2
+
+ ld a, [wEnemyAISwitchScore]
+ add $30 ; maximum chance
+ ld [wEnemySwitchMonParam], a
+ ret
+
+.not_2
+ call FindAliveEnemyMons
+ sla c
+ sla c
+ ld b, $ff
+
+.loop1
+ inc b
+ sla c
+ jr nc, .loop1
+
+ ld a, b
+ add $30 ; maximum chance
+ ld [wEnemySwitchMonParam], a
+ ret
+
+.no_perish
+ call CheckPlayerMoveTypeMatchups
+ ld a, [wEnemyAISwitchScore]
+ cp 11
+ ret nc
+
+ ld a, [wLastPlayerCounterMove]
+ and a
+ jr z, .no_last_counter_move
+
+ call FindEnemyMonsImmuneToLastCounterMove
+ ld a, [wEnemyAISwitchScore]
+ and a
+ jr z, .no_last_counter_move
+
+ ld c, a
+ call FindEnemyMonsWithASuperEffectiveMove
+ ld a, [wEnemyAISwitchScore]
+ cp $ff
+ ret z
+
+ ld b, a
+ ld a, e
+ cp 2
+ jr z, .not_2_again
+
+ call CheckPlayerMoveTypeMatchups
+ ld a, [wEnemyAISwitchScore]
+ cp 10
+ ret nc
+
+ ld a, b
+ add $10
+ ld [wEnemySwitchMonParam], a
+ ret
+
+.not_2_again
+ ld c, $10
+ call CheckPlayerMoveTypeMatchups
+ ld a, [wEnemyAISwitchScore]
+ cp 10
+ jr nc, .okay
+ ld c, $20
+
+.okay
+ ld a, b
+ add c
+ ld [wEnemySwitchMonParam], a
+ ret
+
+.no_last_counter_move
+ call CheckPlayerMoveTypeMatchups
+ ld a, [wEnemyAISwitchScore]
+ cp 10
+ ret nc
+
+ call FindAliveEnemyMons
+ call FindEnemyMonsWithAtLeastQuarterMaxHP
+ call FindEnemyMonsThatResistPlayer
+ call FindAliveEnemyMonsWithASuperEffectiveMove
+
+ ld a, e
+ cp $2
+ ret nz
+
+ ld a, [wEnemyAISwitchScore]
+ add $10
+ ld [wEnemySwitchMonParam], a
+ ret
+
+FindAliveEnemyMons:
+ ld a, [wOTPartyCount]
+ cp 2
+ jr c, .only_one
+
+ ld d, a
+ ld e, 0
+ ld b, 1 << (PARTY_LENGTH - 1)
+ ld c, 0
+ ld hl, wOTPartyMon1HP
+
+.loop
+ ld a, [wCurOTMon]
+ cp e
+ jr z, .next
+
+ push bc
+ ld b, [hl]
+ inc hl
+ ld a, [hld]
+ or b
+ pop bc
+ jr z, .next
+
+ ld a, c
+ or b
+ ld c, a
+
+.next
+ srl b
+ push bc
+ ld bc, PARTYMON_STRUCT_LENGTH
+ add hl, bc
+ pop bc
+ inc e
+ dec d
+ jr nz, .loop
+
+ ld a, c
+ and a
+ jr nz, .more_than_one
+
+.only_one
+ scf
+ ret
+
+.more_than_one
+ and a
+ ret
+
+FindEnemyMonsImmuneToLastCounterMove:
+ ld hl, wOTPartyMon1
+ ld a, [wOTPartyCount]
+ ld b, a
+ ld c, 1 << (PARTY_LENGTH - 1)
+ ld d, 0
+ xor a
+ ld [wEnemyAISwitchScore], a
+
+.loop
+ ld a, [wCurOTMon]
+ cp d
+ push hl
+ jr z, .next
+
+ push hl
+ push bc
+
+ ; If the Pokemon has at least 1 HP...
+ ld bc, MON_HP
+ add hl, bc
+ pop bc
+ ld a, [hli]
+ or [hl]
+ pop hl
+ jr z, .next
+
+ ld a, [hl]
+ ld [wCurSpecies], a
+ call GetBaseData
+
+ ; the player's last move is damaging...
+ ld a, [wLastPlayerCounterMove]
+ dec a
+ ld hl, Moves + MOVE_POWER
+ call GetMoveAttr
+ and a
+ jr z, .next
+
+ ; and the Pokemon is immune to it...
+ inc hl
+ call GetMoveByte
+ ld hl, wBaseType
+ call CheckTypeMatchup
+ ld a, [wTypeMatchup]
+ and a
+ jr nz, .next
+
+ ; ... encourage that Pokemon.
+ ld a, [wEnemyAISwitchScore]
+ or c
+ ld [wEnemyAISwitchScore], a
+.next
+ pop hl
+ dec b
+ ret z
+
+ push bc
+ ld bc, PARTYMON_STRUCT_LENGTH
+ add hl, bc
+ pop bc
+
+ inc d
+ srl c
+ jr .loop
+
+FindAliveEnemyMonsWithASuperEffectiveMove:
+ push bc
+ ld a, [wOTPartyCount]
+ ld e, a
+ ld hl, wOTPartyMon1HP
+ ld b, 1 << (PARTY_LENGTH - 1)
+ ld c, 0
+.loop
+ ld a, [hli]
+ or [hl]
+ jr z, .next
+
+ ld a, b
+ or c
+ ld c, a
+
+.next
+ srl b
+ push bc
+ ld bc, wPartyMon2HP - (wPartyMon1HP + 1)
+ add hl, bc
+ pop bc
+ dec e
+ jr nz, .loop
+
+ ld a, c
+ pop bc
+
+ and c
+ ld c, a
+ ; fallthrough
+
+FindEnemyMonsWithASuperEffectiveMove:
+ ld a, -1
+ ld [wEnemyAISwitchScore], a
+ ld hl, wOTPartyMon1Moves
+ ld b, 1 << (PARTY_LENGTH - 1)
+ ld d, 0
+ ld e, 0
+.loop
+ ld a, b
+ and c
+ jr z, .next
+
+ push hl
+ push bc
+ ; for move on mon:
+ ld b, NUM_MOVES
+ ld c, 0
+.loop3
+ ; if move is None: break
+ ld a, [hli]
+ and a
+ push hl
+ jr z, .break3
+
+ ; if move has no power: continue
+ dec a
+ ld hl, Moves + MOVE_POWER
+ call GetMoveAttr
+ and a
+ jr z, .nope
+
+ ; check type matchups
+ inc hl
+ call GetMoveByte
+ ld hl, wBattleMonType1
+ call CheckTypeMatchup
+
+ ; if immune or not very effective: continue
+ ld a, [wTypeMatchup]
+ cp 10
+ jr c, .nope
+
+ ; if neutral: load 1 and continue
+ ld e, 1
+ cp EFFECTIVE + 1
+ jr c, .nope
+
+ ; if super-effective: load 2 and break
+ ld e, 2
+ jr .break3
+
+.nope
+ pop hl
+ dec b
+ jr nz, .loop3
+
+ jr .done
+
+.break3
+ pop hl
+.done
+ ld a, e
+ pop bc
+ pop hl
+ cp 2
+ jr z, .done2 ; at least one move is super-effective
+ cp 1
+ jr nz, .next ; no move does more than half damage
+
+ ; encourage this pokemon
+ ld a, d
+ or b
+ ld d, a
+ jr .next ; such a long jump
+
+.next
+ ; next pokemon?
+ push bc
+ ld bc, PARTYMON_STRUCT_LENGTH
+ add hl, bc
+ pop bc
+ srl b
+ jr nc, .loop
+
+ ; if no pokemon has a super-effective move: return
+ ld a, d
+ ld b, a
+ and a
+ ret z
+
+.done2
+ ; convert the bit flag to an int and return
+ push bc
+ sla b
+ sla b
+ ld c, $ff
+.loop2
+ inc c
+ sla b
+ jr nc, .loop2
+
+ ld a, c
+ ld [wEnemyAISwitchScore], a
+ pop bc
+ ret
+
+FindEnemyMonsThatResistPlayer:
+ push bc
+ ld hl, wOTPartyCount
+ ld b, 1 << (PARTY_LENGTH - 1)
+ ld c, 0
+
+.loop
+ ld a, [hli]
+ cp $ff
+ jr z, .done
+
+ push hl
+ ld [wCurSpecies], a
+ call GetBaseData
+ ld a, [wLastPlayerCounterMove]
+ and a
+ jr z, .skip_move
+
+ dec a
+ ld hl, Moves + MOVE_POWER
+ call GetMoveAttr
+ and a
+ jr z, .skip_move
+
+ inc hl
+ call GetMoveByte
+ jr .check_type
+
+.skip_move
+ ld a, [wBattleMonType1]
+ ld hl, wBaseType
+ call CheckTypeMatchup
+ ld a, [wTypeMatchup]
+ cp 10 + 1
+ jr nc, .dont_choose_mon
+ ld a, [wBattleMonType2]
+
+.check_type
+ ld hl, wBaseType
+ call CheckTypeMatchup
+ ld a, [wTypeMatchup]
+ cp EFFECTIVE + 1
+ jr nc, .dont_choose_mon
+
+ ld a, b
+ or c
+ ld c, a
+
+.dont_choose_mon
+ srl b
+ pop hl
+ jr .loop
+
+.done
+ ld a, c
+ pop bc
+ and c
+ ld c, a
+ ret
+
+FindEnemyMonsWithAtLeastQuarterMaxHP:
+ push bc
+ ld de, wOTPartyCount
+ ld b, 1 << (PARTY_LENGTH - 1)
+ ld c, 0
+ ld hl, wOTPartyMon1HP
+
+.loop
+ ld a, [de]
+ inc de
+ cp $ff
+ jr z, .done
+
+ push hl
+ push bc
+ ld b, [hl]
+ inc hl
+ ld c, [hl]
+ inc hl
+ inc hl
+; hl = MaxHP + 1
+; bc = [CurHP] * 4
+ srl c
+ rl b
+ srl c
+ rl b
+; if bc >= [hl], encourage
+ ld a, [hld]
+ cp c
+ ld a, [hl]
+ sbc b
+ pop bc
+ jr nc, .next
+
+ ld a, b
+ or c
+ ld c, a
+
+.next
+ srl b
+ pop hl
+ push bc
+ ld bc, PARTYMON_STRUCT_LENGTH
+ add hl, bc
+ pop bc
+ jr .loop
+
+.done
+ ld a, c
+ pop bc
+ and c
+ ld c, a
+ ret
diff --git a/engine/anim_hp_bar.asm b/engine/battle/anim_hp_bar.asm
index 561cba42..9248ad4f 100755
--- a/engine/anim_hp_bar.asm
+++ b/engine/battle/anim_hp_bar.asm
@@ -1,61 +1,59 @@
-HP_BAR_MAX_PIXELS EQU $30
-
-AnimateHPBar_: ; d62d (3:562d)
- call Functiond665
- jr c, .asm_d64b
- call Functiond676
-.asm_d635
+_AnimateHPBar:
+ call .IsMaximumMoreThan48Pixels
+ jr c, .MoreThan48Pixels
+ call .ComputePixels
+.ShortAnimLoop:
push bc
push hl
- call Functiond6e8
+ call ShortAnim_UpdateVariables
pop hl
pop bc
push af
push bc
push hl
- call Functiond736
- call Functiond7cf
+ call ShortHPBarAnim_UpdateTiles
+ call HPBarAnim_BGMapUpdate
pop hl
pop bc
pop af
- jr nc, .asm_d635
+ jr nc, .ShortAnimLoop
ret
-.asm_d64b
- call Functiond676
-.asm_d64e
+.MoreThan48Pixels:
+ call .ComputePixels
+.LongAnimLoop:
push bc
push hl
- call Functiond6fb
+ call LongAnim_UpdateVariables
pop hl
pop bc
ret c
push af
push bc
push hl
- call Functiond74f
- call Functiond7cf
+ call LongHPBarAnim_UpdateTiles
+ call HPBarAnim_BGMapUpdate
pop hl
pop bc
pop af
- jr nc, .asm_d64e
+ jr nc, .LongAnimLoop
ret
-Functiond665: ; d665 (3:5665)
+.IsMaximumMoreThan48Pixels:
ld a, [wCurHPAnimMaxHP + 1]
and a
- jr nz, .asm_d674
+ jr nz, .player
ld a, [wCurHPAnimMaxHP]
- cp HP_BAR_MAX_PIXELS
- jr nc, .asm_d674
+ cp HP_BAR_LENGTH_PX
+ jr nc, .player
and a
ret
-.asm_d674
+.player
scf
ret
-Functiond676: ; d676 (3:5676)
+.ComputePixels:
push hl
ld hl, wCurHPAnimMaxHP
ld a, [hli]
@@ -70,6 +68,7 @@ Functiond676: ; d676 (3:5676)
call ComputeHPBarPixels
ld a, e
ld [wCurHPBarPixels], a
+
ld a, [wCurHPAnimNewHP]
ld c, a
ld a, [wCurHPAnimNewHP + 1]
@@ -81,6 +80,7 @@ Functiond676: ; d676 (3:5676)
call ComputeHPBarPixels
ld a, e
ld [wNewHPBarPixels], a
+
push hl
ld hl, wCurHPAnimOldHP
ld a, [hli]
@@ -98,15 +98,15 @@ Functiond676: ; d676 (3:5676)
ld a, d
sbc b
ld d, a
- jr c, .asm_d6c7
+ jr c, .negative
ld a, [wCurHPAnimOldHP]
ld [wCurHPAnimLowHP], a
ld a, [wCurHPAnimNewHP]
ld [wCurHPAnimHighHP], a
- ld bc, $1
- jr .asm_d6df
+ ld bc, 1
+ jr .got_direction
-.asm_d6c7
+.negative
ld a, [wCurHPAnimOldHP]
ld [wCurHPAnimHighHP], a
ld a, [wCurHPAnimNewHP]
@@ -118,31 +118,32 @@ Functiond676: ; d676 (3:5676)
ld a, d
xor $ff
ld d, a
- ld bc, rIE
-.asm_d6df
+ ld bc, -1
+.got_direction
ld a, d
ld [wCurHPAnimDeltaHP], a
ld a, e
ld [wCurHPAnimDeltaHP + 1], a
ret
-Functiond6e8: ; d6e8 (3:56e8)
+ShortAnim_UpdateVariables:
ld hl, wCurHPBarPixels
ld a, [wNewHPBarPixels]
cp [hl]
- jr nz, .asm_d6f3
+ jr nz, .not_finished
scf
ret
-.asm_d6f3
+.not_finished
ld a, c
add [hl]
ld [hl], a
- call Functiond83f
+ call ShortHPBar_CalcPixelFrame
and a
ret
-Functiond6fb: ; d6fb (3:56fb)
+LongAnim_UpdateVariables:
+.loop
ld hl, wCurHPAnimOldHP
ld a, [hli]
ld e, a
@@ -150,15 +151,15 @@ Functiond6fb: ; d6fb (3:56fb)
ld d, a
ld a, e
cp [hl]
- jr nz, .asm_d70d
+ jr nz, .next
inc hl
ld a, d
cp [hl]
- jr nz, .asm_d70d
+ jr nz, .next
scf
ret
-.asm_d70d
+.next
ld l, e
ld h, d
add hl, bc
@@ -178,27 +179,26 @@ Functiond6fb: ; d6fb (3:56fb)
ld c, a
ld a, [hli]
ld b, a
- ; BUG: This routine is meant to make the HP bar move at
- ; the same rate regardless of how many HP the Pokemon has.
- ; In actuality, this causes Pokemon with more than 48 HP
- ; to gain or lose HP at the rate of 1 HP per BGMap update
- ; rather than 1 pixel on the HUD.
- ; To fix, move the "ld a, e" above the "pop de".
- call ComputeHPBarPixels ; returns to e
+ ; This routine is buggy. The result from ComputeHPBarPixels is stored
+ ; in e. However, the pop de opcode deletes this result before it is even
+ ; used. The game then proceeds as though it never deleted that output.
+ ; To fix, uncomment the line below.
+ call ComputeHPBarPixels
+ ; ld a, e
pop bc
- pop de ; overloads e
+ pop de
pop hl
- ld a, e ; expects result from ComputeHPBarPixels
+ ld a, e ; Comment or delete this line to fix the above bug.
ld hl, wCurHPBarPixels
cp [hl]
- jr z, Functiond6fb
+ jr z, .loop
ld [hl], a
and a
ret
-Functiond736: ; d736 (3:5736)
- call Functiond78a
- ld d, $6
+ShortHPBarAnim_UpdateTiles:
+ call HPBarAnim_UpdateHPRemaining
+ ld d, HP_BAR_LENGTH
ld a, [wWhichHPBar]
and $1
ld b, a
@@ -206,13 +206,13 @@ Functiond736: ; d736 (3:5736)
ld e, a
ld c, a
push de
- call Functiond777
+ call HPBarAnim_RedrawHPBar
pop de
- call Functiond7ba
+ call HPBarAnim_PaletteUpdate
ret
-Functiond74f: ; d74f (3:574f)
- call Functiond78a
+LongHPBarAnim_UpdateTiles:
+ call HPBarAnim_UpdateHPRemaining
ld a, [wCurHPAnimOldHP]
ld c, a
ld a, [wCurHPAnimOldHP + 1]
@@ -223,45 +223,45 @@ Functiond74f: ; d74f (3:574f)
ld d, a
call ComputeHPBarPixels
ld c, e
- ld d, $6
+ ld d, HP_BAR_LENGTH
ld a, [wWhichHPBar]
and $1
ld b, a
push de
- call Functiond777
+ call HPBarAnim_RedrawHPBar
pop de
- call Functiond7ba
+ call HPBarAnim_PaletteUpdate
ret
-Functiond777: ; d777 (3:5777)
+HPBarAnim_RedrawHPBar:
ld a, [wWhichHPBar]
cp $2
- jr nz, .asm_d786
- ld a, $28
+ jr nz, .skip
+ ld a, 2 * SCREEN_WIDTH
add l
ld l, a
- ld a, $0
+ ld a, 0
adc h
ld h, a
-.asm_d786
+.skip
call DrawBattleHPBar
ret
-Functiond78a: ; d78a (3:578a)
+HPBarAnim_UpdateHPRemaining:
ld a, [wWhichHPBar]
and a
ret z
cp $1
- jr z, .asm_d798
- ld de, $16
- jr .asm_d79b
+ jr z, .load_15
+ ld de, SCREEN_WIDTH + 2
+ jr .loaded_de
-.asm_d798
- ld de, $15
-.asm_d79b
+.load_15
+ ld de, SCREEN_WIDTH + 1
+.loaded_de
push hl
add hl, de
- ld a, $7f
+ ld a, " "
ld [hli], a
ld [hli], a
ld [hld], a
@@ -276,7 +276,7 @@ Functiond78a: ; d78a (3:578a)
pop hl
ret
-Functiond7ba: ; d7ba (3:57ba)
+HPBarAnim_PaletteUpdate:
ldh a, [hCGB]
and a
ret z
@@ -284,45 +284,43 @@ Functiond7ba: ; d7ba (3:57ba)
call SetHPPal
ld a, [wCurHPAnimPal]
ld c, a
- ld a, $2
- ld hl, $520b
- rst FarCall
+ farcall ApplyHPBarPals
ret
-Functiond7cf: ; d7cf (3:57cf)
+HPBarAnim_BGMapUpdate:
ldh a, [hCGB]
and a
- jr nz, .asm_d7db
+ jr nz, .cgb
call DelayFrame
call DelayFrame
ret
-.asm_d7db
+.cgb
ld a, [wWhichHPBar]
and a
- jr z, .asm_d82f
+ jr z, .load_0
cp $1
- jr z, .asm_d833
+ jr z, .load_1
ld a, [wCurPartyMon]
cp $3
- jr nc, .asm_d7f0
+ jr nc, .bottom_half_of_screen
ld c, $0
- jr .asm_d7f2
+ jr .got_third
-.asm_d7f0
+.bottom_half_of_screen
ld c, $1
-.asm_d7f2
+.got_third
push af
cp $2
- jr z, .asm_d805
+ jr z, .skip_delay
cp $5
- jr z, .asm_d805
+ jr z, .skip_delay
ld a, $2
ldh [hBGMapMode], a
ld a, c
ldh [hBGMapThird], a
call DelayFrame
-.asm_d805
+.skip_delay
ld a, $1
ldh [hBGMapMode], a
ld a, c
@@ -330,12 +328,12 @@ Functiond7cf: ; d7cf (3:57cf)
call DelayFrame
pop af
cp $2
- jr z, .asm_d819
+ jr z, .two_frames
cp $5
- jr z, .asm_d819
+ jr z, .two_frames
ret
-.asm_d819
+.two_frames
inc c
ld a, $2
ldh [hBGMapMode], a
@@ -349,73 +347,78 @@ Functiond7cf: ; d7cf (3:57cf)
call DelayFrame
ret
-.asm_d82f
+.load_0
ld c, $0
- jr .asm_d835
+ jr .finish
-.asm_d833
+.load_1
ld c, $1
-.asm_d835
+.finish
call DelayFrame
ld a, c
ldh [hBGMapThird], a
call DelayFrame
ret
-Functiond83f: ; d83f (3:583f)
+ShortHPBar_CalcPixelFrame:
ld a, [wCurHPAnimMaxHP]
ld c, a
- ld b, $0
- ld hl, $0
+ ld b, 0
+ ld hl, 0
ld a, [wCurHPBarPixels]
- cp HP_BAR_MAX_PIXELS
- jr nc, .asm_d88b
+ cp HP_BAR_LENGTH_PX
+ jr nc, .return_max
and a
- jr z, .asm_d886
+ jr z, .return_zero
call AddNTimes
- ld b, $0
-.asm_d857
+
+ ld b, 0
+; This routine is buggy. If [wCurHPAnimMaxHP] * [wCurHPBarPixels] is
+; divisible by HP_BAR_LENGTH_PX, the loop runs one extra time.
+; To fix, uncomment the line below.
+.loop
ld a, l
- sub HP_BAR_MAX_PIXELS % $100
+ sub HP_BAR_LENGTH_PX
ld l, a
ld a, h
- sbc HP_BAR_MAX_PIXELS / $100
+ sbc $0
ld h, a
- jr c, .asm_d864
+ ; jr z, .done
+ jr c, .done
inc b
- jr .asm_d857
+ jr .loop
-.asm_d864
+.done
push bc
ld bc, $80
add hl, bc
pop bc
ld a, l
- sub HP_BAR_MAX_PIXELS % $100
+ sub HP_BAR_LENGTH_PX
ld l, a
ld a, h
- sbc HP_BAR_MAX_PIXELS / $100
+ sbc $0
ld h, a
- jr c, .asm_d875
+ jr c, .no_carry
inc b
-.asm_d875
+.no_carry
ld a, [wCurHPAnimLowHP]
cp b
- jr nc, .asm_d882
+ jr nc, .finish
ld a, [wCurHPAnimHighHP]
cp b
- jr c, .asm_d882
+ jr c, .finish
ld a, b
-.asm_d882
+.finish
ld [wCurHPAnimOldHP], a
ret
-.asm_d886
+.return_zero
xor a
ld [wCurHPAnimOldHP], a
ret
-.asm_d88b
+.return_max
ld a, [wCurHPAnimMaxHP]
ld [wCurHPAnimOldHP], a
ret
diff --git a/engine/battle/consume_held_item.asm b/engine/battle/consume_held_item.asm
new file mode 100644
index 00000000..c5e3b204
--- /dev/null
+++ b/engine/battle/consume_held_item.asm
@@ -0,0 +1,57 @@
+ConsumeHeldItem:
+ push hl
+ push de
+ push bc
+ ldh a, [hBattleTurn]
+ and a
+ ld hl, wOTPartyMon1Item
+ ld de, wEnemyMonItem
+ ld a, [wCurOTMon]
+ jr z, .theirturn
+ ld hl, wPartyMon1Item
+ ld de, wBattleMonItem
+ ld a, [wCurBattleMon]
+
+.theirturn
+ push hl
+ push af
+ ld a, [de]
+ ld b, a
+ farcall GetItemHeldEffect
+ ld hl, ConsumableEffects
+.loop
+ ld a, [hli]
+ cp b
+ jr z, .ok
+ inc a
+ jr nz, .loop
+ pop af
+ pop hl
+ pop bc
+ pop de
+ pop hl
+ ret
+
+.ok
+ xor a
+ ld [de], a
+ pop af
+ pop hl
+ call GetPartyLocation
+ ldh a, [hBattleTurn]
+ and a
+ jr nz, .ourturn
+ ld a, [wBattleMode]
+ dec a
+ jr z, .done
+
+.ourturn
+ ld [hl], NO_ITEM
+
+.done
+ pop bc
+ pop de
+ pop hl
+ ret
+
+INCLUDE "data/battle/held_consumables.asm"
diff --git a/engine/battle/core.asm b/engine/battle/core.asm
new file mode 100644
index 00000000..512c2598
--- /dev/null
+++ b/engine/battle/core.asm
@@ -0,0 +1,8732 @@
+; Core components of the battle engine.
+
+DoBattle:
+ xor a
+ ld [wBattleParticipantsNotFainted], a
+ ld [wBattleParticipantsIncludingFainted], a
+ ld [wBattlePlayerAction], a
+ ld [wBattleEnded], a
+ inc a
+ ld [wBattleHasJustStarted], a
+ ld hl, wOTPartyMon1HP
+ ld bc, PARTYMON_STRUCT_LENGTH - 1
+ ld d, BATTLEACTION_SWITCH1 - 1
+.loop
+ inc d
+ ld a, [hli]
+ or [hl]
+ jr nz, .alive
+ add hl, bc
+ jr .loop
+
+.alive
+ ld a, d
+ ld [wBattleAction], a
+ ld a, [wLinkMode]
+ and a
+ jr z, .not_linked
+
+ ldh a, [hSerialConnectionStatus]
+ cp USING_INTERNAL_CLOCK
+ jr z, .player_2
+
+.not_linked
+ ld a, [wBattleMode]
+ dec a
+ jr z, .wild
+ xor a
+ ld [wEnemySwitchMonIndex], a
+ call NewEnemyMonStatus
+ call ResetEnemyStatLevels
+ call BreakAttraction
+ call EnemySwitch
+
+.wild
+ ld c, 40
+ call DelayFrames
+
+.player_2
+ call LoadTilemapToTempTilemap
+ call CheckPlayerPartyForFitMon
+ ld a, d
+ and a
+ jp z, LostBattle
+ call SafeLoadTempTilemapToTilemap
+ ld a, [wBattleType]
+ cp BATTLETYPE_DEBUG
+ jp z, .tutorial_debug
+ cp BATTLETYPE_TUTORIAL
+ jp z, .tutorial_debug
+ xor a
+ ld [wCurPartyMon], a
+.loop2
+ call CheckIfCurPartyMonIsFitToFight
+ jr nz, .alive2
+ ld hl, wCurPartyMon
+ inc [hl]
+ jr .loop2
+
+.alive2
+ ld a, [wCurBattleMon]
+ ld [wLastPlayerMon], a
+ ld a, [wCurPartyMon]
+ ld [wCurBattleMon], a
+ inc a
+ ld hl, wPartySpecies - 1
+ ld c, a
+ ld b, 0
+ add hl, bc
+ ld a, [hl]
+ ld [wCurPartySpecies], a
+ ld [wTempBattleMonSpecies], a
+ hlcoord 1, 5
+ ld a, 9
+ call SlideBattlePicOut
+ call LoadTilemapToTempTilemap
+ call ResetBattleParticipants
+ call InitBattleMon
+ call ResetPlayerStatLevels
+ call SendOutMonText
+ call NewBattleMonStatus
+ call BreakAttraction
+ call SendOutPlayerMon
+ call EmptyBattleTextbox
+ call LoadTilemapToTempTilemap
+ call SetPlayerTurn
+ call SpikesDamage
+ ld a, [wLinkMode]
+ and a
+ jr z, .not_linked_2
+ ldh a, [hSerialConnectionStatus]
+ cp USING_INTERNAL_CLOCK
+ jr nz, .not_linked_2
+ xor a
+ ld [wEnemySwitchMonIndex], a
+ call NewEnemyMonStatus
+ call ResetEnemyStatLevels
+ call BreakAttraction
+ call EnemySwitch
+ call SetEnemyTurn
+ call SpikesDamage
+
+.not_linked_2
+ jp BattleTurn
+
+.tutorial_debug
+ jp BattleMenu
+
+WildFled_EnemyFled_LinkBattleCanceled:
+ call SafeLoadTempTilemapToTilemap
+ ld a, [wBattleResult]
+ and BATTLERESULT_BITMASK
+ add DRAW
+ ld [wBattleResult], a
+ ld a, [wLinkMode]
+ and a
+ ld hl, BattleText_WildFled
+ jr z, .print_text
+
+ ld a, [wBattleResult]
+ and BATTLERESULT_BITMASK
+ ld [wBattleResult], a ; WIN
+ ld hl, BattleText_EnemyFled
+
+.print_text
+ call StdBattleTextbox
+ call StopDangerSound
+ ld de, SFX_RUN
+ call PlaySFX
+ call SetPlayerTurn
+ callfar DummyPredef38
+ ld a, 1
+ ld [wBattleEnded], a
+ ret
+
+BattleTurn:
+.loop
+ call CheckContestBattleOver
+ jr c, .quit
+
+ xor a
+ ld [wPlayerIsSwitching], a
+ ld [wEnemyIsSwitching], a
+ ld [wBattleHasJustStarted], a
+ ld [wPlayerJustGotFrozen], a
+ ld [wEnemyJustGotFrozen], a
+ ld [wCurDamage], a
+ ld [wCurDamage + 1], a
+
+ call HandleBerserkGene
+ call UpdateBattleMonInParty
+ farcall AIChooseMove
+ call CheckPlayerLockedIn
+ jr c, .skip_iteration
+.loop1
+ call BattleMenu
+ jr c, .quit
+ ld a, [wBattleEnded]
+ and a
+ jr nz, .quit
+ ld a, [wForcedSwitch] ; roared/whirlwinded/teleported
+ and a
+ jr nz, .quit
+.skip_iteration
+ call ParsePlayerAction
+ jr nz, .loop1
+
+ call EnemyTriesToFlee
+ jr c, .quit
+
+ call DetermineMoveOrder
+ jr c, .false
+ call Battle_EnemyFirst
+ jr .proceed
+.false
+ call Battle_PlayerFirst
+.proceed
+ ld a, [wForcedSwitch]
+ and a
+ jr nz, .quit
+
+ ld a, [wBattleEnded]
+ and a
+ jr nz, .quit
+
+ call HandleBetweenTurnEffects
+ ld a, [wBattleEnded]
+ and a
+ jr nz, .quit
+ jr .loop
+
+.quit
+ ret
+
+HandleBetweenTurnEffects:
+ ldh a, [hSerialConnectionStatus]
+ cp USING_EXTERNAL_CLOCK
+ jr z, .CheckEnemyFirst
+ call CheckFaint_PlayerThenEnemy
+ ret c
+ call HandleFutureSight
+ call CheckFaint_PlayerThenEnemy
+ ret c
+ call HandleWeather
+ call CheckFaint_PlayerThenEnemy
+ ret c
+ call HandleWrap
+ call CheckFaint_PlayerThenEnemy
+ ret c
+ call HandlePerishSong
+ call CheckFaint_PlayerThenEnemy
+ ret c
+ jr .NoMoreFaintingConditions
+
+.CheckEnemyFirst:
+ call CheckFaint_EnemyThenPlayer
+ ret c
+ call HandleFutureSight
+ call CheckFaint_EnemyThenPlayer
+ ret c
+ call HandleWeather
+ call CheckFaint_EnemyThenPlayer
+ ret c
+ call HandleWrap
+ call CheckFaint_EnemyThenPlayer
+ ret c
+ call HandlePerishSong
+ call CheckFaint_EnemyThenPlayer
+ ret c
+
+.NoMoreFaintingConditions:
+ call HandleLeftovers
+ call HandleMysteryberry
+ call HandleDefrost
+ call HandleSafeguard
+ call HandleScreens
+ call HandleStatBoostingHeldItems
+ call HandleHealingItems
+ call UpdateBattleMonInParty
+ call LoadTilemapToTempTilemap
+ jp HandleEncore
+
+CheckFaint_PlayerThenEnemy:
+ call HasPlayerFainted
+ jr nz, .PlayerNotFainted
+ call HandlePlayerMonFaint
+ ld a, [wBattleEnded]
+ and a
+ jr nz, .BattleIsOver
+
+.PlayerNotFainted:
+ call HasEnemyFainted
+ jr nz, .BattleContinues
+ call HandleEnemyMonFaint
+ ld a, [wBattleEnded]
+ and a
+ jr nz, .BattleIsOver
+
+.BattleContinues:
+ and a
+ ret
+
+.BattleIsOver:
+ scf
+ ret
+
+CheckFaint_EnemyThenPlayer:
+ call HasEnemyFainted
+ jr nz, .EnemyNotFainted
+ call HandleEnemyMonFaint
+ ld a, [wBattleEnded]
+ and a
+ jr nz, .BattleIsOver
+
+.EnemyNotFainted:
+ call HasPlayerFainted
+ jr nz, .BattleContinues
+ call HandlePlayerMonFaint
+ ld a, [wBattleEnded]
+ and a
+ jr nz, .BattleIsOver
+
+.BattleContinues:
+ and a
+ ret
+
+.BattleIsOver:
+ scf
+ ret
+
+HandleBerserkGene:
+ ldh a, [hSerialConnectionStatus]
+ cp USING_EXTERNAL_CLOCK
+ jr z, .reverse
+
+ call .player
+ jr .enemy
+
+.reverse
+ call .enemy
+ ; fallthrough
+
+.player
+ call SetPlayerTurn
+ ld de, wPartyMon1Item
+ ld a, [wCurBattleMon]
+ ld b, a
+ jr .go
+
+.enemy
+ call SetEnemyTurn
+ ld de, wOTPartyMon1Item
+ ld a, [wCurOTMon]
+ ld b, a
+ ; fallthrough
+
+.go
+ push de
+ push bc
+ callfar GetUserItem
+ ld a, [hl]
+ ld [wNamedObjectIndexBuffer], a
+ sub BERSERK_GENE
+ pop bc
+ pop de
+ ret nz
+
+ ld [hl], a
+
+ ld h, d
+ ld l, e
+ ld a, b
+ call GetPartyLocation
+ xor a
+ ld [hl], a
+ ld a, BATTLE_VARS_SUBSTATUS3
+ call GetBattleVarAddr
+ push af
+ set SUBSTATUS_CONFUSED, [hl]
+ ld a, BATTLE_VARS_MOVE_ANIM
+ call GetBattleVarAddr
+ push hl
+ push af
+ xor a
+ ld [hl], a
+ ld [wAttackMissed], a
+ ld [wEffectFailed], a
+ farcall BattleCommand_AttackUp2
+ pop af
+ pop hl
+ ld [hl], a
+ call GetItemName
+ ld hl, BattleText_UsersStringBuffer1Activated
+ call StdBattleTextbox
+ callfar BattleCommand_StatUpMessage
+ pop af
+ bit SUBSTATUS_CONFUSED, a
+ ret nz
+ xor a
+ ld [wNumHits], a
+ ld de, ANIM_CONFUSED
+ call Call_PlayBattleAnim_OnlyIfVisible
+ call SwitchTurnCore
+ ld hl, BecameConfusedText
+ jp StdBattleTextbox
+
+EnemyTriesToFlee:
+ ld a, [wLinkMode]
+ and a
+ jr z, .not_linked
+ ld a, [wBattleAction]
+ cp BATTLEACTION_FORFEIT
+ jr z, .forfeit
+
+.not_linked
+ and a
+ ret
+
+.forfeit
+ call WildFled_EnemyFled_LinkBattleCanceled
+ scf
+ ret
+
+DetermineMoveOrder:
+ ld a, [wLinkMode]
+ and a
+ jr z, .use_move
+ ld a, [wBattleAction]
+ cp BATTLEACTION_STRUGGLE
+ jr z, .use_move
+ cp BATTLEACTION_SKIPTURN
+ jr z, .use_move
+ sub BATTLEACTION_SWITCH1
+ jr c, .use_move
+ ld a, [wBattlePlayerAction]
+ cp BATTLEPLAYERACTION_SWITCH
+ jr nz, .switch
+ ldh a, [hSerialConnectionStatus]
+ cp USING_INTERNAL_CLOCK
+ jr z, .player_2
+
+ call BattleRandom
+ cp 50 percent + 1
+ jp c, .player_first
+ jp .enemy_first
+
+.player_2
+ call BattleRandom
+ cp 50 percent + 1
+ jp c, .enemy_first
+ jp .player_first
+
+.switch
+ callfar AI_Switch
+ call SetEnemyTurn
+ call SpikesDamage
+ jp .enemy_first
+
+.use_move
+ ld a, [wBattlePlayerAction]
+ and a ; BATTLEPLAYERACTION_USEMOVE?
+ jp nz, .player_first
+ call CompareMovePriority
+ jr z, .equal_priority
+ jp c, .player_first ; player goes first
+ jp .enemy_first
+
+.equal_priority
+ call SetPlayerTurn
+ callfar GetUserItem
+ push bc
+ callfar GetOpponentItem
+ pop de
+ ld a, d
+ cp HELD_QUICK_CLAW
+ jr nz, .player_no_quick_claw
+ ld a, b
+ cp HELD_QUICK_CLAW
+ jr z, .both_have_quick_claw
+ call BattleRandom
+ cp e
+ jr nc, .speed_check
+ jp .player_first
+
+.player_no_quick_claw
+ ld a, b
+ cp HELD_QUICK_CLAW
+ jr nz, .speed_check
+ call BattleRandom
+ cp c
+ jr nc, .speed_check
+ jp .enemy_first
+
+.both_have_quick_claw
+ ldh a, [hSerialConnectionStatus]
+ cp USING_INTERNAL_CLOCK
+ jr z, .player_2b
+ call BattleRandom
+ cp c
+ jp c, .enemy_first
+ call BattleRandom
+ cp e
+ jp c, .player_first
+ jr .speed_check
+
+.player_2b
+ call BattleRandom
+ cp e
+ jp c, .player_first
+ call BattleRandom
+ cp c
+ jp c, .enemy_first
+ jr .speed_check
+
+.speed_check
+ ld de, wBattleMonSpeed
+ ld hl, wEnemyMonSpeed
+ ld c, 2
+ call CompareBytes
+ jr z, .speed_tie
+ jp nc, .player_first
+ jp .enemy_first
+
+.speed_tie
+ ldh a, [hSerialConnectionStatus]
+ cp USING_INTERNAL_CLOCK
+ jr z, .player_2c
+ call BattleRandom
+ cp 50 percent + 1
+ jp c, .player_first
+ jp .enemy_first
+
+.player_2c
+ call BattleRandom
+ cp 50 percent + 1
+ jp c, .enemy_first
+.player_first
+ scf
+ ret
+
+.enemy_first
+ and a
+ ret
+
+CheckContestBattleOver:
+ ld a, [wBattleType]
+ cp BATTLETYPE_CONTEST
+ jr nz, .contest_not_over
+ ld a, [wParkBallsRemaining]
+ and a
+ jr nz, .contest_not_over
+ ld a, [wBattleResult]
+ and BATTLERESULT_BITMASK
+ add DRAW
+ ld [wBattleResult], a
+ scf
+ ret
+
+.contest_not_over
+ and a
+ ret
+
+CheckPlayerLockedIn:
+ ld a, [wPlayerSubStatus4]
+ and 1 << SUBSTATUS_RECHARGE
+ jp nz, .quit
+
+ ld hl, wEnemySubStatus3
+ res SUBSTATUS_FLINCHED, [hl]
+ ld hl, wPlayerSubStatus3
+ res SUBSTATUS_FLINCHED, [hl]
+
+ ld a, [hl]
+ and 1 << SUBSTATUS_CHARGED | 1 << SUBSTATUS_RAMPAGE
+ jp nz, .quit
+
+ ld hl, wPlayerSubStatus1
+ bit SUBSTATUS_ROLLOUT, [hl]
+ jp nz, .quit
+
+ and a
+ ret
+
+.quit
+ scf
+ ret
+
+ParsePlayerAction:
+ call CheckPlayerLockedIn
+ jp c, .locked_in
+ ld hl, wPlayerSubStatus5
+ bit SUBSTATUS_ENCORED, [hl]
+ jr z, .not_encored
+ ld a, [wLastPlayerMove]
+ ld [wCurPlayerMove], a
+ jr .encored
+
+.not_encored
+ ld a, [wBattlePlayerAction]
+ cp BATTLEPLAYERACTION_SWITCH
+ jr z, .reset_rage
+ and a
+ jr nz, .reset_bide
+ ld a, [wPlayerSubStatus3]
+ and 1 << SUBSTATUS_BIDE
+ jr nz, .locked_in
+ xor a
+ ld [wMoveSelectionMenuType], a
+ inc a ; POUND
+ ld [wFXAnimID], a
+ call MoveSelectionScreen
+ push af
+ call SafeLoadTempTilemapToTilemap
+ call UpdateBattleHuds
+ ld a, [wCurPlayerMove]
+ cp STRUGGLE
+ jr z, .struggle
+ call PlayClickSFX
+
+.struggle
+ ld a, $1
+ ldh [hBGMapMode], a
+ pop af
+ ret nz
+
+.encored
+ call SetPlayerTurn
+ callfar UpdateMoveData
+ xor a
+ ld [wPlayerCharging], a
+ ld a, [wPlayerMoveStruct + MOVE_EFFECT]
+ cp EFFECT_FURY_CUTTER
+ jr z, .continue_fury_cutter
+ xor a
+ ld [wPlayerFuryCutterCount], a
+
+.continue_fury_cutter
+ ld a, [wPlayerMoveStruct + MOVE_EFFECT]
+ cp EFFECT_RAGE
+ jr z, .continue_rage
+ ld hl, wPlayerSubStatus4
+ res SUBSTATUS_RAGE, [hl]
+ xor a
+ ld [wPlayerRageCounter], a
+
+.continue_rage
+ ld a, [wPlayerMoveStruct + MOVE_EFFECT]
+ cp EFFECT_PROTECT
+ jr z, .continue_protect
+ cp EFFECT_ENDURE
+ jr z, .continue_protect
+ xor a
+ ld [wPlayerProtectCount], a
+ jr .continue_protect
+
+.reset_bide
+ ld hl, wPlayerSubStatus3
+ res SUBSTATUS_BIDE, [hl]
+
+.locked_in
+ xor a
+ ld [wPlayerFuryCutterCount], a
+ ld [wPlayerProtectCount], a
+ ld [wPlayerRageCounter], a
+ ld hl, wPlayerSubStatus4
+ res SUBSTATUS_RAGE, [hl]
+
+.continue_protect
+ call ParseEnemyAction
+ xor a
+ ret
+
+.reset_rage
+ xor a
+ ld [wPlayerFuryCutterCount], a
+ ld [wPlayerProtectCount], a
+ ld [wPlayerRageCounter], a
+ ld hl, wPlayerSubStatus4
+ res SUBSTATUS_RAGE, [hl]
+ xor a
+ ret
+
+HandleEncore:
+ ldh a, [hSerialConnectionStatus]
+ cp USING_EXTERNAL_CLOCK
+ jr z, .player_1
+ call .do_player
+ jr .do_enemy
+
+.player_1
+ call .do_enemy
+.do_player
+ ld hl, wPlayerSubStatus5
+ bit SUBSTATUS_ENCORED, [hl]
+ ret z
+ ld a, [wPlayerEncoreCount]
+ dec a
+ ld [wPlayerEncoreCount], a
+ jr z, .end_player_encore
+ ld hl, wBattleMonPP
+ ld a, [wCurMoveNum]
+ ld c, a
+ ld b, 0
+ add hl, bc
+ ld a, [hl]
+ and PP_MASK
+ ret nz
+
+.end_player_encore
+ ld hl, wPlayerSubStatus5
+ res SUBSTATUS_ENCORED, [hl]
+ call SetEnemyTurn
+ ld hl, BattleText_TargetsEncoreEnded
+ jp StdBattleTextbox
+
+.do_enemy
+ ld hl, wEnemySubStatus5
+ bit SUBSTATUS_ENCORED, [hl]
+ ret z
+ ld a, [wEnemyEncoreCount]
+ dec a
+ ld [wEnemyEncoreCount], a
+ jr z, .end_enemy_encore
+ ld hl, wEnemyMonPP
+ ld a, [wCurEnemyMoveNum]
+ ld c, a
+ ld b, 0
+ add hl, bc
+ ld a, [hl]
+ and PP_MASK
+ ret nz
+
+.end_enemy_encore
+ ld hl, wEnemySubStatus5
+ res SUBSTATUS_ENCORED, [hl]
+ call SetPlayerTurn
+ ld hl, BattleText_TargetsEncoreEnded
+ jp StdBattleTextbox
+
+TryEnemyFlee:
+ ld a, [wBattleMode]
+ dec a
+ jr nz, .Stay
+
+ ld a, [wPlayerSubStatus5]
+ bit SUBSTATUS_CANT_RUN, a
+ jr nz, .Stay
+
+ ld a, [wEnemyWrapCount]
+ and a
+ jr nz, .Stay
+
+ ld a, [wEnemyMonStatus]
+ and 1 << FRZ | SLP
+ jr nz, .Stay
+
+ ld a, [wTempEnemyMonSpecies]
+ ld de, 1
+ ld hl, AlwaysFleeMons
+ call IsInArray
+ jr c, .Flee
+
+ call BattleRandom
+ ld b, a
+ cp 50 percent + 1
+ jr nc, .Stay
+
+ push bc
+ ld a, [wTempEnemyMonSpecies]
+ ld de, 1
+ ld hl, OftenFleeMons
+ call IsInArray
+ pop bc
+ jr c, .Flee
+
+ ld a, b
+ cp 10 percent + 1
+ jr nc, .Stay
+
+ ld a, [wTempEnemyMonSpecies]
+ ld de, 1
+ ld hl, SometimesFleeMons
+ call IsInArray
+ jr c, .Flee
+
+.Stay:
+ and a
+ ret
+
+.Flee:
+ scf
+ ret
+
+INCLUDE "data/wild/flee_mons.asm"
+
+CompareMovePriority:
+; Compare the priority of the player and enemy's moves.
+; Return carry if the player goes first, or z if they match.
+
+ ld a, [wCurPlayerMove]
+ call GetMovePriority
+ ld b, a
+ push bc
+ ld a, [wCurEnemyMove]
+ call GetMovePriority
+ pop bc
+ cp b
+ ret
+
+GetMovePriority:
+; Return the priority (0-3) of move a.
+
+ ld b, a
+
+ ; Vital Throw goes last.
+ cp VITAL_THROW
+ ld a, 0
+ ret z
+
+ call GetMoveEffect
+ ld hl, MoveEffectPriorities
+.loop
+ ld a, [hli]
+ cp b
+ jr z, .done
+ inc hl
+ cp -1
+ jr nz, .loop
+
+ ld a, BASE_PRIORITY
+ ret
+
+.done
+ ld a, [hl]
+ ret
+
+INCLUDE "data/moves/effects_priorities.asm"
+
+GetMoveEffect:
+ ld a, b
+ dec a
+ ld hl, Moves + MOVE_EFFECT
+ ld bc, MOVE_LENGTH
+ call AddNTimes
+ ld a, BANK(Moves)
+ call GetFarByte
+ ld b, a
+ ret
+
+Battle_EnemyFirst:
+ call LoadTilemapToTempTilemap
+ call TryEnemyFlee
+ jp c, WildFled_EnemyFled_LinkBattleCanceled
+ call SetEnemyTurn
+ ld a, $1
+ ld [wEnemyGoesFirst], a
+ callfar AI_SwitchOrTryItem
+ jr c, .switch_item
+ call EnemyTurn_EndOpponentProtectEndureDestinyBond
+ ld a, [wForcedSwitch]
+ and a
+ ret nz
+ call HasPlayerFainted
+ jp z, HandlePlayerMonFaint
+ call HasEnemyFainted
+ jp z, HandleEnemyMonFaint
+
+.switch_item
+ call SetEnemyTurn
+ call ResidualDamage
+ jp z, HandleEnemyMonFaint
+ call RefreshBattleHuds
+ call PlayerTurn_EndOpponentProtectEndureDestinyBond
+ ld a, [wForcedSwitch]
+ and a
+ ret nz
+ call HasEnemyFainted
+ jp z, HandleEnemyMonFaint
+ call HasPlayerFainted
+ jp z, HandlePlayerMonFaint
+ call SetPlayerTurn
+ call ResidualDamage
+ jp z, HandlePlayerMonFaint
+ call RefreshBattleHuds
+ xor a ; BATTLEPLAYERACTION_USEMOVE
+ ld [wBattlePlayerAction], a
+ ret
+
+Battle_PlayerFirst:
+ xor a
+ ld [wEnemyGoesFirst], a
+ call SetEnemyTurn
+ callfar AI_SwitchOrTryItem
+ push af
+ call PlayerTurn_EndOpponentProtectEndureDestinyBond
+ pop bc
+ ld a, [wForcedSwitch]
+ and a
+ ret nz
+ call HasEnemyFainted
+ jp z, HandleEnemyMonFaint
+ call HasPlayerFainted
+ jp z, HandlePlayerMonFaint
+ push bc
+ call SetPlayerTurn
+ call ResidualDamage
+ pop bc
+ jp z, HandlePlayerMonFaint
+ push bc
+ call RefreshBattleHuds
+ pop af
+ jr c, .switched_or_used_item
+ call LoadTilemapToTempTilemap
+ call TryEnemyFlee
+ jp c, WildFled_EnemyFled_LinkBattleCanceled
+ call EnemyTurn_EndOpponentProtectEndureDestinyBond
+ ld a, [wForcedSwitch]
+ and a
+ ret nz
+ call HasPlayerFainted
+ jp z, HandlePlayerMonFaint
+ call HasEnemyFainted
+ jp z, HandleEnemyMonFaint
+
+.switched_or_used_item
+ call SetEnemyTurn
+ call ResidualDamage
+ jp z, HandleEnemyMonFaint
+ call RefreshBattleHuds
+ xor a ; BATTLEPLAYERACTION_USEMOVE
+ ld [wBattlePlayerAction], a
+ ret
+
+PlayerTurn_EndOpponentProtectEndureDestinyBond:
+ call SetPlayerTurn
+ call EndUserDestinyBond
+ callfar DoPlayerTurn
+ jp EndOpponentProtectEndureDestinyBond
+
+EnemyTurn_EndOpponentProtectEndureDestinyBond:
+ call SetEnemyTurn
+ call EndUserDestinyBond
+ callfar DoEnemyTurn
+ jp EndOpponentProtectEndureDestinyBond
+
+EndOpponentProtectEndureDestinyBond:
+ ld a, BATTLE_VARS_SUBSTATUS1_OPP
+ call GetBattleVarAddr
+ res SUBSTATUS_PROTECT, [hl]
+ res SUBSTATUS_ENDURE, [hl]
+ ld a, BATTLE_VARS_SUBSTATUS5_OPP
+ call GetBattleVarAddr
+ res SUBSTATUS_DESTINY_BOND, [hl]
+ ret
+
+EndUserDestinyBond:
+ ld a, BATTLE_VARS_SUBSTATUS5
+ call GetBattleVarAddr
+ res SUBSTATUS_DESTINY_BOND, [hl]
+ ret
+
+HasUserFainted:
+ ldh a, [hBattleTurn]
+ and a
+ jr z, HasPlayerFainted
+HasEnemyFainted:
+ ld hl, wEnemyMonHP
+ jr CheckIfHPIsZero
+
+HasPlayerFainted:
+ ld hl, wBattleMonHP
+
+CheckIfHPIsZero:
+ ld a, [hli]
+ or [hl]
+ ret
+
+ResidualDamage:
+; Return z if the user fainted before
+; or as a result of residual damage.
+; For Sandstorm damage, see HandleWeather.
+
+ call HasUserFainted
+ ret z
+
+ ld a, BATTLE_VARS_STATUS
+ call GetBattleVar
+ and 1 << PSN | 1 << BRN
+ jr z, .did_psn_brn
+
+ ld hl, HurtByPoisonText
+ ld de, ANIM_PSN
+ and 1 << BRN
+ jr z, .got_anim
+ ld hl, HurtByBurnText
+ ld de, ANIM_BRN
+.got_anim
+
+ push de
+ call StdBattleTextbox
+ pop de
+
+ xor a
+ ld [wNumHits], a
+ call Call_PlayBattleAnim_OnlyIfVisible
+ call GetEighthMaxHP
+ ld de, wPlayerToxicCount
+ ldh a, [hBattleTurn]
+ and a
+ jr z, .check_toxic
+ ld de, wEnemyToxicCount
+.check_toxic
+
+ ld a, BATTLE_VARS_SUBSTATUS5
+ call GetBattleVar
+ bit SUBSTATUS_TOXIC, a
+ jr z, .did_toxic
+ call GetSixteenthMaxHP
+ ld a, [de]
+ inc a
+ ld [de], a
+ ld hl, 0
+.add
+ add hl, bc
+ dec a
+ jr nz, .add
+ ld b, h
+ ld c, l
+.did_toxic
+
+ call SubtractHPFromUser
+.did_psn_brn
+
+ call HasUserFainted
+ jp z, .fainted
+
+ ld a, BATTLE_VARS_SUBSTATUS4
+ call GetBattleVarAddr
+ bit SUBSTATUS_LEECH_SEED, [hl]
+ jr z, .not_seeded
+
+ call SwitchTurnCore
+ xor a
+ ld [wNumHits], a
+ ld de, ANIM_SAP
+ ld a, BATTLE_VARS_SUBSTATUS3_OPP
+ call GetBattleVar
+ and 1 << SUBSTATUS_FLYING | 1 << SUBSTATUS_UNDERGROUND
+ call z, Call_PlayBattleAnim_OnlyIfVisible
+ call SwitchTurnCore
+
+ call GetEighthMaxHP
+ call SubtractHPFromUser
+ ld a, $1
+ ldh [hBGMapMode], a
+ call RestoreHP
+ ld hl, LeechSeedSapsText
+ call StdBattleTextbox
+.not_seeded
+
+ call HasUserFainted
+ jr z, .fainted
+
+ ld a, BATTLE_VARS_SUBSTATUS1
+ call GetBattleVarAddr
+ bit SUBSTATUS_NIGHTMARE, [hl]
+ jr z, .not_nightmare
+ xor a
+ ld [wNumHits], a
+ ld de, ANIM_IN_NIGHTMARE
+ call Call_PlayBattleAnim_OnlyIfVisible
+ call GetQuarterMaxHP
+ call SubtractHPFromUser
+ ld hl, HasANightmareText
+ call StdBattleTextbox
+.not_nightmare
+
+ call HasUserFainted
+ jr z, .fainted
+
+ ld a, BATTLE_VARS_SUBSTATUS1
+ call GetBattleVarAddr
+ bit SUBSTATUS_CURSE, [hl]
+ jr z, .not_cursed
+
+ xor a
+ ld [wNumHits], a
+ ld de, ANIM_IN_NIGHTMARE
+ call Call_PlayBattleAnim_OnlyIfVisible
+ call GetQuarterMaxHP
+ call SubtractHPFromUser
+ ld hl, HurtByCurseText
+ call StdBattleTextbox
+
+.not_cursed
+ ld hl, wBattleMonHP
+ ldh a, [hBattleTurn]
+ and a
+ jr z, .check_fainted
+ ld hl, wEnemyMonHP
+
+.check_fainted
+ ld a, [hli]
+ or [hl]
+ ret nz
+
+.fainted
+ call RefreshBattleHuds
+ ld c, 20
+ call DelayFrames
+ xor a
+ ret
+
+HandlePerishSong:
+ ldh a, [hSerialConnectionStatus]
+ cp USING_EXTERNAL_CLOCK
+ jr z, .EnemyFirst
+ call SetPlayerTurn
+ call .do_it
+ call SetEnemyTurn
+ jp .do_it
+
+.EnemyFirst:
+ call SetEnemyTurn
+ call .do_it
+ call SetPlayerTurn
+
+.do_it
+ ld hl, wPlayerPerishCount
+ ldh a, [hBattleTurn]
+ and a
+ jr z, .got_count
+ ld hl, wEnemyPerishCount
+
+.got_count
+ ld a, BATTLE_VARS_SUBSTATUS1
+ call GetBattleVar
+ bit SUBSTATUS_PERISH, a
+ ret z
+ dec [hl]
+ ld a, [hl]
+ ld [wDeciramBuffer], a
+ push af
+ ld hl, PerishCountText
+ call StdBattleTextbox
+ pop af
+ ret nz
+ ld a, BATTLE_VARS_SUBSTATUS1
+ call GetBattleVarAddr
+ res SUBSTATUS_PERISH, [hl]
+ ldh a, [hBattleTurn]
+ and a
+ jr nz, .kill_enemy
+ ld hl, wBattleMonHP
+ xor a
+ ld [hli], a
+ ld [hl], a
+ ld hl, wPartyMon1HP
+ ld a, [wCurBattleMon]
+ call GetPartyLocation
+ xor a
+ ld [hli], a
+ ld [hl], a
+ ret
+
+.kill_enemy
+ ld hl, wEnemyMonHP
+ xor a
+ ld [hli], a
+ ld [hl], a
+ ld a, [wBattleMode]
+ dec a
+ ret z
+ ld hl, wOTPartyMon1HP
+ ld a, [wCurOTMon]
+ call GetPartyLocation
+ xor a
+ ld [hli], a
+ ld [hl], a
+ ret
+
+HandleWrap:
+ ldh a, [hSerialConnectionStatus]
+ cp USING_EXTERNAL_CLOCK
+ jr z, .EnemyFirst
+ call SetPlayerTurn
+ call .do_it
+ call SetEnemyTurn
+ jp .do_it
+
+.EnemyFirst:
+ call SetEnemyTurn
+ call .do_it
+ call SetPlayerTurn
+
+.do_it
+ ld hl, wPlayerWrapCount
+ ld de, wPlayerTrappingMove
+ ldh a, [hBattleTurn]
+ and a
+ jr z, .got_addrs
+ ld hl, wEnemyWrapCount
+ ld de, wEnemyTrappingMove
+
+.got_addrs
+ ld a, [hl]
+ and a
+ ret z
+
+ ld a, BATTLE_VARS_SUBSTATUS4
+ call GetBattleVar
+ bit SUBSTATUS_SUBSTITUTE, a
+ ret nz
+
+ ld a, [de]
+ ld [wNamedObjectIndexBuffer], a
+ ld [wFXAnimID], a
+ call GetMoveName
+ dec [hl]
+ jr z, .release_from_bounds
+
+ ld a, BATTLE_VARS_SUBSTATUS3
+ call GetBattleVar
+ and 1 << SUBSTATUS_FLYING | 1 << SUBSTATUS_UNDERGROUND
+ jr nz, .skip_anim
+
+ call SwitchTurnCore
+ xor a
+ ld [wNumHits], a
+ ld [wFXAnimID + 1], a
+ predef PlayBattleAnim
+ call SwitchTurnCore
+
+.skip_anim
+ call GetSixteenthMaxHP
+ call SubtractHPFromUser
+ ld hl, BattleText_UsersHurtByStringBuffer1
+ jr .print_text
+
+.release_from_bounds
+ ld hl, BattleText_UserWasReleasedFromStringBuffer1
+
+.print_text
+ jp StdBattleTextbox
+
+SwitchTurnCore:
+ ldh a, [hBattleTurn]
+ xor 1
+ ldh [hBattleTurn], a
+ ret
+
+HandleLeftovers:
+ ldh a, [hSerialConnectionStatus]
+ cp USING_EXTERNAL_CLOCK
+ jr z, .DoEnemyFirst
+ call SetPlayerTurn
+ call .do_it
+ call SetEnemyTurn
+ jp .do_it
+
+.DoEnemyFirst:
+ call SetEnemyTurn
+ call .do_it
+ call SetPlayerTurn
+.do_it
+
+ callfar GetUserItem
+ ld a, [hl]
+ ld [wNamedObjectIndexBuffer], a
+ call GetItemName
+ ld a, b
+ cp HELD_LEFTOVERS
+ ret nz
+
+ ld hl, wBattleMonHP
+ ldh a, [hBattleTurn]
+ and a
+ jr z, .got_hp
+ ld hl, wEnemyMonHP
+
+.got_hp
+; Don't restore if we're already at max HP
+ ld a, [hli]
+ ld b, a
+ ld a, [hli]
+ ld c, a
+ ld a, [hli]
+ cp b
+ jr nz, .restore
+ ld a, [hl]
+ cp c
+ ret z
+
+.restore
+ call GetSixteenthMaxHP
+ call SwitchTurnCore
+ call RestoreHP
+ ld hl, BattleText_TargetRecoveredWithItem
+ jp StdBattleTextbox
+
+HandleMysteryberry:
+ ldh a, [hSerialConnectionStatus]
+ cp USING_EXTERNAL_CLOCK
+ jr z, .DoEnemyFirst
+ call SetPlayerTurn
+ call .do_it
+ call SetEnemyTurn
+ jp .do_it
+
+.DoEnemyFirst:
+ call SetEnemyTurn
+ call .do_it
+ call SetPlayerTurn
+
+.do_it
+ callfar GetUserItem
+ ld a, b
+ cp HELD_RESTORE_PP
+ jr nz, .quit
+ ld hl, wPartyMon1PP
+ ld a, [wCurBattleMon]
+ call GetPartyLocation
+ ld d, h
+ ld e, l
+ ld hl, wPartyMon1Moves
+ ld a, [wCurBattleMon]
+ call GetPartyLocation
+ ldh a, [hBattleTurn]
+ and a
+ jr z, .wild
+ ld de, wWildMonPP
+ ld hl, wWildMonMoves
+ ld a, [wBattleMode]
+ dec a
+ jr z, .wild
+ ld hl, wOTPartyMon1PP
+ ld a, [wCurOTMon]
+ call GetPartyLocation
+ ld d, h
+ ld e, l
+ ld hl, wOTPartyMon1Moves
+ ld a, [wCurOTMon]
+ call GetPartyLocation
+
+.wild
+ ld c, $0
+.loop
+ ld a, [hl]
+ and a
+ jr z, .quit
+ ld a, [de]
+ and PP_MASK
+ jr z, .restore
+ inc hl
+ inc de
+ inc c
+ ld a, c
+ cp NUM_MOVES
+ jr nz, .loop
+
+.quit
+ ret
+
+.restore
+ ; lousy hack
+ ld a, [hl]
+ cp SKETCH
+ ld b, 1
+ jr z, .sketch
+ ld b, 5
+.sketch
+ ld a, [de]
+ add b
+ ld [de], a
+ push bc
+ push bc
+ ld a, [hl]
+ ld [wTempByteValue], a
+ ld de, wBattleMonMoves - 1
+ ld hl, wBattleMonPP
+ ldh a, [hBattleTurn]
+ and a
+ jr z, .player_pp
+ ld de, wEnemyMonMoves - 1
+ ld hl, wEnemyMonPP
+.player_pp
+ inc de
+ pop bc
+ ld b, 0
+ add hl, bc
+ push hl
+ ld h, d
+ ld l, e
+ add hl, bc
+ pop de
+ pop bc
+
+ ld a, [wTempByteValue]
+ cp [hl]
+ jr nz, .skip_checks
+ ldh a, [hBattleTurn]
+ and a
+ ld a, [wPlayerSubStatus5]
+ jr z, .check_transform
+ ld a, [wEnemySubStatus5]
+.check_transform
+ bit SUBSTATUS_TRANSFORMED, a
+ jr nz, .skip_checks
+ ld a, [de]
+ add b
+ ld [de], a
+.skip_checks
+ callfar GetUserItem
+ ld a, [hl]
+ ld [wNamedObjectIndexBuffer], a
+ xor a
+ ld [hl], a
+ call GetPartymonItem
+ ldh a, [hBattleTurn]
+ and a
+ jr z, .consume_item
+ ld a, [wBattleMode]
+ dec a
+ jr z, .skip_consumption
+ call GetOTPartymonItem
+
+.consume_item
+ xor a
+ ld [hl], a
+
+.skip_consumption
+ call GetItemName
+ call SwitchTurnCore
+ call ItemRecoveryAnim
+ call SwitchTurnCore
+ ld hl, BattleText_UserRecoveredPPUsing
+ jp StdBattleTextbox
+
+HandleFutureSight:
+ ldh a, [hSerialConnectionStatus]
+ cp USING_EXTERNAL_CLOCK
+ jr z, .enemy_first
+ call SetPlayerTurn
+ call .do_it
+ call SetEnemyTurn
+ jp .do_it
+
+.enemy_first
+ call SetEnemyTurn
+ call .do_it
+ call SetPlayerTurn
+
+.do_it
+ ld hl, wPlayerFutureSightCount
+ ldh a, [hBattleTurn]
+ and a
+ jr z, .okay
+ ld hl, wEnemyFutureSightCount
+
+.okay
+ ld a, [hl]
+ and a
+ ret z
+ dec a
+ ld [hl], a
+ cp $1
+ ret nz
+
+ ld hl, BattleText_TargetWasHitByFutureSight
+ call StdBattleTextbox
+
+ ld a, BATTLE_VARS_MOVE
+ call GetBattleVarAddr
+ push af
+ ld a, FUTURE_SIGHT
+ ld [hl], a
+
+ callfar UpdateMoveData
+ xor a
+ ld [wAttackMissed], a
+ ld [wAlreadyDisobeyed], a
+ ld a, EFFECTIVE
+ ld [wTypeModifier], a
+ callfar DoMove
+ xor a
+ ld [wCurDamage], a
+ ld [wCurDamage + 1], a
+
+ ld a, BATTLE_VARS_MOVE
+ call GetBattleVarAddr
+ pop af
+ ld [hl], a
+
+ call UpdateBattleMonInParty
+ jp UpdateEnemyMonInParty
+
+HandleDefrost:
+ ldh a, [hSerialConnectionStatus]
+ cp USING_EXTERNAL_CLOCK
+ jr z, .enemy_first
+ call .do_player_turn
+ jr .do_enemy_turn
+
+.enemy_first
+ call .do_enemy_turn
+.do_player_turn
+ ld a, [wBattleMonStatus]
+ bit FRZ, a
+ ret z
+
+ ld a, [wPlayerJustGotFrozen]
+ and a
+ ret nz
+
+ call BattleRandom
+ cp 10 percent
+ ret nc
+ xor a
+ ld [wBattleMonStatus], a
+ ld a, [wCurBattleMon]
+ ld hl, wPartyMon1Status
+ call GetPartyLocation
+ ld [hl], 0
+ call UpdateBattleHuds
+ call SetEnemyTurn
+ ld hl, DefrostedOpponentText
+ jp StdBattleTextbox
+
+.do_enemy_turn
+ ld a, [wEnemyMonStatus]
+ bit FRZ, a
+ ret z
+ ld a, [wEnemyJustGotFrozen]
+ and a
+ ret nz
+ call BattleRandom
+ cp 10 percent
+ ret nc
+ xor a
+ ld [wEnemyMonStatus], a
+
+ ld a, [wBattleMode]
+ dec a
+ jr z, .wild
+ ld a, [wCurOTMon]
+ ld hl, wOTPartyMon1Status
+ call GetPartyLocation
+ ld [hl], 0
+.wild
+
+ call UpdateBattleHuds
+ call SetPlayerTurn
+ ld hl, DefrostedOpponentText
+ jp StdBattleTextbox
+
+HandleSafeguard:
+ ldh a, [hSerialConnectionStatus]
+ cp USING_EXTERNAL_CLOCK
+ jr z, .player1
+ call .CheckPlayer
+ jr .CheckEnemy
+
+.player1
+ call .CheckEnemy
+.CheckPlayer:
+ ld a, [wPlayerScreens]
+ bit SCREENS_SAFEGUARD, a
+ ret z
+ ld hl, wPlayerSafeguardCount
+ dec [hl]
+ ret nz
+ res SCREENS_SAFEGUARD, a
+ ld [wPlayerScreens], a
+ xor a
+ jr .print
+
+.CheckEnemy:
+ ld a, [wEnemyScreens]
+ bit SCREENS_SAFEGUARD, a
+ ret z
+ ld hl, wEnemySafeguardCount
+ dec [hl]
+ ret nz
+ res SCREENS_SAFEGUARD, a
+ ld [wEnemyScreens], a
+ ld a, $1
+
+.print
+ ldh [hBattleTurn], a
+ ld hl, BattleText_SafeguardFaded
+ jp StdBattleTextbox
+
+HandleScreens:
+ ldh a, [hSerialConnectionStatus]
+ cp USING_EXTERNAL_CLOCK
+ jr z, .Both
+ call .CheckPlayer
+ jr .CheckEnemy
+
+.Both:
+ call .CheckEnemy
+
+.CheckPlayer:
+ call SetPlayerTurn
+ ld de, .Your
+ call .Copy
+ ld hl, wPlayerScreens
+ ld de, wPlayerLightScreenCount
+ jr .TickScreens
+
+.CheckEnemy:
+ call SetEnemyTurn
+ ld de, .Enemy
+ call .Copy
+ ld hl, wEnemyScreens
+ ld de, wEnemyLightScreenCount
+
+.TickScreens:
+ bit SCREENS_LIGHT_SCREEN, [hl]
+ call nz, .LightScreenTick
+ bit SCREENS_REFLECT, [hl]
+ call nz, .ReflectTick
+ ret
+
+.Copy:
+ ld hl, wStringBuffer1
+ jp CopyName2
+
+.Your:
+ db "Your@"
+.Enemy:
+ db "Enemy@"
+
+.LightScreenTick:
+ ld a, [de]
+ dec a
+ ld [de], a
+ ret nz
+ res SCREENS_LIGHT_SCREEN, [hl]
+ push hl
+ push de
+ ld hl, BattleText_MonsLightScreenFell
+ call StdBattleTextbox
+ pop de
+ pop hl
+ ret
+
+.ReflectTick:
+ inc de
+ ld a, [de]
+ dec a
+ ld [de], a
+ ret nz
+ res SCREENS_REFLECT, [hl]
+ ld hl, BattleText_MonsReflectFaded
+ jp StdBattleTextbox
+
+HandleWeather:
+ ld a, [wBattleWeather]
+ cp WEATHER_NONE
+ ret z
+
+ ld hl, wWeatherCount
+ dec [hl]
+ jr z, .ended
+
+ ld hl, .WeatherMessages
+ call .PrintWeatherMessage
+
+ ld a, [wBattleWeather]
+ cp WEATHER_SANDSTORM
+ ret nz
+
+ ldh a, [hSerialConnectionStatus]
+ cp USING_EXTERNAL_CLOCK
+ jr z, .enemy_first
+
+.player_first
+ call SetPlayerTurn
+ call .SandstormDamage
+ call SetEnemyTurn
+ jr .SandstormDamage
+
+.enemy_first
+ call SetEnemyTurn
+ call .SandstormDamage
+ call SetPlayerTurn
+
+.SandstormDamage:
+ ld a, BATTLE_VARS_SUBSTATUS3
+ call GetBattleVar
+ bit SUBSTATUS_UNDERGROUND, a
+ ret nz
+
+ ld hl, wBattleMonType1
+ ldh a, [hBattleTurn]
+ and a
+ jr z, .ok
+ ld hl, wEnemyMonType1
+.ok
+ ld a, [hli]
+ cp ROCK
+ ret z
+ cp GROUND
+ ret z
+ cp STEEL
+ ret z
+
+ ld a, [hl]
+ cp ROCK
+ ret z
+ cp GROUND
+ ret z
+ cp STEEL
+ ret z
+
+ call SwitchTurnCore
+ xor a
+ ld [wNumHits], a
+ ld de, ANIM_IN_SANDSTORM
+ call Call_PlayBattleAnim
+ call SwitchTurnCore
+ call GetEighthMaxHP
+ call SubtractHPFromUser
+
+ ld hl, SandstormHitsText
+ jp StdBattleTextbox
+
+.ended
+ ld hl, .WeatherEndedMessages
+ call .PrintWeatherMessage
+ xor a
+ ld [wBattleWeather], a
+ ret
+
+.PrintWeatherMessage:
+ ld a, [wBattleWeather]
+ dec a
+ ld c, a
+ ld b, 0
+ add hl, bc
+ add hl, bc
+ ld a, [hli]
+ ld h, [hl]
+ ld l, a
+ jp StdBattleTextbox
+
+.WeatherMessages:
+; entries correspond to WEATHER_* constants
+ dw BattleText_RainContinuesToFall
+ dw BattleText_TheSunlightIsStrong
+ dw BattleText_TheSandstormRages
+
+.WeatherEndedMessages:
+; entries correspond to WEATHER_* constants
+ dw BattleText_TheRainStopped
+ dw BattleText_TheSunlightFaded
+ dw BattleText_TheSandstormSubsided
+
+SubtractHPFromTarget:
+ call SubtractHP
+ jp UpdateHPBar
+
+SubtractHPFromUser:
+; Subtract HP from mon
+ call SubtractHP
+ jp UpdateHPBarBattleHuds
+
+SubtractHP:
+ ld hl, wBattleMonHP
+ ldh a, [hBattleTurn]
+ and a
+ jr z, .ok
+ ld hl, wEnemyMonHP
+.ok
+ inc hl
+ ld a, [hl]
+ ld [wBuffer3], a
+ sub c
+ ld [hld], a
+ ld [wBuffer5], a
+ ld a, [hl]
+ ld [wBuffer4], a
+ sbc b
+ ld [hl], a
+ ld [wBuffer6], a
+ ret nc
+
+ ld a, [wBuffer3]
+ ld c, a
+ ld a, [wBuffer4]
+ ld b, a
+ xor a
+ ld [hli], a
+ ld [hl], a
+ ld [wBuffer5], a
+ ld [wBuffer6], a
+ ret
+
+GetSixteenthMaxHP:
+ call GetQuarterMaxHP
+; quarter result
+ srl c
+ srl c
+; at least 1
+ ld a, c
+ and a
+ jr nz, .ok
+ inc c
+.ok
+ ret
+
+GetEighthMaxHP:
+; output: bc
+ call GetQuarterMaxHP
+; assumes nothing can have 1024 or more hp
+; halve result
+ srl c
+; at least 1
+ ld a, c
+ and a
+ jr nz, .end
+ inc c
+.end
+ ret
+
+GetQuarterMaxHP:
+; output: bc
+ call GetMaxHP
+
+; quarter result
+ srl b
+ rr c
+ srl b
+ rr c
+
+; assumes nothing can have 1024 or more hp
+; at least 1
+ ld a, c
+ and a
+ jr nz, .end
+ inc c
+.end
+ ret
+
+GetHalfMaxHP:
+; output: bc
+ call GetMaxHP
+
+; halve result
+ srl b
+ rr c
+
+; at least 1
+ ld a, c
+ or b
+ jr nz, .end
+ inc c
+.end
+ ret
+
+GetMaxHP:
+; output: bc, wBuffer1-2
+
+ ld hl, wBattleMonMaxHP
+ ldh a, [hBattleTurn]
+ and a
+ jr z, .ok
+ ld hl, wEnemyMonMaxHP
+.ok
+ ld a, [hli]
+ ld [wBuffer2], a
+ ld b, a
+
+ ld a, [hl]
+ ld [wBuffer1], a
+ ld c, a
+ ret
+
+Unreferenced_GetHalfHP:
+ ld hl, wBattleMonHP
+ ldh a, [hBattleTurn]
+ and a
+ jr z, .ok
+ ld hl, wEnemyMonHP
+.ok
+ ld a, [hli]
+ ld b, a
+ ld a, [hli]
+ ld c, a
+ srl b
+ rr c
+ ld a, [hli]
+ ld [wBuffer2], a
+ ld a, [hl]
+ ld [wBuffer1], a
+ ret
+
+CheckUserHasEnoughHP:
+ ld hl, wBattleMonHP + 1
+ ldh a, [hBattleTurn]
+ and a
+ jr z, .ok
+ ld hl, wEnemyMonHP + 1
+.ok
+ ld a, c
+ sub [hl]
+ dec hl
+ ld a, b
+ sbc [hl]
+ ret
+
+RestoreHP:
+ ld hl, wEnemyMonMaxHP
+ ldh a, [hBattleTurn]
+ and a
+ jr z, .ok
+ ld hl, wBattleMonMaxHP
+.ok
+ ld a, [hli]
+ ld [wBuffer2], a
+ ld a, [hld]
+ ld [wBuffer1], a
+ dec hl
+ ld a, [hl]
+ ld [wBuffer3], a
+ add c
+ ld [hld], a
+ ld [wBuffer5], a
+ ld a, [hl]
+ ld [wBuffer4], a
+ adc b
+ ld [hli], a
+ ld [wBuffer6], a
+
+ ld a, [wBuffer1]
+ ld c, a
+ ld a, [hld]
+ sub c
+ ld a, [wBuffer2]
+ ld b, a
+ ld a, [hl]
+ sbc b
+ jr c, .asm_3ccd5
+ ld a, b
+ ld [hli], a
+ ld [wBuffer6], a
+ ld a, c
+ ld [hl], a
+ ld [wBuffer5], a
+.asm_3ccd5
+
+ call SwitchTurnCore
+ call UpdateHPBarBattleHuds
+ jp SwitchTurnCore
+
+UpdateHPBarBattleHuds:
+ call UpdateHPBar
+ jp UpdateBattleHuds
+
+UpdateHPBar:
+ hlcoord 10, 9
+ ldh a, [hBattleTurn]
+ and a
+ ld a, 1
+ jr z, .ok
+ hlcoord 2, 2
+ xor a
+.ok
+ push bc
+ ld [wWhichHPBar], a
+ predef AnimateHPBar
+ pop bc
+ ret
+
+HandleEnemyMonFaint:
+ call FaintEnemyPokemon
+ ld hl, wBattleMonHP
+ ld a, [hli]
+ or [hl]
+ call z, FaintYourPokemon
+ xor a
+ ld [wWhichMonFaintedFirst], a
+ call UpdateBattleStateAndExperienceAfterEnemyFaint
+ call CheckPlayerPartyForFitMon
+ ld a, d
+ and a
+ jp z, LostBattle
+
+ ld hl, wBattleMonHP
+ ld a, [hli]
+ or [hl]
+ call nz, UpdatePlayerHUD
+
+ ld a, $1
+ ldh [hBGMapMode], a
+ ld c, 60
+ call DelayFrames
+
+ ld a, [wBattleMode]
+ dec a
+ jr nz, .trainer
+
+ ld a, 1
+ ld [wBattleEnded], a
+ ret
+
+.trainer
+ call CheckEnemyTrainerDefeated
+ jp z, WinTrainerBattle
+
+ ld hl, wBattleMonHP
+ ld a, [hli]
+ or [hl]
+ jr nz, .player_mon_not_fainted
+
+ call AskUseNextPokemon
+ jr nc, .dont_flee
+
+ ld a, 1
+ ld [wBattleEnded], a
+ ret
+
+.dont_flee
+ call ForcePlayerMonChoice
+ ld a, BATTLEPLAYERACTION_USEITEM
+ ld [wBattlePlayerAction], a
+ call HandleEnemySwitch
+ jp z, WildFled_EnemyFled_LinkBattleCanceled
+ jr DoubleSwitch
+
+.player_mon_not_fainted
+ ld a, BATTLEPLAYERACTION_USEITEM
+ ld [wBattlePlayerAction], a
+ call HandleEnemySwitch
+ jp z, WildFled_EnemyFled_LinkBattleCanceled
+ xor a ; BATTLEPLAYERACTION_USEMOVE
+ ld [wBattlePlayerAction], a
+ ret
+
+DoubleSwitch:
+ ldh a, [hSerialConnectionStatus]
+ cp USING_EXTERNAL_CLOCK
+ jr z, .player_1
+ call ClearSprites
+ hlcoord 1, 0
+ lb bc, 4, 10
+ call ClearBox
+ call PlayerPartyMonEntrance
+ ld a, $1
+ call EnemyPartyMonEntrance
+ jr .done
+
+.player_1
+ ld a, [wCurPartyMon]
+ push af
+ ld a, $1
+ call EnemyPartyMonEntrance
+ call ClearSprites
+ call LoadTilemapToTempTilemap
+ pop af
+ ld [wCurPartyMon], a
+ call PlayerPartyMonEntrance
+
+.done
+ xor a ; BATTLEPLAYERACTION_USEMOVE
+ ld [wBattlePlayerAction], a
+ ret
+
+UpdateBattleStateAndExperienceAfterEnemyFaint:
+ call UpdateBattleMonInParty
+ ld a, [wBattleMode]
+ dec a
+ jr z, .wild
+ ld a, [wCurOTMon]
+ ld hl, wOTPartyMon1HP
+ call GetPartyLocation
+ xor a
+ ld [hli], a
+ ld [hl], a
+
+.wild
+ ld hl, wPlayerSubStatus3
+ res SUBSTATUS_IN_LOOP, [hl]
+ xor a
+ ld hl, wEnemyDamageTaken
+ ld [hli], a
+ ld [hl], a
+ call NewEnemyMonStatus
+ call BreakAttraction
+ ld a, [wBattleMode]
+ dec a
+ jr z, .wild2
+ jr .trainer
+
+.wild2
+ call StopDangerSound
+ ld a, $1
+ ld [wBattleLowHealthAlarm], a
+
+.trainer
+ ld hl, wBattleMonHP
+ ld a, [hli]
+ or [hl]
+ jr nz, .player_mon_did_not_faint
+ ld a, [wWhichMonFaintedFirst]
+ and a
+ jr nz, .player_mon_did_not_faint
+ call UpdateFaintedPlayerMon
+
+.player_mon_did_not_faint
+ call CheckPlayerPartyForFitMon
+ ld a, d
+ and a
+ ret z
+ ld a, [wBattleMode]
+ dec a
+ call z, PlayVictoryMusic
+ call EmptyBattleTextbox
+ call LoadTilemapToTempTilemap
+ ld a, [wBattleResult]
+ and BATTLERESULT_BITMASK
+ ld [wBattleResult], a ; WIN
+ call IsAnyMonHoldingExpShare
+ jr z, .skip_exp
+ ld hl, wEnemyMonBaseStats
+ ld b, wEnemyMonEnd - wEnemyMonBaseStats
+.loop
+ srl [hl]
+ inc hl
+ dec b
+ jr nz, .loop
+
+.skip_exp
+ ld hl, wEnemyMonBaseStats
+ ld de, wBackupEnemyMonBaseStats
+ ld bc, wEnemyMonEnd - wEnemyMonBaseStats
+ call CopyBytes
+ xor a
+ ld [wGivingExperienceToExpShareHolders], a
+ call GiveExperiencePoints
+ call IsAnyMonHoldingExpShare
+ ret z
+
+ ld a, [wBattleParticipantsNotFainted]
+ push af
+ ld a, d
+ ld [wBattleParticipantsNotFainted], a
+ ld hl, wBackupEnemyMonBaseStats
+ ld de, wEnemyMonBaseStats
+ ld bc, wEnemyMonEnd - wEnemyMonBaseStats
+ call CopyBytes
+ ld a, $1
+ ld [wGivingExperienceToExpShareHolders], a
+ call GiveExperiencePoints
+ pop af
+ ld [wBattleParticipantsNotFainted], a
+ ret
+
+IsAnyMonHoldingExpShare:
+ ld a, [wPartyCount]
+ ld b, a
+ ld hl, wPartyMon1
+ ld c, 1
+ ld d, 0
+.loop
+ push hl
+ push bc
+ ld bc, MON_HP
+ add hl, bc
+ ld a, [hli]
+ or [hl]
+ pop bc
+ pop hl
+ jr z, .next
+
+ push hl
+ push bc
+ ld bc, MON_ITEM
+ add hl, bc
+ pop bc
+ ld a, [hl]
+ pop hl
+
+ cp EXP_SHARE
+ jr nz, .next
+ ld a, d
+ or c
+ ld d, a
+
+.next
+ sla c
+ push de
+ ld de, PARTYMON_STRUCT_LENGTH
+ add hl, de
+ pop de
+ dec b
+ jr nz, .loop
+
+ ld a, d
+ ld e, 0
+ ld b, PARTY_LENGTH
+.loop2
+ srl a
+ jr nc, .okay
+ inc e
+
+.okay
+ dec b
+ jr nz, .loop2
+ ld a, e
+ and a
+ ret
+
+StopDangerSound:
+ xor a
+ ld [wLowHealthAlarm], a
+ ret
+
+FaintYourPokemon:
+ call StopDangerSound
+ call WaitSFX
+ ld a, $f0
+ ld [wCryTracks], a
+ ld a, [wBattleMonSpecies]
+ call PlayStereoCry
+ call PlayerMonFaintedAnimation
+ hlcoord 9, 7
+ lb bc, 5, 11
+ call ClearBox
+ ld hl, BattleText_MonFainted
+ jp StdBattleTextbox
+
+FaintEnemyPokemon:
+ call WaitSFX
+ ld de, SFX_KINESIS
+ call PlaySFX
+ call EnemyMonFaintedAnimation
+ ld de, SFX_FAINT
+ call PlaySFX
+ hlcoord 1, 0
+ lb bc, 4, 10
+ call ClearBox
+ ld hl, BattleText_EnemyMonFainted
+ jp StdBattleTextbox
+
+CheckEnemyTrainerDefeated:
+ ld a, [wOTPartyCount]
+ ld b, a
+ xor a
+ ld hl, wOTPartyMon1HP
+ ld de, PARTYMON_STRUCT_LENGTH
+
+.loop
+ or [hl]
+ inc hl
+ or [hl]
+ dec hl
+ add hl, de
+ dec b
+ jr nz, .loop
+
+ and a
+ ret
+
+HandleEnemySwitch:
+ ld hl, wEnemyHPPal
+ ld e, HP_BAR_LENGTH_PX
+ call UpdateHPPal
+ call WaitBGMap
+ farcall EnemySwitch_TrainerHud
+ ld a, [wLinkMode]
+ and a
+ jr z, .not_linked
+
+ call LinkBattleSendReceiveAction
+ ld a, [wBattleAction]
+ cp BATTLEACTION_FORFEIT
+ ret z
+
+ call SafeLoadTempTilemapToTilemap
+
+.not_linked
+ ld hl, wBattleMonHP
+ ld a, [hli]
+ or [hl]
+ ld a, $0
+ jr nz, EnemyPartyMonEntrance
+ inc a
+ ret
+
+EnemyPartyMonEntrance:
+ push af
+ xor a
+ ld [wEnemySwitchMonIndex], a
+ call NewEnemyMonStatus
+ call ResetEnemyStatLevels
+ call BreakAttraction
+ pop af
+ and a
+ jr nz, .set
+ call EnemySwitch
+ jr .done_switch
+
+.set
+ call EnemySwitch_SetMode
+.done_switch
+ call ResetBattleParticipants
+ call SetEnemyTurn
+ call SpikesDamage
+ xor a
+ ld [wEnemyMoveStruct + MOVE_ANIM], a
+ ld [wBattlePlayerAction], a
+ inc a
+ ret
+
+WinTrainerBattle:
+; Player won the battle
+ call StopDangerSound
+ ld a, $1
+ ld [wBattleLowHealthAlarm], a
+ ld [wBattleEnded], a
+ ld a, [wLinkMode]
+ and a
+ ld a, b
+ call z, PlayVictoryMusic
+ callfar Battle_GetTrainerName
+ ld hl, BattleText_EnemyWasDefeated
+ call StdBattleTextbox
+
+ ld a, [wLinkMode]
+ cp LINK_COLOSSEUM
+ ret z
+
+ call BattleWinSlideInEnemyTrainerFrontpic
+ ld c, 40
+ call DelayFrames
+ ld a, [wBattleType]
+ cp BATTLETYPE_CANLOSE
+ jr nz, .skip_heal
+ predef HealParty
+.skip_heal
+ ld a, [wDebugFlags]
+ bit DEBUG_BATTLE_F, a
+ jr nz, .GiveMoney
+ call PrintWinLossText
+
+.GiveMoney:
+ ld a, [wAmuletCoin]
+ and a
+ call nz, .DoubleReward
+ call .CheckMaxedOutMomMoney
+ push af
+ ld a, FALSE
+ jr nc, .okay
+ ld a, [wMomSavingMoney]
+ and MOM_SAVING_MONEY_MASK
+ cp (1 << MOM_SAVING_SOME_MONEY_F) | (1 << MOM_SAVING_HALF_MONEY_F)
+ jr nz, .okay
+ inc a ; TRUE
+
+.okay
+ ld b, a
+ ld c, 4
+.loop
+ ld a, b
+ and a
+ jr z, .loop2
+ call .AddMoneyToMom
+ dec c
+ dec b
+ jr .loop
+
+.loop2
+ ld a, c
+ and a
+ jr z, .done
+ call .AddMoneyToWallet
+ dec c
+ jr .loop2
+
+.done
+ call .DoubleReward
+ call .DoubleReward
+ pop af
+ jr nc, .KeepItAll
+ ld a, [wMomSavingMoney]
+ and MOM_SAVING_MONEY_MASK
+ jr z, .KeepItAll
+ ld hl, .SentToMomTexts
+ dec a
+ ld c, a
+ ld b, 0
+ add hl, bc
+ add hl, bc
+ ld a, [hli]
+ ld h, [hl]
+ ld l, a
+ jp StdBattleTextbox
+
+.KeepItAll:
+ ld hl, GotMoneyForWinningText
+ jp StdBattleTextbox
+
+.AddMoneyToMom:
+ push bc
+ ld hl, wBattleReward + 2
+ ld de, wMomsMoney + 2
+ call AddBattleMoneyToAccount
+ pop bc
+ ret
+
+.AddMoneyToWallet:
+ push bc
+ ld hl, wBattleReward + 2
+ ld de, wMoney + 2
+ call AddBattleMoneyToAccount
+ pop bc
+ ret
+
+.DoubleReward:
+ ld hl, wBattleReward + 2
+ sla [hl]
+ dec hl
+ rl [hl]
+ dec hl
+ rl [hl]
+ ret nc
+ ld a, $ff
+ ld [hli], a
+ ld [hli], a
+ ld [hl], a
+ ret
+
+.SentToMomTexts:
+; entries correspond to MOM_SAVING_* constants
+ dw SentSomeToMomText
+ dw SentHalfToMomText
+ dw SentAllToMomText
+
+.CheckMaxedOutMomMoney:
+ ld hl, wMomsMoney + 2
+ ld a, [hld]
+ cp LOW(MAX_MONEY)
+ ld a, [hld]
+ sbc HIGH(MAX_MONEY) ; mid
+ ld a, [hl]
+ sbc HIGH(MAX_MONEY >> 8)
+ ret
+
+AddBattleMoneyToAccount:
+ ld c, 3
+ and a
+ push de
+.loop
+ ld a, [de]
+ adc [hl]
+ ld [de], a
+ dec de
+ dec hl
+ dec c
+ jr nz, .loop
+ pop hl
+ ld a, [hld]
+ cp LOW(MAX_MONEY)
+ ld a, [hld]
+ sbc HIGH(MAX_MONEY) ; mid
+ ld a, [hl]
+ sbc HIGH(MAX_MONEY >> 8)
+ ret c
+ ld [hl], HIGH(MAX_MONEY >> 8)
+ inc hl
+ ld [hl], HIGH(MAX_MONEY) ; mid
+ inc hl
+ ld [hl], LOW(MAX_MONEY)
+ ret
+
+PlayVictoryMusic:
+ push de
+ ld de, MUSIC_NONE
+ call PlayMusic
+ call DelayFrame
+ ld de, MUSIC_WILD_VICTORY
+ ld a, [wBattleMode]
+ dec a
+ jr nz, .trainer_victory
+ push de
+ call IsAnyMonHoldingExpShare
+ pop de
+ jr nz, .play_music
+ ld hl, wPayDayMoney
+ ld a, [hli]
+ or [hl]
+ jr nz, .play_music
+ ld a, [wBattleParticipantsNotFainted]
+ and a
+ jr z, .lost
+ jr .play_music
+
+.trainer_victory
+ ld de, MUSIC_GYM_VICTORY
+ call IsGymLeader
+ jr c, .play_music
+ ld de, MUSIC_TRAINER_VICTORY
+
+.play_music
+ call PlayMusic
+
+.lost
+ pop de
+ ret
+
+IsKantoGymLeader:
+ ld hl, KantoGymLeaders
+ jr IsGymLeaderCommon
+
+IsGymLeader:
+ ld hl, GymLeaders
+IsGymLeaderCommon:
+ push de
+ ld a, [wOtherTrainerClass]
+ ld de, 1
+ call IsInArray
+ pop de
+ ret
+
+INCLUDE "data/trainers/leaders.asm"
+
+HandlePlayerMonFaint:
+ call FaintYourPokemon
+ ld hl, wEnemyMonHP
+ ld a, [hli]
+ or [hl]
+ call z, FaintEnemyPokemon
+ ld a, $1
+ ld [wWhichMonFaintedFirst], a
+ call UpdateFaintedPlayerMon
+ call CheckPlayerPartyForFitMon
+ ld a, d
+ and a
+ jp z, LostBattle
+ ld hl, wEnemyMonHP
+ ld a, [hli]
+ or [hl]
+ jr nz, .notfainted
+ call UpdateBattleStateAndExperienceAfterEnemyFaint
+ ld a, [wBattleMode]
+ dec a
+ jr nz, .trainer
+ ld a, $1
+ ld [wBattleEnded], a
+ ret
+
+.trainer
+ call CheckEnemyTrainerDefeated
+ jp z, WinTrainerBattle
+
+.notfainted
+ call AskUseNextPokemon
+ jr nc, .switch
+ ld a, $1
+ ld [wBattleEnded], a
+ ret
+
+.switch
+ call ForcePlayerMonChoice
+ ret nz
+ ld a, BATTLEPLAYERACTION_USEITEM
+ ld [wBattlePlayerAction], a
+ call HandleEnemySwitch
+ jp z, WildFled_EnemyFled_LinkBattleCanceled
+ jp DoubleSwitch
+
+UpdateFaintedPlayerMon:
+ ld a, [wCurBattleMon]
+ ld c, a
+ ld hl, wBattleParticipantsNotFainted
+ ld b, RESET_FLAG
+ predef SmallFarFlagAction
+ ld hl, wEnemySubStatus3
+ res SUBSTATUS_IN_LOOP, [hl]
+ xor a
+ ld [wLowHealthAlarm], a
+ ld hl, wPlayerDamageTaken
+ ld [hli], a
+ ld [hl], a
+ ld [wBattleMonStatus], a
+ call UpdateBattleMonInParty
+ ld c, HAPPINESS_FAINTED
+ ; If TheirLevel > (YourLevel + 30), use a different parameter
+ ld a, [wBattleMonLevel]
+ add 30
+ ld b, a
+ ld a, [wEnemyMonLevel]
+ cp b
+ jr c, .got_param
+ ld c, HAPPINESS_BEATENBYSTRONGFOE
+
+.got_param
+ ld a, [wCurBattleMon]
+ ld [wCurPartyMon], a
+ callfar ChangeHappiness
+ ld a, [wBattleResult]
+ and BATTLERESULT_BITMASK
+ add LOSE
+ ld [wBattleResult], a
+ ld a, [wWhichMonFaintedFirst]
+ and a
+ ret z
+ ret ; ??????????
+
+AskUseNextPokemon:
+ call EmptyBattleTextbox
+ call LoadTilemapToTempTilemap
+; We don't need to be here if we're in a Trainer battle,
+; as that decision is made for us.
+ ld a, [wBattleMode]
+ and a
+ dec a
+ ret nz
+
+ ld hl, BattleText_UseNextMon
+ call StdBattleTextbox
+.loop
+ lb bc, 1, 7
+ call PlaceYesNoBox
+ ld a, [wMenuCursorY]
+ jr c, .pressed_b
+ and a
+ ret
+
+.pressed_b
+ ld a, [wMenuCursorY]
+ cp $1 ; YES
+ jr z, .loop
+ ld hl, wPartyMon1Speed
+ ld de, wEnemyMonSpeed
+ jp TryToRunAwayFromBattle
+
+ForcePlayerMonChoice:
+ call EmptyBattleTextbox
+ call LoadStandardMenuHeader
+ call SetUpBattlePartyMenu_NoLoop
+ call ForcePickPartyMonInBattle
+ ld a, [wLinkMode]
+ cp LINK_COLOSSEUM
+ jr nz, .skip_link
+ ld a, BATTLEPLAYERACTION_USEITEM
+ ld [wBattlePlayerAction], a
+ call LinkBattleSendReceiveAction
+
+.skip_link
+ xor a ; BATTLEPLAYERACTION_USEMOVE
+ ld [wBattlePlayerAction], a
+ ld hl, wEnemyMonHP
+ ld a, [hli]
+ or [hl]
+ jr nz, .send_out_pokemon
+
+ call ClearSprites
+ call ClearBGPalettes
+ call _LoadHPBar
+ call ExitMenu
+ call LoadTilemapToTempTilemap
+ call WaitBGMap
+ call GetMemSGBLayout
+ call SetPalettes
+ xor a
+ ret
+
+.send_out_pokemon
+ call ClearSprites
+ ld a, [wCurBattleMon]
+ ld [wLastPlayerMon], a
+ ld a, [wCurPartyMon]
+ ld [wCurBattleMon], a
+ call AddBattleParticipant
+ call InitBattleMon
+ call ResetPlayerStatLevels
+ call ClearPalettes
+ call DelayFrame
+ call _LoadHPBar
+ call CloseWindow
+ call GetMemSGBLayout
+ call SetPalettes
+ call SendOutMonText
+ call NewBattleMonStatus
+ call BreakAttraction
+ call SendOutPlayerMon
+ call EmptyBattleTextbox
+ call LoadTilemapToTempTilemap
+ call SetPlayerTurn
+ call SpikesDamage
+ ld a, $1
+ and a
+ ret
+
+PlayerPartyMonEntrance:
+ ld a, [wCurBattleMon]
+ ld [wLastPlayerMon], a
+ ld a, [wCurPartyMon]
+ ld [wCurBattleMon], a
+ call AddBattleParticipant
+ call InitBattleMon
+ call ResetPlayerStatLevels
+ call SendOutMonText
+ call NewBattleMonStatus
+ call BreakAttraction
+ call SendOutPlayerMon
+ call EmptyBattleTextbox
+ call LoadTilemapToTempTilemap
+ call SetPlayerTurn
+ jp SpikesDamage
+
+SetUpBattlePartyMenu_NoLoop:
+ call ClearBGPalettes
+SetUpBattlePartyMenu: ; switch to fullscreen menu?
+ farcall LoadPartyMenuGFX
+ farcall InitPartyMenuWithCancel
+ farcall InitPartyMenuGFX
+ ret
+
+PickPartyMonInBattle:
+.loop
+ ld a, PARTYMENUACTION_SWITCH
+ ld [wPartyMenuActionText], a
+ farcall WritePartyMenuTilemap
+ farcall PrintPartyMenuText
+ call WaitBGMap
+ call SetPalettes
+ call DelayFrame
+ farcall PartyMenuSelect
+ ret c
+ call CheckIfCurPartyMonIsFitToFight
+ jr z, .loop
+ xor a
+ ret
+
+SwitchMonAlreadyOut:
+ ld hl, wCurBattleMon
+ ld a, [wCurPartyMon]
+ cp [hl]
+ jr nz, .notout
+
+ ld hl, BattleText_MonIsAlreadyOut
+ call StdBattleTextbox
+ scf
+ ret
+
+.notout
+ xor a
+ ret
+
+ForcePickPartyMonInBattle:
+; Can't back out.
+
+.pick
+ call PickPartyMonInBattle
+ ret nc
+
+ ld de, SFX_WRONG
+ call PlaySFX
+ call WaitSFX
+ jr .pick
+
+PickSwitchMonInBattle:
+.pick
+ call PickPartyMonInBattle
+ ret c
+ call SwitchMonAlreadyOut
+ jr c, .pick
+ xor a
+ ret
+
+ForcePickSwitchMonInBattle:
+; Can't back out.
+
+.pick
+ call ForcePickPartyMonInBattle
+ call SwitchMonAlreadyOut
+ jr c, .pick
+
+ xor a
+ ret
+
+LostBattle:
+ ld a, 1
+ ld [wBattleEnded], a
+ ld a, [wBattleType]
+ cp BATTLETYPE_CANLOSE
+ jr nz, .not_canlose
+
+; Remove the enemy from the screen.
+ hlcoord 0, 0
+ lb bc, 8, 21
+ call ClearBox
+ call BattleWinSlideInEnemyTrainerFrontpic
+
+ ld c, 40
+ call DelayFrames
+
+ ld a, [wDebugFlags]
+ bit DEBUG_BATTLE_F, a
+ jr nz, .skip_win_loss_text
+ call PrintWinLossText
+.skip_win_loss_text
+ ret
+
+.not_canlose
+ ld a, [wLinkMode]
+ and a
+ jr nz, .LostLinkBattle
+
+; Greyscale
+ ld b, SCGB_BATTLE_GRAYSCALE
+ call GetSGBLayout
+ call SetPalettes
+ jr .end
+
+.LostLinkBattle:
+ call UpdateEnemyMonInParty
+ call CheckEnemyTrainerDefeated
+ jr nz, .not_tied
+ ld hl, TiedAgainstText
+ ld a, [wBattleResult]
+ and BATTLERESULT_BITMASK
+ add DRAW
+ ld [wBattleResult], a
+ jr .text
+
+.not_tied
+ ld hl, LostAgainstText
+
+.text
+ call StdBattleTextbox
+
+.end
+ scf
+ ret
+
+EnemyMonFaintedAnimation:
+ hlcoord 12, 5
+ decoord 12, 6
+ jp MonFaintedAnimation
+
+PlayerMonFaintedAnimation:
+ hlcoord 1, 10
+ decoord 1, 11
+ jp MonFaintedAnimation
+
+MonFaintedAnimation:
+ ld a, [wd8ba]
+ push af
+ set 6, a
+ ld [wd8ba], a
+ ld b, 7
+
+.OuterLoop:
+ push bc
+ push de
+ push hl
+ ld b, 6
+
+.InnerLoop:
+ push bc
+ push hl
+ push de
+ ld bc, 7
+ call CopyBytes
+ pop de
+ pop hl
+ ld bc, -SCREEN_WIDTH
+ add hl, bc
+ push hl
+ ld h, d
+ ld l, e
+ add hl, bc
+ ld d, h
+ ld e, l
+ pop hl
+ pop bc
+ dec b
+ jr nz, .InnerLoop
+
+ ld bc, 20
+ add hl, bc
+ ld de, .Spaces
+ call PlaceString
+ ld c, 2
+ call DelayFrames
+ pop hl
+ pop de
+ pop bc
+ dec b
+ jr nz, .OuterLoop
+
+ pop af
+ ld [wd8ba], a
+ ret
+
+.Spaces:
+ db " @"
+
+SlideBattlePicOut:
+ ldh [hMapObjectIndexBuffer], a
+ ld c, a
+.loop
+ push bc
+ push hl
+ ld b, $7
+.loop2
+ push hl
+ call .DoFrame
+ pop hl
+ ld de, SCREEN_WIDTH
+ add hl, de
+ dec b
+ jr nz, .loop2
+ ld c, 2
+ call DelayFrames
+ pop hl
+ pop bc
+ dec c
+ jr nz, .loop
+ ret
+
+.DoFrame:
+ ldh a, [hMapObjectIndexBuffer]
+ ld c, a
+ cp $8
+ jr nz, .back
+.forward
+ ld a, [hli]
+ ld [hld], a
+ dec hl
+ dec c
+ jr nz, .forward
+ ret
+
+.back
+ ld a, [hld]
+ ld [hli], a
+ inc hl
+ dec c
+ jr nz, .back
+ ret
+
+ForceEnemySwitch:
+ call ResetEnemyBattleVars
+ ld a, [wEnemySwitchMonIndex]
+ dec a
+ ld b, a
+ call LoadEnemyMonToSwitchTo
+ call ClearEnemyMonBox
+ call NewEnemyMonStatus
+ call ResetEnemyStatLevels
+ call Function_SetEnemyMonAndSendOutAnimation
+ call BreakAttraction
+ call ResetBattleParticipants
+ ret
+
+EnemySwitch:
+ call CheckWhetherToAskSwitch
+ jr nc, EnemySwitch_SetMode
+ ; Shift Mode
+ call ResetEnemyBattleVars
+ call CheckWhetherSwitchmonIsPredetermined
+ jr c, .skip
+ call FindMonInOTPartyToSwitchIntoBattle
+.skip
+ ; 'b' contains the PartyNr of the mon the AI will switch to
+ call LoadEnemyMonToSwitchTo
+ call OfferSwitch
+ push af
+ call ClearEnemyMonBox
+ call Function_BattleTextEnemySentOut
+ call Function_SetEnemyMonAndSendOutAnimation
+ pop af
+ ret c
+ ; If we're here, then we're switching too
+ xor a
+ ld [wBattleParticipantsNotFainted], a
+ ld [wBattleParticipantsIncludingFainted], a
+ ld [wBattlePlayerAction], a
+ inc a
+ ld [wEnemyIsSwitching], a
+ call LoadTilemapToTempTilemap
+ jp PlayerSwitch
+
+EnemySwitch_SetMode:
+ call ResetEnemyBattleVars
+ call CheckWhetherSwitchmonIsPredetermined
+ jr c, .skip
+ call FindMonInOTPartyToSwitchIntoBattle
+.skip
+ ; 'b' contains the PartyNr of the mon the AI will switch to
+ call LoadEnemyMonToSwitchTo
+ ld a, 1
+ ld [wEnemyIsSwitching], a
+ call ClearEnemyMonBox
+ call Function_BattleTextEnemySentOut
+ jp Function_SetEnemyMonAndSendOutAnimation
+
+CheckWhetherSwitchmonIsPredetermined:
+; returns carry if: ???
+ ld a, [wLinkMode]
+ and a
+ jr z, .not_linked
+
+ ld a, [wBattleAction]
+ sub BATTLEACTION_SWITCH1
+ ld b, a
+ jr .return_carry
+
+.not_linked
+ ld a, [wEnemySwitchMonIndex]
+ and a
+ jr z, .check_wBattleHasJustStarted
+
+ dec a
+ ld b, a
+ jr .return_carry
+
+.check_wBattleHasJustStarted
+ ld a, [wBattleHasJustStarted]
+ and a
+ ld b, $0
+ jr nz, .return_carry
+
+ and a
+ ret
+
+.return_carry
+ scf
+ ret
+
+ResetEnemyBattleVars:
+; and draw empty Textbox
+ xor a
+ ld [wLastPlayerCounterMove], a
+ ld [wLastEnemyCounterMove], a
+ ld [wLastEnemyMove], a
+ ld [wCurEnemyMove], a
+ dec a
+ ld [wEnemyItemState], a
+ xor a
+ ld [wPlayerWrapCount], a
+ hlcoord 18, 0
+ ld a, 8
+ call SlideBattlePicOut
+ call EmptyBattleTextbox
+ jp LoadStandardMenuHeader
+
+ResetBattleParticipants:
+ xor a
+ ld [wBattleParticipantsNotFainted], a
+ ld [wBattleParticipantsIncludingFainted], a
+AddBattleParticipant:
+ ld a, [wCurBattleMon]
+ ld c, a
+ ld hl, wBattleParticipantsNotFainted
+ ld b, SET_FLAG
+ push bc
+ predef SmallFarFlagAction
+ pop bc
+ ld hl, wBattleParticipantsIncludingFainted
+ predef_jump SmallFarFlagAction
+
+FindMonInOTPartyToSwitchIntoBattle:
+ ld b, -1
+ ld a, $1
+ ld [wBuffer1], a
+ ld [wBuffer2], a
+.loop
+ ld hl, wBuffer1
+ sla [hl]
+ inc hl
+ sla [hl]
+ inc b
+ ld a, [wOTPartyCount]
+ cp b
+ jp z, ScoreMonTypeMatchups
+ ld a, [wCurOTMon]
+ cp b
+ jr z, .discourage
+ ld hl, wOTPartyMon1HP
+ push bc
+ ld a, b
+ call GetPartyLocation
+ ld a, [hli]
+ ld c, a
+ ld a, [hl]
+ or c
+ pop bc
+ jr z, .discourage
+ call LookUpTheEffectivenessOfEveryMove
+ call IsThePlayerMonTypesEffectiveAgainstOTMon
+ jr .loop
+
+.discourage
+ ld hl, wBuffer2
+ set 0, [hl]
+ jr .loop
+
+LookUpTheEffectivenessOfEveryMove:
+ push bc
+ ld hl, wOTPartyMon1Moves
+ ld a, b
+ call GetPartyLocation
+ pop bc
+ ld e, NUM_MOVES + 1
+.loop
+ dec e
+ jr z, .done
+ ld a, [hli]
+ and a
+ jr z, .done
+ push hl
+ push de
+ push bc
+ dec a
+ ld hl, Moves
+ ld bc, MOVE_LENGTH
+ call AddNTimes
+ ld de, wEnemyMoveStruct
+ ld a, BANK(Moves)
+ call FarCopyBytes
+ call SetEnemyTurn
+ callfar BattleCheckTypeMatchup
+ pop bc
+ pop de
+ pop hl
+ ld a, [wTypeMatchup]
+ cp EFFECTIVE + 1
+ jr c, .loop
+ ld hl, wBuffer1
+ set 0, [hl]
+ ret
+.done
+ ret
+
+IsThePlayerMonTypesEffectiveAgainstOTMon:
+; Calculates the effectiveness of the types of the PlayerMon
+; against the OTMon
+ push bc
+ ld hl, wOTPartyCount
+ ld a, b
+ inc a
+ ld c, a
+ ld b, 0
+ add hl, bc
+ ld a, [hl]
+ dec a
+ ld hl, BaseData + BASE_TYPES
+ ld bc, BASE_DATA_SIZE
+ call AddNTimes
+ ld de, wEnemyMonType
+ ld bc, BASE_CATCH_RATE - BASE_TYPES
+ ld a, BANK(BaseData)
+ call FarCopyBytes
+ ld a, [wBattleMonType1]
+ ld [wPlayerMoveStruct + MOVE_TYPE], a
+ call SetPlayerTurn
+ callfar BattleCheckTypeMatchup
+ ld a, [wTypeMatchup]
+ cp EFFECTIVE + 1
+ jr nc, .super_effective
+ ld a, [wBattleMonType2]
+ ld [wPlayerMoveStruct + MOVE_TYPE], a
+ callfar BattleCheckTypeMatchup
+ ld a, [wTypeMatchup]
+ cp EFFECTIVE + 1
+ jr nc, .super_effective
+ pop bc
+ ret
+
+.super_effective
+ pop bc
+ ld hl, wBuffer1
+ bit 0, [hl]
+ jr nz, .reset
+ inc hl
+ set 0, [hl]
+ ret
+
+.reset
+ res 0, [hl]
+ ret
+
+ScoreMonTypeMatchups:
+.loop1
+ ld hl, wBuffer1
+ sla [hl]
+ inc hl
+ sla [hl]
+ jr nc, .loop1
+ ld a, [wOTPartyCount]
+ ld b, a
+ ld c, [hl]
+.loop2
+ sla c
+ jr nc, .okay
+ dec b
+ jr z, .loop5
+ jr .loop2
+
+.okay
+ ld a, [wBuffer1]
+ and a
+ jr z, .okay2
+ ld b, -1
+ ld c, a
+.loop3
+ inc b
+ sla c
+ jr nc, .loop3
+ jr .quit
+
+.okay2
+ ld b, -1
+ ld a, [wBuffer2]
+ ld c, a
+.loop4
+ inc b
+ sla c
+ jr c, .loop4
+ jr .quit
+
+.loop5
+ call BattleRandom
+ and $7
+ cp 6
+ jr nc, .loop5
+ ld b, a
+ ld a, [wCurOTMon]
+ cp b
+ jr z, .loop5
+ ld hl, wOTPartyMon1HP
+ push bc
+ ld a, b
+ call GetPartyLocation
+ pop bc
+ ld a, [hli]
+ ld c, a
+ ld a, [hl]
+ or c
+ jr z, .loop5
+
+.quit
+ ret
+
+LoadEnemyMonToSwitchTo:
+ ; 'b' contains the PartyNr of the mon the AI will switch to
+ ld a, b
+ ld [wCurPartyMon], a
+ ld hl, wOTPartyMon1Level
+ call GetPartyLocation
+ ld a, [hl]
+ ld [wCurPartyLevel], a
+ ld a, [wCurPartyMon]
+ inc a
+ ld hl, wOTPartyCount
+ ld c, a
+ ld b, 0
+ add hl, bc
+ ld a, [hl]
+ ld [wTempEnemyMonSpecies], a
+ ld [wCurPartySpecies], a
+ call LoadEnemyMon
+
+ ld a, [wCurPartySpecies]
+ cp UNOWN
+ jr nz, .skip_unown
+ ld a, [wFirstUnownSeen]
+ and a
+ jr nz, .skip_unown
+ ld hl, wEnemyMonDVs
+ predef GetUnownLetter
+ ld a, [wUnownLetter]
+ ld [wFirstUnownSeen], a
+.skip_unown
+
+ ld hl, wEnemyMonHP
+ ld a, [hli]
+ ld [wEnemyHPAtTimeOfPlayerSwitch], a
+ ld a, [hl]
+ ld [wEnemyHPAtTimeOfPlayerSwitch + 1], a
+ ret
+
+CheckWhetherToAskSwitch:
+ ld a, [wBattleHasJustStarted]
+ dec a
+ jp z, .return_nc
+ ld a, [wPartyCount]
+ dec a
+ jp z, .return_nc
+ ld a, [wLinkMode]
+ and a
+ jp nz, .return_nc
+ ld a, [wOptions]
+ bit BATTLE_SHIFT, a
+ jr nz, .return_nc
+ ld a, [wCurPartyMon]
+ push af
+ ld a, [wCurBattleMon]
+ ld [wCurPartyMon], a
+ farcall CheckCurPartyMonFainted
+ pop bc
+ ld a, b
+ ld [wCurPartyMon], a
+ jr c, .return_nc
+ scf
+ ret
+
+.return_nc
+ and a
+ ret
+
+OfferSwitch:
+ ld a, [wCurPartyMon]
+ push af
+ callfar Battle_GetTrainerName
+ ld hl, BattleText_EnemyIsAboutToUseWillPlayerChangeMon
+ call StdBattleTextbox
+ lb bc, 1, 7
+ call PlaceYesNoBox
+ ld a, [wMenuCursorY]
+ dec a
+ jr nz, .said_no
+ call SetUpBattlePartyMenu_NoLoop
+ call PickSwitchMonInBattle
+ jr c, .canceled_switch
+ ld a, [wCurBattleMon]
+ ld [wLastPlayerMon], a
+ ld a, [wCurPartyMon]
+ ld [wCurBattleMon], a
+ call ClearPalettes
+ call DelayFrame
+ call _LoadHPBar
+ pop af
+ ld [wCurPartyMon], a
+ xor a
+ ld [wCurEnemyMove], a
+ ld [wCurPlayerMove], a
+ and a
+ ret
+
+.canceled_switch
+ call ClearPalettes
+ call DelayFrame
+ call _LoadHPBar
+
+.said_no
+ pop af
+ ld [wCurPartyMon], a
+ scf
+ ret
+
+ClearEnemyMonBox:
+ xor a
+ ldh [hBGMapMode], a
+ call ExitMenu
+ call ClearSprites
+ hlcoord 1, 0
+ lb bc, 4, 10
+ call ClearBox
+ call WaitBGMap
+ jp FinishBattleAnim
+
+Function_BattleTextEnemySentOut:
+ callfar Battle_GetTrainerName
+ ld hl, BattleText_EnemySentOut
+ jp StdBattleTextbox
+
+Function_SetEnemyMonAndSendOutAnimation:
+ ld a, [wTempEnemyMonSpecies]
+ ld [wCurPartySpecies], a
+ ld [wCurSpecies], a
+ call GetBaseData
+ ld a, OTPARTYMON
+ ld [wMonType], a
+ predef CopyMonToTempMon
+ call GetEnemyMonFrontpic
+
+ xor a
+ ld [wNumHits], a
+ ld [wBattleAnimParam], a
+ call SetEnemyTurn
+ ld de, ANIM_SEND_OUT_MON
+ call Call_PlayBattleAnim
+
+ call BattleCheckEnemyShininess
+ jr nc, .cry_no_anim
+
+ ld a, 1 ; shiny anim
+ ld [wBattleAnimParam], a
+ ld de, ANIM_SEND_OUT_MON
+ call Call_PlayBattleAnim
+
+.cry_no_anim
+ ld a, $f
+ ld [wCryTracks], a
+ ld a, [wTempEnemyMonSpecies]
+ call PlayStereoCry
+ call UpdateEnemyHUD
+ ld a, $1
+ ldh [hBGMapMode], a
+ ret
+
+NewEnemyMonStatus:
+ xor a
+ ld [wLastPlayerCounterMove], a
+ ld [wLastEnemyCounterMove], a
+ ld [wLastEnemyMove], a
+ ld hl, wEnemySubStatus1
+rept 4
+ ld [hli], a
+endr
+ ld [hl], a
+ ld [wEnemyDisableCount], a
+ ld [wEnemyFuryCutterCount], a
+ ld [wEnemyProtectCount], a
+ ld [wEnemyRageCounter], a
+ ld [wEnemyDisabledMove], a
+ ld [wEnemyMinimized], a
+ ld [wPlayerWrapCount], a
+ ld [wEnemyWrapCount], a
+ ld [wEnemyTurnsTaken], a
+ ld hl, wPlayerSubStatus5
+ res SUBSTATUS_CANT_RUN, [hl]
+ ret
+
+ResetEnemyStatLevels:
+ ld a, BASE_STAT_LEVEL
+ ld b, NUM_LEVEL_STATS
+ ld hl, wEnemyStatLevels
+.loop
+ ld [hli], a
+ dec b
+ jr nz, .loop
+ ret
+
+CheckPlayerPartyForFitMon:
+; Has the player any mon in his Party that can fight?
+ ld a, [wPartyCount]
+ ld e, a
+ xor a
+ ld hl, wPartyMon1HP
+ ld bc, PARTYMON_STRUCT_LENGTH - 1
+.loop
+ or [hl]
+ inc hl ; + 1
+ or [hl]
+ add hl, bc
+ dec e
+ jr nz, .loop
+ ld d, a
+ ret
+
+CheckIfCurPartyMonIsFitToFight:
+ ld a, [wCurPartyMon]
+ ld hl, wPartyMon1HP
+ call GetPartyLocation
+ ld a, [hli]
+ or [hl]
+ ret nz
+
+ ld a, [wBattleHasJustStarted]
+ and a
+ jr nz, .finish_fail
+ ld hl, wPartySpecies
+ ld a, [wCurPartyMon]
+ ld c, a
+ ld b, 0
+ add hl, bc
+ ld a, [hl]
+ cp EGG
+ ld hl, BattleText_AnEGGCantBattle
+ jr z, .print_textbox
+
+ ld hl, BattleText_TheresNoWillToBattle
+
+.print_textbox
+ call StdBattleTextbox
+
+.finish_fail
+ xor a
+ ret
+
+TryToRunAwayFromBattle:
+; Run away from battle, with or without item
+ ld a, [wBattleType]
+ cp BATTLETYPE_DEBUG
+ jp z, .can_escape
+ cp BATTLETYPE_CONTEST
+ jp z, .can_escape
+ cp BATTLETYPE_TRAP
+ jp z, .cant_escape
+ cp BATTLETYPE_SHINY
+ jp z, .cant_escape
+
+ ld a, [wLinkMode]
+ and a
+ jp nz, .can_escape
+
+ ld a, [wBattleMode]
+ dec a
+ jp nz, .cant_run_from_trainer
+
+ ld a, [wEnemySubStatus5]
+ bit SUBSTATUS_CANT_RUN, a
+ jp nz, .cant_escape
+
+ ld a, [wPlayerWrapCount]
+ and a
+ jp nz, .cant_escape
+
+ push hl
+ push de
+ ld a, [wBattleMonItem]
+ ld [wNamedObjectIndexBuffer], a
+ ld b, a
+ callfar GetItemHeldEffect
+ ld a, b
+ cp HELD_ESCAPE
+ pop de
+ pop hl
+ jr nz, .no_flee_item
+
+ call SetPlayerTurn
+ call GetItemName
+ ld hl, BattleText_UserFledUsingAStringBuffer1
+ call StdBattleTextbox
+ jp .can_escape
+
+.no_flee_item
+ ld a, [wNumFleeAttempts]
+ inc a
+ ld [wNumFleeAttempts], a
+ ld a, [hli]
+ ldh [hMultiplicand + 1], a
+ ld a, [hl]
+ ldh [hMultiplicand + 2], a
+ ld a, [de]
+ inc de
+ ldh [hEnemyMonSpeed + 0], a
+ ld a, [de]
+ ldh [hEnemyMonSpeed + 1], a
+ call SafeLoadTempTilemapToTilemap
+ ld de, hMultiplicand + 1
+ ld hl, hEnemyMonSpeed
+ ld c, 2
+ call CompareBytes
+ jr nc, .can_escape
+
+ xor a
+ ldh [hMultiplicand + 0], a
+ ld a, 32
+ ldh [hMultiplier], a
+ call Multiply
+ ldh a, [hProduct + 2]
+ ldh [hDividend + 0], a
+ ldh a, [hProduct + 3]
+ ldh [hDividend + 1], a
+ ldh a, [hEnemyMonSpeed + 0]
+ ld b, a
+ ldh a, [hEnemyMonSpeed + 1]
+ srl b
+ rr a
+ srl b
+ rr a
+ and a
+ jr z, .can_escape
+ ldh [hDivisor], a
+ ld b, 2
+ call Divide
+ ldh a, [hQuotient + 2]
+ and a
+ jr nz, .can_escape
+ ld a, [wNumFleeAttempts]
+ ld c, a
+.loop
+ dec c
+ jr z, .cant_escape_2
+ ld b, 30
+ ldh a, [hQuotient + 3]
+ add b
+ ldh [hQuotient + 3], a
+ jr c, .can_escape
+ jr .loop
+
+.cant_escape_2
+ call BattleRandom
+ ld b, a
+ ldh a, [hQuotient + 3]
+ cp b
+ jr nc, .can_escape
+ ld a, BATTLEPLAYERACTION_USEITEM
+ ld [wBattlePlayerAction], a
+ ld hl, BattleText_CantEscape2
+ jr .print_inescapable_text
+
+.cant_escape
+ ld hl, BattleText_CantEscape
+ jr .print_inescapable_text
+
+.cant_run_from_trainer
+ ld hl, BattleText_TheresNoEscapeFromTrainerBattle
+
+.print_inescapable_text
+ call StdBattleTextbox
+ ld a, TRUE
+ ld [wFailedToFlee], a
+ call LoadTilemapToTempTilemap
+ and a
+ ret
+
+.can_escape
+ ld a, [wLinkMode]
+ and a
+ ld a, DRAW
+ jr z, .fled
+ call LoadTilemapToTempTilemap
+ xor a ; BATTLEPLAYERACTION_USEMOVE
+ ld [wBattlePlayerAction], a
+ ld a, $f
+ ld [wCurMoveNum], a
+ xor a
+ ld [wCurPlayerMove], a
+ call LinkBattleSendReceiveAction
+ call SafeLoadTempTilemapToTilemap
+
+ ; Got away safely
+ ld a, [wBattleAction]
+ cp BATTLEACTION_FORFEIT
+ ld a, DRAW
+ jr z, .fled
+ dec a ; LOSE
+.fled
+ ld b, a
+ ld a, [wBattleResult]
+ and BATTLERESULT_BITMASK
+ add b
+ ld [wBattleResult], a
+ call StopDangerSound
+ push de
+ ld de, SFX_RUN
+ call WaitPlaySFX
+ pop de
+ call WaitSFX
+ ld hl, BattleText_GotAwaySafely
+ call StdBattleTextbox
+ call WaitSFX
+ call LoadTilemapToTempTilemap
+ scf
+ ret
+
+InitBattleMon:
+ ld a, MON_SPECIES
+ call GetPartyParamLocation
+ ld de, wBattleMonSpecies
+ ld bc, MON_ID
+ call CopyBytes
+ ld bc, MON_DVS - MON_ID
+ add hl, bc
+ ld de, wBattleMonDVs
+ ld bc, MON_PKRUS - MON_DVS
+ call CopyBytes
+ inc hl
+ inc hl
+ inc hl
+ ld de, wBattleMonLevel
+ ld bc, PARTYMON_STRUCT_LENGTH - MON_LEVEL
+ call CopyBytes
+ ld a, [wBattleMonSpecies]
+ ld [wTempBattleMonSpecies], a
+ ld [wCurPartySpecies], a
+ ld [wCurSpecies], a
+ call GetBaseData
+ ld a, [wBaseType1]
+ ld [wBattleMonType1], a
+ ld a, [wBaseType2]
+ ld [wBattleMonType2], a
+ ld hl, wPartyMonNicknames
+ ld a, [wCurBattleMon]
+ call SkipNames
+ ld de, wBattleMonNick
+ ld bc, MON_NAME_LENGTH
+ call CopyBytes
+ ld hl, wBattleMonAttack
+ ld de, wPlayerStats
+ ld bc, PARTYMON_STRUCT_LENGTH - MON_ATK
+ call CopyBytes
+ call ApplyStatusEffectOnPlayerStats
+ call BadgeStatBoosts
+ ret
+
+BattleCheckPlayerShininess:
+ call GetPartyMonDVs
+ jr BattleCheckShininess
+
+BattleCheckEnemyShininess:
+ call GetEnemyMonDVs
+
+BattleCheckShininess:
+ ld b, h
+ ld c, l
+ callfar CheckShininess
+ ret
+
+GetPartyMonDVs:
+ ld hl, wBattleMonDVs
+ ld a, [wPlayerSubStatus5]
+ bit SUBSTATUS_TRANSFORMED, a
+ ret z
+ ld hl, wPartyMon1DVs
+ ld a, [wCurBattleMon]
+ jp GetPartyLocation
+
+GetEnemyMonDVs:
+ ld hl, wEnemyMonDVs
+ ld a, [wEnemySubStatus5]
+ bit SUBSTATUS_TRANSFORMED, a
+ ret z
+ ld hl, wEnemyBackupDVs
+ ld a, [wBattleMode]
+ dec a
+ ret z
+ ld hl, wOTPartyMon1DVs
+ ld a, [wCurOTMon]
+ jp GetPartyLocation
+
+ResetPlayerStatLevels:
+ ld a, BASE_STAT_LEVEL
+ ld b, NUM_LEVEL_STATS
+ ld hl, wPlayerStatLevels
+.loop
+ ld [hli], a
+ dec b
+ jr nz, .loop
+ ret
+
+InitEnemyMon:
+ ld a, [wCurPartyMon]
+ ld hl, wOTPartyMon1Species
+ call GetPartyLocation
+ ld de, wEnemyMonSpecies
+ ld bc, MON_ID
+ call CopyBytes
+ ld bc, MON_DVS - MON_ID
+ add hl, bc
+ ld de, wEnemyMonDVs
+ ld bc, MON_PKRUS - MON_DVS
+ call CopyBytes
+ inc hl
+ inc hl
+ inc hl
+ ld de, wEnemyMonLevel
+ ld bc, PARTYMON_STRUCT_LENGTH - MON_LEVEL
+ call CopyBytes
+ ld a, [wEnemyMonSpecies]
+ ld [wCurSpecies], a
+ call GetBaseData
+ ld hl, wOTPartyMonNicknames
+ ld a, [wCurPartyMon]
+ call SkipNames
+ ld de, wEnemyMonNick
+ ld bc, MON_NAME_LENGTH
+ call CopyBytes
+ ld hl, wEnemyMonAttack
+ ld de, wEnemyStats
+ ld bc, PARTYMON_STRUCT_LENGTH - MON_ATK
+ call CopyBytes
+ call ApplyStatusEffectOnEnemyStats
+ ld hl, wBaseType1
+ ld de, wEnemyMonType1
+ ld a, [hli]
+ ld [de], a
+ inc de
+ ld a, [hl]
+ ld [de], a
+ ld hl, wBaseStats
+ ld de, wEnemyMonBaseStats
+ ld b, 5
+.loop
+ ld a, [hli]
+ ld [de], a
+ inc de
+ dec b
+ jr nz, .loop
+ ld a, [wCurPartyMon]
+ ld [wCurOTMon], a
+ ret
+
+SwitchPlayerMon:
+ call ClearSprites
+ ld a, [wCurBattleMon]
+ ld [wLastPlayerMon], a
+ ld a, [wCurPartyMon]
+ ld [wCurBattleMon], a
+ call AddBattleParticipant
+ call InitBattleMon
+ call ResetPlayerStatLevels
+ call NewBattleMonStatus
+ call BreakAttraction
+ call SendOutPlayerMon
+ call EmptyBattleTextbox
+ call LoadTilemapToTempTilemap
+ ld hl, wEnemyMonHP
+ ld a, [hli]
+ or [hl]
+ ret
+
+SendOutPlayerMon:
+ ld hl, wBattleMonDVs
+ predef GetUnownLetter
+ hlcoord 1, 5
+ ld b, 7
+ ld c, 8
+ call ClearBox
+ call WaitBGMap
+ xor a
+ ldh [hBGMapMode], a
+ call GetBattleMonBackpic
+ xor a
+ ldh [hGraphicStartTile], a
+ ld [wBattleMenuCursorBuffer], a
+ ld [wCurMoveNum], a
+ ld [wTypeModifier], a
+ ld [wPlayerMoveStruct + MOVE_ANIM], a
+ ld [wLastPlayerCounterMove], a
+ ld [wLastEnemyCounterMove], a
+ ld [wLastPlayerMove], a
+ call CheckAmuletCoin
+ call FinishBattleAnim
+ xor a
+ ld [wEnemyWrapCount], a
+ call SetPlayerTurn
+ xor a
+ ld [wNumHits], a
+ ld [wBattleAnimParam], a
+ ld de, ANIM_SEND_OUT_MON
+ call Call_PlayBattleAnim
+ call BattleCheckPlayerShininess
+ jr nc, .not_shiny
+ ld a, 1
+ ld [wBattleAnimParam], a
+ ld de, ANIM_SEND_OUT_MON
+ call Call_PlayBattleAnim
+
+.not_shiny
+ ld a, $f0
+ ld [wCryTracks], a
+ ld a, [wCurPartySpecies]
+ call PlayStereoCry
+ call UpdatePlayerHUD
+ ld a, $1
+ ldh [hBGMapMode], a
+ ret
+
+NewBattleMonStatus:
+ xor a
+ ld [wLastPlayerCounterMove], a
+ ld [wLastEnemyCounterMove], a
+ ld [wLastPlayerMove], a
+ ld hl, wPlayerSubStatus1
+rept 4
+ ld [hli], a
+endr
+ ld [hl], a
+ ld hl, wPlayerUsedMoves
+ ld [hli], a
+ ld [hli], a
+ ld [hli], a
+ ld [hl], a
+ ld [wPlayerDisableCount], a
+ ld [wPlayerFuryCutterCount], a
+ ld [wPlayerProtectCount], a
+ ld [wPlayerRageCounter], a
+ ld [wDisabledMove], a
+ ld [wPlayerMinimized], a
+ ld [wEnemyWrapCount], a
+ ld [wPlayerWrapCount], a
+ ld [wPlayerTurnsTaken], a
+ ld hl, wEnemySubStatus5
+ res SUBSTATUS_CANT_RUN, [hl]
+ ret
+
+BreakAttraction:
+ ld hl, wPlayerSubStatus1
+ res SUBSTATUS_IN_LOVE, [hl]
+ ld hl, wEnemySubStatus1
+ res SUBSTATUS_IN_LOVE, [hl]
+ ret
+
+SpikesDamage:
+ ld hl, wPlayerScreens
+ ld de, wBattleMonType
+ ld bc, UpdatePlayerHUD
+ ldh a, [hBattleTurn]
+ and a
+ jr z, .ok
+ ld hl, wEnemyScreens
+ ld de, wEnemyMonType
+ ld bc, UpdateEnemyHUD
+.ok
+
+ bit SCREENS_SPIKES, [hl]
+ ret z
+
+ ; Flying-types aren't affected by Spikes.
+ ld a, [de]
+ cp FLYING
+ ret z
+ inc de
+ ld a, [de]
+ cp FLYING
+ ret z
+
+ push bc
+
+ ld hl, BattleText_UserHurtBySpikes ; "hurt by SPIKES!"
+ call StdBattleTextbox
+
+ call GetEighthMaxHP
+ call SubtractHPFromTarget
+
+ pop hl
+ call .hl
+
+ jp WaitBGMap
+
+.hl
+ jp hl
+
+PursuitSwitch:
+ ld a, BATTLE_VARS_MOVE
+ call GetBattleVar
+ ld b, a
+ call GetMoveEffect
+ ld a, b
+ cp EFFECT_PURSUIT
+ jr nz, .done
+
+ ld a, [wCurBattleMon]
+ push af
+
+ ld hl, DoPlayerTurn
+ ldh a, [hBattleTurn]
+ and a
+ jr z, .do_turn
+ ld hl, DoEnemyTurn
+ ld a, [wLastPlayerMon]
+ ld [wCurBattleMon], a
+.do_turn
+ ld a, BANK(DoPlayerTurn) ; aka BANK(DoEnemyTurn)
+ rst FarCall
+
+ ld a, BATTLE_VARS_MOVE
+ call GetBattleVarAddr
+ ld a, $ff
+ ld [hl], a
+
+ pop af
+ ld [wCurBattleMon], a
+
+ ldh a, [hBattleTurn]
+ and a
+ jr z, .check_enemy_fainted
+
+ ld a, [wLastPlayerMon]
+ call UpdateBattleMon
+ ld hl, wBattleMonHP
+ ld a, [hli]
+ or [hl]
+ jr nz, .done
+
+ ld a, $f0
+ ld [wCryTracks], a
+ ld a, [wBattleMonSpecies]
+ call PlayStereoCry
+ ld a, [wLastPlayerMon]
+ ld c, a
+ ld hl, wBattleParticipantsNotFainted
+ ld b, RESET_FLAG
+ predef SmallFarFlagAction
+ call PlayerMonFaintedAnimation
+ ld hl, BattleText_MonFainted
+ jr .done_fainted
+
+.check_enemy_fainted
+ ld hl, wEnemyMonHP
+ ld a, [hli]
+ or [hl]
+ jr nz, .done
+
+ ld de, SFX_KINESIS
+ call PlaySFX
+ call WaitSFX
+ ld de, SFX_FAINT
+ call PlaySFX
+ call WaitSFX
+ call EnemyMonFaintedAnimation
+ ld hl, BattleText_EnemyMonFainted
+
+.done_fainted
+ call StdBattleTextbox
+ scf
+ ret
+
+.done
+ and a
+ ret
+
+RecallPlayerMon:
+ ldh a, [hBattleTurn]
+ push af
+ xor a
+ ldh [hBattleTurn], a
+ ld [wNumHits], a
+ ld de, ANIM_RETURN_MON
+ call Call_PlayBattleAnim
+ pop af
+ ldh [hBattleTurn], a
+ ret
+
+HandleHealingItems:
+ ldh a, [hSerialConnectionStatus]
+ cp USING_EXTERNAL_CLOCK
+ jr z, .player_1
+ call SetPlayerTurn
+ call HandleHPHealingItem
+ call UseHeldStatusHealingItem
+ call UseConfusionHealingItem
+ call SetEnemyTurn
+ call HandleHPHealingItem
+ call UseHeldStatusHealingItem
+ jp UseConfusionHealingItem
+
+.player_1
+ call SetEnemyTurn
+ call HandleHPHealingItem
+ call UseHeldStatusHealingItem
+ call UseConfusionHealingItem
+ call SetPlayerTurn
+ call HandleHPHealingItem
+ call UseHeldStatusHealingItem
+ jp UseConfusionHealingItem
+
+HandleHPHealingItem:
+ callfar GetOpponentItem
+ ld a, b
+ cp HELD_BERRY
+ ret nz
+ ld de, wEnemyMonHP + 1
+ ld hl, wEnemyMonMaxHP
+ ldh a, [hBattleTurn]
+ and a
+ jr z, .go
+ ld de, wBattleMonHP + 1
+ ld hl, wBattleMonMaxHP
+
+.go
+; If, and only if, Pokemon's HP is less than half max, use the item.
+; Store current HP in Buffer 3/4
+ push bc
+ ld a, [de]
+ ld [wBuffer3], a
+ add a
+ ld c, a
+ dec de
+ ld a, [de]
+ inc de
+ ld [wBuffer4], a
+ adc a
+ ld b, a
+ ld a, b
+ cp [hl]
+ ld a, c
+ pop bc
+ jr z, .equal
+ jr c, .less
+ ret
+
+.equal
+ inc hl
+ cp [hl]
+ dec hl
+ ret nc
+
+.less
+ call ItemRecoveryAnim
+ ; store max HP in wBuffer1/2
+ ld a, [hli]
+ ld [wBuffer2], a
+ ld a, [hl]
+ ld [wBuffer1], a
+ ld a, [de]
+ add c
+ ld [wBuffer5], a
+ ld c, a
+ dec de
+ ld a, [de]
+ adc 0
+ ld [wBuffer6], a
+ ld b, a
+ ld a, [hld]
+ cp c
+ ld a, [hl]
+ sbc b
+ jr nc, .okay
+ ld a, [hli]
+ ld [wBuffer6], a
+ ld a, [hl]
+ ld [wBuffer5], a
+
+.okay
+ ld a, [wBuffer6]
+ ld [de], a
+ inc de
+ ld a, [wBuffer5]
+ ld [de], a
+ ldh a, [hBattleTurn]
+ ld [wWhichHPBar], a
+ and a
+ hlcoord 2, 2
+ jr z, .got_hp_bar_coords
+ hlcoord 10, 9
+
+.got_hp_bar_coords
+ ld [wWhichHPBar], a
+ predef AnimateHPBar
+UseOpponentItem:
+ call RefreshBattleHuds
+ callfar GetOpponentItem
+ ld a, [hl]
+ ld [wNamedObjectIndexBuffer], a
+ call GetItemName
+ callfar ConsumeHeldItem
+ ld hl, RecoveredUsingText
+ jp StdBattleTextbox
+
+ItemRecoveryAnim:
+ push hl
+ push de
+ push bc
+ call EmptyBattleTextbox
+ ld a, RECOVER
+ ld [wFXAnimID], a
+ call SwitchTurnCore
+ xor a
+ ld [wNumHits], a
+ ld [wFXAnimID + 1], a
+ predef PlayBattleAnim
+ call SwitchTurnCore
+ pop bc
+ pop de
+ pop hl
+ ret
+
+UseHeldStatusHealingItem:
+ callfar GetOpponentItem
+ ld hl, HeldStatusHealingEffects
+.loop
+ ld a, [hli]
+ cp $ff
+ ret z
+ inc hl
+ cp b
+ jr nz, .loop
+ dec hl
+ ld b, [hl]
+ ld a, BATTLE_VARS_STATUS_OPP
+ call GetBattleVarAddr
+ and b
+ ret z
+ xor a
+ ld [hl], a
+ push bc
+ call UpdateOpponentInParty
+ pop bc
+ ld a, BATTLE_VARS_SUBSTATUS5_OPP
+ call GetBattleVarAddr
+ and [hl]
+ res SUBSTATUS_TOXIC, [hl]
+ ld a, BATTLE_VARS_SUBSTATUS1_OPP
+ call GetBattleVarAddr
+ and [hl]
+ res SUBSTATUS_NIGHTMARE, [hl]
+ ld a, b
+ cp ALL_STATUS
+ jr nz, .skip_confuse
+ ld a, BATTLE_VARS_SUBSTATUS3_OPP
+ call GetBattleVarAddr
+ res SUBSTATUS_CONFUSED, [hl]
+
+.skip_confuse
+ ld hl, CalcEnemyStats
+ ldh a, [hBattleTurn]
+ and a
+ jr z, .got_pointer
+ ld hl, CalcPlayerStats
+
+.got_pointer
+ call SwitchTurnCore
+ ld a, BANK(CalcPlayerStats) ; aka BANK(CalcEnemyStats)
+ rst FarCall
+ call SwitchTurnCore
+ call ItemRecoveryAnim
+ call UseOpponentItem
+ ld a, $1
+ and a
+ ret
+
+INCLUDE "data/battle/held_heal_status.asm"
+
+UseConfusionHealingItem:
+ ld a, BATTLE_VARS_SUBSTATUS3_OPP
+ call GetBattleVar
+ bit SUBSTATUS_CONFUSED, a
+ ret z
+ callfar GetOpponentItem
+ ld a, b
+ cp HELD_HEAL_CONFUSION
+ jr z, .heal_status
+ cp HELD_HEAL_STATUS
+ ret nz
+
+.heal_status
+ ld a, [hl]
+ ld [wNamedObjectIndexBuffer], a
+ ld a, BATTLE_VARS_SUBSTATUS3_OPP
+ call GetBattleVarAddr
+ res SUBSTATUS_CONFUSED, [hl]
+ call GetItemName
+ call ItemRecoveryAnim
+ ld hl, BattleText_ItemHealedConfusion
+ call StdBattleTextbox
+ ldh a, [hBattleTurn]
+ and a
+ jr nz, .do_partymon
+ call GetOTPartymonItem
+ xor a
+ ld [bc], a
+ ld a, [wBattleMode]
+ dec a
+ ret z
+ ld [hl], $0
+ ret
+
+.do_partymon
+ call GetPartymonItem
+ xor a
+ ld [bc], a
+ ld [hl], a
+ ret
+
+HandleStatBoostingHeldItems:
+; The effects handled here are not used in-game.
+ ldh a, [hSerialConnectionStatus]
+ cp USING_EXTERNAL_CLOCK
+ jr z, .player_1
+ call .DoPlayer
+ jp .DoEnemy
+
+.player_1
+ call .DoEnemy
+ jp .DoPlayer
+
+.DoPlayer:
+ call GetPartymonItem
+ ld a, $0
+ jp .HandleItem
+
+.DoEnemy:
+ call GetOTPartymonItem
+ ld a, $1
+.HandleItem:
+ ldh [hBattleTurn], a
+ ld d, h
+ ld e, l
+ push de
+ push bc
+ ld a, [bc]
+ ld b, a
+ callfar GetItemHeldEffect
+ ld hl, HeldStatUpItems
+.loop
+ ld a, [hli]
+ cp -1
+ jr z, .finish
+ inc hl
+ inc hl
+ cp b
+ jr nz, .loop
+ pop bc
+ ld a, [bc]
+ ld [wNamedObjectIndexBuffer], a
+ push bc
+ dec hl
+ dec hl
+ ld a, [hli]
+ ld h, [hl]
+ ld l, a
+ ld a, BANK(BattleCommand_AttackUp)
+ rst FarCall
+ pop bc
+ pop de
+ ld a, [wFailedMessage]
+ and a
+ ret nz
+ xor a
+ ld [bc], a
+ ld [de], a
+ call GetItemName
+ ld hl, BattleText_UsersStringBuffer1Activated
+ call StdBattleTextbox
+ callfar BattleCommand_StatUpMessage
+ ret
+
+.finish
+ pop bc
+ pop de
+ ret
+
+INCLUDE "data/battle/held_stat_up.asm"
+
+GetPartymonItem:
+ ld hl, wPartyMon1Item
+ ld a, [wCurBattleMon]
+ call GetPartyLocation
+ ld bc, wBattleMonItem
+ ret
+
+GetOTPartymonItem:
+ ld hl, wOTPartyMon1Item
+ ld a, [wCurOTMon]
+ call GetPartyLocation
+ ld bc, wEnemyMonItem
+ ret
+
+UpdateBattleHUDs:
+ push hl
+ push de
+ push bc
+ call DrawPlayerHUD
+ ld hl, wPlayerHPPal
+ call SetHPPal
+ call CheckDanger
+ call DrawEnemyHUD
+ ld hl, wEnemyHPPal
+ call SetHPPal
+ pop bc
+ pop de
+ pop hl
+ ret
+
+UpdatePlayerHUD::
+ push hl
+ push de
+ push bc
+ call DrawPlayerHUD
+ call UpdatePlayerHPPal
+ call CheckDanger
+ pop bc
+ pop de
+ pop hl
+ ret
+
+DrawPlayerHUD:
+ xor a
+ ldh [hBGMapMode], a
+
+ ; Clear the area
+ hlcoord 9, 7
+ lb bc, 5, 11
+ call ClearBox
+
+ farcall DrawPlayerHUDBorder
+
+ hlcoord 18, 9
+ ld [hl], $73 ; vertical bar
+ call PrintPlayerHUD
+
+ ; HP bar
+ hlcoord 10, 9
+ ld b, 1
+ xor a ; PARTYMON
+ ld [wMonType], a
+ predef DrawPlayerHP
+
+ ; Exp bar
+ push de
+ ld a, [wCurBattleMon]
+ ld hl, wPartyMon1Exp + 2
+ call GetPartyLocation
+ ld d, h
+ ld e, l
+
+ hlcoord 10, 11
+ ld a, [wTempMonLevel]
+ ld b, a
+ call FillInExpBar
+ pop de
+ ret
+
+UpdatePlayerHPPal:
+ ld hl, wPlayerHPPal
+ jp UpdateHPPal
+
+CheckDanger:
+ ld hl, wBattleMonHP
+ ld a, [hli]
+ or [hl]
+ jr z, .no_danger
+ ld a, [wBattleLowHealthAlarm]
+ and a
+ jr nz, .done
+ ld a, [wPlayerHPPal]
+ cp HP_RED
+ jr z, .danger
+
+.no_danger
+ ld hl, wLowHealthAlarm
+ res DANGER_ON_F, [hl]
+ jr .done
+
+.danger
+ ld hl, wLowHealthAlarm
+ set DANGER_ON_F, [hl]
+
+.done
+ ret
+
+PrintPlayerHUD:
+ ld de, wBattleMonNick
+ hlcoord 10, 7
+ call ret_3df99
+ call PlaceString
+
+ push bc
+
+ ld a, [wCurBattleMon]
+ ld hl, wPartyMon1DVs
+ call GetPartyLocation
+ ld de, wTempMonDVs
+ ld a, [hli]
+ ld [de], a
+ inc de
+ ld a, [hl]
+ ld [de], a
+ ld hl, wBattleMonLevel
+ ld de, wTempMonLevel
+ ld bc, $11
+ call CopyBytes
+ ld a, [wCurBattleMon]
+ ld hl, wPartyMon1Species
+ call GetPartyLocation
+ ld a, [hl]
+ ld [wCurPartySpecies], a
+ ld [wCurSpecies], a
+ call GetBaseData
+
+ pop hl
+ dec hl
+
+ ld a, TEMPMON
+ ld [wMonType], a
+ callfar GetGender
+ ld a, " "
+ jr c, .got_gender_char
+ ld a, "♂"
+ jr nz, .got_gender_char
+ ld a, "♀"
+
+.got_gender_char
+ hlcoord 17, 8
+ ld [hl], a
+ hlcoord 14, 8
+ push af ; back up gender
+ push hl
+ ld de, wBattleMonStatus
+ predef PlaceNonFaintStatus
+ pop hl
+ pop bc
+ ret nz
+ ld a, b
+ cp " "
+ jr nz, .copy_level ; male or female
+ dec hl ; genderless
+
+.copy_level
+ ld a, [wBattleMonLevel]
+ ld [wTempMonLevel], a
+ jp PrintLevel
+
+UpdateEnemyHUD::
+ push hl
+ push de
+ push bc
+ call DrawEnemyHUD
+ call UpdateEnemyHPPal
+ pop bc
+ pop de
+ pop hl
+ ret
+
+DrawEnemyHUD:
+ xor a
+ ldh [hBGMapMode], a
+
+ hlcoord 1, 0
+ lb bc, 4, 11
+ call ClearBox
+
+ farcall DrawEnemyHUDBorder
+
+ ld a, [wTempEnemyMonSpecies]
+ ld [wCurSpecies], a
+ ld [wCurPartySpecies], a
+ call GetBaseData
+ ld de, wEnemyMonNick
+ hlcoord 1, 0
+ call ret_3df99
+ call PlaceString
+ ld h, b
+ ld l, c
+ dec hl
+
+ ld hl, wEnemyMonDVs
+ ld de, wTempMonDVs
+ ld a, [wEnemySubStatus5]
+ bit SUBSTATUS_TRANSFORMED, a
+ jr z, .ok
+ ld hl, wEnemyBackupDVs
+.ok
+ ld a, [hli]
+ ld [de], a
+ inc de
+ ld a, [hl]
+ ld [de], a
+
+ ld a, TEMPMON
+ ld [wMonType], a
+ callfar GetGender
+ ld a, " "
+ jr c, .got_gender
+ ld a, "♂"
+ jr nz, .got_gender
+ ld a, "♀"
+
+.got_gender
+ hlcoord 9, 1
+ ld [hl], a
+
+ hlcoord 6, 1
+ push af
+ push hl
+ ld de, wEnemyMonStatus
+ predef PlaceNonFaintStatus
+ pop hl
+ pop bc
+ jr nz, .skip_level
+ ld a, b
+ cp " "
+ jr nz, .print_level
+ dec hl
+.print_level
+ ld a, [wEnemyMonLevel]
+ ld [wTempMonLevel], a
+ call PrintLevel
+.skip_level
+
+ ld hl, wEnemyMonHP
+ ld a, [hli]
+ ldh [hMultiplicand + 1], a
+ ld a, [hld]
+ ldh [hMultiplicand + 2], a
+ or [hl]
+ jr nz, .not_fainted
+
+ ld c, a
+ ld e, a
+ ld d, HP_BAR_LENGTH
+ jp .draw_bar
+
+.not_fainted
+ xor a
+ ldh [hMultiplicand + 0], a
+ ld a, HP_BAR_LENGTH_PX
+ ldh [hMultiplier], a
+ call Multiply
+ ld hl, wEnemyMonMaxHP
+ ld a, [hli]
+ ld b, a
+ ld a, [hl]
+ ldh [hMultiplier], a
+ ld a, b
+ and a
+ jr z, .less_than_256_max
+ ldh a, [hMultiplier]
+ srl b
+ rr a
+ srl b
+ rr a
+ ldh [hDivisor], a
+ ldh a, [hProduct + 2]
+ ld b, a
+ srl b
+ ldh a, [hProduct + 3]
+ rr a
+ srl b
+ rr a
+ ldh [hProduct + 3], a
+ ld a, b
+ ldh [hProduct + 2], a
+
+.less_than_256_max
+ ldh a, [hProduct + 2]
+ ldh [hDividend + 0], a
+ ldh a, [hProduct + 3]
+ ldh [hDividend + 1], a
+ ld a, 2
+ ld b, a
+ call Divide
+ ldh a, [hQuotient + 3]
+ ld e, a
+ ld a, HP_BAR_LENGTH
+ ld d, a
+ ld c, a
+
+.draw_bar
+ xor a
+ ld [wWhichHPBar], a
+ hlcoord 2, 2
+ ld b, 0
+ call DrawBattleHPBar
+ ret
+
+UpdateEnemyHPPal:
+ ld hl, wEnemyHPPal
+ call UpdateHPPal
+ ret
+
+UpdateHPPal:
+ ld b, [hl]
+ call SetHPPal
+ ld a, [hl]
+ cp b
+ ret z
+ jp FinishBattleAnim
+
+ret_3df99:
+ ret
+
+BattleMenu:
+ xor a
+ ldh [hBGMapMode], a
+ call LoadTempTilemapToTilemap
+
+ ld a, [wBattleType]
+ cp BATTLETYPE_DEBUG
+ jr z, .ok
+ cp BATTLETYPE_TUTORIAL
+ jr z, .ok
+ call UpdateBattleHuds
+ call EmptyBattleTextbox
+ call LoadTilemapToTempTilemap
+.ok
+
+.loop
+ ld a, [wBattleType]
+ cp BATTLETYPE_CONTEST
+ jr nz, .not_contest
+ callfar ContestBattleMenu
+ jr .next
+.not_contest
+
+ ; Auto input: choose "ITEM"
+ ld a, [wInputType]
+ or a
+ jr z, .skip_dude_pack_select
+ farcall _DudeAutoInput_DownA
+.skip_dude_pack_select
+ callfar LoadBattleMenu
+
+.next
+ ld a, $1
+ ldh [hBGMapMode], a
+ ld a, [wBattleMenuCursorBuffer]
+ cp $1
+ jp z, BattleMenu_Fight
+ cp $3
+ jp z, BattleMenu_Pack
+ cp $2
+ jp z, BattleMenu_PKMN
+ cp $4
+ jp z, BattleMenu_Run
+ jr .loop
+
+BattleMenu_Fight:
+ xor a
+ ld [wNumFleeAttempts], a
+ call SafeLoadTempTilemapToTilemap
+ and a
+ ret
+
+BattleMenu_Pack:
+ ld a, [wLinkMode]
+ and a
+ jp nz, .ItemsCantBeUsed
+
+ call LoadStandardMenuHeader
+
+ ld a, [wBattleType]
+ cp BATTLETYPE_TUTORIAL
+ jr z, .tutorial
+ cp BATTLETYPE_CONTEST
+ jr z, .contest
+
+ farcall BattlePack
+ ld a, [wBattlePlayerAction]
+ and a ; BATTLEPLAYERACTION_USEMOVE?
+ jr z, .didnt_use_item
+ jr .got_item
+
+.tutorial
+ farcall TutorialPack
+ ld a, POKE_BALL
+ ld [wCurItem], a
+ call DoItemEffect
+ jr .got_item
+
+.contest
+ ld a, PARK_BALL
+ ld [wCurItem], a
+ call DoItemEffect
+
+.got_item
+ call .UseItem
+ ret
+
+.didnt_use_item
+ call ClearPalettes
+ call DelayFrame
+ call _LoadBattleFontsHPBar
+ call GetBattleMonBackpic
+ call GetEnemyMonFrontpic
+ call ExitMenu
+ call WaitBGMap
+ call FinishBattleAnim
+ call LoadTilemapToTempTilemap
+ jp BattleMenu
+
+.ItemsCantBeUsed:
+ ld hl, BattleText_ItemsCantBeUsedHere
+ call StdBattleTextbox
+ jp BattleMenu
+
+.UseItem:
+ ld a, [wWildMon]
+ and a
+ jr nz, .run
+ callfar CheckItemPocket
+ ld a, [wItemAttributeParamBuffer]
+ cp BALL
+ jr z, .ball
+ call ClearBGPalettes
+
+.ball
+ xor a
+ ldh [hBGMapMode], a
+ call _LoadBattleFontsHPBar
+ call ClearSprites
+ ld a, [wBattleType]
+ cp BATTLETYPE_TUTORIAL
+ jr z, .tutorial2
+ call GetBattleMonBackpic
+
+.tutorial2
+ call GetEnemyMonFrontpic
+ ld a, $1
+ ld [wMenuCursorY], a
+ call ExitMenu
+ call UpdateBattleHUDs
+ call WaitBGMap
+ call LoadTilemapToTempTilemap
+ call ClearWindowData
+ call FinishBattleAnim
+ and a
+ ret
+
+.run
+ xor a
+ ld [wWildMon], a
+ ld a, [wBattleResult]
+ and BATTLERESULT_BITMASK
+ ld [wBattleResult], a ; WIN
+ call ClearWindowData
+ call SetPalettes
+ scf
+ ret
+
+BattleMenu_PKMN:
+ call LoadStandardMenuHeader
+BattleMenuPKMN_ReturnFromStats:
+ call ExitMenu
+ call LoadStandardMenuHeader
+ call ClearBGPalettes
+BattleMenuPKMN_Loop:
+ farcall LoadPartyMenuGFX
+ farcall InitPartyMenuWithCancel
+ farcall InitPartyMenuGFX
+ xor a
+ ld [wPartyMenuActionText], a
+ farcall WritePartyMenuTilemap
+ farcall PrintPartyMenuText
+ call WaitBGMap
+ call SetPalettes
+ call DelayFrame
+ farcall PartyMenuSelect
+ jr c, .Cancel
+.loop
+ callfar FreezeMonIcons
+ callfar BattleMonMenu
+ jr c, BattleMenuPKMN_Loop
+ call PlaceHollowCursor
+ ld a, [wMenuCursorY]
+ cp $1 ; SWITCH
+ jp z, TryPlayerSwitch
+ cp $2 ; STATS
+ jr z, .Stats
+ cp $3 ; CANCEL
+ jr z, .Cancel
+ jr .loop
+
+.Stats:
+ call Battle_StatsScreen
+ jp BattleMenuPKMN_ReturnFromStats
+
+.Cancel:
+ call ClearSprites
+ call ClearPalettes
+ call DelayFrame
+ call _LoadHPBar
+ call CloseWindow
+ call LoadTilemapToTempTilemap
+ call GetMemSGBLayout
+ call SetPalettes
+ jp BattleMenu
+
+Battle_StatsScreen:
+ call DisableLCD
+
+ ld hl, vTiles2 tile $31
+ ld de, vTiles0
+ ld bc, $11 tiles
+ call CopyBytes
+
+ ld hl, vTiles2
+ ld de, vTiles0 tile $11
+ ld bc, $31 tiles
+ call CopyBytes
+
+ call EnableLCD
+
+ call ClearSprites
+ call LowVolume
+ xor a ; PARTYMON
+ ld [wMonType], a
+ ld hl, wPartyMons
+ predef StatsScreenInit
+ call MaxVolume
+
+ call DisableLCD
+
+ ld hl, vTiles0
+ ld de, vTiles2 tile $31
+ ld bc, $11 tiles
+ call CopyBytes
+
+ ld hl, vTiles0 tile $11
+ ld de, vTiles2
+ ld bc, $31 tiles
+ call CopyBytes
+
+ call EnableLCD
+ ret
+
+TryPlayerSwitch:
+ ld a, [wCurBattleMon]
+ ld d, a
+ ld a, [wCurPartyMon]
+ cp d
+ jr nz, .check_trapped
+ ld hl, BattleText_MonIsAlreadyOut
+ call StdBattleTextbox
+ jp BattleMenuPKMN_Loop
+
+.check_trapped
+ ld a, [wPlayerWrapCount]
+ and a
+ jr nz, .trapped
+ ld a, [wEnemySubStatus5]
+ bit SUBSTATUS_CANT_RUN, a
+ jr z, .try_switch
+
+.trapped
+ ld hl, BattleText_MonCantBeRecalled
+ call StdBattleTextbox
+ jp BattleMenuPKMN_Loop
+
+.try_switch
+ call CheckIfCurPartyMonIsFitToFight
+ jp z, BattleMenuPKMN_Loop
+ ld a, [wCurBattleMon]
+ ld [wLastPlayerMon], a
+ ld a, BATTLEPLAYERACTION_SWITCH
+ ld [wBattlePlayerAction], a
+ call ClearPalettes
+ call DelayFrame
+ call ClearSprites
+ call _LoadHPBar
+ call CloseWindow
+ call GetMemSGBLayout
+ call SetPalettes
+ ld a, [wCurPartyMon]
+ ld [wCurBattleMon], a
+PlayerSwitch:
+ ld a, 1
+ ld [wPlayerIsSwitching], a
+ ld a, [wLinkMode]
+ and a
+ jr z, .not_linked
+ call LoadStandardMenuHeader
+ call LinkBattleSendReceiveAction
+ call CloseWindow
+
+.not_linked
+ call ParseEnemyAction
+ ld a, [wLinkMode]
+ and a
+ jr nz, .linked
+
+.switch
+ call BattleMonEntrance
+ and a
+ ret
+
+.linked
+ ld a, [wBattleAction]
+ cp BATTLEACTION_STRUGGLE
+ jp z, .switch
+ cp BATTLEACTION_SKIPTURN
+ jp z, .switch
+ cp BATTLEACTION_SWITCH1
+ jp c, .switch
+ cp BATTLEACTION_FORFEIT
+ jr nz, .dont_run
+ call WildFled_EnemyFled_LinkBattleCanceled
+ ret
+
+.dont_run
+ ldh a, [hSerialConnectionStatus]
+ cp USING_EXTERNAL_CLOCK
+ jr z, .player_1
+ call BattleMonEntrance
+ call EnemyMonEntrance
+ and a
+ ret
+
+.player_1
+ call EnemyMonEntrance
+ call BattleMonEntrance
+ and a
+ ret
+
+EnemyMonEntrance:
+ callfar AI_Switch
+ call SetEnemyTurn
+ jp SpikesDamage
+
+BattleMonEntrance:
+ call WithdrawMonText
+
+ ld c, 50
+ call DelayFrames
+
+ ld hl, wPlayerSubStatus4
+ res SUBSTATUS_RAGE, [hl]
+
+ call SetEnemyTurn
+ call PursuitSwitch
+ jr c, .ok
+ call RecallPlayerMon
+.ok
+
+ hlcoord 9, 7
+ lb bc, 5, 11
+ call ClearBox
+
+ ld a, [wCurBattleMon]
+ ld [wCurPartyMon], a
+ call AddBattleParticipant
+ call InitBattleMon
+ call ResetPlayerStatLevels
+ call SendOutMonText
+ call NewBattleMonStatus
+ call BreakAttraction
+ call SendOutPlayerMon
+ call EmptyBattleTextbox
+ call LoadTilemapToTempTilemap
+ call SetPlayerTurn
+ call SpikesDamage
+ ld a, $2
+ ld [wMenuCursorY], a
+ ret
+
+PassedBattleMonEntrance:
+ ld c, 50
+ call DelayFrames
+
+ hlcoord 9, 7
+ lb bc, 5, 11
+ call ClearBox
+
+ ld a, [wCurPartyMon]
+ ld [wCurBattleMon], a
+ call AddBattleParticipant
+ call InitBattleMon
+ xor a ; FALSE
+ ld [wApplyStatLevelMultipliersToEnemy], a
+ call ApplyStatLevelMultiplierOnAllStats
+ call SendOutPlayerMon
+ call EmptyBattleTextbox
+ call LoadTilemapToTempTilemap
+ call SetPlayerTurn
+ jp SpikesDamage
+
+BattleMenu_Run:
+ call SafeLoadTempTilemapToTilemap
+ ld a, $3
+ ld [wMenuCursorY], a
+ ld hl, wBattleMonSpeed
+ ld de, wEnemyMonSpeed
+ call TryToRunAwayFromBattle
+ ld a, FALSE
+ ld [wFailedToFlee], a
+ ret c
+ ld a, [wBattlePlayerAction]
+ and a ; BATTLEPLAYERACTION_USEMOVE?
+ ret nz
+ jp BattleMenu
+
+CheckAmuletCoin:
+ ld a, [wBattleMonItem]
+ ld b, a
+ callfar GetItemHeldEffect
+ ld a, b
+ cp HELD_AMULET_COIN
+ ret nz
+ ld a, 1
+ ld [wAmuletCoin], a
+ ret
+
+MoveSelectionScreen:
+ ld hl, wEnemyMonMoves
+ ld a, [wMoveSelectionMenuType]
+ dec a
+ jr z, .got_menu_type
+ dec a
+ jr z, .ether_elixer_menu
+ call .CheckPlayerHasUsableMoves
+ ret z ; use Struggle
+ ld hl, wBattleMonMoves
+ jr .got_menu_type
+
+.ether_elixer_menu
+ ld a, MON_MOVES
+ call GetPartyParamLocation
+
+.got_menu_type
+ ld de, wListMoves_MoveIndicesBuffer
+ ld bc, NUM_MOVES
+ call CopyBytes
+ xor a
+ ldh [hBGMapMode], a
+
+ hlcoord 4, 17 - NUM_MOVES - 1
+ ld b, 4
+ ld c, 14
+ ld a, [wMoveSelectionMenuType]
+ cp $2
+ jr nz, .got_dims
+ hlcoord 4, 17 - NUM_MOVES - 1 - 4
+ ld b, 4
+ ld c, 14
+.got_dims
+ call Textbox
+
+ hlcoord 6, 17 - NUM_MOVES
+ ld a, [wMoveSelectionMenuType]
+ cp $2
+ jr nz, .got_start_coord
+ hlcoord 6, 17 - NUM_MOVES - 4
+.got_start_coord
+ ld a, SCREEN_WIDTH
+ ld [wBuffer1], a
+ predef ListMoves
+
+ ld b, 5
+ ld a, [wMoveSelectionMenuType]
+ cp $2
+ ld a, 17 - NUM_MOVES
+ jr nz, .got_default_coord
+ ld b, 5
+ ld a, 17 - NUM_MOVES - 4
+
+.got_default_coord
+ ld [w2DMenuCursorInitY], a
+ ld a, b
+ ld [w2DMenuCursorInitX], a
+ ld a, [wMoveSelectionMenuType]
+ cp $1
+ jr z, .skip_inc
+ ld a, [wCurMoveNum]
+ inc a
+
+.skip_inc
+ ld [wMenuCursorY], a
+ ld a, 1
+ ld [wMenuCursorX], a
+ ld a, [wNumMoves]
+ inc a
+ ld [w2DMenuNumRows], a
+ ld a, 1
+ ld [w2DMenuNumCols], a
+ ld c, STATICMENU_ENABLE_LEFT_RIGHT | STATICMENU_ENABLE_START | STATICMENU_WRAP
+ ld a, [wMoveSelectionMenuType]
+ dec a
+ ld b, D_DOWN | D_UP | A_BUTTON
+ jr z, .okay
+ dec a
+ ld b, D_DOWN | D_UP | A_BUTTON | B_BUTTON
+ jr z, .okay
+ ld a, [wLinkMode]
+ cp LINK_COLOSSEUM
+ jr z, .okay
+ ld b, D_DOWN | D_UP | A_BUTTON | B_BUTTON | SELECT
+
+.okay
+ ld a, b
+ ld [wMenuJoypadFilter], a
+ ld a, c
+ ld [w2DMenuFlags1], a
+ xor a
+ ld [w2DMenuFlags2], a
+ ld a, $10
+ ld [w2DMenuCursorOffsets], a
+.menu_loop
+ ld a, [wMoveSelectionMenuType]
+ and a
+ jr z, .battle_player_moves
+ dec a
+ jr nz, .interpret_joypad
+ hlcoord 11, 14
+ ld de, .string_3e448
+ call PlaceString
+ jr .interpret_joypad
+
+.battle_player_moves
+ call MoveInfoBox
+ ld a, [wMoveSwapBuffer]
+ and a
+ jr z, .interpret_joypad
+ hlcoord 5, 13
+ ld bc, SCREEN_WIDTH
+ dec a
+ call AddNTimes
+ ld [hl], "▷"
+
+.interpret_joypad
+ ld a, $1
+ ldh [hBGMapMode], a
+ call ScrollingMenuJoypad
+ bit D_UP_F, a
+ jp nz, .pressed_up
+ bit D_DOWN_F, a
+ jp nz, .pressed_down
+ bit SELECT_F, a
+ jp nz, .pressed_select
+ bit B_BUTTON_F, a
+ ; A button
+ push af
+
+ xor a
+ ld [wMoveSwapBuffer], a
+ ld a, [wMenuCursorY]
+ dec a
+ ld [wMenuCursorY], a
+ ld b, a
+ ld a, [wMoveSelectionMenuType]
+ dec a
+ jr nz, .not_enemy_moves_process_b
+
+ pop af
+ ret
+
+.not_enemy_moves_process_b
+ dec a
+ ld a, b
+ ld [wCurMoveNum], a
+ jr nz, .use_move
+
+ pop af
+ ret
+
+.use_move
+ pop af
+ ret nz
+
+ ld hl, wBattleMonPP
+ ld a, [wMenuCursorY]
+ ld c, a
+ ld b, 0
+ add hl, bc
+ ld a, [hl]
+ and PP_MASK
+ jr z, .no_pp_left
+ ld a, [wPlayerDisableCount]
+ swap a
+ and $f
+ dec a
+ cp c
+ jr z, .move_disabled
+ ld a, [wUnusedPlayerLockedMove]
+ and a
+ jr nz, .skip2
+ ld a, [wMenuCursorY]
+ ld hl, wBattleMonMoves
+ ld c, a
+ ld b, 0
+ add hl, bc
+ ld a, [hl]
+
+.skip2
+ ld [wCurPlayerMove], a
+ xor a
+ ret
+
+.move_disabled
+ ld hl, BattleText_TheMoveIsDisabled
+ jr .place_textbox_start_over
+
+.no_pp_left
+ ld hl, BattleText_TheresNoPPLeftForThisMove
+
+.place_textbox_start_over
+ call StdBattleTextbox
+ call SafeLoadTempTilemapToTilemap
+ jp MoveSelectionScreen
+
+.string_3e448
+ db "@"
+
+.pressed_up
+ ld a, [wMenuCursorY]
+ and a
+ jp nz, .menu_loop
+ ld a, [wNumMoves]
+ inc a
+ ld [wMenuCursorY], a
+ jp .menu_loop
+
+.pressed_down
+ ld a, [wMenuCursorY]
+ ld b, a
+ ld a, [wNumMoves]
+ inc a
+ inc a
+ cp b
+ jp nz, .menu_loop
+ ld a, $1
+ ld [wMenuCursorY], a
+ jp .menu_loop
+
+.CheckPlayerHasUsableMoves:
+ ld a, STRUGGLE
+ ld [wCurPlayerMove], a
+ ld a, [wPlayerDisableCount]
+ and a
+ ld hl, wBattleMonPP
+ jr nz, .disabled
+
+ ld a, [hli]
+ or [hl]
+ inc hl
+ or [hl]
+ inc hl
+ or [hl]
+ and PP_MASK
+ ret nz
+ jr .force_struggle
+
+.disabled
+ swap a
+ and $f
+ ld b, a
+ ld d, NUM_MOVES + 1
+ xor a
+.loop
+ dec d
+ jr z, .done
+ ld c, [hl]
+ inc hl
+ dec b
+ jr z, .loop
+ or c
+ jr .loop
+
+.done
+ ; Bug: this will result in a move with PP Up confusing the game.
+ and a ; should be "and PP_MASK"
+ ret nz
+
+.force_struggle
+ ld hl, BattleText_MonHasNoMovesLeft
+ call StdBattleTextbox
+ ld c, 60
+ call DelayFrames
+ xor a
+ ret
+
+.pressed_select
+ ld a, [wMoveSwapBuffer]
+ and a
+ jr z, .start_swap
+ ld hl, wBattleMonMoves
+ call .swap_bytes
+ ld hl, wBattleMonPP
+ call .swap_bytes
+ ld hl, wPlayerDisableCount
+ ld a, [hl]
+ swap a
+ and $f
+ ld b, a
+ ld a, [wMenuCursorY]
+ cp b
+ jr nz, .not_swapping_disabled_move
+ ld a, [hl]
+ and $f
+ ld b, a
+ ld a, [wMoveSwapBuffer]
+ swap a
+ add b
+ ld [hl], a
+ jr .swap_moves_in_party_struct
+
+.not_swapping_disabled_move
+ ld a, [wMoveSwapBuffer]
+ cp b
+ jr nz, .swap_moves_in_party_struct
+ ld a, [hl]
+ and $f
+ ld b, a
+ ld a, [wMenuCursorY]
+ swap a
+ add b
+ ld [hl], a
+
+.swap_moves_in_party_struct
+; Fixes the COOLTRAINER glitch
+ ld a, [wPlayerSubStatus5]
+ bit SUBSTATUS_TRANSFORMED, a
+ jr nz, .transformed
+ ld hl, wPartyMon1Moves
+ ld a, [wCurBattleMon]
+ call GetPartyLocation
+ push hl
+ call .swap_bytes
+ pop hl
+ ld bc, MON_PP - MON_MOVES
+ add hl, bc
+ call .swap_bytes
+
+.transformed
+ xor a
+ ld [wMoveSwapBuffer], a
+ jp MoveSelectionScreen
+
+.swap_bytes
+ push hl
+ ld a, [wMoveSwapBuffer]
+ dec a
+ ld c, a
+ ld b, 0
+ add hl, bc
+ ld d, h
+ ld e, l
+ pop hl
+ ld a, [wMenuCursorY]
+ dec a
+ ld c, a
+ ld b, 0
+ add hl, bc
+ ld a, [de]
+ ld b, [hl]
+ ld [hl], a
+ ld a, b
+ ld [de], a
+ ret
+
+.start_swap
+ ld a, [wMenuCursorY]
+ ld [wMoveSwapBuffer], a
+ jp MoveSelectionScreen
+
+MoveInfoBox:
+ xor a
+ ldh [hBGMapMode], a
+
+ hlcoord 0, 8
+ ld b, 3
+ ld c, 9
+ call Textbox
+
+ ld a, [wPlayerDisableCount]
+ and a
+ jr z, .not_disabled
+
+ swap a
+ and $f
+ ld b, a
+ ld a, [wMenuCursorY]
+ cp b
+ jr nz, .not_disabled
+
+ hlcoord 1, 10
+ ld de, .Disabled
+ call PlaceString
+ jr .done
+
+.not_disabled
+ ld hl, wMenuCursorY
+ dec [hl]
+ call SetPlayerTurn
+ ld hl, wBattleMonMoves
+ ld a, [wMenuCursorY]
+ ld c, a
+ ld b, 0
+ add hl, bc
+ ld a, [hl]
+ ld [wCurPlayerMove], a
+
+ ld a, [wCurBattleMon]
+ ld [wCurPartyMon], a
+ ld a, WILDMON
+ ld [wMonType], a
+ callfar GetMaxPPOfMove
+
+ ld hl, wMenuCursorY
+ ld c, [hl]
+ inc [hl]
+ ld b, 0
+ ld hl, wBattleMonPP
+ add hl, bc
+ ld a, [hl]
+ and PP_MASK
+ ld [wStringBuffer1], a
+ hlcoord 1, 9
+ ld de, .Type
+ call PlaceString
+
+ hlcoord 7, 11
+ ld [hl], "/"
+ hlcoord 5, 11
+ ld de, wStringBuffer1
+ lb bc, 1, 2
+ call PrintNum
+
+ hlcoord 8, 11
+ ld de, wNamedObjectIndexBuffer
+ lb bc, 1, 2
+ call PrintNum
+
+ callfar UpdateMoveData
+ ld a, [wPlayerMoveStruct + MOVE_ANIM]
+ ld b, a
+ hlcoord 2, 10
+ predef PrintMoveType
+
+.done
+ ret
+
+.Disabled:
+ db "Disabled!@"
+.Type:
+ db "TYPE/@"
+
+ParseEnemyAction:
+ ld a, [wEnemyIsSwitching]
+ and a
+ ret nz
+ ld a, [wLinkMode]
+ and a
+ jr z, .not_linked
+ call EmptyBattleTextbox
+ call LoadTilemapToTempTilemap
+ ld a, [wBattlePlayerAction]
+ and a ; BATTLEPLAYERACTION_USEMOVE?
+ call z, LinkBattleSendReceiveAction
+ call SafeLoadTempTilemapToTilemap
+ ld a, [wBattleAction]
+ cp BATTLEACTION_STRUGGLE
+ jp z, .struggle
+ cp BATTLEACTION_SKIPTURN
+ jp z, .skip_turn
+ cp BATTLEACTION_SWITCH1
+ jp nc, ResetVarsForSubstatusRage
+ ld [wCurEnemyMoveNum], a
+ ld c, a
+ ld a, [wEnemySubStatus1]
+ bit SUBSTATUS_ROLLOUT, a
+ jp nz, .skip_load
+ ld a, [wEnemySubStatus3]
+ and 1 << SUBSTATUS_CHARGED | 1 << SUBSTATUS_RAMPAGE | 1 << SUBSTATUS_BIDE
+ jp nz, .skip_load
+
+ ld hl, wEnemySubStatus5
+ bit SUBSTATUS_ENCORED, [hl]
+ ld a, [wLastEnemyMove]
+ jp nz, .finish
+ ld hl, wEnemyMonMoves
+ ld b, 0
+ add hl, bc
+ ld a, [hl]
+ jp .finish
+
+.not_linked
+ ld hl, wEnemySubStatus5
+ bit SUBSTATUS_ENCORED, [hl]
+ jr z, .skip_encore
+ ld a, [wLastEnemyMove]
+ jp .finish
+
+.skip_encore
+ call CheckEnemyLockedIn
+ jp nz, ResetVarsForSubstatusRage
+ jr .continue
+
+.skip_turn
+ ld a, $ff
+ jr .finish
+
+.continue
+ ld hl, wEnemyMonMoves
+ ld de, wEnemyMonPP
+ ld b, NUM_MOVES
+.loop
+ ld a, [hl]
+ and a
+ jp z, .struggle
+ ld a, [wEnemyDisabledMove]
+ cp [hl]
+ jr z, .disabled
+ ld a, [de]
+ and PP_MASK
+ jr nz, .enough_pp
+
+.disabled
+ inc hl
+ inc de
+ dec b
+ jr nz, .loop
+ jr .struggle
+
+.enough_pp
+ ld a, [wBattleMode]
+ dec a
+ jr nz, .skip_load
+; wild
+.loop2
+ ld hl, wEnemyMonMoves
+ call BattleRandom
+ maskbits NUM_MOVES
+ ld c, a
+ ld b, 0
+ add hl, bc
+ ld a, [wEnemyDisableCount]
+ swap a
+ and $f
+ dec a
+ cp c
+ jr z, .loop2
+ ld a, [hl]
+ and a
+ jr z, .loop2
+ ld hl, wEnemyMonPP
+ add hl, bc
+ ld b, a
+ ld a, [hl]
+ and PP_MASK
+ jr z, .loop2
+ ld a, c
+ ld [wCurEnemyMoveNum], a
+ ld a, b
+
+.finish
+ ld [wCurEnemyMove], a
+
+.skip_load
+ call SetEnemyTurn
+ callfar UpdateMoveData
+ call CheckEnemyLockedIn
+ jr nz, .raging
+ xor a
+ ld [wEnemyCharging], a
+
+.raging
+ ld a, [wEnemyMoveStruct + MOVE_EFFECT]
+ cp EFFECT_FURY_CUTTER
+ jr z, .fury_cutter
+ xor a
+ ld [wEnemyFuryCutterCount], a
+
+.fury_cutter
+ ld a, [wEnemyMoveStruct + MOVE_EFFECT]
+ cp EFFECT_RAGE
+ jr z, .no_rage
+ ld hl, wEnemySubStatus4
+ res SUBSTATUS_RAGE, [hl]
+ xor a
+ ld [wEnemyRageCounter], a
+
+.no_rage
+ ld a, [wEnemyMoveStruct + MOVE_EFFECT]
+ cp EFFECT_PROTECT
+ ret z
+ cp EFFECT_ENDURE
+ ret z
+ xor a
+ ld [wEnemyProtectCount], a
+ ret
+
+.struggle
+ ld a, STRUGGLE
+ jr .finish
+
+ResetVarsForSubstatusRage:
+ xor a
+ ld [wEnemyFuryCutterCount], a
+ ld [wEnemyProtectCount], a
+ ld [wEnemyRageCounter], a
+ ld hl, wEnemySubStatus4
+ res SUBSTATUS_RAGE, [hl]
+ ret
+
+CheckEnemyLockedIn:
+ ld a, [wEnemySubStatus4]
+ and 1 << SUBSTATUS_RECHARGE
+ ret nz
+
+ ld hl, wEnemySubStatus3
+ ld a, [hl]
+ and 1 << SUBSTATUS_CHARGED | 1 << SUBSTATUS_RAMPAGE | 1 << SUBSTATUS_BIDE
+ ret nz
+
+ ld hl, wEnemySubStatus1
+ bit SUBSTATUS_ROLLOUT, [hl]
+ ret
+
+LinkBattleSendReceiveAction:
+ ld a, $ff
+ ld [wOtherPlayerLinkAction], a
+ ld a, [wBattlePlayerAction]
+ and a ; BATTLEPLAYERACTION_USEMOVE?
+ jr nz, .switch
+ ld a, [wCurPlayerMove]
+ cp STRUGGLE
+ ld b, BATTLEACTION_STRUGGLE
+ jr z, .struggle
+ dec b
+ inc a
+ jr z, .struggle
+ ld a, [wCurMoveNum]
+ jr .use_move
+
+.switch
+ ld a, [wCurPartyMon]
+ add BATTLEACTION_SWITCH1
+ ld b, a
+
+.struggle
+ ld a, b
+
+.use_move
+ ld [wPlayerLinkAction], a
+ callfar PlaceWaitingText
+
+.waiting
+ call LinkTransfer
+ call DelayFrame
+ ld a, [wOtherPlayerLinkAction]
+ inc a
+ jr z, .waiting
+
+ ld b, 10
+.receive
+ call DelayFrame
+ call LinkTransfer
+ dec b
+ jr nz, .receive
+
+ ld b, 10
+.acknowledge
+ call DelayFrame
+ call LinkDataReceived
+ dec b
+ jr nz, .acknowledge
+
+ ret
+
+LoadEnemyMon:
+; Initialize enemy monster parameters
+; To do this we pull the species from wTempEnemyMonSpecies
+
+; Notes:
+; BattleRandom is used to ensure sync between Game Boys
+
+; Clear the whole enemy mon struct (wEnemyMon)
+ xor a
+ ld hl, wEnemyMonSpecies
+ ld bc, wEnemyMonEnd - wEnemyMon
+ call ByteFill
+
+; We don't need to be here if we're in a link battle
+ ld a, [wLinkMode]
+ and a
+ jp nz, InitEnemyMon
+
+; Make sure everything knows what species we're working with
+ ld a, [wTempEnemyMonSpecies]
+ ld [wEnemyMonSpecies], a
+ ld [wCurSpecies], a
+ ld [wCurPartySpecies], a
+
+; Grab the BaseData for this species
+ call GetBaseData
+
+; Let's get the item:
+
+; Is the item predetermined?
+ ld a, [wBattleMode]
+ dec a
+ jr z, .WildItem
+
+; If we're in a trainer battle, the item is in the party struct
+ ld a, [wCurPartyMon]
+ ld hl, wOTPartyMon1Item
+ call GetPartyLocation ; bc = PartyMon[wCurPartyMon] - wPartyMons
+ ld a, [hl]
+ jr .UpdateItem
+
+.WildItem:
+; In a wild battle, we pull from the item slots in BaseData
+
+; Force Item1
+; Used for Ho-Oh, Lugia and Snorlax encounters
+ ld a, [wBattleType]
+ cp BATTLETYPE_FORCEITEM
+ ld a, [wBaseItem1]
+ jr z, .UpdateItem
+
+; Failing that, it's all up to chance
+; Effective chances:
+; 75% None
+; 23% Item1
+; 2% Item2
+
+; 25% chance of getting an item
+ call BattleRandom
+ cp 75 percent + 1
+ ld a, NO_ITEM
+ jr c, .UpdateItem
+
+; From there, an 8% chance for Item2
+ call BattleRandom
+ cp 8 percent ; 8% of 25% = 2% Item2
+ ld a, [wBaseItem1]
+ jr nc, .UpdateItem
+ ld a, [wBaseItem2]
+
+.UpdateItem:
+ ld [wEnemyMonItem], a
+
+; Initialize DVs
+
+; If we're in a trainer battle, DVs are predetermined
+ ld a, [wBattleMode]
+ and a
+ jr z, .InitDVs
+
+ ld a, [wEnemySubStatus5]
+ bit SUBSTATUS_TRANSFORMED, a
+ jr z, .InitDVs
+
+; Unknown
+ ld hl, wEnemyBackupDVs
+ ld de, wEnemyMonDVs
+ ld a, [hli]
+ ld [de], a
+ inc de
+ ld a, [hl]
+ ld [de], a
+ jp .Happiness
+
+.InitDVs:
+; Trainer DVs
+
+; All trainers have preset DVs, determined by class
+; See GetTrainerDVs for more on that
+ farcall GetTrainerDVs
+; These are the DVs we'll use if we're actually in a trainer battle
+ ld a, [wBattleMode]
+ dec a
+ jr nz, .UpdateDVs
+
+; Wild DVs
+; Here's where the fun starts
+
+; Roaming monsters (Entei, Raikou, Suicune) work differently
+; They have their own structs, which are shorter than normal
+ ld a, [wBattleType]
+ cp BATTLETYPE_ROAMING
+ jr nz, .NotRoaming
+
+; Grab HP
+ call GetRoamMonHP
+ ld a, [hl]
+; Check if the HP has been initialized
+ and a
+; We'll do something with the result in a minute
+ push af
+
+; Grab DVs
+ call GetRoamMonDVs
+ inc hl
+ ld a, [hld]
+ ld c, a
+ ld b, [hl]
+
+; Get back the result of our check
+ pop af
+; If the RoamMon struct has already been initialized, we're done
+ jr nz, .UpdateDVs
+
+; If it hasn't, we need to initialize the DVs
+; (HP is initialized at the end of the battle)
+ call GetRoamMonDVs
+ inc hl
+ call BattleRandom
+ ld [hld], a
+ ld c, a
+ call BattleRandom
+ ld [hl], a
+ ld b, a
+; We're done with DVs
+ jr .UpdateDVs
+
+.NotRoaming:
+; Register a contains wBattleType
+
+; Forced shiny battle type
+; Used by Red Gyarados at Lake of Rage
+ cp BATTLETYPE_SHINY
+ jr nz, .GenerateDVs
+
+ ld b, ATKDEFDV_SHINY ; $ea
+ ld c, SPDSPCDV_SHINY ; $aa
+ jr .UpdateDVs
+
+.GenerateDVs:
+; Generate new random DVs
+ call BattleRandom
+ ld b, a
+ call BattleRandom
+ ld c, a
+
+.UpdateDVs:
+; Input DVs in register bc
+ ld hl, wEnemyMonDVs
+ ld a, b
+ ld [hli], a
+ ld [hl], c
+
+; We've still got more to do if we're dealing with a wild monster
+ ld a, [wBattleMode]
+ dec a
+ jr nz, .Happiness
+
+; Species-specfic:
+
+; Unown
+ ld a, [wTempEnemyMonSpecies]
+ cp UNOWN
+ jr nz, .Magikarp
+
+; Get letter based on DVs
+ ld hl, wEnemyMonDVs
+ predef GetUnownLetter
+; Can't use any letters that haven't been unlocked
+; If combined with forced shiny battletype, causes an infinite loop
+ call CheckUnownLetter
+ jr c, .GenerateDVs ; try again
+
+.Magikarp:
+; These filters are untranslated.
+; They expect at wMagikarpLength a 2-byte value in mm,
+; but the value is in feet and inches (one byte each).
+
+; The first filter is supposed to make very large Magikarp even rarer,
+; by targeting those 1600 mm (= 5'3") or larger.
+; After the conversion to feet, it is unable to target any,
+; since the largest possible Magikarp is 5'3", and $0503 = 1283 mm.
+ ld a, [wTempEnemyMonSpecies]
+ cp MAGIKARP
+ jr nz, .Happiness
+
+; Get Magikarp's length
+ ld de, wEnemyMonDVs
+ ld bc, wPlayerID
+ callfar CalcMagikarpLength
+
+; No reason to keep going if length > 1536 mm (i.e. if HIGH(length) > 6 feet)
+ ld a, [wMagikarpLength]
+ cp HIGH(1536) ; should be "cp 5", since 1536 mm = 5'0", but HIGH(1536) = 6
+ jr nz, .CheckMagikarpArea
+
+; 5% chance of skipping both size checks
+ call Random
+ cp 5 percent
+ jr c, .CheckMagikarpArea
+; Try again if length >= 1616 mm (i.e. if LOW(length) >= 4 inches)
+ ld a, [wMagikarpLength + 1]
+ cp LOW(1616) ; should be "cp 4", since 1616 mm = 5'4", but LOW(1616) = 80
+ jr nc, .GenerateDVs
+
+; 20% chance of skipping this check
+ call Random
+ cp 20 percent - 1
+ jr c, .CheckMagikarpArea
+; Try again if length >= 1600 mm (i.e. if LOW(length) >= 3 inches)
+ ld a, [wMagikarpLength + 1]
+ cp LOW(1600) ; should be "cp 3", since 1600 mm = 5'3", but LOW(1600) = 64
+ jr nc, .GenerateDVs
+
+.CheckMagikarpArea:
+; The "jr z" checks are supposed to be "jr nz".
+
+; Instead, all maps in GROUP_LAKE_OF_RAGE (Mahogany area)
+; and Routes 20 and 44 are treated as Lake of Rage.
+
+; This also means Lake of Rage Magikarp can be smaller than ones
+; caught elsewhere rather than the other way around.
+
+; Intended behavior enforces a minimum size at Lake of Rage.
+; The real behavior prevents a minimum size in the Lake of Rage area.
+
+; Moreover, due to the check not being translated to feet+inches, all Magikarp
+; smaller than 4'0" may be caught by the filter, a lot more than intended.
+ ld a, [wMapGroup]
+ cp GROUP_LAKE_OF_RAGE
+ jr z, .Happiness
+ ld a, [wMapNumber]
+ cp MAP_LAKE_OF_RAGE
+ jr z, .Happiness
+; 40% chance of not flooring
+ call Random
+ cp 40 percent - 2
+ jr c, .Happiness
+; Try again if length < 1024 mm (i.e. if HIGH(length) < 3 feet)
+ ld a, [wMagikarpLength]
+ cp HIGH(1024) ; should be "cp 3", since 1024 mm = 3'4", but HIGH(1024) = 4
+ jr c, .GenerateDVs ; try again
+
+; Finally done with DVs
+
+.Happiness:
+; Set happiness
+ ld a, BASE_HAPPINESS
+ ld [wEnemyMonHappiness], a
+; Set level
+ ld a, [wCurPartyLevel]
+ ld [wEnemyMonLevel], a
+; Fill stats
+ ld de, wEnemyMonMaxHP
+ ld b, FALSE
+ ld hl, wEnemyMonDVs - (MON_DVS - MON_STAT_EXP + 1)
+ predef CalcMonStats
+
+; If we're in a trainer battle,
+; get the rest of the parameters from the party struct
+ ld a, [wBattleMode]
+ cp TRAINER_BATTLE
+ jr z, .OpponentParty
+
+; If we're in a wild battle, check wild-specific stuff
+ and a
+ jr z, .TreeMon
+
+ ld a, [wEnemySubStatus5]
+ bit SUBSTATUS_TRANSFORMED, a
+ jr nz, .Moves
+
+.TreeMon:
+; If we're headbutting trees, some monsters enter battle asleep
+ ld a, [wTempEnemyMonSpecies]
+
+; Hoothoot/Noctowl are asleep if MORN/DAY
+ cp HOOTHOOT
+ jr z, .sleeping_if_not_nite
+ cp NOCTOWL
+ jr z, .sleeping_if_not_nite
+
+; Pidgey/Spearow are asleep if NITE
+ cp PIDGEY
+ jr z, .sleeping_if_nite
+ cp SPEAROW
+ jr z, .sleeping_if_nite
+
+; Other species are never asleep
+ jr .not_sleeping
+
+.sleeping_if_not_nite
+ ld a, [wTimeOfDay]
+ cp NITE_F
+ jr nz, .sleeping
+ jr .not_sleeping
+
+.sleeping_if_nite
+ ld a, [wTimeOfDay]
+ cp NITE_F
+ jr z, .sleeping
+ jr .not_sleeping
+
+.sleeping
+ ld a, TREEMON_SLEEP_TURNS
+ jr .UpdateStatus
+
+.not_sleeping
+ xor a
+
+.UpdateStatus:
+ ld hl, wEnemyMonStatus
+ ld [hli], a
+
+; Unused byte
+ xor a
+ ld [hli], a
+
+; Full HP..
+ ld a, [wEnemyMonMaxHP]
+ ld [hli], a
+ ld a, [wEnemyMonMaxHP + 1]
+ ld [hl], a
+
+; ..unless it's a RoamMon
+ ld a, [wBattleType]
+ cp BATTLETYPE_ROAMING
+ jr nz, .Moves
+
+; Grab HP
+ call GetRoamMonHP
+ ld a, [hl]
+; Check if it's been initialized again
+ and a
+ jr z, .InitRoamHP
+; Update from the struct if it has
+ ld a, [hl]
+ ld [wEnemyMonHP + 1], a
+ jr .Moves
+
+.InitRoamHP:
+; HP only uses the lo byte in the RoamMon struct since
+; Raikou and Entei will have < 256 hp at level 40
+ ld a, [wEnemyMonHP + 1]
+ ld [hl], a
+ jr .Moves
+
+.OpponentParty:
+; Get HP from the party struct
+ ld hl, (wOTPartyMon1HP + 1)
+ ld a, [wCurPartyMon]
+ call GetPartyLocation
+ ld a, [hld]
+ ld [wEnemyMonHP + 1], a
+ ld a, [hld]
+ ld [wEnemyMonHP], a
+
+; Make sure everything knows which monster the opponent is using
+ ld a, [wCurPartyMon]
+ ld [wCurOTMon], a
+
+; Get status from the party struct
+ dec hl
+ ld a, [hl] ; OTPartyMonStatus
+ ld [wEnemyMonStatus], a
+
+.Moves:
+ ld hl, wBaseType1
+ ld de, wEnemyMonType1
+ ld a, [hli]
+ ld [de], a
+ inc de
+ ld a, [hl]
+ ld [de], a
+
+; Get moves
+ ld de, wEnemyMonMoves
+; Are we in a trainer battle?
+ ld a, [wBattleMode]
+ cp TRAINER_BATTLE
+ jr nz, .WildMoves
+; Then copy moves from the party struct
+ ld hl, wOTPartyMon1Moves
+ ld a, [wCurPartyMon]
+ call GetPartyLocation
+ ld bc, NUM_MOVES
+ call CopyBytes
+ jr .PP
+
+.WildMoves:
+; Clear wEnemyMonMoves
+ xor a
+ ld h, d
+ ld l, e
+ ld [hli], a
+ ld [hli], a
+ ld [hli], a
+ ld [hl], a
+; Make sure the predef knows this isn't a partymon
+ ld [wEvolutionOldSpecies], a
+; Fill moves based on level
+ predef FillMoves
+
+.PP:
+; Trainer battle?
+ ld a, [wBattleMode]
+ cp TRAINER_BATTLE
+ jr z, .TrainerPP
+
+; Fill wild PP
+ ld hl, wEnemyMonMoves
+ ld de, wEnemyMonPP
+ predef FillPP
+ jr .Finish
+
+.TrainerPP:
+; Copy PP from the party struct
+ ld hl, wOTPartyMon1PP
+ ld a, [wCurPartyMon]
+ call GetPartyLocation
+ ld de, wEnemyMonPP
+ ld bc, NUM_MOVES
+ call CopyBytes
+
+.Finish:
+; Only the first five base stats are copied..
+ ld hl, wBaseStats
+ ld de, wEnemyMonBaseStats
+ ld b, wBaseSpecialDefense - wBaseStats
+.loop
+ ld a, [hli]
+ ld [de], a
+ inc de
+ dec b
+ jr nz, .loop
+
+ ld a, [wBaseCatchRate]
+ ld [de], a
+ inc de
+
+ ld a, [wBaseExp]
+ ld [de], a
+
+ ld a, [wTempEnemyMonSpecies]
+ ld [wNamedObjectIndexBuffer], a
+
+ call GetPokemonName
+
+; Did we catch it?
+ ld a, [wBattleMode]
+ and a
+ ret z
+
+; Update enemy nick
+ ld hl, wStringBuffer1
+ ld de, wEnemyMonNick
+ ld bc, MON_NAME_LENGTH
+ call CopyBytes
+
+; Saw this mon
+ ld a, [wTempEnemyMonSpecies]
+ dec a
+ ld c, a
+ ld b, SET_FLAG
+ ld hl, wPokedexSeen
+ predef SmallFarFlagAction
+
+ ld hl, wEnemyMonStats
+ ld de, wEnemyStats
+ ld bc, wEnemyMonStatsEnd - wEnemyMonStats
+ call CopyBytes
+
+ ret
+
+CheckUnownLetter:
+; Return carry if the Unown letter hasn't been unlocked yet
+
+ ld a, [wUnlockedUnowns]
+ ld c, a
+ ld de, 0
+
+.loop
+
+; Don't check this set unless it's been unlocked
+ srl c
+ jr nc, .next
+
+; Is our letter in the set?
+ ld hl, UnlockedUnownLetterSets
+ add hl, de
+ ld a, [hli]
+ ld h, [hl]
+ ld l, a
+
+ push de
+ ld a, [wUnownLetter]
+ ld de, 1
+ push bc
+ call IsInArray
+ pop bc
+ pop de
+
+ jr c, .match
+
+.next
+; Make sure we haven't gone past the end of the table
+ inc e
+ inc e
+ ld a, e
+ cp UnlockedUnownLetterSets.End - UnlockedUnownLetterSets
+ jr c, .loop
+
+; Hasn't been unlocked, or the letter is invalid
+ scf
+ ret
+
+.match
+; Valid letter
+ and a
+ ret
+
+INCLUDE "data/wild/unlocked_unowns.asm"
+
+Unreferenced_SwapBattlerLevels:
+ push bc
+ ld a, [wBattleMonLevel]
+ ld b, a
+ ld a, [wEnemyMonLevel]
+ ld [wBattleMonLevel], a
+ ld a, b
+ ld [wEnemyMonLevel], a
+ pop bc
+ ret
+
+BattleWinSlideInEnemyTrainerFrontpic:
+ xor a
+ ld [wTempEnemyMonSpecies], a
+ call FinishBattleAnim
+ ld a, [wOtherTrainerClass]
+ ld [wTrainerClass], a
+ ld de, vTiles2
+ callfar GetTrainerPic
+ hlcoord 19, 0
+ ld c, 0
+
+.outer_loop
+ inc c
+ ld a, c
+ cp 7
+ ret z
+ xor a
+ ldh [hBGMapMode], a
+ ldh [hBGMapThird], a
+ ld d, $0
+ push bc
+ push hl
+
+.inner_loop
+ call .CopyColumn
+ inc hl
+ ld a, 7
+ add d
+ ld d, a
+ dec c
+ jr nz, .inner_loop
+
+ ld a, $1
+ ldh [hBGMapMode], a
+ ld c, 4
+ call DelayFrames
+ pop hl
+ pop bc
+ dec hl
+ jr .outer_loop
+
+.CopyColumn:
+ push hl
+ push de
+ push bc
+ ld e, 7
+
+.loop
+ ld [hl], d
+ ld bc, SCREEN_WIDTH
+ add hl, bc
+ inc d
+ dec e
+ jr nz, .loop
+
+ pop bc
+ pop de
+ pop hl
+ ret
+
+ApplyStatusEffectOnPlayerStats:
+ ld a, 1
+ jr ApplyStatusEffectOnStats
+
+ApplyStatusEffectOnEnemyStats:
+ xor a
+
+ApplyStatusEffectOnStats:
+ ldh [hBattleTurn], a
+ call ApplyPrzEffectOnSpeed
+ jp ApplyBrnEffectOnAttack
+
+ApplyPrzEffectOnSpeed:
+ ldh a, [hBattleTurn]
+ and a
+ jr z, .enemy
+ ld a, [wBattleMonStatus]
+ and 1 << PAR
+ ret z
+ ld hl, wBattleMonSpeed + 1
+ ld a, [hld]
+ ld b, a
+ ld a, [hl]
+ srl a
+ rr b
+ srl a
+ rr b
+ ld [hli], a
+ or b
+ jr nz, .player_ok
+ ld b, $1 ; min speed
+
+.player_ok
+ ld [hl], b
+ ret
+
+.enemy
+ ld a, [wEnemyMonStatus]
+ and 1 << PAR
+ ret z
+ ld hl, wEnemyMonSpeed + 1
+ ld a, [hld]
+ ld b, a
+ ld a, [hl]
+ srl a
+ rr b
+ srl a
+ rr b
+ ld [hli], a
+ or b
+ jr nz, .enemy_ok
+ ld b, $1 ; min speed
+
+.enemy_ok
+ ld [hl], b
+ ret
+
+ApplyBrnEffectOnAttack:
+ ldh a, [hBattleTurn]
+ and a
+ jr z, .enemy
+ ld a, [wBattleMonStatus]
+ and 1 << BRN
+ ret z
+ ld hl, wBattleMonAttack + 1
+ ld a, [hld]
+ ld b, a
+ ld a, [hl]
+ srl a
+ rr b
+ ld [hli], a
+ or b
+ jr nz, .player_ok
+ ld b, $1 ; min attack
+
+.player_ok
+ ld [hl], b
+ ret
+
+.enemy
+ ld a, [wEnemyMonStatus]
+ and 1 << BRN
+ ret z
+ ld hl, wEnemyMonAttack + 1
+ ld a, [hld]
+ ld b, a
+ ld a, [hl]
+ srl a
+ rr b
+ ld [hli], a
+ or b
+ jr nz, .enemy_ok
+ ld b, $1 ; min attack
+
+.enemy_ok
+ ld [hl], b
+ ret
+
+ApplyStatLevelMultiplierOnAllStats:
+; Apply StatLevelMultipliers on all 5 Stats
+ ld c, 0
+.stat_loop
+ call ApplyStatLevelMultiplier
+ inc c
+ ld a, c
+ cp NUM_BATTLE_STATS
+ jr nz, .stat_loop
+ ret
+
+ApplyStatLevelMultiplier:
+ push bc
+ push bc
+ ld a, [wApplyStatLevelMultipliersToEnemy]
+ and a
+ ld a, c
+ ld hl, wBattleMonAttack
+ ld de, wPlayerStats
+ ld bc, wPlayerAtkLevel
+ jr z, .got_pointers
+ ld hl, wEnemyMonAttack
+ ld de, wEnemyStats
+ ld bc, wEnemyAtkLevel
+
+.got_pointers
+ add c
+ ld c, a
+ jr nc, .okay
+ inc b
+.okay
+ ld a, [bc]
+ pop bc
+ ld b, a
+ push bc
+ sla c
+ ld b, 0
+ add hl, bc
+ ld a, c
+ add e
+ ld e, a
+ jr nc, .okay2
+ inc d
+.okay2
+ pop bc
+ push hl
+ ld hl, StatLevelMultipliers_Applied
+ dec b
+ sla b
+ ld c, b
+ ld b, 0
+ add hl, bc
+ xor a
+ ldh [hMultiplicand + 0], a
+ ld a, [de]
+ ldh [hMultiplicand + 1], a
+ inc de
+ ld a, [de]
+ ldh [hMultiplicand + 2], a
+ ld a, [hli]
+ ldh [hMultiplier], a
+ call Multiply
+ ld a, [hl]
+ ldh [hDivisor], a
+ ld b, 4
+ call Divide
+ pop hl
+
+; Cap at 999.
+ ldh a, [hQuotient + 3]
+ sub LOW(MAX_STAT_VALUE)
+ ldh a, [hQuotient + 2]
+ sbc HIGH(MAX_STAT_VALUE)
+ jp c, .okay3
+
+ ld a, HIGH(MAX_STAT_VALUE)
+ ldh [hQuotient + 2], a
+ ld a, LOW(MAX_STAT_VALUE)
+ ldh [hQuotient + 3], a
+
+.okay3
+ ldh a, [hQuotient + 2]
+ ld [hli], a
+ ld b, a
+ ldh a, [hQuotient + 3]
+ ld [hl], a
+ or b
+ jr nz, .okay4
+ inc [hl]
+
+.okay4
+ pop bc
+ ret
+
+INCLUDE "data/battle/stat_multipliers_2.asm"
+
+BadgeStatBoosts:
+; Raise the stats of the battle mon in wBattleMon
+; depending on which badges have been obtained.
+
+; Every other badge boosts a stat, starting from the first.
+; GlacierBadge also boosts Special Defense, although the relevant code is buggy (see below).
+
+; ZephyrBadge: Attack
+; PlainBadge: Speed
+; MineralBadge: Defense
+; GlacierBadge: Special Attack and Special Defense
+
+; The boosted stats are in order, except PlainBadge and MineralBadge's boosts are swapped.
+
+ ld a, [wLinkMode]
+ and a
+ ret nz
+
+ ld a, [wJohtoBadges]
+
+; Swap badges 3 (PlainBadge) and 5 (MineralBadge).
+ ld d, a
+ and (1 << PLAINBADGE)
+ add a
+ add a
+ ld b, a
+ ld a, d
+ and (1 << MINERALBADGE)
+ rrca
+ rrca
+ ld c, a
+ ld a, d
+ and ((1 << ZEPHYRBADGE) | (1 << HIVEBADGE) | (1 << FOGBADGE) | (1 << STORMBADGE) | (1 << GLACIERBADGE) | (1 << RISINGBADGE))
+ or b
+ or c
+ ld b, a
+
+ ld hl, wBattleMonAttack
+ ld c, 4
+.CheckBadge:
+ ld a, b
+ srl b
+ call c, BoostStat
+ inc hl
+ inc hl
+; Check every other badge.
+ srl b
+ dec c
+ jr nz, .CheckBadge
+; Check GlacierBadge again for Special Defense.
+; This check is buggy because it assumes that a is set by the "ld a, b" in the above loop,
+; but it can actually be overwritten by the call to BoostStat.
+ srl a
+ call c, BoostStat
+ ret
+
+BoostStat:
+; Raise stat at hl by 1/8.
+
+ ld a, [hli]
+ ld d, a
+ ld e, [hl]
+ srl d
+ rr e
+ srl d
+ rr e
+ srl d
+ rr e
+ ld a, [hl]
+ add e
+ ld [hld], a
+ ld a, [hl]
+ adc d
+ ld [hli], a
+
+; Cap at 999.
+ ld a, [hld]
+ sub LOW(MAX_STAT_VALUE)
+ ld a, [hl]
+ sbc HIGH(MAX_STAT_VALUE)
+ ret c
+ ld a, HIGH(MAX_STAT_VALUE)
+ ld [hli], a
+ ld a, LOW(MAX_STAT_VALUE)
+ ld [hld], a
+ ret
+
+_LoadBattleFontsHPBar:
+ callfar LoadBattleFontsHPBar
+ ret
+
+_LoadHPBar:
+ callfar LoadHPBar
+ ret
+
+Unreferenced_LoadHPExpBarGFX:
+ ld de, EnemyHPBarBorderGFX
+ ld hl, vTiles2 tile $6c
+ lb bc, BANK(EnemyHPBarBorderGFX), 4
+ call Get1bpp
+ ld de, HPExpBarBorderGFX
+ ld hl, vTiles2 tile $73
+ lb bc, BANK(HPExpBarBorderGFX), 6
+ call Get1bpp
+ ld de, ExpBarGFX
+ ld hl, vTiles2 tile $55
+ lb bc, BANK(ExpBarGFX), 8
+ jp Get2bpp
+
+EmptyBattleTextbox:
+ ld hl, .empty
+ jp PrintText
+
+.empty:
+ text_end
+
+_BattleRandom::
+; If the normal RNG is used in a link battle it'll desync.
+; To circumvent this a shared PRNG is used instead.
+
+; But if we're in a non-link battle we're safe to use it
+ ld a, [wLinkMode]
+ and a
+ jp z, Random
+
+; The PRNG operates in streams of 10 values.
+
+; Which value are we trying to pull?
+ push hl
+ push bc
+ ld a, [wLinkBattleRNCount]
+ ld c, a
+ ld b, 0
+ ld hl, wLinkBattleRNs
+ add hl, bc
+ inc a
+ ld [wLinkBattleRNCount], a
+
+; If we haven't hit the end yet, we're good
+ cp 10 - 1 ; Exclude last value. See the closing comment
+ ld a, [hl]
+ pop bc
+ pop hl
+ ret c
+
+; If we have, we have to generate new pseudorandom data
+; Instead of having multiple PRNGs, ten seeds are used
+ push hl
+ push bc
+ push af
+
+; Reset count to 0
+ xor a
+ ld [wLinkBattleRNCount], a
+ ld hl, wLinkBattleRNs
+ ld b, 10 ; number of seeds
+
+; Generate next number in the sequence for each seed
+; a[n+1] = (a[n] * 5 + 1) % 256
+.loop
+ ; get last #
+ ld a, [hl]
+
+ ; a * 5 + 1
+ ld c, a
+ add a
+ add a
+ add c
+ inc a
+
+ ; update #
+ ld [hli], a
+ dec b
+ jr nz, .loop
+
+; This has the side effect of pulling the last value first,
+; then wrapping around. As a result, when we check to see if
+; we've reached the end, we check the one before it.
+
+ pop af
+ pop bc
+ pop hl
+ ret
+
+Call_PlayBattleAnim_OnlyIfVisible:
+ ld a, BATTLE_VARS_SUBSTATUS3
+ call GetBattleVar
+ and 1 << SUBSTATUS_FLYING | 1 << SUBSTATUS_UNDERGROUND
+ ret nz
+
+Call_PlayBattleAnim:
+ ld a, e
+ ld [wFXAnimID], a
+ ld a, d
+ ld [wFXAnimID + 1], a
+ call WaitBGMap
+ predef_jump PlayBattleAnim
+
+FinishBattleAnim:
+ push af
+ push bc
+ push de
+ push hl
+ ld b, SCGB_BATTLE_COLORS
+ call GetSGBLayout
+ call SetPalettes
+ call DelayFrame
+ pop hl
+ pop de
+ pop bc
+ pop af
+ ret
+
+GiveExperiencePoints:
+; Give experience.
+; Don't give experience if linked or in the Battle Tower.
+ ld a, [wLinkMode]
+ and a
+ ret nz
+
+ call .EvenlyDivideExpAmongParticipants
+ xor a
+ ld [wCurPartyMon], a
+ ld bc, wPartyMon1Species
+
+.loop
+ ld hl, MON_HP
+ add hl, bc
+ ld a, [hli]
+ or [hl]
+ jp z, .next_mon ; fainted
+
+ push bc
+ ld hl, wBattleParticipantsNotFainted
+ ld a, [wCurPartyMon]
+ ld c, a
+ ld b, CHECK_FLAG
+ ld d, 0
+ predef SmallFarFlagAction
+ ld a, c
+ and a
+ pop bc
+ jp z, .next_mon
+
+; give stat exp
+ ld hl, MON_STAT_EXP + 1
+ add hl, bc
+ ld d, h
+ ld e, l
+ ld hl, wEnemyMonBaseStats - 1
+ push bc
+ ld c, NUM_EXP_STATS
+.stat_exp_loop
+ inc hl
+ ld a, [de]
+ add [hl]
+ ld [de], a
+ jr nc, .no_carry_stat_exp
+ dec de
+ ld a, [de]
+ inc a
+ jr z, .stat_exp_maxed_out
+ ld [de], a
+ inc de
+
+.no_carry_stat_exp
+ push hl
+ push bc
+ ld a, MON_PKRUS
+ call GetPartyParamLocation
+ ld a, [hl]
+ and a
+ pop bc
+ pop hl
+ jr z, .stat_exp_awarded
+ ld a, [de]
+ add [hl]
+ ld [de], a
+ jr nc, .stat_exp_awarded
+ dec de
+ ld a, [de]
+ inc a
+ jr z, .stat_exp_maxed_out
+ ld [de], a
+ inc de
+ jr .stat_exp_awarded
+
+.stat_exp_maxed_out
+ ld a, $ff
+ ld [de], a
+ inc de
+ ld [de], a
+
+.stat_exp_awarded
+ inc de
+ inc de
+ dec c
+ jr nz, .stat_exp_loop
+ xor a
+ ldh [hMultiplicand + 0], a
+ ldh [hMultiplicand + 1], a
+ ld a, [wEnemyMonBaseExp]
+ ldh [hMultiplicand + 2], a
+ ld a, [wEnemyMonLevel]
+ ldh [hMultiplier], a
+ call Multiply
+ ld a, 7
+ ldh [hDivisor], a
+ ld b, 4
+ call Divide
+; Boost Experience for traded Pokemon
+ pop bc
+ ld hl, MON_ID
+ add hl, bc
+ ld a, [wPlayerID]
+ cp [hl]
+ jr nz, .boosted
+ inc hl
+ ld a, [wPlayerID + 1]
+ cp [hl]
+ ld a, 0
+ jr z, .no_boost
+
+.boosted
+ call BoostExp
+ ld a, 1
+
+.no_boost
+; Boost experience for a Trainer Battle
+ ld [wStringBuffer2 + 2], a
+ ld a, [wBattleMode]
+ dec a
+ call nz, BoostExp
+; Boost experience for Lucky Egg
+ push bc
+ ld a, MON_ITEM
+ call GetPartyParamLocation
+ ld a, [hl]
+ cp LUCKY_EGG
+ call z, BoostExp
+ ldh a, [hQuotient + 3]
+ ld [wStringBuffer2 + 1], a
+ ldh a, [hQuotient + 2]
+ ld [wStringBuffer2], a
+ ld a, [wCurPartyMon]
+ ld hl, wPartyMonNicknames
+ call GetNick
+ ld hl, Text_MonGainedExpPoint
+ call PrintText
+ ld a, [wStringBuffer2 + 1]
+ ldh [hQuotient + 3], a
+ ld a, [wStringBuffer2]
+ ldh [hQuotient + 2], a
+ pop bc
+ call AnimateExpBar
+ push bc
+ call LoadTilemapToTempTilemap
+ pop bc
+ ld hl, MON_EXP + 2
+ add hl, bc
+ ld d, [hl]
+ ldh a, [hQuotient + 3]
+ add d
+ ld [hld], a
+ ld d, [hl]
+ ldh a, [hQuotient + 2]
+ adc d
+ ld [hl], a
+ jr nc, .no_exp_overflow
+ dec hl
+ inc [hl]
+
+.no_exp_overflow
+ ld a, [wCurPartyMon]
+ ld e, a
+ ld d, 0
+ ld hl, wPartySpecies
+ add hl, de
+ ld a, [hl]
+ ld [wCurSpecies], a
+ call GetBaseData
+ push bc
+ ld d, MAX_LEVEL
+ callfar CalcExpAtLevel
+ pop bc
+ ld hl, MON_EXP + 2
+ add hl, bc
+ push bc
+ ldh a, [hQuotient + 1]
+ ld b, a
+ ldh a, [hQuotient + 2]
+ ld c, a
+ ldh a, [hQuotient + 3]
+ ld d, a
+ ld a, [hld]
+ sub d
+ ld a, [hld]
+ sbc c
+ ld a, [hl]
+ sbc b
+ jr c, .not_max_exp
+ ld a, b
+ ld [hli], a
+ ld a, c
+ ld [hli], a
+ ld a, d
+ ld [hld], a
+
+.not_max_exp
+; Check if the mon leveled up
+ xor a ; PARTYMON
+ ld [wMonType], a
+ predef CopyMonToTempMon
+ callfar CalcLevel
+ pop bc
+ ld hl, MON_LEVEL
+ add hl, bc
+ ld a, [hl]
+ cp d
+ jp z, .next_mon
+; <NICKNAME> grew to level ##!
+ ld [wTempLevel], a
+ ld a, [wCurPartyLevel]
+ push af
+ ld a, d
+ ld [wCurPartyLevel], a
+ ld [hl], a
+ ld hl, MON_SPECIES
+ add hl, bc
+ ld a, [hl]
+ ld [wCurSpecies], a
+ ld [wTempSpecies], a ; unused?
+ call GetBaseData
+ ld hl, MON_MAXHP + 1
+ add hl, bc
+ ld a, [hld]
+ ld e, a
+ ld d, [hl]
+ push de
+ ld hl, MON_MAXHP
+ add hl, bc
+ ld d, h
+ ld e, l
+ ld hl, MON_STAT_EXP - 1
+ add hl, bc
+ push bc
+ ld b, TRUE
+ predef CalcMonStats
+ pop bc
+ pop de
+ ld hl, MON_MAXHP + 1
+ add hl, bc
+ ld a, [hld]
+ sub e
+ ld e, a
+ ld a, [hl]
+ sbc d
+ ld d, a
+ dec hl
+ ld a, [hl]
+ add e
+ ld [hld], a
+ ld a, [hl]
+ adc d
+ ld [hl], a
+ ld a, [wCurBattleMon]
+ ld d, a
+ ld a, [wCurPartyMon]
+ cp d
+ jr nz, .skip_active_mon_update
+ ld de, wBattleMonHP
+ ld a, [hli]
+ ld [de], a
+ inc de
+ ld a, [hli]
+ ld [de], a
+ ld de, wBattleMonMaxHP
+ push bc
+ ld bc, PARTYMON_STRUCT_LENGTH - MON_MAXHP
+ call CopyBytes
+ pop bc
+ ld hl, MON_LEVEL
+ add hl, bc
+ ld a, [hl]
+ ld [wBattleMonLevel], a
+ ld a, [wPlayerSubStatus5]
+ bit SUBSTATUS_TRANSFORMED, a
+ jr nz, .transformed
+ ld hl, MON_ATK
+ add hl, bc
+ ld de, wPlayerStats
+ ld bc, PARTYMON_STRUCT_LENGTH - MON_ATK
+ call CopyBytes
+
+.transformed
+ xor a ; FALSE
+ ld [wApplyStatLevelMultipliersToEnemy], a
+ call ApplyStatLevelMultiplierOnAllStats
+ callfar ApplyStatusEffectOnPlayerStats
+ callfar BadgeStatBoosts
+ callfar UpdatePlayerHUD
+ call EmptyBattleTextbox
+ call LoadTilemapToTempTilemap
+ ld a, $1
+ ldh [hBGMapMode], a
+
+.skip_active_mon_update
+ ; level up happiness mod
+ ld c, 1
+ callfar ChangeHappiness
+ ld a, [wCurBattleMon]
+ ld b, a
+ ld a, [wCurPartyMon]
+ cp b
+ jr z, .skip_exp_bar_animation
+ ld de, SFX_HIT_END_OF_EXP_BAR
+ call PlaySFX
+ call WaitSFX
+ ld hl, BattleText_StringBuffer1GrewToLevel
+ call StdBattleTextbox
+ call LoadTilemapToTempTilemap
+
+.skip_exp_bar_animation
+ 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
+ ld c, 30
+ call DelayFrames
+ call WaitPressAorB_BlinkCursor
+ call SafeLoadTempTilemapToTilemap
+ xor a ; PARTYMON
+ ld [wMonType], a
+ ld a, [wCurSpecies]
+ ld [wTempSpecies], a ; unused?
+ ld a, [wCurPartyLevel]
+ push af
+ ld c, a
+ ld a, [wTempLevel]
+ ld b, a
+
+.level_loop
+ inc b
+ ld a, b
+ ld [wCurPartyLevel], a
+ push bc
+ predef LearnLevelMoves
+ pop bc
+ ld a, b
+ cp c
+ jr nz, .level_loop
+ pop af
+ ld [wCurPartyLevel], a
+ ld hl, wEvolvableFlags
+ ld a, [wCurPartyMon]
+ ld c, a
+ ld b, SET_FLAG
+ predef SmallFarFlagAction
+ pop af
+ ld [wCurPartyLevel], a
+
+.next_mon
+ ld a, [wPartyCount]
+ ld b, a
+ ld a, [wCurPartyMon]
+ inc a
+ cp b
+ jr z, .done
+ ld [wCurPartyMon], a
+ ld a, MON_SPECIES
+ call GetPartyParamLocation
+ ld b, h
+ ld c, l
+ jp .loop
+
+.done
+ jp ResetBattleParticipants
+
+.EvenlyDivideExpAmongParticipants:
+; count number of battle participants
+ ld a, [wBattleParticipantsNotFainted]
+ ld b, a
+ ld c, PARTY_LENGTH
+ ld d, 0
+.count_loop
+ xor a
+ srl b
+ adc d
+ ld d, a
+ dec c
+ jr nz, .count_loop
+ cp 2
+ ret c
+
+ ld [wTempByteValue], a
+ ld hl, wEnemyMonBaseStats
+ ld c, wEnemyMonEnd - wEnemyMonBaseStats
+.base_stat_division_loop
+ xor a
+ ldh [hDividend + 0], a
+ ld a, [hl]
+ ldh [hDividend + 1], a
+ ld a, [wTempByteValue]
+ ldh [hDivisor], a
+ ld b, 2
+ call Divide
+ ldh a, [hQuotient + 3]
+ ld [hli], a
+ dec c
+ jr nz, .base_stat_division_loop
+ ret
+
+BoostExp:
+; Multiply experience by 1.5x
+ push bc
+; load experience value
+ ldh a, [hProduct + 2]
+ ld b, a
+ ldh a, [hProduct + 3]
+ ld c, a
+; halve it
+ srl b
+ rr c
+; add it back to the whole exp value
+ add c
+ ldh [hProduct + 3], a
+ ldh a, [hProduct + 2]
+ adc b
+ ldh [hProduct + 2], a
+ pop bc
+ ret
+
+Text_MonGainedExpPoint:
+ text_far Text_Gained
+ text_asm
+ ld hl, ExpPointsText
+ ld a, [wStringBuffer2 + 2] ; IsTradedMon
+ and a
+ ret z
+
+ ld hl, BoostedExpPointsText
+ ret
+
+BoostedExpPointsText:
+ text_far _BoostedExpPointsText
+ text_end
+
+ExpPointsText:
+ text_far _ExpPointsText
+ text_end
+
+AnimateExpBar:
+ push bc
+
+ ld hl, wCurPartyMon
+ ld a, [wCurBattleMon]
+ cp [hl]
+ jp nz, .finish
+
+ ld a, [wBattleMonLevel]
+ cp MAX_LEVEL
+ jp z, .finish
+
+ ldh a, [hProduct + 3]
+ ld [wceef], a
+ push af
+ ldh a, [hProduct + 2]
+ ld [wceee], a
+ push af
+ xor a
+ ld [wceed], a
+ xor a ; PARTYMON
+ ld [wMonType], a
+ predef CopyMonToTempMon
+ ld a, [wTempMonLevel]
+ ld b, a
+ ld e, a
+ push de
+ ld de, wTempMonExp + 2
+ call CalcExpBar
+ push bc
+ ld hl, wTempMonExp + 2
+ ld a, [wceef]
+ add [hl]
+ ld [hld], a
+ ld a, [wceee]
+ adc [hl]
+ ld [hld], a
+ jr nc, .NoOverflow
+ inc [hl]
+
+.NoOverflow:
+ ld d, MAX_LEVEL
+ callfar CalcExpAtLevel
+ ldh a, [hProduct + 1]
+ ld b, a
+ ldh a, [hProduct + 2]
+ ld c, a
+ ldh a, [hProduct + 3]
+ ld d, a
+ ld hl, wTempMonExp + 2
+ ld a, [hld]
+ sub d
+ ld a, [hld]
+ sbc c
+ ld a, [hl]
+ sbc b
+ jr c, .AlreadyAtMaxExp
+ ld a, b
+ ld [hli], a
+ ld a, c
+ ld [hli], a
+ ld a, d
+ ld [hld], a
+
+.AlreadyAtMaxExp:
+ callfar CalcLevel
+ ld a, d
+ pop bc
+ pop de
+ ld d, a
+
+.LoopLevels:
+ ld a, e
+ cp d
+ jr z, .FinishExpBar
+ inc a
+ ld [wTempMonLevel], a
+ ld [wCurPartyLevel], a
+ ld [wBattleMonLevel], a
+ push de
+ call .PlayExpBarSound
+ ld c, $40
+ call .LoopBarAnimation
+ call PrintPlayerHUD
+ ld hl, wBattleMonNick
+ ld de, wStringBuffer1
+ ld bc, MON_NAME_LENGTH
+ call CopyBytes
+ call TerminateExpBarSound
+ ld de, SFX_HIT_END_OF_EXP_BAR
+ call PlaySFX
+ farcall AnimateEndOfExpBar
+ call WaitSFX
+ ld hl, BattleText_StringBuffer1GrewToLevel
+ call StdBattleTextbox
+ pop de
+ inc e
+ ld b, $0
+ jr .LoopLevels
+
+.FinishExpBar:
+ push bc
+ ld b, d
+ ld de, wTempMonExp + 2
+ call CalcExpBar
+ ld a, b
+ pop bc
+ ld c, a
+ call .PlayExpBarSound
+ call .LoopBarAnimation
+ call TerminateExpBarSound
+ pop af
+ ldh [hProduct + 2], a
+ pop af
+ ldh [hProduct + 3], a
+
+.finish
+ pop bc
+ ret
+
+.PlayExpBarSound:
+ push bc
+ call WaitSFX
+ ld de, SFX_EXP_BAR
+ call PlaySFX
+ ld c, 10
+ call DelayFrames
+ pop bc
+ ret
+
+.LoopBarAnimation:
+ ld d, 3
+ dec b
+.anim_loop
+ inc b
+ push bc
+ push de
+ hlcoord 17, 11
+ call PlaceExpBar
+ pop de
+ ld a, $1
+ ldh [hBGMapMode], a
+ ld c, d
+ call DelayFrames
+ xor a
+ ldh [hBGMapMode], a
+ pop bc
+ ld a, c
+ cp b
+ jr z, .end_animation
+ inc b
+ push bc
+ push de
+ hlcoord 17, 11
+ call PlaceExpBar
+ pop de
+ ld a, $1
+ ldh [hBGMapMode], a
+ ld c, d
+ call DelayFrames
+ xor a
+ ldh [hBGMapMode], a
+ dec d
+ jr nz, .min_number_of_frames
+ ld d, 1
+.min_number_of_frames
+ pop bc
+ ld a, c
+ cp b
+ jr nz, .anim_loop
+.end_animation
+ ld a, $1
+ ldh [hBGMapMode], a
+ ret
+
+SendOutMonText:
+ ld a, [wLinkMode]
+ and a
+ jr z, .not_linked
+
+ ld hl, JumpText_GoMon ; If we're in a LinkBattle print just "Go <PlayerMon>"
+
+ ld a, [wBattleHasJustStarted] ; unless this (unidentified) variable is set
+ and a
+ jr nz, .skip_to_textbox
+
+.not_linked
+; Depending on the HP of the enemy mon, the game prints a different text
+ ld hl, wEnemyMonHP
+ ld a, [hli]
+ or [hl]
+ ld hl, JumpText_GoMon
+ jr z, .skip_to_textbox
+
+ ; compute enemy helth remaining as a percentage
+ xor a
+ ldh [hMultiplicand + 0], a
+ ld hl, wEnemyMonHP
+ ld a, [hli]
+ ld [wEnemyHPAtTimeOfPlayerSwitch], a
+ ldh [hMultiplicand + 1], a
+ ld a, [hl]
+ ld [wEnemyHPAtTimeOfPlayerSwitch + 1], a
+ ldh [hMultiplicand + 2], a
+ ld a, 25
+ ldh [hMultiplier], a
+ call Multiply
+ ld hl, wEnemyMonMaxHP
+ ld a, [hli]
+ ld b, [hl]
+ srl a
+ rr b
+ srl a
+ rr b
+ ld a, b
+ ld b, 4
+ ldh [hDivisor], a
+ call Divide
+
+ ldh a, [hQuotient + 3]
+ ld hl, JumpText_GoMon
+ cp 70
+ jr nc, .skip_to_textbox
+
+ ld hl, JumpText_DoItMon
+ cp 40
+ jr nc, .skip_to_textbox
+
+ ld hl, JumpText_GoForItMon
+ cp 10
+ jr nc, .skip_to_textbox
+
+ ld hl, JumpText_YourFoesWeakGetmMon
+.skip_to_textbox
+ jp PrintText
+
+JumpText_GoMon:
+ text_far Text_GoMon
+ text_end
+
+JumpText_DoItMon:
+ text_far Text_DoItMon
+ text_end
+
+JumpText_GoForItMon:
+ text_far Text_GoForItMon
+ text_end
+
+JumpText_YourFoesWeakGetmMon:
+ text_far Text_YourFoesWeakGetmMon
+ text_end
+
+WithdrawMonText:
+ ld hl, .WithdrawMonText
+ jp PrintText
+
+.WithdrawMonText:
+ text_far Text_BattleMonNickComma
+ text_asm
+; Print text to withdraw mon
+; depending on HP the message is different
+ push de
+ push bc
+ ld hl, wEnemyMonHP + 1
+ ld de, wEnemyHPAtTimeOfPlayerSwitch + 1
+ ld b, [hl]
+ dec hl
+ ld a, [de]
+ sub b
+ ldh [hMultiplicand + 2], a
+ dec de
+ ld b, [hl]
+ ld a, [de]
+ sbc b
+ ldh [hMultiplicand + 1], a
+ ld a, 25
+ ldh [hMultiplier], a
+ call Multiply
+ ld hl, wEnemyMonMaxHP
+ ld a, [hli]
+ ld b, [hl]
+ srl a
+ rr b
+ srl a
+ rr b
+ ld a, b
+ ld b, 4
+ ldh [hDivisor], a
+ call Divide
+ pop bc
+ pop de
+ ldh a, [hQuotient + 3]
+ ld hl, ThatsEnoughComeBackText
+ and a
+ ret z
+
+ ld hl, ComeBackText
+ cp 30
+ ret c
+
+ ld hl, OKComeBackText
+ cp 70
+ ret c
+
+ ld hl, GoodComeBackText
+ ret
+
+ThatsEnoughComeBackText:
+ text_far _ThatsEnoughComeBackText
+ text_end
+
+OKComeBackText:
+ text_far _OKComeBackText
+ text_end
+
+GoodComeBackText:
+ text_far _GoodComeBackText
+ text_end
+
+ComeBackText:
+ text_far _ComeBackText
+ text_end
+
+Unreferenced_HandleSafariAngerEatingStatus:
+ ld hl, wSafariMonEating
+ ld a, [hl]
+ and a
+ jr z, .angry
+ dec [hl]
+ ld hl, BattleText_WildMonIsEating
+ jr .finish
+
+.angry
+ dec hl ; wSafariMonAngerCount
+ ld a, [hl]
+ and a
+ ret z
+ dec [hl]
+ ld hl, BattleText_WildMonIsAngry
+ jr nz, .finish
+ push hl
+ ld a, [wEnemyMonSpecies]
+ ld [wCurSpecies], a
+ call GetBaseData
+ ld a, [wBaseCatchRate]
+ ld [wEnemyMonCatchRate], a
+ pop hl
+
+.finish
+ push hl
+ call SafeLoadTempTilemapToTilemap
+ pop hl
+ jp StdBattleTextbox
+
+FillInExpBar:
+ push hl
+ call CalcExpBar
+ pop hl
+ ld de, 7
+ add hl, de
+ jp PlaceExpBar
+
+CalcExpBar:
+; Calculate the percent exp between this level and the next
+; Level in b
+ push de
+ ld d, b
+ push de
+ callfar CalcExpAtLevel
+ pop de
+; exp at current level gets pushed to the stack
+ ld hl, hMultiplicand
+ ld a, [hli]
+ push af
+ ld a, [hli]
+ push af
+ ld a, [hl]
+ push af
+; next level
+ inc d
+ callfar CalcExpAtLevel
+; back up the next level exp, and subtract the two levels
+ ld hl, hMultiplicand + 2
+ ld a, [hl]
+ ldh [hMathBuffer + 2], a
+ pop bc
+ sub b
+ ld [hld], a
+ ld a, [hl]
+ ldh [hMathBuffer + 1], a
+ pop bc
+ sbc b
+ ld [hld], a
+ ld a, [hl]
+ ldh [hMathBuffer], a
+ pop bc
+ sbc b
+ ld [hl], a
+ pop de
+
+ ld hl, hMultiplicand + 1
+ ld a, [hli]
+ push af
+ ld a, [hl]
+ push af
+
+; get the amount of exp remaining to the next level
+ ld a, [de]
+ dec de
+ ld c, a
+ ldh a, [hMathBuffer + 2]
+ sub c
+ ld [hld], a
+ ld a, [de]
+ dec de
+ ld b, a
+ ldh a, [hMathBuffer + 1]
+ sbc b
+ ld [hld], a
+ ld a, [de]
+ ld c, a
+ ldh a, [hMathBuffer]
+ sbc c
+ ld [hld], a
+ xor a
+ ld [hl], a
+ ld a, 64
+ ldh [hMultiplier], a
+ call Multiply
+ pop af
+ ld c, a
+ pop af
+ ld b, a
+.loop
+ ld a, b
+ and a
+ jr z, .done
+ srl b
+ rr c
+ ld hl, hProduct
+ srl [hl]
+ inc hl
+ rr [hl]
+ inc hl
+ rr [hl]
+ inc hl
+ rr [hl]
+ jr .loop
+
+.done
+ ld a, c
+ ldh [hDivisor], a
+ ld b, 4
+ call Divide
+ ldh a, [hQuotient + 3]
+ ld b, a
+ ld a, $40
+ sub b
+ ld b, a
+ ret
+
+PlaceExpBar:
+ ld c, $8 ; number of tiles
+.loop1
+ ld a, b
+ sub $8
+ jr c, .next
+ ld b, a
+ ld a, $6a ; full bar
+ ld [hld], a
+ dec c
+ jr z, .finish
+ jr .loop1
+
+.next
+ add $8
+ jr z, .loop2
+ add $54 ; tile to the left of small exp bar tile
+ jr .skip
+
+.loop2
+ ld a, $62 ; empty bar
+
+.skip
+ ld [hld], a
+ ld a, $62 ; empty bar
+ dec c
+ jr nz, .loop2
+
+.finish
+ ret
+
+GetBattleMonBackpic:
+ ld a, [wPlayerSubStatus4]
+ bit SUBSTATUS_SUBSTITUTE, a
+ ld hl, BattleAnimCmd_RaiseSub
+ jr nz, GetBattleMonBackpic_DoAnim ; substitute
+
+DropPlayerSub:
+ ld a, [wPlayerMinimized]
+ and a
+ ld hl, BattleAnimCmd_MinimizeOpp
+ jr nz, GetBattleMonBackpic_DoAnim
+ ld a, [wCurPartySpecies]
+ push af
+ ld a, [wBattleMonSpecies]
+ ld [wCurPartySpecies], a
+ ld hl, wBattleMonDVs
+ predef GetUnownLetter
+ ld de, vTiles2 tile $31
+ predef GetMonBackpic
+ pop af
+ ld [wCurPartySpecies], a
+ ret
+
+GetBattleMonBackpic_DoAnim:
+ ldh a, [hBattleTurn]
+ push af
+ xor a
+ ldh [hBattleTurn], a
+ ld a, BANK(BattleAnimCommands)
+ rst FarCall
+ pop af
+ ldh [hBattleTurn], a
+ ret
+
+GetEnemyMonFrontpic:
+ ld a, [wEnemySubStatus4]
+ bit SUBSTATUS_SUBSTITUTE, a
+ ld hl, BattleAnimCmd_RaiseSub
+ jr nz, GetEnemyMonFrontpic_DoAnim
+
+DropEnemySub:
+ ld a, [wEnemyMinimized]
+ and a
+ ld hl, BattleAnimCmd_MinimizeOpp
+ jr nz, GetEnemyMonFrontpic_DoAnim
+
+ ld a, [wCurPartySpecies]
+ push af
+ ld a, [wEnemyMonSpecies]
+ ld [wCurSpecies], a
+ ld [wCurPartySpecies], a
+ call GetBaseData
+ ld hl, wEnemyMonDVs
+ predef GetUnownLetter
+ ld de, vTiles2
+ predef GetMonFrontpic
+ pop af
+ ld [wCurPartySpecies], a
+ ret
+
+GetEnemyMonFrontpic_DoAnim:
+ ldh a, [hBattleTurn]
+ push af
+ call SetEnemyTurn
+ ld a, BANK(BattleAnimCmd_MinimizeOpp)
+ rst FarCall
+ pop af
+ ldh [hBattleTurn], a
+ ret
+
+StartBattle:
+; This check prevents you from entering a battle without any Pokemon.
+; Those using walk-through-walls to bypass getting a Pokemon experience
+; the effects of this check.
+ ld a, [wPartyCount]
+ and a
+ ret z
+
+ ld a, [wOtherTrainerClass]
+ and a
+ jr nz, .battle_intro
+
+ ld a, [wTempWildMonSpecies]
+ ld [wCurPartySpecies], a
+
+.battle_intro
+ ld [wTempEnemyMonSpecies], a
+ ld a, [wTimeOfDayPal]
+ push af
+ xor a
+ ldh [hMapAnims], a
+ xor a
+ ld [wTempBattleMonSpecies], a
+ ld [wBattleMenuCursorBuffer], a
+ farcall PlayBattleMusic
+ ld a, 0
+ ld [wSpriteUpdatesEnabled], a
+ call ShowLinkBattleParticipants
+ farcall ClearBattleRAM
+ ld hl, rLCDC
+ res rLCDC_WINDOW_TILEMAP, [hl] ; select 9800-9BFF
+ ld a, [wOtherTrainerClass]
+ and a
+ jr nz, .trainer
+
+ call InitEnemyWildmon
+ jr .back_up_bgmap2
+
+.trainer
+ call InitEnemyTrainer
+
+.back_up_bgmap2
+ ld b, 0
+ call GetSGBLayout
+ ld hl, wVramState
+ res 0, [hl]
+ call InitBattleDisplay
+ call BattleStartMessage
+ xor a
+ ldh [hBGMapMode], a
+ ld hl, rLCDC
+ set rLCDC_WINDOW_TILEMAP, [hl] ; select 9C00-9FFF
+ call EmptyBattleTextbox
+ hlcoord 9, 7
+ lb bc, 5, 11
+ call ClearBox
+ hlcoord 1, 0
+ lb bc, 4, 10
+ call ClearBox
+ call ClearSprites
+ ld a, [wEnemyMonEnd]
+ cp WILD_BATTLE
+ call z, UpdateEnemyHUD
+ ld a, $1
+ ldh [hBGMapMode], a
+ call DoBattle
+ call ExitBattle
+ pop af
+ ld [wTimeOfDayPal], a
+ scf
+ ret
+
+InitEnemyTrainer:
+ ld [wTrainerClass], a
+ xor a
+ ld [wTempEnemyMonSpecies], a
+ callfar GetTrainerAttributes
+ callfar ReadTrainerParty
+
+ ; RIVAL1's first mon has no held item
+ ld a, [wTrainerClass]
+ cp RIVAL1
+ jr nz, .ok
+ xor a
+ ld [wOTPartyMon1Item], a
+
+.ok:
+ ld de, vTiles2
+ callfar GetTrainerPic
+ xor a
+ ldh [hGraphicStartTile], a
+ dec a
+ ld [wEnemyItemState], a
+ hlcoord 12, 0
+ lb bc, 7, 7
+ predef PlaceGraphic
+ ld a, -1
+ ld [wCurOTMon], a
+ ld a, TRAINER_BATTLE
+ ld [wBattleMode], a
+
+ call IsGymLeader
+ jr nc, .done
+ xor a
+ ld [wCurPartyMon], a
+ ld a, [wPartyCount]
+ ld b, a
+.partyloop
+ push bc
+ ld a, MON_HP
+ call GetPartyParamLocation
+ ld a, [hli]
+ or [hl]
+ jr z, .skipfaintedmon
+ ld c, HAPPINESS_GYMBATTLE
+ callfar ChangeHappiness
+.skipfaintedmon
+ pop bc
+ dec b
+ jr z, .done
+ ld hl, wCurPartyMon
+ inc [hl]
+ jr .partyloop
+.done
+ ret
+
+InitEnemyWildmon:
+ ld a, WILD_BATTLE
+ ld [wBattleMode], a
+ call LoadEnemyMon
+ ld hl, wEnemyMonMoves
+ ld de, wWildMonMoves
+ ld bc, NUM_MOVES
+ call CopyBytes
+ ld hl, wEnemyMonPP
+ ld de, wWildMonPP
+ ld bc, NUM_MOVES
+ call CopyBytes
+ ld hl, wEnemyMonDVs
+ predef GetUnownLetter
+ ld a, [wCurPartySpecies]
+ cp UNOWN
+ jr nz, .skip_unown
+ ld a, [wFirstUnownSeen]
+ and a
+ jr nz, .skip_unown
+ ld a, [wUnownLetter]
+ ld [wFirstUnownSeen], a
+.skip_unown
+ ld de, vTiles2
+ predef GetMonFrontpic
+ xor a
+ ld [wTrainerClass], a
+ ldh [hGraphicStartTile], a
+ hlcoord 12, 0
+ lb bc, 7, 7
+ predef PlaceGraphic
+ ret
+
+Unreferenced_Function3f41a:
+ ld hl, wEnemyMonMoves
+ ld de, wListMoves_MoveIndicesBuffer
+ ld b, NUM_MOVES
+.loop
+ ld a, [de]
+ inc de
+ ld [hli], a
+ and a
+ jr z, .clearpp
+
+ push bc
+ push hl
+
+ push hl
+ dec a
+ ld hl, Moves + MOVE_PP
+ ld bc, MOVE_LENGTH
+ call AddNTimes
+ ld a, BANK(Moves)
+ call GetFarByte
+ pop hl
+
+ ld bc, wEnemyMonPP - (wEnemyMonMoves + 1)
+ add hl, bc
+ ld [hl], a
+
+ pop hl
+ pop bc
+
+ dec b
+ jr nz, .loop
+ ret
+
+.clear
+ xor a
+ ld [hli], a
+
+.clearpp
+ push bc
+ push hl
+ ld bc, wEnemyMonPP - (wEnemyMonMoves + 1)
+ add hl, bc
+ xor a
+ ld [hl], a
+ pop hl
+ pop bc
+ dec b
+ jr nz, .clear
+ ret
+
+ExitBattle:
+ call IsLinkBattle
+ jr nz, .handle_end_of_battle
+ call ShowLinkBattleParticipantsAfterEnd
+ jr .clean_up_battle_ram
+
+.handle_end_of_battle
+ ld a, [wBattleResult]
+ and $f
+ jr nz, .clean_up_battle_ram
+ ; WIN
+ call CheckPayDay
+ xor a
+ ld [wForceEvolution], a
+ predef EvolveAfterBattle
+ farcall GivePokerusAndConvertBerries
+
+.clean_up_battle_ram
+ call BattleEnd_HandleRoamMons
+ xor a
+ ld [wLowHealthAlarm], a
+ ld [wBattleMode], a
+ ld [wBattleType], a
+ ld [wAttackMissed], a
+ ld [wTempWildMonSpecies], a
+ ld [wOtherTrainerClass], a
+ ld [wFailedToFlee], a
+ ld [wNumFleeAttempts], a
+ ld [wForcedSwitch], a
+ ld [wPartyMenuCursor], a
+ ld [wKeyItemsPocketCursor], a
+ ld [wItemsPocketCursor], a
+ ld [wBattleMenuCursorBuffer], a
+ ld [wCurMoveNum], a
+ ld [wBallsPocketCursor], a
+ ld [wLastPocket], a
+ ld [wMenuScrollPosition], a
+ ld [wKeyItemsPocketScrollPosition], a
+ ld [wItemsPocketScrollPosition], a
+ ld [wBallsPocketScrollPosition], a
+ ld hl, wPlayerSubStatus1
+ ld b, wEnemyFuryCutterCount - wPlayerSubStatus1
+.loop
+ ld [hli], a
+ dec b
+ jr nz, .loop
+ call WaitSFX
+ ret
+
+CheckPayDay:
+ ld hl, wPayDayMoney
+ ld a, [hli]
+ or [hl]
+ inc hl
+ or [hl]
+ ret z
+ ld a, [wAmuletCoin]
+ and a
+ jr z, .okay
+ ld hl, wPayDayMoney + 2
+ sla [hl]
+ dec hl
+ rl [hl]
+ dec hl
+ rl [hl]
+ jr nc, .okay
+ ld a, $ff
+ ld [hli], a
+ ld [hli], a
+ ld [hl], a
+
+.okay
+ ld hl, wPayDayMoney + 2
+ ld de, wMoney + 2
+ call AddBattleMoneyToAccount
+ ld hl, BattleText_PlayerPickedUpPayDayMoney
+ call StdBattleTextbox
+ ret
+
+PlayerPickedUpPayDayMoney:
+ text_far _PlayerPickedUpPayDayMoney
+ text_end
+
+ShowLinkBattleParticipantsAfterEnd:
+ ld a, [wCurOTMon]
+ ld hl, wOTPartyMon1Status
+ call GetPartyLocation
+ ld a, [wEnemyMonStatus]
+ ld [hl], a
+ call ClearTilemap
+ farcall _ShowLinkBattleParticipants
+ ld a, [wBattleResult]
+ and $f
+ cp LOSE
+ ld de, .Win
+ jr c, .store_result
+ ld de, .Lose
+ jr z, .store_result
+ ; DRAW
+ ld de, .Draw
+
+.store_result
+ hlcoord 6, 8
+ call PlaceString
+ ld c, 200
+ call DelayFrames
+
+ ld a, BANK(sLinkBattleStats)
+ call OpenSRAM
+
+ call AddLastLinkBattleToLinkRecord
+ call ReadAndPrintLinkBattleRecord
+
+ call CloseSRAM
+
+ call WaitPressAorB_BlinkCursor
+ call ClearTilemap
+ ret
+
+.Win:
+ db "YOU WIN@"
+.Lose:
+ db "YOU LOSE@"
+.Draw:
+ db " DRAW@"
+
+LINK_BATTLE_RECORD_LENGTH EQUS "(sLinkBattleRecord1End - sLinkBattleRecord1)" ; 18
+NUM_LINK_BATTLE_RECORDS EQUS "((sLinkBattleStatsEnd - sLinkBattleRecord) / LINK_BATTLE_RECORD_LENGTH)" ; 5
+
+_DisplayLinkRecord:
+ ld a, BANK(sLinkBattleStats)
+ call OpenSRAM
+
+ call ReadAndPrintLinkBattleRecord
+
+ call CloseSRAM
+ hlcoord 0, 0, wAttrmap
+ xor a
+ ld bc, SCREEN_WIDTH * SCREEN_HEIGHT
+ call ByteFill
+ call WaitBGMap2
+ ld b, SCGB_DIPLOMA
+ call GetSGBLayout
+ call SetPalettes
+ ld c, 8
+ call DelayFrames
+ call WaitPressAorB_BlinkCursor
+ ret
+
+ReadAndPrintLinkBattleRecord:
+ call ClearTilemap
+ call ClearSprites
+ call .PrintBattleRecord
+ hlcoord 0, 8
+ ld b, NUM_LINK_BATTLE_RECORDS
+ ld de, sLinkBattleRecord + 2
+.loop
+ push bc
+ push hl
+ push de
+ ld a, [de]
+ and a
+ jr z, .PrintFormatString
+ ld a, [wSavedAtLeastOnce]
+ and a
+ jr z, .PrintFormatString
+ push hl
+ push hl
+ ld h, d
+ ld l, e
+ ld de, wceed
+ ld bc, NAME_LENGTH - 1
+ call CopyBytes
+ ld a, "@"
+ ld [de], a
+ inc de
+ ld bc, 6
+ call CopyBytes
+ ld de, wceed
+ pop hl
+ call PlaceString
+ pop hl
+ ld de, 26
+ add hl, de
+ push hl
+ ld de, wcef8
+ lb bc, 2, 4
+ call PrintNum
+ pop hl
+ ld de, 5
+ add hl, de
+ push hl
+ ld de, wcefa
+ lb bc, 2, 4
+ call PrintNum
+ pop hl
+ ld de, 5
+ add hl, de
+ ld de, wcefc
+ lb bc, 2, 4
+ call PrintNum
+ jr .next
+
+.PrintFormatString:
+ ld de, .Format
+ call PlaceString
+.next
+ pop hl
+ ld bc, LINK_BATTLE_RECORD_LENGTH
+ add hl, bc
+ ld d, h
+ ld e, l
+ pop hl
+ ld bc, 2 * SCREEN_WIDTH
+ add hl, bc
+ pop bc
+ dec b
+ jr nz, .loop
+ ret
+
+.PrintBattleRecord:
+ hlcoord 1, 0
+ ld de, .Record
+ call PlaceString
+
+ hlcoord 0, 6
+ ld de, .Result
+ call PlaceString
+
+ hlcoord 0, 2
+ ld de, .Total
+ call PlaceString
+
+ hlcoord 6, 4
+ ld de, sLinkBattleWins
+ call .PrintZerosIfNoSaveFileExists
+
+ lb bc, 2, 4
+ call PrintNum
+
+ hlcoord 11, 4
+ ld de, sLinkBattleLosses
+ call .PrintZerosIfNoSaveFileExists
+
+ lb bc, 2, 4
+ call PrintNum
+
+ hlcoord 16, 4
+ ld de, sLinkBattleDraws
+ call .PrintZerosIfNoSaveFileExists
+
+ lb bc, 2, 4
+ call PrintNum
+
+.quit
+ ret
+
+.PrintZerosIfNoSaveFileExists:
+ ld a, [wSavedAtLeastOnce]
+ and a
+ ret nz
+ ld de, .Scores
+ ret
+
+.Scores:
+ db "<NULL><NULL>"
+.Format:
+ db " --- <LF>"
+ db " - - -@"
+.Record:
+ db "<PLAYER>'s RECORD@"
+.Result:
+ db "RESULT WIN LOSE DRAW@"
+.Total:
+ db "TOTAL WIN LOSE DRAW@"
+
+BattleEnd_HandleRoamMons:
+ ld a, [wBattleType]
+ cp BATTLETYPE_ROAMING
+ jr nz, .not_roaming
+ ld a, [wBattleResult]
+ and $f
+ jr z, .caught_or_defeated_roam_mon ; WIN
+ call GetRoamMonHP
+ ld a, [wEnemyMonHP + 1]
+ ld [hl], a
+ jr .update_roam_mons
+
+.caught_or_defeated_roam_mon
+ call GetRoamMonHP
+ ld [hl], 0
+ call GetRoamMonMapGroup
+ ld [hl], GROUP_N_A
+ call GetRoamMonMapNumber
+ ld [hl], MAP_N_A
+ call GetRoamMonSpecies
+ ld [hl], 0
+ ret
+
+.not_roaming
+ call BattleRandom
+ and $f
+ ret nz
+
+.update_roam_mons
+ callfar UpdateRoamMons
+ ret
+
+GetRoamMonMapGroup:
+ ld a, [wTempEnemyMonSpecies]
+ ld b, a
+ ld a, [wRoamMon1Species]
+ cp b
+ ld hl, wRoamMon1MapGroup
+ ret z
+ ld a, [wRoamMon2Species]
+ cp b
+ ld hl, wRoamMon2MapGroup
+ ret z
+ ld hl, wRoamMon3MapGroup
+ ret
+
+GetRoamMonMapNumber:
+ ld a, [wTempEnemyMonSpecies]
+ ld b, a
+ ld a, [wRoamMon1Species]
+ cp b
+ ld hl, wRoamMon1MapNumber
+ ret z
+ ld a, [wRoamMon2Species]
+ cp b
+ ld hl, wRoamMon2MapNumber
+ ret z
+ ld hl, wRoamMon3MapNumber
+ ret
+
+GetRoamMonHP:
+; output: hl = wRoamMonHP
+ ld a, [wTempEnemyMonSpecies]
+ ld b, a
+ ld a, [wRoamMon1Species]
+ cp b
+ ld hl, wRoamMon1HP
+ ret z
+ ld a, [wRoamMon2Species]
+ cp b
+ ld hl, wRoamMon2HP
+ ret z
+ ld hl, wRoamMon3HP
+ ret
+
+GetRoamMonDVs:
+; output: hl = wRoamMonDVs
+ ld a, [wTempEnemyMonSpecies]
+ ld b, a
+ ld a, [wRoamMon1Species]
+ cp b
+ ld hl, wRoamMon1DVs
+ ret z
+ ld a, [wRoamMon2Species]
+ cp b
+ ld hl, wRoamMon2DVs
+ ret z
+ ld hl, wRoamMon3DVs
+ ret
+
+GetRoamMonSpecies:
+ ld a, [wTempEnemyMonSpecies]
+ ld hl, wRoamMon1Species
+ cp [hl]
+ ret z
+ ld hl, wRoamMon2Species
+ cp [hl]
+ ret z
+ ld hl, wRoamMon3Species
+ ret
+
+AddLastLinkBattleToLinkRecord:
+ ld hl, wOTPlayerID
+ ld de, wStringBuffer1
+ ld bc, 2
+ call CopyBytes
+ ld hl, wOTPlayerName
+ ld bc, NAME_LENGTH - 1
+ call CopyBytes
+ ld hl, sLinkBattleStats - (LINK_BATTLE_RECORD_LENGTH - 6)
+ call .StoreResult
+ ld hl, sLinkBattleRecord
+ ld d, NUM_LINK_BATTLE_RECORDS
+.loop
+ push hl
+ inc hl
+ inc hl
+ ld a, [hl]
+ dec hl
+ dec hl
+ and a
+ jr z, .copy
+ push de
+ ld bc, LINK_BATTLE_RECORD_LENGTH - 6
+ ld de, wStringBuffer1
+ call CompareBytesLong
+ pop de
+ pop hl
+ jr c, .done
+ ld bc, LINK_BATTLE_RECORD_LENGTH
+ add hl, bc
+ dec d
+ jr nz, .loop
+ ld bc, -LINK_BATTLE_RECORD_LENGTH
+ add hl, bc
+ push hl
+
+.copy
+ ld d, h
+ ld e, l
+ ld hl, wStringBuffer1
+ ld bc, LINK_BATTLE_RECORD_LENGTH - 6
+ call CopyBytes
+ ld b, 6
+ xor a
+.loop2
+ ld [de], a
+ inc de
+ dec b
+ jr nz, .loop2
+ pop hl
+
+.done
+ call .StoreResult
+ call .FindOpponentAndAppendRecord
+ ret
+.StoreResult:
+ ld a, [wBattleResult]
+ and $f
+ cp LOSE
+ ld bc, (sLinkBattleRecord1Wins - sLinkBattleRecord1) + 1
+ jr c, .okay ; WIN
+ ld bc, (sLinkBattleRecord1Losses - sLinkBattleRecord1) + 1
+ jr z, .okay ; LOSE
+ ; DRAW
+ ld bc, (sLinkBattleRecord1Draws - sLinkBattleRecord1) + 1
+.okay
+ add hl, bc
+ call .CheckOverflow
+ ret nc
+ inc [hl]
+ ret nz
+ dec hl
+ inc [hl]
+ ret
+
+.CheckOverflow:
+ dec hl
+ ld a, [hl]
+ inc hl
+ cp HIGH(MAX_LINK_RECORD)
+ ret c
+ ld a, [hl]
+ cp LOW(MAX_LINK_RECORD)
+ ret
+
+.FindOpponentAndAppendRecord:
+ ld b, NUM_LINK_BATTLE_RECORDS
+ ld hl, sLinkBattleRecord1End - 1
+ ld de, wceed
+.loop3
+ push bc
+ push de
+ push hl
+ call .LoadPointer
+ pop hl
+ ld a, e
+ pop de
+ ld [de], a
+ inc de
+ ld a, b
+ ld [de], a
+ inc de
+ ld a, c
+ ld [de], a
+ inc de
+ ld bc, LINK_BATTLE_RECORD_LENGTH
+ add hl, bc
+ pop bc
+ dec b
+ jr nz, .loop3
+ ld b, $0
+ ld c, $1
+.loop4
+ ld a, b
+ add b
+ add b
+ ld e, a
+ ld d, $0
+ ld hl, wceed
+ add hl, de
+ push hl
+ ld a, c
+ add c
+ add c
+ ld e, a
+ ld d, $0
+ ld hl, wceed
+ add hl, de
+ ld d, h
+ ld e, l
+ pop hl
+ push bc
+ ld c, 3
+ call CompareBytes
+ pop bc
+ jr z, .equal
+ jr nc, .done2
+
+.equal
+ inc c
+ ld a, c
+ cp $5
+ jr nz, .loop4
+ inc b
+ ld c, b
+ inc c
+ ld a, b
+ cp $4
+ jr nz, .loop4
+ ret
+
+.done2
+ push bc
+ ld a, b
+ ld bc, LINK_BATTLE_RECORD_LENGTH
+ ld hl, sLinkBattleRecord
+ call AddNTimes
+ push hl
+ ld de, wceed
+ ld bc, LINK_BATTLE_RECORD_LENGTH
+ call CopyBytes
+ pop hl
+ pop bc
+ push hl
+ ld a, c
+ ld bc, LINK_BATTLE_RECORD_LENGTH
+ ld hl, sLinkBattleRecord
+ call AddNTimes
+ pop de
+ push hl
+ ld bc, LINK_BATTLE_RECORD_LENGTH
+ call CopyBytes
+ ld hl, wceed
+ ld bc, LINK_BATTLE_RECORD_LENGTH
+ pop de
+ call CopyBytes
+ ret
+
+.LoadPointer:
+ ld e, $0
+ ld a, [hld]
+ ld c, a
+ ld a, [hld]
+ ld b, a
+ ld a, [hld]
+ add c
+ ld c, a
+ ld a, [hld]
+ adc b
+ ld b, a
+ jr nc, .okay2
+ inc e
+
+.okay2
+ ld a, [hld]
+ add c
+ ld c, a
+ ld a, [hl]
+ adc b
+ ld b, a
+ ret nc
+ inc e
+ ret
+
+InitBattleDisplay:
+ call InitBackPic
+ hlcoord 0, 12
+ ld b, 4
+ ld c, 18
+ call Textbox
+ hlcoord 1, 5
+ lb bc, 3, 7
+ call ClearBox
+ call LoadStandardFont
+ call _LoadBattleFontsHPBar
+ call .BlankBGMap
+ xor a
+ ldh [hMapAnims], a
+ ldh [hSCY], a
+ ld a, $90
+ ldh [hWY], a
+ ldh [rWY], a
+ call WaitBGMap
+ xor a
+ ldh [hBGMapMode], a
+ call BattleIntroSlidingPics
+ ld a, $1
+ ldh [hBGMapMode], a
+ ld a, $31
+ ldh [hGraphicStartTile], a
+ hlcoord 2, 6
+ lb bc, 6, 6
+ predef PlaceGraphic
+ xor a
+ ldh [hWY], a
+ ldh [rWY], a
+ call WaitBGMap
+ call HideSprites
+ ld b, SCGB_BATTLE_COLORS
+ call GetSGBLayout
+ call SetPalettes
+ ld a, $90
+ ldh [hWY], a
+ xor a
+ ldh [hSCX], a
+ ret
+
+.BlankBGMap:
+ ld a, BANK(sDecompressScratch)
+ call OpenSRAM
+
+ ld hl, sDecompressScratch
+ ld bc, sScratchAttrmap - sDecompressScratch
+ ld a, " "
+ call ByteFill
+
+ ld de, sDecompressScratch
+ hlbgcoord 0, 0
+ lb bc, BANK(.BlankBGMap), $40
+ call Request2bpp
+ call CloseSRAM
+ ret
+
+INCLUDE "engine/battle/sliding_intro.asm"
+
+InitBackPic:
+ call GetTrainerBackpic
+ call CopyBackpic
+ ret
+
+GetTrainerBackpic:
+ ld hl, ChrisBackpic
+ ld a, [wBattleType]
+ cp BATTLETYPE_TUTORIAL
+ jr nz, .ok
+ ld hl, DudeBackpic
+
+.ok:
+ ld de, vTiles2 tile $31
+ ld b, BANK(ChrisBackpic)
+ ld c, 7 * 7
+ predef DecompressGet2bpp
+ ret
+
+CopyBackpic:
+ ld a, BANK(sDecompressBuffer)
+ call OpenSRAM
+ ld hl, vTiles3
+ ld de, sDecompressBuffer
+ ldh a, [hROMBank]
+ ld b, a
+ ld c, 7 * 7
+ call Request2bpp
+ call CloseSRAM
+ call .LoadTrainerBackpicAsOAM
+ ld a, 7 * 7
+ ldh [hGraphicStartTile], a
+ hlcoord 2, 6
+ lb bc, 6, 6
+ predef PlaceGraphic
+ ret
+
+.LoadTrainerBackpicAsOAM:
+ ld hl, wVirtualOAMSprite00
+ xor a
+ ldh [hMapObjectIndexBuffer], a
+ ld b, 6
+ ld e, (SCREEN_WIDTH + 1) * TILE_WIDTH
+.outer_loop
+ ld c, 3
+ ld d, 8 * TILE_WIDTH
+.inner_loop
+ ld [hl], d ; y
+ inc hl
+ ld [hl], e ; x
+ inc hl
+ ldh a, [hMapObjectIndexBuffer]
+ ld [hli], a ; tile id
+ inc a
+ ldh [hMapObjectIndexBuffer], a
+ ld a, PAL_BATTLE_OB_PLAYER
+ ld [hli], a ; attributes
+ ld a, d
+ add 1 * TILE_WIDTH
+ ld d, a
+ dec c
+ jr nz, .inner_loop
+ ldh a, [hMapObjectIndexBuffer]
+ add $3
+ ldh [hMapObjectIndexBuffer], a
+ ld a, e
+ add 1 * TILE_WIDTH
+ ld e, a
+ dec b
+ jr nz, .outer_loop
+ ret
+
+ChrisBackpic:
+INCBIN "gfx/player/chris_back.2bpp.lz"
+
+DudeBackpic:
+INCBIN "gfx/battle/dude.2bpp.lz"
+
+BattleStartMessage:
+ ld a, [wBattleMode]
+ dec a
+ jr z, .wild
+
+ ld de, SFX_SHINE
+ call PlaySFX
+ call WaitSFX
+
+ ld c, 20
+ call DelayFrames
+
+ callfar Battle_GetTrainerName
+
+ ld hl, WantsToBattleText
+ jr .PlaceBattleStartText
+
+.wild
+ call BattleCheckEnemyShininess
+ jr nc, .not_shiny
+
+ xor a
+ ld [wNumHits], a
+ ld a, 1
+ ldh [hBattleTurn], a
+ ld a, 1
+ ld [wBattleAnimParam], a
+ ld de, ANIM_SEND_OUT_MON
+ call Call_PlayBattleAnim
+
+.not_shiny
+ ld a, $f
+ ld [wCryTracks], a
+ ld a, [wTempEnemyMonSpecies]
+ call PlayStereoCry
+ ld hl, HookedPokemonAttackedText
+ ld a, [wBattleType]
+ cp BATTLETYPE_FISH
+ jr z, .PlaceBattleStartText
+ ld hl, PokemonFellFromTreeText
+ cp BATTLETYPE_TREE
+ jr z, .PlaceBattleStartText
+ ld hl, WildPokemonAppearedText
+
+.PlaceBattleStartText:
+ push hl
+ farcall BattleStart_TrainerHuds
+ pop hl
+ call StdBattleTextbox
+ ret
+
+ShowLinkBattleParticipants:
+ call IsLinkBattle
+ jr nz, .ok
+ farcall _ShowLinkBattleParticipants
+ call ClearTilemap
+ call ClearSprites
+
+.ok
+ xor a
+ ldh [hMapAnims], a
+ call DelayFrame
+ predef DoBattleTransition
+ call _LoadBattleFontsHPBar
+ ld a, $1
+ ldh [hBGMapMode], a
+ call ClearSprites
+ call ClearTilemap
+ xor a
+ ldh [hBGMapMode], a
+ ldh [hWY], a
+ ldh [rWY], a
+ ldh [hMapAnims], a
+ ret
+
+IsLinkBattle:
+ push bc
+ push af
+ ld a, [wLinkMode]
+ cp LINK_COLOSSEUM
+ pop bc
+ ld a, b
+ pop bc
+ ret
diff --git a/engine/battle/effect_commands.asm b/engine/battle/effect_commands.asm
new file mode 100644
index 00000000..815cc17d
--- /dev/null
+++ b/engine/battle/effect_commands.asm
@@ -0,0 +1,6865 @@
+DoPlayerTurn:
+; Read in and execute the player's move effects for this turn.
+ call SetPlayerTurn
+
+ ld a, [wBattlePlayerAction]
+ and a ; BATTLEPLAYERACTION_USEMOVE?
+ ret nz
+
+ xor a
+ ld [wTurnEnded], a
+
+ ; Effect command checkturn is called for every move.
+ call CheckTurn
+
+ ld a, [wTurnEnded]
+ and a
+ ret nz
+
+ call UpdateMoveData
+ jr DoMove
+
+DoEnemyTurn:
+; Read in and execute the enemy's move effects for this turn.
+ call SetEnemyTurn
+
+ ld a, [wLinkMode]
+ and a
+ jr z, .do_it
+
+ ld a, [wBattleAction]
+ cp BATTLEACTION_STRUGGLE
+ jr z, .do_it
+ cp BATTLEACTION_SWITCH1
+ ret nc
+
+.do_it
+ xor a
+ ld [wTurnEnded], a
+
+ ; Effect command checkturn is called for every move.
+ call CheckTurn
+
+ ld a, [wTurnEnded]
+ and a
+ ret nz
+
+ call UpdateMoveData
+
+ ; fallthrough
+
+DoMove:
+; Get the user's move effect.
+ ld a, BATTLE_VARS_MOVE_EFFECT
+ call GetBattleVar
+ ld c, a
+ ld b, 0
+ ld hl, MoveEffectsPointers
+ add hl, bc
+ add hl, bc
+ ld a, BANK(MoveEffectsPointers)
+ call GetFarHalfword
+
+ ld de, wBattleScriptBuffer
+
+.GetMoveEffect:
+ ld a, BANK(MoveEffects)
+ call GetFarByte
+ inc hl
+ ld [de], a
+ inc de
+ cp endmove_command
+ jr nz, .GetMoveEffect
+
+; Start at the first command.
+ ld hl, wBattleScriptBuffer
+ ld a, l
+ ld [wBattleScriptBufferAddress], a
+ ld a, h
+ ld [wBattleScriptBufferAddress + 1], a
+
+.ReadMoveEffectCommand:
+; ld a, [wBattleScriptBufferAddress++]
+ ld a, [wBattleScriptBufferAddress]
+ ld l, a
+ ld a, [wBattleScriptBufferAddress + 1]
+ ld h, a
+
+ ld a, [hli]
+
+ push af
+ ld a, l
+ ld [wBattleScriptBufferAddress], a
+ ld a, h
+ ld [wBattleScriptBufferAddress + 1], a
+ pop af
+
+; endturn_command (-2) is used to terminate branches without ending the read cycle.
+ cp endturn_command
+ ret nc
+
+; The rest of the commands (01-af) are read from BattleCommandPointers.
+ push bc
+ dec a
+ ld c, a
+ ld b, 0
+ ld hl, BattleCommandPointers
+ add hl, bc
+ add hl, bc
+ pop bc
+
+ ld a, BANK(BattleCommandPointers)
+ call GetFarHalfword
+
+ call .DoMoveEffectCommand
+
+ jr .ReadMoveEffectCommand
+
+.DoMoveEffectCommand:
+ jp hl
+
+CheckTurn:
+BattleCommand_CheckTurn:
+; checkturn
+
+; Repurposed as hardcoded turn handling. Useless as a command.
+
+; Move $ff immediately ends the turn.
+ ld a, BATTLE_VARS_MOVE
+ call GetBattleVar
+ inc a
+ jp z, EndTurn
+
+ xor a
+ ld [wAttackMissed], a
+ ld [wEffectFailed], a
+ ld [wKickCounter], a
+ ld [wAlreadyDisobeyed], a
+ ld [wAlreadyFailed], a
+ ld [wSomeoneIsRampaging], a
+
+ ld a, EFFECTIVE
+ ld [wTypeModifier], a
+
+ ldh a, [hBattleTurn]
+ and a
+ jp nz, CheckEnemyTurn
+
+CheckPlayerTurn:
+ ld hl, wPlayerSubStatus4
+ bit SUBSTATUS_RECHARGE, [hl]
+ jr z, .no_recharge
+
+ res SUBSTATUS_RECHARGE, [hl]
+ ld hl, MustRechargeText
+ call StdBattleTextbox
+ call CantMove
+ jp EndTurn
+
+.no_recharge
+
+ ld hl, wBattleMonStatus
+ ld a, [hl]
+ and SLP
+ jr z, .not_asleep
+
+ dec a
+ ld [wBattleMonStatus], a
+ and SLP
+ jr z, .woke_up
+
+ xor a
+ ld [wNumHits], a
+ ld de, ANIM_SLP
+ call FarPlayBattleAnimation
+ jr .fast_asleep
+
+.woke_up
+ ld hl, WokeUpText
+ call StdBattleTextbox
+ call CantMove
+ call UpdateBattleMonInParty
+ ld hl, UpdatePlayerHUD
+ call CallBattleCore
+ ld a, $1
+ ldh [hBGMapMode], a
+ ld hl, wPlayerSubStatus1
+ res SUBSTATUS_NIGHTMARE, [hl]
+ jr .not_asleep
+
+.fast_asleep
+ ld hl, FastAsleepText
+ call StdBattleTextbox
+
+ ; Snore and Sleep Talk bypass sleep.
+ ld a, [wCurPlayerMove]
+ cp SNORE
+ jr z, .not_asleep
+ cp SLEEP_TALK
+ jr z, .not_asleep
+
+ call CantMove
+ jp EndTurn
+
+.not_asleep
+
+ ld hl, wBattleMonStatus
+ bit FRZ, [hl]
+ jr z, .not_frozen
+
+ ; Flame Wheel and Sacred Fire thaw the user.
+ ld a, [wCurPlayerMove]
+ cp FLAME_WHEEL
+ jr z, .not_frozen
+ cp SACRED_FIRE
+ jr z, .not_frozen
+
+ ld hl, FrozenSolidText
+ call StdBattleTextbox
+
+ call CantMove
+ jp EndTurn
+
+.not_frozen
+
+ ld hl, wPlayerSubStatus3
+ bit SUBSTATUS_FLINCHED, [hl]
+ jr z, .not_flinched
+
+ res SUBSTATUS_FLINCHED, [hl]
+ ld hl, FlinchedText
+ call StdBattleTextbox
+
+ call CantMove
+ jp EndTurn
+
+.not_flinched
+
+ ld hl, wPlayerDisableCount
+ ld a, [hl]
+ and a
+ jr z, .not_disabled
+
+ dec a
+ ld [hl], a
+ and $f
+ jr nz, .not_disabled
+
+ ld [hl], a
+ ld [wDisabledMove], a
+ ld hl, DisabledNoMoreText
+ call StdBattleTextbox
+
+.not_disabled
+
+ ld a, [wPlayerSubStatus3]
+ add a
+ jr nc, .not_confused
+ ld hl, wPlayerConfuseCount
+ dec [hl]
+ jr nz, .confused
+
+ ld hl, wPlayerSubStatus3
+ res SUBSTATUS_CONFUSED, [hl]
+ ld hl, ConfusedNoMoreText
+ call StdBattleTextbox
+ jr .not_confused
+
+.confused
+ ld hl, IsConfusedText
+ call StdBattleTextbox
+ xor a
+ ld [wNumHits], a
+ ld de, ANIM_CONFUSED
+ call FarPlayBattleAnimation
+
+ ; 50% chance of hitting itself
+ call BattleRandom
+ cp 50 percent + 1
+ jr nc, .not_confused
+
+ ; clear confusion-dependent substatus
+ ld hl, wPlayerSubStatus3
+ ld a, [hl]
+ and 1 << SUBSTATUS_CONFUSED
+ ld [hl], a
+
+ call HitConfusion
+ call CantMove
+ jp EndTurn
+
+.not_confused
+
+ ld a, [wPlayerSubStatus1]
+ add a ; bit SUBSTATUS_ATTRACT
+ jr nc, .not_infatuated
+
+ ld hl, InLoveWithText
+ call StdBattleTextbox
+ xor a
+ ld [wNumHits], a
+ ld de, ANIM_IN_LOVE
+ call FarPlayBattleAnimation
+
+ ; 50% chance of infatuation
+ call BattleRandom
+ cp 50 percent + 1
+ jr c, .not_infatuated
+
+ ld hl, InfatuationText
+ call StdBattleTextbox
+ call CantMove
+ jp EndTurn
+
+.not_infatuated
+
+ ; We can't disable a move that doesn't exist.
+ ld a, [wDisabledMove]
+ and a
+ jr z, .no_disabled_move
+
+ ; Are we using the disabled move?
+ ld hl, wCurPlayerMove
+ cp [hl]
+ jr nz, .no_disabled_move
+
+ call MoveDisabled
+ call CantMove
+ jp EndTurn
+
+.no_disabled_move
+
+ ld hl, wBattleMonStatus
+ bit PAR, [hl]
+ ret z
+
+ ; 25% chance to be fully paralyzed
+ call BattleRandom
+ cp 25 percent
+ ret nc
+
+ ld hl, FullyParalyzedText
+ call StdBattleTextbox
+ call CantMove
+ jp EndTurn
+
+CantMove:
+ ld a, BATTLE_VARS_SUBSTATUS1
+ call GetBattleVarAddr
+ res SUBSTATUS_ROLLOUT, [hl]
+
+ ld a, BATTLE_VARS_SUBSTATUS3
+ call GetBattleVarAddr
+ ld a, [hl]
+ and $ff ^ (1 << SUBSTATUS_BIDE | 1 << SUBSTATUS_RAMPAGE | 1 << SUBSTATUS_CHARGED)
+ ld [hl], a
+
+ call ResetFuryCutterCount
+
+ ld a, BATTLE_VARS_MOVE_ANIM
+ call GetBattleVar
+ cp FLY
+ jr z, .fly_dig
+
+ cp DIG
+ ret nz
+
+.fly_dig
+ res SUBSTATUS_UNDERGROUND, [hl]
+ res SUBSTATUS_FLYING, [hl]
+ jp AppearUserRaiseSub
+
+OpponentCantMove:
+ call BattleCommand_SwitchTurn
+ call CantMove
+ jp BattleCommand_SwitchTurn
+
+CheckEnemyTurn:
+ ld hl, wEnemySubStatus4
+ bit SUBSTATUS_RECHARGE, [hl]
+ jr z, .no_recharge
+
+ res SUBSTATUS_RECHARGE, [hl]
+ ld hl, MustRechargeText
+ call StdBattleTextbox
+ call CantMove
+ jp EndTurn
+
+.no_recharge
+
+ ld hl, wEnemyMonStatus
+ ld a, [hl]
+ and SLP
+ jr z, .not_asleep
+
+ dec a
+ ld [wEnemyMonStatus], a
+ and a
+ jr z, .woke_up
+
+ ld hl, FastAsleepText
+ call StdBattleTextbox
+ xor a
+ ld [wNumHits], a
+ ld de, ANIM_SLP
+ call FarPlayBattleAnimation
+ jr .fast_asleep
+
+.woke_up
+ ld hl, WokeUpText
+ call StdBattleTextbox
+ call CantMove
+ call UpdateEnemyMonInParty
+ ld hl, UpdateEnemyHUD
+ call CallBattleCore
+ ld a, $1
+ ldh [hBGMapMode], a
+ ld hl, wEnemySubStatus1
+ res SUBSTATUS_NIGHTMARE, [hl]
+ jr .not_asleep
+
+.fast_asleep
+ ; Snore and Sleep Talk bypass sleep.
+ ld a, [wCurEnemyMove]
+ cp SNORE
+ jr z, .not_asleep
+ cp SLEEP_TALK
+ jr z, .not_asleep
+ call CantMove
+ jp EndTurn
+
+.not_asleep
+
+ ld hl, wEnemyMonStatus
+ bit FRZ, [hl]
+ jr z, .not_frozen
+
+ ; Flame Wheel and Sacred Fire thaw the user.
+ ld a, [wCurEnemyMove]
+ cp FLAME_WHEEL
+ jr z, .not_frozen
+ cp SACRED_FIRE
+ jr z, .not_frozen
+
+ ld hl, FrozenSolidText
+ call StdBattleTextbox
+ call CantMove
+ jp EndTurn
+
+.not_frozen
+
+ ld hl, wEnemySubStatus3
+ bit SUBSTATUS_FLINCHED, [hl]
+ jr z, .not_flinched
+
+ res SUBSTATUS_FLINCHED, [hl]
+ ld hl, FlinchedText
+ call StdBattleTextbox
+
+ call CantMove
+ jp EndTurn
+
+.not_flinched
+
+ ld hl, wEnemyDisableCount
+ ld a, [hl]
+ and a
+ jr z, .not_disabled
+
+ dec a
+ ld [hl], a
+ and $f
+ jr nz, .not_disabled
+
+ ld [hl], a
+ ld [wEnemyDisabledMove], a
+
+ ld hl, DisabledNoMoreText
+ call StdBattleTextbox
+
+.not_disabled
+
+ ld a, [wEnemySubStatus3]
+ add a ; bit SUBSTATUS_CONFUSED
+ jr nc, .not_confused
+
+ ld hl, wEnemyConfuseCount
+ dec [hl]
+ jr nz, .confused
+
+ ld hl, wEnemySubStatus3
+ res SUBSTATUS_CONFUSED, [hl]
+ ld hl, ConfusedNoMoreText
+ call StdBattleTextbox
+ jr .not_confused
+
+.confused
+ ld hl, IsConfusedText
+ call StdBattleTextbox
+
+ xor a
+ ld [wNumHits], a
+ ld de, ANIM_CONFUSED
+ call FarPlayBattleAnimation
+
+ ; 50% chance of hitting itself
+ call BattleRandom
+ cp 50 percent + 1
+ jr nc, .not_confused
+
+ ; clear confusion-dependent substatus
+ ld hl, wEnemySubStatus3
+ ld a, [hl]
+ and 1 << SUBSTATUS_CONFUSED
+ ld [hl], a
+
+ ld hl, HurtItselfText
+ call StdBattleTextbox
+
+ call HitSelfInConfusion
+ call BattleCommand_DamageCalc
+ call BattleCommand_LowerSub
+
+ xor a
+ ld [wNumHits], a
+
+ ; Flicker the monster pic unless flying or underground.
+ ld de, ANIM_HIT_CONFUSION
+ ld a, BATTLE_VARS_SUBSTATUS3_OPP
+ call GetBattleVar
+ and 1 << SUBSTATUS_FLYING | 1 << SUBSTATUS_UNDERGROUND
+ call z, PlayFXAnimID
+
+ ld c, TRUE
+ call DoEnemyDamage
+ call BattleCommand_RaiseSub
+ call CantMove
+ jp EndTurn
+
+.not_confused
+
+ ld a, [wEnemySubStatus1]
+ add a ; bit SUBSTATUS_ATTRACT
+ jr nc, .not_infatuated
+
+ ld hl, InLoveWithText
+ call StdBattleTextbox
+ xor a
+ ld [wNumHits], a
+ ld de, ANIM_IN_LOVE
+ call FarPlayBattleAnimation
+
+ ; 50% chance of infatuation
+ call BattleRandom
+ cp 50 percent + 1
+ jr c, .not_infatuated
+
+ ld hl, InfatuationText
+ call StdBattleTextbox
+ call CantMove
+ jp EndTurn
+
+.not_infatuated
+
+ ; We can't disable a move that doesn't exist.
+ ld a, [wEnemyDisabledMove]
+ and a
+ jr z, .no_disabled_move
+
+ ; Are we using the disabled move?
+ ld hl, wCurEnemyMove
+ cp [hl]
+ jr nz, .no_disabled_move
+
+ call MoveDisabled
+
+ call CantMove
+ jp EndTurn
+
+.no_disabled_move
+
+ ld hl, wEnemyMonStatus
+ bit PAR, [hl]
+ ret z
+
+ ; 25% chance to be fully paralyzed
+ call BattleRandom
+ cp 25 percent
+ ret nc
+
+ ld hl, FullyParalyzedText
+ call StdBattleTextbox
+ call CantMove
+
+ ; fallthrough
+
+EndTurn:
+ ld a, $1
+ ld [wTurnEnded], a
+ jp ResetDamage
+
+MoveDisabled:
+ ; Make sure any charged moves fail
+ ld a, BATTLE_VARS_SUBSTATUS3
+ call GetBattleVarAddr
+ res SUBSTATUS_CHARGED, [hl]
+
+ ld a, BATTLE_VARS_MOVE
+ call GetBattleVar
+ ld [wNamedObjectIndexBuffer], a
+ call GetMoveName
+
+ ld hl, DisabledMoveText
+ jp StdBattleTextbox
+
+HitConfusion:
+ ld hl, HurtItselfText
+ call StdBattleTextbox
+
+ xor a
+ ld [wCriticalHit], a
+
+ call HitSelfInConfusion
+ call BattleCommand_DamageCalc
+ call BattleCommand_LowerSub
+
+ xor a
+ ld [wNumHits], a
+
+ ; Flicker the monster pic unless flying or underground.
+ ld de, ANIM_HIT_CONFUSION
+ ld a, BATTLE_VARS_SUBSTATUS3_OPP
+ call GetBattleVar
+ and 1 << SUBSTATUS_FLYING | 1 << SUBSTATUS_UNDERGROUND
+ call z, PlayFXAnimID
+
+ ld hl, UpdatePlayerHUD
+ call CallBattleCore
+ ld a, $1
+ ldh [hBGMapMode], a
+ ld c, TRUE
+ call DoPlayerDamage
+ jp BattleCommand_RaiseSub
+
+BattleCommand_CheckObedience:
+; checkobedience
+
+ ; Enemy can't disobey
+ ldh a, [hBattleTurn]
+ and a
+ ret nz
+
+ call CheckUserIsCharging
+ ret nz
+
+ ; If we've already checked this turn
+ ld a, [wAlreadyDisobeyed]
+ and a
+ ret nz
+
+ xor a
+ ld [wAlreadyDisobeyed], a
+
+ ; No obedience in link battles
+ ; (since no handling exists for enemy)
+ ld a, [wLinkMode]
+ and a
+ ret nz
+
+ ; If the monster's id doesn't match the player's,
+ ; some conditions need to be met.
+ ld a, MON_ID
+ call BattlePartyAttr
+
+ ld a, [wPlayerID]
+ cp [hl]
+ jr nz, .obeylevel
+ inc hl
+ ld a, [wPlayerID + 1]
+ cp [hl]
+ ret z
+
+.obeylevel
+ ; The maximum obedience level is constrained by owned badges:
+ ld hl, wJohtoBadges
+
+ ; risingbadge
+ bit RISINGBADGE, [hl]
+ ld a, MAX_LEVEL + 1
+ jr nz, .getlevel
+
+ ; stormbadge
+ bit STORMBADGE, [hl]
+ ld a, 70
+ jr nz, .getlevel
+
+ ; fogbadge
+ bit FOGBADGE, [hl]
+ ld a, 50
+ jr nz, .getlevel
+
+ ; hivebadge
+ bit HIVEBADGE, [hl]
+ ld a, 30
+ jr nz, .getlevel
+
+ ; no badges
+ ld a, 10
+
+.getlevel
+; c = obedience level
+; d = monster level
+; b = c + d
+
+ ld b, a
+ ld c, a
+
+ ld a, [wBattleMonLevel]
+ ld d, a
+
+ add b
+ ld b, a
+
+; No overflow (this should never happen)
+ jr nc, .checklevel
+ ld b, $ff
+
+.checklevel
+; If the monster's level is lower than the obedience level, it will obey.
+ ld a, c
+ cp d
+ ret nc
+
+; Random number from 0 to obedience level + monster level
+.rand1
+ call BattleRandom
+ swap a
+ cp b
+ jr nc, .rand1
+
+; The higher above the obedience level the monster is,
+; the more likely it is to disobey.
+ cp c
+ ret c
+
+; Sleep-only moves have separate handling, and a higher chance of
+; being ignored. Lazy monsters like their sleep.
+ call IgnoreSleepOnly
+ ret c
+
+; Another random number from 0 to obedience level + monster level
+.rand2
+ call BattleRandom
+ cp b
+ jr nc, .rand2
+
+; A second chance.
+ cp c
+ jr c, .UseInstead
+
+; No hope of using a move now.
+
+; b = number of levels the monster is above the obedience level
+ ld a, d
+ sub c
+ ld b, a
+
+; The chance of napping is the difference out of 256.
+ call BattleRandom
+ swap a
+ sub b
+ jr c, .Nap
+
+; The chance of not hitting itself is the same.
+ cp b
+ jr nc, .DoNothing
+
+ ld hl, WontObeyText
+ call StdBattleTextbox
+ call HitConfusion
+ jp .EndDisobedience
+
+.Nap:
+ call BattleRandom
+ add a
+ swap a
+ and SLP
+ jr z, .Nap
+
+ ld [wBattleMonStatus], a
+
+ ld hl, BeganToNapText
+ jr .Print
+
+.DoNothing:
+ ; 4 random choices
+ call BattleRandom
+ and %11
+
+ ld hl, LoafingAroundText
+ and a ; 0
+ jr z, .Print
+
+ ld hl, WontObeyText
+ dec a ; 1
+ jr z, .Print
+
+ ld hl, TurnedAwayText
+ dec a ; 2
+ jr z, .Print
+
+ ld hl, IgnoredOrdersText
+
+.Print:
+ call StdBattleTextbox
+ jp .EndDisobedience
+
+.UseInstead:
+; Can't use another move if the monster only has one!
+ ld a, [wBattleMonMoves + 1]
+ and a
+ jr z, .DoNothing
+
+; Don't bother trying to handle Disable.
+ ld a, [wDisabledMove]
+ and a
+ jr nz, .DoNothing
+
+ ld hl, wBattleMonPP
+ ld de, wBattleMonMoves
+ ld b, 0
+ ld c, NUM_MOVES
+
+.GetTotalPP:
+ ld a, [hli]
+ and PP_MASK
+ add b
+ ld b, a
+
+ dec c
+ jr z, .CheckMovePP
+
+; Stop at undefined moves.
+ inc de
+ ld a, [de]
+ and a
+ jr nz, .GetTotalPP
+
+.CheckMovePP:
+ ld hl, wBattleMonPP
+ ld a, [wCurMoveNum]
+ ld e, a
+ ld d, 0
+ add hl, de
+
+; Can't use another move if only one move has PP.
+ ld a, [hl]
+ and PP_MASK
+ cp b
+ jr z, .DoNothing
+
+; Make sure we can actually use the move once we get there.
+ ld a, 1
+ ld [wAlreadyDisobeyed], a
+
+ ld a, [w2DMenuNumRows]
+ ld b, a
+
+; Save the move we originally picked for afterward.
+ ld a, [wCurMoveNum]
+ ld c, a
+ push af
+
+.RandomMove:
+ call BattleRandom
+ maskbits NUM_MOVES
+
+ cp b
+ jr nc, .RandomMove
+
+; Not the move we were trying to use.
+ cp c
+ jr z, .RandomMove
+
+; Make sure it has PP.
+ ld [wCurMoveNum], a
+ ld hl, wBattleMonPP
+ ld e, a
+ ld d, 0
+ add hl, de
+ ld a, [hl]
+ and PP_MASK
+ jr z, .RandomMove
+
+; Use it.
+ ld a, [wCurMoveNum]
+ ld c, a
+ ld b, 0
+ ld hl, wBattleMonMoves
+ add hl, bc
+ ld a, [hl]
+ ld [wCurPlayerMove], a
+
+ call SetPlayerTurn
+ call UpdateMoveData
+ call DoMove
+
+; Restore original move choice.
+ pop af
+ ld [wCurMoveNum], a
+
+.EndDisobedience:
+ xor a
+ ld [wLastPlayerMove], a
+ ld [wLastPlayerCounterMove], a
+
+ ; Break Encore too.
+ ld hl, wPlayerSubStatus5
+ res SUBSTATUS_ENCORED, [hl]
+ xor a
+ ld [wPlayerEncoreCount], a
+
+ jp EndMoveEffect
+
+IgnoreSleepOnly:
+ ld a, BATTLE_VARS_MOVE_ANIM
+ call GetBattleVar
+
+ ; Snore and Sleep Talk bypass sleep.
+ cp SNORE
+ jr z, .CheckSleep
+ cp SLEEP_TALK
+ jr z, .CheckSleep
+ and a
+ ret
+
+.CheckSleep:
+ ld a, BATTLE_VARS_STATUS
+ call GetBattleVar
+ and SLP
+ ret z
+
+; 'ignored orders…sleeping!'
+ ld hl, IgnoredSleepingText
+ call StdBattleTextbox
+
+ call EndMoveEffect
+
+ scf
+ ret
+
+INCLUDE "engine/battle/used_move_text.asm"
+
+BattleCommand_DoTurn:
+ call CheckUserIsCharging
+ ret nz
+
+ ld hl, wBattleMonPP
+ ld de, wPlayerSubStatus3
+ ld bc, wPlayerTurnsTaken
+
+ ldh a, [hBattleTurn]
+ and a
+ jr z, .proceed
+
+ ld hl, wEnemyMonPP
+ ld de, wEnemySubStatus3
+ ld bc, wEnemyTurnsTaken
+
+.proceed
+
+; If we've gotten this far, this counts as a turn.
+ ld a, [bc]
+ inc a
+ ld [bc], a
+
+ ld a, BATTLE_VARS_MOVE
+ call GetBattleVar
+ cp STRUGGLE
+ ret z
+
+ ld a, [de]
+ and 1 << SUBSTATUS_IN_LOOP | 1 << SUBSTATUS_RAMPAGE | 1 << SUBSTATUS_BIDE
+ ret nz
+
+ call .consume_pp
+ ld a, b
+ and a
+ jp nz, EndMoveEffect
+
+ ; SubStatus5
+ inc de
+ inc de
+
+ ld a, [de]
+ bit SUBSTATUS_TRANSFORMED, a
+ ret nz
+
+ ldh a, [hBattleTurn]
+ and a
+
+ ld hl, wPartyMon1PP
+ ld a, [wCurBattleMon]
+ jr z, .player
+
+; mimic this part entirely if wildbattle
+ ld a, [wBattleMode]
+ dec a
+ jr z, .wild
+
+ ld hl, wOTPartyMon1PP
+ ld a, [wCurOTMon]
+
+.player
+ call GetPartyLocation
+ push hl
+ call CheckMimicUsed
+ pop hl
+ ret c
+
+.consume_pp
+ ldh a, [hBattleTurn]
+ and a
+ ld a, [wCurMoveNum]
+ jr z, .okay
+ ld a, [wCurEnemyMoveNum]
+
+.okay
+ ld c, a
+ ld b, 0
+ add hl, bc
+ ld a, [hl]
+ and PP_MASK
+ jr z, .out_of_pp
+ dec [hl]
+ ld b, 0
+ ret
+
+.wild
+ ld hl, wEnemyMonMoves
+ ld a, [wCurEnemyMoveNum]
+ ld c, a
+ ld b, 0
+ add hl, bc
+ ld a, [hl]
+ cp MIMIC
+ jr z, .mimic
+ ld hl, wWildMonMoves
+ add hl, bc
+ ld a, [hl]
+ cp MIMIC
+ ret z
+
+.mimic
+ ld hl, wWildMonPP
+ call .consume_pp
+ ret
+
+.out_of_pp
+ call BattleCommand_MoveDelay
+; 'has no pp left for [move]'
+ ld hl, HasNoPPLeftText
+; get move effect
+ ld a, BATTLE_VARS_MOVE_EFFECT
+ call GetBattleVar
+; continuous?
+ cp EFFECT_RAZOR_WIND
+ jr z, .print
+
+ cp EFFECT_SKY_ATTACK
+ jr z, .print
+
+ cp EFFECT_SKULL_BASH
+ jr z, .print
+
+ cp EFFECT_SOLARBEAM
+ jr z, .print
+
+ cp EFFECT_FLY
+ jr z, .print
+
+ cp EFFECT_ROLLOUT
+ jr z, .print
+
+ cp EFFECT_BIDE
+ jr z, .print
+
+ cp EFFECT_RAMPAGE
+ jr z, .print
+
+; 'but no pp is left for the move'
+ ld hl, NoPPLeftText
+.print
+ call StdBattleTextbox
+ ld b, 1
+ ret
+
+CheckMimicUsed:
+ ldh a, [hBattleTurn]
+ and a
+ ld a, [wCurMoveNum]
+ jr z, .player
+ ld a, [wCurEnemyMoveNum]
+
+.player
+ ld c, a
+ ld a, MON_MOVES
+ call UserPartyAttr
+
+ ld a, BATTLE_VARS_MOVE
+ call GetBattleVar
+ cp MIMIC
+ jr z, .mimic
+;
+ ld b, 0
+ add hl, bc
+ ld a, [hl]
+ cp MIMIC
+ jr nz, .mimic
+
+ scf
+ ret
+
+.mimic
+ and a
+ ret
+
+BattleCommand_Critical:
+; critical
+
+; Determine whether this attack's hit will be critical.
+
+ xor a
+ ld [wCriticalHit], a
+
+ ld a, BATTLE_VARS_MOVE_POWER
+ call GetBattleVar
+ and a
+ ret z
+
+ ldh a, [hBattleTurn]
+ and a
+ ld hl, wEnemyMonItem
+ ld a, [wEnemyMonSpecies]
+ jr nz, .Item
+ ld hl, wBattleMonItem
+ ld a, [wBattleMonSpecies]
+
+.Item:
+ ld c, 0
+
+ cp CHANSEY
+ jr nz, .Farfetchd
+ ld a, [hl]
+ cp LUCKY_PUNCH
+ jr nz, .FocusEnergy
+
+; +2 critical level
+ ld c, 2
+ jr .Tally
+
+.Farfetchd:
+ cp FARFETCH_D
+ jr nz, .FocusEnergy
+ ld a, [hl]
+ cp STICK
+ jr nz, .FocusEnergy
+
+; +2 critical level
+ ld c, 2
+ jr .Tally
+
+.FocusEnergy:
+ ld a, BATTLE_VARS_SUBSTATUS4
+ call GetBattleVar
+ bit SUBSTATUS_FOCUS_ENERGY, a
+ jr z, .CheckCritical
+
+; +1 critical level
+ inc c
+
+.CheckCritical:
+ ld a, BATTLE_VARS_MOVE_ANIM
+ call GetBattleVar
+ ld de, 1
+ ld hl, CriticalHitMoves
+ push bc
+ call IsInArray
+ pop bc
+ jr nc, .ScopeLens
+
+; +2 critical level
+ inc c
+ inc c
+
+.ScopeLens:
+ push bc
+ call GetUserItem
+ ld a, b
+ cp HELD_CRITICAL_UP ; Increased critical chance. Only Scope Lens has this.
+ pop bc
+ jr nz, .Tally
+
+; +1 critical level
+ inc c
+
+.Tally:
+ ld hl, CriticalHitChances
+ ld b, 0
+ add hl, bc
+ call BattleRandom
+ cp [hl]
+ ret nc
+ ld a, 1
+ ld [wCriticalHit], a
+ ret
+
+INCLUDE "data/moves/critical_hit_moves.asm"
+
+INCLUDE "data/battle/critical_hit_chances.asm"
+
+INCLUDE "engine/battle/move_effects/triple_kick.asm"
+
+BattleCommand_Stab:
+; STAB = Same Type Attack Bonus
+ ld a, BATTLE_VARS_MOVE_ANIM
+ call GetBattleVar
+ cp STRUGGLE
+ ret z
+
+ ld hl, wBattleMonType1
+ ld a, [hli]
+ ld b, a
+ ld c, [hl]
+ ld hl, wEnemyMonType1
+ ld a, [hli]
+ ld d, a
+ ld e, [hl]
+
+ ldh a, [hBattleTurn]
+ and a
+ jr z, .go ; Who Attacks and who Defends
+
+ ld hl, wEnemyMonType1
+ ld a, [hli]
+ ld b, a
+ ld c, [hl]
+ ld hl, wBattleMonType1
+ ld a, [hli]
+ ld d, a
+ ld e, [hl]
+
+.go
+ ld a, BATTLE_VARS_MOVE_TYPE
+ call GetBattleVarAddr
+ ld [wCurType], a
+
+ push hl
+ push de
+ push bc
+ farcall DoWeatherModifiers
+ pop bc
+ pop de
+ pop hl
+
+ push de
+ push bc
+ farcall DoBadgeTypeBoosts
+ pop bc
+ pop de
+
+ ld a, [wCurType]
+ cp b
+ jr z, .stab
+ cp c
+ jr z, .stab
+
+ jr .SkipStab
+
+.stab
+ ld hl, wCurDamage + 1
+ ld a, [hld]
+ ld h, [hl]
+ ld l, a
+
+ ld b, h
+ ld c, l
+ srl b
+ rr c
+ add hl, bc
+
+ ld a, h
+ ld [wCurDamage], a
+ ld a, l
+ ld [wCurDamage + 1], a
+
+ ld hl, wTypeModifier
+ set 7, [hl]
+
+.SkipStab:
+ ld a, BATTLE_VARS_MOVE_TYPE
+ call GetBattleVar
+ ld b, a
+ ld hl, TypeMatchups
+
+.TypesLoop:
+ ld a, [hli]
+
+ cp -1
+ jr z, .end
+
+ ; foresight
+ cp -2
+ jr nz, .SkipForesightCheck
+ ld a, BATTLE_VARS_SUBSTATUS1_OPP
+ call GetBattleVar
+ bit SUBSTATUS_IDENTIFIED, a
+ jr nz, .end
+
+ jr .TypesLoop
+
+.SkipForesightCheck:
+ cp b
+ jr nz, .SkipType
+ ld a, [hl]
+ cp d
+ jr z, .GotMatchup
+ cp e
+ jr z, .GotMatchup
+ jr .SkipType
+
+.GotMatchup:
+ push hl
+ push bc
+ inc hl
+ ld a, [wTypeModifier]
+ and %10000000
+ ld b, a
+; If the target is immune to the move, treat it as a miss and calculate the damage as 0
+ ld a, [hl]
+ and a
+ jr nz, .NotImmune
+ inc a
+ ld [wAttackMissed], a
+ xor a
+.NotImmune:
+ ldh [hMultiplier], a
+ add b
+ ld [wTypeModifier], a
+
+ xor a
+ ldh [hMultiplicand + 0], a
+
+ ld hl, wCurDamage
+ ld a, [hli]
+ ldh [hMultiplicand + 1], a
+ ld a, [hld]
+ ldh [hMultiplicand + 2], a
+
+ call Multiply
+
+ ldh a, [hProduct + 1]
+ ld b, a
+ ldh a, [hProduct + 2]
+ or b
+ ld b, a
+ ldh a, [hProduct + 3]
+ or b
+ jr z, .ok ; This is a very convoluted way to get back that we've essentially dealt no damage.
+
+; Take the product and divide it by 10.
+ ld a, 10
+ ldh [hDivisor], a
+ ld b, 4
+ call Divide
+ ldh a, [hQuotient + 2]
+ ld b, a
+ ldh a, [hQuotient + 3]
+ or b
+ jr nz, .ok
+
+ ld a, 1
+ ldh [hMultiplicand + 2], a
+
+.ok
+ ldh a, [hMultiplicand + 1]
+ ld [hli], a
+ ldh a, [hMultiplicand + 2]
+ ld [hl], a
+ pop bc
+ pop hl
+
+.SkipType:
+ inc hl
+ inc hl
+ jr .TypesLoop
+
+.end
+ call BattleCheckTypeMatchup
+ ld a, [wTypeMatchup]
+ ld b, a
+ ld a, [wTypeModifier]
+ and %10000000
+ or b
+ ld [wTypeModifier], a
+ ret
+
+BattleCheckTypeMatchup:
+ ld hl, wEnemyMonType1
+ ldh a, [hBattleTurn]
+ and a
+ jr z, CheckTypeMatchup
+ ld hl, wBattleMonType1
+CheckTypeMatchup:
+; There is an incorrect assumption about this function made in the AI related code: when
+; the AI calls CheckTypeMatchup (not BattleCheckTypeMatchup), it assumes that placing the
+; offensive type in a will make this function do the right thing. Since a is overwritten,
+; this assumption is incorrect. A simple fix would be to load the move type for the
+; current move into a in BattleCheckTypeMatchup, before falling through, which is
+; consistent with how the rest of the code assumes this code works like.
+ push hl
+ push de
+ push bc
+ ld a, BATTLE_VARS_MOVE_TYPE
+ call GetBattleVar
+ ld d, a
+ ld b, [hl]
+ inc hl
+ ld c, [hl]
+ ld a, 10 ; 1.0
+ ld [wTypeMatchup], a
+ ld hl, TypeMatchups
+.TypesLoop:
+ ld a, [hli]
+ cp -1
+ jr z, .End
+ cp -2
+ jr nz, .Next
+ ld a, BATTLE_VARS_SUBSTATUS1_OPP
+ call GetBattleVar
+ bit SUBSTATUS_IDENTIFIED, a
+ jr nz, .End
+ jr .TypesLoop
+
+.Next:
+ cp d
+ jr nz, .Nope
+ ld a, [hli]
+ cp b
+ jr z, .Yup
+ cp c
+ jr z, .Yup
+ jr .Nope2
+
+.Nope:
+ inc hl
+.Nope2:
+ inc hl
+ jr .TypesLoop
+
+.Yup:
+ xor a
+ ldh [hDividend + 0], a
+ ldh [hMultiplicand + 0], a
+ ldh [hMultiplicand + 1], a
+ ld a, [hli]
+ ldh [hMultiplicand + 2], a
+ ld a, [wTypeMatchup]
+ ldh [hMultiplier], a
+ call Multiply
+ ld a, 10
+ ldh [hDivisor], a
+ push bc
+ ld b, 4
+ call Divide
+ pop bc
+ ldh a, [hQuotient + 3]
+ ld [wTypeMatchup], a
+ jr .TypesLoop
+
+.End:
+ pop bc
+ pop de
+ pop hl
+ ret
+
+BattleCommand_ResetTypeMatchup:
+; Reset the type matchup multiplier to 1.0, if the type matchup is not 0.
+; If there is immunity in play, the move automatically misses.
+ call BattleCheckTypeMatchup
+ ld a, [wTypeMatchup]
+ and a
+ ld a, 10 ; 1.0
+ jr nz, .reset
+ call ResetDamage
+ xor a
+ ld [wTypeModifier], a
+ inc a
+ ld [wAttackMissed], a
+ ret
+
+.reset
+ ld [wTypeMatchup], a
+ ret
+
+INCLUDE "engine/battle/ai/switch.asm"
+
+INCLUDE "data/types/type_matchups.asm"
+
+BattleCommand_DamageVariation:
+; damagevariation
+
+; Modify the damage spread between 85% and 100%.
+
+; Because of the method of division the probability distribution
+; is not consistent. This makes the highest damage multipliers
+; rarer than normal.
+
+; No point in reducing 1 or 0 damage.
+ ld hl, wCurDamage
+ ld a, [hli]
+ and a
+ jr nz, .go
+ ld a, [hl]
+ cp 2
+ ret c
+
+.go
+; Start with the maximum damage.
+ xor a
+ ldh [hMultiplicand + 0], a
+ dec hl
+ ld a, [hli]
+ ldh [hMultiplicand + 1], a
+ ld a, [hl]
+ ldh [hMultiplicand + 2], a
+
+; Multiply by 85-100%...
+.loop
+ call BattleRandom
+ rrca
+ cp 85 percent + 1
+ jr c, .loop
+
+ ldh [hMultiplier], a
+ call Multiply
+
+; ...divide by 100%...
+ ld a, $ff ; 100%
+ ldh [hDivisor], a
+ ld b, $4
+ call Divide
+
+; ...to get .85-1.00x damage.
+ ldh a, [hQuotient + 2]
+ ld hl, wCurDamage
+ ld [hli], a
+ ldh a, [hQuotient + 3]
+ ld [hl], a
+ ret
+
+BattleCommand_CheckHit:
+; checkhit
+
+ call .DreamEater
+ jp z, .Miss
+
+ call .Protect
+ jp nz, .Miss
+
+ call .DrainSub
+ jp z, .Miss
+
+ call .LockOn
+ ret nz
+
+ call .FlyDigMoves
+ jp nz, .Miss
+
+ call .ThunderRain
+ ret z
+
+ call .XAccuracy
+ ret nz
+
+ ; Perfect-accuracy moves
+ ld a, BATTLE_VARS_MOVE_EFFECT
+ call GetBattleVar
+ cp EFFECT_ALWAYS_HIT
+ ret z
+
+ call .StatModifiers
+
+ ld a, [wPlayerMoveStruct + MOVE_ACC]
+ ld b, a
+ ldh a, [hBattleTurn]
+ and a
+ jr z, .BrightPowder
+ ld a, [wEnemyMoveStruct + MOVE_ACC]
+ ld b, a
+
+.BrightPowder:
+ push bc
+ call GetOpponentItem
+ ld a, b
+ cp HELD_BRIGHTPOWDER
+ ld a, c ; % miss
+ pop bc
+ jr nz, .skip_brightpowder
+
+ ld c, a
+ ld a, b
+ sub c
+ ld b, a
+ jr nc, .skip_brightpowder
+ ld b, 0
+
+.skip_brightpowder
+ ld a, b
+ cp -1
+ jr z, .Hit
+
+ call BattleRandom
+ cp b
+ jr nc, .Miss
+
+.Hit:
+ ret
+
+.Miss:
+; Keep the damage value intact if we're using (Hi) Jump Kick.
+ ld a, BATTLE_VARS_MOVE_EFFECT
+ call GetBattleVar
+ cp EFFECT_JUMP_KICK
+ jr z, .Missed
+ call ResetDamage
+
+.Missed:
+ ld a, 1
+ ld [wAttackMissed], a
+ ret
+
+.DreamEater:
+; Return z if we're trying to eat the dream of
+; a monster that isn't sleeping.
+ ld a, BATTLE_VARS_MOVE_EFFECT
+ call GetBattleVar
+ cp EFFECT_DREAM_EATER
+ ret nz
+
+ ld a, BATTLE_VARS_STATUS_OPP
+ call GetBattleVar
+ and SLP
+ ret
+
+.Protect:
+; Return nz if the opponent is protected.
+ ld a, BATTLE_VARS_SUBSTATUS1_OPP
+ call GetBattleVar
+ bit SUBSTATUS_PROTECT, a
+ ret z
+
+ ld c, 40
+ call DelayFrames
+
+; 'protecting itself!'
+ ld hl, ProtectingItselfText
+ call StdBattleTextbox
+
+ ld c, 40
+ call DelayFrames
+
+ ld a, 1
+ and a
+ ret
+
+.LockOn:
+; Return nz if we are locked-on and aren't trying to use Earthquake,
+; Fissure or Magnitude on a monster that is flying.
+ ld a, BATTLE_VARS_SUBSTATUS5_OPP
+ call GetBattleVarAddr
+ bit SUBSTATUS_LOCK_ON, [hl]
+ res SUBSTATUS_LOCK_ON, [hl]
+ ret z
+
+ ld a, BATTLE_VARS_SUBSTATUS3_OPP
+ call GetBattleVar
+ bit SUBSTATUS_FLYING, a
+ jr z, .LockedOn
+
+ ld a, BATTLE_VARS_MOVE_ANIM
+ call GetBattleVar
+
+ cp EARTHQUAKE
+ ret z
+ cp FISSURE
+ ret z
+ cp MAGNITUDE
+ ret z
+
+.LockedOn:
+ ld a, 1
+ and a
+ ret
+
+.DrainSub:
+; Return z if using an HP drain move on a substitute.
+ call CheckSubstituteOpp
+ jr z, .not_draining_sub
+
+ ld a, BATTLE_VARS_MOVE_EFFECT
+ call GetBattleVar
+
+ cp EFFECT_LEECH_HIT
+ ret z
+ cp EFFECT_DREAM_EATER
+ ret z
+
+.not_draining_sub
+ ld a, 1
+ and a
+ ret
+
+.FlyDigMoves:
+; Check for moves that can hit underground/flying opponents.
+; Return z if the current move can hit the opponent.
+
+ ld a, BATTLE_VARS_SUBSTATUS3_OPP
+ call GetBattleVar
+ and 1 << SUBSTATUS_FLYING | 1 << SUBSTATUS_UNDERGROUND
+ ret z
+
+ bit SUBSTATUS_FLYING, a
+ jr z, .DigMoves
+
+ ld a, BATTLE_VARS_MOVE_ANIM
+ call GetBattleVar
+
+ cp GUST
+ ret z
+ cp WHIRLWIND
+ ret z
+ cp THUNDER
+ ret z
+ cp TWISTER
+ ret
+
+.DigMoves:
+ ld a, BATTLE_VARS_MOVE_ANIM
+ call GetBattleVar
+
+ cp EARTHQUAKE
+ ret z
+ cp FISSURE
+ ret z
+ cp MAGNITUDE
+ ret
+
+.ThunderRain:
+; Return z if the current move always hits in rain, and it is raining.
+ ld a, BATTLE_VARS_MOVE_EFFECT
+ call GetBattleVar
+ cp EFFECT_THUNDER
+ ret nz
+
+ ld a, [wBattleWeather]
+ cp WEATHER_RAIN
+ ret
+
+.XAccuracy:
+ ld a, BATTLE_VARS_SUBSTATUS4
+ call GetBattleVar
+ bit SUBSTATUS_X_ACCURACY, a
+ ret
+
+.StatModifiers:
+ ldh a, [hBattleTurn]
+ and a
+
+ ; load the user's accuracy into b and the opponent's evasion into c.
+ ld hl, wPlayerMoveStruct + MOVE_ACC
+ ld a, [wPlayerAccLevel]
+ ld b, a
+ ld a, [wEnemyEvaLevel]
+ ld c, a
+
+ jr z, .got_acc_eva
+
+ ld hl, wEnemyMoveStruct + MOVE_ACC
+ ld a, [wEnemyAccLevel]
+ ld b, a
+ ld a, [wPlayerEvaLevel]
+ ld c, a
+
+.got_acc_eva
+ cp b
+ jr c, .skip_foresight_check
+
+ ; if the target's evasion is greater than the user's accuracy,
+ ; check the target's foresight status
+ ld a, BATTLE_VARS_SUBSTATUS1_OPP
+ call GetBattleVar
+ bit SUBSTATUS_IDENTIFIED, a
+ ret nz
+
+.skip_foresight_check
+ ; subtract evasion from 14
+ ld a, MAX_STAT_LEVEL + 1
+ sub c
+ ld c, a
+ ; store the base move accuracy for math ops
+ xor a
+ ldh [hMultiplicand + 0], a
+ ldh [hMultiplicand + 1], a
+ ld a, [hl]
+ ldh [hMultiplicand + 2], a
+ push hl
+ ld d, 2 ; do this twice, once for the user's accuracy and once for the target's evasion
+
+.accuracy_loop
+ ; look up the multiplier from the table
+ push bc
+ ld hl, AccuracyLevelMultipliers
+ dec b
+ sla b
+ ld c, b
+ ld b, 0
+ add hl, bc
+ pop bc
+ ; multiply by the first byte in that row...
+ ld a, [hli]
+ ldh [hMultiplier], a
+ call Multiply
+ ; ... and divide by the second byte
+ ld a, [hl]
+ ldh [hDivisor], a
+ ld b, 4
+ call Divide
+ ; minimum accuracy is $0001
+ ldh a, [hQuotient + 3]
+ ld b, a
+ ldh a, [hQuotient + 2]
+ or b
+ jr nz, .min_accuracy
+ ldh [hQuotient + 2], a
+ ld a, 1
+ ldh [hQuotient + 3], a
+
+.min_accuracy
+ ; do the same thing to the target's evasion
+ ld b, c
+ dec d
+ jr nz, .accuracy_loop
+
+ ; if the result is more than 2 bytes, max out at 100%
+ ldh a, [hQuotient + 2]
+ and a
+ ldh a, [hQuotient + 3]
+ jr z, .finish_accuracy
+ ld a, $ff
+
+.finish_accuracy
+ pop hl
+ ld [hl], a
+ ret
+
+INCLUDE "data/battle/accuracy_multipliers.asm"
+
+BattleCommand_EffectChance:
+; effectchance
+
+ xor a
+ ld [wEffectFailed], a
+ call CheckSubstituteOpp
+ jr nz, .failed
+
+ push hl
+ ld hl, wPlayerMoveStruct + MOVE_CHANCE
+ ldh a, [hBattleTurn]
+ and a
+ jr z, .got_move_chance
+ ld hl, wEnemyMoveStruct + MOVE_CHANCE
+.got_move_chance
+
+ ; BUG: 1/256 chance to fail even for a 100% effect chance,
+ ; since carry is not set if BattleRandom == [hl] == 255
+ call BattleRandom
+ cp [hl]
+ pop hl
+ ret c
+
+.failed
+ ld a, 1
+ ld [wEffectFailed], a
+ and a
+ ret
+
+BattleCommand_LowerSub:
+; lowersub
+
+ ld a, BATTLE_VARS_SUBSTATUS4
+ call GetBattleVar
+ bit SUBSTATUS_SUBSTITUTE, a
+ ret z
+
+ ld a, BATTLE_VARS_SUBSTATUS3
+ call GetBattleVar
+ bit SUBSTATUS_CHARGED, a
+ jr nz, .already_charged
+
+ ld a, BATTLE_VARS_MOVE_EFFECT
+ call GetBattleVar
+ cp EFFECT_RAZOR_WIND
+ jr z, .charge_turn
+ cp EFFECT_SKY_ATTACK
+ jr z, .charge_turn
+ cp EFFECT_SKULL_BASH
+ jr z, .charge_turn
+ cp EFFECT_SOLARBEAM
+ jr z, .charge_turn
+ cp EFFECT_FLY
+ jr z, .charge_turn
+
+.already_charged
+ call .Rampage
+ jr z, .charge_turn
+
+ call CheckUserIsCharging
+ ret nz
+
+.charge_turn
+ ; check battle scene
+ ld a, [wOptions]
+ add a
+ jr c, .mimic_anims
+
+ xor a
+ ld [wNumHits], a
+ ld [wFXAnimID + 1], a
+ inc a
+ ld [wKickCounter], a
+ ld a, SUBSTITUTE
+ jp LoadAnim
+
+.mimic_anims
+ call BattleCommand_LowerSubNoAnim
+ jp BattleCommand_MoveDelay
+
+.Rampage:
+ ld a, BATTLE_VARS_MOVE_EFFECT
+ call GetBattleVar
+ cp EFFECT_ROLLOUT
+ jr z, .rollout_rampage
+ cp EFFECT_RAMPAGE
+ jr z, .rollout_rampage
+
+ ld a, 1
+ and a
+ ret
+
+.rollout_rampage
+ ld a, [wSomeoneIsRampaging]
+ and a
+ ld a, 0
+ ld [wSomeoneIsRampaging], a
+ ret
+
+BattleCommand_MoveAnim:
+; moveanim
+ call BattleCommand_LowerSub
+ call BattleCommand_MoveAnimNoSub
+ jp BattleCommand_RaiseSub
+
+BattleCommand_MoveAnimNoSub:
+ ld a, [wAttackMissed]
+ and a
+ jp nz, BattleCommand_MoveDelay
+
+ ldh a, [hBattleTurn]
+ and a
+ ld de, wPlayerRolloutCount
+ ld a, BATTLEANIM_ENEMY_DAMAGE
+ jr z, .got_rollout_count
+ ld de, wEnemyRolloutCount
+ ld a, BATTLEANIM_PLAYER_DAMAGE
+
+.got_rollout_count
+ ld [wNumHits], a
+ ld a, BATTLE_VARS_MOVE_EFFECT
+ call GetBattleVar
+ cp EFFECT_MULTI_HIT
+ jr z, .alternate_anim
+ cp EFFECT_CONVERSION
+ jr z, .alternate_anim
+ cp EFFECT_DOUBLE_HIT
+ jr z, .alternate_anim
+ cp EFFECT_POISON_MULTI_HIT
+ jr z, .alternate_anim
+ cp EFFECT_TRIPLE_KICK
+ jr z, .triplekick
+ xor a
+ ld [wKickCounter], a
+
+.triplekick
+ ld a, BATTLE_VARS_MOVE_ANIM
+ call GetBattleVar
+ ld e, a
+ ld d, 0
+ call PlayFXAnimID
+
+ ld a, BATTLE_VARS_MOVE_ANIM
+ call GetBattleVar
+ cp FLY
+ jr z, .clear_sprite
+ cp DIG
+ ret nz
+.clear_sprite
+ jp AppearUserLowerSub
+
+.alternate_anim
+ ld a, [wKickCounter]
+ and 1
+ xor 1
+ ld [wKickCounter], a
+ ld a, [de]
+ cp 1
+ push af
+ ld a, BATTLE_VARS_MOVE_ANIM
+ call GetBattleVar
+ ld e, a
+ ld d, 0
+ pop af
+ jp z, PlayFXAnimID
+ xor a
+ ld [wNumHits], a
+ jp PlayFXAnimID
+
+BattleCommand_StatUpAnim:
+ ld a, [wAttackMissed]
+ and a
+ jp nz, BattleCommand_MoveDelay
+
+ xor a
+ jr BattleCommand_StatUpDownAnim
+
+BattleCommand_StatDownAnim:
+ ld a, [wAttackMissed]
+ and a
+ jp nz, BattleCommand_MoveDelay
+
+ ldh a, [hBattleTurn]
+ and a
+ ld a, BATTLEANIM_ENEMY_STAT_DOWN
+ jr z, BattleCommand_StatUpDownAnim
+ ld a, BATTLEANIM_WOBBLE
+
+ ; fallthrough
+
+BattleCommand_StatUpDownAnim:
+ ld [wNumHits], a
+ xor a
+ ld [wKickCounter], a
+ ld a, BATTLE_VARS_MOVE_ANIM
+ call GetBattleVar
+ ld e, a
+ ld d, 0
+ jp PlayFXAnimID
+
+BattleCommand_SwitchTurn:
+; switchturn
+
+ ldh a, [hBattleTurn]
+ xor 1
+ ldh [hBattleTurn], a
+ ret
+
+BattleCommand_RaiseSub:
+; raisesub
+
+ ld a, BATTLE_VARS_SUBSTATUS4
+ call GetBattleVar
+ bit SUBSTATUS_SUBSTITUTE, a
+ ret z
+
+ ; check battle scene
+ ld a, [wOptions]
+ add a
+ jp c, BattleCommand_RaiseSubNoAnim
+
+ xor a
+ ld [wNumHits], a
+ ld [wFXAnimID + 1], a
+ ld a, $2
+ ld [wKickCounter], a
+ ld a, SUBSTITUTE
+ jp LoadAnim
+
+BattleCommand_FailureText:
+; failuretext
+; If the move missed or failed, load the appropriate
+; text, and end the effects of multi-turn or multi-
+; hit moves.
+ ld a, [wAttackMissed]
+ and a
+ ret z
+
+ call GetFailureResultText
+ ld a, BATTLE_VARS_MOVE_ANIM
+ call GetBattleVarAddr
+
+ cp FLY
+ jr z, .fly_dig
+ cp DIG
+ jr z, .fly_dig
+
+; Move effect:
+ inc hl
+ ld a, [hl]
+
+ cp EFFECT_MULTI_HIT
+ jr z, .multihit
+ cp EFFECT_DOUBLE_HIT
+ jr z, .multihit
+ cp EFFECT_POISON_MULTI_HIT
+ jr z, .multihit
+ jp EndMoveEffect
+
+.multihit
+ call BattleCommand_RaiseSub
+ jp EndMoveEffect
+
+.fly_dig
+ ld a, BATTLE_VARS_SUBSTATUS3
+ call GetBattleVarAddr
+ res SUBSTATUS_UNDERGROUND, [hl]
+ res SUBSTATUS_FLYING, [hl]
+ call AppearUserRaiseSub
+ jp EndMoveEffect
+
+BattleCommand_ApplyDamage:
+; applydamage
+
+ ld a, BATTLE_VARS_SUBSTATUS1_OPP
+ call GetBattleVar
+ bit SUBSTATUS_ENDURE, a
+ jr z, .focus_band
+
+ call BattleCommand_FalseSwipe
+ ld b, 0
+ jr nc, .damage
+ ld b, 1
+ jr .damage
+
+.focus_band
+ call GetOpponentItem
+ ld a, b
+ cp HELD_FOCUS_BAND
+ ld b, 0
+ jr nz, .damage
+
+ call BattleRandom
+ cp c
+ jr nc, .damage
+ call BattleCommand_FalseSwipe
+ ld b, 0
+ jr nc, .damage
+ ld b, 2
+
+.damage
+ push bc
+ call .update_damage_taken
+ ld c, FALSE
+ ldh a, [hBattleTurn]
+ and a
+ jr nz, .damage_player
+ call DoEnemyDamage
+ jr .done_damage
+
+.damage_player
+ call DoPlayerDamage
+
+.done_damage
+ pop bc
+ ld a, b
+ and a
+ ret z
+
+ dec a
+ jr nz, .focus_band_text
+ ld hl, EnduredText
+ jp StdBattleTextbox
+
+.focus_band_text
+ call GetOpponentItem
+ ld a, [hl]
+ ld [wNamedObjectIndexBuffer], a
+ call GetItemName
+ ld hl, HungOnText
+ jp StdBattleTextbox
+
+.update_damage_taken
+ ld a, BATTLE_VARS_SUBSTATUS4_OPP
+ call GetBattleVar
+ bit SUBSTATUS_SUBSTITUTE, a
+ ret nz
+
+ ld de, wPlayerDamageTaken + 1
+ ldh a, [hBattleTurn]
+ and a
+ jr nz, .got_damage_taken
+ ld de, wEnemyDamageTaken + 1
+
+.got_damage_taken
+ ld a, [wCurDamage + 1]
+ ld b, a
+ ld a, [de]
+ add b
+ ld [de], a
+ dec de
+ ld a, [wCurDamage]
+ ld b, a
+ ld a, [de]
+ adc b
+ ld [de], a
+ ret nc
+ ld a, $ff
+ ld [de], a
+ inc de
+ ld [de], a
+ ret
+
+GetFailureResultText:
+ ld hl, DoesntAffectText
+ ld de, DoesntAffectText
+ ld a, [wTypeModifier]
+ and $7f
+ jr z, .got_text
+ ld a, BATTLE_VARS_MOVE_EFFECT
+ call GetBattleVar
+ cp EFFECT_FUTURE_SIGHT
+ ld hl, ButItFailedText
+ ld de, ItFailedText
+ jr z, .got_text
+ ld hl, AttackMissedText
+ ld de, AttackMissed2Text
+ ld a, [wCriticalHit]
+ cp -1
+ jr nz, .got_text
+ ld hl, UnaffectedText
+.got_text
+ call FailText_CheckOpponentProtect
+ xor a
+ ld [wCriticalHit], a
+
+ ld a, BATTLE_VARS_MOVE_EFFECT
+ call GetBattleVar
+ cp EFFECT_JUMP_KICK
+ ret nz
+
+ ld a, [wTypeModifier]
+ and $7f
+ ret z
+
+ ld hl, wCurDamage
+ ld a, [hli]
+ ld b, [hl]
+rept 3
+ srl a
+ rr b
+endr
+ ld [hl], b
+ dec hl
+ ld [hli], a
+ or b
+ jr nz, .do_at_least_1_damage
+ inc a
+ ld [hl], a
+.do_at_least_1_damage
+ ld hl, CrashedText
+ call StdBattleTextbox
+ ld a, $1
+ ld [wKickCounter], a
+ call LoadMoveAnim
+ ld c, TRUE
+ ldh a, [hBattleTurn]
+ and a
+ jp nz, DoEnemyDamage
+ jp DoPlayerDamage
+
+FailText_CheckOpponentProtect:
+ ld a, BATTLE_VARS_SUBSTATUS1_OPP
+ call GetBattleVar
+ bit SUBSTATUS_PROTECT, a
+ jr z, .not_protected
+ ld h, d
+ ld l, e
+.not_protected
+ jp StdBattleTextbox
+
+BattleCommand_BideFailText:
+ ld a, [wAttackMissed]
+ and a
+ ret z
+
+ ld a, [wTypeModifier]
+ and $7f
+ jp z, PrintDoesntAffect
+ jp PrintButItFailed
+
+BattleCommand_CriticalText:
+; criticaltext
+; Prints the message for critical hits or one-hit KOs.
+
+; If there is no message to be printed, wait 20 frames.
+ ld a, [wCriticalHit]
+ and a
+ jr z, .wait
+
+ dec a
+ add a
+ ld hl, .texts
+ ld b, 0
+ ld c, a
+ add hl, bc
+ ld a, [hli]
+ ld h, [hl]
+ ld l, a
+ call StdBattleTextbox
+
+ xor a
+ ld [wCriticalHit], a
+
+.wait
+ ld c, 20
+ jp DelayFrames
+
+.texts
+ dw CriticalHitText
+ dw OneHitKOText
+
+BattleCommand_StartLoop:
+; startloop
+
+ ld hl, wPlayerRolloutCount
+ ldh a, [hBattleTurn]
+ and a
+ jr z, .ok
+ ld hl, wEnemyRolloutCount
+.ok
+ xor a
+ ld [hl], a
+ ret
+
+BattleCommand_SuperEffectiveLoopText:
+; supereffectivelooptext
+
+ ld a, BATTLE_VARS_SUBSTATUS3
+ call GetBattleVarAddr
+ bit SUBSTATUS_IN_LOOP, a
+ ret nz
+
+ ; fallthrough
+
+BattleCommand_SuperEffectiveText:
+; supereffectivetext
+
+ ld a, [wTypeModifier]
+ and $7f
+ cp 10 ; 1.0
+ ret z
+ ld hl, SuperEffectiveText
+ jr nc, .print
+ ld hl, NotVeryEffectiveText
+.print
+ jp StdBattleTextbox
+
+BattleCommand_CheckFaint:
+; checkfaint
+
+; Faint the opponent if its HP reached zero
+; and faint the user along with it if it used Destiny Bond.
+; Ends the move effect if the opponent faints.
+
+ ld hl, wEnemyMonHP
+ ldh a, [hBattleTurn]
+ and a
+ jr z, .got_hp
+ ld hl, wBattleMonHP
+
+.got_hp
+ ld a, [hli]
+ or [hl]
+ ret nz
+
+ ld a, BATTLE_VARS_SUBSTATUS5_OPP
+ call GetBattleVar
+ bit SUBSTATUS_DESTINY_BOND, a
+ jr z, .no_dbond
+
+ ld hl, TookDownWithItText
+ call StdBattleTextbox
+
+ ldh a, [hBattleTurn]
+ and a
+ ld hl, wEnemyMonMaxHP + 1
+ bccoord 2, 2 ; hp bar
+ ld a, 0
+ jr nz, .got_max_hp
+ ld hl, wBattleMonMaxHP + 1
+ bccoord 10, 9 ; hp bar
+ ld a, 1
+
+.got_max_hp
+ ld [wWhichHPBar], a
+ ld a, [hld]
+ ld [wBuffer1], a
+ ld a, [hld]
+ ld [wBuffer2], a
+ ld a, [hl]
+ ld [wBuffer3], a
+ xor a
+ ld [hld], a
+ ld a, [hl]
+ ld [wBuffer4], a
+ xor a
+ ld [hl], a
+ ld [wBuffer5], a
+ ld [wBuffer6], a
+ ld h, b
+ ld l, c
+ predef AnimateHPBar
+ call RefreshBattleHuds
+
+ call BattleCommand_SwitchTurn
+ xor a
+ ld [wNumHits], a
+ ld [wFXAnimID + 1], a
+ inc a
+ ld [wKickCounter], a
+ ld a, DESTINY_BOND
+ call LoadAnim
+ call BattleCommand_SwitchTurn
+
+ jr .finish
+
+.no_dbond
+ ld a, BATTLE_VARS_MOVE_EFFECT
+ call GetBattleVar
+ cp EFFECT_MULTI_HIT
+ jr z, .multiple_hit_raise_sub
+ cp EFFECT_DOUBLE_HIT
+ jr z, .multiple_hit_raise_sub
+ cp EFFECT_POISON_MULTI_HIT
+ jr z, .multiple_hit_raise_sub
+ cp EFFECT_TRIPLE_KICK
+ jr z, .multiple_hit_raise_sub
+ cp EFFECT_BEAT_UP
+ jr nz, .finish
+
+.multiple_hit_raise_sub
+ call BattleCommand_RaiseSub
+
+.finish
+ jp EndMoveEffect
+
+BattleCommand_BuildOpponentRage:
+; buildopponentrage
+
+ jp .start
+
+.start
+ ld a, [wAttackMissed]
+ and a
+ ret nz
+
+ ld a, BATTLE_VARS_SUBSTATUS4_OPP
+ call GetBattleVar
+ bit SUBSTATUS_RAGE, a
+ ret z
+
+ ld de, wEnemyRageCounter
+ ldh a, [hBattleTurn]
+ and a
+ jr z, .player
+ ld de, wPlayerRageCounter
+.player
+ ld a, [de]
+ inc a
+ ret z
+ ld [de], a
+
+ call BattleCommand_SwitchTurn
+ ld hl, RageBuildingText
+ call StdBattleTextbox
+ jp BattleCommand_SwitchTurn
+
+BattleCommand_RageDamage:
+; ragedamage
+
+ ld a, [wCurDamage]
+ ld h, a
+ ld b, a
+ ld a, [wCurDamage + 1]
+ ld l, a
+ ld c, a
+ ldh a, [hBattleTurn]
+ and a
+ ld a, [wPlayerRageCounter]
+ jr z, .rage_loop
+ ld a, [wEnemyRageCounter]
+.rage_loop
+ and a
+ jr z, .done
+ dec a
+ add hl, bc
+ jr nc, .rage_loop
+ ld hl, $ffff
+.done
+ ld a, h
+ ld [wCurDamage], a
+ ld a, l
+ ld [wCurDamage + 1], a
+ ret
+
+EndMoveEffect:
+ ld a, [wBattleScriptBufferAddress]
+ ld l, a
+ ld a, [wBattleScriptBufferAddress + 1]
+ ld h, a
+ ld a, $ff
+ ld [hli], a
+ ld [hli], a
+ ld [hl], a
+ ret
+
+DittoMetalPowder:
+ ld a, MON_SPECIES
+ call BattlePartyAttr
+ ldh a, [hBattleTurn]
+ and a
+ ld a, [hl]
+ jr nz, .Ditto
+ ld a, [wTempEnemyMonSpecies]
+
+.Ditto:
+ cp DITTO
+ ret nz
+
+ push bc
+ call GetOpponentItem
+ ld a, [hl]
+ cp METAL_POWDER
+ pop bc
+ ret nz
+
+ ld a, c
+ srl a
+ add c
+ ld c, a
+ ret nc
+
+ srl b
+ ld a, b
+ and a
+ jr nz, .done
+ inc b
+.done
+ scf
+ rr c
+ ret
+
+BattleCommand_DamageStats:
+; damagestats
+
+ ldh a, [hBattleTurn]
+ and a
+ jp nz, EnemyAttackDamage
+
+ ; fallthrough
+
+PlayerAttackDamage:
+; Return move power d, player level e, enemy defense c and player attack b.
+
+ call ResetDamage
+
+ ld hl, wPlayerMoveStructPower
+ ld a, [hli]
+ and a
+ ld d, a
+ ret z
+
+ ld a, [hl]
+ cp SPECIAL
+ jr nc, .special
+
+.physical
+ ld hl, wEnemyMonDefense
+ ld a, [hli]
+ ld b, a
+ ld c, [hl]
+
+ ld a, [wEnemyScreens]
+ bit SCREENS_REFLECT, a
+ jr z, .physicalcrit
+ sla c
+ rl b
+
+.physicalcrit
+ ld hl, wBattleMonAttack
+ call CheckDamageStatsCritical
+ jr c, .thickclub
+
+ ld hl, wEnemyDefense
+ ld a, [hli]
+ ld b, a
+ ld c, [hl]
+ ld hl, wPlayerAttack
+ jr .thickclub
+
+.special
+ ld hl, wEnemyMonSpclDef
+ ld a, [hli]
+ ld b, a
+ ld c, [hl]
+
+ ld a, [wEnemyScreens]
+ bit SCREENS_LIGHT_SCREEN, a
+ jr z, .specialcrit
+ sla c
+ rl b
+
+.specialcrit
+ ld hl, wBattleMonSpclAtk
+ call CheckDamageStatsCritical
+ jr c, .lightball
+
+ ld hl, wEnemySpDef
+ ld a, [hli]
+ ld b, a
+ ld c, [hl]
+ ld hl, wPlayerSpAtk
+
+.lightball
+; Note: Returns player special attack at hl in hl.
+ call LightBallBoost
+ jr .done
+
+.thickclub
+; Note: Returns player attack at hl in hl.
+ call ThickClubBoost
+
+.done
+ call TruncateHL_BC
+
+ ld a, [wBattleMonLevel]
+ ld e, a
+ call DittoMetalPowder
+
+ ld a, 1
+ and a
+ ret
+
+TruncateHL_BC:
+.loop
+; Truncate 16-bit values hl and bc to 8-bit values b and c respectively.
+; b = hl, c = bc
+
+ ld a, h
+ or b
+ jr z, .done
+
+ srl b
+ rr c
+ srl b
+ rr c
+
+ ld a, c
+ or b
+ jr nz, .done_bc
+ inc c
+
+.done_bc
+ srl h
+ rr l
+ srl h
+ rr l
+
+ ld a, l
+ or h
+ jr nz, .done
+ inc l
+
+.done
+ ld b, l
+ ret
+
+CheckDamageStatsCritical:
+; Return carry if boosted stats should be used in damage calculations.
+; Unboosted stats should be used if the attack is a critical hit,
+; and the stage of the opponent's defense is higher than the user's attack.
+
+ ld a, [wCriticalHit]
+ and a
+ scf
+ ret z
+
+ push hl
+ push bc
+ ldh a, [hBattleTurn]
+ and a
+ jr nz, .enemy
+ ld a, [wPlayerMoveStructType]
+ cp SPECIAL
+; special
+ ld a, [wPlayerSAtkLevel]
+ ld b, a
+ ld a, [wEnemySDefLevel]
+ jr nc, .end
+; physical
+ ld a, [wPlayerAtkLevel]
+ ld b, a
+ ld a, [wEnemyDefLevel]
+ jr .end
+
+.enemy
+ ld a, [wEnemyMoveStructType]
+ cp SPECIAL
+; special
+ ld a, [wEnemySAtkLevel]
+ ld b, a
+ ld a, [wPlayerSDefLevel]
+ jr nc, .end
+; physical
+ ld a, [wEnemyAtkLevel]
+ ld b, a
+ ld a, [wPlayerDefLevel]
+.end
+ cp b
+ pop bc
+ pop hl
+ ret
+
+ThickClubBoost:
+; Return in hl the stat value at hl.
+
+; If the attacking monster is Cubone or Marowak and
+; it's holding a Thick Club, double it.
+ push bc
+ push de
+ ld b, CUBONE
+ ld c, MAROWAK
+ ld d, THICK_CLUB
+ call SpeciesItemBoost
+ pop de
+ pop bc
+ ret
+
+LightBallBoost:
+; Return in hl the stat value at hl.
+
+; If the attacking monster is Pikachu and it's
+; holding a Light Ball, double it.
+ push bc
+ push de
+ ld b, PIKACHU
+ ld c, PIKACHU
+ ld d, LIGHT_BALL
+ call SpeciesItemBoost
+ pop de
+ pop bc
+ ret
+
+SpeciesItemBoost:
+; Return in hl the stat value at hl.
+
+; If the attacking monster is species b or c and
+; it's holding item d, double it.
+
+ ld a, [hli]
+ ld l, [hl]
+ ld h, a
+
+ push hl
+ ld a, MON_SPECIES
+ call BattlePartyAttr
+
+ ldh a, [hBattleTurn]
+ and a
+ ld a, [hl]
+ jr z, .CompareSpecies
+ ld a, [wTempEnemyMonSpecies]
+.CompareSpecies:
+ pop hl
+
+ cp b
+ jr z, .GetItemHeldEffect
+ cp c
+ ret nz
+
+.GetItemHeldEffect:
+ push hl
+ call GetUserItem
+ ld a, [hl]
+ pop hl
+ cp d
+ ret nz
+
+; Double the stat
+ sla l
+ rl h
+ ret
+
+EnemyAttackDamage:
+ call ResetDamage
+
+; No damage dealt with 0 power.
+ ld hl, wEnemyMoveStructPower
+ ld a, [hli] ; hl = wEnemyMoveStructType
+ ld d, a
+ and a
+ ret z
+
+ ld a, [hl]
+ cp SPECIAL
+ jr nc, .Special
+
+.physical
+ ld hl, wBattleMonDefense
+ ld a, [hli]
+ ld b, a
+ ld c, [hl]
+
+ ld a, [wPlayerScreens]
+ bit SCREENS_REFLECT, a
+ jr z, .physicalcrit
+ sla c
+ rl b
+
+.physicalcrit
+ ld hl, wEnemyMonAttack
+ call CheckDamageStatsCritical
+ jr c, .thickclub
+
+ ld hl, wPlayerDefense
+ ld a, [hli]
+ ld b, a
+ ld c, [hl]
+ ld hl, wEnemyAttack
+ jr .thickclub
+
+.Special:
+ ld hl, wBattleMonSpclDef
+ ld a, [hli]
+ ld b, a
+ ld c, [hl]
+
+ ld a, [wPlayerScreens]
+ bit SCREENS_LIGHT_SCREEN, a
+ jr z, .specialcrit
+ sla c
+ rl b
+
+.specialcrit
+ ld hl, wEnemyMonSpclAtk
+ call CheckDamageStatsCritical
+ jr c, .lightball
+ ld hl, wPlayerSpDef
+ ld a, [hli]
+ ld b, a
+ ld c, [hl]
+ ld hl, wEnemySpAtk
+
+.lightball
+ call LightBallBoost
+ jr .done
+
+.thickclub
+ call ThickClubBoost
+
+.done
+ call TruncateHL_BC
+
+ ld a, [wEnemyMonLevel]
+ ld e, a
+ call DittoMetalPowder
+
+ ld a, 1
+ and a
+ ret
+
+INCLUDE "engine/battle/move_effects/beat_up.asm"
+
+BattleCommand_ClearMissDamage:
+; clearmissdamage
+ ld a, [wAttackMissed]
+ and a
+ ret z
+
+ jp ResetDamage
+
+HitSelfInConfusion:
+ call ResetDamage
+ ldh a, [hBattleTurn]
+ and a
+ ld hl, wBattleMonDefense
+ ld de, wPlayerScreens
+ ld a, [wBattleMonLevel]
+ jr z, .got_it
+
+ ld hl, wEnemyMonDefense
+ ld de, wEnemyScreens
+ ld a, [wEnemyMonLevel]
+.got_it
+ push af
+ ld a, [hli]
+ ld b, a
+ ld c, [hl]
+ ld a, [de]
+ bit SCREENS_REFLECT, a
+ jr z, .mimic_screen
+
+ sla c
+ rl b
+.mimic_screen
+ dec hl
+ dec hl
+ dec hl
+ ld a, [hli]
+ ld l, [hl]
+ ld h, a
+ call TruncateHL_BC
+ ld d, 40
+ pop af
+ ld e, a
+ ret
+
+BattleCommand_DamageCalc:
+; damagecalc
+
+; Return a damage value for move power d, player level e, enemy defense c and player attack b.
+
+; Return 1 if successful, else 0.
+
+ ld a, BATTLE_VARS_MOVE_EFFECT
+ call GetBattleVar
+
+; Selfdestruct and Explosion halve defense.
+ cp EFFECT_SELFDESTRUCT
+ jr nz, .dont_selfdestruct
+
+ srl c
+ jr nz, .dont_selfdestruct
+ inc c
+
+.dont_selfdestruct
+
+; Variable-hit moves and Conversion can have a power of 0.
+ cp EFFECT_MULTI_HIT
+ jr z, .skip_zero_damage_check
+
+ cp EFFECT_CONVERSION
+ jr z, .skip_zero_damage_check
+
+; No damage if move power is 0.
+ ld a, d
+ and a
+ ret z
+
+.skip_zero_damage_check
+; Minimum defense value is 1.
+ ld a, c
+ and a
+ jr nz, .not_dividing_by_zero
+ ld c, 1
+.not_dividing_by_zero
+
+ xor a
+ ld hl, hDividend
+ ld [hli], a
+ ld [hli], a
+ ld [hl], a
+
+; Level * 2
+ ld a, e
+ add a
+ jr nc, .level_not_overflowing
+ ld [hl], 1
+.level_not_overflowing
+ inc hl
+ ld [hli], a
+
+; / 5
+ ld a, 5
+ ld [hld], a
+ push bc
+ ld b, 4
+ call Divide
+ pop bc
+
+; + 2
+ inc [hl]
+ inc [hl]
+
+; * bp
+ inc hl
+ ld [hl], d
+ call Multiply
+
+; * Attack
+ ld [hl], b
+ call Multiply
+
+; / Defense
+ ld [hl], c
+ ld b, 4
+ call Divide
+
+; / 50
+ ld [hl], 50
+ ld b, $4
+ call Divide
+
+; Item boosts
+ call GetUserItem
+
+ ld a, b
+ and a
+ jr z, .DoneItem
+
+ ld hl, TypeBoostItems
+
+.NextItem:
+ ld a, [hli]
+ cp -1
+ jr z, .DoneItem
+
+; Item effect
+ cp b
+ ld a, [hli]
+ jr nz, .NextItem
+
+; Type
+ ld b, a
+ ld a, BATTLE_VARS_MOVE_TYPE
+ call GetBattleVar
+ cp b
+ jr nz, .DoneItem
+
+; * 100 + item effect amount
+ ld a, c
+ add 100
+ ldh [hMultiplier], a
+ call Multiply
+
+; / 100
+ ld a, 100
+ ldh [hDivisor], a
+ ld b, 4
+ call Divide
+
+.DoneItem:
+; Critical hits
+ call .CriticalMultiplier
+
+; Update wCurDamage (capped at 997).
+ ld hl, wCurDamage
+ ld b, [hl]
+ ldh a, [hProduct + 3]
+ add b
+ ldh [hProduct + 3], a
+ jr nc, .dont_cap_1
+
+ ldh a, [hProduct + 2]
+ inc a
+ ldh [hProduct + 2], a
+ and a
+ jr z, .Cap
+
+.dont_cap_1
+ ldh a, [hProduct]
+ ld b, a
+ ldh a, [hProduct + 1]
+ or a
+ jr nz, .Cap
+
+ ldh a, [hProduct + 2]
+ cp HIGH(MAX_STAT_VALUE - MIN_NEUTRAL_DAMAGE + 1)
+ jr c, .dont_cap_2
+
+ cp HIGH(MAX_STAT_VALUE - MIN_NEUTRAL_DAMAGE + 1) + 1
+ jr nc, .Cap
+
+ ldh a, [hProduct + 3]
+ cp LOW(MAX_STAT_VALUE - MIN_NEUTRAL_DAMAGE + 1)
+ jr nc, .Cap
+
+.dont_cap_2
+ inc hl
+
+ ldh a, [hProduct + 3]
+ ld b, [hl]
+ add b
+ ld [hld], a
+
+ ldh a, [hProduct + 2]
+ ld b, [hl]
+ adc b
+ ld [hl], a
+ jr c, .Cap
+
+ ld a, [hl]
+ cp HIGH(MAX_STAT_VALUE - MIN_NEUTRAL_DAMAGE + 1)
+ jr c, .dont_cap_3
+
+ cp HIGH(MAX_STAT_VALUE - MIN_NEUTRAL_DAMAGE + 1) + 1
+ jr nc, .Cap
+
+ inc hl
+ ld a, [hld]
+ cp LOW(MAX_STAT_VALUE - MIN_NEUTRAL_DAMAGE + 1)
+ jr c, .dont_cap_3
+
+.Cap:
+ ld a, HIGH(MAX_STAT_VALUE - MIN_NEUTRAL_DAMAGE)
+ ld [hli], a
+ ld a, LOW(MAX_STAT_VALUE - MIN_NEUTRAL_DAMAGE)
+ ld [hld], a
+
+.dont_cap_3
+; Minimum neutral damage is 2 (bringing the cap to 999).
+ inc hl
+ ld a, [hl]
+ add MIN_NEUTRAL_DAMAGE
+ ld [hld], a
+ jr nc, .dont_floor
+ inc [hl]
+.dont_floor
+
+ ld a, 1
+ and a
+ ret
+
+.CriticalMultiplier:
+ ld a, [wCriticalHit]
+ and a
+ ret z
+
+; x2
+ ldh a, [hQuotient + 3]
+ sla a
+ ldh [hProduct + 3], a
+
+ ldh a, [hQuotient + 2]
+ rl a
+ ldh [hProduct + 2], a
+
+; Cap at $ffff.
+ ret nc
+
+ ld a, $ff
+ ldh [hProduct + 2], a
+ ldh [hProduct + 3], a
+
+ ret
+
+INCLUDE "data/types/type_boost_items.asm"
+
+BattleCommand_ConstantDamage:
+; constantdamage
+
+ ld hl, wBattleMonLevel
+ ldh a, [hBattleTurn]
+ and a
+ jr z, .got_turn
+ ld hl, wEnemyMonLevel
+
+.got_turn
+ ld a, BATTLE_VARS_MOVE_EFFECT
+ call GetBattleVar
+ cp EFFECT_LEVEL_DAMAGE
+ ld b, [hl]
+ ld a, 0
+ jr z, .got_power
+
+ ld a, BATTLE_VARS_MOVE_EFFECT
+ call GetBattleVar
+ cp EFFECT_PSYWAVE
+ jr z, .psywave
+
+ cp EFFECT_SUPER_FANG
+ jr z, .super_fang
+
+ cp EFFECT_REVERSAL
+ jr z, .reversal
+
+ ld a, BATTLE_VARS_MOVE_POWER
+ call GetBattleVar
+ ld b, a
+ ld a, $0
+ jr .got_power
+
+.psywave
+ ld a, b
+ srl a
+ add b
+ ld b, a
+.psywave_loop
+ call BattleRandom
+ and a
+ jr z, .psywave_loop
+ cp b
+ jr nc, .psywave_loop
+ ld b, a
+ ld a, 0
+ jr .got_power
+
+.super_fang
+ ld hl, wEnemyMonHP
+ ldh a, [hBattleTurn]
+ and a
+ jr z, .got_hp
+ ld hl, wBattleMonHP
+.got_hp
+ ld a, [hli]
+ srl a
+ ld b, a
+ ld a, [hl]
+ rr a
+ push af
+ ld a, b
+ pop bc
+ and a
+ jr nz, .got_power
+ or b
+ ld a, 0
+ jr nz, .got_power
+ ld b, 1
+ jr .got_power
+
+.got_power
+ ld hl, wCurDamage
+ ld [hli], a
+ ld [hl], b
+ ret
+
+.reversal
+ ld hl, wBattleMonHP
+ ldh a, [hBattleTurn]
+ and a
+ jr z, .reversal_got_hp
+ ld hl, wEnemyMonHP
+.reversal_got_hp
+ xor a
+ ldh [hDividend], a
+ ldh [hMultiplicand + 0], a
+ ld a, [hli]
+ ldh [hMultiplicand + 1], a
+ ld a, [hli]
+ ldh [hMultiplicand + 2], a
+ ld a, 48
+ ldh [hMultiplier], a
+ call Multiply
+ ld a, [hli]
+ ld b, a
+ ld a, [hl]
+ ldh [hDivisor], a
+ ld a, b
+ and a
+ jr z, .skip_to_divide
+
+ ldh a, [hProduct + 4]
+ srl b
+ rr a
+ srl b
+ rr a
+ ldh [hDivisor], a
+ ldh a, [hProduct + 2]
+ ld b, a
+ srl b
+ ldh a, [hProduct + 3]
+ rr a
+ srl b
+ rr a
+ ldh [hDividend + 3], a
+ ld a, b
+ ldh [hDividend + 2], a
+
+.skip_to_divide
+ ld b, 4
+ call Divide
+ ldh a, [hQuotient + 3]
+ ld b, a
+ ld hl, FlailReversalPower
+
+.reversal_loop
+ ld a, [hli]
+ cp b
+ jr nc, .break_loop
+ inc hl
+ jr .reversal_loop
+
+.break_loop
+ ldh a, [hBattleTurn]
+ and a
+ ld a, [hl]
+ jr nz, .notPlayersTurn
+
+ ld hl, wPlayerMoveStructPower
+ ld [hl], a
+ push hl
+ call PlayerAttackDamage
+ jr .notEnemysTurn
+
+.notPlayersTurn
+ ld hl, wEnemyMoveStructPower
+ ld [hl], a
+ push hl
+ call EnemyAttackDamage
+
+.notEnemysTurn
+ call BattleCommand_DamageCalc
+ pop hl
+ ld [hl], 1
+ ret
+
+INCLUDE "data/moves/flail_reversal_power.asm"
+
+INCLUDE "engine/battle/move_effects/counter.asm"
+
+INCLUDE "engine/battle/move_effects/encore.asm"
+
+INCLUDE "engine/battle/move_effects/pain_split.asm"
+
+INCLUDE "engine/battle/move_effects/snore.asm"
+
+INCLUDE "engine/battle/move_effects/conversion2.asm"
+
+INCLUDE "engine/battle/move_effects/lock_on.asm"
+
+INCLUDE "engine/battle/move_effects/sketch.asm"
+
+BattleCommand_DefrostOpponent:
+; defrostopponent
+; Thaw the opponent if frozen, and
+; raise the user's Attack one stage.
+
+ call AnimateCurrentMove
+
+ ld a, BATTLE_VARS_STATUS_OPP
+ call GetBattleVarAddr
+ call Defrost
+
+ ld a, BATTLE_VARS_MOVE_EFFECT
+ call GetBattleVarAddr
+ ld a, [hl]
+ push hl
+ push af
+
+ ld a, EFFECT_ATTACK_UP
+ ld [hl], a
+ call BattleCommand_StatUp
+
+ pop af
+ pop hl
+ ld [hl], a
+ ret
+
+INCLUDE "engine/battle/move_effects/sleep_talk.asm"
+
+INCLUDE "engine/battle/move_effects/destiny_bond.asm"
+
+INCLUDE "engine/battle/move_effects/spite.asm"
+
+INCLUDE "engine/battle/move_effects/false_swipe.asm"
+
+INCLUDE "engine/battle/move_effects/heal_bell.asm"
+
+FarPlayBattleAnimation:
+; play animation de
+
+ ld a, BATTLE_VARS_SUBSTATUS3
+ call GetBattleVar
+ and 1 << SUBSTATUS_FLYING | 1 << SUBSTATUS_UNDERGROUND
+ ret nz
+
+ ; fallthrough
+
+PlayFXAnimID:
+ ld a, e
+ ld [wFXAnimID], a
+ ld a, d
+ ld [wFXAnimID + 1], a
+
+ ld c, 3
+ call DelayFrames
+ callfar PlayBattleAnim
+ ret
+
+DoEnemyDamage:
+ ld hl, wCurDamage
+ ld a, [hli]
+ ld b, a
+ ld a, [hl]
+ or b
+ jr z, .did_no_damage
+
+ ld a, c
+ and a
+ jr nz, .ignore_substitute
+ ld a, [wEnemySubStatus4]
+ bit SUBSTATUS_SUBSTITUTE, a
+ jp nz, DoSubstituteDamage
+
+.ignore_substitute
+ ; Substract wCurDamage from wEnemyMonHP.
+ ; store original HP in little endian wBuffer3/4
+ ld a, [hld]
+ ld b, a
+ ld a, [wEnemyMonHP + 1]
+ ld [wBuffer3], a
+ sub b
+ ld [wEnemyMonHP + 1], a
+ ld a, [hl]
+ ld b, a
+ ld a, [wEnemyMonHP]
+ ld [wBuffer4], a
+ sbc b
+ ld [wEnemyMonHP], a
+ jr nc, .no_underflow
+
+ ld a, [wBuffer4]
+ ld [hli], a
+ ld a, [wBuffer3]
+ ld [hl], a
+ xor a
+ ld hl, wEnemyMonHP
+ ld [hli], a
+ ld [hl], a
+
+.no_underflow
+ ld hl, wEnemyMonMaxHP
+ ld a, [hli]
+ ld [wBuffer2], a
+ ld a, [hl]
+ ld [wBuffer1], a
+ ld hl, wEnemyMonHP
+ ld a, [hli]
+ ld [wBuffer6], a
+ ld a, [hl]
+ ld [wBuffer5], a
+
+ hlcoord 2, 2
+ xor a
+ ld [wWhichHPBar], a
+ predef AnimateHPBar
+.did_no_damage
+ jp RefreshBattleHuds
+
+DoPlayerDamage:
+ ld hl, wCurDamage
+ ld a, [hli]
+ ld b, a
+ ld a, [hl]
+ or b
+ jr z, .did_no_damage
+
+ ld a, c
+ and a
+ jr nz, .ignore_substitute
+ ld a, [wPlayerSubStatus4]
+ bit SUBSTATUS_SUBSTITUTE, a
+ jp nz, DoSubstituteDamage
+
+.ignore_substitute
+ ; Substract wCurDamage from wBattleMonHP.
+ ; store original HP in little endian wBuffer3/4
+ ; store new HP in little endian wBuffer5/6
+ ld a, [hld]
+ ld b, a
+ ld a, [wBattleMonHP + 1]
+ ld [wBuffer3], a
+ sub b
+ ld [wBattleMonHP + 1], a
+ ld [wBuffer5], a
+ ld b, [hl]
+ ld a, [wBattleMonHP]
+ ld [wBuffer4], a
+ sbc b
+ ld [wBattleMonHP], a
+ ld [wBuffer6], a
+ jr nc, .no_underflow
+
+ ld a, [wBuffer4]
+ ld [hli], a
+ ld a, [wBuffer3]
+ ld [hl], a
+ xor a
+ ld hl, wBattleMonHP
+ ld [hli], a
+ ld [hl], a
+ ld hl, wBuffer5
+ ld [hli], a
+ ld [hl], a
+
+.no_underflow
+ ld hl, wBattleMonMaxHP
+ ld a, [hli]
+ ld [wBuffer2], a
+ ld a, [hl]
+ ld [wBuffer1], a
+
+ hlcoord 10, 9
+ ld a, 1
+ ld [wWhichHPBar], a
+ predef AnimateHPBar
+.did_no_damage
+ jp RefreshBattleHuds
+
+DoSubstituteDamage:
+ ld hl, SubTookDamageText
+ call StdBattleTextbox
+
+ ld de, wEnemySubstituteHP
+ ldh a, [hBattleTurn]
+ and a
+ jr z, .got_hp
+ ld de, wPlayerSubstituteHP
+.got_hp
+
+ ld hl, wCurDamage
+ ld a, [hli]
+ and a
+ jr nz, .broke
+
+ ld a, [de]
+ sub [hl]
+ ld [de], a
+ jr z, .broke
+ jr nc, .done
+
+.broke
+ ld a, BATTLE_VARS_SUBSTATUS4_OPP
+ call GetBattleVarAddr
+ res SUBSTATUS_SUBSTITUTE, [hl]
+
+ ld hl, SubFadedText
+ call StdBattleTextbox
+
+ call BattleCommand_SwitchTurn
+ call BattleCommand_LowerSubNoAnim
+ ld a, BATTLE_VARS_SUBSTATUS3
+ call GetBattleVar
+ and 1 << SUBSTATUS_FLYING | 1 << SUBSTATUS_UNDERGROUND
+ call z, AppearUserLowerSub
+ call BattleCommand_SwitchTurn
+
+ ld a, BATTLE_VARS_MOVE_EFFECT
+ call GetBattleVarAddr
+ cp EFFECT_MULTI_HIT
+ jr z, .ok
+ cp EFFECT_DOUBLE_HIT
+ jr z, .ok
+ cp EFFECT_POISON_MULTI_HIT
+ jr z, .ok
+ cp EFFECT_TRIPLE_KICK
+ jr z, .ok
+ cp EFFECT_BEAT_UP
+ jr z, .ok
+ xor a
+ ld [hl], a
+.ok
+ call RefreshBattleHuds
+.done
+ jp ResetDamage
+
+UpdateMoveData:
+ ld a, BATTLE_VARS_MOVE_ANIM
+ call GetBattleVarAddr
+ ld d, h
+ ld e, l
+
+ ld a, BATTLE_VARS_MOVE
+ call GetBattleVar
+ ld [wCurSpecies], a
+ ld [wNamedObjectIndexBuffer], a
+
+ dec a
+ call GetMoveData
+ call GetMoveName
+ jp CopyName1
+
+BattleCommand_SleepTarget:
+; sleeptarget
+
+ call GetOpponentItem
+ ld a, b
+ cp HELD_PREVENT_SLEEP
+ jr nz, .not_protected_by_item
+
+ ld a, [hl]
+ ld [wNamedObjectIndexBuffer], a
+ call GetItemName
+ ld hl, ProtectedByText
+ jr .fail
+
+.not_protected_by_item
+ ld a, BATTLE_VARS_STATUS_OPP
+ call GetBattleVarAddr
+ ld d, h
+ ld e, l
+ ld a, [de]
+ and SLP
+ ld hl, AlreadyAsleepText
+ jr nz, .fail
+
+ ld a, [wAttackMissed]
+ and a
+ jp nz, PrintDidntAffect2
+
+ ld hl, DidntAffect1Text
+ call .CheckAIRandomFail
+ jr c, .fail
+
+ ld a, [de]
+ and a
+ jr nz, .fail
+
+ call CheckSubstituteOpp
+ jr nz, .fail
+
+ call AnimateCurrentMove
+
+.random_loop
+ call BattleRandom
+ and 7
+ jr z, .random_loop
+ cp 7
+ jr z, .random_loop
+ inc a
+ ld [de], a
+ call UpdateOpponentInParty
+ call RefreshBattleHuds
+
+ ld hl, FellAsleepText
+ call StdBattleTextbox
+
+ farcall UseHeldStatusHealingItem
+ ret nz
+
+ call OpponentCantMove
+ ret
+
+.fail
+ call AnimateFailedMove
+ jp StdBattleTextbox
+
+.CheckAIRandomFail:
+ ; Enemy turn
+ ldh a, [hBattleTurn]
+ and a
+ jr z, .dont_fail
+
+ ; Not in link battle
+ ld a, [wLinkMode]
+ and a
+ jr nz, .dont_fail
+
+ ; Not locked-on by the enemy
+ ld a, [wPlayerSubStatus5]
+ bit SUBSTATUS_LOCK_ON, a
+ jr nz, .dont_fail
+
+ call BattleRandom
+ cp 25 percent + 1 ; 25% chance AI fails
+ ret c
+
+.dont_fail
+ xor a
+ ret
+
+BattleCommand_PoisonTarget:
+; poisontarget
+
+ call CheckSubstituteOpp
+ ret nz
+ ld a, BATTLE_VARS_STATUS_OPP
+ call GetBattleVarAddr
+ and a
+ ret nz
+ ld a, [wTypeModifier]
+ and $7f
+ ret z
+ call CheckIfTargetIsPoisonType
+ ret z
+ call GetOpponentItem
+ ld a, b
+ cp HELD_PREVENT_POISON
+ ret z
+ ld a, [wEffectFailed]
+ and a
+ ret nz
+ call SafeCheckSafeguard
+ ret nz
+
+ call PoisonOpponent
+ ld de, ANIM_PSN
+ call PlayOpponentBattleAnim
+ call RefreshBattleHuds
+
+ ld hl, WasPoisonedText
+ call StdBattleTextbox
+
+ farcall UseHeldStatusHealingItem
+ ret
+
+BattleCommand_Poison:
+; poison
+
+ ld hl, DoesntAffectText
+ ld a, [wTypeModifier]
+ and $7f
+ jp z, .failed
+
+ call CheckIfTargetIsPoisonType
+ jp z, .failed
+
+ ld a, BATTLE_VARS_STATUS_OPP
+ call GetBattleVar
+ ld b, a
+ ld hl, AlreadyPoisonedText
+ and 1 << PSN
+ jp nz, .failed
+
+ call GetOpponentItem
+ ld a, b
+ cp HELD_PREVENT_POISON
+ jr nz, .do_poison
+ ld a, [hl]
+ ld [wNamedObjectIndexBuffer], a
+ call GetItemName
+ ld hl, ProtectedByText
+ jr .failed
+
+.do_poison
+ ld hl, DidntAffect1Text
+ ld a, BATTLE_VARS_STATUS_OPP
+ call GetBattleVar
+ and a
+ jr nz, .failed
+
+ ldh a, [hBattleTurn]
+ and a
+ jr z, .dont_sample_failure
+
+ ld a, [wLinkMode]
+ and a
+ jr nz, .dont_sample_failure
+
+ ld a, [wPlayerSubStatus5]
+ bit SUBSTATUS_LOCK_ON, a
+ jr nz, .dont_sample_failure
+
+ call BattleRandom
+ cp 25 percent + 1 ; 25% chance AI fails
+ jr c, .failed
+
+.dont_sample_failure
+ call CheckSubstituteOpp
+ jr nz, .failed
+ ld a, [wAttackMissed]
+ and a
+ jr nz, .failed
+ call .check_toxic
+ jr z, .toxic
+
+ call .apply_poison
+ ld hl, WasPoisonedText
+ call StdBattleTextbox
+ jr .finished
+
+.toxic
+ set SUBSTATUS_TOXIC, [hl]
+ xor a
+ ld [de], a
+ call .apply_poison
+
+ ld hl, BadlyPoisonedText
+ call StdBattleTextbox
+
+.finished
+ farcall UseHeldStatusHealingItem
+ ret
+
+.failed
+ call AnimateFailedMove
+ jp StdBattleTextbox
+
+.apply_poison
+ call AnimateCurrentMove
+ call PoisonOpponent
+ jp RefreshBattleHuds
+
+.check_toxic
+ ld a, BATTLE_VARS_SUBSTATUS5_OPP
+ call GetBattleVarAddr
+ ldh a, [hBattleTurn]
+ and a
+ ld de, wEnemyToxicCount
+ jr z, .ok
+ ld de, wPlayerToxicCount
+.ok
+ ld a, BATTLE_VARS_MOVE_EFFECT
+ call GetBattleVar
+ cp EFFECT_TOXIC
+ ret
+
+CheckIfTargetIsPoisonType:
+ ld de, wEnemyMonType1
+ ldh a, [hBattleTurn]
+ and a
+ jr z, .ok
+ ld de, wBattleMonType1
+.ok
+ ld a, [de]
+ inc de
+ cp POISON
+ ret z
+ ld a, [de]
+ cp POISON
+ ret
+
+PoisonOpponent:
+ ld a, BATTLE_VARS_STATUS_OPP
+ call GetBattleVarAddr
+ set PSN, [hl]
+ jp UpdateOpponentInParty
+
+BattleCommand_DrainTarget:
+; draintarget
+ call SapHealth
+ ld hl, SuckedHealthText
+ jp StdBattleTextbox
+
+BattleCommand_EatDream:
+; eatdream
+ call SapHealth
+ ld hl, DreamEatenText
+ jp StdBattleTextbox
+
+SapHealth:
+ ; Divide damage by 2, store it in hDividend
+ ld hl, wCurDamage
+ ld a, [hli]
+ srl a
+ ldh [hDividend], a
+ ld b, a
+ ld a, [hl]
+ rr a
+ ldh [hDividend + 1], a
+ or b
+ jr nz, .at_least_one
+ ld a, 1
+ ldh [hDividend + 1], a
+.at_least_one
+
+ ld hl, wBattleMonHP
+ ld de, wBattleMonMaxHP
+ ldh a, [hBattleTurn]
+ and a
+ jr z, .battlemonhp
+ ld hl, wEnemyMonHP
+ ld de, wEnemyMonMaxHP
+.battlemonhp
+
+ ; Store current HP in little endian wBuffer3/4
+ ld bc, wBuffer4
+ ld a, [hli]
+ ld [bc], a
+ ld a, [hl]
+ dec bc
+ ld [bc], a
+
+ ; Store max HP in little endian wBuffer1/2
+ ld a, [de]
+ dec bc
+ ld [bc], a
+ inc de
+ ld a, [de]
+ dec bc
+ ld [bc], a
+
+ ; Add hDividend to current HP and copy it to little endian wBuffer5/6
+ ldh a, [hDividend + 1]
+ ld b, [hl]
+ add b
+ ld [hld], a
+ ld [wBuffer5], a
+ ldh a, [hDividend]
+ ld b, [hl]
+ adc b
+ ld [hli], a
+ ld [wBuffer6], a
+ jr c, .max_hp
+
+ ; Substract current HP from max HP (to see if we have more than max HP)
+ ld a, [hld]
+ ld b, a
+ ld a, [de]
+ dec de
+ sub b
+ ld a, [hli]
+ ld b, a
+ ld a, [de]
+ inc de
+ sbc b
+ jr nc, .finish
+
+.max_hp
+ ; Load max HP into current HP and copy it to little endian wBuffer5/6
+ ld a, [de]
+ ld [hld], a
+ ld [wBuffer5], a
+ dec de
+ ld a, [de]
+ ld [hli], a
+ ld [wBuffer6], a
+ inc de
+
+.finish
+ ldh a, [hBattleTurn]
+ and a
+ hlcoord 10, 9
+ ld a, $1
+ jr z, .hp_bar
+ hlcoord 2, 2
+ xor a
+.hp_bar
+ ld [wWhichHPBar], a
+ predef AnimateHPBar
+ call RefreshBattleHuds
+ jp UpdateBattleMonInParty
+
+BattleCommand_BurnTarget:
+; burntarget
+
+ xor a
+ ld [wNumHits], a
+ call CheckSubstituteOpp
+ ret nz
+ ld a, BATTLE_VARS_STATUS_OPP
+ call GetBattleVarAddr
+ and a
+ jp nz, Defrost
+ ld a, [wTypeModifier]
+ and $7f
+ ret z
+ call CheckMoveTypeMatchesTarget ; Don't burn a Fire-type
+ ret z
+ call GetOpponentItem
+ ld a, b
+ cp HELD_PREVENT_BURN
+ ret z
+ ld a, [wEffectFailed]
+ and a
+ ret nz
+ call SafeCheckSafeguard
+ ret nz
+ ld a, BATTLE_VARS_STATUS_OPP
+ call GetBattleVarAddr
+ set BRN, [hl]
+ call UpdateOpponentInParty
+ ld hl, ApplyBrnEffectOnAttack
+ call CallBattleCore
+ ld de, ANIM_BRN
+ call PlayOpponentBattleAnim
+ call RefreshBattleHuds
+
+ ld hl, WasBurnedText
+ call StdBattleTextbox
+
+ farcall UseHeldStatusHealingItem
+ ret
+
+Defrost:
+ ld a, [hl]
+ and 1 << FRZ
+ ret z
+
+ xor a
+ ld [hl], a
+
+ ldh a, [hBattleTurn]
+ and a
+ ld a, [wCurOTMon]
+ ld hl, wOTPartyMon1Status
+ jr z, .ok
+ ld hl, wPartyMon1Status
+ ld a, [wCurBattleMon]
+.ok
+
+ call GetPartyLocation
+ xor a
+ ld [hl], a
+ call UpdateOpponentInParty
+
+ ld hl, DefrostedOpponentText
+ jp StdBattleTextbox
+
+BattleCommand_FreezeTarget:
+; freezetarget
+
+ xor a
+ ld [wNumHits], a
+ call CheckSubstituteOpp
+ ret nz
+ ld a, BATTLE_VARS_STATUS_OPP
+ call GetBattleVarAddr
+ and a
+ ret nz
+ ld a, [wTypeModifier]
+ and $7f
+ ret z
+ ld a, [wBattleWeather]
+ cp WEATHER_SUN
+ ret z
+ call CheckMoveTypeMatchesTarget ; Don't freeze an Ice-type
+ ret z
+ call GetOpponentItem
+ ld a, b
+ cp HELD_PREVENT_FREEZE
+ ret z
+ ld a, [wEffectFailed]
+ and a
+ ret nz
+ call SafeCheckSafeguard
+ ret nz
+ ld a, BATTLE_VARS_STATUS_OPP
+ call GetBattleVarAddr
+ set FRZ, [hl]
+ call UpdateOpponentInParty
+ ld de, ANIM_FRZ
+ call PlayOpponentBattleAnim
+ call RefreshBattleHuds
+
+ ld hl, WasFrozenText
+ call StdBattleTextbox
+
+ farcall UseHeldStatusHealingItem
+ ret nz
+
+ call OpponentCantMove
+ call EndRechargeOpp
+ ld hl, wEnemyJustGotFrozen
+ ldh a, [hBattleTurn]
+ and a
+ jr z, .finish
+ ld hl, wPlayerJustGotFrozen
+.finish
+ ld [hl], $1
+ ret
+
+BattleCommand_ParalyzeTarget:
+; paralyzetarget
+
+ xor a
+ ld [wNumHits], a
+ call CheckSubstituteOpp
+ ret nz
+ ld a, BATTLE_VARS_STATUS_OPP
+ call GetBattleVarAddr
+ and a
+ ret nz
+ ld a, [wTypeModifier]
+ and $7f
+ ret z
+ call GetOpponentItem
+ ld a, b
+ cp HELD_PREVENT_PARALYZE
+ ret z
+ ld a, [wEffectFailed]
+ and a
+ ret nz
+ call SafeCheckSafeguard
+ ret nz
+ ld a, BATTLE_VARS_STATUS_OPP
+ call GetBattleVarAddr
+ set PAR, [hl]
+ call UpdateOpponentInParty
+ ld hl, ApplyPrzEffectOnSpeed
+ call CallBattleCore
+ ld de, ANIM_PAR
+ call PlayOpponentBattleAnim
+ call RefreshBattleHuds
+ call PrintParalyze
+ ld hl, UseHeldStatusHealingItem
+ jp CallBattleCore
+
+BattleCommand_AttackUp:
+; attackup
+ ld b, ATTACK
+ jr BattleCommand_StatUp
+
+BattleCommand_DefenseUp:
+; defenseup
+ ld b, DEFENSE
+ jr BattleCommand_StatUp
+
+BattleCommand_SpeedUp:
+; speedup
+ ld b, SPEED
+ jr BattleCommand_StatUp
+
+BattleCommand_SpecialAttackUp:
+; specialattackup
+ ld b, SP_ATTACK
+ jr BattleCommand_StatUp
+
+BattleCommand_SpecialDefenseUp:
+; specialdefenseup
+ ld b, SP_DEFENSE
+ jr BattleCommand_StatUp
+
+BattleCommand_AccuracyUp:
+; accuracyup
+ ld b, ACCURACY
+ jr BattleCommand_StatUp
+
+BattleCommand_EvasionUp:
+; evasionup
+ ld b, EVASION
+ jr BattleCommand_StatUp
+
+BattleCommand_AttackUp2:
+; attackup2
+ ld b, $10 | ATTACK
+ jr BattleCommand_StatUp
+
+BattleCommand_DefenseUp2:
+; defenseup2
+ ld b, $10 | DEFENSE
+ jr BattleCommand_StatUp
+
+BattleCommand_SpeedUp2:
+; speedup2
+ ld b, $10 | SPEED
+ jr BattleCommand_StatUp
+
+BattleCommand_SpecialAttackUp2:
+; specialattackup2
+ ld b, $10 | SP_ATTACK
+ jr BattleCommand_StatUp
+
+BattleCommand_SpecialDefenseUp2:
+; specialdefenseup2
+ ld b, $10 | SP_DEFENSE
+ jr BattleCommand_StatUp
+
+BattleCommand_AccuracyUp2:
+; accuracyup2
+ ld b, $10 | ACCURACY
+ jr BattleCommand_StatUp
+
+BattleCommand_EvasionUp2:
+; evasionup2
+ ld b, $10 | EVASION
+ jr BattleCommand_StatUp
+
+BattleCommand_StatUp:
+; statup
+ call RaiseStat
+ ld a, [wFailedMessage]
+ and a
+ ret nz
+ jp MinimizeDropSub
+
+RaiseStat:
+ ld a, b
+ ld [wLoweredStat], a
+ ld hl, wPlayerStatLevels
+ ldh a, [hBattleTurn]
+ and a
+ jr z, .got_stat_levels
+ ld hl, wEnemyStatLevels
+.got_stat_levels
+ ld a, [wAttackMissed]
+ and a
+ jp nz, .stat_raise_failed
+ ld a, [wEffectFailed]
+ and a
+ jp nz, .stat_raise_failed
+ ld a, [wLoweredStat]
+ and $f
+ ld c, a
+ ld b, 0
+ add hl, bc
+ ld b, [hl]
+ inc b
+ ld a, $d
+ cp b
+ jp c, .cant_raise_stat
+ ld a, [wLoweredStat]
+ and $f0
+ jr z, .got_num_stages
+ inc b
+ ld a, $d
+ cp b
+ jr nc, .got_num_stages
+ ld b, a
+.got_num_stages
+ ld [hl], b
+ push hl
+ ld a, c
+ cp $5
+ jr nc, .done_calcing_stats
+ ld hl, wBattleMonStats + 1
+ ld de, wPlayerStats
+ ldh a, [hBattleTurn]
+ and a
+ jr z, .got_stats_pointer
+ ld hl, wEnemyMonStats + 1
+ ld de, wEnemyStats
+.got_stats_pointer
+ push bc
+ sla c
+ ld b, 0
+ add hl, bc
+ ld a, c
+ add e
+ ld e, a
+ jr nc, .no_carry
+ inc d
+.no_carry
+ pop bc
+ ld a, [hld]
+ sub LOW(MAX_STAT_VALUE)
+ jr nz, .not_already_max
+ ld a, [hl]
+ sbc HIGH(MAX_STAT_VALUE)
+ jp z, .stats_already_max
+.not_already_max
+ ldh a, [hBattleTurn]
+ and a
+ jr z, .calc_player_stats
+ call CalcEnemyStats
+ jr .done_calcing_stats
+
+.calc_player_stats
+ call CalcPlayerStats
+.done_calcing_stats
+ pop hl
+ xor a
+ ld [wFailedMessage], a
+ ret
+
+.stats_already_max
+ pop hl
+ dec [hl]
+ ; fallthrough
+
+.cant_raise_stat
+ ld a, $2
+ ld [wFailedMessage], a
+ ld a, $1
+ ld [wAttackMissed], a
+ ret
+
+.stat_raise_failed
+ ld a, $1
+ ld [wFailedMessage], a
+ ret
+
+MinimizeDropSub:
+; Lower the substitute if we're minimizing
+
+ ld bc, wPlayerMinimized
+ ld hl, DropPlayerSub
+ ldh a, [hBattleTurn]
+ and a
+ jr z, .do_player
+ ld bc, wEnemyMinimized
+ ld hl, DropEnemySub
+.do_player
+ ld a, BATTLE_VARS_MOVE_ANIM
+ call GetBattleVar
+ cp MINIMIZE
+ ret nz
+
+ ld a, $1
+ ld [bc], a
+ ; check battle scene
+ ld a, [wOptions]
+ add a
+ ret nc
+
+ xor a
+ ldh [hBGMapMode], a
+ call CallBattleCore
+ call WaitBGMap
+ jp BattleCommand_MoveDelay
+
+BattleCommand_AttackDown:
+; attackdown
+ ld a, ATTACK
+ jr BattleCommand_StatDown
+
+BattleCommand_DefenseDown:
+; defensedown
+ ld a, DEFENSE
+ jr BattleCommand_StatDown
+
+BattleCommand_SpeedDown:
+; speeddown
+ ld a, SPEED
+ jr BattleCommand_StatDown
+
+BattleCommand_SpecialAttackDown:
+; specialattackdown
+ ld a, SP_ATTACK
+ jr BattleCommand_StatDown
+
+BattleCommand_SpecialDefenseDown:
+; specialdefensedown
+ ld a, SP_DEFENSE
+ jr BattleCommand_StatDown
+
+BattleCommand_AccuracyDown:
+; accuracydown
+ ld a, ACCURACY
+ jr BattleCommand_StatDown
+
+BattleCommand_EvasionDown:
+; evasiondown
+ ld a, EVASION
+ jr BattleCommand_StatDown
+
+BattleCommand_AttackDown2:
+; attackdown2
+ ld a, $10 | ATTACK
+ jr BattleCommand_StatDown
+
+BattleCommand_DefenseDown2:
+; defensedown2
+ ld a, $10 | DEFENSE
+ jr BattleCommand_StatDown
+
+BattleCommand_SpeedDown2:
+; speeddown2
+ ld a, $10 | SPEED
+ jr BattleCommand_StatDown
+
+BattleCommand_SpecialAttackDown2:
+; specialattackdown2
+ ld a, $10 | SP_ATTACK
+ jr BattleCommand_StatDown
+
+BattleCommand_SpecialDefenseDown2:
+; specialdefensedown2
+ ld a, $10 | SP_DEFENSE
+ jr BattleCommand_StatDown
+
+BattleCommand_AccuracyDown2:
+; accuracydown2
+ ld a, $10 | ACCURACY
+ jr BattleCommand_StatDown
+
+BattleCommand_EvasionDown2:
+; evasiondown2
+ ld a, $10 | EVASION
+
+BattleCommand_StatDown:
+; statdown
+
+ ld [wLoweredStat], a
+
+ call CheckMist
+ jp nz, .Mist
+
+ ld hl, wEnemyStatLevels
+ ldh a, [hBattleTurn]
+ and a
+ jr z, .GetStatLevel
+ ld hl, wPlayerStatLevels
+
+.GetStatLevel:
+; Attempt to lower the stat.
+ ld a, [wLoweredStat]
+ and $f
+ ld c, a
+ ld b, 0
+ add hl, bc
+ ld b, [hl]
+ dec b
+ jp z, .CantLower
+
+; Sharply lower the stat if applicable.
+ ld a, [wLoweredStat]
+ and $f0
+ jr z, .ComputerMiss
+ dec b
+ jr nz, .ComputerMiss
+ inc b
+
+.ComputerMiss:
+; Computer opponents have a 25% chance of failing.
+ ldh a, [hBattleTurn]
+ and a
+ jr z, .DidntMiss
+
+ ld a, [wLinkMode]
+ and a
+ jr nz, .DidntMiss
+
+; Lock-On still always works.
+ ld a, [wPlayerSubStatus5]
+ bit SUBSTATUS_LOCK_ON, a
+ jr nz, .DidntMiss
+
+; Attacking moves that also lower accuracy are unaffected.
+ ld a, BATTLE_VARS_MOVE_EFFECT
+ call GetBattleVar
+ cp EFFECT_ACCURACY_DOWN_HIT
+ jr z, .DidntMiss
+
+ call BattleRandom
+ cp 25 percent + 1 ; 25% chance AI fails
+ jr c, .Failed
+
+.DidntMiss:
+ call CheckSubstituteOpp
+ jr nz, .Failed
+
+ ld a, [wAttackMissed]
+ and a
+ jr nz, .Failed
+
+ ld a, [wEffectFailed]
+ and a
+ jr nz, .Failed
+
+ call CheckHiddenOpponent
+ jr nz, .Failed
+
+; Accuracy/Evasion reduction don't involve stats.
+ ld [hl], b
+ ld a, c
+ cp ACCURACY
+ jr nc, .Hit
+
+ push hl
+ ld hl, wEnemyMonAttack + 1
+ ld de, wEnemyStats
+ ldh a, [hBattleTurn]
+ and a
+ jr z, .do_enemy
+ ld hl, wBattleMonAttack + 1
+ ld de, wPlayerStats
+.do_enemy
+ call TryLowerStat
+ pop hl
+ jr z, .CouldntLower
+
+.Hit:
+ xor a
+ ld [wFailedMessage], a
+ ret
+
+.CouldntLower:
+ inc [hl]
+.CantLower:
+ ld a, 3
+ ld [wFailedMessage], a
+ ld a, 1
+ ld [wAttackMissed], a
+ ret
+
+.Failed:
+ ld a, 1
+ ld [wFailedMessage], a
+ ld [wAttackMissed], a
+ ret
+
+.Mist:
+ ld a, 2
+ ld [wFailedMessage], a
+ ld a, 1
+ ld [wAttackMissed], a
+ ret
+
+CheckMist:
+ ld a, BATTLE_VARS_MOVE_EFFECT
+ call GetBattleVar
+ cp EFFECT_ATTACK_DOWN
+ jr c, .dont_check_mist
+ cp EFFECT_EVASION_DOWN + 1
+ jr c, .check_mist
+ cp EFFECT_ATTACK_DOWN_2
+ jr c, .dont_check_mist
+ cp EFFECT_EVASION_DOWN_2 + 1
+ jr c, .check_mist
+ cp EFFECT_ATTACK_DOWN_HIT
+ jr c, .dont_check_mist
+ cp EFFECT_EVASION_DOWN_HIT + 1
+ jr c, .check_mist
+.dont_check_mist
+ xor a
+ ret
+
+.check_mist
+ ld a, BATTLE_VARS_SUBSTATUS4_OPP
+ call GetBattleVar
+ bit SUBSTATUS_MIST, a
+ ret
+
+BattleCommand_StatUpMessage:
+ ld a, [wFailedMessage]
+ and a
+ ret nz
+ ld a, [wLoweredStat]
+ and $f
+ ld b, a
+ inc b
+ call GetStatName
+ ld hl, .stat
+ jp PrintText
+
+.stat
+ text_far Text_BattleEffectActivate
+ text_asm
+ ld hl, .BattleStatWentUpText
+ ld a, [wLoweredStat]
+ and $f0
+ ret z
+ ld hl, .BattleStatWentWayUpText
+ ret
+
+.BattleStatWentWayUpText:
+ text_far _BattleStatWentWayUpText
+ text_end
+
+.BattleStatWentUpText:
+ text_far _BattleStatWentUpText
+ text_end
+
+BattleCommand_StatDownMessage:
+ ld a, [wFailedMessage]
+ and a
+ ret nz
+ ld a, [wLoweredStat]
+ and $f
+ ld b, a
+ inc b
+ call GetStatName
+ ld hl, .stat
+ jp PrintText
+
+.stat
+ text_far Text_BattleFoeEffectActivate
+ text_asm
+ ld hl, .BattleStatFellText
+ ld a, [wLoweredStat]
+ and $f0
+ ret z
+ ld hl, .BattleStatSharplyFellText
+ ret
+
+.BattleStatSharplyFellText:
+ text_far _BattleStatSharplyFellText
+ text_end
+
+.BattleStatFellText:
+ text_far _BattleStatFellText
+ text_end
+
+TryLowerStat:
+; Lower stat c from stat struct hl (buffer de).
+
+ push bc
+ sla c
+ ld b, 0
+ add hl, bc
+ ; add de, c
+ ld a, c
+ add e
+ ld e, a
+ jr nc, .no_carry
+ inc d
+.no_carry
+ pop bc
+
+; The lowest possible stat is 1.
+ ld a, [hld]
+ sub 1
+ jr nz, .not_min
+ ld a, [hl]
+ and a
+ ret z
+
+.not_min
+ ldh a, [hBattleTurn]
+ and a
+ jr z, .Player
+
+ call BattleCommand_SwitchTurn
+ call CalcPlayerStats
+ call BattleCommand_SwitchTurn
+ jr .end
+
+.Player:
+ call BattleCommand_SwitchTurn
+ call CalcEnemyStats
+ call BattleCommand_SwitchTurn
+.end
+ ld a, 1
+ and a
+ ret
+
+BattleCommand_StatUpFailText:
+; statupfailtext
+ ld a, [wFailedMessage]
+ and a
+ ret z
+ push af
+ call BattleCommand_MoveDelay
+ pop af
+ dec a
+ jp z, TryPrintButItFailed
+ ld a, [wLoweredStat]
+ and $f
+ ld b, a
+ inc b
+ call GetStatName
+ ld hl, WontRiseAnymoreText
+ jp StdBattleTextbox
+
+BattleCommand_StatDownFailText:
+; statdownfailtext
+ ld a, [wFailedMessage]
+ and a
+ ret z
+ push af
+ call BattleCommand_MoveDelay
+ pop af
+ dec a
+ jp z, TryPrintButItFailed
+ dec a
+ ld hl, ProtectedByMistText
+ jp z, StdBattleTextbox
+ ld a, [wLoweredStat]
+ and $f
+ ld b, a
+ inc b
+ call GetStatName
+ ld hl, WontDropAnymoreText
+ jp StdBattleTextbox
+
+GetStatName:
+ ld hl, StatNames
+ ld c, "@"
+.CheckName:
+ dec b
+ jr z, .Copy
+.GetName:
+ ld a, [hli]
+ cp c
+ jr z, .CheckName
+ jr .GetName
+
+.Copy:
+ ld de, wStringBuffer2
+ ld bc, 10
+ jp CopyBytes
+
+INCLUDE "data/battle/stat_names.asm"
+
+INCLUDE "data/battle/stat_multipliers.asm"
+
+BattleCommand_AllStatsUp:
+; allstatsup
+
+; Attack
+ call ResetMiss
+ call BattleCommand_AttackUp
+ call BattleCommand_StatUpMessage
+
+; Defense
+ call ResetMiss
+ call BattleCommand_DefenseUp
+ call BattleCommand_StatUpMessage
+
+; Speed
+ call ResetMiss
+ call BattleCommand_SpeedUp
+ call BattleCommand_StatUpMessage
+
+; Special Attack
+ call ResetMiss
+ call BattleCommand_SpecialAttackUp
+ call BattleCommand_StatUpMessage
+
+; Special Defense
+ call ResetMiss
+ call BattleCommand_SpecialDefenseUp
+ jp BattleCommand_StatUpMessage
+
+ResetMiss:
+ xor a
+ ld [wAttackMissed], a
+ ret
+
+LowerStat:
+ ld [wLoweredStat], a
+
+ ld hl, wPlayerStatLevels
+ ldh a, [hBattleTurn]
+ and a
+ jr z, .got_target
+ ld hl, wEnemyStatLevels
+
+.got_target
+ ld a, [wLoweredStat]
+ and $f
+ ld c, a
+ ld b, 0
+ add hl, bc
+ ld b, [hl]
+ dec b
+ jr z, .cant_lower_anymore
+
+ ld a, [wLoweredStat]
+ and $f0
+ jr z, .got_num_stages
+ dec b
+ jr nz, .got_num_stages
+ inc b
+
+.got_num_stages
+ ld [hl], b
+ ld a, c
+ cp 5
+ jr nc, .accuracy_evasion
+
+ push hl
+ ld hl, wBattleMonStats + 1
+ ld de, wPlayerStats
+ ldh a, [hBattleTurn]
+ and a
+ jr z, .got_target_2
+ ld hl, wEnemyMonStats + 1
+ ld de, wEnemyStats
+
+.got_target_2
+ call TryLowerStat
+ pop hl
+ jr z, .failed
+
+.accuracy_evasion
+ ldh a, [hBattleTurn]
+ and a
+ jr z, .player
+
+ call CalcEnemyStats
+
+ jr .finish
+
+.player
+ call CalcPlayerStats
+
+.finish
+ xor a
+ ld [wFailedMessage], a
+ ret
+
+.failed
+ inc [hl]
+
+.cant_lower_anymore
+ ld a, 2
+ ld [wFailedMessage], a
+ ret
+
+BattleCommand_TriStatusChance:
+; tristatuschance
+
+ call BattleCommand_EffectChance
+
+.loop
+ ; 1/3 chance of each status
+ call BattleRandom
+ swap a
+ and %11
+ jr z, .loop
+ dec a
+ ld hl, .ptrs
+ rst JumpTable
+ ret
+
+.ptrs
+ dw BattleCommand_ParalyzeTarget ; paralyze
+ dw BattleCommand_FreezeTarget ; freeze
+ dw BattleCommand_BurnTarget ; burn
+
+BattleCommand_Curl:
+; curl
+ ld a, BATTLE_VARS_SUBSTATUS2
+ call GetBattleVarAddr
+ set SUBSTATUS_CURLED, [hl]
+ ret
+
+BattleCommand_RaiseSubNoAnim:
+ ld hl, GetBattleMonBackpic
+ ldh a, [hBattleTurn]
+ and a
+ jr z, .PlayerTurn
+ ld hl, GetEnemyMonFrontpic
+.PlayerTurn:
+ xor a
+ ldh [hBGMapMode], a
+ call CallBattleCore
+ jp WaitBGMap
+
+BattleCommand_LowerSubNoAnim:
+ ld hl, DropPlayerSub
+ ldh a, [hBattleTurn]
+ and a
+ jr z, .PlayerTurn
+ ld hl, DropEnemySub
+.PlayerTurn:
+ xor a
+ ldh [hBGMapMode], a
+ call CallBattleCore
+ jp WaitBGMap
+
+CalcPlayerStats:
+ ld hl, wPlayerAtkLevel
+ ld de, wPlayerStats
+ ld bc, wBattleMonAttack
+
+ ld a, 5
+ call CalcBattleStats
+
+ ld hl, BadgeStatBoosts
+ call CallBattleCore
+
+ call BattleCommand_SwitchTurn
+
+ ld hl, ApplyPrzEffectOnSpeed
+ call CallBattleCore
+
+ ld hl, ApplyBrnEffectOnAttack
+ call CallBattleCore
+
+ jp BattleCommand_SwitchTurn
+
+CalcEnemyStats:
+ ld hl, wEnemyAtkLevel
+ ld de, wEnemyStats
+ ld bc, wEnemyMonAttack
+
+ ld a, 5
+ call CalcBattleStats
+
+ call BattleCommand_SwitchTurn
+
+ ld hl, ApplyPrzEffectOnSpeed
+ call CallBattleCore
+
+ ld hl, ApplyBrnEffectOnAttack
+ call CallBattleCore
+
+ jp BattleCommand_SwitchTurn
+
+CalcBattleStats:
+.loop
+ push af
+ ld a, [hli]
+ push hl
+ push bc
+
+ ld c, a
+ dec c
+ ld b, 0
+ ld hl, StatLevelMultipliers
+ add hl, bc
+ add hl, bc
+
+ xor a
+ ldh [hMultiplicand + 0], a
+ ld a, [de]
+ ldh [hMultiplicand + 1], a
+ inc de
+ ld a, [de]
+ ldh [hMultiplicand + 2], a
+ inc de
+
+ ld a, [hli]
+ ldh [hMultiplier], a
+ call Multiply
+
+ ld a, [hl]
+ ldh [hDivisor], a
+ ld b, 4
+ call Divide
+
+ ldh a, [hQuotient + 2]
+ ld b, a
+ ldh a, [hQuotient + 3]
+ or b
+ jr nz, .check_maxed_out
+
+ ld a, 1
+ ldh [hQuotient + 3], a
+ jr .not_maxed_out
+
+.check_maxed_out
+ ldh a, [hQuotient + 3]
+ cp LOW(MAX_STAT_VALUE)
+ ld a, b
+ sbc HIGH(MAX_STAT_VALUE)
+ jr c, .not_maxed_out
+
+ ld a, LOW(MAX_STAT_VALUE)
+ ldh [hQuotient + 3], a
+ ld a, HIGH(MAX_STAT_VALUE)
+ ldh [hQuotient + 2], a
+
+.not_maxed_out
+ pop bc
+ ldh a, [hQuotient + 2]
+ ld [bc], a
+ inc bc
+ ldh a, [hQuotient + 3]
+ ld [bc], a
+ inc bc
+ pop hl
+ pop af
+ dec a
+ jr nz, .loop
+
+ ret
+
+INCLUDE "engine/battle/move_effects/bide.asm"
+
+BattleCommand_CheckRampage:
+; checkrampage
+
+ ld de, wPlayerRolloutCount
+ ldh a, [hBattleTurn]
+ and a
+ jr z, .player
+ ld de, wEnemyRolloutCount
+.player
+ ld a, BATTLE_VARS_SUBSTATUS3
+ call GetBattleVarAddr
+ bit SUBSTATUS_RAMPAGE, [hl]
+ ret z
+ ld a, [de]
+ dec a
+ ld [de], a
+ jr nz, .continue_rampage
+
+ res SUBSTATUS_RAMPAGE, [hl]
+ call BattleCommand_SwitchTurn
+ call SafeCheckSafeguard
+ push af
+ call BattleCommand_SwitchTurn
+ pop af
+ jr nz, .continue_rampage
+
+ set SUBSTATUS_CONFUSED, [hl]
+ call BattleRandom
+ and %00000001
+ inc a
+ inc a
+ inc de ; ConfuseCount
+ ld [de], a
+.continue_rampage
+ ld b, rampage_command
+ jp SkipToBattleCommand
+
+BattleCommand_Rampage:
+; rampage
+
+; No rampage during Sleep Talk.
+ ld a, BATTLE_VARS_STATUS
+ call GetBattleVar
+ and SLP
+ ret nz
+
+ ld de, wPlayerRolloutCount
+ ldh a, [hBattleTurn]
+ and a
+ jr z, .ok
+ ld de, wEnemyRolloutCount
+.ok
+ ld a, BATTLE_VARS_SUBSTATUS3
+ call GetBattleVarAddr
+ set SUBSTATUS_RAMPAGE, [hl]
+; Rampage for 1 or 2 more turns
+ call BattleRandom
+ and %00000001
+ inc a
+ ld [de], a
+ ld a, 1
+ ld [wSomeoneIsRampaging], a
+ ret
+
+INCLUDE "engine/battle/move_effects/teleport.asm"
+
+BattleCommand_ForceSwitch:
+; forceswitch
+
+ ld a, [wBattleType]
+ cp BATTLETYPE_SHINY
+ jp z, .fail
+ cp BATTLETYPE_TRAP
+ jp z, .fail
+ ldh a, [hBattleTurn]
+ and a
+ jp nz, .force_player_switch
+ ld a, [wAttackMissed]
+ and a
+ jr nz, .missed
+ ld a, [wBattleMode]
+ dec a
+ jr nz, .trainer
+ ld a, [wCurPartyLevel]
+ ld b, a
+ ld a, [wBattleMonLevel]
+ cp b
+ jr nc, .wild_force_flee
+ add b
+ ld c, a
+ inc c
+.random_loop_wild
+ call BattleRandom
+ cp c
+ jr nc, .random_loop_wild
+ srl b
+ srl b
+ cp b
+ jr nc, .wild_force_flee
+.missed
+ jp .fail
+
+.wild_force_flee
+ call UpdateBattleMonInParty
+ xor a
+ ld [wNumHits], a
+ inc a
+ ld [wForcedSwitch], a
+ ; set battle draw
+ inc a
+ ld [wBattleResult], a
+ ld a, [wPlayerMoveStructAnimation]
+ jp .succeed
+
+.trainer
+ call FindAliveEnemyMons
+ jr c, .switch_fail
+ ld a, [wEnemyGoesFirst]
+ and a
+ jr z, .switch_fail
+ call UpdateEnemyMonInParty
+ ld a, $1
+ ld [wKickCounter], a
+ call AnimateCurrentMove
+ ld c, $14
+ call DelayFrames
+ hlcoord 1, 0
+ lb bc, 4, 10
+ call ClearBox
+ ld c, 20
+ call DelayFrames
+ ld a, [wOTPartyCount]
+ ld b, a
+ ld a, [wCurOTMon]
+ ld c, a
+; select a random enemy mon to switch to
+.random_loop_trainer
+ call BattleRandom
+ and $7
+ cp b
+ jr nc, .random_loop_trainer
+ cp c
+ jr z, .random_loop_trainer
+ push af
+ push bc
+ ld hl, wOTPartyMon1HP
+ call GetPartyLocation
+ ld a, [hli]
+ or [hl]
+ pop bc
+ pop de
+ jr z, .random_loop_trainer
+ ld a, d
+ inc a
+ ld [wEnemySwitchMonIndex], a
+ callfar ForceEnemySwitch
+
+ ld hl, DraggedOutText
+ call StdBattleTextbox
+
+ ld hl, SpikesDamage
+ jp CallBattleCore
+
+.switch_fail
+ jp .fail
+
+.force_player_switch
+ ld a, [wAttackMissed]
+ and a
+ jr nz, .player_miss
+
+ ld a, [wBattleMode]
+ dec a
+ jr nz, .vs_trainer
+
+ ld a, [wBattleMonLevel]
+ ld b, a
+ ld a, [wCurPartyLevel]
+ cp b
+ jr nc, .wild_succeed_playeristarget
+
+ add b
+ ld c, a
+ inc c
+.wild_random_loop_playeristarget
+ call BattleRandom
+ cp c
+ jr nc, .wild_random_loop_playeristarget
+
+ srl b
+ srl b
+ cp b
+ jr nc, .wild_succeed_playeristarget
+
+.player_miss
+ jp .fail
+
+.wild_succeed_playeristarget
+ call UpdateBattleMonInParty
+ xor a
+ ld [wNumHits], a
+ inc a
+ ld [wForcedSwitch], a
+ ; set battle draw
+ inc a
+ ld [wBattleResult], a
+ ld a, [wEnemyMoveStructAnimation]
+ jr .succeed
+
+.vs_trainer
+ call CheckPlayerHasMonToSwitchTo
+ jr c, .switch_fail2
+
+ ld a, [wEnemyGoesFirst]
+ cp $1
+ jr z, .switch_fail
+
+ call UpdateBattleMonInParty
+ ld a, $1
+ ld [wKickCounter], a
+ call AnimateCurrentMove
+ ld c, 20
+ call DelayFrames
+ hlcoord 9, 7
+ lb bc, 5, 11
+ call ClearBox
+ ld c, 20
+ call DelayFrames
+ ld a, [wPartyCount]
+ ld b, a
+ ld a, [wCurBattleMon]
+ ld c, a
+.random_loop_trainer_playeristarget
+ call BattleRandom
+ and $7
+ cp b
+ jr nc, .random_loop_trainer_playeristarget
+
+ cp c
+ jr z, .random_loop_trainer_playeristarget
+
+ push af
+ push bc
+ ld hl, wPartyMon1HP
+ call GetPartyLocation
+ ld a, [hli]
+ or [hl]
+ pop bc
+ pop de
+ jr z, .random_loop_trainer_playeristarget
+
+ ld a, d
+ ld [wCurPartyMon], a
+ ld hl, SwitchPlayerMon
+ call CallBattleCore
+
+ ld hl, DraggedOutText
+ call StdBattleTextbox
+
+ ld hl, SpikesDamage
+ jp CallBattleCore
+
+.switch_fail2
+ jr .fail
+
+.succeed
+ push af
+ ld a, DRAW
+ ld [wBattleResult], a
+ ld a, $1
+ ld [wKickCounter], a
+ call AnimateCurrentMove
+ ld c, 20
+ call DelayFrames
+ pop af
+
+ ld hl, FledInFearText
+ cp ROAR
+ jr z, .do_text
+ ld hl, BlownAwayText
+.do_text
+ jp StdBattleTextbox
+
+.fail
+ call BattleCommand_LowerSub
+ call BattleCommand_MoveDelay
+ call BattleCommand_RaiseSub
+ jp PrintButItFailed
+
+CheckPlayerHasMonToSwitchTo:
+ ld a, [wPartyCount]
+ ld d, a
+ ld e, 0
+ ld bc, PARTYMON_STRUCT_LENGTH
+.loop
+ ld a, [wCurBattleMon]
+ cp e
+ jr z, .next
+
+ ld a, e
+ ld hl, wPartyMon1HP
+ call AddNTimes
+ ld a, [hli]
+ or [hl]
+ jr nz, .not_fainted
+
+.next
+ inc e
+ dec d
+ jr nz, .loop
+
+ scf
+ ret
+
+.not_fainted
+ and a
+ ret
+
+BattleCommand_EndLoop:
+; endloop
+
+; Loop back to 'critical'.
+
+ ld de, wPlayerRolloutCount
+ ld bc, wPlayerDamageTaken
+ ldh a, [hBattleTurn]
+ and a
+ jr z, .got_addrs
+ ld de, wEnemyRolloutCount
+ ld bc, wEnemyDamageTaken
+.got_addrs
+
+ ld a, BATTLE_VARS_SUBSTATUS3
+ call GetBattleVarAddr
+ bit SUBSTATUS_IN_LOOP, [hl]
+ jp nz, .in_loop
+ set SUBSTATUS_IN_LOOP, [hl]
+ ld a, BATTLE_VARS_MOVE_EFFECT
+ call GetBattleVarAddr
+ ld a, [hl]
+ cp EFFECT_POISON_MULTI_HIT
+ jr z, .twineedle
+ cp EFFECT_DOUBLE_HIT
+ ld a, 1
+ jr z, .double_hit
+ ld a, [hl]
+ cp EFFECT_BEAT_UP
+ jr z, .beat_up
+ cp EFFECT_TRIPLE_KICK
+ jr nz, .not_triple_kick
+.reject_triple_kick_sample
+ call BattleRandom
+ and $3
+ jr z, .reject_triple_kick_sample
+ dec a
+ jr nz, .double_hit
+ ld a, 1
+ ld [bc], a
+ jr .done_loop
+
+.beat_up
+ ldh a, [hBattleTurn]
+ and a
+ jr nz, .check_ot_beat_up
+ ld a, [wPartyCount]
+ cp 1
+ jp z, .only_one_beatup
+ dec a
+ jr .double_hit
+
+.check_ot_beat_up
+ ld a, [wBattleMode]
+ cp WILD_BATTLE
+ jp z, .only_one_beatup
+ ld a, [wOTPartyCount]
+ cp 1
+ jp z, .only_one_beatup
+ dec a
+ jr .double_hit
+
+.only_one_beatup
+ ld a, BATTLE_VARS_SUBSTATUS3
+ call GetBattleVarAddr
+ res SUBSTATUS_IN_LOOP, [hl]
+ call BattleCommand_BeatUpFailText
+ jp EndMoveEffect
+
+.not_triple_kick
+ call BattleRandom
+ and $3
+ cp 2
+ jr c, .got_number_hits
+ call BattleRandom
+ and $3
+.got_number_hits
+ inc a
+.double_hit
+ ld [de], a
+ inc a
+ ld [bc], a
+ jr .loop_back_to_critical
+
+.twineedle
+ ld a, 1
+ jr .double_hit
+
+.in_loop
+ ld a, [de]
+ dec a
+ ld [de], a
+ jr nz, .loop_back_to_critical
+.done_loop
+ ld a, BATTLE_VARS_SUBSTATUS3
+ call GetBattleVarAddr
+ res SUBSTATUS_IN_LOOP, [hl]
+
+ ld hl, PlayerHitTimesText
+ ldh a, [hBattleTurn]
+ and a
+ jr z, .got_hit_n_times_text
+ ld hl, EnemyHitTimesText
+.got_hit_n_times_text
+
+ push bc
+ ld a, BATTLE_VARS_MOVE_EFFECT
+ call GetBattleVar
+ cp EFFECT_BEAT_UP
+ jr z, .beat_up_2
+ call StdBattleTextbox
+.beat_up_2
+
+ pop bc
+ xor a
+ ld [bc], a
+ ret
+
+.loop_back_to_critical
+ ld a, [wBattleScriptBufferAddress + 1]
+ ld h, a
+ ld a, [wBattleScriptBufferAddress]
+ ld l, a
+.not_critical
+ ld a, [hld]
+ cp critical_command
+ jr nz, .not_critical
+ inc hl
+ ld a, h
+ ld [wBattleScriptBufferAddress + 1], a
+ ld a, l
+ ld [wBattleScriptBufferAddress], a
+ ret
+
+BattleCommand_FakeOut:
+ ld a, [wAttackMissed]
+ and a
+ ret nz
+
+ call CheckSubstituteOpp
+ jr nz, .fail
+
+ ld a, BATTLE_VARS_STATUS_OPP
+ call GetBattleVar
+ and 1 << FRZ | SLP
+ jr nz, .fail
+
+ call CheckOpponentWentFirst
+ jr z, FlinchTarget
+
+.fail
+ ld a, 1
+ ld [wAttackMissed], a
+ ret
+
+BattleCommand_FlinchTarget:
+ call CheckSubstituteOpp
+ ret nz
+
+ ld a, BATTLE_VARS_STATUS_OPP
+ call GetBattleVar
+ and 1 << FRZ | SLP
+ ret nz
+
+ call CheckOpponentWentFirst
+ ret nz
+
+ ld a, [wEffectFailed]
+ and a
+ ret nz
+
+ ; fallthrough
+
+FlinchTarget:
+ ld a, BATTLE_VARS_SUBSTATUS3_OPP
+ call GetBattleVarAddr
+ set SUBSTATUS_FLINCHED, [hl]
+ jp EndRechargeOpp
+
+CheckOpponentWentFirst:
+; Returns a=0, z if user went first
+; Returns a=1, nz if opponent went first
+ push bc
+ ld a, [wEnemyGoesFirst] ; 0 if player went first
+ ld b, a
+ ldh a, [hBattleTurn] ; 0 if it's the player's turn
+ xor b ; 1 if opponent went first
+ pop bc
+ ret
+
+BattleCommand_HeldFlinch:
+; kingsrock
+
+ ld a, [wAttackMissed]
+ and a
+ ret nz
+
+ call GetUserItem
+ ld a, b
+ cp HELD_FLINCH
+ ret nz
+
+ call CheckSubstituteOpp
+ ret nz
+ ld a, BATTLE_VARS_MOVE_EFFECT
+ call GetBattleVarAddr
+ ld d, h
+ ld e, l
+ call GetUserItem
+ call BattleRandom
+ cp c
+ ret nc
+ call EndRechargeOpp
+ ld a, BATTLE_VARS_SUBSTATUS3_OPP
+ call GetBattleVarAddr
+ set SUBSTATUS_FLINCHED, [hl]
+ ret
+
+BattleCommand_OHKO:
+; ohko
+
+ call ResetDamage
+ ld a, [wTypeModifier]
+ and $7f
+ jr z, .no_effect
+ ld hl, wEnemyMonLevel
+ ld de, wBattleMonLevel
+ ld bc, wPlayerMoveStruct + MOVE_ACC
+ ldh a, [hBattleTurn]
+ and a
+ jr z, .got_move_accuracy
+ push hl
+ ld h, d
+ ld l, e
+ pop de
+ ld bc, wEnemyMoveStruct + MOVE_ACC
+.got_move_accuracy
+ ld a, [de]
+ sub [hl]
+ jr c, .no_effect
+ add a
+ ld e, a
+ ld a, [bc]
+ add e
+ jr nc, .finish_ohko
+ ld a, $ff
+.finish_ohko
+ ld [bc], a
+ call BattleCommand_CheckHit
+ ld hl, wCurDamage
+ ld a, $ff
+ ld [hli], a
+ ld [hl], a
+ ld a, $2
+ ld [wCriticalHit], a
+ ret
+
+.no_effect
+ ld a, $ff
+ ld [wCriticalHit], a
+ ld a, $1
+ ld [wAttackMissed], a
+ ret
+
+BattleCommand_CheckCharge:
+; checkcharge
+
+ ld a, BATTLE_VARS_SUBSTATUS3
+ call GetBattleVarAddr
+ bit SUBSTATUS_CHARGED, [hl]
+ ret z
+ res SUBSTATUS_CHARGED, [hl]
+ res SUBSTATUS_UNDERGROUND, [hl]
+ res SUBSTATUS_FLYING, [hl]
+ ld b, charge_command
+ jp SkipToBattleCommand
+
+BattleCommand_Charge:
+; charge
+
+ call BattleCommand_ClearText
+ ld a, BATTLE_VARS_STATUS
+ call GetBattleVar
+ and SLP
+ jr z, .awake
+
+ call BattleCommand_MoveDelay
+ call BattleCommand_RaiseSub
+ call PrintButItFailed
+ jp EndMoveEffect
+
+.awake
+ ld a, BATTLE_VARS_SUBSTATUS3
+ call GetBattleVarAddr
+ set SUBSTATUS_CHARGED, [hl]
+
+ ld hl, IgnoredOrders2Text
+ ld a, [wAlreadyDisobeyed]
+ and a
+ call nz, StdBattleTextbox
+
+ call BattleCommand_LowerSub
+ xor a
+ ld [wNumHits], a
+ inc a
+ ld [wKickCounter], a
+ call LoadMoveAnim
+ ld a, BATTLE_VARS_MOVE_ANIM
+ call GetBattleVar
+ cp FLY
+ jr z, .flying
+ cp DIG
+ jr z, .flying
+ call BattleCommand_RaiseSub
+ jr .not_flying
+
+.flying
+ call DisappearUser
+.not_flying
+ ld a, BATTLE_VARS_SUBSTATUS3
+ call GetBattleVarAddr
+ ld a, BATTLE_VARS_MOVE_ANIM
+ call GetBattleVar
+ ld b, a
+ cp FLY
+ jr z, .set_flying
+ cp DIG
+ jr nz, .dont_set_digging
+ set SUBSTATUS_UNDERGROUND, [hl]
+ jr .dont_set_digging
+
+.set_flying
+ set SUBSTATUS_FLYING, [hl]
+
+.dont_set_digging
+ call CheckUserIsCharging
+ jr nz, .mimic
+ ld a, BATTLE_VARS_LAST_COUNTER_MOVE
+ call GetBattleVarAddr
+ ld [hl], b
+ ld a, BATTLE_VARS_LAST_MOVE
+ call GetBattleVarAddr
+ ld [hl], b
+
+.mimic
+ call ResetDamage
+
+ ld hl, .UsedText
+ call PrintText
+
+ ld a, BATTLE_VARS_MOVE_EFFECT
+ call GetBattleVar
+ cp EFFECT_SKULL_BASH
+ ld b, endturn_command
+ jp z, SkipToBattleCommand
+ jp EndMoveEffect
+
+.UsedText:
+ text_far Text_BattleUser ; "<USER>"
+ text_asm
+ ld a, BATTLE_VARS_MOVE_ANIM
+ call GetBattleVar
+ cp RAZOR_WIND
+ ld hl, .BattleMadeWhirlwindText
+ jr z, .done
+
+ cp SOLARBEAM
+ ld hl, .BattleTookSunlightText
+ jr z, .done
+
+ cp SKULL_BASH
+ ld hl, .BattleLoweredHeadText
+ jr z, .done
+
+ cp SKY_ATTACK
+ ld hl, .BattleGlowingText
+ jr z, .done
+
+ cp FLY
+ ld hl, .BattleFlewText
+ jr z, .done
+
+ cp DIG
+ ld hl, .BattleDugText
+
+.done
+ ret
+
+.BattleMadeWhirlwindText:
+ text_far _BattleMadeWhirlwindText
+ text_end
+
+.BattleTookSunlightText:
+ text_far _BattleTookSunlightText
+ text_end
+
+.BattleLoweredHeadText:
+ text_far _BattleLoweredHeadText
+ text_end
+
+.BattleGlowingText:
+ text_far _BattleGlowingText
+ text_end
+
+.BattleFlewText:
+ text_far _BattleFlewText
+ text_end
+
+.BattleDugText:
+ text_far _BattleDugText
+ text_end
+
+BattleCommand3c:
+; unused
+ ret
+
+BattleCommand_TrapTarget:
+; traptarget
+
+ ld a, [wAttackMissed]
+ and a
+ ret nz
+ ld hl, wEnemyWrapCount
+ ld de, wEnemyTrappingMove
+ ldh a, [hBattleTurn]
+ and a
+ jr z, .got_trap
+ ld hl, wPlayerWrapCount
+ ld de, wPlayerTrappingMove
+
+.got_trap
+ ld a, [hl]
+ and a
+ ret nz
+ ld a, BATTLE_VARS_SUBSTATUS4_OPP
+ call GetBattleVar
+ bit SUBSTATUS_SUBSTITUTE, a
+ ret nz
+ call BattleRandom
+ ; trapped for 2-5 turns
+ and %11
+ inc a
+ inc a
+ inc a
+ ld [hl], a
+ ld a, BATTLE_VARS_MOVE_ANIM
+ call GetBattleVar
+ ld [de], a
+ ld b, a
+ ld hl, .Traps
+
+.find_trap_text
+ ld a, [hli]
+ cp b
+ jr z, .found_trap_text
+ inc hl
+ inc hl
+ jr .find_trap_text
+
+.found_trap_text
+ ld a, [hli]
+ ld h, [hl]
+ ld l, a
+ jp StdBattleTextbox
+
+.Traps:
+ dbw BIND, UsedBindText ; 'used BIND on'
+ dbw WRAP, WrappedByText ; 'was WRAPPED by'
+ dbw FIRE_SPIN, WasTrappedText ; 'was trapped!'
+ dbw CLAMP, ClampedByText ; 'was CLAMPED by'
+ dbw WHIRLPOOL, WasTrappedText ; 'was trapped!'
+
+INCLUDE "engine/battle/move_effects/mist.asm"
+
+INCLUDE "engine/battle/move_effects/focus_energy.asm"
+
+BattleCommand_Recoil:
+; recoil
+
+ ld hl, wBattleMonMaxHP
+ ldh a, [hBattleTurn]
+ and a
+ jr z, .got_hp
+ ld hl, wEnemyMonMaxHP
+.got_hp
+ ld a, BATTLE_VARS_MOVE_ANIM
+ call GetBattleVar
+ ld d, a
+; get 1/4 damage or 1 HP, whichever is higher
+ ld a, [wCurDamage]
+ ld b, a
+ ld a, [wCurDamage + 1]
+ ld c, a
+ srl b
+ rr c
+ srl b
+ rr c
+ ld a, b
+ or c
+ jr nz, .min_damage
+ inc c
+.min_damage
+ ld a, [hli]
+ ld [wBuffer2], a
+ ld a, [hl]
+ ld [wBuffer1], a
+ dec hl
+ dec hl
+ ld a, [hl]
+ ld [wBuffer3], a
+ sub c
+ ld [hld], a
+ ld [wBuffer5], a
+ ld a, [hl]
+ ld [wBuffer4], a
+ sbc b
+ ld [hl], a
+ ld [wBuffer6], a
+ jr nc, .dont_ko
+ xor a
+ ld [hli], a
+ ld [hl], a
+ ld hl, wBuffer5
+ ld [hli], a
+ ld [hl], a
+.dont_ko
+ hlcoord 10, 9
+ ldh a, [hBattleTurn]
+ and a
+ ld a, 1
+ jr z, .animate_hp_bar
+ hlcoord 2, 2
+ xor a
+.animate_hp_bar
+ ld [wWhichHPBar], a
+ predef AnimateHPBar
+ call RefreshBattleHuds
+ ld hl, RecoilText
+ jp StdBattleTextbox
+
+BattleCommand_ConfuseTarget:
+; confusetarget
+
+ call GetOpponentItem
+ ld a, b
+ cp HELD_PREVENT_CONFUSE
+ ret z
+ ld a, [wEffectFailed]
+ and a
+ ret nz
+ call SafeCheckSafeguard
+ ret nz
+ call CheckSubstituteOpp
+ ret nz
+ ld a, BATTLE_VARS_SUBSTATUS3_OPP
+ call GetBattleVarAddr
+ bit SUBSTATUS_CONFUSED, [hl]
+ ret nz
+ jr BattleCommand_FinishConfusingTarget
+
+BattleCommand_Confuse:
+; confuse
+
+ call GetOpponentItem
+ ld a, b
+ cp HELD_PREVENT_CONFUSE
+ jr nz, .no_item_protection
+ ld a, [hl]
+ ld [wNamedObjectIndexBuffer], a
+ call GetItemName
+ call AnimateFailedMove
+ ld hl, ProtectedByText
+ jp StdBattleTextbox
+
+.no_item_protection
+ ld a, BATTLE_VARS_SUBSTATUS3_OPP
+ call GetBattleVarAddr
+ bit SUBSTATUS_CONFUSED, [hl]
+ jr z, .not_already_confused
+ call AnimateFailedMove
+ ld hl, AlreadyConfusedText
+ jp StdBattleTextbox
+
+.not_already_confused
+ call CheckSubstituteOpp
+ jr nz, BattleCommand_Confuse_CheckSnore_Swagger_ConfuseHit
+ ld a, [wAttackMissed]
+ and a
+ jr nz, BattleCommand_Confuse_CheckSnore_Swagger_ConfuseHit
+BattleCommand_FinishConfusingTarget:
+ ld bc, wEnemyConfuseCount
+ ldh a, [hBattleTurn]
+ and a
+ jr z, .got_confuse_count
+ ld bc, wPlayerConfuseCount
+
+.got_confuse_count
+ set SUBSTATUS_CONFUSED, [hl]
+ ; confused for 2-5 turns
+ call BattleRandom
+ and %11
+ inc a
+ inc a
+ ld [bc], a
+
+ ld a, BATTLE_VARS_MOVE_EFFECT
+ call GetBattleVar
+ cp EFFECT_CONFUSE_HIT
+ jr z, .got_effect
+ cp EFFECT_SNORE
+ jr z, .got_effect
+ cp EFFECT_SWAGGER
+ jr z, .got_effect
+ call AnimateCurrentMove
+
+.got_effect
+ ld de, ANIM_CONFUSED
+ call PlayOpponentBattleAnim
+
+ ld hl, BecameConfusedText
+ call StdBattleTextbox
+
+ call GetOpponentItem
+ ld a, b
+ cp HELD_HEAL_STATUS
+ jr z, .heal_confusion
+ cp HELD_HEAL_CONFUSION
+ ret nz
+.heal_confusion
+ ld hl, UseConfusionHealingItem
+ jp CallBattleCore
+
+BattleCommand_Confuse_CheckSnore_Swagger_ConfuseHit:
+ ld a, BATTLE_VARS_MOVE_EFFECT
+ call GetBattleVar
+ cp EFFECT_CONFUSE_HIT
+ ret z
+ cp EFFECT_SNORE
+ ret z
+ cp EFFECT_SWAGGER
+ ret z
+ jp PrintDidntAffect2
+
+BattleCommand_Paralyze:
+; paralyze
+
+ ld a, BATTLE_VARS_STATUS_OPP
+ call GetBattleVar
+ bit PAR, a
+ jr nz, .paralyzed
+ ld a, [wTypeModifier]
+ and $7f
+ jr z, .didnt_affect
+ call GetOpponentItem
+ ld a, b
+ cp HELD_PREVENT_PARALYZE
+ jr nz, .no_item_protection
+ ld a, [hl]
+ ld [wNamedObjectIndexBuffer], a
+ call GetItemName
+ call AnimateFailedMove
+ ld hl, ProtectedByText
+ jp StdBattleTextbox
+
+.no_item_protection
+ ldh a, [hBattleTurn]
+ and a
+ jr z, .dont_sample_failure
+
+ ld a, [wLinkMode]
+ and a
+ jr nz, .dont_sample_failure
+
+ ld a, [wPlayerSubStatus5]
+ bit SUBSTATUS_LOCK_ON, a
+ jr nz, .dont_sample_failure
+
+ call BattleRandom
+ cp 25 percent + 1 ; 25% chance AI fails
+ jr c, .failed
+
+.dont_sample_failure
+ ld a, BATTLE_VARS_STATUS_OPP
+ call GetBattleVarAddr
+ and a
+ jr nz, .failed
+ ld a, [wAttackMissed]
+ and a
+ jr nz, .failed
+ call CheckSubstituteOpp
+ jr nz, .failed
+ ld c, 30
+ call DelayFrames
+ call AnimateCurrentMove
+ ld a, $1
+ ldh [hBGMapMode], a
+ ld a, BATTLE_VARS_STATUS_OPP
+ call GetBattleVarAddr
+ set PAR, [hl]
+ call UpdateOpponentInParty
+ ld hl, ApplyPrzEffectOnSpeed
+ call CallBattleCore
+ call UpdateBattleHuds
+ call PrintParalyze
+ ld hl, UseHeldStatusHealingItem
+ jp CallBattleCore
+
+.paralyzed
+ call AnimateFailedMove
+ ld hl, AlreadyParalyzedText
+ jp StdBattleTextbox
+
+.failed
+ jp PrintDidntAffect2
+
+.didnt_affect
+ call AnimateFailedMove
+ jp PrintDoesntAffect
+
+CheckMoveTypeMatchesTarget:
+; Compare move type to opponent type.
+; Return z if matching the opponent type,
+; unless the move is Normal (Tri Attack).
+
+ push hl
+
+ ld hl, wEnemyMonType1
+ ldh a, [hBattleTurn]
+ and a
+ jr z, .ok
+ ld hl, wBattleMonType1
+.ok
+
+ ld a, BATTLE_VARS_MOVE_TYPE
+ call GetBattleVar
+ cp NORMAL
+ jr z, .normal
+
+ cp [hl]
+ jr z, .return
+
+ inc hl
+ cp [hl]
+
+.return
+ pop hl
+ ret
+
+.normal
+ ld a, 1
+ and a
+ pop hl
+ ret
+
+INCLUDE "engine/battle/move_effects/substitute.asm"
+
+BattleCommand_RechargeNextTurn:
+; rechargenextturn
+ ld a, BATTLE_VARS_SUBSTATUS4
+ call GetBattleVarAddr
+ set SUBSTATUS_RECHARGE, [hl]
+ ret
+
+EndRechargeOpp:
+ push hl
+ ld a, BATTLE_VARS_SUBSTATUS4_OPP
+ call GetBattleVarAddr
+ res SUBSTATUS_RECHARGE, [hl]
+ pop hl
+ ret
+
+INCLUDE "engine/battle/move_effects/rage.asm"
+
+BattleCommand_DoubleFlyingDamage:
+; doubleflyingdamage
+ ld a, BATTLE_VARS_SUBSTATUS3_OPP
+ call GetBattleVar
+ bit SUBSTATUS_FLYING, a
+ ret z
+ jr DoubleDamage
+
+BattleCommand_DoubleUndergroundDamage:
+; doubleundergrounddamage
+ ld a, BATTLE_VARS_SUBSTATUS3_OPP
+ call GetBattleVar
+ bit SUBSTATUS_UNDERGROUND, a
+ ret z
+
+ ; fallthrough
+
+DoubleDamage:
+ ld hl, wCurDamage + 1
+ sla [hl]
+ dec hl
+ rl [hl]
+ jr nc, .quit
+
+ ld a, $ff
+ ld [hli], a
+ ld [hl], a
+.quit
+ ret
+
+INCLUDE "engine/battle/move_effects/mimic.asm"
+
+INCLUDE "engine/battle/move_effects/leech_seed.asm"
+
+INCLUDE "engine/battle/move_effects/splash.asm"
+
+INCLUDE "engine/battle/move_effects/disable.asm"
+
+INCLUDE "engine/battle/move_effects/pay_day.asm"
+
+INCLUDE "engine/battle/move_effects/conversion.asm"
+
+BattleCommand_ResetStats:
+; resetstats
+
+ ld a, 7 ; neutral
+ ld hl, wPlayerStatLevels
+ call .Fill
+ ld hl, wEnemyStatLevels
+ call .Fill
+
+ ldh a, [hBattleTurn]
+ push af
+
+ call SetPlayerTurn
+ call CalcPlayerStats
+ call SetEnemyTurn
+ call CalcEnemyStats
+
+ pop af
+ ldh [hBattleTurn], a
+
+ call AnimateCurrentMove
+
+ ld hl, EliminatedStatsText
+ jp StdBattleTextbox
+
+.Fill:
+ ld b, wPlayerStatLevelsEnd - wPlayerStatLevels
+.next
+ ld [hli], a
+ dec b
+ jr nz, .next
+ ret
+
+BattleCommand_Heal:
+; heal
+
+ ld de, wBattleMonHP
+ ld hl, wBattleMonMaxHP
+ ldh a, [hBattleTurn]
+ and a
+ jr z, .got_hp
+ ld de, wEnemyMonHP
+ ld hl, wEnemyMonMaxHP
+.got_hp
+ ld a, BATTLE_VARS_MOVE_ANIM
+ call GetBattleVar
+ ld b, a
+ push hl
+ push de
+ push bc
+ ld c, 2
+ call CompareBytes
+ pop bc
+ pop de
+ pop hl
+ jp z, .hp_full
+ ld a, b
+ cp REST
+ jr nz, .not_rest
+
+ push hl
+ push de
+ push af
+ call BattleCommand_MoveDelay
+ ld a, BATTLE_VARS_SUBSTATUS5
+ call GetBattleVarAddr
+ res SUBSTATUS_TOXIC, [hl]
+ ld a, BATTLE_VARS_STATUS
+ call GetBattleVarAddr
+ ld a, [hl]
+ and a
+ ld [hl], REST_SLEEP_TURNS + 1
+ ld hl, WentToSleepText
+ jr z, .no_status_to_heal
+ ld hl, RestedText
+.no_status_to_heal
+ call StdBattleTextbox
+ ldh a, [hBattleTurn]
+ and a
+ jr nz, .calc_enemy_stats
+ call CalcPlayerStats
+ jr .got_stats
+
+.calc_enemy_stats
+ call CalcEnemyStats
+.got_stats
+ pop af
+ pop de
+ pop hl
+
+.not_rest
+ jr z, .restore_full_hp
+ ld hl, GetHalfMaxHP
+ call CallBattleCore
+ jr .finish
+
+.restore_full_hp
+ ld hl, GetMaxHP
+ call CallBattleCore
+.finish
+ call AnimateCurrentMove
+ call BattleCommand_SwitchTurn
+ ld hl, RestoreHP
+ call CallBattleCore
+ call BattleCommand_SwitchTurn
+ call UpdateUserInParty
+ call RefreshBattleHuds
+ ld hl, RegainedHealthText
+ jp StdBattleTextbox
+
+.hp_full
+ call AnimateFailedMove
+ ld hl, HPIsFullText
+ jp StdBattleTextbox
+
+INCLUDE "engine/battle/move_effects/transform.asm"
+
+BattleEffect_ButItFailed:
+ call AnimateFailedMove
+ jp PrintButItFailed
+
+ClearLastMove:
+ ld a, BATTLE_VARS_LAST_COUNTER_MOVE
+ call GetBattleVarAddr
+ xor a
+ ld [hl], a
+
+ ld a, BATTLE_VARS_LAST_MOVE
+ call GetBattleVarAddr
+ xor a
+ ld [hl], a
+ ret
+
+ResetActorDisable:
+ ldh a, [hBattleTurn]
+ and a
+ jr z, .player
+
+ xor a
+ ld [wEnemyDisableCount], a
+ ld [wEnemyDisabledMove], a
+ ret
+
+.player
+ xor a
+ ld [wPlayerDisableCount], a
+ ld [wDisabledMove], a
+ ret
+
+BattleCommand_Screen:
+; screen
+
+ ld hl, wPlayerScreens
+ ld bc, wPlayerLightScreenCount
+ ldh a, [hBattleTurn]
+ and a
+ jr z, .got_screens_pointer
+ ld hl, wEnemyScreens
+ ld bc, wEnemyLightScreenCount
+
+.got_screens_pointer
+ ld a, BATTLE_VARS_MOVE_EFFECT
+ call GetBattleVar
+ cp EFFECT_LIGHT_SCREEN
+ jr nz, .Reflect
+
+ bit SCREENS_LIGHT_SCREEN, [hl]
+ jr nz, .failed
+ set SCREENS_LIGHT_SCREEN, [hl]
+ ld a, 5
+ ld [bc], a
+ ld hl, LightScreenEffectText
+ jr .good
+
+.Reflect:
+ bit SCREENS_REFLECT, [hl]
+ jr nz, .failed
+ set SCREENS_REFLECT, [hl]
+
+ ; LightScreenCount -> ReflectCount
+ inc bc
+
+ ld a, 5
+ ld [bc], a
+ ld hl, ReflectEffectText
+
+.good
+ call AnimateCurrentMove
+ jp StdBattleTextbox
+
+.failed
+ call AnimateFailedMove
+ jp PrintButItFailed
+
+PrintDoesntAffect:
+; 'it doesn't affect'
+ ld hl, DoesntAffectText
+ jp StdBattleTextbox
+
+PrintNothingHappened:
+; 'but nothing happened!'
+ ld hl, NothingHappenedText
+ jp StdBattleTextbox
+
+TryPrintButItFailed:
+ ld a, [wAlreadyFailed]
+ and a
+ ret nz
+
+ ; fallthrough
+
+PrintButItFailed:
+; 'but it failed!'
+ ld hl, ButItFailedText
+ jp StdBattleTextbox
+
+FailMove:
+ call AnimateFailedMove
+ ; fallthrough
+
+FailMimic:
+ ld hl, ButItFailedText ; 'but it failed!'
+ ld de, ItFailedText ; 'it failed!'
+ jp FailText_CheckOpponentProtect
+
+PrintDidntAffect:
+; 'it didn't affect'
+ ld hl, DidntAffect1Text
+ jp StdBattleTextbox
+
+PrintDidntAffect2:
+ call AnimateFailedMove
+ ld hl, DidntAffect1Text ; 'it didn't affect'
+ ld de, DidntAffect2Text ; 'it didn't affect'
+ jp FailText_CheckOpponentProtect
+
+PrintParalyze:
+; 'paralyzed! maybe it can't attack!'
+ ld hl, ParalyzedText
+ jp StdBattleTextbox
+
+CheckSubstituteOpp:
+ ld a, BATTLE_VARS_SUBSTATUS4_OPP
+ call GetBattleVar
+ bit SUBSTATUS_SUBSTITUTE, a
+ ret
+
+INCLUDE "engine/battle/move_effects/selfdestruct.asm"
+
+INCLUDE "engine/battle/move_effects/mirror_move.asm"
+
+INCLUDE "engine/battle/move_effects/metronome.asm"
+
+CheckUserMove:
+; Return z if the user has move a.
+ ld b, a
+ ld de, wBattleMonMoves
+ ldh a, [hBattleTurn]
+ and a
+ jr z, .ok
+ ld de, wEnemyMonMoves
+.ok
+
+ ld c, NUM_MOVES
+.loop
+ ld a, [de]
+ inc de
+ cp b
+ ret z
+
+ dec c
+ jr nz, .loop
+
+ ld a, 1
+ and a
+ ret
+
+ResetTurn:
+ ld hl, wPlayerCharging
+ ldh a, [hBattleTurn]
+ and a
+ jr z, .player
+ ld hl, wEnemyCharging
+
+.player
+ ld [hl], 1
+ xor a
+ ld [wAlreadyDisobeyed], a
+ call DoMove
+ jp EndMoveEffect
+
+INCLUDE "engine/battle/move_effects/thief.asm"
+
+BattleCommand_ArenaTrap:
+; arenatrap
+
+; Doesn't work on an absent opponent.
+
+ call CheckHiddenOpponent
+ jr nz, .failed
+
+; Don't trap if the opponent is already trapped.
+
+ ld a, BATTLE_VARS_SUBSTATUS5
+ call GetBattleVarAddr
+ bit SUBSTATUS_CANT_RUN, [hl]
+ jr nz, .failed
+
+; Otherwise trap the opponent.
+
+ set SUBSTATUS_CANT_RUN, [hl]
+ call AnimateCurrentMove
+ ld hl, CantEscapeNowText
+ jp StdBattleTextbox
+
+.failed
+ call AnimateFailedMove
+ jp PrintButItFailed
+
+INCLUDE "engine/battle/move_effects/nightmare.asm"
+
+BattleCommand_Defrost:
+; defrost
+
+; Thaw the user.
+
+ ld a, BATTLE_VARS_STATUS
+ call GetBattleVarAddr
+ bit FRZ, [hl]
+ ret z
+ res FRZ, [hl]
+
+; Don't update the enemy's party struct in a wild battle.
+
+ ldh a, [hBattleTurn]
+ and a
+ jr z, .party
+
+ ld a, [wBattleMode]
+ dec a
+ jr z, .done
+
+.party
+ ld a, MON_STATUS
+ call UserPartyAttr
+ res FRZ, [hl]
+
+.done
+ call RefreshBattleHuds
+ ld hl, WasDefrostedText
+ jp StdBattleTextbox
+
+INCLUDE "engine/battle/move_effects/curse.asm"
+
+INCLUDE "engine/battle/move_effects/protect.asm"
+
+INCLUDE "engine/battle/move_effects/endure.asm"
+
+INCLUDE "engine/battle/move_effects/spikes.asm"
+
+INCLUDE "engine/battle/move_effects/foresight.asm"
+
+INCLUDE "engine/battle/move_effects/perish_song.asm"
+
+INCLUDE "engine/battle/move_effects/sandstorm.asm"
+
+INCLUDE "engine/battle/move_effects/rollout.asm"
+
+BattleCommand5d:
+; unused
+ ret
+
+INCLUDE "engine/battle/move_effects/fury_cutter.asm"
+
+INCLUDE "engine/battle/move_effects/attract.asm"
+
+INCLUDE "engine/battle/move_effects/return.asm"
+
+INCLUDE "engine/battle/move_effects/present.asm"
+
+INCLUDE "engine/battle/move_effects/frustration.asm"
+
+INCLUDE "engine/battle/move_effects/safeguard.asm"
+
+SafeCheckSafeguard:
+ push hl
+ ld hl, wEnemyScreens
+ ldh a, [hBattleTurn]
+ and a
+ jr z, .got_turn
+ ld hl, wPlayerScreens
+
+.got_turn
+ bit SCREENS_SAFEGUARD, [hl]
+ pop hl
+ ret
+
+BattleCommand_CheckSafeguard:
+; checksafeguard
+ ld hl, wEnemyScreens
+ ldh a, [hBattleTurn]
+ and a
+ jr z, .got_turn
+ ld hl, wPlayerScreens
+.got_turn
+ bit SCREENS_SAFEGUARD, [hl]
+ ret z
+ ld a, 1
+ ld [wAttackMissed], a
+ call BattleCommand_MoveDelay
+ ld hl, SafeguardProtectText
+ call StdBattleTextbox
+ jp EndMoveEffect
+
+INCLUDE "engine/battle/move_effects/magnitude.asm"
+
+INCLUDE "engine/battle/move_effects/baton_pass.asm"
+
+INCLUDE "engine/battle/move_effects/pursuit.asm"
+
+INCLUDE "engine/battle/move_effects/rapid_spin.asm"
+
+BattleCommand_HealMorn:
+; healmorn
+ ld b, MORN_F
+ jr BattleCommand_TimeBasedHealContinue
+
+BattleCommand_HealDay:
+; healday
+ ld b, DAY_F
+ jr BattleCommand_TimeBasedHealContinue
+
+BattleCommand_HealNite:
+; healnite
+ ld b, NITE_F
+ ; fallthrough
+
+BattleCommand_TimeBasedHealContinue:
+; Time- and weather-sensitive heal.
+
+ ld hl, wBattleMonMaxHP
+ ld de, wBattleMonHP
+ ldh a, [hBattleTurn]
+ and a
+ jr z, .start
+ ld hl, wEnemyMonMaxHP
+ ld de, wEnemyMonHP
+
+.start
+; Index for .Multipliers
+; Default restores half max HP.
+ ld c, 2
+
+; Don't bother healing if HP is already full.
+ push bc
+ call CompareBytes
+ pop bc
+ jr z, .Full
+
+; Don't factor in time of day in link battles.
+ ld a, [wLinkMode]
+ and a
+ jr nz, .Weather
+
+ ld a, [wTimeOfDay]
+ cp b
+ jr z, .Weather
+ dec c ; double
+
+.Weather:
+ ld a, [wBattleWeather]
+ and a
+ jr z, .Heal
+
+; x2 in sun
+; /2 in rain/sandstorm
+ inc c
+ cp WEATHER_SUN
+ jr z, .Heal
+ dec c
+ dec c
+
+.Heal:
+ ld b, 0
+ ld hl, .Multipliers
+ add hl, bc
+ add hl, bc
+
+ ld a, [hli]
+ ld h, [hl]
+ ld l, a
+ ld a, BANK(GetMaxHP)
+ rst FarCall
+
+ call AnimateCurrentMove
+ call BattleCommand_SwitchTurn
+
+ callfar RestoreHP
+
+ call BattleCommand_SwitchTurn
+ call UpdateUserInParty
+
+; 'regained health!'
+ ld hl, RegainedHealthText
+ jp StdBattleTextbox
+
+.Full:
+ call AnimateFailedMove
+
+; 'hp is full!'
+ ld hl, HPIsFullText
+ jp StdBattleTextbox
+
+.Multipliers:
+ dw GetEighthMaxHP
+ dw GetQuarterMaxHP
+ dw GetHalfMaxHP
+ dw GetMaxHP
+
+INCLUDE "engine/battle/move_effects/hidden_power.asm"
+
+INCLUDE "engine/battle/move_effects/rain_dance.asm"
+
+INCLUDE "engine/battle/move_effects/sunny_day.asm"
+
+INCLUDE "engine/battle/move_effects/belly_drum.asm"
+
+INCLUDE "engine/battle/move_effects/psych_up.asm"
+
+INCLUDE "engine/battle/move_effects/mirror_coat.asm"
+
+BattleCommand_DoubleMinimizeDamage:
+; doubleminimizedamage
+
+ ld hl, wEnemyMinimized
+ ldh a, [hBattleTurn]
+ and a
+ jr z, .ok
+ ld hl, wPlayerMinimized
+.ok
+ ld a, [hl]
+ and a
+ ret z
+ ld hl, wCurDamage + 1
+ sla [hl]
+ dec hl
+ rl [hl]
+ ret nc
+ ld a, $ff
+ ld [hli], a
+ ld [hl], a
+ ret
+
+BattleCommand_SkipSunCharge:
+; mimicsuncharge
+ ld a, [wBattleWeather]
+ cp WEATHER_SUN
+ ret nz
+ ld b, charge_command
+ jp SkipToBattleCommand
+
+INCLUDE "engine/battle/move_effects/future_sight.asm"
+
+INCLUDE "engine/battle/move_effects/thunder.asm"
+
+CheckHiddenOpponent:
+; BUG: This routine is completely redundant and introduces a bug, since BattleCommand_CheckHit does these checks properly.
+ ld a, BATTLE_VARS_SUBSTATUS3_OPP
+ call GetBattleVar
+ and 1 << SUBSTATUS_FLYING | 1 << SUBSTATUS_UNDERGROUND
+ ret
+
+GetUserItem:
+; Return the effect of the user's item in bc, and its id at hl.
+ ld hl, wBattleMonItem
+ ldh a, [hBattleTurn]
+ and a
+ jr z, .go
+ ld hl, wEnemyMonItem
+.go
+ ld b, [hl]
+ jp GetItemHeldEffect
+
+GetOpponentItem:
+; Return the effect of the opponent's item in bc, and its id at hl.
+ ld hl, wEnemyMonItem
+ ldh a, [hBattleTurn]
+ and a
+ jr z, .go
+ ld hl, wBattleMonItem
+.go
+ ld b, [hl]
+ jp GetItemHeldEffect
+
+GetItemHeldEffect:
+; Return the effect of item b in bc.
+ ld a, b
+ and a
+ ret z
+
+ push hl
+ ld hl, ItemAttributes + ITEMATTR_EFFECT
+ dec a
+ ld c, a
+ ld b, 0
+ ld a, ITEMATTR_STRUCT_LENGTH
+ call AddNTimes
+ ld a, BANK(ItemAttributes)
+ call GetFarHalfword
+ ld b, l
+ ld c, h
+ pop hl
+ ret
+
+AnimateCurrentMoveEitherSide:
+ push hl
+ push de
+ push bc
+ ld a, [wKickCounter]
+ push af
+ call BattleCommand_LowerSub
+ pop af
+ ld [wKickCounter], a
+ call PlayDamageAnim
+ call BattleCommand_RaiseSub
+ pop bc
+ pop de
+ pop hl
+ ret
+
+AnimateCurrentMove:
+ push hl
+ push de
+ push bc
+ ld a, [wKickCounter]
+ push af
+ call BattleCommand_LowerSub
+ pop af
+ ld [wKickCounter], a
+ call LoadMoveAnim
+ call BattleCommand_RaiseSub
+ pop bc
+ pop de
+ pop hl
+ ret
+
+PlayDamageAnim:
+ xor a
+ ld [wFXAnimID + 1], a
+
+ ld a, BATTLE_VARS_MOVE_ANIM
+ call GetBattleVar
+ and a
+ ret z
+
+ ld [wFXAnimID], a
+
+ ldh a, [hBattleTurn]
+ and a
+ ld a, BATTLEANIM_ENEMY_DAMAGE
+ jr z, .player
+ ld a, BATTLEANIM_PLAYER_DAMAGE
+
+.player
+ ld [wNumHits], a
+
+ jp PlayUserBattleAnim
+
+LoadMoveAnim:
+ xor a
+ ld [wNumHits], a
+ ld [wFXAnimID + 1], a
+
+ ld a, BATTLE_VARS_MOVE_ANIM
+ call GetBattleVar
+ and a
+ ret z
+
+ ; fallthrough
+
+LoadAnim:
+ ld [wFXAnimID], a
+
+ ; fallthrough
+
+PlayUserBattleAnim:
+ push hl
+ push de
+ push bc
+ callfar PlayBattleAnim
+ pop bc
+ pop de
+ pop hl
+ ret
+
+PlayOpponentBattleAnim:
+ ld a, e
+ ld [wFXAnimID], a
+ ld a, d
+ ld [wFXAnimID + 1], a
+ xor a
+ ld [wNumHits], a
+
+ push hl
+ push de
+ push bc
+ call BattleCommand_SwitchTurn
+
+ callfar PlayBattleAnim
+
+ call BattleCommand_SwitchTurn
+ pop bc
+ pop de
+ pop hl
+ ret
+
+CallBattleCore:
+ ld a, BANK("Battle Core")
+ rst FarCall
+ ret
+
+AnimateFailedMove:
+ call BattleCommand_LowerSub
+ call BattleCommand_MoveDelay
+ jp BattleCommand_RaiseSub
+
+BattleCommand_MoveDelay:
+; movedelay
+; Wait 40 frames.
+ ld c, 40
+ jp DelayFrames
+
+BattleCommand_ClearText:
+; cleartext
+
+; Used in multi-hit moves.
+ ld hl, .text
+ jp PrintText
+
+.text:
+ text_end
+
+SkipToBattleCommand:
+; Skip over commands until reaching command b.
+ ld a, [wBattleScriptBufferAddress + 1]
+ ld h, a
+ ld a, [wBattleScriptBufferAddress]
+ ld l, a
+.loop
+ ld a, [hli]
+ cp b
+ jr nz, .loop
+
+ ld a, h
+ ld [wBattleScriptBufferAddress + 1], a
+ ld a, l
+ ld [wBattleScriptBufferAddress], a
+ ret
+
+GetMoveAttr:
+; Assuming hl = Moves + x, return attribute x of move a.
+ push bc
+ ld bc, MOVE_LENGTH
+ call AddNTimes
+ call GetMoveByte
+ pop bc
+ ret
+
+GetMoveData:
+; Copy move struct a to de.
+ ld hl, Moves
+ ld bc, MOVE_LENGTH
+ call AddNTimes
+ ld a, BANK(Moves)
+ jp FarCopyBytes
+
+GetMoveByte:
+ ld a, BANK(Moves)
+ jp GetFarByte
+
+DisappearUser:
+ farcall _DisappearUser
+ ret
+
+AppearUserLowerSub:
+ farcall _AppearUserLowerSub
+ ret
+
+AppearUserRaiseSub:
+ farcall _AppearUserRaiseSub
+ ret
diff --git a/engine/battle/menu.asm b/engine/battle/menu.asm
new file mode 100644
index 00000000..f75d4114
--- /dev/null
+++ b/engine/battle/menu.asm
@@ -0,0 +1,94 @@
+LoadBattleMenu:
+ ld hl, BattleMenuHeader
+ call LoadMenuHeader
+ jr Function24e78
+
+SafariBattleMenu:
+ ; untranslated
+ ld hl, MenuHeader_0x24eae
+ call LoadMenuHeader
+ jr Function24e78
+
+ContestBattleMenu:
+ ld hl, MenuHeader_0x24ee9
+ call LoadMenuHeader
+; fallthrough
+Function24e78:
+ ld a, [wBattleMenuCursorBuffer]
+ ld [wMenuCursorBuffer], a
+ call _2DMenu
+ ld a, [wMenuCursorBuffer]
+ ld [wBattleMenuCursorBuffer], a
+ call ExitMenu
+ ret
+
+BattleMenuHeader:
+ db MENU_BACKUP_TILES ; flags
+ menu_coords 8, 12, SCREEN_WIDTH - 1, SCREEN_HEIGHT - 1
+ dw MenuData_0x24e93
+ db 1 ; default option
+
+MenuData_0x24e93:
+ db STATICMENU_CURSOR | STATICMENU_DISABLE_B ; flags
+ dn 2, 2 ; rows, columns
+ db 6 ; spacing
+ dba Strings24e9c
+ dbw BANK(MenuData_0x24e93), 0
+
+Strings24e9c:
+ db "FIGHT@"
+ db "<PK><MN>@"
+ db "PACK@"
+ db "RUN@"
+
+MenuHeader_0x24eae:
+ db MENU_BACKUP_TILES ; flags
+ menu_coords 0, 12, SCREEN_WIDTH - 1, SCREEN_HEIGHT - 1
+ dw MenuData_0x24eb6
+ db 1 ; default option
+
+MenuData_0x24eb6:
+ db STATICMENU_CURSOR | STATICMENU_DISABLE_B ; flags
+ dn 2, 2 ; rows, columns
+ db 11 ; spacing
+ dba Strings24ebf
+ dba Function24edc
+
+Strings24ebf:
+ db "サファりボール×  @" ; "SAFARI BALL× @"
+ db "エサをなげる@" ; "THROW BAIT"
+ db "いしをなげる@" ; "THROW ROCK"
+ db "にげる@" ; "RUN"
+
+Function24edc:
+ hlcoord 17, 13
+ ld de, wSafariBallsRemaining
+ lb bc, PRINTNUM_LEADINGZEROS | 1, 2
+ call PrintNum
+ ret
+
+MenuHeader_0x24ee9:
+ db MENU_BACKUP_TILES ; flags
+ menu_coords 2, 12, SCREEN_WIDTH - 1, SCREEN_HEIGHT - 1
+ dw MenuData_0x24ef1
+ db 1 ; default option
+
+MenuData_0x24ef1:
+ db STATICMENU_CURSOR | STATICMENU_DISABLE_B ; flags
+ dn 2, 2 ; rows, columns
+ db 12 ; spacing
+ dba Strings24efa
+ dba Strings24f13
+
+Strings24efa:
+ db "FIGHT@"
+ db "<PK><MN>@"
+ db "PARKBALL× @"
+ db "RUN@"
+
+Strings24f13:
+ hlcoord 13, 16
+ ld de, wParkBallsRemaining
+ lb bc, PRINTNUM_LEADINGZEROS | 1, 2
+ call PrintNum
+ ret
diff --git a/engine/battle/move_effects/attract.asm b/engine/battle/move_effects/attract.asm
new file mode 100644
index 00000000..5eb82d65
--- /dev/null
+++ b/engine/battle/move_effects/attract.asm
@@ -0,0 +1,76 @@
+BattleCommand_Attract:
+; attract
+ ld a, [wAttackMissed]
+ and a
+ jr nz, .failed
+ call CheckOppositeGender
+ jr c, .failed
+ call CheckHiddenOpponent
+ jr nz, .failed
+ ld a, BATTLE_VARS_SUBSTATUS1_OPP
+ call GetBattleVarAddr
+ bit SUBSTATUS_IN_LOVE, [hl]
+ jr nz, .failed
+
+ set SUBSTATUS_IN_LOVE, [hl]
+ call AnimateCurrentMove
+
+; 'fell in love!'
+ ld hl, FellInLoveText
+ jp StdBattleTextbox
+
+.failed
+ jp FailMove
+
+CheckOppositeGender:
+ ld a, MON_SPECIES
+ call BattlePartyAttr
+ ld a, [hl]
+ ld [wCurPartySpecies], a
+
+ ld a, [wCurBattleMon]
+ ld [wCurPartyMon], a
+ xor a
+ ld [wMonType], a
+
+ farcall GetGender
+ jr c, .genderless_samegender
+
+ ld b, 1
+ jr nz, .got_gender
+ dec b
+
+.got_gender
+ push bc
+ ld a, [wTempEnemyMonSpecies]
+ ld [wCurPartySpecies], a
+ ld hl, wEnemyMonDVs
+ ld a, [wEnemySubStatus5]
+ bit SUBSTATUS_TRANSFORMED, a
+ jr z, .not_transformed
+ ld hl, wEnemyBackupDVs
+.not_transformed
+ ld a, [hli]
+ ld [wTempMonDVs], a
+ ld a, [hl]
+ ld [wTempMonDVs + 1], a
+ ld a, 3
+ ld [wMonType], a
+ farcall GetGender
+ pop bc
+ jr c, .genderless_samegender
+
+ ld a, 1
+ jr nz, .got_enemy_gender
+ dec a
+
+.got_enemy_gender
+ xor b
+ jr z, .genderless_samegender
+
+ and a
+ ret
+
+.genderless_samegender
+ scf
+ ret
diff --git a/engine/battle/move_effects/baton_pass.asm b/engine/battle/move_effects/baton_pass.asm
new file mode 100644
index 00000000..bf9e3235
--- /dev/null
+++ b/engine/battle/move_effects/baton_pass.asm
@@ -0,0 +1,194 @@
+BattleCommand_BatonPass:
+; batonpass
+
+ ldh a, [hBattleTurn]
+ and a
+ jp nz, .Enemy
+
+; Need something to switch to
+ call CheckAnyOtherAlivePartyMons
+ jp z, FailedBatonPass
+
+ call UpdateBattleMonInParty
+ call AnimateCurrentMove
+
+ ld c, 50
+ call DelayFrames
+
+; Transition into switchmon menu
+ call LoadStandardMenuHeader
+ farcall SetUpBattlePartyMenu_NoLoop
+
+ farcall ForcePickSwitchMonInBattle
+
+; Return to battle scene
+ call ClearPalettes
+ farcall _LoadBattleFontsHPBar
+ call CloseWindow
+ call ClearSprites
+ hlcoord 1, 0
+ lb bc, 4, 10
+ call ClearBox
+ ld b, SCGB_BATTLE_COLORS
+ call GetSGBLayout
+ call SetPalettes
+ call BatonPass_LinkPlayerSwitch
+
+ ld hl, PassedBattleMonEntrance
+ call CallBattleCore
+
+ call ResetBatonPassStatus
+ ret
+
+.Enemy:
+; Wildmons don't have anything to switch to
+ ld a, [wBattleMode]
+ dec a ; WILDMON
+ jp z, FailedBatonPass
+
+ call CheckAnyOtherAliveEnemyMons
+ jp z, FailedBatonPass
+
+ call UpdateEnemyMonInParty
+ call AnimateCurrentMove
+ call BatonPass_LinkEnemySwitch
+
+; Passed enemy PartyMon entrance
+ xor a
+ ld [wEnemySwitchMonIndex], a
+ ld hl, EnemySwitch_SetMode
+ call CallBattleCore
+ ld hl, ResetBattleParticipants
+ call CallBattleCore
+ ld a, TRUE
+ ld [wApplyStatLevelMultipliersToEnemy], a
+ ld hl, ApplyStatLevelMultiplierOnAllStats
+ call CallBattleCore
+
+ ld hl, SpikesDamage
+ call CallBattleCore
+
+ jr ResetBatonPassStatus
+
+BatonPass_LinkPlayerSwitch:
+ ld a, [wLinkMode]
+ and a
+ ret z
+
+ ld a, BATTLEPLAYERACTION_USEITEM
+ ld [wBattlePlayerAction], a
+
+ call LoadStandardMenuHeader
+ ld hl, LinkBattleSendReceiveAction
+ call CallBattleCore
+ call CloseWindow
+
+ xor a ; BATTLEPLAYERACTION_USEMOVE
+ ld [wBattlePlayerAction], a
+ ret
+
+BatonPass_LinkEnemySwitch:
+ ld a, [wLinkMode]
+ and a
+ ret z
+
+ call LoadStandardMenuHeader
+ ld hl, LinkBattleSendReceiveAction
+ call CallBattleCore
+ jp CloseWindow
+
+FailedBatonPass:
+ call AnimateFailedMove
+ jp PrintButItFailed
+
+ResetBatonPassStatus:
+; Reset status changes that aren't passed by Baton Pass.
+
+ ; Nightmare isn't passed.
+ ld a, BATTLE_VARS_STATUS
+ call GetBattleVar
+ and SLP
+ jr nz, .ok
+
+ ld a, BATTLE_VARS_SUBSTATUS1
+ call GetBattleVarAddr
+ res SUBSTATUS_NIGHTMARE, [hl]
+.ok
+
+ ; Disable isn't passed.
+ call ResetActorDisable
+
+ ; Attraction isn't passed.
+ ld hl, wPlayerSubStatus1
+ res SUBSTATUS_IN_LOVE, [hl]
+ ld hl, wEnemySubStatus1
+ res SUBSTATUS_IN_LOVE, [hl]
+ ld hl, wPlayerSubStatus5
+
+ ld a, BATTLE_VARS_SUBSTATUS5
+ call GetBattleVarAddr
+ res SUBSTATUS_TRANSFORMED, [hl]
+ res SUBSTATUS_ENCORED, [hl]
+
+ ; New mon hasn't used a move yet.
+ ld a, BATTLE_VARS_LAST_MOVE
+ call GetBattleVarAddr
+ ld [hl], 0
+
+ xor a
+ ld [wPlayerWrapCount], a
+ ld [wEnemyWrapCount], a
+ ret
+
+CheckAnyOtherAlivePartyMons:
+ ld hl, wPartyMon1HP
+ ld a, [wPartyCount]
+ ld d, a
+ ld a, [wCurBattleMon]
+ ld e, a
+ jr CheckAnyOtherAliveMons
+
+CheckAnyOtherAliveEnemyMons:
+ ld hl, wOTPartyMon1HP
+ ld a, [wOTPartyCount]
+ ld d, a
+ ld a, [wCurOTMon]
+ ld e, a
+
+ ; fallthrough
+
+CheckAnyOtherAliveMons:
+; Check for nonzero HP starting from partymon
+; HP at hl for d partymons, besides current mon e.
+
+; Return nz if any are alive.
+
+ xor a
+ ld b, a
+ ld c, a
+.loop
+ ld a, c
+ cp d
+ jr z, .done
+ cp e
+ jr z, .next
+
+ ld a, [hli]
+ or b
+ ld b, a
+ ld a, [hld]
+ or b
+ ld b, a
+
+.next
+ push bc
+ ld bc, PARTYMON_STRUCT_LENGTH
+ add hl, bc
+ pop bc
+ inc c
+ jr .loop
+
+.done
+ ld a, b
+ and a
+ ret
diff --git a/engine/battle/move_effects/beat_up.asm b/engine/battle/move_effects/beat_up.asm
new file mode 100644
index 00000000..8546c37d
--- /dev/null
+++ b/engine/battle/move_effects/beat_up.asm
@@ -0,0 +1,220 @@
+BattleCommand_BeatUp:
+; beatup
+
+ call ResetDamage
+ ldh a, [hBattleTurn]
+ and a
+ jp nz, .enemy_beats_up
+
+ ld a, [wPlayerSubStatus3]
+ bit SUBSTATUS_IN_LOOP, a
+ jr nz, .next_mon
+
+ ld c, 20
+ call DelayFrames
+ xor a
+ ld [wPlayerRolloutCount], a
+ ld [wceed], a
+ ld [wBeatUpHitAtLeastOnce], a
+ jr .got_mon
+
+.next_mon
+ ld a, [wPlayerRolloutCount]
+ ld b, a
+ ld a, [wPartyCount]
+ sub b
+ ld [wceed], a
+
+.got_mon
+ ld a, [wceed]
+ ld hl, wPartyMonNicknames
+ call GetNick
+ ld a, MON_HP
+ call GetBeatupMonLocation
+ ld a, [hli]
+ or [hl]
+ jp z, .beatup_fail ; fainted
+ ld a, [wceed]
+ ld c, a
+ ld a, [wCurBattleMon]
+ ; BUG: this can desynchronize link battles
+ ; Change "cp [hl]" to "cp c" to fix
+ cp [hl]
+ ld hl, wBattleMonStatus
+ jr z, .active_mon
+ ld a, MON_STATUS
+ call GetBeatupMonLocation
+.active_mon
+ ld a, [hl]
+ and a
+ jp nz, .beatup_fail
+
+ ld a, $1
+ ld [wBeatUpHitAtLeastOnce], a
+ ld hl, BeatUpAttackText
+ call StdBattleTextbox
+
+ ld a, [wEnemyMonSpecies]
+ ld [wCurSpecies], a
+ call GetBaseData
+ ld a, [wBaseDefense]
+ ld c, a
+
+ push bc
+ ld a, MON_SPECIES
+ call GetBeatupMonLocation
+ ld a, [hl]
+ ld [wCurSpecies], a
+ call GetBaseData
+ ld a, [wBaseAttack]
+ pop bc
+ ld b, a
+
+ push bc
+ ld a, MON_LEVEL
+ call GetBeatupMonLocation
+ ld a, [hl]
+ ld e, a
+ pop bc
+
+ ld a, [wPlayerMoveStructPower]
+ ld d, a
+ ret
+
+.enemy_beats_up
+ ld a, [wEnemySubStatus3]
+ bit SUBSTATUS_IN_LOOP, a
+ jr nz, .enemy_next_mon
+
+ xor a
+ ld [wEnemyRolloutCount], a
+ ld [wceed], a
+ ld [wBeatUpHitAtLeastOnce], a
+ jr .enemy_got_mon
+
+.enemy_next_mon
+ ld a, [wEnemyRolloutCount]
+ ld b, a
+ ld a, [wOTPartyCount]
+ sub b
+ ld [wceed], a
+
+.enemy_got_mon
+ ld a, [wBattleMode]
+ dec a
+ jr z, .wild
+
+ ld a, [wLinkMode]
+ and a
+ jr nz, .linked
+
+ ld a, [wceed]
+ ld c, a
+ ld b, 0
+ ld hl, wOTPartySpecies
+ add hl, bc
+ ld a, [hl]
+ ld [wNamedObjectIndexBuffer], a
+ call GetPokemonName
+ jr .got_enemy_nick
+
+.linked
+ ld a, [wceed]
+ ld hl, wOTPartyMonNicknames
+ ld bc, NAME_LENGTH
+ call AddNTimes
+ ld de, wStringBuffer1
+ call CopyBytes
+
+.got_enemy_nick
+ ld a, MON_HP
+ call GetBeatupMonLocation
+ ld a, [hli]
+ or [hl]
+ jp z, .beatup_fail
+
+ ld a, [wceed]
+ ld b, a
+ ld a, [wCurOTMon]
+ cp b
+ ld hl, wEnemyMonStatus
+ jr z, .active_enemy
+ ld a, MON_STATUS
+ call GetBeatupMonLocation
+.active_enemy
+ ld a, [hl]
+ and a
+ jr nz, .beatup_fail
+
+ ld a, $1
+ ld [wBeatUpHitAtLeastOnce], a
+ jr .finish_beatup
+
+.wild
+ ld a, [wEnemyMonSpecies]
+ ld [wNamedObjectIndexBuffer], a
+ call GetPokemonName
+ ld hl, BeatUpAttackText
+ call StdBattleTextbox
+ jp EnemyAttackDamage
+
+.finish_beatup
+ ld hl, BeatUpAttackText
+ call StdBattleTextbox
+
+ ld a, [wBattleMonSpecies]
+ ld [wCurSpecies], a
+ call GetBaseData
+ ld a, [wBaseDefense]
+ ld c, a
+
+ push bc
+ ld a, MON_SPECIES
+ call GetBeatupMonLocation
+ ld a, [hl]
+ ld [wCurSpecies], a
+ call GetBaseData
+ ld a, [wBaseAttack]
+ pop bc
+ ld b, a
+
+ push bc
+ ld a, MON_LEVEL
+ call GetBeatupMonLocation
+ ld a, [hl]
+ ld e, a
+ pop bc
+
+ ld a, [wEnemyMoveStructPower]
+ ld d, a
+ ret
+
+.beatup_fail
+ ld b, buildopponentrage_command
+ jp SkipToBattleCommand
+
+BattleCommand_BeatUpFailText:
+; beatupfailtext
+
+ ld a, [wBeatUpHitAtLeastOnce]
+ and a
+ ret nz
+
+ jp PrintButItFailed
+
+GetBeatupMonLocation:
+ push bc
+ ld c, a
+ ld b, 0
+ ldh a, [hBattleTurn]
+ and a
+ ld hl, wPartyMon1Species
+ jr z, .got_species
+ ld hl, wOTPartyMon1Species
+
+.got_species
+ ld a, [wceed]
+ add hl, bc
+ call GetPartyLocation
+ pop bc
+ ret
diff --git a/engine/battle/move_effects/belly_drum.asm b/engine/battle/move_effects/belly_drum.asm
new file mode 100644
index 00000000..5b1361f2
--- /dev/null
+++ b/engine/battle/move_effects/belly_drum.asm
@@ -0,0 +1,30 @@
+BattleCommand_BellyDrum:
+; bellydrum
+; This command is buggy because it raises the user's attack
+; before checking that it has enough HP to use the move.
+; Swap the order of these two blocks to fix.
+ call BattleCommand_AttackUp2
+ ld a, [wAttackMissed]
+ and a
+ jr nz, .failed
+
+ callfar GetHalfMaxHP
+ callfar CheckUserHasEnoughHP
+ jr nc, .failed
+
+ push bc
+ call AnimateCurrentMove
+ pop bc
+ callfar SubtractHPFromUser
+ call UpdateUserInParty
+
+rept 5
+ call BattleCommand_AttackUp2
+endr
+
+ ld hl, BellyDrumText
+ jp StdBattleTextbox
+
+.failed
+ call AnimateFailedMove
+ jp PrintButItFailed
diff --git a/engine/battle/move_effects/bide.asm b/engine/battle/move_effects/bide.asm
new file mode 100644
index 00000000..74f7c9cf
--- /dev/null
+++ b/engine/battle/move_effects/bide.asm
@@ -0,0 +1,100 @@
+BattleCommand_StoreEnergy:
+; storeenergy
+
+ ld a, BATTLE_VARS_SUBSTATUS3
+ call GetBattleVar
+ bit SUBSTATUS_BIDE, a
+ ret z
+
+ ld hl, wPlayerRolloutCount
+ ldh a, [hBattleTurn]
+ and a
+ jr z, .check_still_storing_energy
+ ld hl, wEnemyRolloutCount
+.check_still_storing_energy
+ dec [hl]
+ jr nz, .still_storing
+
+ ld a, BATTLE_VARS_SUBSTATUS3
+ call GetBattleVarAddr
+ res SUBSTATUS_BIDE, [hl]
+
+ ld hl, UnleashedEnergyText
+ call StdBattleTextbox
+
+ ld a, BATTLE_VARS_MOVE_POWER
+ call GetBattleVarAddr
+ ld a, 1
+ ld [hl], a
+ ld hl, wPlayerDamageTaken + 1
+ ld de, wPlayerCharging ; player
+ ldh a, [hBattleTurn]
+ and a
+ jr z, .player
+ ld hl, wEnemyDamageTaken + 1
+ ld de, wEnemyCharging ; enemy
+.player
+ ld a, [hld]
+ add a
+ ld b, a
+ ld [wCurDamage + 1], a
+ ld a, [hl]
+ rl a
+ ld [wCurDamage], a
+ jr nc, .not_maxed
+ ld a, $ff
+ ld [wCurDamage], a
+ ld [wCurDamage + 1], a
+.not_maxed
+ or b
+ jr nz, .built_up_something
+ ld a, 1
+ ld [wAttackMissed], a
+.built_up_something
+ xor a
+ ld [hli], a
+ ld [hl], a
+ ld [de], a
+
+ ld a, BATTLE_VARS_MOVE_ANIM
+ call GetBattleVarAddr
+ ld a, BIDE
+ ld [hl], a
+
+ ld b, unleashenergy_command
+ jp SkipToBattleCommand
+
+.still_storing
+ ld hl, StoringEnergyText
+ call StdBattleTextbox
+ jp EndMoveEffect
+
+BattleCommand_UnleashEnergy:
+; unleashenergy
+
+ ld de, wPlayerDamageTaken
+ ld bc, wPlayerRolloutCount
+ ldh a, [hBattleTurn]
+ and a
+ jr z, .got_damage
+ ld de, wEnemyDamageTaken
+ ld bc, wEnemyRolloutCount
+.got_damage
+ ld a, BATTLE_VARS_SUBSTATUS3
+ call GetBattleVarAddr
+ set SUBSTATUS_BIDE, [hl]
+ xor a
+ ld [de], a
+ inc de
+ ld [de], a
+ ld [wPlayerMoveStructEffect], a
+ ld [wEnemyMoveStructEffect], a
+ call BattleRandom
+ and 1
+ inc a
+ inc a
+ ld [bc], a
+ ld a, 1
+ ld [wKickCounter], a
+ call AnimateCurrentMove
+ jp EndMoveEffect
diff --git a/engine/battle/move_effects/conversion.asm b/engine/battle/move_effects/conversion.asm
new file mode 100644
index 00000000..b6081a6b
--- /dev/null
+++ b/engine/battle/move_effects/conversion.asm
@@ -0,0 +1,96 @@
+BattleCommand_Conversion:
+; conversion
+
+ ld hl, wBattleMonMoves
+ ld de, wBattleMonType1
+ ldh a, [hBattleTurn]
+ and a
+ jr z, .got_moves
+ ld hl, wEnemyMonMoves
+ ld de, wEnemyMonType1
+.got_moves
+ push de
+ ld c, 0
+ ld de, wStringBuffer1
+.loop
+ push hl
+ ld b, 0
+ add hl, bc
+ ld a, [hl]
+ pop hl
+ and a
+ jr z, .okay
+ push hl
+ push bc
+ dec a
+ ld hl, Moves + MOVE_TYPE
+ call GetMoveAttr
+ ld [de], a
+ inc de
+ pop bc
+ pop hl
+ inc c
+ ld a, c
+ cp NUM_MOVES
+ jr c, .loop
+.okay
+ ld a, $ff
+ ld [de], a
+ inc de
+ ld [de], a
+ inc de
+ ld [de], a
+ pop de
+ ld hl, wStringBuffer1
+.loop2
+ ld a, [hl]
+ cp -1
+ jr z, .fail
+ cp CURSE_TYPE
+ jr z, .next
+ ld a, [de]
+ cp [hl]
+ jr z, .next
+ inc de
+ ld a, [de]
+ dec de
+ cp [hl]
+ jr nz, .done
+.next
+ inc hl
+ jr .loop2
+
+.fail
+ call AnimateFailedMove
+ jp PrintButItFailed
+
+.done
+.loop3
+ call BattleRandom
+ maskbits NUM_MOVES
+ ld c, a
+ ld b, 0
+ ld hl, wStringBuffer1
+ add hl, bc
+ ld a, [hl]
+ cp -1
+ jr z, .loop3
+ cp CURSE_TYPE
+ jr z, .loop3
+ ld a, [de]
+ cp [hl]
+ jr z, .loop3
+ inc de
+ ld a, [de]
+ dec de
+ cp [hl]
+ jr z, .loop3
+ ld a, [hl]
+ ld [de], a
+ inc de
+ ld [de], a
+ ld [wNamedObjectIndexBuffer], a
+ farcall GetTypeName
+ call AnimateCurrentMove
+ ld hl, TransformedTypeText
+ jp StdBattleTextbox
diff --git a/engine/battle/move_effects/conversion2.asm b/engine/battle/move_effects/conversion2.asm
new file mode 100644
index 00000000..bc866727
--- /dev/null
+++ b/engine/battle/move_effects/conversion2.asm
@@ -0,0 +1,64 @@
+BattleCommand_Conversion2:
+; conversion2
+
+ ld a, [wAttackMissed]
+ and a
+ jr nz, .failed
+ ld hl, wBattleMonType1
+ ldh a, [hBattleTurn]
+ and a
+ jr z, .got_type
+ ld hl, wEnemyMonType1
+.got_type
+ ld a, BATTLE_VARS_LAST_COUNTER_MOVE_OPP
+ call GetBattleVar
+ and a
+ jr z, .failed
+ push hl
+ dec a
+ ld hl, Moves + MOVE_TYPE
+ call GetMoveAttr
+ ld d, a
+ pop hl
+ cp CURSE_TYPE
+ jr z, .failed
+ call AnimateCurrentMove
+ call BattleCommand_SwitchTurn
+
+.loop
+ call BattleRandom
+ maskbits NUM_TYPES
+ cp UNUSED_TYPES
+ jr c, .okay
+ cp UNUSED_TYPES_END
+ jr c, .loop
+ cp TYPES_END
+ jr nc, .loop
+.okay
+ ld [hli], a
+ ld [hld], a
+ push hl
+ ld a, BATTLE_VARS_MOVE_TYPE
+ call GetBattleVarAddr
+ push af
+ push hl
+ ld a, d
+ ld [hl], a
+ call BattleCheckTypeMatchup
+ pop hl
+ pop af
+ ld [hl], a
+ pop hl
+ ld a, [wTypeMatchup]
+ cp EFFECTIVE
+ jr nc, .loop
+ call BattleCommand_SwitchTurn
+
+ ld a, [hl]
+ ld [wNamedObjectIndexBuffer], a
+ predef GetTypeName
+ ld hl, TransformedTypeText
+ jp StdBattleTextbox
+
+.failed
+ jp FailMove
diff --git a/engine/battle/move_effects/counter.asm b/engine/battle/move_effects/counter.asm
new file mode 100644
index 00000000..031c399a
--- /dev/null
+++ b/engine/battle/move_effects/counter.asm
@@ -0,0 +1,59 @@
+BattleCommand_Counter:
+; counter
+
+ ld a, 1
+ ld [wAttackMissed], a
+ ld a, BATTLE_VARS_LAST_COUNTER_MOVE_OPP
+ call GetBattleVar
+ and a
+ ret z
+
+ ld b, a
+ callfar GetMoveEffect
+ ld a, b
+ cp EFFECT_COUNTER
+ ret z
+
+ call BattleCommand_ResetTypeMatchup
+ ld a, [wTypeMatchup]
+ and a
+ ret z
+
+ call CheckOpponentWentFirst
+ ret z
+
+ ld a, BATTLE_VARS_LAST_COUNTER_MOVE_OPP
+ call GetBattleVar
+ dec a
+ ld de, wStringBuffer1
+ call GetMoveData
+
+ ld a, [wStringBuffer1 + MOVE_POWER]
+ and a
+ ret z
+
+ ld a, [wStringBuffer1 + MOVE_TYPE]
+ cp SPECIAL
+ ret nc
+
+ ; BUG: Move should fail with all non-damaging battle actions
+ ld hl, wCurDamage
+ ld a, [hli]
+ or [hl]
+ ret z
+
+ ld a, [hl]
+ add a
+ ld [hld], a
+ ld a, [hl]
+ adc a
+ ld [hl], a
+ jr nc, .capped
+ ld a, $ff
+ ld [hli], a
+ ld [hl], a
+.capped
+
+ xor a
+ ld [wAttackMissed], a
+ ret
diff --git a/engine/battle/move_effects/curse.asm b/engine/battle/move_effects/curse.asm
new file mode 100644
index 00000000..3507c668
--- /dev/null
+++ b/engine/battle/move_effects/curse.asm
@@ -0,0 +1,93 @@
+BattleCommand_Curse:
+; curse
+
+ ld de, wBattleMonType1
+ ld bc, wPlayerStatLevels
+ ldh a, [hBattleTurn]
+ and a
+ jr z, .go
+ ld de, wEnemyMonType1
+ ld bc, wEnemyStatLevels
+
+.go
+
+; Curse is different for Ghost-types.
+
+ ld a, [de]
+ cp GHOST
+ jr z, .ghost
+ inc de
+ ld a, [de]
+ cp GHOST
+ jr z, .ghost
+
+; If no stats can be increased, don't.
+
+; Attack
+ ld a, [bc]
+ cp MAX_STAT_LEVEL
+ jr c, .raise
+
+; Defense
+ inc bc
+ ld a, [bc]
+ cp MAX_STAT_LEVEL
+ jr nc, .cantraise
+
+.raise
+
+; Raise Attack and Defense, and lower Speed.
+
+ ld a, $1
+ ld [wKickCounter], a
+ call AnimateCurrentMove
+ ld a, SPEED
+ call LowerStat
+ call BattleCommand_SwitchTurn
+ call BattleCommand_StatDownMessage
+ call ResetMiss
+ call BattleCommand_SwitchTurn
+ call BattleCommand_AttackUp
+ call BattleCommand_StatUpMessage
+ call ResetMiss
+ call BattleCommand_DefenseUp
+ jp BattleCommand_StatUpMessage
+
+.ghost
+
+; Cut HP in half and put a curse on the opponent.
+
+ call CheckHiddenOpponent
+ jr nz, .failed
+
+ call CheckSubstituteOpp
+ jr nz, .failed
+
+ ld a, BATTLE_VARS_SUBSTATUS1_OPP
+ call GetBattleVarAddr
+ bit SUBSTATUS_CURSE, [hl]
+ jr nz, .failed
+
+ set SUBSTATUS_CURSE, [hl]
+ call AnimateCurrentMove
+ ld hl, GetHalfMaxHP
+ call CallBattleCore
+ ld hl, SubtractHPFromUser
+ call CallBattleCore
+ call UpdateUserInParty
+ ld hl, PutACurseText
+ jp StdBattleTextbox
+
+.failed
+ call AnimateFailedMove
+ jp PrintButItFailed
+
+.cantraise
+
+; Can't raise either stat.
+
+ ld b, ABILITY + 1
+ call GetStatName
+ call AnimateFailedMove
+ ld hl, WontRiseAnymoreText
+ jp StdBattleTextbox
diff --git a/engine/battle/move_effects/destiny_bond.asm b/engine/battle/move_effects/destiny_bond.asm
new file mode 100644
index 00000000..6a03b9a7
--- /dev/null
+++ b/engine/battle/move_effects/destiny_bond.asm
@@ -0,0 +1,9 @@
+BattleCommand_DestinyBond:
+; destinybond
+
+ ld a, BATTLE_VARS_SUBSTATUS5
+ call GetBattleVarAddr
+ set SUBSTATUS_DESTINY_BOND, [hl]
+ call AnimateCurrentMove
+ ld hl, DestinyBondEffectText
+ jp StdBattleTextbox
diff --git a/engine/battle/move_effects/disable.asm b/engine/battle/move_effects/disable.asm
new file mode 100644
index 00000000..de6dbc60
--- /dev/null
+++ b/engine/battle/move_effects/disable.asm
@@ -0,0 +1,72 @@
+BattleCommand_Disable:
+; disable
+
+ ld a, [wAttackMissed]
+ and a
+ jr nz, .failed
+
+ ld de, wEnemyDisableCount
+ ld hl, wEnemyMonMoves
+ ldh a, [hBattleTurn]
+ and a
+ jr z, .got_moves
+ ld de, wPlayerDisableCount
+ ld hl, wBattleMonMoves
+.got_moves
+
+ ld a, [de]
+ and a
+ jr nz, .failed
+
+ ld a, BATTLE_VARS_LAST_COUNTER_MOVE_OPP
+ call GetBattleVar
+ and a
+ jr z, .failed
+ cp STRUGGLE
+ jr z, .failed
+
+ ld b, a
+ ld c, $ff
+.loop
+ inc c
+ ld a, [hli]
+ cp b
+ jr nz, .loop
+
+ ldh a, [hBattleTurn]
+ and a
+ ld hl, wEnemyMonPP
+ jr z, .got_pp
+ ld hl, wBattleMonPP
+.got_pp
+ ld b, 0
+ add hl, bc
+ ld a, [hl]
+ and a
+ jr z, .failed
+.loop2
+ call BattleRandom
+ and 7
+ jr z, .loop2
+ inc a
+ inc c
+ swap c
+ add c
+ ld [de], a
+ call AnimateCurrentMove
+ ld hl, wDisabledMove
+ ldh a, [hBattleTurn]
+ and a
+ jr nz, .got_disabled_move_pointer
+ inc hl
+.got_disabled_move_pointer
+ ld a, BATTLE_VARS_LAST_COUNTER_MOVE_OPP
+ call GetBattleVar
+ ld [hl], a
+ ld [wNamedObjectIndexBuffer], a
+ call GetMoveName
+ ld hl, WasDisabledText
+ jp StdBattleTextbox
+
+.failed
+ jp FailMove
diff --git a/engine/battle/move_effects/encore.asm b/engine/battle/move_effects/encore.asm
new file mode 100644
index 00000000..8ca3595f
--- /dev/null
+++ b/engine/battle/move_effects/encore.asm
@@ -0,0 +1,120 @@
+BattleCommand_Encore:
+; encore
+
+ ld hl, wEnemyMonMoves
+ ld de, wEnemyEncoreCount
+ ldh a, [hBattleTurn]
+ and a
+ jr z, .ok
+ ld hl, wBattleMonMoves
+ ld de, wPlayerEncoreCount
+.ok
+ ld a, BATTLE_VARS_LAST_MOVE_OPP
+ call GetBattleVar
+ and a
+ jp z, .failed
+ cp STRUGGLE
+ jp z, .failed
+ cp ENCORE
+ jp z, .failed
+ cp MIRROR_MOVE
+ jp z, .failed
+ ld b, a
+
+.got_move
+ ld a, [hli]
+ cp b
+ jr nz, .got_move
+
+ ld bc, wBattleMonPP - wBattleMonMoves - 1
+ add hl, bc
+ ld a, [hl]
+ and PP_MASK
+ jp z, .failed
+ ld a, [wAttackMissed]
+ and a
+ jp nz, .failed
+ ld a, BATTLE_VARS_SUBSTATUS5_OPP
+ call GetBattleVarAddr
+ bit SUBSTATUS_ENCORED, [hl]
+ jp nz, .failed
+ set SUBSTATUS_ENCORED, [hl]
+ call BattleRandom
+ and $3
+ inc a
+ inc a
+ inc a
+ ld [de], a
+ call CheckOpponentWentFirst
+ jr nz, .finish_move
+ ldh a, [hBattleTurn]
+ and a
+ jr z, .force_last_enemy_move
+
+ push hl
+ ld a, [wLastPlayerMove]
+ ld b, a
+ ld c, 0
+ ld hl, wBattleMonMoves
+.find_player_move
+ ld a, [hli]
+ cp b
+ jr z, .got_player_move
+ inc c
+ ld a, c
+ cp NUM_MOVES
+ jr c, .find_player_move
+ pop hl
+ res SUBSTATUS_ENCORED, [hl]
+ xor a
+ ld [de], a
+ jr .failed
+
+.got_player_move
+ pop hl
+ ld a, c
+ ld [wCurMoveNum], a
+ ld a, b
+ ld [wCurPlayerMove], a
+ dec a
+ ld de, wPlayerMoveStruct
+ call GetMoveData
+ jr .finish_move
+
+.force_last_enemy_move
+ push hl
+ ld a, [wLastEnemyMove]
+ ld b, a
+ ld c, 0
+ ld hl, wEnemyMonMoves
+.find_enemy_move
+ ld a, [hli]
+ cp b
+ jr z, .got_enemy_move
+ inc c
+ ld a, c
+ cp NUM_MOVES
+ jr c, .find_enemy_move
+ pop hl
+ res SUBSTATUS_ENCORED, [hl]
+ xor a
+ ld [de], a
+ jr .failed
+
+.got_enemy_move
+ pop hl
+ ld a, c
+ ld [wCurEnemyMoveNum], a
+ ld a, b
+ ld [wCurEnemyMove], a
+ dec a
+ ld de, wEnemyMoveStruct
+ call GetMoveData
+
+.finish_move
+ call AnimateCurrentMove
+ ld hl, GotAnEncoreText
+ jp StdBattleTextbox
+
+.failed
+ jp PrintDidntAffect2
diff --git a/engine/battle/move_effects/endure.asm b/engine/battle/move_effects/endure.asm
new file mode 100644
index 00000000..00ccb130
--- /dev/null
+++ b/engine/battle/move_effects/endure.asm
@@ -0,0 +1,16 @@
+BattleCommand_Endure:
+; endure
+
+; Endure shares code with Protect. See protect.asm.
+
+ call ProtectChance
+ ret c
+
+ ld a, BATTLE_VARS_SUBSTATUS1
+ call GetBattleVarAddr
+ set SUBSTATUS_ENDURE, [hl]
+
+ call AnimateCurrentMove
+
+ ld hl, BracedItselfText
+ jp StdBattleTextbox
diff --git a/engine/battle/move_effects/false_swipe.asm b/engine/battle/move_effects/false_swipe.asm
new file mode 100644
index 00000000..e2e0c6f1
--- /dev/null
+++ b/engine/battle/move_effects/false_swipe.asm
@@ -0,0 +1,48 @@
+BattleCommand_FalseSwipe:
+; falseswipe
+
+; Makes sure wCurDamage < MonHP
+
+ ld hl, wEnemyMonHP
+ ldh a, [hBattleTurn]
+ and a
+ jr z, .got_hp
+ ld hl, wBattleMonHP
+.got_hp
+ ld de, wCurDamage
+ ld c, 2
+ push hl
+ push de
+ call CompareBytes
+ pop de
+ pop hl
+ jr c, .done
+
+ ld a, [hli]
+ ld [de], a
+ inc de
+ ld a, [hl]
+ dec a
+ ld [de], a
+
+ inc a
+ jr nz, .okay
+ dec de
+ ld a, [de]
+ dec a
+ ld [de], a
+.okay
+
+ ld a, [wCriticalHit]
+ cp 2
+ jr nz, .carry
+ xor a
+ ld [wCriticalHit], a
+
+.carry
+ scf
+ ret
+
+.done
+ and a
+ ret
diff --git a/engine/battle/move_effects/focus_energy.asm b/engine/battle/move_effects/focus_energy.asm
new file mode 100644
index 00000000..c4eb1f33
--- /dev/null
+++ b/engine/battle/move_effects/focus_energy.asm
@@ -0,0 +1,15 @@
+BattleCommand_FocusEnergy:
+; focusenergy
+
+ ld a, BATTLE_VARS_SUBSTATUS4
+ call GetBattleVarAddr
+ bit SUBSTATUS_FOCUS_ENERGY, [hl]
+ jr nz, .already_pumped
+ set SUBSTATUS_FOCUS_ENERGY, [hl]
+ call AnimateCurrentMove
+ ld hl, GettingPumpedText
+ jp StdBattleTextbox
+
+.already_pumped
+ call AnimateFailedMove
+ jp PrintButItFailed
diff --git a/engine/battle/move_effects/foresight.asm b/engine/battle/move_effects/foresight.asm
new file mode 100644
index 00000000..ff25b04e
--- /dev/null
+++ b/engine/battle/move_effects/foresight.asm
@@ -0,0 +1,22 @@
+BattleCommand_Foresight:
+; foresight
+
+ ld a, [wAttackMissed]
+ and a
+ jr nz, .failed
+
+ call CheckHiddenOpponent
+ jr nz, .failed
+
+ ld a, BATTLE_VARS_SUBSTATUS1_OPP
+ call GetBattleVarAddr
+ bit SUBSTATUS_IDENTIFIED, [hl]
+ jr nz, .failed
+
+ set SUBSTATUS_IDENTIFIED, [hl]
+ call AnimateCurrentMove
+ ld hl, IdentifiedText
+ jp StdBattleTextbox
+
+.failed
+ jp FailMove
diff --git a/engine/battle/move_effects/frustration.asm b/engine/battle/move_effects/frustration.asm
new file mode 100644
index 00000000..b07942c7
--- /dev/null
+++ b/engine/battle/move_effects/frustration.asm
@@ -0,0 +1,27 @@
+BattleCommand_FrustrationPower:
+; frustrationpower
+
+ push bc
+ ld hl, wBattleMonHappiness
+ ldh a, [hBattleTurn]
+ and a
+ jr z, .got_happiness
+ ld hl, wEnemyMonHappiness
+.got_happiness
+ ld a, $ff
+ sub [hl]
+ ldh [hMultiplicand + 2], a
+ xor a
+ ldh [hMultiplicand + 0], a
+ ldh [hMultiplicand + 1], a
+ ld a, 10
+ ldh [hMultiplier], a
+ call Multiply
+ ld a, 25
+ ldh [hDivisor], a
+ ld b, 4
+ call Divide
+ ldh a, [hQuotient + 3]
+ ld d, a
+ pop bc
+ ret
diff --git a/engine/battle/move_effects/fury_cutter.asm b/engine/battle/move_effects/fury_cutter.asm
new file mode 100644
index 00000000..a1284849
--- /dev/null
+++ b/engine/battle/move_effects/fury_cutter.asm
@@ -0,0 +1,55 @@
+BattleCommand_FuryCutter:
+; furycutter
+
+ ld hl, wPlayerFuryCutterCount
+ ldh a, [hBattleTurn]
+ and a
+ jr z, .go
+ ld hl, wEnemyFuryCutterCount
+
+.go
+ ld a, [wAttackMissed]
+ and a
+ jp nz, ResetFuryCutterCount
+
+ inc [hl]
+
+; Damage capped at 5 turns' worth (16x).
+ ld a, [hl]
+ ld b, a
+ cp 6
+ jr c, .checkdouble
+ ld b, 5
+
+.checkdouble
+ dec b
+ ret z
+
+; Double the damage
+ ld hl, wCurDamage + 1
+ sla [hl]
+ dec hl
+ rl [hl]
+ jr nc, .checkdouble
+
+; No overflow
+ ld a, $ff
+ ld [hli], a
+ ld [hl], a
+ ret
+
+ResetFuryCutterCount:
+ push hl
+
+ ld hl, wPlayerFuryCutterCount
+ ldh a, [hBattleTurn]
+ and a
+ jr z, .reset
+ ld hl, wEnemyFuryCutterCount
+
+.reset
+ xor a
+ ld [hl], a
+
+ pop hl
+ ret
diff --git a/engine/battle/move_effects/future_sight.asm b/engine/battle/move_effects/future_sight.asm
new file mode 100644
index 00000000..129a9e08
--- /dev/null
+++ b/engine/battle/move_effects/future_sight.asm
@@ -0,0 +1,81 @@
+BattleCommand_CheckFutureSight:
+; checkfuturesight
+
+ ld hl, wPlayerFutureSightCount
+ ld de, wPlayerFutureSightDamage
+ ldh a, [hBattleTurn]
+ and a
+ jr z, .ok
+ ld hl, wEnemyFutureSightCount
+ ld de, wEnemyFutureSightDamage
+.ok
+
+ ld a, [hl]
+ and a
+ ret z
+ cp 1
+ ret nz
+
+ ld [hl], 0
+ ld a, [de]
+ inc de
+ ld [wCurDamage], a
+ ld a, [de]
+ ld [wCurDamage + 1], a
+ ld b, futuresight_command
+ jp SkipToBattleCommand
+
+BattleCommand_FutureSight:
+; futuresight
+
+ call CheckUserIsCharging
+ jr nz, .AlreadyChargingFutureSight
+ ld a, BATTLE_VARS_MOVE_ANIM
+ call GetBattleVar
+ ld b, a
+ ld a, BATTLE_VARS_LAST_COUNTER_MOVE
+ call GetBattleVarAddr
+ ld [hl], b
+ ld a, BATTLE_VARS_LAST_MOVE
+ call GetBattleVarAddr
+ ld [hl], b
+.AlreadyChargingFutureSight:
+ ld hl, wPlayerFutureSightCount
+ ldh a, [hBattleTurn]
+ and a
+ jr z, .GotFutureSightCount
+ ld hl, wEnemyFutureSightCount
+.GotFutureSightCount:
+ ld a, [hl]
+ and a
+ jr nz, .failed
+ ld a, 4
+ ld [hl], a
+ call BattleCommand_LowerSub
+ call BattleCommand_MoveDelay
+ ld hl, ForesawAttackText
+ call StdBattleTextbox
+ call BattleCommand_RaiseSub
+ ld de, wPlayerFutureSightDamage
+ ldh a, [hBattleTurn]
+ and a
+ jr z, .StoreDamage
+ ld de, wEnemyFutureSightDamage
+.StoreDamage:
+ ld hl, wCurDamage
+ ld a, [hl]
+ ld [de], a
+ ld [hl], 0
+ inc hl
+ inc de
+ ld a, [hl]
+ ld [de], a
+ ld [hl], 0
+ jp EndMoveEffect
+
+.failed
+ pop bc
+ call ResetDamage
+ call AnimateFailedMove
+ call PrintButItFailed
+ jp EndMoveEffect
diff --git a/engine/battle/move_effects/heal_bell.asm b/engine/battle/move_effects/heal_bell.asm
new file mode 100644
index 00000000..62309f1d
--- /dev/null
+++ b/engine/battle/move_effects/heal_bell.asm
@@ -0,0 +1,34 @@
+BattleCommand_HealBell:
+; healbell
+
+ ld a, BATTLE_VARS_SUBSTATUS1
+ call GetBattleVarAddr
+ res SUBSTATUS_NIGHTMARE, [hl]
+ ld de, wPartyMon1Status
+ ldh a, [hBattleTurn]
+ and a
+ jr z, .got_status
+ ld de, wOTPartyMon1Status
+.got_status
+ ld a, BATTLE_VARS_STATUS
+ call GetBattleVarAddr
+ xor a
+ ld [hl], a
+ ld h, d
+ ld l, e
+ ld bc, PARTYMON_STRUCT_LENGTH
+ ld d, PARTY_LENGTH
+.loop
+ ld [hl], a
+ add hl, bc
+ dec d
+ jr nz, .loop
+ call AnimateCurrentMove
+
+ ld hl, BellChimedText
+ call StdBattleTextbox
+
+ ldh a, [hBattleTurn]
+ and a
+ jp z, CalcPlayerStats
+ jp CalcEnemyStats
diff --git a/engine/battle/move_effects/hidden_power.asm b/engine/battle/move_effects/hidden_power.asm
new file mode 100644
index 00000000..3b40a6c3
--- /dev/null
+++ b/engine/battle/move_effects/hidden_power.asm
@@ -0,0 +1,8 @@
+BattleCommand_HiddenPower:
+; hiddenpower
+
+ ld a, [wAttackMissed]
+ and a
+ ret nz
+ farcall HiddenPowerDamage
+ ret
diff --git a/engine/battle/move_effects/leech_seed.asm b/engine/battle/move_effects/leech_seed.asm
new file mode 100644
index 00000000..bb17ee00
--- /dev/null
+++ b/engine/battle/move_effects/leech_seed.asm
@@ -0,0 +1,40 @@
+BattleCommand_LeechSeed:
+; leechseed
+ ld a, [wAttackMissed]
+ and a
+ jr nz, .evaded
+ call CheckSubstituteOpp
+ jr nz, .evaded
+
+ ld de, wEnemyMonType1
+ ldh a, [hBattleTurn]
+ and a
+ jr z, .ok
+ ld de, wBattleMonType1
+.ok
+
+ ld a, [de]
+ cp GRASS
+ jr z, .grass
+ inc de
+ ld a, [de]
+ cp GRASS
+ jr z, .grass
+
+ ld a, BATTLE_VARS_SUBSTATUS4_OPP
+ call GetBattleVarAddr
+ bit SUBSTATUS_LEECH_SEED, [hl]
+ jr nz, .evaded
+ set SUBSTATUS_LEECH_SEED, [hl]
+ call AnimateCurrentMove
+ ld hl, WasSeededText
+ jp StdBattleTextbox
+
+.grass
+ call AnimateFailedMove
+ jp PrintDoesntAffect
+
+.evaded
+ call AnimateFailedMove
+ ld hl, EvadedText
+ jp StdBattleTextbox
diff --git a/engine/battle/move_effects/lock_on.asm b/engine/battle/move_effects/lock_on.asm
new file mode 100644
index 00000000..1de3e14b
--- /dev/null
+++ b/engine/battle/move_effects/lock_on.asm
@@ -0,0 +1,21 @@
+BattleCommand_LockOn:
+; lockon
+
+ call CheckSubstituteOpp
+ jr nz, .fail
+
+ ld a, [wAttackMissed]
+ and a
+ jr nz, .fail
+
+ ld a, BATTLE_VARS_SUBSTATUS5_OPP
+ call GetBattleVarAddr
+ set SUBSTATUS_LOCK_ON, [hl]
+ call AnimateCurrentMove
+
+ ld hl, TookAimText
+ jp StdBattleTextbox
+
+.fail
+ call AnimateFailedMove
+ jp PrintDidntAffect
diff --git a/engine/battle/move_effects/magnitude.asm b/engine/battle/move_effects/magnitude.asm
new file mode 100644
index 00000000..f8961b66
--- /dev/null
+++ b/engine/battle/move_effects/magnitude.asm
@@ -0,0 +1,29 @@
+BattleCommand_GetMagnitude:
+; getmagnitude
+
+ push bc
+ call BattleRandom
+ ld b, a
+ ld hl, MagnitudePower
+.loop
+ ld a, [hli]
+ cp b
+ jr nc, .ok
+ inc hl
+ inc hl
+ jr .loop
+
+.ok
+ ld d, [hl]
+ push de
+ inc hl
+ ld a, [hl]
+ ld [wDeciramBuffer], a
+ call BattleCommand_MoveDelay
+ ld hl, MagnitudeText
+ call StdBattleTextbox
+ pop de
+ pop bc
+ ret
+
+INCLUDE "data/moves/magnitude_power.asm"
diff --git a/engine/battle/move_effects/metronome.asm b/engine/battle/move_effects/metronome.asm
new file mode 100644
index 00000000..02766c16
--- /dev/null
+++ b/engine/battle/move_effects/metronome.asm
@@ -0,0 +1,43 @@
+BattleCommand_Metronome:
+; metronome
+
+ call ClearLastMove
+ call CheckUserIsCharging
+ jr nz, .asm_3752a
+
+ ld a, [wKickCounter]
+ push af
+ call BattleCommand_LowerSub
+ pop af
+ ld [wKickCounter], a
+
+.asm_3752a
+ call LoadMoveAnim
+
+.GetMove:
+ call BattleRandom
+
+; No invalid moves.
+ cp NUM_ATTACKS + 1
+ jr nc, .GetMove
+
+; None of the moves in MetronomeExcepts.
+ push af
+ ld de, 1
+ ld hl, MetronomeExcepts
+ call IsInArray
+ pop bc
+ jr c, .GetMove
+
+; No moves the user already has.
+ ld a, b
+ call CheckUserMove
+ jr z, .GetMove
+
+ ld a, BATTLE_VARS_MOVE
+ call GetBattleVarAddr
+ ld [hl], b
+ call UpdateMoveData
+ jp ResetTurn
+
+INCLUDE "data/moves/metronome_exception_moves.asm"
diff --git a/engine/battle/move_effects/mimic.asm b/engine/battle/move_effects/mimic.asm
new file mode 100644
index 00000000..71eb72c6
--- /dev/null
+++ b/engine/battle/move_effects/mimic.asm
@@ -0,0 +1,50 @@
+BattleCommand_Mimic:
+; mimic
+
+ call ClearLastMove
+ call BattleCommand_MoveDelay
+ ld a, [wAttackMissed]
+ and a
+ jr nz, .fail
+ ld hl, wBattleMonMoves
+ ldh a, [hBattleTurn]
+ and a
+ jr z, .player_turn
+ ld hl, wEnemyMonMoves
+.player_turn
+ call CheckHiddenOpponent
+ jr nz, .fail
+ ld a, BATTLE_VARS_LAST_COUNTER_MOVE_OPP
+ call GetBattleVar
+ and a
+ jr z, .fail
+ cp STRUGGLE
+ jr z, .fail
+ ld b, a
+ ld c, NUM_MOVES
+.check_already_knows_move
+ ld a, [hli]
+ cp b
+ jr z, .fail
+ dec c
+ jr nz, .check_already_knows_move
+ dec hl
+.find_mimic
+ ld a, [hld]
+ cp MIMIC
+ jr nz, .find_mimic
+ inc hl
+ ld a, BATTLE_VARS_LAST_COUNTER_MOVE_OPP
+ call GetBattleVar
+ ld [hl], a
+ ld [wNamedObjectIndexBuffer], a
+ ld bc, wBattleMonPP - wBattleMonMoves
+ add hl, bc
+ ld [hl], 5
+ call GetMoveName
+ call AnimateCurrentMove
+ ld hl, MimicLearnedMoveText
+ jp StdBattleTextbox
+
+.fail
+ jp FailMimic
diff --git a/engine/battle/move_effects/mirror_coat.asm b/engine/battle/move_effects/mirror_coat.asm
new file mode 100644
index 00000000..96afa317
--- /dev/null
+++ b/engine/battle/move_effects/mirror_coat.asm
@@ -0,0 +1,60 @@
+BattleCommand_MirrorCoat:
+; mirrorcoat
+
+ ld a, 1
+ ld [wAttackMissed], a
+
+ ld a, BATTLE_VARS_LAST_COUNTER_MOVE_OPP
+ call GetBattleVar
+ and a
+ ret z
+
+ ld b, a
+ callfar GetMoveEffect
+ ld a, b
+ cp EFFECT_MIRROR_COAT
+ ret z
+
+ call BattleCommand_ResetTypeMatchup
+ ld a, [wTypeMatchup]
+ and a
+ ret z
+
+ call CheckOpponentWentFirst
+ ret z
+
+ ld a, BATTLE_VARS_LAST_COUNTER_MOVE_OPP
+ call GetBattleVar
+ dec a
+ ld de, wStringBuffer1
+ call GetMoveData
+
+ ld a, [wStringBuffer1 + MOVE_POWER]
+ and a
+ ret z
+
+ ld a, [wStringBuffer1 + MOVE_TYPE]
+ cp SPECIAL
+ ret c
+
+ ; BUG: Move should fail with all non-damaging battle actions
+ ld hl, wCurDamage
+ ld a, [hli]
+ or [hl]
+ ret z
+
+ ld a, [hl]
+ add a
+ ld [hld], a
+ ld a, [hl]
+ adc a
+ ld [hl], a
+ jr nc, .capped
+ ld a, $ff
+ ld [hli], a
+ ld [hl], a
+.capped
+
+ xor a
+ ld [wAttackMissed], a
+ ret
diff --git a/engine/battle/move_effects/mirror_move.asm b/engine/battle/move_effects/mirror_move.asm
new file mode 100644
index 00000000..98e8aacc
--- /dev/null
+++ b/engine/battle/move_effects/mirror_move.asm
@@ -0,0 +1,51 @@
+BattleCommand_MirrorMove:
+; mirrormove
+
+ call ClearLastMove
+
+ ld a, BATTLE_VARS_MOVE
+ call GetBattleVarAddr
+
+ ld a, BATTLE_VARS_LAST_COUNTER_MOVE_OPP
+ call GetBattleVar
+ and a
+ jr z, .failed
+
+ call CheckUserMove
+ jr nz, .use
+
+.failed
+ call AnimateFailedMove
+
+ ld hl, MirrorMoveFailedText
+ call StdBattleTextbox
+ jp EndMoveEffect
+
+.use
+ ld a, b
+ ld [hl], a
+ ld [wNamedObjectIndexBuffer], a
+
+ push af
+ ld a, BATTLE_VARS_MOVE_ANIM
+ call GetBattleVarAddr
+ ld d, h
+ ld e, l
+ pop af
+
+ dec a
+ call GetMoveData
+ call GetMoveName
+ call CopyName1
+ call CheckUserIsCharging
+ jr nz, .done
+
+ ld a, [wKickCounter]
+ push af
+ call BattleCommand_LowerSub
+ pop af
+ ld [wKickCounter], a
+
+.done
+ call BattleCommand_MoveDelay
+ jp ResetTurn
diff --git a/engine/battle/move_effects/mist.asm b/engine/battle/move_effects/mist.asm
new file mode 100644
index 00000000..26fafdd2
--- /dev/null
+++ b/engine/battle/move_effects/mist.asm
@@ -0,0 +1,15 @@
+BattleCommand_Mist:
+; mist
+
+ ld a, BATTLE_VARS_SUBSTATUS4
+ call GetBattleVarAddr
+ bit SUBSTATUS_MIST, [hl]
+ jr nz, .already_mist
+ set SUBSTATUS_MIST, [hl]
+ call AnimateCurrentMove
+ ld hl, MistText
+ jp StdBattleTextbox
+
+.already_mist
+ call AnimateFailedMove
+ jp PrintButItFailed
diff --git a/engine/battle/move_effects/nightmare.asm b/engine/battle/move_effects/nightmare.asm
new file mode 100644
index 00000000..9354b15b
--- /dev/null
+++ b/engine/battle/move_effects/nightmare.asm
@@ -0,0 +1,37 @@
+BattleCommand_Nightmare:
+; nightmare
+
+; Can't hit an absent opponent.
+
+ call CheckHiddenOpponent
+ jr nz, .failed
+
+; Can't hit a substitute.
+
+ call CheckSubstituteOpp
+ jr nz, .failed
+
+; Only works on a sleeping opponent.
+
+ ld a, BATTLE_VARS_STATUS_OPP
+ call GetBattleVarAddr
+ and SLP
+ jr z, .failed
+
+; Bail if the opponent is already having a nightmare.
+
+ ld a, BATTLE_VARS_SUBSTATUS1_OPP
+ call GetBattleVarAddr
+ bit SUBSTATUS_NIGHTMARE, [hl]
+ jr nz, .failed
+
+; Otherwise give the opponent a nightmare.
+
+ set SUBSTATUS_NIGHTMARE, [hl]
+ call AnimateCurrentMove
+ ld hl, StartedNightmareText
+ jp StdBattleTextbox
+
+.failed
+ call AnimateFailedMove
+ jp PrintButItFailed
diff --git a/engine/battle/move_effects/pain_split.asm b/engine/battle/move_effects/pain_split.asm
new file mode 100644
index 00000000..68d7cfb4
--- /dev/null
+++ b/engine/battle/move_effects/pain_split.asm
@@ -0,0 +1,92 @@
+BattleCommand_PainSplit:
+; painsplit
+
+ ld a, [wAttackMissed]
+ and a
+ jp nz, .ButItFailed
+ call CheckSubstituteOpp
+ jp nz, .ButItFailed
+ call AnimateCurrentMove
+ ld hl, wBattleMonMaxHP + 1
+ ld de, wEnemyMonMaxHP + 1
+ call .PlayerShareHP
+ ld a, $1
+ ld [wWhichHPBar], a
+ hlcoord 10, 9
+ predef AnimateHPBar
+ ld hl, wEnemyMonHP
+ ld a, [hli]
+ ld [wBuffer4], a
+ ld a, [hli]
+ ld [wBuffer3], a
+ ld a, [hli]
+ ld [wBuffer2], a
+ ld a, [hl]
+ ld [wBuffer1], a
+ call .EnemyShareHP
+ xor a
+ ld [wWhichHPBar], a
+ call ResetDamage
+ hlcoord 2, 2
+ predef AnimateHPBar
+
+ ld hl, SharedPainText
+ jp StdBattleTextbox
+
+.PlayerShareHP:
+ ld a, [hld]
+ ld [wBuffer1], a
+ ld a, [hld]
+ ld [wBuffer2], a
+ ld a, [hld]
+ ld b, a
+ ld [wBuffer3], a
+ ld a, [hl]
+ ld [wBuffer4], a
+ dec de
+ dec de
+ ld a, [de]
+ dec de
+ add b
+ ld [wCurDamage + 1], a
+ ld b, [hl]
+ ld a, [de]
+ adc b
+ srl a
+ ld [wCurDamage], a
+ ld a, [wCurDamage + 1]
+ rr a
+ ld [wCurDamage + 1], a
+ inc hl
+ inc hl
+ inc hl
+ inc de
+ inc de
+ inc de
+
+.EnemyShareHP:
+ ld c, [hl]
+ dec hl
+ ld a, [wCurDamage + 1]
+ sub c
+ ld b, [hl]
+ dec hl
+ ld a, [wCurDamage]
+ sbc b
+ jr nc, .skip
+
+ ld a, [wCurDamage]
+ ld b, a
+ ld a, [wCurDamage + 1]
+ ld c, a
+.skip
+ ld a, c
+ ld [hld], a
+ ld [wBuffer5], a
+ ld a, b
+ ld [hli], a
+ ld [wBuffer6], a
+ ret
+
+.ButItFailed:
+ jp PrintDidntAffect2
diff --git a/engine/battle/move_effects/pay_day.asm b/engine/battle/move_effects/pay_day.asm
new file mode 100644
index 00000000..5f857aea
--- /dev/null
+++ b/engine/battle/move_effects/pay_day.asm
@@ -0,0 +1,26 @@
+BattleCommand_PayDay:
+; payday
+
+ xor a
+ ld hl, wStringBuffer1
+ ld [hli], a
+
+ ldh a, [hBattleTurn]
+ and a
+ ld a, [wBattleMonLevel]
+ jr z, .ok
+ ld a, [wEnemyMonLevel]
+.ok
+
+ add a
+ ld hl, wPayDayMoney + 2
+ add [hl]
+ ld [hld], a
+ jr nc, .done
+ inc [hl]
+ dec hl
+ jr nz, .done
+ inc [hl]
+.done
+ ld hl, CoinsScatteredText
+ jp StdBattleTextbox
diff --git a/engine/battle/move_effects/perish_song.asm b/engine/battle/move_effects/perish_song.asm
new file mode 100644
index 00000000..1758b65a
--- /dev/null
+++ b/engine/battle/move_effects/perish_song.asm
@@ -0,0 +1,38 @@
+BattleCommand_PerishSong:
+; perishsong
+
+ ld hl, wPlayerSubStatus1
+ ld de, wEnemySubStatus1
+ bit SUBSTATUS_PERISH, [hl]
+ jr z, .ok
+
+ ld a, [de]
+ bit SUBSTATUS_PERISH, a
+ jr nz, .failed
+
+.ok
+ bit SUBSTATUS_PERISH, [hl]
+ jr nz, .enemy
+
+ set SUBSTATUS_PERISH, [hl]
+ ld a, 4
+ ld [wPlayerPerishCount], a
+
+.enemy
+ ld a, [de]
+ bit SUBSTATUS_PERISH, a
+ jr nz, .done
+
+ set SUBSTATUS_PERISH, a
+ ld [de], a
+ ld a, 4
+ ld [wEnemyPerishCount], a
+
+.done
+ call AnimateCurrentMove
+ ld hl, StartPerishText
+ jp StdBattleTextbox
+
+.failed
+ call AnimateFailedMove
+ jp PrintButItFailed
diff --git a/engine/battle/move_effects/present.asm b/engine/battle/move_effects/present.asm
new file mode 100644
index 00000000..360a4172
--- /dev/null
+++ b/engine/battle/move_effects/present.asm
@@ -0,0 +1,75 @@
+BattleCommand_Present:
+; present
+
+ call BattleCommand_Stab
+ ld a, [wTypeMatchup]
+ and a
+ jp z, AnimateFailedMove
+ ld a, [wAttackMissed]
+ and a
+ jp nz, AnimateFailedMove
+
+ push bc
+ call BattleRandom
+ ld b, a
+ ld hl, PresentPower
+ ld c, 0
+.next
+ ld a, [hli]
+ cp -1
+ jr z, .heal_effect
+ cp b
+ jr nc, .got_power
+ inc c
+ inc hl
+ jr .next
+
+.got_power
+ ld a, c
+ ld [wPresentPower], a
+ call AnimateCurrentMoveEitherSide
+ ld d, [hl]
+ pop bc
+ ret
+
+.heal_effect
+ pop bc
+ ld a, 3
+ ld [wPresentPower], a
+ call AnimateCurrentMove
+ call BattleCommand_SwitchTurn
+ ld hl, AICheckPlayerMaxHP
+ ldh a, [hBattleTurn]
+ and a
+ jr z, .got_hp_fn_pointer
+ ld hl, AICheckEnemyMaxHP
+.got_hp_fn_pointer
+ ld a, BANK(AICheckPlayerMaxHP) ; aka BANK(AICheckEnemyMaxHP)
+ rst FarCall
+ jr c, .already_fully_healed
+
+ ld hl, GetQuarterMaxHP
+ call CallBattleCore
+ call BattleCommand_SwitchTurn
+ ld hl, RestoreHP
+ call CallBattleCore
+ call BattleCommand_SwitchTurn
+ ld hl, RegainedHealthText
+ call StdBattleTextbox
+ call BattleCommand_SwitchTurn
+ call UpdateOpponentInParty
+ jr .do_animation
+
+.already_fully_healed
+ call BattleCommand_SwitchTurn
+ ; check battle scene
+ ld a, [wOptions]
+ add a
+ jr nc, .do_animation
+ call AnimateFailedMove
+ ld hl, CantReceiveGiftText
+ call StdBattleTextbox
+.do_animation
+ jp EndMoveEffect
+
+INCLUDE "data/moves/present_power.asm"
diff --git a/engine/battle/move_effects/protect.asm b/engine/battle/move_effects/protect.asm
new file mode 100644
index 00000000..9f3899a9
--- /dev/null
+++ b/engine/battle/move_effects/protect.asm
@@ -0,0 +1,75 @@
+BattleCommand_Protect:
+; protect
+ call ProtectChance
+ ret c
+
+ ld a, BATTLE_VARS_SUBSTATUS1
+ call GetBattleVarAddr
+ set SUBSTATUS_PROTECT, [hl]
+
+ call AnimateCurrentMove
+
+ ld hl, ProtectedItselfText
+ jp StdBattleTextbox
+
+ProtectChance:
+ ld de, wPlayerProtectCount
+ ldh a, [hBattleTurn]
+ and a
+ jr z, .asm_37736
+ ld de, wEnemyProtectCount
+.asm_37736
+
+ call CheckOpponentWentFirst
+ jr nz, .failed
+
+; Can't have a substitute.
+
+ ld a, BATTLE_VARS_SUBSTATUS4
+ call GetBattleVar
+ bit SUBSTATUS_SUBSTITUTE, a
+ jr nz, .failed
+
+; Halve the chance of a successful Protect for each consecutive use.
+
+ ld b, $ff
+ ld a, [de]
+ ld c, a
+.loop
+ ld a, c
+ and a
+ jr z, .done
+ dec c
+
+ srl b
+ ld a, b
+ and a
+ jr nz, .loop
+ jr .failed
+.done
+
+.rand
+ call BattleRandom
+ and a
+ jr z, .rand
+
+ dec a
+ cp b
+ jr nc, .failed
+
+; Another consecutive Protect use.
+
+ ld a, [de]
+ inc a
+ ld [de], a
+
+ and a
+ ret
+
+.failed
+ xor a
+ ld [de], a
+ call AnimateFailedMove
+ call PrintButItFailed
+ scf
+ ret
diff --git a/engine/battle/move_effects/psych_up.asm b/engine/battle/move_effects/psych_up.asm
new file mode 100644
index 00000000..3473b9db
--- /dev/null
+++ b/engine/battle/move_effects/psych_up.asm
@@ -0,0 +1,47 @@
+BattleCommand_PsychUp:
+; psychup
+
+ ld hl, wEnemyStatLevels
+ ld de, wPlayerStatLevels
+ ldh a, [hBattleTurn]
+ and a
+ jr z, .pointers_correct
+; It's the enemy's turn, so swap the pointers.
+ ld hl, wPlayerStatLevels
+ ld de, wEnemyStatLevels
+.pointers_correct
+ push hl
+ ld b, NUM_LEVEL_STATS
+; If any of the enemy's stats is modified from its base level,
+; the move succeeds. Otherwise, it fails.
+.loop
+ ld a, [hli]
+ cp BASE_STAT_LEVEL
+ jr nz, .break
+ dec b
+ jr nz, .loop
+ pop hl
+ call AnimateFailedMove
+ jp PrintButItFailed
+
+.break
+ pop hl
+ ld b, NUM_LEVEL_STATS
+.loop2
+ ld a, [hli]
+ ld [de], a
+ inc de
+ dec b
+ jr nz, .loop2
+ ldh a, [hBattleTurn]
+ and a
+ jr nz, .calc_enemy_stats
+ call CalcPlayerStats
+ jr .merge
+
+.calc_enemy_stats
+ call CalcEnemyStats
+.merge
+ call AnimateCurrentMove
+ ld hl, CopiedStatsText
+ jp StdBattleTextbox
diff --git a/engine/battle/move_effects/pursuit.asm b/engine/battle/move_effects/pursuit.asm
new file mode 100644
index 00000000..f8979fb9
--- /dev/null
+++ b/engine/battle/move_effects/pursuit.asm
@@ -0,0 +1,24 @@
+BattleCommand_Pursuit:
+; pursuit
+; Double damage if the opponent is switching.
+
+ ld hl, wEnemyIsSwitching
+ ldh a, [hBattleTurn]
+ and a
+ jr z, .ok
+ ld hl, wPlayerIsSwitching
+.ok
+ ld a, [hl]
+ and a
+ ret z
+
+ ld hl, wCurDamage + 1
+ sla [hl]
+ dec hl
+ rl [hl]
+ ret nc
+
+ ld a, $ff
+ ld [hli], a
+ ld [hl], a
+ ret
diff --git a/engine/battle/move_effects/rage.asm b/engine/battle/move_effects/rage.asm
new file mode 100644
index 00000000..df206a6b
--- /dev/null
+++ b/engine/battle/move_effects/rage.asm
@@ -0,0 +1,6 @@
+BattleCommand_Rage:
+; rage
+ ld a, BATTLE_VARS_SUBSTATUS4
+ call GetBattleVarAddr
+ set SUBSTATUS_RAGE, [hl]
+ ret
diff --git a/engine/battle/move_effects/rain_dance.asm b/engine/battle/move_effects/rain_dance.asm
new file mode 100644
index 00000000..c22fb9fd
--- /dev/null
+++ b/engine/battle/move_effects/rain_dance.asm
@@ -0,0 +1,9 @@
+BattleCommand_StartRain:
+; startrain
+ ld a, WEATHER_RAIN
+ ld [wBattleWeather], a
+ ld a, 5
+ ld [wWeatherCount], a
+ call AnimateCurrentMove
+ ld hl, DownpourText
+ jp StdBattleTextbox
diff --git a/engine/battle/move_effects/rapid_spin.asm b/engine/battle/move_effects/rapid_spin.asm
new file mode 100644
index 00000000..eb396a35
--- /dev/null
+++ b/engine/battle/move_effects/rapid_spin.asm
@@ -0,0 +1,36 @@
+BattleCommand_ClearHazards:
+; clearhazards
+
+ ld a, BATTLE_VARS_SUBSTATUS4
+ call GetBattleVarAddr
+ bit SUBSTATUS_LEECH_SEED, [hl]
+ jr z, .not_leeched
+ res SUBSTATUS_LEECH_SEED, [hl]
+ ld hl, ShedLeechSeedText
+ call StdBattleTextbox
+.not_leeched
+
+ ld hl, wPlayerScreens
+ ld de, wPlayerWrapCount
+ ldh a, [hBattleTurn]
+ and a
+ jr z, .got_screens_wrap
+ ld hl, wEnemyScreens
+ ld de, wEnemyWrapCount
+.got_screens_wrap
+ bit SCREENS_SPIKES, [hl]
+ jr z, .no_spikes
+ res SCREENS_SPIKES, [hl]
+ ld hl, BlewSpikesText
+ push de
+ call StdBattleTextbox
+ pop de
+.no_spikes
+
+ ld a, [de]
+ and a
+ ret z
+ xor a
+ ld [de], a
+ ld hl, ReleasedByText
+ jp StdBattleTextbox
diff --git a/engine/battle/move_effects/return.asm b/engine/battle/move_effects/return.asm
new file mode 100644
index 00000000..7c7c5fcb
--- /dev/null
+++ b/engine/battle/move_effects/return.asm
@@ -0,0 +1,25 @@
+BattleCommand_HappinessPower:
+; happinesspower
+ push bc
+ ld hl, wBattleMonHappiness
+ ldh a, [hBattleTurn]
+ and a
+ jr z, .ok
+ ld hl, wEnemyMonHappiness
+.ok
+ xor a
+ ldh [hMultiplicand + 0], a
+ ldh [hMultiplicand + 1], a
+ ld a, [hl]
+ ldh [hMultiplicand + 2], a
+ ld a, 10
+ ldh [hMultiplier], a
+ call Multiply
+ ld a, 25
+ ldh [hDivisor], a
+ ld b, 4
+ call Divide
+ ldh a, [hQuotient + 3]
+ ld d, a
+ pop bc
+ ret
diff --git a/engine/battle/move_effects/rollout.asm b/engine/battle/move_effects/rollout.asm
new file mode 100644
index 00000000..e2f810e6
--- /dev/null
+++ b/engine/battle/move_effects/rollout.asm
@@ -0,0 +1,95 @@
+MAX_ROLLOUT_COUNT EQU 5
+
+BattleCommand_CheckCurl:
+; checkcurl
+
+ ld de, wPlayerRolloutCount
+ ldh a, [hBattleTurn]
+ and a
+ jr z, .ok
+ ld de, wEnemyRolloutCount
+.ok
+ ld a, BATTLE_VARS_SUBSTATUS1
+ call GetBattleVar
+ bit SUBSTATUS_ROLLOUT, a
+ jr z, .reset
+
+ ld b, $4 ; doturn
+ jp SkipToBattleCommand
+
+.reset
+ xor a
+ ld [de], a
+ ret
+
+BattleCommand_RolloutPower:
+; rolloutpower
+
+ ld a, BATTLE_VARS_STATUS
+ call GetBattleVar
+ and SLP
+ ret nz
+
+ ld hl, wPlayerRolloutCount
+ ldh a, [hBattleTurn]
+ and a
+ jr z, .got_rollout_count
+ ld hl, wEnemyRolloutCount
+
+.got_rollout_count
+ ld a, [hl]
+ and a
+ jr nz, .skip_set_rampage
+ ld a, 1
+ ld [wSomeoneIsRampaging], a
+
+.skip_set_rampage
+ ld a, [wAttackMissed]
+ and a
+ jr z, .hit
+
+ ld a, BATTLE_VARS_SUBSTATUS1
+ call GetBattleVarAddr
+ res 6, [hl]
+ ret
+
+.hit
+ inc [hl]
+ ld a, [hl]
+ ld b, a
+ cp MAX_ROLLOUT_COUNT
+ jr c, .not_done_with_rollout
+
+ ld a, BATTLE_VARS_SUBSTATUS1
+ call GetBattleVarAddr
+ res SUBSTATUS_ROLLOUT, [hl]
+ jr .done_with_substatus_flag
+
+.not_done_with_rollout
+ ld a, BATTLE_VARS_SUBSTATUS1
+ call GetBattleVarAddr
+ set SUBSTATUS_ROLLOUT, [hl]
+
+.done_with_substatus_flag
+ ld a, BATTLE_VARS_SUBSTATUS2
+ call GetBattleVar
+ bit SUBSTATUS_CURLED, a
+ jr z, .not_curled
+ inc b
+.not_curled
+.loop
+ dec b
+ jr z, .done_damage
+
+ ld hl, wCurDamage + 1
+ sla [hl]
+ dec hl
+ rl [hl]
+ jr nc, .loop
+
+ ld a, $ff
+ ld [hli], a
+ ld [hl], a
+
+.done_damage
+ ret
diff --git a/engine/battle/move_effects/safeguard.asm b/engine/battle/move_effects/safeguard.asm
new file mode 100644
index 00000000..e64e8092
--- /dev/null
+++ b/engine/battle/move_effects/safeguard.asm
@@ -0,0 +1,23 @@
+BattleCommand_Safeguard:
+; safeguard
+
+ ld hl, wPlayerScreens
+ ld de, wPlayerSafeguardCount
+ ldh a, [hBattleTurn]
+ and a
+ jr z, .ok
+ ld hl, wEnemyScreens
+ ld de, wEnemySafeguardCount
+.ok
+ bit SCREENS_SAFEGUARD, [hl]
+ jr nz, .failed
+ set SCREENS_SAFEGUARD, [hl]
+ ld a, 5
+ ld [de], a
+ call AnimateCurrentMove
+ ld hl, CoveredByVeilText
+ jp StdBattleTextbox
+
+.failed
+ call AnimateFailedMove
+ jp PrintButItFailed
diff --git a/engine/battle/move_effects/sandstorm.asm b/engine/battle/move_effects/sandstorm.asm
new file mode 100644
index 00000000..c88529fb
--- /dev/null
+++ b/engine/battle/move_effects/sandstorm.asm
@@ -0,0 +1,18 @@
+BattleCommand_StartSandstorm:
+; startsandstorm
+
+ ld a, [wBattleWeather]
+ cp WEATHER_SANDSTORM
+ jr z, .failed
+
+ ld a, WEATHER_SANDSTORM
+ ld [wBattleWeather], a
+ ld a, 5
+ ld [wWeatherCount], a
+ call AnimateCurrentMove
+ ld hl, SandstormBrewedText
+ jp StdBattleTextbox
+
+.failed
+ call AnimateFailedMove
+ jp PrintButItFailed
diff --git a/engine/battle/move_effects/selfdestruct.asm b/engine/battle/move_effects/selfdestruct.asm
new file mode 100644
index 00000000..b4967b03
--- /dev/null
+++ b/engine/battle/move_effects/selfdestruct.asm
@@ -0,0 +1,30 @@
+BattleCommand_Selfdestruct:
+ ld a, BATTLEANIM_PLAYER_DAMAGE
+ ld [wNumHits], a
+ ld c, 3
+ call DelayFrames
+ ld a, BATTLE_VARS_STATUS
+ call GetBattleVarAddr
+ xor a
+ ld [hli], a
+ inc hl
+ ld [hli], a
+ ld [hl], a
+ ld a, $1
+ ld [wKickCounter], a
+ call BattleCommand_LowerSub
+ call LoadMoveAnim
+ ld a, BATTLE_VARS_SUBSTATUS4
+ call GetBattleVarAddr
+ res SUBSTATUS_LEECH_SEED, [hl]
+ ld a, BATTLE_VARS_SUBSTATUS5_OPP
+ call GetBattleVarAddr
+ res SUBSTATUS_DESTINY_BOND, [hl]
+ ; check battle scene
+ ld a, [wOptions]
+ add a
+ ret nc
+ farcall DrawPlayerHUD
+ farcall DrawEnemyHUD
+ call WaitBGMap
+ jp RefreshBattleHuds
diff --git a/engine/battle/move_effects/sketch.asm b/engine/battle/move_effects/sketch.asm
new file mode 100644
index 00000000..654fb3f5
--- /dev/null
+++ b/engine/battle/move_effects/sketch.asm
@@ -0,0 +1,117 @@
+BattleCommand_Sketch:
+; sketch
+
+ call ClearLastMove
+; Don't sketch during a link battle
+ ld a, [wLinkMode]
+ and a
+ jr z, .not_linked
+ call AnimateFailedMove
+ jp PrintNothingHappened
+
+.not_linked
+; If the opponent has a substitute up, fail.
+ call CheckSubstituteOpp
+ jp nz, .fail
+; If the opponent is transformed, fail.
+ ld a, BATTLE_VARS_SUBSTATUS5_OPP
+ call GetBattleVarAddr
+ bit SUBSTATUS_TRANSFORMED, [hl]
+ jp nz, .fail
+; Get the user's moveset in its party struct.
+; This move replacement shall be permanent.
+; Pointer will be in de.
+ ld a, MON_MOVES
+ call UserPartyAttr
+ ld d, h
+ ld e, l
+; Get the battle move structs.
+ ld hl, wBattleMonMoves
+ ldh a, [hBattleTurn]
+ and a
+ jr z, .get_last_move
+ ld hl, wEnemyMonMoves
+.get_last_move
+ ld a, BATTLE_VARS_LAST_COUNTER_MOVE_OPP
+ call GetBattleVar
+ ld [wNamedObjectIndexBuffer], a
+ ld b, a
+; Fail if move is invalid or is Struggle.
+ and a
+ jr z, .fail
+ cp STRUGGLE
+ jr z, .fail
+; Fail if user already knows that move
+ ld c, NUM_MOVES
+.does_user_already_know_move
+ ld a, [hli]
+ cp b
+ jr z, .fail
+ dec c
+ jr nz, .does_user_already_know_move
+; Find Sketch in the user's moveset.
+; Pointer in hl, and index in c.
+ dec hl
+ ld c, NUM_MOVES
+.find_sketch
+ dec c
+ ld a, [hld]
+ cp SKETCH
+ jr nz, .find_sketch
+ inc hl
+; The Sketched move is loaded to that slot.
+ ld a, b
+ ld [hl], a
+; Copy the base PP from that move.
+ push bc
+ push hl
+ dec a
+ ld hl, Moves + MOVE_PP
+ call GetMoveAttr
+ pop hl
+ ld bc, wBattleMonPP - wBattleMonMoves
+ add hl, bc
+ ld [hl], a
+ pop bc
+
+ ldh a, [hBattleTurn]
+ and a
+ jr z, .user_trainer
+ ld a, [wBattleMode]
+ dec a
+ jr nz, .user_trainer
+; wildmon
+ ld a, [hl]
+ push bc
+ ld hl, wWildMonPP
+ ld b, 0
+ add hl, bc
+ ld [hl], a
+ ld hl, wWildMonMoves
+ add hl, bc
+ pop bc
+ ld [hl], b
+ jr .done_copy
+
+.user_trainer
+ ld a, [hl]
+ push af
+ ld l, c
+ ld h, 0
+ add hl, de
+ ld a, b
+ ld [hl], a
+ pop af
+ ld de, MON_PP - MON_MOVES
+ add hl, de
+ ld [hl], a
+.done_copy
+ call GetMoveName
+ call AnimateCurrentMove
+
+ ld hl, SketchedText
+ jp StdBattleTextbox
+
+.fail
+ call AnimateFailedMove
+ jp PrintDidntAffect
diff --git a/engine/battle/move_effects/sleep_talk.asm b/engine/battle/move_effects/sleep_talk.asm
new file mode 100644
index 00000000..92bff260
--- /dev/null
+++ b/engine/battle/move_effects/sleep_talk.asm
@@ -0,0 +1,143 @@
+BattleCommand_SleepTalk:
+; sleeptalk
+
+ call ClearLastMove
+ ld a, [wAttackMissed]
+ and a
+ jr nz, .fail
+ ldh a, [hBattleTurn]
+ and a
+ ld hl, wBattleMonMoves + 1
+ ld a, [wDisabledMove]
+ ld d, a
+ jr z, .got_moves
+ ld hl, wEnemyMonMoves + 1
+ ld a, [wEnemyDisabledMove]
+ ld d, a
+.got_moves
+ ld a, BATTLE_VARS_STATUS
+ call GetBattleVar
+ and SLP
+ jr z, .fail
+ ld a, [hl]
+ and a
+ jr z, .fail
+ call .safely_check_has_usable_move
+ jr c, .fail
+ dec hl
+.sample_move
+ push hl
+ call BattleRandom
+ maskbits NUM_MOVES
+ ld c, a
+ ld b, 0
+ add hl, bc
+ ld a, [hl]
+ pop hl
+ and a
+ jr z, .sample_move
+ ld e, a
+ ld a, BATTLE_VARS_MOVE_ANIM
+ call GetBattleVar
+ cp e
+ jr z, .sample_move
+ ld a, e
+ cp d
+ jr z, .sample_move
+ call .check_two_turn_move
+ jr z, .sample_move
+ ld a, BATTLE_VARS_MOVE
+ call GetBattleVarAddr
+ ld a, e
+ ld [hl], a
+ call CheckUserIsCharging
+ jr nz, .charging
+ ld a, [wKickCounter]
+ push af
+ call BattleCommand_LowerSub
+ pop af
+ ld [wKickCounter], a
+.charging
+ call LoadMoveAnim
+ call UpdateMoveData
+ jp ResetTurn
+
+.fail
+ call AnimateFailedMove
+ jp TryPrintButItFailed
+
+.safely_check_has_usable_move
+ push hl
+ push de
+ push bc
+ call .check_has_usable_move
+ pop bc
+ pop de
+ pop hl
+ ret
+
+.check_has_usable_move
+ ldh a, [hBattleTurn]
+ and a
+ ld a, [wDisabledMove]
+ jr z, .got_move_2
+
+ ld a, [wEnemyDisabledMove]
+.got_move_2
+ ld b, a
+ ld a, BATTLE_VARS_MOVE
+ call GetBattleVar
+ ld c, a
+ dec hl
+ ld d, NUM_MOVES
+.loop2
+ ld a, [hl]
+ and a
+ jr z, .carry
+
+ cp c
+ jr z, .nope
+ cp b
+ jr z, .nope
+
+ call .check_two_turn_move
+ jr nz, .no_carry
+
+.nope
+ inc hl
+ dec d
+ jr nz, .loop2
+
+.carry
+ scf
+ ret
+
+.no_carry
+ and a
+ ret
+
+.check_two_turn_move
+ push hl
+ push de
+ push bc
+
+ ld b, a
+ callfar GetMoveEffect
+ ld a, b
+
+ pop bc
+ pop de
+ pop hl
+
+ cp EFFECT_SKULL_BASH
+ ret z
+ cp EFFECT_RAZOR_WIND
+ ret z
+ cp EFFECT_SKY_ATTACK
+ ret z
+ cp EFFECT_SOLARBEAM
+ ret z
+ cp EFFECT_FLY
+ ret z
+ cp EFFECT_BIDE
+ ret
diff --git a/engine/battle/move_effects/snore.asm b/engine/battle/move_effects/snore.asm
new file mode 100644
index 00000000..e2432c59
--- /dev/null
+++ b/engine/battle/move_effects/snore.asm
@@ -0,0 +1,11 @@
+BattleCommand_Snore:
+; snore
+ ld a, BATTLE_VARS_STATUS
+ call GetBattleVar
+ and SLP
+ ret nz
+ call ResetDamage
+ ld a, $1
+ ld [wAttackMissed], a
+ call FailMove
+ jp EndMoveEffect
diff --git a/engine/battle/move_effects/spikes.asm b/engine/battle/move_effects/spikes.asm
new file mode 100644
index 00000000..06aa35e8
--- /dev/null
+++ b/engine/battle/move_effects/spikes.asm
@@ -0,0 +1,26 @@
+BattleCommand_Spikes:
+; spikes
+
+ ld hl, wEnemyScreens
+ ldh a, [hBattleTurn]
+ and a
+ jr z, .asm_3778d
+ ld hl, wPlayerScreens
+.asm_3778d
+
+; Fails if spikes are already down!
+
+ bit SCREENS_SPIKES, [hl]
+ jr nz, .failed
+
+; Nothing else stops it from working.
+
+ set SCREENS_SPIKES, [hl]
+
+ call AnimateCurrentMove
+
+ ld hl, SpikesText
+ jp StdBattleTextbox
+
+.failed
+ jp FailMove
diff --git a/engine/battle/move_effects/spite.asm b/engine/battle/move_effects/spite.asm
new file mode 100644
index 00000000..06627268
--- /dev/null
+++ b/engine/battle/move_effects/spite.asm
@@ -0,0 +1,86 @@
+BattleCommand_Spite:
+; spite
+
+ ld a, [wAttackMissed]
+ and a
+ jp nz, .failed
+ ld bc, PARTYMON_STRUCT_LENGTH ; ????
+ ld hl, wEnemyMonMoves
+ ldh a, [hBattleTurn]
+ and a
+ jr z, .got_moves
+ ld hl, wBattleMonMoves
+.got_moves
+ ld a, BATTLE_VARS_LAST_COUNTER_MOVE_OPP
+ call GetBattleVar
+ and a
+ jr z, .failed
+ cp STRUGGLE
+ jr z, .failed
+ ld b, a
+ ld c, -1
+.loop
+ inc c
+ ld a, [hli]
+ cp b
+ jr nz, .loop
+ ld [wNamedObjectIndexBuffer], a
+ dec hl
+ ld b, 0
+ push bc
+ ld c, wBattleMonPP - wBattleMonMoves
+ add hl, bc
+ pop bc
+ ld a, [hl]
+ and PP_MASK
+ jr z, .failed
+ push bc
+ call GetMoveName
+ ; lose 2-5 PP
+ call BattleRandom
+ and %11
+ inc a
+ inc a
+ ld b, a
+ ld a, [hl]
+ and PP_MASK
+ cp b
+ jr nc, .deplete_pp
+ ld b, a
+.deplete_pp
+ ld a, [hl]
+ sub b
+ ld [hl], a
+ push af
+ ld a, MON_PP
+ call OpponentPartyAttr
+ ld d, b
+ pop af
+ pop bc
+ add hl, bc
+ ld e, a
+ ld a, BATTLE_VARS_SUBSTATUS5_OPP
+ call GetBattleVar
+ bit SUBSTATUS_TRANSFORMED, a
+ jr nz, .transformed
+ ldh a, [hBattleTurn]
+ and a
+ jr nz, .not_wildmon
+ ld a, [wBattleMode]
+ dec a
+ jr nz, .not_wildmon
+ ld hl, wWildMonPP
+ add hl, bc
+.not_wildmon
+ ld [hl], e
+.transformed
+ push de
+ call AnimateCurrentMove
+ pop de
+ ld a, d
+ ld [wDeciramBuffer], a
+ ld hl, SpiteEffectText
+ jp StdBattleTextbox
+
+.failed
+ jp PrintDidntAffect2
diff --git a/engine/battle/move_effects/splash.asm b/engine/battle/move_effects/splash.asm
new file mode 100644
index 00000000..1be307f8
--- /dev/null
+++ b/engine/battle/move_effects/splash.asm
@@ -0,0 +1,3 @@
+BattleCommand_Splash:
+ call AnimateCurrentMove
+ jp PrintNothingHappened
diff --git a/engine/battle/move_effects/substitute.asm b/engine/battle/move_effects/substitute.asm
new file mode 100644
index 00000000..c5ab8741
--- /dev/null
+++ b/engine/battle/move_effects/substitute.asm
@@ -0,0 +1,90 @@
+BattleCommand_Substitute:
+; substitute
+
+ call BattleCommand_MoveDelay
+ ld hl, wBattleMonMaxHP
+ ld de, wPlayerSubstituteHP
+ ldh a, [hBattleTurn]
+ and a
+ jr z, .got_hp
+ ld hl, wEnemyMonMaxHP
+ ld de, wEnemySubstituteHP
+.got_hp
+
+ ld a, BATTLE_VARS_SUBSTATUS4
+ call GetBattleVar
+ bit SUBSTATUS_SUBSTITUTE, a
+ jr nz, .already_has_sub
+
+ ld a, [hli]
+ ld b, [hl]
+ srl a
+ rr b
+ srl a
+ rr b
+ dec hl
+ dec hl
+ ld a, b
+ ld [de], a
+ ld a, [hld]
+ sub b
+ ld e, a
+ ld a, [hl]
+ sbc 0
+ ld d, a
+ jr c, .too_weak_to_sub
+ ld a, d
+ or e
+ jr z, .too_weak_to_sub
+ ld [hl], d
+ inc hl
+ ld [hl], e
+
+ ld a, BATTLE_VARS_SUBSTATUS4
+ call GetBattleVarAddr
+ set SUBSTATUS_SUBSTITUTE, [hl]
+
+ ld hl, wPlayerWrapCount
+ ld de, wPlayerTrappingMove
+ ldh a, [hBattleTurn]
+ and a
+ jr z, .player
+ ld hl, wEnemyWrapCount
+ ld de, wEnemyTrappingMove
+.player
+
+ xor a
+ ld [hl], a
+ ld [de], a
+ ; check battle scene
+ ld a, [wOptions]
+ add a
+ jr c, .no_anim
+
+ xor a
+ ld [wNumHits], a
+ ld [wFXAnimID + 1], a
+ ld [wKickCounter], a
+ ld a, SUBSTITUTE
+ call LoadAnim
+ jr .finish
+
+.no_anim
+ call BattleCommand_RaiseSubNoAnim
+.finish
+ ld hl, MadeSubstituteText
+ call StdBattleTextbox
+ jp RefreshBattleHuds
+
+.already_has_sub
+ call CheckUserIsCharging
+ call nz, BattleCommand_RaiseSub
+ ld hl, HasSubstituteText
+ jr .jp_stdbattletextbox
+
+.too_weak_to_sub
+ call CheckUserIsCharging
+ call nz, BattleCommand_RaiseSub
+ ld hl, TooWeakSubText
+.jp_stdbattletextbox
+ jp StdBattleTextbox
diff --git a/engine/battle/move_effects/sunny_day.asm b/engine/battle/move_effects/sunny_day.asm
new file mode 100644
index 00000000..0edc38e4
--- /dev/null
+++ b/engine/battle/move_effects/sunny_day.asm
@@ -0,0 +1,9 @@
+BattleCommand_StartSun:
+; startsun
+ ld a, WEATHER_SUN
+ ld [wBattleWeather], a
+ ld a, 5
+ ld [wWeatherCount], a
+ call AnimateCurrentMove
+ ld hl, SunGotBrightText
+ jp StdBattleTextbox
diff --git a/engine/battle/move_effects/teleport.asm b/engine/battle/move_effects/teleport.asm
new file mode 100644
index 00000000..7d866ccf
--- /dev/null
+++ b/engine/battle/move_effects/teleport.asm
@@ -0,0 +1,87 @@
+BattleCommand_Teleport:
+; teleport
+
+ ld a, [wBattleType]
+ cp BATTLETYPE_SHINY
+ jr z, .failed
+ cp BATTLETYPE_TRAP
+ jr z, .failed
+
+ ld a, BATTLE_VARS_SUBSTATUS5_OPP
+ call GetBattleVar
+ bit SUBSTATUS_CANT_RUN, a
+ jr nz, .failed
+; Only need to check these next things if it's your turn
+ ldh a, [hBattleTurn]
+ and a
+ jr nz, .enemy_turn
+; Can't teleport from a trainer battle
+ ld a, [wBattleMode]
+ dec a
+ jr nz, .failed
+; If your level is greater than the opponent's, you run without fail.
+ ld a, [wCurPartyLevel]
+ ld b, a
+ ld a, [wBattleMonLevel]
+ cp b
+ jr nc, .run_away
+; Generate a number between 0 and (YourLevel + TheirLevel).
+ add b
+ ld c, a
+ inc c
+.loop_player
+ call BattleRandom
+ cp c
+ jr nc, .loop_player
+; If that number is greater than 4 times your level, run away.
+ srl b
+ srl b
+ cp b
+ jr nc, .run_away
+
+.failed
+ call AnimateFailedMove
+ jp PrintButItFailed
+
+.enemy_turn
+ ld a, [wBattleMode]
+ dec a
+ jr nz, .failed
+ ld a, [wBattleMonLevel]
+ ld b, a
+ ld a, [wCurPartyLevel]
+ cp b
+ jr nc, .run_away
+ add b
+ ld c, a
+ inc c
+.loop_enemy
+ call BattleRandom
+ cp c
+ jr nc, .loop_enemy
+ srl b
+ srl b
+ cp b
+ ; This should be jr c, .failed
+ ; As written, it makes enemy use of Teleport always succeed if able
+ jr nc, .run_away
+.run_away
+ call UpdateBattleMonInParty
+ xor a
+ ld [wNumHits], a
+ inc a
+ ld [wForcedSwitch], a
+ ; set battle draw
+ inc a
+ ld [wBattleResult], a
+ ld a, 1
+ ld [wKickCounter], a
+ call BattleCommand_LowerSub
+ call LoadMoveAnim
+ ld c, 20
+ call DelayFrames
+ ld a, DRAW
+ ld [wBattleResult], a
+
+ ld hl, FledFromBattleText
+ jp StdBattleTextbox
diff --git a/engine/battle/move_effects/thief.asm b/engine/battle/move_effects/thief.asm
new file mode 100644
index 00000000..e588c5ff
--- /dev/null
+++ b/engine/battle/move_effects/thief.asm
@@ -0,0 +1,112 @@
+BattleCommand_Thief:
+; thief
+
+ ldh a, [hBattleTurn]
+ and a
+ jr nz, .enemy
+
+; The player needs to be able to steal an item.
+
+ call .playeritem
+ ld a, [hl]
+ and a
+ ret nz
+
+; The enemy needs to have an item to steal.
+
+ call .enemyitem
+ ld a, [hl]
+ and a
+ ret z
+
+; Can't steal mail.
+
+ ld [wNamedObjectIndexBuffer], a
+ ld d, a
+ farcall ItemIsMail
+ ret c
+
+ ld a, [wEffectFailed]
+ and a
+ ret nz
+
+ ld a, [wLinkMode]
+ and a
+ jr z, .stealenemyitem
+
+ ld a, [wBattleMode]
+ dec a
+ ret z
+
+.stealenemyitem
+ call .enemyitem
+ xor a
+ ld [hl], a
+ ld [de], a
+
+ call .playeritem
+ ld a, [wNamedObjectIndexBuffer]
+ ld [hl], a
+ ld [de], a
+ jr .stole
+
+.enemy
+
+; The enemy can't already have an item.
+
+ call .enemyitem
+ ld a, [hl]
+ and a
+ ret nz
+
+; The player must have an item to steal.
+
+ call .playeritem
+ ld a, [hl]
+ and a
+ ret z
+
+; Can't steal mail!
+
+ ld [wNamedObjectIndexBuffer], a
+ ld d, a
+ farcall ItemIsMail
+ ret c
+
+ ld a, [wEffectFailed]
+ and a
+ ret nz
+
+; If the enemy steals your item,
+; it's gone for good if you don't get it back.
+
+ call .playeritem
+ xor a
+ ld [hl], a
+ ld [de], a
+
+ call .enemyitem
+ ld a, [wNamedObjectIndexBuffer]
+ ld [hl], a
+ ld [de], a
+
+.stole
+ call GetItemName
+ ld hl, StoleText
+ jp StdBattleTextbox
+
+.playeritem
+ ld a, 1
+ call BattlePartyAttr
+ ld d, h
+ ld e, l
+ ld hl, wBattleMonItem
+ ret
+
+.enemyitem
+ ld a, 1
+ call OTPartyAttr
+ ld d, h
+ ld e, l
+ ld hl, wEnemyMonItem
+ ret
diff --git a/engine/battle/move_effects/thunder.asm b/engine/battle/move_effects/thunder.asm
new file mode 100644
index 00000000..b2a64378
--- /dev/null
+++ b/engine/battle/move_effects/thunder.asm
@@ -0,0 +1,18 @@
+BattleCommand_ThunderAccuracy:
+; thunderaccuracy
+
+ ld a, BATTLE_VARS_MOVE_TYPE
+ call GetBattleVarAddr
+ inc hl
+ ld a, [wBattleWeather]
+ cp WEATHER_RAIN
+ jr z, .rain
+ cp WEATHER_SUN
+ ret nz
+ ld [hl], 50 percent + 1
+ ret
+
+.rain
+ ; Redundant with CheckHit guranteeing hit
+ ld [hl], 100 percent
+ ret
diff --git a/engine/battle/move_effects/transform.asm b/engine/battle/move_effects/transform.asm
new file mode 100644
index 00000000..0247d8bb
--- /dev/null
+++ b/engine/battle/move_effects/transform.asm
@@ -0,0 +1,155 @@
+BattleCommand_Transform:
+; transform
+
+ call ClearLastMove
+ ld a, BATTLE_VARS_SUBSTATUS5_OPP
+ call GetBattleVarAddr
+ bit SUBSTATUS_TRANSFORMED, [hl]
+ jp nz, BattleEffect_ButItFailed
+ call CheckHiddenOpponent
+ jp nz, BattleEffect_ButItFailed
+ xor a
+ ld [wNumHits], a
+ ld [wFXAnimID + 1], a
+ ld a, $1
+ ld [wKickCounter], a
+ ld a, BATTLE_VARS_SUBSTATUS4
+ call GetBattleVarAddr
+ bit SUBSTATUS_SUBSTITUTE, [hl]
+ push af
+ jr z, .mimic_substitute
+ call CheckUserIsCharging
+ jr nz, .mimic_substitute
+ ld a, SUBSTITUTE
+ call LoadAnim
+.mimic_substitute
+ ld a, BATTLE_VARS_SUBSTATUS5
+ call GetBattleVarAddr
+ set SUBSTATUS_TRANSFORMED, [hl]
+ call ResetActorDisable
+ ld hl, wBattleMonSpecies
+ ld de, wEnemyMonSpecies
+ ldh a, [hBattleTurn]
+ and a
+ jr nz, .got_mon_species
+ ld hl, wEnemyMonSpecies
+ ld de, wBattleMonSpecies
+ xor a
+ ld [wCurMoveNum], a
+.got_mon_species
+ push hl
+ ld a, [hli]
+ ld [de], a
+ inc hl
+ inc de
+ inc de
+ ld bc, NUM_MOVES
+ call CopyBytes
+ ldh a, [hBattleTurn]
+ and a
+ jr z, .mimic_enemy_backup
+ ld a, [de]
+ ld [wEnemyBackupDVs], a
+ inc de
+ ld a, [de]
+ ld [wEnemyBackupDVs + 1], a
+ dec de
+.mimic_enemy_backup
+; copy DVs
+ ld a, [hli]
+ ld [de], a
+ inc de
+ ld a, [hli]
+ ld [de], a
+ inc de
+; move pointer to stats
+ ld bc, wBattleMonStats - wBattleMonPP
+ add hl, bc
+ push hl
+ ld h, d
+ ld l, e
+ add hl, bc
+ ld d, h
+ ld e, l
+ pop hl
+ ld bc, wBattleMonStructEnd - wBattleMonStats
+ call CopyBytes
+; init the power points
+ ld bc, wBattleMonMoves - wBattleMonStructEnd
+ add hl, bc
+ push de
+ ld d, h
+ ld e, l
+ pop hl
+ ld bc, wBattleMonPP - wBattleMonStructEnd
+ add hl, bc
+ ld b, NUM_MOVES
+.pp_loop
+ ld a, [de]
+ inc de
+ and a
+ jr z, .done_move
+ cp SKETCH
+ ld a, 1
+ jr z, .done_move
+ ld a, 5
+.done_move
+ ld [hli], a
+ dec b
+ jr nz, .pp_loop
+ pop hl
+ ld a, [hl]
+ ld [wNamedObjectIndexBuffer], a
+ call GetPokemonName
+ ld hl, wEnemyStats
+ ld de, wPlayerStats
+ ld bc, 2 * 5
+ call BattleSideCopy
+ ld hl, wEnemyStatLevels
+ ld de, wPlayerStatLevels
+ ld bc, 8
+ call BattleSideCopy
+ ; check battle scene
+ ld a, [wOptions]
+ add a
+ jr c, .mimic_anims
+ ldh a, [hBattleTurn]
+ and a
+ ld a, [wPlayerMinimized]
+ jr z, .got_byte
+ ld a, [wEnemyMinimized]
+.got_byte
+ and a
+ jr nz, .mimic_anims
+ call LoadMoveAnim
+ jr .after_anim
+
+.mimic_anims
+ call BattleCommand_MoveDelay
+ call BattleCommand_RaiseSubNoAnim
+.after_anim
+ xor a
+ ld [wNumHits], a
+ ld [wFXAnimID + 1], a
+ ld a, $2
+ ld [wKickCounter], a
+ pop af
+ ld a, SUBSTITUTE
+ call nz, LoadAnim
+ ld hl, TransformedText
+ jp StdBattleTextbox
+
+BattleSideCopy:
+; Copy bc bytes from hl to de if it's the player's turn.
+; Copy bc bytes from de to hl if it's the enemy's turn.
+ ldh a, [hBattleTurn]
+ and a
+ jr z, .copy
+
+; Swap hl and de
+ push hl
+ ld h, d
+ ld l, e
+ pop de
+.copy
+ jp CopyBytes
diff --git a/engine/battle/move_effects/triple_kick.asm b/engine/battle/move_effects/triple_kick.asm
new file mode 100644
index 00000000..e41044c9
--- /dev/null
+++ b/engine/battle/move_effects/triple_kick.asm
@@ -0,0 +1,34 @@
+BattleCommand_TripleKick:
+; triplekick
+
+ ld a, [wKickCounter]
+ ld b, a
+ inc b
+ ld hl, wCurDamage + 1
+ ld a, [hld]
+ ld e, a
+ ld a, [hli]
+ ld d, a
+.next_kick
+ dec b
+ ret z
+ ld a, [hl]
+ add e
+ ld [hld], a
+ ld a, [hl]
+ adc d
+ ld [hli], a
+
+; No overflow.
+ jr nc, .next_kick
+ ld a, $ff
+ ld [hld], a
+ ld [hl], a
+ ret
+
+BattleCommand_KickCounter:
+; kickcounter
+
+ ld hl, wKickCounter
+ inc [hl]
+ ret
diff --git a/engine/battle/read_trainer_attributes.asm b/engine/battle/read_trainer_attributes.asm
new file mode 100644
index 00000000..3f4d4a98
--- /dev/null
+++ b/engine/battle/read_trainer_attributes.asm
@@ -0,0 +1,66 @@
+GetTrainerClassName:
+ ld hl, wRivalName
+ ld a, c
+ cp RIVAL1
+ jr z, .rival
+
+ ld [wCurSpecies], a
+ ld a, TRAINER_NAME
+ ld [wNamedObjectTypeBuffer], a
+ call GetName
+ ld de, wStringBuffer1
+ ret
+
+.rival
+ ld de, wStringBuffer1
+ push de
+ ld bc, TRAINER_CLASS_NAME_LENGTH
+ call CopyBytes
+ pop de
+ ret
+
+GetOTName:
+ ld hl, wOTPlayerName
+ ld a, [wLinkMode]
+ and a
+ jr nz, .ok
+
+ ld hl, wRivalName
+ ld a, c
+ cp RIVAL1
+ jr z, .ok
+
+ ld [wCurSpecies], a
+ ld a, TRAINER_NAME
+ ld [wNamedObjectTypeBuffer], a
+ call GetName
+ ld hl, wStringBuffer1
+
+.ok
+ ld bc, TRAINER_CLASS_NAME_LENGTH
+ ld de, wOTClassName
+ push de
+ call CopyBytes
+ pop de
+ ret
+
+GetTrainerAttributes:
+ ld a, [wTrainerClass]
+ ld c, a
+ call GetOTName
+ ld a, [wTrainerClass]
+ dec a
+ ld hl, TrainerClassAttributes + TRNATTR_ITEM1
+ ld bc, NUM_TRAINER_ATTRIBUTES
+ call AddNTimes
+ ld de, wEnemyTrainerItem1
+ ld a, [hli]
+ ld [de], a
+ inc de
+ ld a, [hli]
+ ld [de], a
+ ld a, [hl]
+ ld [wEnemyTrainerBaseReward], a
+ ret
+
+INCLUDE "data/trainers/attributes.asm"
diff --git a/engine/battle/read_trainer_party.asm b/engine/battle/read_trainer_party.asm
new file mode 100644
index 00000000..18e23f13
--- /dev/null
+++ b/engine/battle/read_trainer_party.asm
@@ -0,0 +1,374 @@
+ReadTrainerParty:
+ ld a, [wLinkMode]
+ and a
+ ret nz
+
+ ld hl, wOTPartyCount
+ xor a
+ ld [hli], a
+ dec a
+ ld [hl], a
+
+ ld hl, wOTPartyMons
+ ld bc, wOTPartyMonsEnd - wOTPartyMons
+ xor a
+ call ByteFill
+
+ ld a, [wOtherTrainerClass]
+ cp CAL
+ jr nz, .not_cal2
+ ld a, [wOtherTrainerID]
+ cp CAL2
+ jr z, .cal2
+ ld a, [wOtherTrainerClass]
+.not_cal2
+
+ dec a
+ ld c, a
+ ld b, 0
+ ld hl, TrainerGroups
+ add hl, bc
+ add hl, bc
+ ld a, [hli]
+ ld h, [hl]
+ ld l, a
+
+ ld a, [wOtherTrainerID]
+ ld b, a
+.skip_trainer
+ dec b
+ jr z, .got_trainer
+.loop
+ ld a, [hli]
+ cp -1
+ jr nz, .loop
+ jr .skip_trainer
+.got_trainer
+
+.skip_name
+ ld a, [hli]
+ cp "@"
+ jr nz, .skip_name
+
+ ld a, [hli]
+ ld c, a
+ ld b, 0
+ ld d, h
+ ld e, l
+ ld hl, TrainerTypes
+ add hl, bc
+ add hl, bc
+ ld a, [hli]
+ ld h, [hl]
+ ld l, a
+ ld bc, .done
+ push bc
+ jp hl
+
+.done
+ jp ComputeTrainerReward
+
+.cal2
+ ld a, BANK(sMysteryGiftTrainer)
+ call OpenSRAM
+ ld de, sMysteryGiftTrainer
+ call TrainerType2
+ call CloseSRAM
+ jr .done
+
+TrainerTypes:
+; entries correspond to TRAINERTYPE_* constants
+ dw TrainerType1 ; level, species
+ dw TrainerType2 ; level, species, moves
+ dw TrainerType3 ; level, species, item
+ dw TrainerType4 ; level, species, item, moves
+
+TrainerType1:
+; normal (level, species)
+ ld h, d
+ ld l, e
+.loop
+ ld a, [hli]
+ cp $ff
+ ret z
+
+ ld [wCurPartyLevel], a
+ ld a, [hli]
+ ld [wCurPartySpecies], a
+ ld a, OTPARTYMON
+ ld [wMonType], a
+ push hl
+ predef TryAddMonToParty
+ pop hl
+ jr .loop
+
+TrainerType2:
+; moves
+ ld h, d
+ ld l, e
+.loop
+ ld a, [hli]
+ cp $ff
+ ret z
+
+ ld [wCurPartyLevel], a
+ ld a, [hli]
+ ld [wCurPartySpecies], a
+ ld a, OTPARTYMON
+ ld [wMonType], a
+
+ push hl
+ predef TryAddMonToParty
+ ld a, [wOTPartyCount]
+ dec a
+ ld hl, wOTPartyMon1Moves
+ ld bc, PARTYMON_STRUCT_LENGTH
+ call AddNTimes
+ ld d, h
+ ld e, l
+ pop hl
+
+ ld b, NUM_MOVES
+.copy_moves
+ ld a, [hli]
+ ld [de], a
+ inc de
+ dec b
+ jr nz, .copy_moves
+
+ push hl
+
+ ld a, [wOTPartyCount]
+ dec a
+ ld hl, wOTPartyMon1Species
+ ld bc, PARTYMON_STRUCT_LENGTH
+ call AddNTimes
+ ld d, h
+ ld e, l
+ ld hl, MON_PP
+ add hl, de
+ push hl
+ ld hl, MON_MOVES
+ add hl, de
+ pop de
+
+ ld b, NUM_MOVES
+.copy_pp
+ ld a, [hli]
+ and a
+ jr z, .copied_pp
+
+ push hl
+ push bc
+ dec a
+ ld hl, Moves + MOVE_PP
+ ld bc, MOVE_LENGTH
+ call AddNTimes
+ ld a, BANK(Moves)
+ call GetFarByte
+ pop bc
+ pop hl
+
+ ld [de], a
+ inc de
+ dec b
+ jr nz, .copy_pp
+.copied_pp
+
+ pop hl
+ jr .loop
+
+TrainerType3:
+; item
+ ld h, d
+ ld l, e
+.loop
+ ld a, [hli]
+ cp $ff
+ ret z
+
+ ld [wCurPartyLevel], a
+ ld a, [hli]
+ ld [wCurPartySpecies], a
+ ld a, OTPARTYMON
+ ld [wMonType], a
+ push hl
+ predef TryAddMonToParty
+ ld a, [wOTPartyCount]
+ dec a
+ ld hl, wOTPartyMon1Item
+ ld bc, PARTYMON_STRUCT_LENGTH
+ call AddNTimes
+ ld d, h
+ ld e, l
+ pop hl
+ ld a, [hli]
+ ld [de], a
+ jr .loop
+
+TrainerType4:
+; item + moves
+ ld h, d
+ ld l, e
+.loop
+ ld a, [hli]
+ cp $ff
+ ret z
+
+ ld [wCurPartyLevel], a
+ ld a, [hli]
+ ld [wCurPartySpecies], a
+
+ ld a, OTPARTYMON
+ ld [wMonType], a
+
+ push hl
+ predef TryAddMonToParty
+ ld a, [wOTPartyCount]
+ dec a
+ ld hl, wOTPartyMon1Item
+ ld bc, PARTYMON_STRUCT_LENGTH
+ call AddNTimes
+ ld d, h
+ ld e, l
+ pop hl
+
+ ld a, [hli]
+ ld [de], a
+
+ push hl
+ ld a, [wOTPartyCount]
+ dec a
+ ld hl, wOTPartyMon1Moves
+ ld bc, PARTYMON_STRUCT_LENGTH
+ call AddNTimes
+ ld d, h
+ ld e, l
+ pop hl
+
+ ld b, NUM_MOVES
+.copy_moves
+ ld a, [hli]
+ ld [de], a
+ inc de
+ dec b
+ jr nz, .copy_moves
+
+ push hl
+
+ ld a, [wOTPartyCount]
+ dec a
+ ld hl, wOTPartyMon1
+ ld bc, PARTYMON_STRUCT_LENGTH
+ call AddNTimes
+ ld d, h
+ ld e, l
+ ld hl, MON_PP
+ add hl, de
+
+ push hl
+ ld hl, MON_MOVES
+ add hl, de
+ pop de
+
+ ld b, NUM_MOVES
+.copy_pp
+ ld a, [hli]
+ and a
+ jr z, .copied_pp
+
+ push hl
+ push bc
+ dec a
+ ld hl, Moves + MOVE_PP
+ ld bc, MOVE_LENGTH
+ call AddNTimes
+ ld a, BANK(Moves)
+ call GetFarByte
+ pop bc
+ pop hl
+
+ ld [de], a
+ inc de
+ dec b
+ jr nz, .copy_pp
+.copied_pp
+
+ pop hl
+ jr .loop
+
+ComputeTrainerReward:
+ ld hl, hProduct
+ xor a
+ ld [hli], a
+ ld [hli], a ; hMultiplicand + 0
+ ld [hli], a ; hMultiplicand + 1
+ ld a, [wEnemyTrainerBaseReward]
+ ld [hli], a ; hMultiplicand + 2
+ ld a, [wCurPartyLevel]
+ ld [hl], a ; hMultiplier
+ call Multiply
+ ld hl, wBattleReward
+ xor a
+ ld [hli], a
+ ldh a, [hProduct + 2]
+ ld [hli], a
+ ldh a, [hProduct + 3]
+ ld [hl], a
+ ret
+
+Battle_GetTrainerName::
+ ld a, [wOtherTrainerID]
+ ld b, a
+ ld a, [wOtherTrainerClass]
+ ld c, a
+
+GetTrainerName::
+ ld a, c
+ cp CAL
+ jr nz, .not_cal2
+
+ ld a, BANK(sMysteryGiftTrainerHouseFlag)
+ call OpenSRAM
+ ld a, [sMysteryGiftTrainerHouseFlag]
+ and a
+ call CloseSRAM
+ jr z, .not_cal2
+
+ ld a, BANK(sMysteryGiftPartnerName)
+ call OpenSRAM
+ ld hl, sMysteryGiftPartnerName
+ call CopyTrainerName
+ jp CloseSRAM
+
+.not_cal2
+ dec c
+ push bc
+ ld b, 0
+ ld hl, TrainerGroups
+ add hl, bc
+ add hl, bc
+ ld a, [hli]
+ ld h, [hl]
+ ld l, a
+ pop bc
+
+.loop
+ dec b
+ jr z, CopyTrainerName
+
+.skip
+ ld a, [hli]
+ cp $ff
+ jr nz, .skip
+ jr .loop
+
+CopyTrainerName:
+ ld de, wStringBuffer1
+ push de
+ ld bc, NAME_LENGTH
+ call CopyBytes
+ pop de
+ ret
+
+INCLUDE "data/trainers/parties.asm"
diff --git a/engine/battle/returntobattle_useball.asm b/engine/battle/returntobattle_useball.asm
new file mode 100644
index 00000000..fd138ae6
--- /dev/null
+++ b/engine/battle/returntobattle_useball.asm
@@ -0,0 +1,19 @@
+_ReturnToBattle_UseBall:
+ call ClearBGPalettes
+ call ClearTilemap
+ ld a, [wBattleType]
+ cp BATTLETYPE_TUTORIAL
+ jr z, .gettutorialbackpic
+ farcall GetBattleMonBackpic
+ jr .continue
+
+.gettutorialbackpic
+ farcall GetTrainerBackpic
+.continue
+ farcall GetEnemyMonFrontpic
+ farcall _LoadBattleFontsHPBar
+ call GetMemSGBLayout
+ call CloseWindow
+ call LoadStandardMenuHeader
+ call WaitBGMap
+ jp SetPalettes
diff --git a/engine/battle/sliding_intro.asm b/engine/battle/sliding_intro.asm
new file mode 100644
index 00000000..f872a8de
--- /dev/null
+++ b/engine/battle/sliding_intro.asm
@@ -0,0 +1,57 @@
+BattleIntroSlidingPics:
+ ld b, $70
+ ld c, $90
+ ld a, c
+ ldh [hSCX], a
+ call DelayFrame
+ ld a, %11100100
+ call DmgToCgbBGPals
+ lb de, %11100100, %11100100
+ call DmgToCgbObjPals
+
+.loop1
+ push bc
+ ld h, b
+ ld l, $40
+ call .subfunction2
+ ld h, $00
+ ld l, $60
+ call .subfunction2
+ call .subfunction1
+ pop bc
+ ld a, c
+ ldh [hSCX], a
+ inc b
+ inc b
+ dec c
+ dec c
+ jr nz, .loop1
+ ret
+
+.subfunction1
+ push bc
+ ld hl, wVirtualOAMSprite00XCoord
+ ld c, $12 ; 18
+ ld de, SPRITEOAMSTRUCT_LENGTH
+.loop2
+ dec [hl]
+ dec [hl]
+ add hl, de
+ dec c
+ jr nz, .loop2
+ pop bc
+ ret
+
+.subfunction2
+.loop3
+ ldh a, [rLY]
+ cp l
+ jr nz, .loop3
+ ld a, h
+ ldh [rSCX], a
+
+.loop4
+ ldh a, [rLY]
+ cp h
+ jr z, .loop4
+ ret
diff --git a/engine/battle/trainer_huds.asm b/engine/battle/trainer_huds.asm
new file mode 100644
index 00000000..7fd57571
--- /dev/null
+++ b/engine/battle/trainer_huds.asm
@@ -0,0 +1,257 @@
+BattleStart_TrainerHuds:
+ ld a, $e4
+ ldh [rOBP0], a
+ call LoadBallIconGFX
+ call ShowPlayerMonsRemaining
+ ld a, [wBattleMode]
+ dec a
+ ret z
+ jp ShowOTTrainerMonsRemaining
+
+EnemySwitch_TrainerHud:
+ ld a, $e4
+ ldh [rOBP0], a
+ call LoadBallIconGFX
+ jp ShowOTTrainerMonsRemaining
+
+ShowPlayerMonsRemaining:
+ call DrawPlayerPartyIconHUDBorder
+ ld hl, wPartyMon1HP
+ ld de, wPartyCount
+ call StageBallTilesData
+ ; ldpixel wPlaceBallsX, 12, 12
+ ld a, 12 * 8
+ ld hl, wPlaceBallsX
+ ld [hli], a
+ ld [hl], a
+ ld a, 8
+ ld [wPlaceBallsDirection], a
+ ld hl, wVirtualOAMSprite00
+ jp LoadTrainerHudOAM
+
+ShowOTTrainerMonsRemaining:
+ call DrawEnemyHUDBorder
+ ld hl, wOTPartyMon1HP
+ ld de, wOTPartyCount
+ call StageBallTilesData
+ ; ldpixel wPlaceBallsX, 9, 4
+ ld hl, wPlaceBallsX
+ ld a, 9 * 8
+ ld [hli], a
+ ld [hl], 4 * 8
+ ld a, -8
+ ld [wPlaceBallsDirection], a
+ ld hl, wVirtualOAMSprite00 + PARTY_LENGTH * SPRITEOAMSTRUCT_LENGTH
+ jp LoadTrainerHudOAM
+
+StageBallTilesData:
+ ld a, [de]
+ push af
+ ld de, wBuffer1
+ ld c, PARTY_LENGTH
+ ld a, $34 ; empty slot
+.loop1
+ ld [de], a
+ inc de
+ dec c
+ jr nz, .loop1
+ pop af
+ ld de, wBuffer1
+.loop2
+ push af
+ call .GetHUDTile
+ inc de
+ pop af
+ dec a
+ jr nz, .loop2
+ ret
+
+.GetHUDTile:
+ ld a, [hli]
+ and a
+ jr nz, .got_hp
+ ld a, [hl]
+ and a
+ ld b, $33 ; fainted
+ jr z, .fainted
+
+.got_hp
+ dec hl
+ dec hl
+ dec hl
+ ld a, [hl]
+ and a
+ ld b, $32 ; statused
+ jr nz, .load
+ dec b ; normal
+ jr .load
+
+.fainted
+ dec hl
+ dec hl
+ dec hl
+
+.load
+ ld a, b
+ ld [de], a
+ ld bc, PARTYMON_STRUCT_LENGTH + MON_HP - MON_STATUS
+ add hl, bc
+ ret
+
+DrawPlayerHUDBorder:
+ ld hl, .tiles
+ ld de, wTrainerHUDTiles
+ ld bc, .tiles_end - .tiles
+ call CopyBytes
+ hlcoord 18, 10
+ ld de, -1 ; start on right
+ jr PlaceHUDBorderTiles
+
+.tiles
+ db $73 ; right side
+ db $77 ; bottom right
+ db $6f ; bottom left
+ db $76 ; bottom side
+.tiles_end
+
+DrawPlayerPartyIconHUDBorder:
+ ld hl, .tiles
+ ld de, wTrainerHUDTiles
+ ld bc, .tiles_end - .tiles
+ call CopyBytes
+ hlcoord 18, 10
+ ld de, -1 ; start on right
+ jr PlaceHUDBorderTiles
+
+.tiles
+ db $73 ; right side
+ db $5c ; bottom right
+ db $6f ; bottom left
+ db $76 ; bottom side
+.tiles_end
+
+DrawEnemyHUDBorder:
+ ld hl, .tiles
+ ld de, wTrainerHUDTiles
+ ld bc, .tiles_end - .tiles
+ call CopyBytes
+ hlcoord 1, 2
+ ld de, 1 ; start on left
+ call PlaceHUDBorderTiles
+ ld a, [wBattleMode]
+ dec a
+ ret nz
+ ld a, [wTempEnemyMonSpecies]
+ dec a
+ call CheckCaughtMon
+ ret z
+ hlcoord 1, 1
+ ld [hl], $5d
+ ret
+
+.tiles
+ db $6d ; left side
+ db $74 ; bottom left
+ db $78 ; bottom right
+ db $76 ; bottom side
+.tiles_end
+
+PlaceHUDBorderTiles:
+ ld a, [wTrainerHUDTiles + 0]
+ ld [hl], a
+ ld bc, SCREEN_WIDTH
+ add hl, bc
+ ld a, [wTrainerHUDTiles + 1]
+ ld [hl], a
+ ld b, 8
+.loop
+ add hl, de
+ ld a, [wTrainerHUDTiles + 3]
+ ld [hl], a
+ dec b
+ jr nz, .loop
+ add hl, de
+ ld a, [wTrainerHUDTiles + 2]
+ ld [hl], a
+ ret
+
+LinkBattle_TrainerHuds:
+ call LoadBallIconGFX
+ ld hl, wPartyMon1HP
+ ld de, wPartyCount
+ call StageBallTilesData
+ ld hl, wPlaceBallsX
+ ld a, 10 * 8
+ ld [hli], a
+ ld [hl], 8 * 8
+ ld a, 8
+ ld [wPlaceBallsDirection], a
+ ld hl, wVirtualOAMSprite00
+ call LoadTrainerHudOAM
+
+ ld hl, wOTPartyMon1HP
+ ld de, wOTPartyCount
+ call StageBallTilesData
+ ld hl, wPlaceBallsX
+ ld a, 10 * 8
+ ld [hli], a
+ ld [hl], 13 * 8
+ ld hl, wVirtualOAMSprite00 + PARTY_LENGTH * SPRITEOAMSTRUCT_LENGTH
+ jp LoadTrainerHudOAM
+
+LoadTrainerHudOAM:
+ ld de, wBuffer1
+ ld c, PARTY_LENGTH
+.loop
+ ld a, [wPlaceBallsY]
+ ld [hli], a ; y
+ ld a, [wPlaceBallsX]
+ ld [hli], a ; x
+ ld a, [de]
+ ld [hli], a ; tile id
+ ld a, PAL_BATTLE_OB_YELLOW
+ ld [hli], a ; attributes
+ ld a, [wPlaceBallsX]
+ ld b, a
+ ld a, [wPlaceBallsDirection]
+ add b
+ ld [wPlaceBallsX], a
+ inc de
+ dec c
+ jr nz, .loop
+ ret
+
+LoadBallIconGFX:
+ ld de, .gfx
+ ld hl, vTiles0 tile $31
+ lb bc, BANK(LoadBallIconGFX), 4
+ jp Request2bpp
+
+.gfx
+INCBIN "gfx/battle/balls.2bpp"
+
+_ShowLinkBattleParticipants:
+ call ClearBGPalettes
+ call LoadFontsExtra
+ hlcoord 3, 3
+ ld b, 9
+ ld c, 12
+ call Textbox
+ hlcoord 4, 5
+ ld de, wPlayerName
+ call PlaceString
+ hlcoord 4, 10
+ ld de, wOTPlayerName
+ call PlaceString
+ hlcoord 9, 8
+ ld a, "<BOLD_V>"
+ ld [hli], a
+ ld [hl], "<BOLD_S>"
+ farcall LinkBattle_TrainerHuds ; no need to farcall
+ ld b, SCGB_DIPLOMA
+ call GetSGBLayout
+ call SetPalettes
+ ld a, $e4
+ ldh [rOBP0], a
+ ld c, 150
+ jp DelayFrames
diff --git a/engine/battle/used_move_text.asm b/engine/battle/used_move_text.asm
new file mode 100644
index 00000000..5b148ab5
--- /dev/null
+++ b/engine/battle/used_move_text.asm
@@ -0,0 +1,235 @@
+BattleCommand_UsedMoveText:
+; battle command 03
+ ld hl, UsedMoveText
+ call PrintText
+ jp WaitBGMap
+
+UsedMoveText:
+; this is a stream of text and asm from 105db9 to 105ef6
+ text_far _ActorNameText
+ text_asm
+ ldh a, [hBattleTurn]
+ and a
+ jr nz, .start
+
+ ld a, [wPlayerMoveStruct + MOVE_ANIM]
+ call UpdateUsedMoves
+
+.start
+ ld a, BATTLE_VARS_LAST_MOVE
+ call GetBattleVarAddr
+ ld d, h
+ ld e, l
+
+ ld a, BATTLE_VARS_LAST_COUNTER_MOVE
+ call GetBattleVarAddr
+
+ ld a, BATTLE_VARS_MOVE_ANIM
+ call GetBattleVar
+ ld [wMoveGrammar], a
+
+ call CheckUserIsCharging
+ jr nz, .grammar
+
+ ; update last move
+ ld a, [wMoveGrammar]
+ ld [hl], a
+ ld [de], a
+
+.grammar
+ call GetMoveGrammar ; convert move id to grammar index
+
+; everything except 'CheckObedience' made redundant in localization
+
+ ; check obedience
+ ld a, [wAlreadyDisobeyed]
+ and a
+ ld hl, UsedMove2Text
+ ret nz
+
+ ; check move grammar
+ ld a, [wMoveGrammar]
+ cp $3
+ ld hl, UsedMove2Text
+ ret c
+ ld hl, UsedMove1Text
+ ret
+
+UsedMove1Text:
+ text_far _UsedMove1Text
+ text_asm
+ jr UsedMoveText_CheckObedience
+
+UsedMove2Text:
+ text_far _UsedMove2Text
+ text_asm
+UsedMoveText_CheckObedience:
+; check obedience
+ ld a, [wAlreadyDisobeyed]
+ and a
+ jr z, .GetMoveNameText
+; print "instead,"
+ ld hl, .UsedInsteadText
+ ret
+
+.UsedInsteadText:
+ text_far _UsedInsteadText
+ text_asm
+.GetMoveNameText:
+ ld hl, MoveNameText
+ ret
+
+MoveNameText:
+ text_far _MoveNameText
+ text_asm
+; get start address
+ ld hl, .endusedmovetexts
+
+; get move id
+ ld a, [wMoveGrammar]
+
+; 2-byte pointer
+ add a
+
+; seek
+ push bc
+ ld b, 0
+ ld c, a
+ add hl, bc
+ pop bc
+
+; get pointer to usedmovetext ender
+ ld a, [hli]
+ ld h, [hl]
+ ld l, a
+ ret
+
+.endusedmovetexts
+; entries correspond to MoveGrammar sets
+ dw EndUsedMove1Text
+ dw EndUsedMove2Text
+ dw EndUsedMove3Text
+ dw EndUsedMove4Text
+ dw EndUsedMove5Text
+
+EndUsedMove1Text:
+ text_far _EndUsedMove1Text
+ text_end
+
+EndUsedMove2Text:
+ text_far _EndUsedMove2Text
+ text_end
+
+EndUsedMove3Text:
+ text_far _EndUsedMove3Text
+ text_end
+
+EndUsedMove4Text:
+ text_far _EndUsedMove4Text
+ text_end
+
+EndUsedMove5Text:
+ text_far _EndUsedMove5Text
+ text_end
+
+GetMoveGrammar:
+; store move grammar type in wMoveGrammar
+
+ push bc
+; wMoveGrammar contains move id
+ ld a, [wMoveGrammar]
+ ld c, a ; move id
+ ld b, 0 ; grammar index
+
+; read grammar table
+ ld hl, MoveGrammar
+.loop
+ ld a, [hli]
+; end of table?
+ cp -1
+ jr z, .end
+; match?
+ cp c
+ jr z, .end
+; advance grammar type at 0
+ and a
+ jr nz, .loop
+; next grammar type
+ inc b
+ jr .loop
+
+.end
+; wMoveGrammar now contains move grammar
+ ld a, b
+ ld [wMoveGrammar], a
+
+; we're done
+ pop bc
+ ret
+
+INCLUDE "data/moves/grammar.asm"
+
+CheckUserIsCharging:
+ ldh a, [hBattleTurn]
+ and a
+ ld a, [wPlayerCharging] ; player
+ jr z, .end
+ ld a, [wEnemyCharging] ; enemy
+.end
+ and a
+ ret
+
+UpdateUsedMoves:
+; append move a to wPlayerUsedMoves unless it has already been used
+
+ push bc
+; start of list
+ ld hl, wPlayerUsedMoves
+; get move id
+ ld b, a
+; next count
+ ld c, NUM_MOVES
+
+.loop
+; get move from the list
+ ld a, [hli]
+; not used yet?
+ and a
+ jr z, .add
+; already used?
+ cp b
+ jr z, .quit
+; next byte
+ dec c
+ jr nz, .loop
+
+; if the list is full and the move hasn't already been used
+; shift the list back one byte, deleting the first move used
+; this can occur with struggle or a new learned move
+ ld hl, wPlayerUsedMoves + 1
+; 1 = 2
+ ld a, [hld]
+ ld [hli], a
+; 2 = 3
+ inc hl
+ ld a, [hld]
+ ld [hli], a
+; 3 = 4
+ inc hl
+ ld a, [hld]
+ ld [hl], a
+; 4 = new move
+ ld a, b
+ ld [wPlayerUsedMoves + 3], a
+ jr .quit
+
+.add
+; go back to the byte we just inced from
+ dec hl
+; add the new move
+ ld [hl], b
+
+.quit
+; list updated
+ pop bc
+ ret
diff --git a/engine/battle_anims/pokeball_wobble.asm b/engine/battle_anims/pokeball_wobble.asm
new file mode 100644
index 00000000..c430e513
--- /dev/null
+++ b/engine/battle_anims/pokeball_wobble.asm
@@ -0,0 +1,45 @@
+GetPokeBallWobble:
+; Returns whether a Poke Ball will wobble in the catch animation.
+; Whether a Pokemon is caught is determined beforehand.
+
+ ld a, [wBuffer2]
+ inc a
+ ld [wBuffer2], a
+
+; Wobble up to 3 times.
+ cp 3 + 1
+ jr z, .finished
+
+ ld a, [wWildMon]
+ and a
+ ld c, 0 ; next
+ ret nz
+
+ ld hl, WobbleProbabilities
+ ld a, [wBuffer1]
+ ld b, a
+.loop
+ ld a, [hli]
+ cp b
+ jr nc, .checkwobble
+ inc hl
+ jr .loop
+
+.checkwobble
+ ld b, [hl]
+ call Random
+ cp b
+ ld c, 0 ; next
+ ret c
+ ld c, 2 ; escaped
+ ret
+
+.finished
+ ld a, [wWildMon]
+ and a
+ ld c, 1 ; caught
+ ret nz
+ ld c, 2 ; escaped
+ ret
+
+INCLUDE "data/battle/wobble_probabilities.asm"
diff --git a/engine/color.asm b/engine/color.asm
deleted file mode 100755
index 05c13b2b..00000000
--- a/engine/color.asm
+++ /dev/null
@@ -1,1903 +0,0 @@
-PALPACKET_LENGTH EQU $10
-INCLUDE "predef/sgb.asm"
-
-SHINY_ATK_BIT EQU 5
-SHINY_DEF_VAL EQU 10
-SHINY_SPD_VAL EQU 10
-SHINY_SPC_VAL EQU 10
-
-CheckShininess:
- ld l, c
- ld h, b
- ld a, [hl]
- and $20
- jr z, .asm_9070
- ld a, [hli]
- and $f
- cp $a
- jr nz, .asm_9070
- ld a, [hl]
- and $f0
- cp $a0
- jr nz, .asm_9070
- ld a, [hl]
- and $f
- cp $a
- jr nz, .asm_9070
- scf
- ret
-
-.asm_9070
- and a
- ret
-
-Unused_CheckShininess: ; 9072 (2:5072)
- ld a, [hl]
- cp $a0
- jr c, .asm_908c
- ld a, [hli]
- and $f
- cp $a
- jr c, .asm_908c
- ld a, [hl]
- cp $a0
- jr c, .asm_908c
- ld a, [hl]
- and $f
- cp $a
- jr c, .asm_908c
- scf
- ret
-
-.asm_908c
- and a
- ret
-
-Function908e:
- push de
- push bc
- ld hl, PalPacket_a155
- ld de, wcca9
- ld bc, $10
- call CopyBytes
- pop bc
- pop de
- ld a, c
- ld [wccac], a
- ld a, b
- ld [wccad], a
- ld a, e
- ld [wccae], a
- ld a, d
- ld [wccaf], a
- ld hl, wcca9
- call PushSGBPals_
- ld hl, BlkPacket_9ee5
- call PushSGBPals_
- ret
-
-InitPartyMenuPalettes:
- call CheckCGB
- jr nz, .asm_90cc
- ld hl, BlkPacket_9fa5
- ld de, wccaa
- ld bc, $30
- jp CopyBytes
-
-.asm_90cc
- ld hl, PalPacket_a0c5 + 1
- call Function9ab2
- call Function9b9c
- call Function9b1d
- ret
-
-SGB_ApplyPartyMenuHPPals:
- ld hl, wcc9b
- ld a, [wcca9]
- ld e, a
- ld d, $0
- add hl, de
- ld e, l
- ld d, h
- ld a, [de]
- and a
- ld e, $5
- jr z, .asm_90f2
- dec a
- ld e, $a
- jr z, .asm_90f2
- ld e, $f
-.asm_90f2
- push de
- ld hl, wccb3
- ld bc, $6
- ld a, [wcca9]
- call AddNTimes
- pop de
- ld [hl], e
- ret
-
-Function9102:
- call CheckCGB
- ret z
- ld hl, .BGPal
- ld de, wTempBGPals
- ld bc, $8
- call CopyBytes
- ld hl, .OBPal
- ld de, wTempOBPals
- ld bc, $8
- call CopyBytes
- call Function9b28
- ld a, $1
- ldh [hCGBPalUpdate], a
- ret
-
-.BGPal:
- RGB 31, 31, 31
- RGB 18, 23, 31
- RGB 15, 20, 31
- RGB 00, 00, 00
-
-.OBPal:
- RGB 31, 31, 31
- RGB 31, 31, 12
- RGB 08, 16, 28
- RGB 00, 00, 00
-
-Function9136:
- call CheckCGB
- ret nz
- ldh a, [hSGB]
- and a
- ret z
- ld hl, BlkPacket_9ee5
- jp PushSGBPals_
-
-Function9144:
- call CheckCGB
- jr nz, .asm_9153
- ldh a, [hSGB]
- and a
- ret z
- ld hl, PalPacket_a095
- jp PushSGBPals_
-
-.asm_9153
- ld de, wTempOBPals
- ld a, $3b
- call Function9ac7
- jp Function9ad2
-
-Function915e:
- call CheckCGB
- jr nz, .asm_916d
- ldh a, [hSGB]
- and a
- ret z
- ld hl, PalPacket_a0a5
- jp PushSGBPals_
-
-.asm_916d
- ld de, wTempOBPals
- ld a, $3c
- call Function9ac7
- jp Function9ad2
-
-Function9178:
- call CheckCGB
- jr nz, .asm_91a9
- ldh a, [hSGB]
- and a
- ret z
- ld a, c
- push af
- ld hl, PalPacket_a155
- ld de, wcca9
- ld bc, $10
- call CopyBytes
- pop af
- call Function9be4
- ld a, [hli]
- ld [wccac], a
- ld a, [hli]
- ld [wccad], a
- ld a, [hli]
- ld [wccae], a
- ld a, [hl]
- ld [wccaf], a
- ld hl, wcca9
- jp PushSGBPals_
-
-.asm_91a9
- ld de, wTempOBPals
- ld a, c
- call Function9be4
- call Function9adb
- ret
-
-Function91b4:
- ldh a, [hCGB]
- and a
- jr nz, .asm_91bf
- ld hl, wc602
- jp PushSGBPals_
-
-.asm_91bf
- ld a, [wc606]
- ld c, a
- ld a, [wc607]
- ld hl, wAttrmap
- ld de, $14
-.asm_91cc
- and a
- jr z, .asm_91d3
- add hl, de
- dec a
- jr .asm_91cc
-
-.asm_91d3
- ld b, $0
- add hl, bc
- lb bc, 6, 4
- ld a, [wc605]
- and $3
- call Function9af1
- call CopyTilemapAtOnce
- ret
-
-ApplyMonOrTrainerPals: ; 91e5 (2:51e5)
- call CheckCGB
- ret z
- ld a, e
- and a
- jr z, .asm_91f5
- ld a, [wCurPartySpecies]
- call Function9be4
- jr .asm_91fb
-
-.asm_91f5
- ld a, [wTrainerClass]
- call Function9bda
-.asm_91fb
- ld de, wTempBGPals
- call Function9adb
- call Function9b1d
- call Function9b35
- call Function9b28
- ret
-
-ApplyHPBarPals:
- ld a, [wWhichHPBar]
- and a
- jr z, .asm_921a
- cp $1
- jr z, .asm_921f
- cp $2
- jr z, .asm_9236
- ret
-
-.asm_921a
- ld de, $c292
- jr .asm_9222
-
-.asm_921f
- ld de, $c29a
-.asm_9222
- ld l, c
- ld h, $0
- add hl, hl
- add hl, hl
- ld bc, $6d2d
- add hl, bc
- ld bc, $4
- call CopyBytes
- ld a, $1
- ldh [hCGBPalUpdate], a
- ret
-
-.asm_9236
- ld e, c
- inc e
- hlcoord 11, 1, wAttrmap
- ld bc, 2 * SCREEN_WIDTH
- ld a, [wCurPartyMon]
-.asm_9241
- and a
- jr z, .asm_9248
- add hl, bc
- dec a
- jr .asm_9241
-
-.asm_9248
- lb bc, 2, 8
- ld a, e
- call Function9af1
- ret
-
-LoadStatsScreenPals:
- call CheckCGB
- ret z
- ld hl, StatsScreenPals ; $54eb
- ld b, $0
- dec c
- add hl, bc
- add hl, bc
- ld a, [hli]
- ld [wTempBGPals], a
- ld [wTempBGPals + $10], a
- ld a, [hl]
- ld [wTempBGPals + 1], a
- ld [wTempBGPals + $11], a
- call Function9b28
- ld a, $1
- ldh [hCGBPalUpdate], a
- ret
-
-LoadMailPalettes:
- ld l, e
- ld h, $0
- add hl, hl
- add hl, hl
- add hl, hl
- ld de, .MailPals
- add hl, de
- call CheckCGB
- jr nz, .asm_92ae
- push hl
- ld hl, PalPacket_a155
- ld de, wcca9
- ld bc, $10
- call CopyBytes
- pop hl
- inc hl
- inc hl
- ld a, [hli]
- ld [wccac], a
- ld a, [hli]
- ld [wccad], a
- ld a, [hli]
- ld [wccae], a
- ld a, [hli]
- ld [wccaf], a
- ld hl, wcca9
- call PushSGBPals_
- ld hl, BlkPacket_9ee5
- call PushSGBPals_
- ret
-
-.asm_92ae
- ld de, wTempBGPals
- ld bc, $8
- call CopyBytes
- call Function9b28
- call Function9b1d
- call Function9b35
- ret
-
-.MailPals:
- RGB 20, 31, 11
- RGB 31, 19, 00
- RGB 31, 10, 09
- RGB 00, 00, 00
-
- RGB 15, 20, 31
- RGB 30, 26, 00
- RGB 31, 12, 00
- RGB 00, 00, 00
-
- RGB 24, 17, 31
- RGB 30, 26, 00
- RGB 08, 11, 31
- RGB 00, 00, 00
-
- RGB 31, 25, 17
- RGB 31, 18, 04
- RGB 28, 12, 05
- RGB 00, 00, 00
-
- RGB 19, 26, 31
- RGB 31, 05, 08
- RGB 31, 09, 31
- RGB 00, 00, 00
-
- RGB 31, 19, 28
- RGB 31, 21, 00
- RGB 12, 22, 00
- RGB 00, 00, 00
-
- RGB 19, 17, 23
- RGB 30, 26, 00
- RGB 31, 12, 00
- RGB 00, 00, 00
-
- RGB 07, 26, 31
- RGB 26, 26, 27
- RGB 31, 11, 11
- RGB 00, 00, 00
-
- RGB 21, 31, 21
- RGB 30, 26, 00
- RGB 31, 12, 00
- RGB 00, 00, 00
-
- RGB 07, 26, 31
- RGB 31, 31, 00
- RGB 00, 21, 00
- RGB 00, 00, 00
-
-INCLUDE "predef/cgb.asm"
-
-Function9a94: ; 9a94 (2:5a94)
- ld hl, Palettes_9aaa
- ld de, wTempBGPals
- ld bc, $8
- call CopyBytes
- call Function9b28
- call Function9b1d
- call Function9b35
- ret
-
-Palettes_9aaa:
- RGB 31, 31, 31
- RGB 9, 31, 31
- RGB 10, 12, 31
- RGB 0, 3, 19
-
-Function9ab2: ; 9ab2 (2:5ab2)
- ld de, wTempBGPals
- ld c, $4
-Function9ab7: ; 9ab7 (2:5ab7)
- push bc
- ld a, [hli]
- push hl
- call Function9ac7
- call Function9ad2
- pop hl
- inc hl
- pop bc
- dec c
- jr nz, Function9ab7
- ret
-
-Function9ac7: ; 9ac7 (2:5ac7)
- ld l, a
- ld h, $0
- add hl, hl
- add hl, hl
- add hl, hl
- ld bc, Palettes_a265
- add hl, bc
- ret
-
-Function9ad2: ; 9ad2 (2:5ad2)
- ld c, $8
-.asm_9ad4
- ld a, [hli]
- ld [de], a
- inc de
- dec c
- jr nz, .asm_9ad4
- ret
-
-Function9adb: ; 9adb (2:5adb)
- ld a, $ff
- ld [de], a
- inc de
- ld a, $7f
- ld [de], a
- inc de
- ld c, $4
-.asm_9ae5
- ld a, [hli]
- ld [de], a
- inc de
- dec c
- jr nz, .asm_9ae5
- xor a
- ld [de], a
- inc de
- ld [de], a
- inc de
- ret
-
-Function9af1: ; 9af1 (2:5af1)
- push bc
- push hl
-.asm_9af3
- ld [hli], a
- dec c
- jr nz, .asm_9af3
- pop hl
- ld bc, $14
- add hl, bc
- pop bc
- dec b
- jr nz, Function9af1
- ret
-
-Function9b01: ; 9b01 (2:5b01)
- push af
- push bc
- push de
- push hl
- ld hl, wTempBGPals
- ld c, $8
-.asm_9b0a
- ld a, $ff
- ld [hli], a
- ld [hli], a
- ld [hli], a
- ld [hli], a
- xor a
- ld [hli], a
- ld [hli], a
- ld [hli], a
- ld [hli], a
- dec c
- jr nz, .asm_9b0a
- pop hl
- pop de
- pop bc
- pop af
- ret
-
-Function9b1d: ; 9b1d (2:5b1d)
- hlcoord 0, 0, wAttrmap
- ld bc, SCREEN_HEIGHT * SCREEN_WIDTH
- xor a
- call ByteFill
- ret
-
-Function9b28: ; 9b28 (2:5b28)
- ld hl, wTempBGPals
- ld de, wBGPals
- ld bc, $80
- call CopyBytes
- ret
-
-Function9b35: ; 9b35 (2:5b35)
- ldh a, [rLCDC]
- bit 7, a
- jr z, .asm_9b52
- ldh a, [hBGMapMode]
- push af
- ld a, $2
- ldh [hBGMapMode], a
- call DelayFrame
- call DelayFrame
- call DelayFrame
- call DelayFrame
- pop af
- ldh [hBGMapMode], a
- ret
-
-.asm_9b52
- hlcoord 0, 0, wAttrmap
- ld de, $9800
- ld b, $12
- ld a, $1
- ldh [rVBK], a
-.asm_9b5e
- ld c, $14
-.asm_9b60
- ld a, [hli]
- ld [de], a
- inc de
- dec c
- jr nz, .asm_9b60
- ld a, $c
- add e
- jr nc, .asm_9b6c
- inc d
-.asm_9b6c
- ld e, a
- dec b
- jr nz, .asm_9b5e
- ld a, $0
- ldh [rVBK], a
- ret
-
-Function9b75: ; 9b75 (2:5b75)
- ld hl, wcc9b
- ld a, [wcca9]
- ld e, a
- ld d, $0
- add hl, de
- ld e, l
- ld d, h
- ld a, [de]
- inc a
- ld e, a
- hlcoord 11, 2, wAttrmap
- ld bc, $28
- ld a, [wcca9]
-.asm_9b8d
- and a
- jr z, .asm_9b94
- add hl, bc
- dec a
- jr .asm_9b8d
-
-.asm_9b94
- lb bc, 2, 8
- ld a, e
- call Function9af1
- ret
-
-Function9b9c: ; 9b9c (2:5b9c)
- ld hl, Palettes_bac6
- ld de, wTempOBPal0
- ld bc, $10
- call CopyBytes
- ret
-
-Function9ba9: ; 9ba9 (2:5ba9)
- push de
- farcall Function3d8f5
- ld c, l
- ld b, h
- ld a, [wd0ee]
- call Function9bcb
- pop de
- ret
-
-Function9bba: ; 9bba (2:5bba)
- push de
- farcall Function3d907
- ld c, l
- ld b, h
- ld a, [wTempEnemyMonSpecies]
- call Function9bd3
- pop de
- ret
-
-Function9bcb: ; 9bcb (2:5bcb)
- and a
- jp nz, Function9c66
- ld hl, TrainerPalettes
- ret
-
-Function9bd3: ; 9bd3 (2:5bd3)
- and a
- jp nz, Function9c66
- ld a, [wTrainerClass]
-Function9bda: ; 9bda (2:5bda)
- ld l, a
- ld h, $0
- add hl, hl
- add hl, hl
- ld bc, TrainerPalettes
- add hl, bc
- ret
-
-Function9be4: ; 9be4 (2:5be4)
- call Function9c5b
- ret
-
-Function9be8:
- ret
-
-Function9be9:
- call CheckCGB
- ret z
- ld hl, Palettes_9c09
- ld a, $90
- ldh [rOBPI], a
- ld c, $30
-.asm_9bf6
- ld a, [hli]
- ldh [rOBPD], a
- dec c
- jr nz, .asm_9bf6
- ld hl, Palettes_9c09
- ld de, wTempOBPal2
- ld bc, $10
- call CopyBytes
- ret
-
-Palettes_9c09:
- RGB 31, 31, 31
- RGB 25, 25, 25
- RGB 13, 13, 13
- RGB 0, 0, 0
-
- RGB 31, 31, 31
- RGB 31, 31, 7
- RGB 31, 16, 1
- RGB 0, 0, 0
-
- RGB 31, 31, 31
- RGB 31, 19, 24
- RGB 30, 10, 6
- RGB 0, 0, 0
-
- RGB 31, 31, 31
- RGB 12, 25, 1
- RGB 5, 14, 0
- RGB 0, 0, 0
-
- RGB 31, 31, 31
- RGB 8, 12, 31
- RGB 1, 4, 31
- RGB 0, 0, 0
-
- RGB 31, 31, 31
- RGB 24, 18, 7
- RGB 20, 15, 3
- RGB 0, 0, 0
-
-Function9c39:
- call CheckCGB
- ret z
- ld a, $90
- ldh [rOBPI], a
- ld a, $1c
- call Function9ac7
- call Function9c52
- ld a, $21
- call Function9ac7
- call Function9c52
- ret
-
-Function9c52: ; 9c52 (2:5c52)
- ld c, $8
-.asm_9c54
- ld a, [hli]
- ldh [rOBPD], a
- dec c
- jr nz, .asm_9c54
- ret
-
-Function9c5b: ; 9c5b (2:5c5b)
- ld l, a
- ld h, $0
- add hl, hl
- add hl, hl
- add hl, hl
- ld bc, PokemonPalettes
- add hl, bc
- ret
-
-Function9c66: ; 9c66 (2:5c66)
- push bc
- call Function9c5b
- pop bc
- push hl
- call CheckShininess
- pop hl
- ret nc
- inc hl
- inc hl
- inc hl
- inc hl
- ret
-
-PushSGBPals_: ; 9c76 (2:5c76)
- ld a, [wd8ba]
- push af
- set 7, a
- ld [wd8ba], a
- call Function9c87
- pop af
- ld [wd8ba], a
- ret
-
-Function9c87: ; 9c87 (2:5c87)
- ld a, [hl]
- and $7
- ret z
- ld b, a
-.asm_9c8c
- push bc
- xor a
- ldh [rJOYP], a
- ld a, $30
- ldh [rJOYP], a
- ld b, $10
-.asm_9c96
- ld e, $8
- ld a, [hli]
- ld d, a
-.asm_9c9a
- bit 0, d
- ld a, $10
- jr nz, .asm_9ca2
- ld a, $20
-.asm_9ca2
- ldh [rJOYP], a
- ld a, $30
- ldh [rJOYP], a
- rr d
- dec e
- jr nz, .asm_9c9a
- dec b
- jr nz, .asm_9c96
- ld a, $20
- ldh [rJOYP], a
- ld a, $30
- ldh [rJOYP], a
- call Function9ed9
- pop bc
- dec b
- jr nz, .asm_9c8c
- ret
-
-InitSGBBorder: ; 9cc0 (2:5cc0)
- call CheckCGB
- ret nz
- di
- ld a, [wd8ba]
- push af
- set 7, a
- ld [wd8ba], a
- xor a
- ldh [rJOYP], a
- ldh [hSGB], a
- call Function9da9
- jr nc, .asm_9cf7
- ld a, $1
- ldh [hSGB], a
- call Function9d4a
- call Function9e13
- call Function9ed9
- call Function9d9e
- call Function9d8b
- call Function9ed9
- call Function9d9e
- ld hl, PalPacket_a1d5
- call Function9c87
-.asm_9cf7
- pop af
- ld [wd8ba], a
- ei
- ret
-
-InitCGBPals:: ; 9cfd (2:5cfd)
- call CheckCGB
- ret z
- ld a, $1
- ldh [rVBK], a
- ld hl, $8000
- ld bc, $2000
- xor a
- call ByteFill
- ld a, $0
- ldh [rVBK], a
- ld a, $80
- ldh [rBGPI], a
- ld c, $20
-.asm_9d19
- ld a, $ff
- ldh [rBGPD], a
- ld a, $7f
- ldh [rBGPD], a
- dec c
- jr nz, .asm_9d19
- ld a, $80
- ldh [rOBPI], a
- ld c, $20
-.asm_9d2a
- ld a, $ff
- ldh [rOBPD], a
- ld a, $7f
- ldh [rOBPD], a
- dec c
- jr nz, .asm_9d2a
- ld hl, wTempBGPals
- call Function9d3e
- ld hl, wBGPals
-Function9d3e: ; 9d3e (2:5d3e)
- ld c, $40
-.asm_9d40
- ld a, $ff
- ld [hli], a
- ld a, $7f
- ld [hli], a
- dec c
- jr nz, .asm_9d40
- ret
-
-Function9d4a: ; 9d4a (2:5d4a)
- ld hl, .Pointers
- ld c, $9
-.asm_9d4f
- push bc
- ld a, [hli]
- push hl
- ld h, [hl]
- ld l, a
- call Function9c87
- pop hl
- inc hl
- pop bc
- dec c
- jr nz, .asm_9d4f
- ret
-
-.Pointers:
- dw PalPacket_a1c5
- dw PalPacket_a1e5
- dw PalPacket_a1f5
- dw PalPacket_a205
- dw PalPacket_a215
- dw PalPacket_a225
- dw PalPacket_a235
- dw PalPacket_a245
- dw PalPacket_a255
-
-Function9d70:
- di
- xor a
- ldh [rJOYP], a
- ld hl, PalPacket_a1c5
- call Function9c87
- call Function9d8b
- call Function9ed9
- call Function9d9e
- ld hl, PalPacket_a1d5
- call Function9c87
- ei
- ret
-
-Function9d8b: ; 9d8b (2:5d8b)
- call Function9d97
- push de
- call Function9e83
- pop hl
- call Function9e37
- ret
-
-Function9d97: ; 9d97 (2:5d97)
- ld hl, SGBBorder
- ld de, SGBBorderMap
- ret
-
-Function9d9e: ; 9d9e (2:5d9e)
- ld hl, $8000
- ld bc, $2000
- xor a
- call ByteFill
- ret
-
-Function9da9: ; 9da9 (2:5da9)
- ld hl, PalPacket_a195
- call Function9c87
- call Function9ed9
- ldh a, [rJOYP]
- and $3
- cp $3
- jr nz, .asm_9e05
- ld a, $20
- ldh [rJOYP], a
- ldh a, [rJOYP]
- ldh a, [rJOYP]
- call Function9ed9
- call Function9ed9
- ld a, $30
- ldh [rJOYP], a
- call Function9ed9
- call Function9ed9
- ld a, $10
- ldh [rJOYP], a
- ldh a, [rJOYP]
- ldh a, [rJOYP]
- ldh a, [rJOYP]
- ldh a, [rJOYP]
- ldh a, [rJOYP]
- ldh a, [rJOYP]
- call Function9ed9
- call Function9ed9
- ld a, $30
- ldh [rJOYP], a
- ldh a, [rJOYP]
- ldh a, [rJOYP]
- ldh a, [rJOYP]
- call Function9ed9
- call Function9ed9
- ldh a, [rJOYP]
- and $3
- cp $3
- jr nz, .asm_9e05
- call Function9e0a
- and a
- ret
-
-.asm_9e05
- call Function9e0a
- scf
- ret
-
-Function9e0a: ; 9e0a (2:5e0a)
- ld hl, PalPacket_a185
- call Function9c87
- jp Function9ed9
-
-Function9e13: ; 9e13 (2:5e13)
- call DisableLCD
- ld a, $e4
- ldh [rBGP], a
- ld hl, Palettes_a265
- ld de, $8800
- ld bc, $1000
- call Function9eb1
- call Function9ec3
- ld a, $e3
- ldh [rLCDC], a
- ld hl, PalPacket_a175
- call Function9c87
- xor a
- ldh [rBGP], a
- ret
-
-Function9e37: ; 9e37 (2:5e37)
- call DisableLCD
- ld a, $e4
- ldh [rBGP], a
- ld de, $8800
- ld bc, $140
- call Function9eb1
- ld b, $12
-.asm_9e49
- push bc
- ld bc, $c
- call Function9eb1
- ld bc, $28
- call Function9eba
- ld bc, $c
- call Function9eb1
- pop bc
- dec b
- jr nz, .asm_9e49
- ld bc, $140
- call Function9eb1
- ld bc, $100
- call Function9eba
- ld bc, $80
- call Function9eb1
- call Function9ec3
- ld a, $e3
- ldh [rLCDC], a
- ld hl, PalPacket_a1b5
- call Function9c87
- xor a
- ldh [rBGP], a
- ret
-
-Function9e83: ; 9e83 (2:5e83)
- call DisableLCD
- ld a, $e4
- ldh [rBGP], a
- ld de, $8800
- ld b, $80
-.asm_9e8f
- push bc
- ld bc, $10
- call Function9eb1
- ld bc, $10
- call Function9eba
- pop bc
- dec b
- jr nz, .asm_9e8f
- call Function9ec3
- ld a, $e3
- ldh [rLCDC], a
- ld hl, PalPacket_a1a5
- call Function9c87
- xor a
- ldh [rBGP], a
- ret
-
-Function9eb1: ; 9eb1 (2:5eb1)
- ld a, [hli]
- ld [de], a
- inc de
- dec bc
- ld a, c
- or b
- jr nz, Function9eb1
- ret
-
-Function9eba: ; 9eba (2:5eba)
- xor a
- ld [de], a
- inc de
- dec bc
- ld a, c
- or b
- jr nz, Function9eba
- ret
-
-Function9ec3: ; 9ec3 (2:5ec3)
- ld hl, $9800
- ld de, $c
- ld a, $80
- ld c, $d
-.asm_9ecd
- ld b, $14
-.asm_9ecf
- ld [hli], a
- inc a
- dec b
- jr nz, .asm_9ecf
- add hl, de
- dec c
- jr nz, .asm_9ecd
- ret
-
-Function9ed9: ; 9ed9 (2:5ed9)
- ld de, 7000
-.asm_9edc
- nop
- nop
- nop
- dec de
- ld a, d
- or e
- jr nz, .asm_9edc
- ret
-
-BlkPacket_9ee5: db $21, $01, $03, $00, $00, $00, $13, $11, $00, $00, $00, $00, $00, $00, $00, $00
-BlkPacket_9ef5: db $21, $01, $07, $05, $00, $0a, $13, $0d, $00, $00, $00, $00, $00, $00, $00, $00
-BlkPacket_9f05: db $22, $05, $07, $0a, $00, $0c, $13, $11, $03, $05, $01, $00, $0a, $03, $03, $00
-BlkPacket_9f15: db $0a, $08, $13, $0a, $03, $0a, $00, $04, $08, $0b, $03, $0f, $0b, $00, $13, $07
-BlkPacket_9f25: db $21, $01, $07, $05, $00, $00, $06, $06, $00, $00, $00, $00, $00, $00, $00, $00
-BlkPacket_9f35: db $21, $01, $06, $05, $0b, $01, $13, $02, $00, $00, $00, $00, $00, $00, $00, $00
-BlkPacket_9f45: db $21, $01, $07, $05, $00, $01, $07, $07, $00, $00, $00, $00, $00, $00, $00, $00
-BlkPacket_9f55: db $21, $01, $07, $05, $01, $04, $07, $0a, $00, $00, $00, $00, $00, $00, $00, $00
-BlkPacket_9f65: db $21, $01, $07, $05, $01, $01, $05, $05, $00, $00, $00, $00, $00, $00, $00, $00
-BlkPacket_9f75: db $21, $01, $07, $05, $07, $05, $0d, $0b, $00, $00, $00, $00, $00, $00, $00, $00
-BlkPacket_9f85: db $22, $05, $03, $05, $00, $00, $13, $0b, $03, $0a, $00, $04, $13, $09, $02, $0f
-BlkPacket_9f95: db $00, $06, $13, $07, $03, $00, $04, $04, $0f, $09, $03, $00, $00, $0c, $13, $11
-BlkPacket_9fa5: db $23, $07, $07, $10, $00, $00, $02, $0c, $02, $00, $0c, $01, $12, $02, $02, $00
-BlkPacket_9fb5: db $0c, $03, $12, $04, $02, $00, $0c, $05, $12, $06, $02, $00, $0c, $07, $12, $08
-BlkPacket_9fc5: db $02, $00, $0c, $09, $12, $0a, $02, $00, $0c, $0b, $12, $0c, $00, $00, $00, $00
-BlkPacket_9fd5: db $21, $02, $07, $30, $00, $00, $13, $06, $02, $04, $05, $06, $0e, $06, $00, $00
-BlkPacket_9fe5: db $21, $01, $07, $10, $00, $00, $13, $05, $00, $00, $00, $00, $00, $00, $00, $00
-BlkPacket_9ff5: db $21, $02, $07, $0a, $00, $04, $13, $0d, $03, $05, $00, $06, $13, $0b, $00, $00
-
-PalPacket_a005:
- db $51
- RGB 8, 2, 0
- RGB 9, 2, 0
- RGB 10, 2, 0
- RGB 11, 2, 0
- db $00, $00, $00, $00, $00, $00, $00
-
-PalPacket_a015:
- db $51
- RGB 11, 1, 0
- RGB 4, 1, 0
- RGB 0, 1, 0
- RGB 0, 0, 0
- db $00, $00, $00, $00, $00, $00, $00
-
-PalPacket_a025:
- db $51
- RGB 1, 2, 0
- RGB 2, 2, 0
- RGB 3, 2, 0
- RGB 4, 2, 0
- db $00, $00, $00, $00, $00, $00, $00
-
-PalPacket_a035:
- db $51
- RGB 12, 2, 0
- RGB 12, 2, 0
- RGB 12, 2, 0
- RGB 12, 2, 0
- db $00, $00, $00, $00, $00, $00, $00
-
-PalPacket_a045:
- db $51
- RGB 0, 0, 0
- RGB 0, 0, 0
- RGB 0, 0, 0
- RGB 0, 0, 0
- db $00, $00, $00, $00, $00, $00, $00
-
-PalPacket_a055:
- db $51
- RGB 22, 1, 0
- RGB 0, 0, 0
- RGB 0, 0, 0
- RGB 0, 0, 0
- db $00, $00, $00, $00, $00, $00, $00
-
-PalPacket_a065:
- db $51
- RGB 23, 1, 0
- RGB 0, 0, 0
- RGB 0, 0, 0
- RGB 0, 0, 0
- db $00, $00, $00, $00, $00, $00, $00
-
-PalPacket_a075:
- db $51
- RGB 24, 1, 0
- RGB 25, 1, 0
- RGB 0, 0, 0
- RGB 0, 0, 0
- db $00, $00, $00, $00, $00, $00, $00
-
-PalPacket_a085:
- db $51
- RGB 26, 1, 0
- RGB 0, 0, 0
- RGB 0, 0, 0
- RGB 0, 0, 0
- db $00, $00, $00, $00, $00, $00, $00
-
-PalPacket_a095:
- db $51
- RGB 27, 1, 0
- RGB 0, 0, 0
- RGB 0, 0, 0
- RGB 0, 0, 0
- db $00, $00, $00, $00, $00, $00, $00
-
-PalPacket_a0a5:
- db $51
- RGB 28, 1, 0
- RGB 0, 0, 0
- RGB 0, 0, 0
- RGB 0, 0, 0
- db $00, $00, $00, $00, $00, $00, $00
-
-PalPacket_a0b5:
- db $51
- RGB 25, 1, 0
- RGB 0, 0, 0
- RGB 0, 0, 0
- RGB 0, 0, 0
- db $00, $00, $00, $00, $00, $00, $00
-
-PalPacket_a0c5:
- db $51
- RGB 14, 1, 0
- RGB 15, 1, 0
- RGB 16, 1, 0
- RGB 17, 1, 0
- db $00, $00, $00, $00, $00, $00, $00
-
-PalPacket_a0d5:
- db $51
- RGB 26, 0, 0
- RGB 26, 0, 0
- RGB 26, 0, 0
- RGB 26, 0, 0
- db $00, $00, $00, $00, $00, $00, $00
-
-PalPacket_a0e5:
- db $51
- RGB 18, 1, 0
- RGB 0, 0, 0
- RGB 0, 0, 0
- RGB 0, 0, 0
- db $00, $00, $00, $00, $00, $00, $00
-
-PalPacket_a0f5:
- db $51
- RGB 28, 1, 0
- RGB 0, 0, 0
- RGB 0, 0, 0
- RGB 0, 0, 0
- db $00, $00, $00, $00, $00, $00, $00
-
-PalPacket_a105:
- db $51
- RGB 29, 1, 0
- RGB 30, 1, 0
- RGB 31, 1, 0
- RGB 0, 2, 0
- db $00, $00, $00, $00, $00, $00, $00
-
-PalPacket_a115:
- db $51
- RGB 19, 1, 0
- RGB 20, 1, 0
- RGB 27, 0, 0
- RGB 31, 0, 0
- db $00, $00, $00, $00, $00, $00, $00
-
-PalPacket_a125:
- db $51
- RGB 27, 0, 0
- RGB 0, 0, 0
- RGB 0, 0, 0
- RGB 0, 0, 0
- db $00, $00, $00, $00, $00, $00, $00
-
-PalPacket_a135:
- db $51
- RGB 28, 0, 0
- RGB 0, 0, 0
- RGB 0, 0, 0
- RGB 0, 0, 0
- db $00, $00, $00, $00, $00, $00, $00
-
-PalPacket_a145:
- db $51
- RGB 21, 1, 0
- RGB 0, 0, 0
- RGB 0, 0, 0
- RGB 0, 0, 0
- db $00, $00, $00, $00, $00, $00, $00
-
-PalPacket_a155: db $01, $ff, $7f, $00, $00, $00, $00, $00, $00, $00, $00, $00, $00, $00, $00, $00
-PalPacket_a165: db $09, $ff, $7f, $00, $00, $00, $00, $00, $00, $00, $00, $00, $00, $00, $00, $00
-PalPacket_a175: db $59, $00, $00, $00, $00, $00, $00, $00, $00, $00, $00, $00, $00, $00, $00, $00
-PalPacket_a185: db $89, $00, $00, $00, $00, $00, $00, $00, $00, $00, $00, $00, $00, $00, $00, $00
-PalPacket_a195: db $89, $01, $00, $00, $00, $00, $00, $00, $00, $00, $00, $00, $00, $00, $00, $00
-PalPacket_a1a5: db $99, $00, $00, $00, $00, $00, $00, $00, $00, $00, $00, $00, $00, $00, $00, $00
-PalPacket_a1b5: db $a1, $00, $00, $00, $00, $00, $00, $00, $00, $00, $00, $00, $00, $00, $00, $00
-
-PalPacket_a1c5: db $b9, $01, $00, $00, $00, $00, $00, $00, $00, $00, $00, $00, $00, $00, $00, $00
-PalPacket_a1d5: db $b9, $00, $00, $00, $00, $00, $00, $00, $00, $00, $00, $00, $00, $00, $00, $00
-PalPacket_a1e5: db $79, $5d, $08, $00, $0b, $8c, $d0, $f4, $60, $00, $00, $00, $00, $00, $00, $00
-PalPacket_a1f5: db $79, $52, $08, $00, $0b, $a9, $e7, $9f, $01, $c0, $7e, $e8, $e8, $e8, $e8, $e0
-PalPacket_a205: db $79, $47, $08, $00, $0b, $c4, $d0, $16, $a5, $cb, $c9, $05, $d0, $10, $a2, $28
-PalPacket_a215: db $79, $3c, $08, $00, $0b, $f0, $12, $a5, $c9, $c9, $c8, $d0, $1c, $a5, $ca, $c9
-PalPacket_a225: db $79, $31, $08, $00, $0b, $0c, $a5, $ca, $c9, $7e, $d0, $06, $a5, $cb, $c9, $7e
-PalPacket_a235: db $79, $26, $08, $00, $0b, $39, $cd, $48, $0c, $d0, $34, $a5, $c9, $c9, $80, $d0
-PalPacket_a245: db $79, $1b, $08, $00, $0b, $ea, $ea, $ea, $ea, $ea, $a9, $01, $cd, $4f, $0c, $d0
-PalPacket_a255: db $79, $10, $08, $00, $0b, $4c, $20, $08, $ea, $ea, $ea, $ea, $ea, $60, $ea, $ea
-
-IF DEF(GOLD)
-Palettes_a265: INCLUDE "gfx/pals/gold_a265.pal"
-ENDC
-IF DEF(SILVER)
-Palettes_a265: INCLUDE "gfx/pals/silver_a265.pal"
-ENDC
-
-IF DEF(GOLD)
-SGBBorderMap: INCBIN "gfx/sgb_border/gold.map"
-SGBBorderPalettes: INCLUDE "gfx/sgb_border/pals/gold.pal"
-SGBBorder: INCBIN "gfx/sgb_border/gold.2bpp"
-ENDC
-
-IF DEF(SILVER)
-SGBBorderMap: INCBIN "gfx/sgb_border/silver.map"
-SGBBorderPalettes: INCLUDE "gfx/sgb_border/pals/silver.pal"
-SGBBorder: INCBIN "gfx/sgb_border/silver.2bpp"
-ENDC
-
-Palettes_ad2d:
- RGB 30, 26, 15
- RGB 00, 23, 00
-
- RGB 30, 26, 15
- RGB 31, 21, 00
-
- RGB 30, 26, 15
- RGB 31, 00, 00
-
-Palettes_ad39:
- RGB 30, 26, 15
- RGB 04, 17, 31
-
-INCLUDE "gfx/pics/palette_pointers.asm"
-INCLUDE "gfx/trainers/palette_pointers.asm"
-
-Functionb649: ; b649 (2:7649)
- ld a, [wPermission]
- and $7
- ld e, a
- ld d, $0
- ld hl, Pointers_b6ce
- add hl, de
- add hl, de
- ld a, [hli]
- ld h, [hl]
- ld l, a
- ld a, [wTimeOfDayPal]
- and $3
- add a
- add a
- add a
- ld e, a
- ld d, $0
- add hl, de
- ld e, l
- ld d, h
- ld hl, wTempBGPals
- ld b, $8
-.asm_b66c
- ld a, [de]
- push de
- push hl
- ld l, a
- ld h, $0
- add hl, hl
- add hl, hl
- add hl, hl
- ld de, $775e
- add hl, de
- ld e, l
- ld d, h
- pop hl
- ld c, $8
-.asm_b67e
- ld a, [de]
- inc de
- ld [hli], a
- dec c
- jr nz, .asm_b67e
- pop de
- inc de
- dec b
- jr nz, .asm_b66c
- ld a, [wTimeOfDayPal]
- and $3
- ld bc, $40
- ld hl, MapObjectPals
- call AddNTimes
- ld de, wTempOBPal0
- ld bc, $40
- call CopyBytes
- ld a, [wPermission]
- cp $1
- jr z, .asm_b6aa
- cp $2
- ret nz
-.asm_b6aa
- ld a, [wMapGroup]
- ld l, a
- ld h, $0
- add hl, hl
- add hl, hl
- add hl, hl
- ld de, RoofPals
- add hl, de
- ld a, [wTimeOfDayPal]
- and $3
- cp $2
- jr c, .asm_b6c4
- inc hl
- inc hl
- inc hl
- inc hl
-.asm_b6c4
- ld de, wTempBGPal6 + 2
- ld bc, $4
- call CopyBytes
- ret
-
-Pointers_b6ce:
- dw .OutdoorColors ; unused
- dw .OutdoorColors ; TOWN
- dw .OutdoorColors ; ROUTE
- dw .IndoorColors ; INDOOR
- dw .DungeonColors ; CAVE
- dw .Perm5Colors ; ENVIRONMENT_5
- dw .IndoorColors ; GATE
- dw .DungeonColors ; DUNGEON
-
-; Valid indices: $00 - $29
-.OutdoorColors:
- db $00, $01, $02, $28, $04, $05, $06, $07 ; morn
- db $08, $09, $0a, $28, $0c, $0d, $0e, $0f ; day
- db $10, $11, $12, $29, $14, $15, $16, $17 ; nite
- db $18, $19, $1a, $1b, $1c, $1d, $1e, $1f ; dark
-
-.IndoorColors:
- db $20, $21, $22, $23, $24, $25, $26, $07 ; morn
- db $20, $21, $22, $23, $24, $25, $26, $07 ; day
- db $10, $11, $12, $13, $14, $15, $16, $07 ; nite
- db $18, $19, $1a, $1b, $1c, $1d, $1e, $07 ; dark
-
-.DungeonColors:
- db $00, $01, $02, $03, $04, $05, $06, $07 ; morn
- db $08, $09, $0a, $0b, $0c, $0d, $0e, $0f ; day
- db $10, $11, $12, $13, $14, $15, $16, $17 ; nite
- db $18, $19, $1a, $1b, $1c, $1d, $1e, $1f ; dark
-
-.Perm5Colors:
- db $00, $01, $02, $03, $04, $05, $06, $07 ; morn
- db $08, $09, $0a, $0b, $0c, $0d, $0e, $0f ; day
- db $10, $11, $12, $13, $14, $15, $16, $17 ; nite
- db $18, $19, $1a, $1b, $1c, $1d, $1e, $1f ; dark
-
-TilesetBGPalette: ; b75e
-INCLUDE "gfx/tilesets/bg.pal"
-
-MapObjectPals:: ; b8ae
-INCLUDE "gfx/tilesets/ob.pal"
-
-RoofPals: ; b9ae
-INCLUDE "gfx/tilesets/roof.pal"
-
-Palettes_ba86:
- RGB 27, 31, 27
- RGB 21, 21, 21
- RGB 13, 13, 13
- RGB 00, 00, 00
-
- RGB 27, 31, 27
- RGB 31, 07, 06
- RGB 20, 02, 03
- RGB 00, 00, 00
-
- RGB 27, 31, 27
- RGB 10, 31, 09
- RGB 04, 14, 01
- RGB 00, 00, 00
-
- RGB 27, 31, 27
- RGB 08, 12, 31
- RGB 01, 04, 31
- RGB 00, 00, 00
-
- RGB 27, 31, 27
- RGB 31, 31, 07
- RGB 31, 16, 01
- RGB 00, 00, 00
-
- RGB 27, 31, 27
- RGB 22, 16, 08
- RGB 13, 07, 01
- RGB 00, 00, 00
-
- RGB 27, 31, 27
- RGB 15, 31, 31
- RGB 05, 17, 31
- RGB 00, 00, 00
-
- RGB 31, 31, 31
- RGB 11, 11, 19
- RGB 07, 07, 12
- RGB 00, 00, 00
-
-Palettes_bac6:
- RGB 27, 31, 27
- RGB 31, 19, 10
- RGB 31, 07, 04
- RGB 00, 00, 00
-
- RGB 27, 31, 27
- RGB 31, 19, 10
- RGB 10, 14, 20
- RGB 00, 00, 00
-
- RGB 27, 31, 27
- RGB 31, 19, 10
- RGB 31, 07, 04
- RGB 00, 00, 00
-
- RGB 27, 31, 27
- RGB 31, 19, 10
- RGB 31, 07, 04
- RGB 00, 00, 00
-
- RGB 27, 31, 27
- RGB 31, 19, 10
- RGB 31, 07, 04
- RGB 00, 00, 00
-
- RGB 27, 31, 27
- RGB 31, 19, 10
- RGB 31, 07, 04
- RGB 00, 00, 00
-
- RGB 27, 31, 27
- RGB 31, 19, 10
- RGB 31, 07, 04
- RGB 00, 00, 00
-
- RGB 27, 31, 27
- RGB 31, 19, 10
- RGB 31, 07, 04
- RGB 00, 00, 00
-
- RGB 31, 31, 31
- RGB 21, 21, 21
- RGB 13, 13, 13
- RGB 07, 07, 07
-
- RGB 31, 31, 31
- RGB 31, 31, 07
- RGB 31, 16, 01
- RGB 07, 07, 07
-
- RGB 31, 31, 31
- RGB 31, 19, 24
- RGB 30, 10, 06
- RGB 07, 07, 07
-
- RGB 31, 31, 31
- RGB 12, 25, 01
- RGB 05, 14, 00
- RGB 07, 07, 07
-
- RGB 31, 31, 31
- RGB 08, 12, 31
- RGB 01, 04, 31
- RGB 07, 07, 07
-
- RGB 31, 31, 31
- RGB 24, 18, 07
- RGB 20, 15, 03
- RGB 07, 07, 07
-
-Palettes_bb36:
-IF DEF(GOLD)
- RGB 31, 31, 31
- RGB 18, 23, 31
- RGB 15, 20, 31
- RGB 0, 0, 0
-
- RGB 31, 21, 0
- RGB 12, 14, 12
- RGB 15, 20, 31
- RGB 0, 0, 17
-
- RGB 31, 31, 31
- RGB 31, 0, 0
- RGB 15, 20, 31
- RGB 0, 0, 0
-
- RGB 31, 31, 31
- RGB 29, 25, 0
- RGB 15, 20, 31
- RGB 17, 10, 1
-
- RGB 31, 31, 31
- RGB 23, 26, 31
- RGB 18, 23, 31
- RGB 0, 0, 0
-ENDC
-
-IF DEF(SILVER)
- RGB 31, 31, 31
- RGB 0, 12, 15
- RGB 4, 8, 21
- RGB 0, 0, 0
-
- RGB 31, 21, 0
- RGB 15, 17, 15
- RGB 4, 8, 21
- RGB 0, 0, 17
-
- RGB 31, 31, 31
- RGB 31, 0, 0
- RGB 4, 8, 21
- RGB 0, 0, 0
-
- RGB 31, 31, 31
- RGB 24, 23, 25
- RGB 4, 8, 21
- RGB 8, 8, 9
-
- RGB 31, 31, 31
- RGB 5, 10, 11
- RGB 0, 12, 15
- RGB 0, 0, 0
-ENDC
-
-Palettes_bb5e:
- RGB 31, 31, 31
- RGB 07, 06, 03
- RGB 07, 06, 03
- RGB 07, 06, 03
-
- RGB 31, 31, 31
- RGB 31, 31, 00
- RGB 26, 22, 00
- RGB 00, 00, 00
-
-Palettes_bb6e:
- RGB 28, 31, 20
- RGB 21, 21, 21
- RGB 13, 13, 13
- RGB 00, 00, 00
-
- RGB 28, 31, 20
- RGB 00, 31, 00
- RGB 00, 00, 31
- RGB 00, 00, 00
-
- RGB 28, 31, 20
- RGB 00, 31, 00
- RGB 15, 07, 00
- RGB 00, 00, 00
-
- RGB 28, 31, 20
- RGB 31, 15, 00
- RGB 15, 07, 00
- RGB 00, 00, 00
-
- RGB 28, 31, 20
- RGB 00, 31, 00
- RGB 00, 00, 31
- RGB 31, 00, 00
-
- RGB 28, 31, 20
- RGB 00, 31, 00
- RGB 15, 07, 00
- RGB 31, 00, 00
-
-Palettes_bb9e:
- RGB 31, 31, 31
- RGB 30, 22, 24
- RGB 18, 18, 18
- RGB 00, 00, 00
-
- RGB 31, 31, 31
- RGB 10, 11, 31
- RGB 18, 18, 18
- RGB 00, 00, 00
-
- RGB 31, 31, 31
- RGB 12, 31, 11
- RGB 18, 18, 18
- RGB 00, 00, 00
-
- RGB 31, 31, 31
- RGB 29, 26, 05
- RGB 18, 18, 18
- RGB 00, 00, 00
-
-Palettes_bbbe:
-IF DEF(GOLD)
- RGB 31, 31, 31
- RGB 24, 25, 28
- RGB 24, 24, 09
- RGB 00, 00, 00
-
- RGB 31, 31, 31
- RGB 30, 10, 06
- RGB 24, 24, 09
- RGB 00, 00, 00
-
- RGB 31, 31, 31
- RGB 15, 31, 00
- RGB 24, 24, 09
- RGB 00, 00, 00
-
- RGB 31, 31, 31
- RGB 31, 15, 31
- RGB 24, 24, 09
- RGB 00, 00, 00
-
- RGB 31, 31, 31
- RGB 15, 21, 31
- RGB 24, 24, 09
- RGB 00, 00, 00
-
- RGB 31, 31, 11
- RGB 31, 31, 06
- RGB 24, 24, 09
- RGB 00, 00, 00
-
- RGB 31, 31, 31
- RGB 16, 19, 29
- RGB 25, 22, 00
- RGB 00, 00, 00
-
- RGB 31, 31, 31
- RGB 21, 21, 21
- RGB 13, 13, 13
- RGB 00, 00, 00
-
- RGB 31, 31, 31
- RGB 30, 10, 06
- RGB 31, 00, 00
- RGB 00, 00, 00
-
- RGB 31, 31, 31
- RGB 12, 25, 01
- RGB 05, 14, 00
- RGB 00, 00, 00
-
- RGB 31, 31, 31
- RGB 12, 25, 01
- RGB 30, 10, 06
- RGB 00, 00, 00
-
- RGB 31, 31, 31
- RGB 31, 31, 06
- RGB 20, 15, 03
- RGB 00, 00, 00
-
- RGB 31, 31, 31
- RGB 31, 31, 06
- RGB 15, 21, 31
- RGB 00, 00, 00
-
- RGB 31, 31, 31
- RGB 31, 31, 06
- RGB 20, 15, 03
- RGB 00, 00, 00
-
- RGB 31, 31, 31
- RGB 31, 24, 21
- RGB 31, 13, 31
- RGB 00, 00, 00
-
- RGB 31, 31, 31
- RGB 31, 31, 31
- RGB 00, 00, 00
- RGB 00, 00, 00
-ENDC
-
-IF DEF(SILVER)
- RGB 31, 31, 31
- RGB 25, 26, 14
- RGB 20, 17, 31
- RGB 0, 0, 0
-
- RGB 31, 31, 31
- RGB 30, 10, 6
- RGB 20, 17, 31
- RGB 0, 0, 0
-
- RGB 31, 31, 31
- RGB 15, 31, 0
- RGB 20, 17, 31
- RGB 0, 0, 0
-
- RGB 31, 31, 31
- RGB 31, 15, 31
- RGB 20, 17, 31
- RGB 0, 0, 0
-
- RGB 31, 31, 31
- RGB 15, 21, 31
- RGB 20, 17, 31
- RGB 0, 0, 0
-
- RGB 31, 31, 11
- RGB 31, 31, 6
- RGB 20, 17, 31
- RGB 0, 0, 0
-
- RGB 31, 31, 31
- RGB 16, 19, 29
- RGB 25, 22, 0
- RGB 0, 0, 0
-
- RGB 31, 31, 31
- RGB 21, 21, 21
- RGB 13, 13, 13
- RGB 0, 0, 0
-
- RGB 31, 31, 31
- RGB 30, 10, 6
- RGB 31, 0, 0
- RGB 0, 0, 0
-
- RGB 31, 31, 31
- RGB 12, 25, 1
- RGB 5, 14, 0
- RGB 0, 0, 0
-
- RGB 31, 31, 31
- RGB 12, 25, 1
- RGB 30, 10, 6
- RGB 0, 0, 0
-
- RGB 31, 31, 31
- RGB 31, 31, 6
- RGB 20, 15, 3
- RGB 0, 0, 0
-
- RGB 31, 31, 31
- RGB 31, 31, 6
- RGB 15, 21, 31
- RGB 0, 0, 0
-
- RGB 31, 31, 31
- RGB 31, 31, 6
- RGB 20, 15, 3
- RGB 0, 0, 0
-
- RGB 31, 31, 31
- RGB 31, 24, 21
- RGB 31, 13, 31
- RGB 0, 0, 0
-
- RGB 31, 31, 31
- RGB 31, 31, 31
- RGB 0, 0, 0
- RGB 0, 0, 0
-ENDC
diff --git a/engine/engine_flags.asm b/engine/engine_flags.asm
deleted file mode 100755
index 9fa5f8c0..00000000
--- a/engine/engine_flags.asm
+++ /dev/null
@@ -1,195 +0,0 @@
-EngineFlagAction:: ; c01b
-; Do action b on engine flag de
-;
-; b = 0: reset flag
-; = 1: set flag
-; > 1: check flag, result in c
-;
-; Setting/resetting does not return a result.
-
-
-; 16-bit flag ids are considered invalid, but it's nice
-; to know that the infrastructure is there.
-
- ld a, d
- cp 0
- jr z, .ceiling
- jr c, .read ; cp 0 can't set carry!
- jr .invalid
-
-; There are only $a2 engine flags, so
-; anything beyond that is invalid too.
-
-.ceiling
- ld a, e
- cp NUM_ENGINE_FLAGS
- jr c, .read
-
-; Invalid flags are treated as flag 00.
-
-.invalid
- xor a
- ld e, a
- ld d, a
-
-; Get this flag's location.
-
-.read
- ld hl, EngineFlags
-; location
- add hl, de
- add hl, de
-; bit
- add hl, de
-
-; location
- ld e, [hl]
- inc hl
- ld d, [hl]
- inc hl
-; bit
- ld c, [hl]
-
-; What are we doing with this flag?
-
- ld a, b
- cp 1
- jr c, .reset ; b = 0
- jr z, .set ; b = 1
-
-; Return the given flag in c.
-.check
- ld a, [de]
- and c
- ld c, a
- ret
-
-; Set the given flag.
-.set
- ld a, [de]
- or c
- ld [de], a
- ret
-
-; Reset the given flag.
-.reset
- ld a, c
- cpl ; AND all bits except the one in question
- ld c, a
- ld a, [de]
- and c
- ld [de], a
- ret
-
-; 404d
-EngineFlags:
-; All locations are in WRAM bank 1.
-
- ; location, bit
- engine_flag ENGINE_RADIO_CARD
- engine_flag ENGINE_MAP_CARD
- engine_flag ENGINE_PHONE_CARD
- engine_flag ENGINE_EXPN_CARD
- engine_flag ENGINE_POKEGEAR
-
- engine_flag ENGINE_DAY_CARE_MAN_HAS_EGG
- engine_flag ENGINE_DAY_CARE_MAN_HAS_MON
-
- engine_flag ENGINE_DAY_CARE_LADY_HAS_MON
-
- engine_flag ENGINE_MOM_SAVING_MONEY
- engine_flag ENGINE_DST
-
- engine_flag ENGINE_0A
-
- engine_flag ENGINE_POKEDEX
- engine_flag ENGINE_UNOWN_DEX
- engine_flag ENGINE_POKERUS
- engine_flag ENGINE_ROCKET_SIGNAL_ON_CH20
- engine_flag ENGINE_CREDITS_SKIP
- engine_flag ENGINE_BUG_CONTEST_TIMER
- engine_flag ENGINE_SAFARI_ZONE
- engine_flag ENGINE_ROCKETS_IN_RADIO_TOWER
- engine_flag ENGINE_BIKE_SHOP_CALL_ENABLED
- engine_flag ENGINE_GIVE_POKERUS
- engine_flag ENGINE_REACHED_GOLDENROD
- engine_flag ENGINE_ROCKETS_IN_MAHOGANY
-
- engine_flag ENGINE_STRENGTH_ACTIVE
- engine_flag ENGINE_ALWAYS_ON_BIKE
- engine_flag ENGINE_DOWNHILL
-
- engine_flag ENGINE_ZEPHYRBADGE
- engine_flag ENGINE_HIVEBADGE
- engine_flag ENGINE_PLAINBADGE
- engine_flag ENGINE_FOGBADGE
- engine_flag ENGINE_MINERALBADGE
- engine_flag ENGINE_STORMBADGE
- engine_flag ENGINE_GLACIERBADGE
- engine_flag ENGINE_RISINGBADGE
-
- engine_flag ENGINE_BOULDERBADGE
- engine_flag ENGINE_CASCADEBADGE
- engine_flag ENGINE_THUNDERBADGE
- engine_flag ENGINE_RAINBOWBADGE
- engine_flag ENGINE_SOULBADGE
- engine_flag ENGINE_MARSHBADGE
- engine_flag ENGINE_VOLCANOBADGE
- engine_flag ENGINE_EARTHBADGE
-
- engine_flag ENGINE_UNLOCKED_UNOWNS_A_TO_K
- engine_flag ENGINE_UNLOCKED_UNOWNS_L_TO_R
- engine_flag ENGINE_UNLOCKED_UNOWNS_S_TO_W
- engine_flag ENGINE_UNLOCKED_UNOWNS_X_TO_Z
- engine_flag ENGINE_UNLOCKED_UNOWNS_UNUSED_4
- engine_flag ENGINE_UNLOCKED_UNOWNS_UNUSED_5
- engine_flag ENGINE_UNLOCKED_UNOWNS_UNUSED_6
- engine_flag ENGINE_UNLOCKED_UNOWNS_UNUSED_7
-
- engine_flag ENGINE_FLYPOINT_PLAYERS_HOUSE
- engine_flag ENGINE_FLYPOINT_VIRIDIAN_POKECENTER
- engine_flag ENGINE_FLYPOINT_PALLET
- engine_flag ENGINE_FLYPOINT_VIRIDIAN
- engine_flag ENGINE_FLYPOINT_PEWTER
- engine_flag ENGINE_FLYPOINT_CERULEAN
- engine_flag ENGINE_FLYPOINT_ROCK_TUNNEL
- engine_flag ENGINE_FLYPOINT_VERMILION
- engine_flag ENGINE_FLYPOINT_LAVENDER
- engine_flag ENGINE_FLYPOINT_SAFFRON
- engine_flag ENGINE_FLYPOINT_CELADON
- engine_flag ENGINE_FLYPOINT_FUCHSIA
- engine_flag ENGINE_FLYPOINT_CINNABAR
- engine_flag ENGINE_FLYPOINT_INDIGO_PLATEAU
- engine_flag ENGINE_FLYPOINT_NEW_BARK
- engine_flag ENGINE_FLYPOINT_CHERRYGROVE
- engine_flag ENGINE_FLYPOINT_VIOLET
-
- engine_flag ENGINE_FLYPOINT_AZALEA
- engine_flag ENGINE_FLYPOINT_CIANWOOD
- engine_flag ENGINE_FLYPOINT_GOLDENROD
- engine_flag ENGINE_FLYPOINT_OLIVINE
- engine_flag ENGINE_FLYPOINT_ECRUTEAK
- engine_flag ENGINE_FLYPOINT_MAHOGANY
- engine_flag ENGINE_FLYPOINT_LAKE_OF_RAGE
- engine_flag ENGINE_FLYPOINT_BLACKTHORN
- engine_flag ENGINE_FLYPOINT_SILVER_CAVE
-
- engine_flag ENGINE_FLYPOINT_UNUSED
- engine_flag ENGINE_LUCKY_NUMBER_SHOW
- engine_flag ENGINE_4E
-
- engine_flag ENGINE_KURT_MAKING_BALLS
- engine_flag ENGINE_DAILY_BUG_CONTEST
- engine_flag ENGINE_SPECIAL_WILDDATA
- engine_flag ENGINE_TIME_CAPSULE
- engine_flag ENGINE_ALL_FRUIT_TREES
- engine_flag ENGINE_GOT_SHUCKIE_TODAY
- engine_flag ENGINE_GOLDENROD_UNDERGROUND_MERCHANT_CLOSED
- engine_flag ENGINE_FOUGHT_IN_TRAINER_HALL_TODAY
-
- engine_flag ENGINE_MT_MOON_SQUARE_CLEFAIRY
- engine_flag ENGINE_UNION_CAVE_LAPRAS
- engine_flag ENGINE_GOLDENROD_UNDERGROUND_GOT_HAIRCUT
- engine_flag ENGINE_GOLDENROD_DEPT_STORE_TM27_RETURN
- engine_flag ENGINE_DAISYS_GROOMING
- engine_flag ENGINE_INDIGO_PLATEAU_RIVAL_FIGHT
diff --git a/engine/events/bug_contest/caught_mon.asm b/engine/events/bug_contest/caught_mon.asm
new file mode 100644
index 00000000..b2cc044a
--- /dev/null
+++ b/engine/events/bug_contest/caught_mon.asm
@@ -0,0 +1,37 @@
+BugContest_SetCaughtContestMon:
+ ld a, [wContestMon]
+ and a
+ jr z, .firstcatch
+ ld [wNamedObjectIndexBuffer], a
+ farcall DisplayAlreadyCaughtText
+ farcall DisplayCaughtContestMonStats
+ lb bc, 14, 7
+ call PlaceYesNoBox
+ ret c
+
+.firstcatch
+ call .generatestats
+ ld a, [wTempEnemyMonSpecies]
+ ld [wNamedObjectIndexBuffer], a
+ call GetPokemonName
+ ld hl, .ContestCaughtMonText
+ call PrintText
+ ret
+
+.generatestats
+ ld a, [wTempEnemyMonSpecies]
+ ld [wCurSpecies], a
+ ld [wCurPartySpecies], a
+ call GetBaseData
+ xor a
+ ld bc, PARTYMON_STRUCT_LENGTH
+ ld hl, wContestMon
+ call ByteFill
+ xor a
+ ld [wMonType], a
+ ld hl, wContestMon
+ jp GeneratePartyMonStats
+
+.ContestCaughtMonText:
+ text_far _ContestCaughtMonText
+ text_end
diff --git a/engine/events/bug_contest/contest.asm b/engine/events/bug_contest/contest.asm
index 88c300e9..6a3f7799 100755
--- a/engine/events/bug_contest/contest.asm
+++ b/engine/events/bug_contest/contest.asm
@@ -2,16 +2,16 @@ GiveParkBalls:
xor a
ld [wContestMon], a
ld a, 20
- ld [wParkBalls], a
+ ld [wParkBallsRemaining], a
farcall StartBugContestTimer
ret
BugCatchingContestBattleScript::
- writecode VAR_BATTLETYPE, BATTLETYPE_CONTEST
+ loadvar VAR_BATTLETYPE, BATTLETYPE_CONTEST
randomwildmon
startbattle
reloadmapafterbattle
- copybytetovar wParkBalls
+ readmem wParkBallsRemaining
iffalse BugCatchingContestOutOfBallsScript
end
@@ -20,22 +20,22 @@ BugCatchingContestOverScript::
opentext
writetext BugCatchingContestTimeUpText
waitbutton
- jump $79CD
-
+ sjump BugCatchingContestReturnToGateScript
+
BugCatchingContestOutOfBallsScript:
playsound SFX_ELEVATOR_END
opentext
writetext BugCatchingContestIsOverText
waitbutton
-
+
BugCatchingContestReturnToGateScript:
closetext
jumpstd bugcontestresultswarp
-
+
BugCatchingContestTimeUpText:
text_far _BugCatchingContestTimeUpText
- db "@"
+ text_end
BugCatchingContestIsOverText:
text_far _BugCatchingContestIsOverText
- db "@" \ No newline at end of file
+ text_end
diff --git a/engine/events/bug_contest/contest_2.asm b/engine/events/bug_contest/contest_2.asm
new file mode 100644
index 00000000..ddfad864
--- /dev/null
+++ b/engine/events/bug_contest/contest_2.asm
@@ -0,0 +1,116 @@
+SelectRandomBugContestContestants:
+; Select five random people to participate in the current contest.
+
+; First we have to make sure that any old data is cleared away.
+ ld c, NUM_BUG_CONTESTANTS
+ ld hl, BugCatchingContestantEventFlagTable
+.loop1
+ push bc
+ push hl
+ ld e, [hl]
+ inc hl
+ ld d, [hl]
+ ld b, RESET_FLAG
+ call EventFlagAction
+ pop hl
+ inc hl
+ inc hl
+ pop bc
+ dec c
+ jr nz, .loop1
+
+; Now that that's out of the way, we can get on to the good stuff.
+ ld c, 5
+.loop2
+ push bc
+.next
+; Choose a flag at uniform random to be set.
+ call Random
+ cp $ff / NUM_BUG_CONTESTANTS * NUM_BUG_CONTESTANTS
+ jr nc, .next
+ ld c, $ff / NUM_BUG_CONTESTANTS
+ call SimpleDivide
+ ld e, b
+ ld d, 0
+ ld hl, BugCatchingContestantEventFlagTable
+ add hl, de
+ add hl, de
+ ld e, [hl]
+ inc hl
+ ld d, [hl]
+ push de
+; If we've already set it, it doesn't count.
+ ld b, CHECK_FLAG
+ call EventFlagAction
+ pop de
+ ld a, c
+ and a
+ jr nz, .next
+; Set the flag. This will cause that sprite to not be visible in the contest.
+ ld b, SET_FLAG
+ call EventFlagAction
+ pop bc
+; Check if we're done. If so, return. Otherwise, choose the next victim.
+ dec c
+ jr nz, .loop2
+ ret
+
+CheckBugContestContestantFlag:
+; Checks the flag of the Bug Catching Contestant whose index is loaded in a.
+
+ ld hl, BugCatchingContestantEventFlagTable
+ ld e, a
+ ld d, 0
+ add hl, de
+ add hl, de
+ ld e, [hl]
+ inc hl
+ ld d, [hl]
+ ld b, CHECK_FLAG
+ call EventFlagAction
+ ret
+
+INCLUDE "data/events/bug_contest_flags.asm"
+
+ContestDropOffMons:
+ ld hl, wPartyMon1HP
+ ld a, [hli]
+ or [hl]
+ jr z, .fainted
+; Mask the rest of your party by setting the count to 1...
+ ld hl, wPartyCount
+ ld a, 1
+ ld [hli], a
+ inc hl
+; ... backing up the second mon index somewhere...
+ ld a, [hl]
+ ld [wBugContestSecondPartySpecies], a
+; ... and replacing it with the terminator byte
+ ld [hl], -1
+ xor a
+ ld [wScriptVar], a
+ ret
+
+.fainted
+ ld a, $1
+ ld [wScriptVar], a
+ ret
+
+ContestReturnMons:
+; Restore the species of the second mon.
+ ld hl, wPartySpecies + 1
+ ld a, [wBugContestSecondPartySpecies]
+ ld [hl], a
+; Restore the party count, which must be recomputed.
+ ld b, 1
+.loop
+ ld a, [hli]
+ cp -1
+ jr z, .done
+ inc b
+ jr .loop
+
+.done
+ ld a, b
+ ld [wPartyCount], a
+ ret
diff --git a/engine/events/bug_contest/judging.asm b/engine/events/bug_contest/judging.asm
new file mode 100644
index 00000000..4f55fd78
--- /dev/null
+++ b/engine/events/bug_contest/judging.asm
@@ -0,0 +1,373 @@
+_BugContestJudging:
+ call ContestScore
+ call BugContest_JudgeContestants
+ ld a, [wBugContestThirdPlaceWinnerID]
+ call LoadContestantName
+ ld a, [wBugContestThirdPlaceMon]
+ ld [wNamedObjectIndexBuffer], a
+ call GetPokemonName
+ ld hl, ContestJudging_ThirdPlaceText
+ call PrintText
+ ld a, [wBugContestSecondPlaceWinnerID]
+ call LoadContestantName
+ ld a, [wBugContestSecondPlaceMon]
+ ld [wNamedObjectIndexBuffer], a
+ call GetPokemonName
+ ld hl, ContestJudging_SecondPlaceText
+ call PrintText
+ ld a, [wBugContestFirstPlaceWinnerID]
+ call LoadContestantName
+ ld a, [wBugContestFirstPlaceMon]
+ ld [wNamedObjectIndexBuffer], a
+ call GetPokemonName
+ ld hl, ContestJudging_FirstPlaceText
+ call PrintText
+ jp BugContest_GetPlayersResult
+
+ContestJudging_FirstPlaceText:
+ text_far _ContestJudging_FirstPlaceText
+ text_asm
+ ld de, SFX_1ST_PLACE
+ call PlaySFX
+ call WaitSFX
+ ld hl, ContestJudging_FirstPlaceScoreText
+ ret
+
+ContestJudging_FirstPlaceScoreText:
+ text_far _ContestJudging_FirstPlaceScoreText
+ text_end
+
+ContestJudging_SecondPlaceText:
+ ; Placing second was @ , who caught a @ !@ @
+ text_far _ContestJudging_SecondPlaceText
+ text_asm
+ ld de, SFX_2ND_PLACE
+ call PlaySFX
+ call WaitSFX
+ ld hl, ContestJudging_SecondPlaceScoreText
+ ret
+
+ContestJudging_SecondPlaceScoreText:
+ text_far _ContestJudging_SecondPlaceScoreText
+ text_end
+
+ContestJudging_ThirdPlaceText:
+ ; Placing third was @ , who caught a @ !@ @
+ text_far _ContestJudging_ThirdPlaceText
+ text_asm
+ ld de, SFX_3RD_PLACE
+ call PlaySFX
+ call WaitSFX
+ ld hl, ContestJudging_ThirdPlaceScoreText
+ ret
+
+ContestJudging_ThirdPlaceScoreText:
+ text_far _ContestJudging_ThirdPlaceScoreText
+ text_end
+
+LoadContestantName:
+; If a = 1, get your name.
+ dec a ; BUG_CONTEST_PLAYER
+ jr z, .player
+; Find the pointer for the trainer class of the Bug Catching Contestant whose ID is in a.
+ ld c, a
+ ld b, 0
+ ld hl, BugContestantPointers
+ add hl, bc
+ add hl, bc
+ ld a, [hli]
+ ld h, [hl]
+ ld l, a
+; Copy the Trainer Class to c.
+ ld a, [hli]
+ ld c, a
+; Save hl and bc for later.
+ push hl
+ push bc
+; Get the Trainer Class name and copy it into wBugContestWinnerName.
+ callfar GetTrainerClassName
+ ld hl, wStringBuffer1
+ ld de, wBugContestWinnerName
+ ld bc, TRAINER_CLASS_NAME_LENGTH
+ call CopyBytes
+ ld hl, wBugContestWinnerName
+; Delete the trailing terminator and replace it with a space.
+.next
+ ld a, [hli]
+ cp "@"
+ jr nz, .next
+ dec hl
+ ld [hl], " "
+ inc hl
+ ld d, h
+ ld e, l
+; Restore the Trainer Class ID and Trainer ID pointer. Save de for later.
+ pop bc
+ pop hl
+ push de
+; Get the name of the trainer with class c and ID b.
+ ld a, [hl]
+ ld b, a
+ callfar GetTrainerName
+; Append the name to wBugContestWinnerName.
+ ld hl, wStringBuffer1
+ pop de
+ ld bc, NAME_LENGTH - 1
+ jp CopyBytes
+
+.player
+ ld hl, wPlayerName
+ ld de, wBugContestWinnerName
+ ld bc, NAME_LENGTH
+ jp CopyBytes
+
+INCLUDE "data/events/bug_contest_winners.asm"
+
+BugContest_GetPlayersResult:
+ ld hl, wBugContestThirdPlaceWinnerID
+ ld de, -BUG_CONTESTANT_SIZE
+ ld b, 3 ; 3rd, 2nd, or 1st
+.loop
+ ld a, [hl]
+ cp BUG_CONTEST_PLAYER
+ jr z, .done
+ add hl, de
+ dec b
+ jr nz, .loop
+
+.done
+ ret
+
+BugContest_JudgeContestants:
+ call ClearContestResults
+ call ComputeAIContestantScores
+ ld hl, wBugContestTempWinnerID
+ ld a, BUG_CONTEST_PLAYER
+ ld [hli], a
+ ld a, [wContestMon]
+ ld [hli], a
+ ldh a, [hProduct]
+ ld [hli], a
+ ldh a, [hProduct + 1]
+ ld [hl], a
+ call DetermineContestWinners
+ ret
+
+ClearContestResults:
+ ld hl, wBugContestResults
+ ld b, wBugContestWinnersEnd - wBugContestResults
+ xor a
+.loop
+ ld [hli], a
+ dec b
+ jr nz, .loop
+ ret
+
+DetermineContestWinners:
+ ld de, wBugContestTempScore
+ ld hl, wBugContestFirstPlaceScore
+ ld c, 2
+ call CompareBytes
+ jr c, .not_first_place
+ ld hl, wBugContestSecondPlaceWinnerID
+ ld de, wBugContestThirdPlaceWinnerID
+ ld bc, BUG_CONTESTANT_SIZE
+ call CopyBytes
+ ld hl, wBugContestFirstPlaceWinnerID
+ ld de, wBugContestSecondPlaceWinnerID
+ ld bc, BUG_CONTESTANT_SIZE
+ call CopyBytes
+ ld hl, wBugContestFirstPlaceWinnerID
+ call CopyTempContestant
+ jr .done
+
+.not_first_place
+ ld de, wBugContestTempScore
+ ld hl, wBugContestSecondPlaceScore
+ ld c, 2
+ call CompareBytes
+ jr c, .not_second_place
+ ld hl, wBugContestSecondPlaceWinnerID
+ ld de, wBugContestThirdPlaceWinnerID
+ ld bc, BUG_CONTESTANT_SIZE
+ call CopyBytes
+ ld hl, wBugContestSecondPlaceWinnerID
+ call CopyTempContestant
+ jr .done
+
+.not_second_place
+ ld de, wBugContestTempScore
+ ld hl, wBugContestThirdPlaceScore
+ ld c, 2
+ call CompareBytes
+ jr c, .done
+ ld hl, wBugContestThirdPlaceWinnerID
+ call CopyTempContestant
+
+.done
+ ret
+
+CopyTempContestant:
+; Could've just called CopyBytes.
+ ld de, wBugContestTempWinnerID
+rept BUG_CONTESTANT_SIZE - 1
+ ld a, [de]
+ inc de
+ ld [hli], a
+endr
+ ld a, [de]
+ inc de
+ ld [hl], a
+ ret
+
+ComputeAIContestantScores:
+ ld e, 0
+.loop
+ push de
+ call CheckBugContestContestantFlag
+ pop de
+ jr nz, .done
+ ld a, e
+ inc a
+ inc a
+ ld [wBugContestTempWinnerID], a
+ dec a
+ ld c, a
+ ld b, 0
+ ld hl, BugContestantPointers
+ add hl, bc
+ add hl, bc
+ ld a, [hli]
+ ld h, [hl]
+ ld l, a
+ inc hl
+ inc hl
+.loop2
+ ; 0, 1, or 2 for 1st, 2nd, or 3rd
+ call Random
+ and 3
+ cp 3
+ jr z, .loop2
+ ld c, a
+ ld b, 0
+ add hl, bc
+ add hl, bc
+ add hl, bc
+ ld a, [hli]
+ ld [wBugContestTempMon], a
+ ld a, [hli]
+ ld h, [hl]
+ ld l, a
+ ; randomly perturb score
+ call Random
+ and %111
+ ld c, a
+ ld b, 0
+ add hl, bc
+ ld a, h
+ ld [wBugContestTempScore], a
+ ld a, l
+ ld [wBugContestTempScore + 1], a
+ push de
+ call DetermineContestWinners
+ pop de
+
+.done
+ inc e
+ ld a, e
+ cp NUM_BUG_CONTESTANTS
+ jr nz, .loop
+ ret
+
+ContestScore:
+; Determine the player's score in the Bug Catching Contest.
+
+ xor a
+ ldh [hProduct], a
+ ldh [hMultiplicand], a
+
+ ld a, [wContestMonSpecies] ; Species
+ and a
+ jr z, .done
+
+ ; Tally the following:
+
+ ; Max HP * 4
+ ld a, [wContestMonMaxHP + 1]
+ call .AddContestStat
+ ld a, [wContestMonMaxHP + 1]
+ call .AddContestStat
+ ld a, [wContestMonMaxHP + 1]
+ call .AddContestStat
+ ld a, [wContestMonMaxHP + 1]
+ call .AddContestStat
+
+ ; Stats
+ ld a, [wContestMonAttack + 1]
+ call .AddContestStat
+ ld a, [wContestMonDefense + 1]
+ call .AddContestStat
+ ld a, [wContestMonSpeed + 1]
+ call .AddContestStat
+ ld a, [wContestMonSpclAtk + 1]
+ call .AddContestStat
+ ld a, [wContestMonSpclDef + 1]
+ call .AddContestStat
+
+ ; DVs
+ ld a, [wContestMonDVs + 0]
+ ld b, a
+ and %0010
+ add a
+ add a
+ ld c, a
+
+ swap b
+ ld a, b
+ and %0010
+ add a
+ add c
+ ld d, a
+
+ ld a, [wContestMonDVs + 1]
+ ld b, a
+ and %0010
+ ld c, a
+
+ swap b
+ ld a, b
+ and %0010
+ srl a
+ add c
+ add c
+ add d
+ add d
+
+ call .AddContestStat
+
+ ; Remaining HP / 8
+ ld a, [wContestMonHP + 1]
+ srl a
+ srl a
+ srl a
+ call .AddContestStat
+
+ ; Whether it's holding an item
+ ld a, [wContestMonItem]
+ and a
+ jr z, .done
+
+ ld a, 1
+ call .AddContestStat
+
+.done
+ ret
+
+.AddContestStat:
+ ld hl, hMultiplicand
+ add [hl]
+ ld [hl], a
+ ret nc
+ dec hl
+ inc [hl]
+ ret
diff --git a/engine/events/checkforhiddenitems.asm b/engine/events/checkforhiddenitems.asm
new file mode 100644
index 00000000..c71bd290
--- /dev/null
+++ b/engine/events/checkforhiddenitems.asm
@@ -0,0 +1,83 @@
+CheckForHiddenItems:
+; Checks to see if there are hidden items on the screen that have not yet been found. If it finds one, returns carry.
+ call GetMapScriptsBank
+ ld [wBuffer1], a
+; Get the coordinate of the bottom right corner of the screen, and load it in wBuffer3/wBuffer4.
+ ld a, [wXCoord]
+ add SCREEN_WIDTH / 4
+ ld [wBuffer4], a
+ ld a, [wYCoord]
+ add SCREEN_HEIGHT / 4
+ ld [wBuffer3], a
+; Get the pointer for the first bg_event in the map...
+ ld hl, wCurMapBGEventsPointer
+ ld a, [hli]
+ ld h, [hl]
+ ld l, a
+; ... before even checking to see if there are any BG events on this map.
+ ld a, [wCurMapBGEventCount]
+ and a
+ jr z, .nobgeventitems
+; For i = 1:wCurMapBGEventCount...
+.loop
+; Store the counter in wBuffer2, and store the bg_event pointer in the stack.
+ ld [wBuffer2], a
+ push hl
+; Get the Y coordinate of the BG event.
+ call .GetFarByte
+ ld e, a
+; Is the Y coordinate of the BG event on the screen? If not, go to the next BG event.
+ ld a, [wBuffer3]
+ sub e
+ jr c, .next
+ cp SCREEN_HEIGHT / 2
+ jr nc, .next
+; Is the X coordinate of the BG event on the screen? If not, go to the next BG event.
+ call .GetFarByte
+ ld d, a
+ ld a, [wBuffer4]
+ sub d
+ jr c, .next
+ cp SCREEN_WIDTH / 2
+ jr nc, .next
+; Is this BG event a hidden item? If not, go to the next BG event.
+ call .GetFarByte
+ cp BGEVENT_ITEM
+ jr nz, .next
+; Has this item already been found? If not, set off the Itemfinder.
+ ld a, [wBuffer1]
+ call GetFarHalfword
+ ld a, [wBuffer1]
+ call GetFarHalfword
+ ld d, h
+ ld e, l
+ ld b, CHECK_FLAG
+ call EventFlagAction
+ ld a, c
+ and a
+ jr z, .itemnearby
+
+.next
+; Restore the bg_event pointer and increment it by the length of a bg_event.
+ pop hl
+ ld bc, BG_EVENT_SIZE
+ add hl, bc
+; Restore the BG event counter and decrement it. If it hits zero, there are no hidden items in range.
+ ld a, [wBuffer2]
+ dec a
+ jr nz, .loop
+
+.nobgeventitems
+ xor a
+ ret
+
+.itemnearby
+ pop hl
+ scf
+ ret
+
+.GetFarByte:
+ ld a, [wBuffer1]
+ call GetFarByte
+ inc hl
+ ret
diff --git a/engine/events/checktime.asm b/engine/events/checktime.asm
new file mode 100644
index 00000000..6e470e88
--- /dev/null
+++ b/engine/events/checktime.asm
@@ -0,0 +1,19 @@
+CheckTime::
+ ld a, [wTimeOfDay]
+ ld hl, .TimeOfDayTable
+ ld de, 2
+ call IsInArray
+ inc hl
+ ld c, [hl]
+ ret c
+
+ xor a
+ ld c, a
+ ret
+
+.TimeOfDayTable:
+ db MORN_F, MORN
+ db DAY_F, DAY
+ db NITE_F, NITE
+ db NITE_F, NITE
+ db -1
diff --git a/engine/events/daycare.asm b/engine/events/daycare.asm
index 4cd12087..9cbe61ce 100644
--- a/engine/events/daycare.asm
+++ b/engine/events/daycare.asm
@@ -321,7 +321,7 @@ PrintDayCareText:
.CantAcceptEgg:
; Sorry, but I can't accept an EGG.
- text_far _CantRaiseEggText
+ text_far _CantAcceptEggText
db "@"
.RemoveMail:
@@ -376,7 +376,7 @@ PrintDayCareText:
.NotEnoughMoney:
; You don't have enough money.
- text_far _DCNotEnoughMoneyText
+ text_far _NotEnoughMoneyText
db "@"
.OhFineThen:
@@ -456,7 +456,7 @@ DayCareManOutside:
.IllKeepItThanksText:
; Well then, I'll keep it. Thanks!
- text_far _RefuseEggText
+ text_far _IllKeepItThanksText
db "@"
.PartyFullText:
diff --git a/engine/events/elevator.asm b/engine/events/elevator.asm
new file mode 100644
index 00000000..e51b6be1
--- /dev/null
+++ b/engine/events/elevator.asm
@@ -0,0 +1,215 @@
+Elevator::
+ call .LoadPointer
+ call .FindCurrentFloor
+ jr c, .quit
+ ld [wElevatorOriginFloor], a
+ call Elevator_AskWhichFloor
+ jr c, .quit
+ ld hl, wElevatorOriginFloor
+ cp [hl]
+ jr z, .quit
+ call Elevator_GoToFloor
+ and a
+ ret
+
+.quit
+ scf
+ ret
+
+.LoadPointer:
+ ld a, b
+ ld [wElevatorPointerBank], a
+ ld a, e
+ ld [wElevatorPointer], a
+ ld a, d
+ ld [wElevatorPointer + 1], a
+ call .LoadFloors
+ ret
+
+.LoadFloors:
+ ld de, wCurElevator
+ ld bc, wElevatorDataEnd - wElevatorData
+ ld hl, wElevatorPointer
+ ld a, [hli]
+ ld h, [hl]
+ ld l, a
+ ld a, [wElevatorPointerBank]
+ call GetFarByte
+ inc hl
+ ld [de], a
+ inc de
+.loop
+ ld a, [wElevatorPointerBank]
+ call GetFarByte
+ ld [de], a
+ inc de
+ add hl, bc
+ cp -1
+ jr nz, .loop
+ ret
+
+.FindCurrentFloor:
+ ld hl, wElevatorPointer
+ ld a, [hli]
+ ld h, [hl]
+ ld l, a
+ ld a, [wElevatorPointerBank]
+ call GetFarByte
+ ld c, a
+ inc hl
+ ld a, [wBackupMapGroup]
+ ld d, a
+ ld a, [wBackupMapNumber]
+ ld e, a
+ ld b, 0
+.loop2
+ ld a, [wElevatorPointerBank]
+ call GetFarByte
+ cp -1
+ jr z, .fail
+ inc hl
+ inc hl
+ ld a, [wElevatorPointerBank]
+ call GetFarByte
+ inc hl
+ cp d
+ jr nz, .next1
+ ld a, [wElevatorPointerBank]
+ call GetFarByte
+ inc hl
+ cp e
+ jr nz, .next2
+ jr .done
+
+.next1
+ inc hl
+.next2
+ inc b
+ jr .loop2
+
+.done
+ xor a
+ ld a, b
+ ret
+
+.fail
+ scf
+ ret
+
+Elevator_GoToFloor:
+ push af
+ ld hl, wElevatorPointer
+ ld a, [hli]
+ ld h, [hl]
+ ld l, a
+ inc hl
+ pop af
+ ld bc, wElevatorDataEnd - wElevatorData
+ call AddNTimes
+ inc hl
+ ld de, wBackupWarpNumber
+ ld a, [wElevatorPointerBank]
+ ld bc, wElevatorDataEnd - wElevatorData - 1
+ call FarCopyBytes
+ ret
+
+Elevator_AskWhichFloor:
+ call LoadStandardMenuHeader
+ ld hl, AskFloorElevatorText
+ call PrintText
+ call Elevator_GetCurrentFloorText
+ ld hl, Elevator_MenuHeader
+ call CopyMenuHeader
+ call InitScrollingMenu
+ call UpdateSprites
+ xor a
+ ld [wMenuScrollPosition], a
+ call ScrollingMenu
+ call CloseWindow
+ ld a, [wMenuJoypad]
+ cp B_BUTTON
+ jr z, .cancel
+ xor a
+ ld a, [wScrollingMenuCursorPosition]
+ ret
+
+.cancel
+ scf
+ ret
+
+AskFloorElevatorText:
+ text_far _AskFloorElevatorText
+ text_end
+
+Elevator_GetCurrentFloorText:
+ ld hl, wOptions
+ ld a, [hl]
+ push af
+ set NO_TEXT_SCROLL, [hl]
+ hlcoord 0, 0
+ ld b, 4
+ ld c, 8
+ call Textbox
+ hlcoord 1, 2
+ ld de, Elevator_CurrentFloorText
+ call PlaceString
+ hlcoord 4, 4
+ call Elevator_GetCurrentFloorString
+ pop af
+ ld [wOptions], a
+ ret
+
+Elevator_CurrentFloorText:
+ db "Now on:@"
+
+Elevator_GetCurrentFloorString:
+ push hl
+ ld a, [wElevatorOriginFloor]
+ ld e, a
+ ld d, 0
+ ld hl, wCurElevatorFloors
+ add hl, de
+ ld a, [hl]
+ pop de
+ call GetFloorString
+ ret
+
+Elevator_MenuHeader:
+ db MENU_BACKUP_TILES ; flags
+ menu_coords 12, 1, 18, 9
+ dw Elevator_MenuData
+ db 1 ; default option
+
+Elevator_MenuData:
+ db SCROLLINGMENU_DISPLAY_ARROWS ; flags
+ db 4, 0 ; rows, columns
+ db SCROLLINGMENU_ITEMS_NORMAL ; item format
+ dbw 0, wCurElevator
+ dba GetElevatorFloorStrings
+ dba NULL
+ dba NULL
+
+GetElevatorFloorStrings:
+ ld a, [wMenuSelection]
+GetFloorString:
+ push de
+ call FloorToString
+ ld d, h
+ ld e, l
+ pop hl
+ jp PlaceString
+
+FloorToString:
+ push de
+ ld e, a
+ ld d, 0
+ ld hl, ElevatorFloorNames
+ add hl, de
+ add hl, de
+ ld a, [hli]
+ ld h, [hl]
+ ld l, a
+ pop de
+ ret
+
+INCLUDE "data/events/elevator_floors.asm"
diff --git a/engine/events/engine_flags.asm b/engine/events/engine_flags.asm
new file mode 100755
index 00000000..4099dfda
--- /dev/null
+++ b/engine/events/engine_flags.asm
@@ -0,0 +1,83 @@
+EngineFlagAction::
+; Do action b on engine flag de
+;
+; b = 0: reset flag
+; = 1: set flag
+; > 1: check flag, result in c
+;
+; Setting/resetting does not return a result.
+
+; 16-bit flag ids are considered invalid, but it's nice
+; to know that the infrastructure is there.
+
+ ld a, d
+ cp HIGH(NUM_ENGINE_FLAGS)
+ jr z, .ceiling
+ jr c, .read ; cp 0 can't set carry!
+ jr .invalid
+
+; There are only NUM_ENGINE_FLAGS engine flags, so
+; anything beyond that is invalid too.
+
+.ceiling
+ ld a, e
+ cp LOW(NUM_ENGINE_FLAGS)
+ jr c, .read
+
+; Invalid flags are treated as flag 00.
+
+.invalid
+ xor a
+ ld e, a
+ ld d, a
+
+; Get this flag's location.
+
+.read
+ ld hl, EngineFlags
+; location
+ add hl, de
+ add hl, de
+; bit
+ add hl, de
+
+; location
+ ld e, [hl]
+ inc hl
+ ld d, [hl]
+ inc hl
+; bit
+ ld c, [hl]
+
+; What are we doing with this flag?
+
+ ld a, b
+ cp 1
+ jr c, .reset ; b = 0
+ jr z, .set ; b = 1
+
+; Return the given flag in c.
+.check
+ ld a, [de]
+ and c
+ ld c, a
+ ret
+
+; Set the given flag.
+.set
+ ld a, [de]
+ or c
+ ld [de], a
+ ret
+
+; Reset the given flag.
+.reset
+ ld a, c
+ cpl ; AND all bits except the one in question
+ ld c, a
+ ld a, [de]
+ and c
+ ld [de], a
+ ret
+
+INCLUDE "data/engine_flags.asm"
diff --git a/engine/events/fish.asm b/engine/events/fish.asm
new file mode 100644
index 00000000..8cdcd3f2
--- /dev/null
+++ b/engine/events/fish.asm
@@ -0,0 +1,121 @@
+Fish:
+; Using a fishing rod.
+; Fish for monsters with rod e in encounter group d.
+; Return monster d at level e.
+
+ push af
+ push bc
+ push hl
+
+ ld b, e
+ call GetFishGroupIndex
+
+ ld hl, FishGroups
+rept FISHGROUP_DATA_LENGTH
+ add hl, de
+endr
+ call .Fish
+
+ pop hl
+ pop bc
+ pop af
+ ret
+
+.Fish:
+; Fish for monsters with rod b from encounter data in FishGroup at hl.
+; Return monster d at level e.
+
+ call Random
+ cp [hl]
+ jr nc, .no_bite
+
+ ; Get encounter data by rod:
+ ; 0: Old
+ ; 1: Good
+ ; 2: Super
+ inc hl
+ ld e, b
+ ld d, 0
+ add hl, de
+ add hl, de
+ ld a, [hli]
+ ld h, [hl]
+ ld l, a
+
+ ; Compare the encounter chance to select a Pokemon.
+ call Random
+.loop
+ cp [hl]
+ jr z, .ok
+ jr c, .ok
+ inc hl
+ inc hl
+ inc hl
+ jr .loop
+.ok
+ inc hl
+
+ ; Species 0 reads from a time-based encounter table.
+ ld a, [hli]
+ ld d, a
+ and a
+ call z, .TimeEncounter
+
+ ld e, [hl]
+ ret
+
+.no_bite
+ ld de, 0
+ ret
+
+.TimeEncounter:
+ ; The level byte is repurposed as the index for the new table.
+ ld e, [hl]
+ ld d, 0
+ ld hl, TimeFishGroups
+rept 4
+ add hl, de
+endr
+
+ ld a, [wTimeOfDay]
+ maskbits NUM_DAYTIMES
+ cp NITE_F
+ jr c, .time_species
+ inc hl
+ inc hl
+
+.time_species
+ ld d, [hl]
+ inc hl
+ ret
+
+GetFishGroupIndex:
+; Return the index of fishgroup d in de.
+
+ ld a, d
+ cp FISHGROUP_QWILFISH
+ jr z, .qwilfish
+ cp FISHGROUP_REMORAID
+ jr z, .remoraid
+
+.done
+ dec d
+ ld e, d
+ ld d, 0
+ ret
+
+.qwilfish
+ ld a, [wFishingSwarmFlag]
+ cp FISHSWARM_QWILFISH
+ jr nz, .done
+ ld d, FISHGROUP_QWILFISH_SWARM
+ jr .done
+
+.remoraid
+ ld a, [wFishingSwarmFlag]
+ cp FISHSWARM_REMORAID
+ jr nz, .done
+ ld d, FISHGROUP_REMORAID_SWARM
+ jr .done
+
+INCLUDE "data/wild/fish.asm"
diff --git a/engine/events/forced_movement.asm b/engine/events/forced_movement.asm
index 69f27bfe..fcd2793f 100755
--- a/engine/events/forced_movement.asm
+++ b/engine/events/forced_movement.asm
@@ -1,5 +1,5 @@
Script_ForcedMovement::
- checkcode VAR_FACING
+ readvar VAR_FACING
ifequal DOWN, .down
ifequal UP, .up
ifequal LEFT, .left
diff --git a/engine/events/haircut.asm b/engine/events/haircut.asm
index 55718beb..32043af1 100755
--- a/engine/events/haircut.asm
+++ b/engine/events/haircut.asm
@@ -12,14 +12,14 @@ BillsGrandfather:
ld [wScriptVar], a
ret
-YoungerHaircutBrother:
- ld hl, HappinessData_YoungerHaircutBrother
- jr HaircutOrGrooming
-
OlderHaircutBrother:
ld hl, HappinessData_OlderHaircutBrother
jr HaircutOrGrooming
+YoungerHaircutBrother:
+ ld hl, HappinessData_YoungerHaircutBrother
+ jr HaircutOrGrooming
+
DaisysGrooming:
ld hl, HappinessData_DaisysGrooming
; fallthrough
diff --git a/engine/events/happiness_egg.asm b/engine/events/happiness_egg.asm
index 6c8b918c..bb2e949c 100755
--- a/engine/events/happiness_egg.asm
+++ b/engine/events/happiness_egg.asm
@@ -1,17 +1,17 @@
GetFirstPokemonHappiness:
ld hl, wPartyMon1Happiness
- ld bc, $30
+ ld bc, PARTYMON_STRUCT_LENGTH
ld de, wPartySpecies
-.asm_7275
+.loop
ld a, [de]
cp EGG
- jr nz, .asm_727e
+ jr nz, .done
inc de
add hl, bc
- jr .asm_7275
+ jr .loop
-.asm_727e
- ld [wd151], a
+.done
+ ld [wNamedObjectIndexBuffer], a
ld a, [hl]
ld [wScriptVar], a
call GetPokemonName
@@ -19,67 +19,76 @@ GetFirstPokemonHappiness:
CheckFirstMonIsEgg:
ld a, [wPartySpecies]
- ld [wd151], a
+ ld [wNamedObjectIndexBuffer], a
cp EGG
- ld a, $1
- jr z, .asm_7298
+ ld a, TRUE
+ jr z, .egg
xor a
-.asm_7298
+
+.egg
ld [wScriptVar], a
call GetPokemonName
jp CopyPokemonName_Buffer1_Buffer3
-ChangeHappiness: ; 72a1 (1:72a1)
+ChangeHappiness:
+; Perform happiness action c on wCurPartyMon
+
ld a, [wCurPartyMon]
inc a
ld e, a
- ld d, $0
- ld hl, wPartyCount
+ ld d, 0
+ ld hl, wPartySpecies - 1
add hl, de
ld a, [hl]
- cp $fd
+ cp EGG
ret z
+
push bc
ld hl, wPartyMon1Happiness
- ld bc, $30
+ ld bc, PARTYMON_STRUCT_LENGTH
ld a, [wCurPartyMon]
call AddNTimes
pop bc
+
ld d, h
ld e, l
+
push de
ld a, [de]
- cp $64
- ld e, $0
- jr c, .asm_72ce
+ cp HAPPINESS_THRESHOLD_1
+ ld e, 0
+ jr c, .ok
inc e
- cp $c8
- jr c, .asm_72ce
+ cp HAPPINESS_THRESHOLD_2
+ jr c, .ok
inc e
-.asm_72ce
+
+.ok
dec c
- ld b, $0
- ld hl, .Actions
+ ld b, 0
+ ld hl, HappinessChanges
add hl, bc
add hl, bc
add hl, bc
- ld d, $0
+ ld d, 0
add hl, de
ld a, [hl]
- cp $64
+ cp $64 ; why not $80?
pop de
+
ld a, [de]
- jr nc, .asm_72e8
+ jr nc, .negative
add [hl]
- jr nc, .asm_72ec
- ld a, $ff
- jr .asm_72ec
+ jr nc, .done
+ ld a, -1
+ jr .done
-.asm_72e8
+.negative
add [hl]
- jr c, .asm_72ec
+ jr c, .done
xor a
-.asm_72ec
+
+.done
ld [de], a
ld a, [wBattleMode]
and a
@@ -93,84 +102,76 @@ ChangeHappiness: ; 72a1 (1:72a1)
ld [wBattleMonHappiness], a
ret
-.Actions:
- db +5, +3, +2 ; Gained a level
- db +5, +3, +2 ; Vitamin
- db +1, +1, +0 ; X Item
- db +3, +2, +1 ; Battled a Gym Leader
- db +1, +1, +0 ; Learned a move
- db -1, -1, -1 ; Lost to an enemy
- db -5, -5, -10 ; Fainted due to poison
- db -5, -5, -10 ; Lost to a much stronger enemy
- db +1, +1, +1 ; Haircut (Y1)
- db +3, +3, +1 ; Haircut (Y2)
- db +5, +5, +2 ; Haircut (Y3)
- db +1, +1, +1 ; Haircut (O1)
- db +3, +3, +1 ; Haircut (O2)
- db +10, +10, +4 ; Haircut (O3)
- db -5, -5, -10 ; Used Heal Powder or Energypowder (bitter)
- db -10, -10, -15 ; Used Energy Root (bitter)
- db -15, -15, -20 ; Used Revival Herb (bitter)
- db +3, +3, +1 ; Grooming
+INCLUDE "data/events/happiness_changes.asm"
StepHappiness::
- ld hl, wd9c1
+; Raise the party's happiness by 1 point every other step cycle.
+
+ ld hl, wHappinessStepCount
ld a, [hl]
inc a
- and $1
+ and 1
ld [hl], a
ret nz
+
ld de, wPartyCount
ld a, [de]
and a
ret z
+
ld c, a
ld hl, wPartyMon1Happiness
-.asm_7349
+.loop
inc de
ld a, [de]
cp EGG
- jr z, .asm_7354
+ jr z, .next
inc [hl]
- jr nz, .asm_7354
+ jr nz, .next
ld [hl], $ff
-.asm_7354
+
+.next
push de
- ld de, $30
+ ld de, PARTYMON_STRUCT_LENGTH
add hl, de
pop de
dec c
- jr nz, .asm_7349
+ jr nz, .loop
ret
-MAX_EXP EQU 5242880
+DayCareStep::
+; Raise the experience of Day-Care Pokémon every step cycle.
+
+ ld a, [wDayCareMan]
+ bit DAYCAREMAN_HAS_MON_F, a
+ jr z, .day_care_lady
-DaycareStep::
- CheckFlag ENGINE_DAY_CARE_MAN_HAS_MON
- jr z, .daycare_lady
- ld a, [wBreedMon1Level]
+ ld a, [wBreedMon1Level] ; level
cp MAX_LEVEL
- jr nc, .daycare_lady
- ld hl, wBreedMon1Exp + 2
+ jr nc, .day_care_lady
+ ld hl, wBreedMon1Exp + 2 ; exp
inc [hl]
- jr nz, .daycare_lady
+ jr nz, .day_care_lady
dec hl
inc [hl]
- jr nz, .daycare_lady
+ jr nz, .day_care_lady
dec hl
inc [hl]
ld a, [hl]
- cp MAX_EXP / $10000
- jr c, .daycare_lady
- ld a, MAX_EXP / $10000
+ cp HIGH(MAX_DAY_CARE_EXP >> 8)
+ jr c, .day_care_lady
+ ld a, HIGH(MAX_DAY_CARE_EXP >> 8)
ld [hl], a
-.daycare_lady
- CheckFlag ENGINE_DAY_CARE_LADY_HAS_MON
+
+.day_care_lady
+ ld a, [wDayCareLady]
+ bit DAYCARELADY_HAS_MON_F, a
jr z, .check_egg
- ld a, [wBreedMon2Level]
+
+ ld a, [wBreedMon2Level] ; level
cp MAX_LEVEL
jr nc, .check_egg
- ld hl, wBreedMon2Exp + 2
+ ld hl, wBreedMon2Exp + 2 ; exp
inc [hl]
jr nz, .check_egg
dec hl
@@ -179,13 +180,14 @@ DaycareStep::
dec hl
inc [hl]
ld a, [hl]
- cp MAX_EXP / $10000
+ cp HIGH(MAX_DAY_CARE_EXP >> 8)
jr c, .check_egg
- ld a, MAX_EXP / $10000
+ ld a, HIGH(MAX_DAY_CARE_EXP >> 8)
ld [hl], a
+
.check_egg
ld hl, wDayCareMan
- bit 5, [hl]
+ bit DAYCAREMAN_MONS_COMPATIBLE_F, [hl]
ret z
ld hl, wStepsToEgg
dec [hl]
@@ -194,24 +196,25 @@ DaycareStep::
call Random
ld [hl], a
callfar CheckBreedmonCompatibility
- ld a, [wd151]
+ ld a, [wBreedingCompatibility]
cp 230
- ld b, -1 + 32 percent
+ ld b, 31 percent + 1
jr nc, .okay
- ld a, [wd151]
+ ld a, [wBreedingCompatibility]
cp 170
ld b, 16 percent
jr nc, .okay
- ld a, [wd151]
+ ld a, [wBreedingCompatibility]
cp 110
ld b, 12 percent
jr nc, .okay
ld b, 4 percent
+
.okay
call Random
cp b
ret nc
ld hl, wDayCareMan
- res 5, [hl]
- SetFlagForceReuseHL ENGINE_DAY_CARE_MAN_HAS_EGG
+ res DAYCAREMAN_MONS_COMPATIBLE_F, [hl]
+ set DAYCAREMAN_HAS_EGG_F, [hl]
ret
diff --git a/engine/events/heal_machine_anim.asm b/engine/events/heal_machine_anim.asm
index 9770c35b..002d4ad4 100755
--- a/engine/events/heal_machine_anim.asm
+++ b/engine/events/heal_machine_anim.asm
@@ -134,25 +134,25 @@ ENDM
ret
.PC_ElmsLab_OAM:
- dsprite 4, 0, 4, 2, $7c, PAL_OW_TREE | OBP_NUM
- dsprite 4, 0, 4, 6, $7c, PAL_OW_TREE | OBP_NUM
- dsprite 4, 6, 4, 0, $7d, PAL_OW_TREE | OBP_NUM
- dsprite 4, 6, 5, 0, $7d, PAL_OW_TREE | OBP_NUM | X_FLIP
- dsprite 5, 3, 4, 0, $7d, PAL_OW_TREE | OBP_NUM
- dsprite 5, 3, 5, 0, $7d, PAL_OW_TREE | OBP_NUM | X_FLIP
- dsprite 6, 0, 4, 0, $7d, PAL_OW_TREE | OBP_NUM
- dsprite 6, 0, 5, 0, $7d, PAL_OW_TREE | OBP_NUM | X_FLIP
+ dbsprite 4, 4, 2, 0, $7c, PAL_OW_TREE | OBP_NUM
+ dbsprite 4, 4, 6, 0, $7c, PAL_OW_TREE | OBP_NUM
+ dbsprite 4, 4, 0, 6, $7d, PAL_OW_TREE | OBP_NUM
+ dbsprite 5, 4, 0, 6, $7d, PAL_OW_TREE | OBP_NUM | X_FLIP
+ dbsprite 4, 5, 0, 3, $7d, PAL_OW_TREE | OBP_NUM
+ dbsprite 5, 5, 0, 3, $7d, PAL_OW_TREE | OBP_NUM | X_FLIP
+ dbsprite 4, 6, 0, 0, $7d, PAL_OW_TREE | OBP_NUM
+ dbsprite 5, 6, 0, 0, $7d, PAL_OW_TREE | OBP_NUM | X_FLIP
.HealMachineGFX:
INCBIN "gfx/overworld/heal_machine.2bpp"
.HOF_OAM:
- dsprite 7, 4, 10, 1, $7d, PAL_OW_TREE | OBP_NUM
- dsprite 7, 4, 10, 6, $7d, PAL_OW_TREE | OBP_NUM
- dsprite 7, 3, 9, 5, $7d, PAL_OW_TREE | OBP_NUM
- dsprite 7, 3, 11, 2, $7d, PAL_OW_TREE | OBP_NUM
- dsprite 7, 1, 9, 1, $7d, PAL_OW_TREE | OBP_NUM
- dsprite 7, 1, 11, 5, $7d, PAL_OW_TREE | OBP_NUM
+ dbsprite 10, 7, 1, 4, $7d, PAL_OW_TREE | OBP_NUM
+ dbsprite 10, 7, 6, 4, $7d, PAL_OW_TREE | OBP_NUM
+ dbsprite 9, 7, 5, 3, $7d, PAL_OW_TREE | OBP_NUM
+ dbsprite 11, 7, 2, 3, $7d, PAL_OW_TREE | OBP_NUM
+ dbsprite 9, 7, 1, 1, $7d, PAL_OW_TREE | OBP_NUM
+ dbsprite 11, 7, 5, 1, $7d, PAL_OW_TREE | OBP_NUM
.LoadPalettes:
call IsCGB
@@ -163,7 +163,7 @@ INCBIN "gfx/overworld/heal_machine.2bpp"
.cgb
ld hl, .palettes
- ld de, wOBPal6
+ ld de, wOBPals2 palette PAL_OW_TREE
ld bc, 1 palettes
call CopyBytes
ld a, $1
@@ -171,15 +171,7 @@ INCBIN "gfx/overworld/heal_machine.2bpp"
ret
.palettes
- rst $38
- ld a, a
- ld a, a
- ld a, [hl+]
- rst $38
- inc b
- nop
- nop
-;INCLUDE "gfx/overworld/heal_machine.pal"
+INCLUDE "gfx/overworld/heal_machine.pal"
.FlashPalettes8Times:
ld c, 8
@@ -202,7 +194,7 @@ INCBIN "gfx/overworld/heal_machine.2bpp"
ret
.go
- ld hl, wOBPal6
+ ld hl, wOBPals2 palette PAL_OW_TREE
ld a, [hli]
ld e, a
ld a, [hli]
diff --git a/engine/events/misc_scripts_2.asm b/engine/events/hidden_item.asm
index 4a9e9484..b61a6205 100755..100644
--- a/engine/events/misc_scripts_2.asm
+++ b/engine/events/hidden_item.asm
@@ -1,28 +1,17 @@
-RepelWoreOffScript::
- opentext
- writetext .RepelWoreOffText
- waitbutton
- closetext
- end
-
-.RepelWoreOffText:
- text_far _RepelWoreOffText
- db "@"
-
HiddenItemScript::
opentext
- copybytetovar wcf2b
- itemtotext STRING_BUFFER_3, USE_SCRIPT_VAR
+ readmem wHiddenItemID
+ getitemname STRING_BUFFER_3, USE_SCRIPT_VAR
writetext .PlayerFoundItemText
giveitem ITEM_FROM_MEM
iffalse .bag_full
callasm SetMemEvent
specialsound
itemnotify
- jump .finish
+ sjump .finish
.bag_full
- buttonsound
+ promptbutton
writetext .ButNoSpaceText
waitbutton
@@ -32,14 +21,14 @@ HiddenItemScript::
.PlayerFoundItemText:
text_far _PlayerFoundItemText
- db "@"
+ text_end
.ButNoSpaceText:
text_far _ButNoSpaceText
- db "@"
+ text_end
SetMemEvent:
- ld hl, wcf29
+ ld hl, wHiddenItemEvent
ld a, [hli]
ld d, [hl]
ld e, a
diff --git a/engine/events/itemfinder.asm b/engine/events/itemfinder.asm
new file mode 100644
index 00000000..3665187c
--- /dev/null
+++ b/engine/events/itemfinder.asm
@@ -0,0 +1,50 @@
+ItemFinder:
+ farcall CheckForHiddenItems
+ jr c, .found_something
+ ld hl, .Script_FoundNothing
+ jr .resume
+
+.found_something
+ ld hl, .Script_FoundSomething
+
+.resume
+ call QueueScript
+ ld a, $1
+ ld [wItemEffectSucceeded], a
+ ret
+
+.ItemfinderSound:
+ ld c, 4
+.sfx_loop
+ push bc
+ ld de, SFX_SECOND_PART_OF_ITEMFINDER
+ call WaitPlaySFX
+ ld de, SFX_TRANSACTION
+ call WaitPlaySFX
+ pop bc
+ dec c
+ jr nz, .sfx_loop
+ ret
+
+.Script_FoundSomething:
+ reloadmappart
+ special UpdateTimePals
+ callasm .ItemfinderSound
+ writetext .ItemfinderItemNearbyText
+ closetext
+ end
+
+.Script_FoundNothing:
+ reloadmappart
+ special UpdateTimePals
+ writetext .ItemfinderNopeText
+ closetext
+ end
+
+.ItemfinderItemNearbyText:
+ text_far _ItemfinderItemNearbyText
+ text_end
+
+.ItemfinderNopeText:
+ text_far _ItemfinderNopeText
+ text_end
diff --git a/engine/events/misc_scripts.asm b/engine/events/misc_scripts.asm
index f9ba459f..e9006332 100755
--- a/engine/events/misc_scripts.asm
+++ b/engine/events/misc_scripts.asm
@@ -29,27 +29,27 @@ FindItemInBallScript::
.FoundItemText:
text_far _FoundItemText
- db "@"
+ text_end
.CantCarryItemText:
text_far _CantCarryItemText
- db "@"
+ text_end
.TryReceiveItem:
xor a
ld [wScriptVar], a
- ld a, [wcf29]
- ld [wDeciramBuffer], a
+ ld a, [wItemBallItemID]
+ ld [wNamedObjectIndexBuffer], a
call GetItemName
ld hl, wStringBuffer3
call CopyName2
- ld a, [wcf29]
- ld [wd002], a
- ld a, [wcf2a]
+ ld a, [wItemBallItemID]
+ ld [wCurItem], a
+ ld a, [wItemBallQuantity]
ld [wItemQuantityChangeBuffer], a
ld hl, wNumItems
call ReceiveItem
ret nc
ld a, $1
ld [wScriptVar], a
- ret \ No newline at end of file
+ ret
diff --git a/engine/events/mom.asm b/engine/events/mom.asm
new file mode 100644
index 00000000..18572296
--- /dev/null
+++ b/engine/events/mom.asm
@@ -0,0 +1,676 @@
+BankOfMom:
+ ldh a, [hInMenu]
+ push af
+ ld a, $1
+ ldh [hInMenu], a
+ xor a
+ ld [wJumptableIndex], a
+.loop
+ ld a, [wJumptableIndex]
+ bit 7, a
+ jr nz, .done
+ call .RunJumptable
+ jr .loop
+
+.done
+ pop af
+ ldh [hInMenu], a
+ ret
+
+.RunJumptable:
+ ld a, [wJumptableIndex]
+ ld e, a
+ ld d, 0
+ ld hl, .dw
+ add hl, de
+ add hl, de
+ ld a, [hli]
+ ld h, [hl]
+ ld l, a
+ jp hl
+
+.dw
+
+ dw .CheckIfBankInitialized
+ dw .InitializeBank
+ dw .IsThisAboutYourMoney
+ dw .AccessBankOfMom
+ dw .StoreMoney
+ dw .TakeMoney
+ dw .StopOrStartSavingMoney
+ dw .JustDoWhatYouCan
+ dw .AskDST
+
+.CheckIfBankInitialized:
+ ld a, [wMomSavingMoney]
+ bit MOM_ACTIVE_F, a
+ jr nz, .savingmoneyalready
+ set MOM_ACTIVE_F, a
+ ld [wMomSavingMoney], a
+ ld a, $1
+ jr .done_0
+
+.savingmoneyalready
+ ld a, $2
+
+.done_0
+ ld [wJumptableIndex], a
+ ret
+
+.InitializeBank:
+ ld hl, MomLeavingText1
+ call PrintText
+ call YesNoBox
+ jr c, .DontSaveMoney
+ ld hl, MomLeavingText2
+ call PrintText
+ ld a, (1 << MOM_ACTIVE_F) | (1 << MOM_SAVING_SOME_MONEY_F)
+ jr .done_1
+
+.DontSaveMoney:
+ ld a, 1 << MOM_ACTIVE_F
+
+.done_1
+ ld [wMomSavingMoney], a
+ ld hl, MomLeavingText3
+ call PrintText
+ ld a, $8
+ ld [wJumptableIndex], a
+ ret
+
+.IsThisAboutYourMoney:
+ ld hl, MomIsThisAboutYourMoneyText
+ call PrintText
+ call YesNoBox
+ jr c, .nope
+ ld a, $3
+ jr .done_2
+
+.nope
+ call DSTChecks
+ ld a, $7
+
+.done_2
+ ld [wJumptableIndex], a
+ ret
+
+.AccessBankOfMom:
+ ld hl, MomBankWhatDoYouWantToDoText
+ call PrintText
+ call LoadStandardMenuHeader
+ ld hl, MenuHeader_0x16914
+ call CopyMenuHeader
+ call VerticalMenu
+ call CloseWindow
+ jr c, .cancel
+ ld a, [wMenuCursorY]
+ cp $1
+ jr z, .withdraw
+ cp $2
+ jr z, .deposit
+ cp $3
+ jr z, .stopsaving
+
+.cancel
+ ld a, $7
+ jr .done_3
+
+.withdraw
+ ld a, $5
+ jr .done_3
+
+.deposit
+ ld a, $4
+ jr .done_3
+
+.stopsaving
+ ld a, $6
+
+.done_3
+ ld [wJumptableIndex], a
+ ret
+
+.StoreMoney:
+ ld hl, MomStoreMoneyText
+ call PrintText
+ xor a
+ ld hl, wStringBuffer2
+ ld [hli], a
+ ld [hli], a
+ ld [hl], a
+ ld a, 5
+ ld [wMomBankDigitCursorPosition], a
+ call LoadStandardMenuHeader
+ call Mom_SetUpDepositMenu
+ call Mom_Wait10Frames
+ call Mom_WithdrawDepositMenuJoypad
+ call CloseWindow
+ jr c, .CancelDeposit
+ ld hl, wStringBuffer2
+ ld a, [hli]
+ or [hl]
+ inc hl
+ or [hl]
+ jr z, .CancelDeposit
+ ld de, wMoney
+ ld bc, wStringBuffer2
+ farcall CompareMoney
+ jr c, .InsufficientFundsInWallet
+ ld hl, wStringBuffer2
+ ld de, wStringBuffer2 + 3
+ ld bc, 3
+ call CopyBytes
+ ld bc, wMomsMoney
+ ld de, wStringBuffer2
+ farcall GiveMoney
+ jr c, .NotEnoughRoomInBank
+ ld bc, wStringBuffer2 + 3
+ ld de, wMoney
+ farcall TakeMoney
+ ld hl, wStringBuffer2
+ ld de, wMomsMoney
+ ld bc, 3
+ call CopyBytes
+ ld de, SFX_TRANSACTION
+ call PlaySFX
+ call WaitSFX
+ ld hl, MomStoredMoneyText
+ call PrintText
+ ld a, $8
+ jr .done_4
+
+.InsufficientFundsInWallet:
+ ld hl, MomInsufficientFundsInWalletText
+ call PrintText
+ ret
+
+.NotEnoughRoomInBank:
+ ld hl, MomNotEnoughRoomInBankText
+ call PrintText
+ ret
+
+.CancelDeposit:
+ ld a, $7
+
+.done_4
+ ld [wJumptableIndex], a
+ ret
+
+.TakeMoney:
+ ld hl, MomTakeMoneyText
+ call PrintText
+ xor a
+ ld hl, wStringBuffer2
+ ld [hli], a
+ ld [hli], a
+ ld [hl], a
+ ld a, 5
+ ld [wMomBankDigitCursorPosition], a
+ call LoadStandardMenuHeader
+ call Mom_SetUpWithdrawMenu
+ call Mom_Wait10Frames
+ call Mom_WithdrawDepositMenuJoypad
+ call CloseWindow
+ jr c, .CancelWithdraw
+ ld hl, wStringBuffer2
+ ld a, [hli]
+ or [hl]
+ inc hl
+ or [hl]
+ jr z, .CancelWithdraw
+ ld hl, wStringBuffer2
+ ld de, wStringBuffer2 + 3
+ ld bc, 3
+ call CopyBytes
+ ld de, wMomsMoney
+ ld bc, wStringBuffer2
+ farcall CompareMoney
+ jr c, .InsufficientFundsInBank
+ ld bc, wMoney
+ ld de, wStringBuffer2
+ farcall GiveMoney
+ jr c, .NotEnoughRoomInWallet
+ ld bc, wStringBuffer2 + 3
+ ld de, wMomsMoney
+ farcall TakeMoney
+ ld hl, wStringBuffer2
+ ld de, wMoney
+ ld bc, 3
+ call CopyBytes
+ ld de, SFX_TRANSACTION
+ call PlaySFX
+ call WaitSFX
+ ld hl, MomTakenMoneyText
+ call PrintText
+ ld a, $8
+ jr .done_5
+
+.InsufficientFundsInBank:
+ ld hl, MomHaventSavedThatMuchText
+ call PrintText
+ ret
+
+.NotEnoughRoomInWallet:
+ ld hl, MomNotEnoughRoomInWalletText
+ call PrintText
+ ret
+
+.CancelWithdraw:
+ ld a, $7
+
+.done_5
+ ld [wJumptableIndex], a
+ ret
+
+.StopOrStartSavingMoney:
+ ld hl, MomSaveMoneyText
+ call PrintText
+ call YesNoBox
+ jr c, .StopSavingMoney
+ ld a, (1 << MOM_ACTIVE_F) | (1 << MOM_SAVING_SOME_MONEY_F)
+ ld [wMomSavingMoney], a
+ ld hl, MomStartSavingMoneyText
+ call PrintText
+ ld a, $8
+ ld [wJumptableIndex], a
+ ret
+
+.StopSavingMoney:
+ ld a, 1 << MOM_ACTIVE_F
+ ld [wMomSavingMoney], a
+ ld a, $7
+ ld [wJumptableIndex], a
+ ret
+
+.JustDoWhatYouCan:
+ ld hl, MomJustDoWhatYouCanText
+ call PrintText
+
+.AskDST:
+ ld hl, wJumptableIndex
+ set 7, [hl]
+ ret
+
+DSTChecks:
+; check the time; avoid changing DST if doing so would change the current day
+ ld a, [wDST]
+ bit 7, a
+ ldh a, [hHours]
+ jr z, .NotDST
+ and a ; within one hour of 00:00?
+ jr z, .LostBooklet
+ jr .loop
+
+.NotDST:
+ cp 23 ; within one hour of 23:00?
+ jr nz, .loop
+ ; fallthrough
+
+.LostBooklet:
+ call .ClearBox
+ bccoord 1, 14
+ ld hl, .TimesetAskAdjustDSTText
+ call PlaceHLTextAtBC
+ call YesNoBox
+ ret c
+ call .ClearBox
+ bccoord 1, 14
+ ld hl, .MomLostGearBookletText
+ call PlaceHLTextAtBC
+ ret
+
+.loop
+ call .ClearBox
+ bccoord 1, 14
+ ld a, [wDST]
+ bit 7, a
+ jr z, .SetDST
+ ld hl, .TimesetAskNotDSTText
+ call PlaceHLTextAtBC
+ call YesNoBox
+ ret c
+ ld a, [wDST]
+ res 7, a
+ ld [wDST], a
+ call .SetClockBack
+ predef UpdateTimePredef
+ call .ClearBox
+ bccoord 1, 14
+ ld hl, .TimesetNotDSTText
+ call PlaceHLTextAtBC
+ ret
+
+.SetDST:
+ ld hl, .TimesetAskDSTText
+ call PlaceHLTextAtBC
+ call YesNoBox
+ ret c
+ ld a, [wDST]
+ set 7, a
+ ld [wDST], a
+ call .SetClockForward
+ predef UpdateTimePredef
+ call .ClearBox
+ bccoord 1, 14
+ ld hl, .TimesetDSTText
+ call PlaceHLTextAtBC
+ ret
+
+.SetClockForward:
+ ld a, [wStartHour]
+ add 1
+ sub 24
+ jr nc, .DontLoopHourForward
+ add 24
+.DontLoopHourForward:
+ ld [wStartHour], a
+ ccf
+ ld a, [wStartDay]
+ adc 0
+ ld [wStartDay], a
+ ret
+
+.SetClockBack:
+ ld a, [wStartHour]
+ sub 1
+ jr nc, .DontLoopHourBack
+ add 24
+.DontLoopHourBack:
+ ld [wStartHour], a
+ ld a, [wStartDay]
+ sbc 0
+ jr nc, .DontLoopDayBack
+ add 7
+.DontLoopDayBack:
+ ld [wStartDay], a
+ ret
+
+.ClearBox:
+ hlcoord 1, 14
+ lb bc, 3, 18
+ call ClearBox
+ ret
+
+.TimesetAskAdjustDSTText:
+ text_far _TimesetAskAdjustDSTText
+ text_end
+
+.MomLostGearBookletText:
+ text_far _MomLostGearBookletText
+ text_end
+
+.TimesetAskDSTText:
+ text_far _TimesetAskDSTText
+ text_end
+
+.TimesetDSTText:
+ text_far _TimesetDSTText
+ text_end
+
+.TimesetAskNotDSTText:
+ text_far _TimesetAskNotDSTText
+ text_end
+
+.TimesetNotDSTText:
+ text_far _TimesetNotDSTText
+ text_end
+
+Mom_SetUpWithdrawMenu:
+ ld de, Mon_WithdrawString
+ jr Mom_ContinueMenuSetup
+
+Mom_SetUpDepositMenu:
+ ld de, Mom_DepositString
+Mom_ContinueMenuSetup:
+ push de
+ xor a
+ ldh [hBGMapMode], a
+ hlcoord 0, 0
+ lb bc, 6, 18
+ call Textbox
+ hlcoord 1, 2
+ ld de, Mom_SavedString
+ call PlaceString
+ hlcoord 12, 2
+ ld de, wMomsMoney
+ lb bc, PRINTNUM_MONEY | 3, 6
+ call PrintNum
+ hlcoord 1, 4
+ ld de, Mom_HeldString
+ call PlaceString
+ hlcoord 12, 4
+ ld de, wMoney
+ lb bc, PRINTNUM_MONEY | 3, 6
+ call PrintNum
+ hlcoord 1, 6
+ pop de
+ call PlaceString
+ hlcoord 12, 6
+ ld de, wStringBuffer2
+ lb bc, PRINTNUM_MONEY | PRINTNUM_LEADINGZEROS | 3, 6
+ call PrintNum
+ call UpdateSprites
+ call CGBOnly_CopyTilemapAtOnce
+ ret
+
+Mom_Wait10Frames:
+ ld c, 10
+ call DelayFrames
+ ret
+
+Mom_WithdrawDepositMenuJoypad:
+.loop
+ call JoyTextDelay
+ ld hl, hJoyPressed
+ ld a, [hl]
+ and B_BUTTON
+ jr nz, .pressedB
+ ld a, [hl]
+ and A_BUTTON
+ jr nz, .pressedA
+ call .dpadaction
+ xor a
+ ldh [hBGMapMode], a
+ hlcoord 12, 6
+ ld bc, 7
+ ld a, " "
+ call ByteFill
+ hlcoord 12, 6
+ ld de, wStringBuffer2
+ lb bc, PRINTNUM_MONEY | PRINTNUM_LEADINGZEROS | 3, 6
+ call PrintNum
+ ldh a, [hVBlankCounter]
+ and $10
+ jr nz, .skip
+ hlcoord 13, 6
+ ld a, [wMomBankDigitCursorPosition]
+ ld c, a
+ ld b, 0
+ add hl, bc
+ ld [hl], " "
+
+.skip
+ call WaitBGMap
+ jr .loop
+
+.pressedB
+ scf
+ ret
+
+.pressedA
+ and a
+ ret
+
+.dpadaction
+ ld hl, hJoyLast
+ ld a, [hl]
+ and D_UP
+ jr nz, .incrementdigit
+ ld a, [hl]
+ and D_DOWN
+ jr nz, .decrementdigit
+ ld a, [hl]
+ and D_LEFT
+ jr nz, .movecursorleft
+ ld a, [hl]
+ and D_RIGHT
+ jr nz, .movecursorright
+ and a
+ ret
+
+.movecursorleft
+ ld hl, wMomBankDigitCursorPosition
+ ld a, [hl]
+ and a
+ ret z
+ dec [hl]
+ ret
+
+.movecursorright
+ ld hl, wMomBankDigitCursorPosition
+ ld a, [hl]
+ cp 5
+ ret nc
+ inc [hl]
+ ret
+
+.incrementdigit
+ ld hl, .DigitQuantities
+ call .getdigitquantity
+ ld c, l
+ ld b, h
+ ld de, wStringBuffer2
+ farcall GiveMoney
+ ret
+
+.decrementdigit
+ ld hl, .DigitQuantities
+ call .getdigitquantity
+ ld c, l
+ ld b, h
+ ld de, wStringBuffer2
+ farcall TakeMoney
+ ret
+
+.getdigitquantity
+ ld a, [wMomBankDigitCursorPosition]
+ push de
+ ld e, a
+ ld d, 0
+ add hl, de
+ add hl, de
+ add hl, de
+ pop de
+ ret
+
+.DigitQuantities:
+ dt 100000
+ dt 10000
+ dt 1000
+ dt 100
+ dt 10
+ dt 1
+
+ dt 100000
+ dt 10000
+ dt 1000
+ dt 100
+ dt 10
+ dt 1
+
+ dt 900000
+ dt 90000
+ dt 9000
+ dt 900
+ dt 90
+ dt 9
+
+MomLeavingText1:
+ text_far _MomLeavingText1
+ text_end
+
+MomLeavingText2:
+ text_far _MomLeavingText2
+ text_end
+
+MomLeavingText3:
+ text_far _MomLeavingText3
+ text_end
+
+MomIsThisAboutYourMoneyText:
+ text_far _MomIsThisAboutYourMoneyText
+ text_end
+
+MomBankWhatDoYouWantToDoText:
+ text_far _MomBankWhatDoYouWantToDoText
+ text_end
+
+MomStoreMoneyText:
+ text_far _MomStoreMoneyText
+ text_end
+
+MomTakeMoneyText:
+ text_far _MomTakeMoneyText
+ text_end
+
+MomSaveMoneyText:
+ text_far _MomSaveMoneyText
+ text_end
+
+MomHaventSavedThatMuchText:
+ text_far _MomHaventSavedThatMuchText
+ text_end
+
+MomNotEnoughRoomInWalletText:
+ text_far _MomNotEnoughRoomInWalletText
+ text_end
+
+MomInsufficientFundsInWalletText:
+ text_far _MomInsufficientFundsInWalletText
+ text_end
+
+MomNotEnoughRoomInBankText:
+ text_far _MomNotEnoughRoomInBankText
+ text_end
+
+MomStartSavingMoneyText:
+ text_far _MomStartSavingMoneyText
+ text_end
+
+MomStoredMoneyText:
+ text_far _MomStoredMoneyText
+ text_end
+
+MomTakenMoneyText:
+ text_far _MomTakenMoneyText
+ text_end
+
+MomJustDoWhatYouCanText:
+ text_far _MomJustDoWhatYouCanText
+ text_end
+
+Mom_SavedString:
+ db "SAVED@"
+
+Mon_WithdrawString:
+ db "WITHDRAW@"
+
+Mom_DepositString:
+ db "DEPOSIT@"
+
+Mom_HeldString:
+ db "HELD@"
+
+MenuHeader_0x16914:
+ db MENU_BACKUP_TILES ; flags
+ menu_coords 0, 0, 10, 10
+ dw MenuData_0x1691c
+ db 1 ; default option
+
+MenuData_0x1691c:
+ db STATICMENU_CURSOR ; flags
+ db 4 ; items
+ db "GET@"
+ db "SAVE@"
+ db "CHANGE@"
+ db "CANCEL@"
diff --git a/engine/events/money.asm b/engine/events/money.asm
new file mode 100644
index 00000000..c8f9d058
--- /dev/null
+++ b/engine/events/money.asm
@@ -0,0 +1,209 @@
+GiveMoney::
+ ld a, 3
+ call AddMoney
+ ld bc, MaxMoney
+ ld a, 3
+ call CompareMoney
+ jr z, .not_maxed_out
+ jr c, .not_maxed_out
+ ld hl, MaxMoney
+ ld a, [hli]
+ ld [de], a
+ inc de
+ ld a, [hli]
+ ld [de], a
+ inc de
+ ld a, [hli]
+ ld [de], a
+ scf
+ ret
+
+.not_maxed_out
+ and a
+ ret
+
+MaxMoney:
+ dt MAX_MONEY
+
+TakeMoney::
+ ld a, 3
+ call SubtractMoney
+ jr nc, .okay
+ ; leave with 0 money
+ xor a
+ ld [de], a
+ inc de
+ ld [de], a
+ inc de
+ ld [de], a
+ scf
+ ret
+
+.okay
+ and a
+ ret
+
+CompareMoney::
+ ld a, 3
+CompareFunds:
+; a: number of bytes
+; bc: start addr of amount (big-endian)
+; de: start addr of account (big-endian)
+ push hl
+ push de
+ push bc
+ ld h, b
+ ld l, c
+ ld c, 0
+ ld b, a
+.loop1
+ dec a
+ jr z, .done
+ inc de
+ inc hl
+ jr .loop1
+
+.done
+ and a
+.loop2
+ ld a, [de]
+ sbc [hl]
+ jr z, .okay
+ inc c
+
+.okay
+ dec de
+ dec hl
+ dec b
+ jr nz, .loop2
+ jr c, .set_carry
+ ld a, c
+ and a
+ jr .skip_carry
+
+.set_carry
+ ld a, 1
+ and a
+ scf
+.skip_carry
+ pop bc
+ pop de
+ pop hl
+ ret
+
+SubtractMoney:
+ ld a, 3
+SubtractFunds:
+; a: number of bytes
+; bc: start addr of amount (big-endian)
+; de: start addr of account (big-endian)
+ push hl
+ push de
+ push bc
+ ld h, b
+ ld l, c
+ ld b, a
+ ld c, 0
+.loop
+ dec a
+ jr z, .done
+ inc de
+ inc hl
+ jr .loop
+
+.done
+ and a
+.loop2
+ ld a, [de]
+ sbc [hl]
+ ld [de], a
+ dec de
+ dec hl
+ dec b
+ jr nz, .loop2
+ pop bc
+ pop de
+ pop hl
+ ret
+
+AddMoney:
+ ld a, 3
+AddFunds:
+; a: number of bytes
+; bc: start addr of amount (big-endian)
+; de: start addr of account (big-endian)
+ push hl
+ push de
+ push bc
+
+ ld h, b
+ ld l, c
+ ld b, a
+.loop1
+ dec a
+ jr z, .done
+ inc de
+ inc hl
+ jr .loop1
+
+.done
+ and a
+.loop2
+ ld a, [de]
+ adc [hl]
+ ld [de], a
+ dec de
+ dec hl
+ dec b
+ jr nz, .loop2
+
+ pop bc
+ pop de
+ pop hl
+ ret
+
+GiveCoins::
+ ld a, 2
+ ld de, wCoins
+ call AddFunds
+ ld a, 2
+ ld bc, .maxcoins
+ call CompareFunds
+ jr c, .not_maxed
+ ld hl, .maxcoins
+ ld a, [hli]
+ ld [de], a
+ inc de
+ ld a, [hli]
+ ld [de], a
+ scf
+ ret
+
+.not_maxed
+ and a
+ ret
+
+.maxcoins
+ bigdw MAX_COINS
+
+TakeCoins::
+ ld a, 2
+ ld de, wCoins
+ call SubtractFunds
+ jr nc, .okay
+ ; leave with 0 coins
+ xor a
+ ld [de], a
+ inc de
+ ld [de], a
+ scf
+ ret
+
+.okay
+ and a
+ ret
+
+CheckCoins::
+ ld a, 2
+ ld de, wCoins
+ jp CompareFunds
diff --git a/engine/events/move_deleter.asm b/engine/events/move_deleter.asm
new file mode 100644
index 00000000..f9f83fab
--- /dev/null
+++ b/engine/events/move_deleter.asm
@@ -0,0 +1,150 @@
+MoveDeletion:
+ ld hl, .DeleterIntroText
+ call PrintText
+ call YesNoBox
+ jr c, .declined
+ ld hl, .DeleterAskWhichMonText
+ call PrintText
+ farcall SelectMonFromParty
+ jr c, .declined
+ ld a, [wCurPartySpecies]
+ cp EGG
+ jr z, .egg
+ ld a, [wCurPartyMon]
+ ld hl, wPartyMon1Moves + 1
+ ld bc, PARTYMON_STRUCT_LENGTH
+ call AddNTimes
+ ld a, [hl]
+ and a
+ jr z, .onlyonemove
+ ld hl, .DeleterAskWhichMoveText
+ call PrintText
+ call LoadStandardMenuHeader
+ farcall ChooseMoveToDelete
+ push af
+ call ReturnToMapWithSpeechTextbox
+ pop af
+ jr c, .declined
+ ld a, [wMenuCursorY]
+ push af
+ ld a, [wCurSpecies]
+ ld [wNamedObjectIndexBuffer], a
+ call GetMoveName
+ ld hl, .AskDeleteMoveText
+ call PrintText
+ call YesNoBox
+ pop bc
+ jr c, .declined
+ call .DeleteMove
+ call WaitSFX
+ ld de, SFX_MOVE_DELETED
+ call PlaySFX
+ call WaitSFX
+ ld hl, .DeleterForgotMoveText
+ call PrintText
+ ret
+
+.egg
+ ld hl, .MailEggText
+ call PrintText
+ ret
+
+.declined
+ ld hl, .DeleterNoComeAgainText
+ call PrintText
+ ret
+
+.onlyonemove
+ ld hl, .MoveKnowsOneText
+ call PrintText
+ ret
+
+.MoveKnowsOneText:
+ text_far _MoveKnowsOneText
+ text_end
+
+.AskDeleteMoveText:
+ text_far _AskDeleteMoveText
+ text_end
+
+.DeleterForgotMoveText:
+ text_far _DeleterForgotMoveText
+ text_end
+
+.MailEggText:
+ text_far _DeleterEggText
+ text_end
+
+.DeleterNoComeAgainText:
+ text_far _DeleterNoComeAgainText
+ text_end
+
+.DeleterAskWhichMoveText:
+ text_far _DeleterAskWhichMoveText
+ text_end
+
+.DeleterIntroText:
+ text_far _DeleterIntroText
+ text_end
+
+.DeleterAskWhichMonText:
+ text_far _DeleterAskWhichMonText
+ text_end
+
+.DeleteMove:
+ ld a, b
+ push bc
+ dec a
+ ld c, a
+ ld b, 0
+ ld hl, wPartyMon1Moves
+ add hl, bc
+ ld a, [wCurPartyMon]
+ ld bc, PARTYMON_STRUCT_LENGTH
+ call AddNTimes
+ pop bc
+ push bc
+ inc b
+.loop
+ ld a, b
+ cp NUM_MOVES + 1
+ jr z, .okay
+ inc hl
+ ld a, [hld]
+ ld [hl], a
+ inc hl
+ inc b
+ jr .loop
+
+.okay
+ xor a
+ ld [hl], a
+ pop bc
+
+ ld a, b
+ push bc
+ dec a
+ ld c, a
+ ld b, 0
+ ld hl, wPartyMon1PP
+ add hl, bc
+ ld a, [wCurPartyMon]
+ ld bc, PARTYMON_STRUCT_LENGTH
+ call AddNTimes
+ pop bc
+ inc b
+.loop2
+ ld a, b
+ cp NUM_MOVES + 1
+ jr z, .done
+ inc hl
+ ld a, [hld]
+ ld [hl], a
+ inc hl
+ inc b
+ jr .loop2
+
+.done
+ xor a
+ ld [hl], a
+ ret
diff --git a/engine/events/overworld.asm b/engine/events/overworld.asm
index 0787d094..4f2ba801 100755
--- a/engine/events/overworld.asm
+++ b/engine/events/overworld.asm
@@ -1,407 +1,390 @@
-FieldMoveBufferReset: ; c72f (3:472f)
+FieldMoveJumptableReset:
xor a
ld hl, wBuffer1
- ld bc, $7
+ ld bc, 7
call ByteFill
ret
-DoFieldMoveAction: ; c73a (3:473a)
+FieldMoveJumptable:
ld a, [wBuffer1]
rst JumpTable
ld [wBuffer1], a
bit 7, a
- jr nz, .asm_c747
+ jr nz, .okay
and a
ret
-.asm_c747
+.okay
and $7f
scf
ret
-FieldMoveGetPartyNick: ; c74b (3:474b)
- ld hl, wPartyMon1Nickname
- ld a, $2
+GetPartyNick:
+; write wCurPartyMon nickname to wStringBuffer1-3
+ ld hl, wPartyMonNicknames
+ ld a, BOXMON
ld [wMonType], a
ld a, [wCurPartyMon]
call GetNick
call CopyName1
+; copy text from wStringBuffer2 to wStringBuffer3
ld de, wStringBuffer2
ld hl, wStringBuffer3
call CopyName2
ret
-FieldMoveEngineFlagCheck: ; c766 (3:4766)
+CheckEngineFlag:
+; Check engine flag de
+; Return carry if flag is not set
ld b, CHECK_FLAG
- farcall EngineFlagAction ; same bank
+ farcall EngineFlagAction
ld a, c
and a
- jr nz, .asm_c774
+ jr nz, .isset
scf
ret
-
-.asm_c774
+.isset
xor a
ret
-FieldMoveBadgeCheck: ; c776 (3:4776)
- call FieldMoveEngineFlagCheck
+CheckBadge:
+; Check engine flag a (ENGINE_ZEPHYRBADGE thru ENGINE_EARTHBADGE)
+; Display "Badge required" text and return carry if the badge is not owned
+ call CheckEngineFlag
ret nc
ld hl, .BadgeRequiredText
- call MenuTextboxBackup
+ call MenuTextboxBackup ; push text to queue
scf
ret
.BadgeRequiredText:
- text_far BadgeRequiredText_
- db "@"
+ text_far _BadgeRequiredText
+ text_end
-FieldMovePartyCheck: ; c787 (3:4787)
- ld e, $0
+CheckPartyMove:
+; Check if a monster in your party has move d.
+
+ ld e, 0
xor a
ld [wCurPartyMon], a
-.asm_c78d
+.loop
ld c, e
- ld b, $0
+ ld b, 0
ld hl, wPartySpecies
add hl, bc
ld a, [hl]
and a
- jr z, .asm_c7bc
+ jr z, .no
cp -1
- jr z, .asm_c7bc
+ jr z, .no
cp EGG
- jr z, .asm_c7b3
+ jr z, .next
+
ld bc, PARTYMON_STRUCT_LENGTH
ld hl, wPartyMon1Moves
ld a, e
call AddNTimes
ld b, NUM_MOVES
-.asm_c7ac
+.check
ld a, [hli]
cp d
- jr z, .asm_c7b6
+ jr z, .yes
dec b
- jr nz, .asm_c7ac
-.asm_c7b3
+ jr nz, .check
+
+.next
inc e
- jr .asm_c78d
+ jr .loop
-.asm_c7b6
+.yes
ld a, e
- ld [wCurPartyMon], a
+ ld [wCurPartyMon], a ; which mon has the move
xor a
ret
-
-.asm_c7bc
+.no
scf
ret
-FieldMoveFailed: ; c7be (3:47be)
- ld hl, .CantUseHereText
+FieldMoveFailed:
+ ld hl, .CantUseItemText
call MenuTextboxBackup
ret
-.CantUseHereText:
- text_far CantUseFieldMoveHereText_
- db "@"
+.CantUseItemText:
+ text_far _CantUseItemText
+ text_end
-CutFunction::
- call FieldMoveBufferReset
-.asm_c7cd
+CutFunction:
+ call FieldMoveJumptableReset
+.loop
ld hl, .Jumptable
- call DoFieldMoveAction
- jr nc, .asm_c7cd
+ call FieldMoveJumptable
+ jr nc, .loop
and $7f
ld [wFieldMoveSucceeded], a
ret
.Jumptable:
- dw CheckAbleToCut
- dw CutTreeOrGrass
- dw FailToCut
+ dw .CheckAble
+ dw .DoCut
+ dw .FailCut
-CheckAbleToCut:
+.CheckAble:
ld de, ENGINE_HIVEBADGE
- call FieldMoveBadgeCheck
- jr c, .asm_c7f1
+ call CheckBadge
+ jr c, .nohivebadge
call CheckMapForSomethingToCut
- jr c, .asm_c7f4
+ jr c, .nothingtocut
ld a, $1
ret
-.asm_c7f1
+.nohivebadge
ld a, $80
ret
-.asm_c7f4
+.nothingtocut
ld a, $2
ret
-CutTreeOrGrass:
+.DoCut:
ld hl, Script_CutFromMenu
call QueueScript
ld a, $81
ret
-FailToCut:
- ld hl, Text_NothingToCut
+.FailCut:
+ ld hl, CutNothingText
call MenuTextboxBackup
ld a, $80
ret
-Text_UsedCut:
- text_far Text_UsedCut_
- db "@"
+UseCutText:
+ text_far _UseCutText
+ text_end
-Text_NothingToCut:
- text_far Text_NothingToCut_
- db "@"
+CutNothingText:
+ text_far _CutNothingText
+ text_end
-CheckMapForSomethingToCut: ; c813 (3:4813)
+CheckMapForSomethingToCut:
+ ; Does the collision data of the facing tile permit cutting?
call GetFacingTileCoord
ld c, a
push de
farcall CheckCutCollision
pop de
- jr nc, .asm_c841
+ jr nc, .fail
+ ; Get the location of the current block in wOverworldMapBlocks.
call GetBlockLocation
ld c, [hl]
+ ; See if that block contains something that can be cut.
push hl
ld hl, CutTreeBlockPointers
call CheckOverworldTileArrays
pop hl
- jr nc, .asm_c841
+ jr nc, .fail
+ ; Back up the wOverworldMapBlocks address to wBuffer3
ld a, l
ld [wBuffer3], a
ld a, h
ld [wBuffer4], a
+ ; Back up the replacement tile to wBuffer5
ld a, b
ld [wBuffer5], a
+ ; Back up the animation index to wBuffer6
ld a, c
ld [wBuffer6], a
xor a
ret
-.asm_c841
+.fail
scf
ret
Script_CutFromMenu:
reloadmappart
special UpdateTimePals
+
Script_Cut:
- callasm FieldMoveGetPartyNick
- writetext Text_UsedCut
+ callasm GetPartyNick
+ writetext UseCutText
reloadmappart
callasm CutDownTreeOrGrass
closetext
end
CutDownTreeOrGrass:
- ld hl, wBuffer3
+ ld hl, wBuffer3 ; OverworldMapTile
ld a, [hli]
ld h, [hl]
ld l, a
- ld a, [wBuffer5]
+ ld a, [wBuffer5] ; ReplacementTile
ld [hl], a
xor a
ldh [hBGMapMode], a
call OverworldTextModeSwitch
call UpdateSprites
call DelayFrame
- ld a, [wBuffer6]
+ ld a, [wBuffer6] ; Animation type
ld e, a
farcall OWCutAnimation
call BufferScreen
call GetMovementPermissions
ret
-CheckOverworldTileArrays: ; c87c (3:487c)
+CheckOverworldTileArrays:
+ ; Input: c contains the tile you're facing
+ ; Output: Replacement tile in b and effect on wild encounters in c, plus carry set.
+ ; Carry is not set if the facing tile cannot be replaced, or if the tileset
+ ; does not contain a tile you can replace.
+
+ ; Dictionary lookup for pointer to tile replacement table
push bc
- ld a, [wd082]
- ld de, $3
+ ld a, [wMapTileset]
+ ld de, 3
call IsInArray
pop bc
- jr nc, .asm_c89c
+ jr nc, .nope
+ ; Load the pointer
inc hl
ld a, [hli]
ld h, [hl]
ld l, a
- ld de, $3
+ ; Look up the tile you're facing
+ ld de, 3
ld a, c
call IsInArray
- jr nc, .asm_c89c
+ jr nc, .nope
+ ; Load the replacement to b
inc hl
ld b, [hl]
+ ; Load the animation type parameter to c
inc hl
ld c, [hl]
scf
ret
-.asm_c89c
+.nope
xor a
ret
-CutTreeBlockPointers:
- dbw TILESET_JOHTO, .johto1
- dbw TILESET_JOHTO_MODERN, .johto2
- dbw TILESET_KANTO, .kanto
- dbw TILESET_PARK, .park
- dbw TILESET_FOREST, .ilex
- db -1
-
-.johto1
- db $03, $02, $01 ; grass
- db $5b, $3c, $00 ; tree
- db $5f, $3d, $00 ; tree
- db $63, $3f, $00 ; tree
- db $67, $3e, $00 ; tree
- db -1
-
-.johto2
- db $03, $02, $01 ; grass
- db -1
-
-.kanto
- db $0b, $0a, $01 ; grass
- db $32, $6d, $00 ; tree
- db $33, $6c, $00 ; tree
- db $34, $6f, $00 ; tree
- db $35, $4c, $00 ; tree
- db $60, $6e, $00 ; tree
- db -1
-
-.park
- db $13, $03, $01 ; grass
- db $03, $04, $01 ; grass
- db -1
-
-.ilex
- db $0f, $17, $00
- db -1
-
-WhirlpoolBlockPointers:
- dbw TILESET_JOHTO, .johto
- db -1
-
-.johto
- db $07, $36, $00
- db -1
+INCLUDE "data/events/field_move_blocks.asm"
FlashFunction:
- call CheckUseFlash
+ call .CheckUseFlash
and $7f
ld [wFieldMoveSucceeded], a
ret
-CheckUseFlash: ; c8f1 (3:48f1)
+.CheckUseFlash:
+; Flash
ld de, ENGINE_ZEPHYRBADGE
- farcall FieldMoveBadgeCheck ; same bank
- jr c, .asm_c90f
- ld a, [wd56e]
- cp $ff
- jr nz, .asm_c909
+ farcall CheckBadge
+ jr c, .nozephyrbadge
+ ld a, [wTimeOfDayPalset]
+ cp %11111111 ; 3, 3, 3, 3
+ jr nz, .notadarkcave
+.useflash
call UseFlash
ld a, $81
ret
-.asm_c909
+.notadarkcave
call FieldMoveFailed
ld a, $80
ret
-.asm_c90f
+.nozephyrbadge
ld a, $80
ret
-UseFlash: ; c912 (3:4912)
+UseFlash:
ld hl, Script_UseFlash
jp QueueScript
Script_UseFlash:
reloadmappart
special UpdateTimePals
- writetext Text_UsedFlash
+ writetext UseFlashTextScript
callasm BlindingFlash
closetext
end
-Text_UsedFlash:
- text_far Text_UsedFlash_
+UseFlashTextScript:
+ text_far _BlindingFlashText
text_asm
call WaitSFX
ld de, SFX_FLASH
call PlaySFX
call WaitSFX
- ld hl, .end
+ ld hl, .BlankText
ret
-.end db "@"
+
+.BlankText:
+ text_end
SurfFunction:
- call FieldMoveBufferReset
-.asm_c93e
+ call FieldMoveJumptableReset
+.loop
ld hl, .Jumptable
- call DoFieldMoveAction
- jr nc, .asm_c93e
+ call FieldMoveJumptable
+ jr nc, .loop
and $7f
ld [wFieldMoveSucceeded], a
ret
.Jumptable:
- dw CheckAbleToSurf
- dw StartSurfing
- dw CantSurf
- dw AlreadySurfing
+ dw .TrySurf
+ dw .DoSurf
+ dw .FailSurf
+ dw .AlreadySurfing
-CheckAbleToSurf:
+.TrySurf:
ld de, ENGINE_FOGBADGE
- call FieldMoveBadgeCheck
+ call CheckBadge
jr c, .asm_c980
- CheckFlagHL ENGINE_ALWAYS_ON_BIKE
- jr nz, .asm_c986
+ ld hl, wBikeFlags
+ bit BIKEFLAGS_ALWAYS_ON_BIKE_F, [hl]
+ jr nz, .cannotsurf
ld a, [wPlayerState]
cp PLAYER_SURF
- jr z, .asm_c983
+ jr z, .alreadyfail
cp PLAYER_SURF_PIKA
- jr z, .asm_c983
+ jr z, .alreadyfail
call GetFacingTileCoord
call GetTileCollision
- cp $1
- jr nz, .asm_c986
- call GetSurfDirection
- jr c, .asm_c986
+ cp WATER_TILE
+ jr nz, .cannotsurf
+ call CheckDirection
+ jr c, .cannotsurf
ld a, $1
ret
-
.asm_c980
ld a, $80
ret
-
-.asm_c983
+.alreadyfail
ld a, $3
ret
-
-.asm_c986
+.cannotsurf
ld a, $2
ret
-StartSurfing:
+.DoSurf:
call GetSurfType
ld [wBuffer2], a
- call FieldMoveGetPartyNick
+ call GetPartyNick
ld hl, SurfFromMenuScript
call QueueScript
ld a, $81
ret
-CantSurf:
+.FailSurf:
ld hl, CantSurfText
call MenuTextboxBackup
ld a, $80
ret
-AlreadySurfing:
+.AlreadySurfing:
ld hl, AlreadySurfingText
call MenuTextboxBackup
ld a, $80
@@ -409,36 +392,44 @@ AlreadySurfing:
SurfFromMenuScript:
special UpdateTimePals
+
UsedSurfScript:
- writetext UsedSurfText
+ writetext UsedSurfText ; "used SURF!"
waitbutton
closetext
- copybytetovar wBuffer2
- writevarcode VAR_MOVEMENT
- special ReplacePlayerSprite
+
+ readmem wBuffer2
+ writevar VAR_MOVEMENT
+
+ special ReplaceChrisSprite
special PlayMapMusic
+; step into the water (slow_step DIR, step_end)
special SurfStartStep
- applymovement 0, wMovementBuffer
+ applymovement PLAYER, wMovementBuffer
end
UsedSurfText:
- text_far UsedSurfText_
- db "@"
+ text_far _UsedSurfText
+ text_end
CantSurfText:
- text_far CantSurfText_
- db "@"
+ text_far _CantSurfText
+ text_end
AlreadySurfingText:
- text_far AlreadySurfingText_
- db "@"
+ text_far _AlreadySurfingText
+ text_end
+
+GetSurfType:
+; Surfing on Pikachu uses an alternate sprite.
+; This is done by using a separate movement type.
-GetSurfType: ; c9d7 (3:49d7)
ld a, [wCurPartyMon]
ld e, a
- ld d, $0
+ ld d, 0
ld hl, wPartySpecies
add hl, de
+
ld a, [hl]
cp PIKACHU
ld a, PLAYER_SURF_PIKA
@@ -446,22 +437,28 @@ GetSurfType: ; c9d7 (3:49d7)
ld a, PLAYER_SURF
ret
-GetSurfDirection: ; c9ea (3:49ea)
+CheckDirection:
+; Return carry if a tile permission prevents you
+; from moving in the direction you're facing.
+
+; Get player direction
ld a, [wPlayerDirection]
- and $c
+ and %00001100 ; bits 2 and 3 contain direction
rrca
rrca
ld e, a
- ld d, $0
+ ld d, 0
ld hl, .Directions
add hl, de
+
+; Can you walk in this direction?
ld a, [wTilePermissions]
and [hl]
- jr nz, .asm_ca00
+ jr nz, .quit
xor a
ret
-.asm_ca00
+.quit
scf
ret
@@ -472,31 +469,46 @@ GetSurfDirection: ; c9ea (3:49ea)
db FACE_RIGHT
TrySurfOW::
+; Checking a tile in the overworld.
+; Return carry if fail is allowed.
+
+; Don't ask to surf if already fail.
ld a, [wPlayerState]
cp PLAYER_SURF_PIKA
jr z, .quit
cp PLAYER_SURF
jr z, .quit
- ld a, [wcf29]
+
+; Must be facing water.
+ ld a, [wFacingTileID]
call GetTileCollision
- cp $1
+ cp WATER_TILE
jr nz, .quit
- call GetSurfDirection
+
+; Check tile permissions.
+ call CheckDirection
jr c, .quit
+
ld de, ENGINE_FOGBADGE
- call FieldMoveEngineFlagCheck
+ call CheckEngineFlag
jr c, .quit
+
ld d, SURF
- call FieldMovePartyCheck
+ call CheckPartyMove
jr c, .quit
- CheckFlagHL ENGINE_ALWAYS_ON_BIKE
+
+ ld hl, wBikeFlags
+ bit BIKEFLAGS_ALWAYS_ON_BIKE_F, [hl]
jr nz, .quit
+
call GetSurfType
ld [wBuffer2], a
- call FieldMoveGetPartyNick
+ call GetPartyNick
+
ld a, BANK(AskSurfScript)
ld hl, AskSurfScript
call CallScript
+
scf
ret
@@ -513,150 +525,152 @@ AskSurfScript:
end
AskSurfText:
- text_far AskSurfText_
- db "@"
+ text_far _AskSurfText
+ text_end
FlyFunction:
- call FieldMoveBufferReset
-.asm_ca5d
+ call FieldMoveJumptableReset
+.loop
ld hl, .Jumptable
- call DoFieldMoveAction
- jr nc, .asm_ca5d
+ call FieldMoveJumptable
+ jr nc, .loop
and $7f
ld [wFieldMoveSucceeded], a
ret
-.Jumptable
- dw TryToFly
- dw RunFlyScript
- dw FailToFly
+.Jumptable:
+ dw .TryFly
+ dw .DoFly
+ dw .FailFly
-TryToFly:
+.TryFly:
+; Fly
ld de, ENGINE_STORMBADGE
- call FieldMoveBadgeCheck
- jr c, .asm_caa4
- call GetMapPermission
+ call CheckBadge
+ jr c, .nostormbadge
+ call GetMapEnvironment
call CheckOutdoorMap
- jr z, .asm_ca83
- jr .asm_caa7
+ jr z, .outdoors
+ jr .indoors
-.asm_ca83
+.outdoors
xor a
ldh [hMapAnims], a
call LoadStandardMenuHeader
call ClearSprites
- ld a, $24
- ld hl, $5a61
- rst FarCall
+ farcall _FlyMap
ld a, e
- cp $ff
- jr z, .asm_caaa
- cp $1c
- jr nc, .asm_caaa
- ld [wceec], a
+ cp -1
+ jr z, .illegal
+ cp NUM_SPAWNS
+ jr nc, .illegal
+
+ ld [wDefaultSpawnpoint], a
call CloseWindow
ld a, $1
ret
-.asm_caa4
+.nostormbadge
ld a, $82
ret
-.asm_caa7
+.indoors
ld a, $2
ret
-.asm_caaa
+.illegal
call CloseWindow
call WaitBGMap
ld a, $80
ret
-RunFlyScript:
- ld hl, FlyScript
+.DoFly:
+ ld hl, .FlyScript
call QueueScript
ld a, $81
ret
-FailToFly:
+.FailFly:
call FieldMoveFailed
ld a, $82
ret
-FlyScript:
+.FlyScript:
reloadmappart
callasm HideSprites
special UpdateTimePals
- callasm FlyFromAnimation
+ callasm FlyFromAnim
farscall Script_AbortBugContest
special WarpToSpawnPoint
- callasm DelayLoadingNewSprites ; 1560c
- writecode VAR_MOVEMENT, PLAYER_NORMAL
+ callasm SkipUpdateMapSprites
+ loadvar VAR_MOVEMENT, PLAYER_NORMAL
newloadmap MAPSETUP_TELEPORT
- callasm FlyToAnimation
+ callasm FlyToAnim
special WaitSFX
- special ReplacePlayerSprite
- callasm Function1415c
+ special ReplaceChrisSprite
+ callasm _ClearSprites
end
-WaterfallFunction: ; caed
- call TryWaterfall
+WaterfallFunction:
+ call .TryWaterfall
and $7f
ld [wFieldMoveSucceeded], a
ret
-TryWaterfall: ; caf6 (3:4af6)
+.TryWaterfall:
+; Waterfall
ld de, ENGINE_RISINGBADGE
- farcall FieldMoveBadgeCheck ; same bank
+ farcall CheckBadge
ld a, $80
ret c
call CheckMapCanWaterfall
- jr c, .asm_cb10
+ jr c, .failed
ld hl, Script_WaterfallFromMenu
call QueueScript
ld a, $81
ret
-.asm_cb10
+.failed
call FieldMoveFailed
ld a, $80
ret
-CheckMapCanWaterfall: ; cb16 (3:4b16)
+CheckMapCanWaterfall:
ld a, [wPlayerDirection]
and $c
cp FACE_UP
- jr nz, .asm_cb29
+ jr nz, .failed
ld a, [wTileUp]
call CheckWaterfallTile
- jr nz, .asm_cb29
+ jr nz, .failed
xor a
ret
-.asm_cb29
+.failed
scf
ret
-Script_WaterfallFromMenu: ;cb2b
+Script_WaterfallFromMenu:
reloadmappart
special UpdateTimePals
+
Script_UsedWaterfall:
- callasm FieldMoveGetPartyNick
- writetext Text_UsedWaterfall
+ callasm GetPartyNick
+ writetext .UseWaterfallText
waitbutton
closetext
playsound SFX_BUBBLEBEAM
.loop
- applymovement 0, WaterfallStep
- callasm CheckContinueWaterfall
+ applymovement PLAYER, .WaterfallStep
+ callasm .CheckContinueWaterfall
iffalse .loop
end
-WaterfallStep:
+.WaterfallStep:
turn_waterfall UP
step_end
-CheckContinueWaterfall: ;cb49
+.CheckContinueWaterfall:
xor a
ld [wScriptVar], a
ld a, [wPlayerStandingTile]
@@ -666,440 +680,450 @@ CheckContinueWaterfall: ;cb49
ld [wScriptVar], a
ret
-Text_UsedWaterfall:
- text_far Text_UsedWaterfall_
- db "@"
+.UseWaterfallText:
+ text_far _UseWaterfallText
+ text_end
-TryWaterfallOW:
+TryWaterfallOW::
ld d, WATERFALL
- call FieldMovePartyCheck
- jr c, .asm_cb7d
+ call CheckPartyMove
+ jr c, .failed
ld de, ENGINE_RISINGBADGE
- call FieldMoveEngineFlagCheck
- jr c, .asm_cb7d
+ call CheckEngineFlag
+ jr c, .failed
call CheckMapCanWaterfall
- jr c, .asm_cb7d
+ jr c, .failed
ld a, BANK(Script_AskWaterfall)
ld hl, Script_AskWaterfall
call CallScript
scf
ret
-.asm_cb7d
+.failed
ld a, BANK(Script_CantDoWaterfall)
ld hl, Script_CantDoWaterfall
call CallScript
scf
ret
-Script_CantDoWaterfall:;cb87
- jumptext Text_CantDoWaterfall
+Script_CantDoWaterfall:
+ jumptext .HugeWaterfallText
-Text_CantDoWaterfall:
- text_far Text_CantDoWaterfall_
- db "@"
+.HugeWaterfallText:
+ text_far _HugeWaterfallText
+ text_end
Script_AskWaterfall:
opentext
- writetext Text_AskUseWaterfall
+ writetext .AskWaterfallText
yesorno
iftrue Script_UsedWaterfall
closetext
end
-Text_AskUseWaterfall:
- text_far Text_AskUseWaterfall_
- db "@"
+.AskWaterfallText:
+ text_far _AskWaterfallText
+ text_end
EscapeRopeFunction:
- call FieldMoveBufferReset
+ call FieldMoveJumptableReset
ld a, $1
- jr asm_cbaa
+ jr EscapeRopeOrDig
DigFunction:
- call FieldMoveBufferReset
+ call FieldMoveJumptableReset
ld a, $2
-asm_cbaa
+
+EscapeRopeOrDig:
ld [wBuffer2], a
-.asm_cbad
- ld hl, .Jumptable
- call DoFieldMoveAction
- jr nc, .asm_cbad
+.loop
+ ld hl, .DigTable
+ call FieldMoveJumptable
+ jr nc, .loop
and $7f
ld [wFieldMoveSucceeded], a
ret
-.Jumptable:
- dw TryEscapeFromDungeon
- dw EscapeFromDungeon
- dw FailToEscapeFromDungeon
+.DigTable:
+ dw .CheckCanDig
+ dw .DoDig
+ dw .FailDig
-TryEscapeFromDungeon:
- call GetMapPermission
+.CheckCanDig:
+ call GetMapEnvironment
cp CAVE
- jr z, .asm_cbcf
+ jr z, .incave
cp DUNGEON
- jr z, .asm_cbcf
-.asm_cbcc
+ jr z, .incave
+.fail
ld a, $2
ret
-.asm_cbcf
+.incave
ld hl, wDigWarpNumber
ld a, [hli]
and a
- jr z, .asm_cbcc
+ jr z, .fail
ld a, [hli]
and a
- jr z, .asm_cbcc
+ jr z, .fail
ld a, [hl]
and a
- jr z, .asm_cbcc
+ jr z, .fail
ld a, $1
ret
-EscapeFromDungeon:
+.DoDig:
ld hl, wDigWarpNumber
- ld de, wNextWarpNumber
- ld bc, $3
+ ld de, wNextWarp
+ ld bc, 3
call CopyBytes
- call FieldMoveGetPartyNick
+ call GetPartyNick
ld a, [wBuffer2]
cp $2
- jr nz, .asm_cc00
- ld hl, UsedDigScript
+ jr nz, .escaperope
+ ld hl, .UsedDigScript
call QueueScript
ld a, $81
ret
-.asm_cc00
- ld hl, UsedEscapeRopeScript
+.escaperope
+ ld hl, .UsedEscapeRopeScript
call QueueScript
ld a, $81
ret
-FailToEscapeFromDungeon:
+.FailDig:
ld a, [wBuffer2]
cp $2
- jr nz, .asm_cc1c
- ld hl, Text_CantUseDigEscapeRopeHere ; $4c29
+ jr nz, .failescaperope
+ ld hl, .CantUseDigText
call MenuTextbox
call WaitPressAorB_BlinkCursor
call CloseWindow
-.asm_cc1c
+
+.failescaperope
ld a, $80
ret
-Text_UsedDig: ; cc1f
- text_far Text_UsedDig_
- db "@"
+.UseDigText:
+ text_far _UseDigText
+ text_end
-Text_UsedEscapeRope:
- text_far Text_UsedEscapeRope_
- db "@"
+.UseEscapeRopeText:
+ text_far _UseEscapeRopeText
+ text_end
-Text_CantUseDigEscapeRopeHere:
- text_far Text_CantUseDigEscapeRopeHere_
- db "@"
+.CantUseDigText:
+ text_far _CantUseDigText
+ text_end
-UsedEscapeRopeScript: ; cc2e reloadmappart
+.UsedEscapeRopeScript:
reloadmappart
special UpdateTimePals
- writetext Text_UsedEscapeRope ; cc24
- jump ContinueDigEscapeRopeScript
+ writetext .UseEscapeRopeText
+ sjump .UsedDigOrEscapeRopeScript
-UsedDigScript:
+.UsedDigScript:
reloadmappart
special UpdateTimePals
- writetext Text_UsedDig
-ContinueDigEscapeRopeScript:
+ writetext .UseDigText
+
+.UsedDigOrEscapeRopeScript:
waitbutton
closetext
playsound SFX_WARP_TO
- applymovement PLAYER, DigOutMovementData
+ applymovement PLAYER, .DigOut
farscall Script_AbortBugContest
special WarpToSpawnPoint
- writecode VAR_MOVEMENT, PLAYER_NORMAL
+ loadvar VAR_MOVEMENT, PLAYER_NORMAL
newloadmap MAPSETUP_DOOR
playsound SFX_WARP_FROM
- applymovement PLAYER, DigReturnMovementData
+ applymovement PLAYER, .DigReturn
end
-DigOutMovementData:
+.DigOut:
step_dig 32
- hide_person
+ hide_object
step_end
-DigReturnMovementData:
- show_person
+.DigReturn:
+ show_object
return_dig 32
step_end
- call FieldMoveBufferReset
-.asm_cc67
+TeleportFunction:
+ call FieldMoveJumptableReset
+.loop
ld hl, .Jumptable
- call DoFieldMoveAction
- jr nc, .asm_cc67
+ call FieldMoveJumptable
+ jr nc, .loop
and $7f
ld [wFieldMoveSucceeded], a
ret
.Jumptable:
- dw TryTeleport
- dw DoTeleport
- dw FailTeleport
+ dw .TryTeleport
+ dw .DoTeleport
+ dw .FailTeleport
-TryTeleport:
- call GetMapPermission
+.TryTeleport:
+ call GetMapEnvironment
call CheckOutdoorMap
- jr z, .asm_cc85
- jr .asm_cc9c
+ jr z, .CheckIfSpawnPoint
+ jr .nope
-.asm_cc85
- ld a, [wd9fb]
+.CheckIfSpawnPoint:
+ ld a, [wLastSpawnMapGroup]
ld d, a
- ld a, [wd9fc]
+ ld a, [wLastSpawnMapNumber]
ld e, a
- ld a, $5
- ld hl, $5465
- rst FarCall
- jr nc, .asm_cc9c
+ farcall IsSpawnPoint
+ jr nc, .nope
ld a, c
- ld [wceec], a
+ ld [wDefaultSpawnpoint], a
ld a, $1
ret
-.asm_cc9c
+.nope
ld a, $2
ret
-DoTeleport:
- call FieldMoveGetPartyNick
- ld hl, TeleportScript
+.DoTeleport:
+ call GetPartyNick
+ ld hl, .TeleportScript
call QueueScript
ld a, $81
ret
-FailTeleport:
- ld hl, Text_CantUseTeleportHere
+.FailTeleport:
+ ld hl, .CantUseTeleportText
call MenuTextboxBackup
ld a, $80
ret
-Text_ReturnToLastMonCenter:
- text_far Text_ReturnToLastMonCenter_
- db "@"
+.TeleportReturnText:
+ text_far _TeleportReturnText
+ text_end
-Text_CantUseTeleportHere:
- text_far Text_CantUseTeleportHere_
- db "@"
+.CantUseTeleportText:
+ text_far _CantUseTeleportText
+ text_end
-TeleportScript: ; ccbe
+.TeleportScript:
reloadmappart
special UpdateTimePals
- writetext Text_ReturnToLastMonCenter
+ writetext .TeleportReturnText
pause 60
reloadmappart
closetext
playsound SFX_WARP_TO
- applymovement PLAYER, TeleportFromMovementData
+ applymovement PLAYER, .TeleportFrom
farscall Script_AbortBugContest
special WarpToSpawnPoint
- writecode VAR_MOVEMENT, PLAYER_NORMAL
+ loadvar VAR_MOVEMENT, PLAYER_NORMAL
newloadmap MAPSETUP_TELEPORT
playsound SFX_WARP_FROM
- applymovement PLAYER, TeleportToMovementData
+ applymovement PLAYER, .TeleportTo
end
-TeleportFromMovementData: ; cce4
+.TeleportFrom:
teleport_from
step_end
-TeleportToMovementData:
+.TeleportTo:
teleport_to
step_end
StrengthFunction:
- call Functionccf1
+ call .TryStrength
and $7f
ld [wFieldMoveSucceeded], a
ret
-Functionccf1: ; ccf1 (3:4cf1)
+.TryStrength:
+; Strength
ld de, ENGINE_PLAINBADGE
- call FieldMoveBadgeCheck
- jr c, asm_cd09
- jr asm_cd0c
+ call CheckBadge
+ jr c, .Failed
+ jr .UseStrength
- ld hl, Text_AlreadyUsingStrength
+.Unreferenced_AlreadyUsing:
+ ld hl, .AlreadyUsingStrengthText
call MenuTextboxBackup
ld a, $80
ret
-Text_AlreadyUsingStrength:
- text_far Text_AlreadyUsingStrength_
- db "@"
+.AlreadyUsingStrengthText:
+ text_far _AlreadyUsingStrengthText
+ text_end
-asm_cd09
+.Failed:
ld a, $80
ret
-asm_cd0c
+.UseStrength:
ld hl, Script_StrengthFromMenu
call QueueScript
ld a, $81
ret
-GetStrengthUserSpeciesAndSetFlag:
- SetFlag ENGINE_STRENGTH_ACTIVE
+SetStrengthFlag:
+ ld hl, wBikeFlags
+ set BIKEFLAGS_STRENGTH_ACTIVE_F, [hl]
ld a, [wCurPartyMon]
ld e, a
- ld d, $0
+ ld d, 0
ld hl, wPartySpecies
add hl, de
ld a, [hl]
ld [wBuffer6], a
- call FieldMoveGetPartyNick
+ call GetPartyNick
ret
-Script_StrengthFromMenu: ; cd2c
+Script_StrengthFromMenu:
reloadmappart
special UpdateTimePals
+
Script_UsedStrength:
- callasm GetStrengthUserSpeciesAndSetFlag
- writetext Text_UsedStrength
- copybytetovar wBuffer6
+ callasm SetStrengthFlag
+ writetext .UseStrengthText
+ readmem wBuffer6
cry 0
pause 3
- writetext Text_AllowedToMoveBoulders
+ writetext .MoveBoulderText
closetext
end
-Text_UsedStrength: ; cd44
- text_far Text_UsedStrength_
- db "@"
+.UseStrengthText:
+ text_far _UseStrengthText
+ text_end
-Text_AllowedToMoveBoulders:
- text_far Text_AllowedToMoveBoulders_
- db "@"
+.MoveBoulderText:
+ text_far _MoveBoulderText
+ text_end
-AskStrengthScript: ; cd4e
+AskStrengthScript:
callasm TryStrengthOW
- iffalse .ask
- ifequal 1, .not_able
- jump .already_active
+ iffalse .AskStrength
+ ifequal $1, .DontMeetRequirements
+ sjump .AlreadyUsedStrength
-.not_able
- jumptext Text_MonMayBeAbleToMove
+.DontMeetRequirements:
+ jumptext BouldersMayMoveText
-.already_active
- jumptext Text_BouldersMayNowBeMoved
+.AlreadyUsedStrength:
+ jumptext BouldersMoveText
-.ask
+.AskStrength:
opentext
- writetext Text_AskStrength
+ writetext AskStrengthText
yesorno
iftrue Script_UsedStrength
closetext
end
-Text_AskStrength:
- text_far Text_AskStrength_
- db "@"
+AskStrengthText:
+ text_far _AskStrengthText
+ text_end
-Text_BouldersMayNowBeMoved:
- text_far Text_BouldersMayNowBeMoved_
- db "@"
+BouldersMoveText:
+ text_far _BouldersMoveText
+ text_end
-Text_MonMayBeAbleToMove:
- text_far Text_MonMayBeAbleToMove_
- db "@"
+BouldersMayMoveText:
+ text_far _BouldersMayMoveText
+ text_end
TryStrengthOW:
ld d, STRENGTH
- call FieldMovePartyCheck
- jr c, .asm_cd95
+ call CheckPartyMove
+ jr c, .nope
+
ld de, ENGINE_PLAINBADGE
- call FieldMoveEngineFlagCheck
- jr c, .asm_cd95
- CheckFlagHL ENGINE_STRENGTH_ACTIVE
- jr z, .asm_cd99
- ld a, $2
- jr .asm_cd9c
+ call CheckEngineFlag
+ jr c, .nope
-.asm_cd95
- ld a, $1
- jr .asm_cd9c
+ ld hl, wBikeFlags
+ bit BIKEFLAGS_STRENGTH_ACTIVE_F, [hl]
+ jr z, .already_using
+
+ ld a, 2
+ jr .done
+
+.nope
+ ld a, 1
+ jr .done
-.asm_cd99
+.already_using
xor a
- jr .asm_cd9c
+ jr .done
-.asm_cd9c
+.done
ld [wScriptVar], a
ret
WhirlpoolFunction:
- call FieldMoveBufferReset
-.asm_cda3
- ld hl, .Jumptable
- call DoFieldMoveAction
- jr nc, .asm_cda3
+ call FieldMoveJumptableReset
+.loop
+ ld hl, Jumptable_cdae
+ call FieldMoveJumptable
+ jr nc, .loop
and $7f
ld [wFieldMoveSucceeded], a
ret
-.Jumptable
- dw TryWhirlpool
- dw DoWhirlpool
- dw FailWhirlpool
+Jumptable_cdae:
+ dw .TryWhirlpool
+ dw .DoWhirlpool
+ dw .FailWhirlpool
-TryWhirlpool:
+.TryWhirlpool:
ld de, ENGINE_GLACIERBADGE
- call FieldMoveBadgeCheck
- jr c, .asm_cdca
+ call CheckBadge
+ jr c, .noglacierbadge
call TryWhirlpoolMenu
- jr c, .asm_cdc7
+ jr c, .failed
ld a, $1
ret
-.asm_cdc7
+.failed
ld a, $2
ret
-.asm_cdca
+.noglacierbadge
ld a, $80
ret
-DoWhirlpool:
+.DoWhirlpool:
ld hl, Script_WhirlpoolFromMenu
call QueueScript
ld a, $81
ret
-FailWhirlpool:
+.FailWhirlpool:
call FieldMoveFailed
ld a, $80
ret
-Text_UsedWhirlpool:
- text_far Text_UsedWhirlpool_
- db "@"
+UseWhirlpoolText:
+ text_far _UseWhirlpoolText
+ text_end
-TryWhirlpoolMenu: ; cde1 (3:4de1)
+TryWhirlpoolMenu:
call GetFacingTileCoord
ld c, a
push de
call CheckWhirlpoolTile
pop de
- jr c, .asm_ce0c
+ jr c, .failed
call GetBlockLocation
ld c, [hl]
push hl
ld hl, WhirlpoolBlockPointers
call CheckOverworldTileArrays
pop hl
- jr nc, .asm_ce0c
+ jr nc, .failed
ld a, l
ld [wBuffer3], a
ld a, h
@@ -1111,22 +1135,23 @@ TryWhirlpoolMenu: ; cde1 (3:4de1)
xor a
ret
-.asm_ce0c
+.failed
scf
ret
-Script_WhirlpoolFromMenu: ; 4e0e
+Script_WhirlpoolFromMenu:
reloadmappart
special UpdateTimePals
+
Script_UsedWhirlpool:
- callasm FieldMoveGetPartyNick
- writetext Text_UsedWhirlpool
+ callasm GetPartyNick
+ writetext UseWhirlpoolText
reloadmappart
callasm DisappearWhirlpool
closetext
end
-DisappearWhirlpool: ; 4e20
+DisappearWhirlpool:
ld hl, wBuffer3
ld a, [hli]
ld h, [hl]
@@ -1143,46 +1168,46 @@ DisappearWhirlpool: ; 4e20
call GetMovementPermissions
ret
-TryWhirlpoolOW:
+TryWhirlpoolOW::
ld d, WHIRLPOOL
- call FieldMovePartyCheck
- jr c, .asm_ce5f
+ call CheckPartyMove
+ jr c, .failed
ld de, ENGINE_GLACIERBADGE
- call FieldMoveEngineFlagCheck
- jr c, .asm_ce5f
+ call CheckEngineFlag
+ jr c, .failed
call TryWhirlpoolMenu
- jr c, .asm_ce5f
+ jr c, .failed
ld a, BANK(Script_AskWhirlpoolOW)
- ld hl, Script_AskWhirlpoolOW ; $4e71
+ ld hl, Script_AskWhirlpoolOW
call CallScript
scf
ret
-.asm_ce5f
+.failed
ld a, BANK(Script_MightyWhirlpool)
- ld hl, Script_MightyWhirlpool ; $4e69
+ ld hl, Script_MightyWhirlpool
call CallScript
scf
ret
Script_MightyWhirlpool:
- jumptext Text_MightyWhirlpool
+ jumptext .MayPassWhirlpoolText
-Text_MightyWhirlpool:
- text_far Text_MightyWhirlpool_
- db "@"
+.MayPassWhirlpoolText:
+ text_far _MayPassWhirlpoolText
+ text_end
-Script_AskWhirlpoolOW: ; ce71
+Script_AskWhirlpoolOW:
opentext
- writetext Text_AskWhirlpool
+ writetext AskWhirlpoolText
yesorno
iftrue Script_UsedWhirlpool
closetext
end
-Text_AskWhirlpool: ; ce7b
- text_far Text_AskWhirlpool_
- db "@"
+AskWhirlpoolText:
+ text_far _AskWhirlpoolText
+ text_end
HeadbuttFunction:
call TryHeadbuttFromMenu
@@ -1190,252 +1215,259 @@ HeadbuttFunction:
ld [wFieldMoveSucceeded], a
ret
-TryHeadbuttFromMenu: ; ce89 (3:4e89)
+TryHeadbuttFromMenu:
call GetFacingTileCoord
call CheckHeadbuttTreeTile
- jr nz, .asm_ce9a
- ld hl, HeadbuttFromMenuScript ; $4eaa
+ jr nz, .no_tree
+
+ ld hl, HeadbuttFromMenuScript
call QueueScript
ld a, $81
ret
-.asm_ce9a
+.no_tree
call FieldMoveFailed
ld a, $80
ret
-; ceaa
-Text_DidAHeadbutt:
- text_far Text_DidAHeadbutt_
- db "@"
+UseHeadbuttText:
+ text_far _UseHeadbuttText
+ text_end
-Text_NothingFromHeadbutt:
- text_far Text_NothingFromHeadbutt_
- db "@"
+HeadbuttNothingText:
+ text_far _HeadbuttNothingText
+ text_end
HeadbuttFromMenuScript:
reloadmappart
special UpdateTimePals
+
HeadbuttScript:
- callasm FieldMoveGetPartyNick
- writetext Text_DidAHeadbutt
+ callasm GetPartyNick
+ writetext UseHeadbuttText
+
reloadmappart
callasm ShakeHeadbuttTree
+
callasm TreeMonEncounter
- iffalse .nope_nothing
+ iffalse .no_battle
closetext
randomwildmon
startbattle
reloadmapafterbattle
end
-.nope_nothing:
- writetext Text_NothingFromHeadbutt
+.no_battle
+ writetext HeadbuttNothingText
waitbutton
closetext
end
-TryHeadbuttOW: ; cecc
+TryHeadbuttOW::
ld d, HEADBUTT
- call FieldMovePartyCheck
- jr c, .asm_cedd
+ call CheckPartyMove
+ jr c, .no
+
ld a, BANK(AskHeadbuttScript)
- ld hl, AskHeadbuttScript ; $4edf
+ ld hl, AskHeadbuttScript
call CallScript
scf
ret
-.asm_cedd
+.no
xor a
ret
AskHeadbuttScript:
opentext
- writetext Text_AskHeadbutt
+ writetext AskHeadbuttText
yesorno
iftrue HeadbuttScript
closetext
end
-Text_AskHeadbutt: ; cee9
- text_far Text_AskHeadbutt_
- db "@"
+AskHeadbuttText:
+ text_far _AskHeadbuttText
+ text_end
+RockSmashFunction:
call TryRockSmashFromMenu
and $7f
ld [wFieldMoveSucceeded], a
ret
-TryRockSmashFromMenu: ; cef7 (3:4ef7)
+TryRockSmashFromMenu:
call GetFacingObject
- jr c, .asm_cf0a
+ jr c, .no_rock
ld a, d
cp $18
- jr nz, .asm_cf0a
- ld hl, RockSmashFromMenuScript ; $4f31
+ jr nz, .no_rock
+
+ ld hl, RockSmashFromMenuScript
call QueueScript
ld a, $81
ret
-.asm_cf0a
+.no_rock
call FieldMoveFailed
ld a, $80
ret
-GetFacingObject: ; cf10 (3:4f10)
+GetFacingObject:
farcall CheckFacingObject
- jr nc, .asm_cf2f
+ jr nc, .fail
+
ldh a, [hObjectStructIndexBuffer]
call GetObjectStruct
- ld hl, $1
+ ld hl, OBJECT_MAP_OBJECT_INDEX
add hl, bc
ld a, [hl]
ldh [hLastTalked], a
call GetMapObject
- ld hl, $4
+ ld hl, MAPOBJECT_MOVEMENT
add hl, bc
ld a, [hl]
ld d, a
and a
ret
-.asm_cf2f
+.fail
scf
ret
-RockSmashFromMenuScript: ; cf31
+RockSmashFromMenuScript:
reloadmappart
special UpdateTimePals
+
RockSmashScript:
- callasm FieldMoveGetPartyNick
- writetext Text_UsedRockSmash
+ callasm GetPartyNick
+ writetext UseRockSmashText
closetext
special WaitSFX
playsound SFX_STRENGTH
earthquake 84
- applymovement2 RockSmashMovementData
+ applymovementlasttalked MovementData_RockSmash
disappear -2
+
callasm RockMonEncounter
- copybytetovar wd117
- iffalse .skip_battle
+ readmem wTempWildMonSpecies
+ iffalse .done
randomwildmon
startbattle
reloadmapafterbattle
-.skip_battle
+.done
end
-RockSmashMovementData:
+MovementData_RockSmash:
rock_smash 10
step_end
-Text_UsedRockSmash:
- text_far Text_UsedRockSmash_
- db "@"
-; cf60
+UseRockSmashText:
+ text_far _UseRockSmashText
+ text_end
+
AskRockSmashScript:
- callasm TryRockSmashOW
- ifequal 1, .fail
+ callasm HasRockSmash
+ ifequal 1, .no
+
opentext
- writetext Text_AskRockSmash
+ writetext AskRockSmashText
yesorno
iftrue RockSmashScript
closetext
end
-.fail
- jumptext Text_MayBeBreakable
+.no
+ jumptext MaySmashText
-Text_MayBeBreakable:
- text_far Text_MayBeBreakable_
- db "@"
+MaySmashText:
+ text_far _MaySmashText
+ text_end
-Text_AskRockSmash:
- text_far Text_AskRockSmash_
- db "@"
+AskRockSmashText:
+ text_far _AskRockSmashText
+ text_end
-TryRockSmashOW: ; cf7f
+HasRockSmash:
ld d, ROCK_SMASH
- call FieldMovePartyCheck
- jr nc, .asm_cf8a
- ld a, $1
- jr .asm_cf8d
-
-.asm_cf8a
+ call CheckPartyMove
+ jr nc, .yes
+.no
+ ld a, 1
+ jr .done
+.yes
xor a
- jr .asm_cf8d
-
-.asm_cf8d
+ jr .done
+.done
ld [wScriptVar], a
ret
-FishingRodFunction: ; cf91
+FishFunction:
ld a, e
push af
- call FieldMoveBufferReset
+ call FieldMoveJumptableReset
pop af
ld [wBuffer2], a
-.asm_cf9a
- ld hl, .Jumptable ; $4fa8
- call DoFieldMoveAction
- jr nc, .asm_cf9a
+.loop
+ ld hl, .FishTable
+ call FieldMoveJumptable
+ jr nc, .loop
and $7f
ld [wFieldMoveSucceeded], a
ret
-.Jumptable
- dw Fish_CheckMap ; 3:4fb2
- dw Fish_NoBite ; 3:5005
- dw Fish_GotSomething ; 3:4ff7
- dw Fish_Failed ; 3:4ff4
- dw Fish_NoFish ; 3:5013
+.FishTable:
+ dw .TryFish
+ dw .FishNoBite
+ dw .FishGotSomething
+ dw .FailFish
+ dw .FishNoFish
-Fish_CheckMap:
+.TryFish:
ld a, [wPlayerState]
cp PLAYER_SURF
- jr z, .asm_cfc7
+ jr z, .fail
cp PLAYER_SURF_PIKA
- jr z, .asm_cfc7
+ jr z, .fail
call GetFacingTileCoord
call GetTileCollision
- cp $1
- jr z, .asm_cfca
-.asm_cfc7
+ cp WATER_TILE
+ jr z, .facingwater
+.fail
ld a, $3
ret
-.asm_cfca
+.facingwater
call GetFishingGroup
and a
- jr nz, .asm_cfd3
+ jr nz, .goodtofish
ld a, $4
ret
-.asm_cfd3
+.goodtofish
ld d, a
ld a, [wBuffer2]
ld e, a
- ld a, $24
- ld hl, $697a
- rst FarCall
+ farcall Fish
ld a, d
and a
- jr z, .asm_cff1
- ld [wd117], a
+ jr z, .nonibble
+ ld [wTempWildMonSpecies], a
ld a, e
ld [wCurPartyLevel], a
- ld a, $4
+ ld a, BATTLETYPE_FISH
ld [wBattleType], a
ld a, $2
ret
-.asm_cff1
+.nonibble
ld a, $1
ret
-Fish_Failed:
+.FailFish:
ld a, $80
ret
-Fish_GotSomething:
+.FishGotSomething:
ld a, $1
ld [wBuffer6], a
ld hl, Script_GotABite
@@ -1443,7 +1475,7 @@ Fish_GotSomething:
ld a, $81
ret
-Fish_NoBite:
+.FishNoBite:
ld a, $2
ld [wBuffer6], a
ld hl, Script_NotEvenANibble
@@ -1451,7 +1483,7 @@ Fish_NoBite:
ld a, $81
ret
-Fish_NoFish:
+.FishNoFish:
ld a, $0
ld [wBuffer6], a
ld hl, Script_NotEvenANibble2
@@ -1459,32 +1491,34 @@ Fish_NoFish:
ld a, $81
ret
-Script_NotEvenANibble: ; d021
+Script_NotEvenANibble:
scall Script_FishCastRod
- writetext Text_NotEvenANibble
- jump Script_NotEvenANibble_Continue
+ writetext RodNothingText
+ sjump Script_NotEvenANibble_FallThrough
Script_NotEvenANibble2:
scall Script_FishCastRod
- writetext Text_NotEvenANibble
-Script_NotEvenANibble_Continue:
+ writetext RodNothingText
+
+Script_NotEvenANibble_FallThrough:
callasm PutTheRodAway
closetext
end
Script_GotABite:
scall Script_FishCastRod
- callasm Fish_CheckFacingUp
- iffalse .not_facing_up
- applymovement 0, Movement_Fishing_BiteFacingUp
- jump .continue
-
-.not_facing_up
- applymovement 0, Movement_Fishing_BiteNotFacingUp
-.continue
+ callasm Fishing_CheckFacingUp
+ iffalse .NotFacingUp
+ applymovement PLAYER, .Movement_FacingUp
+ sjump .FightTheHookedPokemon
+
+.NotFacingUp:
+ applymovement PLAYER, .Movement_NotFacingUp
+
+.FightTheHookedPokemon:
pause 40
- applymovement 0, Movement_Fishing_RestoreRod
- writetext Text_OhABite
+ applymovement PLAYER, .Movement_RestoreRod
+ writetext RodBiteText
callasm PutTheRodAway
closetext
randomwildmon
@@ -1492,8 +1526,7 @@ Script_GotABite:
reloadmapafterbattle
end
-
-Movement_Fishing_BiteNotFacingUp:
+.Movement_NotFacingUp:
fish_got_bite
fish_got_bite
fish_got_bite
@@ -1501,7 +1534,7 @@ Movement_Fishing_BiteNotFacingUp:
show_emote
step_end
-Movement_Fishing_BiteFacingUp:
+.Movement_FacingUp:
fish_got_bite
fish_got_bite
fish_got_bite
@@ -1510,40 +1543,41 @@ Movement_Fishing_BiteFacingUp:
show_emote
step_end
-Movement_Fishing_RestoreRod:
+.Movement_RestoreRod:
hide_emote
fish_cast_rod
step_end
-Fish_CheckFacingUp: ; d06d
+Fishing_CheckFacingUp:
ld a, [wPlayerDirection]
and $c
cp OW_UP
ld a, $1
- jr z, .asm_d079
+ jr z, .up
xor a
-.asm_d079
+
+.up
ld [wScriptVar], a
ret
-Script_FishCastRod: ; d07d
+Script_FishCastRod:
reloadmappart
- loadvar hBGMapMode, 0
+ loadmem hBGMapMode, $0
special UpdateTimePals
loademote EMOTE_ROD
callasm LoadFishingGFX
loademote EMOTE_SHOCK
- applymovement PLAYER, Movement_CastRod
+ applymovement PLAYER, MovementData_CastRod
pause 40
end
-Movement_CastRod:
+MovementData_CastRod:
fish_cast_rod
step_end
-PutTheRodAway: ; d096
+PutTheRodAway:
hlcoord 1, 14
- lb bc, $3, $12
+ lb bc, 3, 18
call ClearBox
call WaitBGMap
xor a
@@ -1551,41 +1585,41 @@ PutTheRodAway: ; d096
ld a, $1
ld [wPlayerAction], a
call UpdateSprites
- call ReplacePlayerSprite
+ call ReplaceChrisSprite
ret
-Text_OhABite:
- text_far Text_OhABite_
- db "@"
+RodBiteText:
+ text_far _RodBiteText
+ text_end
-Text_NotEvenANibble:
- text_far Text_NotEvenANibble_
- db "@"
+RodNothingText:
+ text_far _RodNothingText
+ text_end
-Text_NothingHereToFish:
- text_far Text_NothingHereToFish_
- db "@"
+UnusedNothingHereText: ; unused
+ text_far _UnusedNothingHereText
+ text_end
-BicycleFunction:
- call Functiond0c9
+BikeFunction:
+ call .TryBike
and $7f
ld [wFieldMoveSucceeded], a
ret
-Functiond0c9: ; d0c9 (3:50c9)
- call CheckBikePermission
- jr c, .cant_bike
+.TryBike:
+ call .CheckEnvironment
+ jr c, .CannotUseBike
ld a, [wPlayerState]
cp PLAYER_NORMAL
- jr z, .get_on_bike
+ jr z, .GetOnBike
cp PLAYER_BIKE
- jr z, .get_off_bike
- jr .cant_bike
+ jr z, .GetOffBike
+ jr .CannotUseBike
-.get_on_bike
+.GetOnBike:
ld hl, Script_GetOnBike
ld de, Script_GetOnBike_Register
- call ChooseScriptBasedOnWhetherBikeIsRegistered
+ call .CheckIfRegistered
call QueueScript
xor a
ld [wMusicFade], a
@@ -1600,30 +1634,30 @@ Functiond0c9: ; d0c9 (3:50c9)
ld a, $1
ret
-.get_off_bike
+.GetOffBike:
ld hl, wBikeFlags
- bit 1, [hl]
- jr nz, .asm_d118
+ bit BIKEFLAGS_ALWAYS_ON_BIKE_F, [hl]
+ jr nz, .CantGetOffBike
ld hl, Script_GetOffBike
ld de, Script_GetOffBike_Register
- call ChooseScriptBasedOnWhetherBikeIsRegistered
- ld a, $3
- jr .queue_off
+ call .CheckIfRegistered
+ ld a, BANK(Script_GetOffBike)
+ jr .done
-.asm_d118
+.CantGetOffBike:
ld hl, Script_CantGetOffBike
- jr .queue_off
+ jr .done
-.cant_bike
+.CannotUseBike:
ld a, $0
ret
-.queue_off
+.done
call QueueScript
ld a, $1
ret
-ChooseScriptBasedOnWhetherBikeIsRegistered: ; d126 (3:5126)
+.CheckIfRegistered:
ld a, [wUsingItemWithSelect]
and a
ret z
@@ -1631,128 +1665,131 @@ ChooseScriptBasedOnWhetherBikeIsRegistered: ; d126 (3:5126)
ld l, e
ret
-CheckBikePermission: ; d12e (3:512e)
- call GetMapPermission
+.CheckEnvironment:
+ call GetMapEnvironment
call CheckOutdoorMap
- jr z, .asm_d140
+ jr z, .ok
cp CAVE
- jr z, .asm_d140
+ jr z, .ok
cp GATE
- jr z, .asm_d140
- jr .asm_d149
+ jr z, .ok
+ jr .nope
-.asm_d140
+.ok
call GetPlayerStandingTile
- and $f
- jr nz, .asm_d149
+ and $f ; lo nybble only
+ jr nz, .nope ; not FLOOR_TILE
xor a
ret
-.asm_d149
+.nope
scf
ret
-Script_GetOnBike: ; d14b
+Script_GetOnBike:
reloadmappart
special UpdateTimePals
- writecode VAR_MOVEMENT, PLAYER_BIKE
- writetext Text_GotOnTheBike
+ loadvar VAR_MOVEMENT, PLAYER_BIKE
+ writetext GotOnBikeText
waitbutton
closetext
- special ReplacePlayerSprite
+ special ReplaceChrisSprite
end
Script_GetOnBike_Register:
- writecode VAR_MOVEMENT, PLAYER_BIKE
+ loadvar VAR_MOVEMENT, PLAYER_BIKE
closetext
- special ReplacePlayerSprite
+ special ReplaceChrisSprite
end
+; unused
nop
ret
Script_GetOffBike:
reloadmappart
special UpdateTimePals
- writecode VAR_MOVEMENT, PLAYER_NORMAL
- writetext Text_GotOffTheBike
+ loadvar VAR_MOVEMENT, PLAYER_NORMAL
+ writetext GotOffBikeText
waitbutton
+
FinishGettingOffBike:
closetext
- special ReplacePlayerSprite
+ special ReplaceChrisSprite
special PlayMapMusic
end
Script_GetOffBike_Register:
- writecode VAR_MOVEMENT, PLAYER_NORMAL
- jump FinishGettingOffBike
+ loadvar VAR_MOVEMENT, PLAYER_NORMAL
+ sjump FinishGettingOffBike
-Script_CantGetOffBike: ; d17e
- writetext Text_CantGetOffBike
+Script_CantGetOffBike:
+ writetext .CantGetOffBikeText
waitbutton
closetext
end
-Text_CantGetOffBike:
- text_far Text_CantGetOffBike_
- db "@"
-
-Text_GotOnTheBike:
- text_far Text_GotOnTheBike_
- db "@"
+.CantGetOffBikeText:
+ text_far _CantGetOffBikeText
+ text_end
-Text_GotOffTheBike:
- text_far Text_GotOffTheBike_
- db "@"
+GotOnBikeText:
+ text_far _GotOnBikeText
+ text_end
+GotOffBikeText:
+ text_far _GotOffBikeText
+ text_end
-TryCutOW: ; d193
+TryCutOW::
ld d, CUT
- call FieldMovePartyCheck
- jr c, .asm_d1ac
+ call CheckPartyMove
+ jr c, .cant_cut
+
ld de, ENGINE_HIVEBADGE
- call FieldMoveEngineFlagCheck
- jr c, .asm_d1ac
+ call CheckEngineFlag
+ jr c, .cant_cut
+
ld a, BANK(AskCutScript)
ld hl, AskCutScript
call CallScript
scf
ret
-.asm_d1ac
+.cant_cut
ld a, BANK(CantCutScript)
ld hl, CantCutScript
call CallScript
scf
ret
-AskCutScript: ; d1b6
+AskCutScript:
opentext
- writetext Text_AskCut
+ writetext AskCutText
yesorno
iffalse .declined
- callasm CheckMapForSomethingToCut_
+ callasm .CheckMap
iftrue Script_Cut
-.declined:
+.declined
closetext
end
-CheckMapForSomethingToCut_: ; d1c7
+.CheckMap:
xor a
ld [wScriptVar], a
call CheckMapForSomethingToCut
ret c
- ld a, $1
+ ld a, TRUE
ld [wScriptVar], a
ret
-Text_AskCut:
- text_far Text_AskCut_
- db "@"
+AskCutText:
+ text_far _AskCutText
+ text_end
-CantCutScript: ; d1da
- jumptext Text_MonCanCutThis
+CantCutScript:
+ jumptext CanCutText
-Text_MonCanCutThis:
- text_far Text_MonCanCutThis_
- db "@"
+CanCutText:
+ text_far _CanCutText
+ text_end
diff --git a/engine/events/pokecenter_pc.asm b/engine/events/pokecenter_pc.asm
new file mode 100644
index 00000000..8981bcf4
--- /dev/null
+++ b/engine/events/pokecenter_pc.asm
@@ -0,0 +1,658 @@
+PokemonCenterPC:
+ call PC_CheckPartyForPokemon
+ ret c
+ call PC_PlayBootSound
+ ld hl, PokecenterPCTurnOnText
+ call PC_DisplayText
+ ld hl, PokecenterPCWhoseText
+ call PC_DisplayTextWaitMenu
+ ld hl, .TopMenu
+ call LoadMenuHeader
+.loop
+ xor a
+ ldh [hBGMapMode], a
+ call .ChooseWhichPCListToUse
+ ld [wWhichIndexSet], a
+ call DoNthMenu
+ jr c, .shutdown
+ ld a, [wMenuSelection]
+ ld hl, .JumpTable
+ call MenuJumptable
+ jr nc, .loop
+
+.shutdown
+ call PC_PlayShutdownSound
+ call ExitMenu
+ call CloseWindow
+ ret
+
+.TopMenu:
+ db MENU_BACKUP_TILES | MENU_NO_CLICK_SFX ; flags
+ menu_coords 0, 0, 15, 12
+ dw .MenuData
+ db 1 ; default option
+
+.MenuData:
+ db STATICMENU_CURSOR | STATICMENU_WRAP ; flags
+ db 0 ; items
+ dw .WhichPC
+ dw PlaceNthMenuStrings
+ dw .JumpTable
+
+PCPC_PLAYERS_PC EQU 0
+PCPC_BILLS_PC EQU 1
+PCPC_OAKS_PC EQU 2
+PCPC_HALL_OF_FAME EQU 3
+PCPC_TURN_OFF EQU 4
+
+.JumpTable:
+; entries correspond to PCPC_* constants
+ dw PlayersPC, .String_PlayersPC
+ dw BillsPC, .String_BillsPC
+ dw OaksPC, .String_OaksPC
+ dw HallOfFamePC, .String_HallOfFame
+ dw TurnOffPC, .String_TurnOff
+
+.String_PlayersPC: db "<PLAYER>'s PC@"
+.String_BillsPC: db "BILL's PC@"
+.String_OaksPC: db "PROF.OAK's PC@"
+.String_HallOfFame: db "HALL OF FAME@"
+.String_TurnOff: db "TURN OFF@"
+
+.WhichPC:
+ ; before Pokédex
+ db 3
+ db PCPC_BILLS_PC
+ db PCPC_PLAYERS_PC
+ db PCPC_TURN_OFF
+ db -1 ; end
+
+ ; before Hall Of Fame
+ db 4
+ db PCPC_BILLS_PC
+ db PCPC_PLAYERS_PC
+ db PCPC_OAKS_PC
+ db PCPC_TURN_OFF
+ db -1 ; end
+
+ ; postgame
+ db 5
+ db PCPC_BILLS_PC
+ db PCPC_PLAYERS_PC
+ db PCPC_OAKS_PC
+ db PCPC_HALL_OF_FAME
+ db PCPC_TURN_OFF
+ db -1 ; end
+
+.ChooseWhichPCListToUse:
+ call CheckReceivedDex
+ jr nz, .got_dex
+ ld a, 0 ; before Pokédex
+ ret
+
+.got_dex
+ ld a, [wHallOfFameCount]
+ and a
+ ld a, 1 ; before Hall Of Fame
+ ret z
+ ld a, 2 ; postgame
+ ret
+
+PC_CheckPartyForPokemon:
+ ld a, [wPartyCount]
+ and a
+ ret nz
+ ld de, SFX_CHOOSE_PC_OPTION
+ call PlaySFX
+ ld hl, .PokecenterPCCantUseText
+ call PC_DisplayText
+ scf
+ ret
+
+.PokecenterPCCantUseText:
+ text_far _PokecenterPCCantUseText
+ text_end
+
+BillsPC:
+ call PC_PlayChoosePCSound
+ ld hl, PokecenterBillsPCText
+ call PC_DisplayText
+ farcall _BillsPC
+ and a
+ ret
+
+PlayersPC:
+ call PC_PlayChoosePCSound
+ ld hl, PokecenterPlayersPCText
+ call PC_DisplayText
+ ld b, $0
+ call _PlayersPC
+ and a
+ ret
+
+OaksPC:
+ call PC_PlayChoosePCSound
+ ld hl, PokecenterOaksPCText
+ call PC_DisplayText
+ farcall ProfOaksPC
+ and a
+ ret
+
+HallOfFamePC:
+ call PC_PlayChoosePCSound
+ call FadeToMenu
+ farcall _HallOfFamePC
+ call CloseSubmenu
+ and a
+ ret
+
+TurnOffPC:
+ ld hl, PokecenterPCOaksClosedText
+ call PrintText
+ scf
+ ret
+
+PC_PlayBootSound:
+ ld de, SFX_BOOT_PC
+ jr PC_WaitPlaySFX
+
+PC_PlayShutdownSound:
+ ld de, SFX_SHUT_DOWN_PC
+ call PC_WaitPlaySFX
+ call WaitSFX
+ ret
+
+PC_PlayChoosePCSound:
+ ld de, SFX_CHOOSE_PC_OPTION
+ jr PC_WaitPlaySFX
+
+PC_PlaySwapItemsSound:
+ ld de, SFX_SWITCH_POKEMON
+ call PC_WaitPlaySFX
+ ld de, SFX_SWITCH_POKEMON
+
+PC_WaitPlaySFX:
+ push de
+ call WaitSFX
+ pop de
+ call PlaySFX
+ ret
+
+_PlayersHousePC:
+ call PC_PlayBootSound
+ ld hl, PlayersPCTurnOnText
+ call PC_DisplayText
+ ld b, $1
+ call _PlayersPC
+ and a
+ jr nz, .asm_159d0
+ call OverworldTextModeSwitch
+ call ApplyTilemap
+ call UpdateSprites
+ call PC_PlayShutdownSound
+ ld c, $0
+ ret
+
+.asm_159d0
+ call ClearBGPalettes
+ ld c, $1
+ ret
+
+PlayersPCTurnOnText:
+ text_far _PlayersPCTurnOnText
+ text_end
+
+_PlayersPC:
+ ld a, b
+ ld [wWhichIndexSet], a
+ ld hl, PlayersPCAskWhatDoText
+ call PC_DisplayTextWaitMenu
+ call Function159ec
+ call ExitMenu
+ ret
+
+Function159ec:
+ xor a
+ ld [wPCItemsCursor], a
+ ld [wPCItemsScrollPosition], a
+ ld hl, PlayersPCMenuData
+ call LoadMenuHeader
+.asm_159f9
+ call UpdateTimePals
+ call DoNthMenu
+ jr c, .asm_15a08
+ call MenuJumptable
+ jr nc, .asm_159f9
+ jr .asm_15a09
+
+.asm_15a08
+ xor a
+
+.asm_15a09
+ call ExitMenu
+ ret
+
+PlayersPCMenuData:
+ db MENU_BACKUP_TILES ; flags
+ menu_coords 0, 0, 15, 12
+ dw .PlayersPCMenuData
+ db 1 ; default selected option
+
+.PlayersPCMenuData:
+ db STATICMENU_CURSOR | STATICMENU_WRAP ; flags
+ db 0 ; # items?
+ dw .PlayersPCMenuList1
+ dw PlaceNthMenuStrings
+ dw .PlayersPCMenuPointers
+
+PLAYERSPC_WITHDRAW_ITEM EQU 0
+PLAYERSPC_DEPOSIT_ITEM EQU 1
+PLAYERSPC_TOSS_ITEM EQU 2
+PLAYERSPC_MAIL_BOX EQU 3
+PLAYERSPC_DECORATION EQU 4
+PLAYERSPC_TURN_OFF EQU 5
+PLAYERSPC_LOG_OFF EQU 6
+
+.PlayersPCMenuPointers:
+; entries correspond to PLAYERSPC_* constants
+ dw PlayerWithdrawItemMenu, .WithdrawItem
+ dw PlayerDepositItemMenu, .DepositItem
+ dw PlayerTossItemMenu, .TossItem
+ dw PlayerMailBoxMenu, .MailBox
+ dw PlayerDecorationMenu, .Decoration
+ dw PlayerLogOffMenu, .LogOff
+ dw PlayerLogOffMenu, .TurnOff
+
+.WithdrawItem: db "WITHDRAW ITEM@"
+.DepositItem: db "DEPOSIT ITEM@"
+.TossItem: db "TOSS ITEM@"
+.MailBox: db "MAIL BOX@"
+.Decoration: db "DECORATION@"
+.TurnOff: db "TURN OFF@"
+.LogOff: db "LOG OFF@"
+
+.PlayersPCMenuList1:
+ db 5
+ db PLAYERSPC_WITHDRAW_ITEM
+ db PLAYERSPC_DEPOSIT_ITEM
+ db PLAYERSPC_TOSS_ITEM
+ db PLAYERSPC_MAIL_BOX
+ db PLAYERSPC_TURN_OFF
+ db -1 ; end
+
+.PlayersPCMenuList2:
+ db 6
+ db PLAYERSPC_WITHDRAW_ITEM
+ db PLAYERSPC_DEPOSIT_ITEM
+ db PLAYERSPC_TOSS_ITEM
+ db PLAYERSPC_MAIL_BOX
+ db PLAYERSPC_DECORATION
+ db PLAYERSPC_LOG_OFF
+ db -1 ; end
+
+PC_DisplayTextWaitMenu:
+ ld a, [wOptions]
+ push af
+ set NO_TEXT_SCROLL, a
+ ld [wOptions], a
+ call MenuTextbox
+ pop af
+ ld [wOptions], a
+ ret
+
+PlayersPCAskWhatDoText:
+ text_far _PlayersPCAskWhatDoText
+ text_end
+
+PlayerWithdrawItemMenu:
+ call LoadStandardMenuHeader
+ farcall ClearPCItemScreen
+.loop
+ call PCItemsJoypad
+ jr c, .quit
+ call .Submenu
+ jr .loop
+
+.quit
+ call CloseSubmenu
+ xor a
+ ret
+
+.Submenu:
+ ; check if the item has a quantity
+ farcall _CheckTossableItem
+ ld a, [wItemAttributeParamBuffer]
+ and a
+ jr z, .askquantity
+
+ ; items without quantity are always ×1
+ ld a, 1
+ ld [wItemQuantityChangeBuffer], a
+ jr .withdraw
+
+.askquantity
+ ld hl, .PlayersPCHowManyWithdrawText
+ call MenuTextbox
+ farcall SelectQuantityToToss
+ call ExitMenu
+ call ExitMenu
+ jr c, .done
+
+.withdraw
+ ld a, [wItemQuantityChangeBuffer]
+ ld [wBuffer1], a ; quantity
+ ld a, [wCurItemQuantity]
+ ld [wBuffer2], a
+ ld hl, wNumItems
+ call ReceiveItem
+ jr nc, .PackFull
+ ld a, [wBuffer1]
+ ld [wItemQuantityChangeBuffer], a
+ ld a, [wBuffer2]
+ ld [wCurItemQuantity], a
+ ld hl, wNumPCItems
+ call TossItem
+ predef PartyMonItemName
+ ld hl, .PlayersPCWithdrewItemsText
+ call MenuTextbox
+ xor a
+ ldh [hBGMapMode], a
+ call ExitMenu
+ ret
+
+.PackFull:
+ ld hl, .PlayersPCNoRoomWithdrawText
+ call MenuTextboxBackup
+ ret
+
+.done
+ ret
+
+.PlayersPCHowManyWithdrawText:
+ text_far _PlayersPCHowManyWithdrawText
+ text_end
+
+.PlayersPCWithdrewItemsText:
+ text_far _PlayersPCWithdrewItemsText
+ text_end
+
+.PlayersPCNoRoomWithdrawText:
+ text_far _PlayersPCNoRoomWithdrawText
+ text_end
+
+PlayerTossItemMenu:
+ call LoadStandardMenuHeader
+ farcall ClearPCItemScreen
+.loop
+ call PCItemsJoypad
+ jr c, .quit
+ ld de, wNumPCItems
+ farcall TossItemFromPC
+ jr .loop
+
+.quit
+ call CloseSubmenu
+ xor a
+ ret
+
+PlayerDecorationMenu:
+ farcall _PlayerDecorationMenu
+ ld a, c
+ and a
+ ret z
+ scf
+ ret
+
+PlayerLogOffMenu:
+ xor a
+ scf
+ ret
+
+PlayerDepositItemMenu:
+ call .CheckItemsInBag
+ jr c, .nope
+ call DisableSpriteUpdates
+ call LoadStandardMenuHeader
+ farcall DepositSellInitPackBuffers
+.loop
+ farcall DepositSellPack
+ ld a, [wPackUsedItem]
+ and a
+ jr z, .close
+ call .TryDepositItem
+ farcall CheckRegisteredItem
+ jr .loop
+
+.close
+ call CloseSubmenu
+
+.nope
+ xor a
+ ret
+
+.CheckItemsInBag:
+ farcall HasNoItems
+ ret nc
+ ld hl, .PlayersPCNoItemsText
+ call MenuTextboxBackup
+ scf
+ ret
+
+.PlayersPCNoItemsText:
+ text_far _PlayersPCNoItemsText
+ text_end
+
+.TryDepositItem:
+ ld a, [wSpriteUpdatesEnabled]
+ push af
+ ld a, $0
+ ld [wSpriteUpdatesEnabled], a
+ farcall CheckItemMenu
+ ld a, [wItemAttributeParamBuffer]
+ ld hl, .dw
+ rst JumpTable
+ pop af
+ ld [wSpriteUpdatesEnabled], a
+ ret
+
+.dw
+; entries correspond to ITEMMENU_* constants
+ dw .tossable ; ITEMMENU_NOUSE
+ dw .no_toss
+ dw .no_toss
+ dw .no_toss
+ dw .tossable ; ITEMMENU_CURRENT
+ dw .tossable ; ITEMMENU_PARTY
+ dw .tossable ; ITEMMENU_CLOSE
+
+.no_toss
+ ret
+
+.tossable
+ ld a, [wBuffer1]
+ push af
+ ld a, [wBuffer2]
+ push af
+ call .DepositItem
+ pop af
+ ld [wBuffer2], a
+ pop af
+ ld [wBuffer1], a
+ ret
+
+.DepositItem:
+ farcall _CheckTossableItem
+ ld a, [wItemAttributeParamBuffer]
+ and a
+ jr z, .AskQuantity
+ ld a, $1
+ ld [wItemQuantityChangeBuffer], a
+ jr .ContinueDeposit
+
+.AskQuantity:
+ ld hl, .PlayersPCHowManyDepositText
+ call MenuTextbox
+ farcall SelectQuantityToToss
+ push af
+ call ExitMenu
+ call ExitMenu
+ pop af
+ jr c, .DeclinedToDeposit
+
+.ContinueDeposit:
+ ld a, [wItemQuantityChangeBuffer]
+ ld [wBuffer1], a
+ ld a, [wCurItemQuantity]
+ ld [wBuffer2], a
+ ld hl, wNumPCItems
+ call ReceiveItem
+ jr nc, .NoRoomInPC
+ ld a, [wBuffer1]
+ ld [wItemQuantityChangeBuffer], a
+ ld a, [wBuffer2]
+ ld [wCurItemQuantity], a
+ ld hl, wNumItems
+ call TossItem
+ predef PartyMonItemName
+ ld hl, .PlayersPCDepositItemsText
+ call PrintText
+ ret
+
+.NoRoomInPC:
+ ld hl, .PlayersPCNoRoomDepositText
+ call PrintText
+ ret
+
+.DeclinedToDeposit:
+ and a
+ ret
+
+.PlayersPCHowManyDepositText:
+ text_far _PlayersPCHowManyDepositText
+ text_end
+
+.PlayersPCDepositItemsText:
+ text_far _PlayersPCDepositItemsText
+ text_end
+
+.PlayersPCNoRoomDepositText:
+ text_far _PlayersPCNoRoomDepositText
+ text_end
+
+PlayerMailBoxMenu:
+ farcall _PlayerMailBoxMenu
+ xor a
+ ret
+
+PCItemsJoypad:
+ xor a
+ ld [wSwitchItem], a
+.loop
+ ld a, [wSpriteUpdatesEnabled]
+ push af
+ ld a, $0
+ ld [wSpriteUpdatesEnabled], a
+ ld hl, .PCItemsMenuData
+ call CopyMenuHeader
+ hlcoord 0, 0
+ ld b, 10
+ ld c, 18
+ call Textbox
+ ld a, [wPCItemsCursor]
+ ld [wMenuCursorBuffer], a
+ ld a, [wPCItemsScrollPosition]
+ ld [wMenuScrollPosition], a
+ call ScrollingMenu
+ ld a, [wMenuScrollPosition]
+ ld [wPCItemsScrollPosition], a
+ ld a, [wMenuCursorY]
+ ld [wPCItemsCursor], a
+ pop af
+ ld [wSpriteUpdatesEnabled], a
+ ld a, [wSwitchItem]
+ and a
+ jr nz, .moving_stuff_around
+ ld a, [wMenuJoypad]
+ cp B_BUTTON
+ jr z, .b_1
+ cp A_BUTTON
+ jr z, .a_1
+ cp SELECT
+ jr z, .select_1
+ jr .next
+
+.moving_stuff_around
+ ld a, [wMenuJoypad]
+ cp B_BUTTON
+ jr z, .b_2
+ cp A_BUTTON
+ jr z, .a_select_2
+ cp SELECT
+ jr z, .a_select_2
+ jr .next
+
+.b_2
+ xor a
+ ld [wSwitchItem], a
+ jr .next
+
+.a_select_2
+ call PC_PlaySwapItemsSound
+.select_1
+ farcall SwitchItemsInBag
+.next
+ jp .loop
+
+.a_1
+ farcall ScrollingMenu_ClearLeftColumn
+ call PlaceHollowCursor
+ and a
+ ret
+
+.b_1
+ scf
+ ret
+
+.PCItemsMenuData:
+ db MENU_BACKUP_TILES ; flags
+ menu_coords 4, 1, 18, 10
+ dw .MenuData
+ db 1 ; default option
+
+.MenuData:
+ db SCROLLINGMENU_ENABLE_SELECT | SCROLLINGMENU_ENABLE_FUNCTION3 | SCROLLINGMENU_DISPLAY_ARROWS ; flags
+ db 4, 8 ; rows, columns
+ db SCROLLINGMENU_ITEMS_QUANTITY ; item format
+ dbw 0, wNumPCItems
+ dba PlaceMenuItemName
+ dba PlaceMenuItemQuantity
+ dba UpdateItemDescription
+
+PC_DisplayText:
+ call MenuTextbox
+ call ExitMenu
+ ret
+
+PokecenterPCTurnOnText:
+ text_far _PokecenterPCTurnOnText
+ text_end
+
+PokecenterPCWhoseText:
+ text_far _PokecenterPCWhoseText
+ text_end
+
+PokecenterBillsPCText:
+ text_far _PokecenterBillsPCText
+ text_end
+
+PokecenterPlayersPCText:
+ text_far _PokecenterPlayersPCText
+ text_end
+
+PokecenterOaksPCText:
+ text_far _PokecenterOaksPCText
+ text_end
+
+PokecenterPCOaksClosedText:
+ text_far _PokecenterPCOaksClosedText
+ text_end
diff --git a/engine/events/pokepic.asm b/engine/events/pokepic.asm
new file mode 100644
index 00000000..523c5df5
--- /dev/null
+++ b/engine/events/pokepic.asm
@@ -0,0 +1,48 @@
+Pokepic::
+ ld hl, PokepicMenuHeader
+ call CopyMenuHeader
+ call MenuBox
+ call UpdateSprites
+ call ApplyTilemap
+ ld b, SCGB_POKEPIC
+ call GetSGBLayout
+ xor a
+ ldh [hBGMapMode], a
+ ld a, [wCurPartySpecies]
+ ld [wCurSpecies], a
+ call GetBaseData
+ ld de, vTiles1
+ predef GetMonFrontpic
+ ld a, [wMenuBorderTopCoord]
+ inc a
+ ld b, a
+ ld a, [wMenuBorderLeftCoord]
+ inc a
+ ld c, a
+ call Coord2Tile
+ ld a, $80
+ ldh [hGraphicStartTile], a
+ lb bc, 7, 7
+ predef PlaceGraphic
+ call WaitBGMap
+ ret
+
+ClosePokepic::
+ ld hl, PokepicMenuHeader
+ call CopyMenuHeader
+ call ClearMenuBoxInterior
+ call WaitBGMap
+ call GetMemSGBLayout
+ xor a
+ ldh [hBGMapMode], a
+ call OverworldTextModeSwitch
+ call ApplyTilemap
+ call UpdateSprites
+ call LoadStandardFont
+ ret
+
+PokepicMenuHeader:
+ db MENU_BACKUP_TILES ; flags
+ menu_coords 6, 4, 14, 13
+ dw NULL
+ db 1 ; default option
diff --git a/engine/events/pokerus/apply_pokerus_tick.asm b/engine/events/pokerus/apply_pokerus_tick.asm
new file mode 100644
index 00000000..223fe014
--- /dev/null
+++ b/engine/events/pokerus/apply_pokerus_tick.asm
@@ -0,0 +1,26 @@
+ApplyPokerusTick:
+; decreases all pokemon's pokerus counter by b. if the lower nybble reaches zero, the pokerus is cured.
+ ld hl, wPartyMon1PokerusStatus ; wPartyMon1 + MON_PKRS
+ ld a, [wPartyCount]
+ and a
+ ret z ; make sure it's not wasting time on an empty party
+ ld c, a
+.loop
+ ld a, [hl]
+ and $f ; lower nybble is the number of days remaining
+ jr z, .next ; if already 0, skip
+ sub b ; subtract the number of days
+ jr nc, .ok ; max(result, 0)
+ xor a
+.ok
+ ld d, a ; back up this value because we need to preserve the strain (upper nybble)
+ ld a, [hl]
+ and $f0
+ add d
+ ld [hl], a ; this prevents a cured pokemon from recontracting pokerus
+.next
+ ld de, PARTYMON_STRUCT_LENGTH
+ add hl, de
+ dec c
+ jr nz, .loop
+ ret
diff --git a/engine/events/pokerus/pokerus.asm b/engine/events/pokerus/pokerus.asm
new file mode 100644
index 00000000..99a5652c
--- /dev/null
+++ b/engine/events/pokerus/pokerus.asm
@@ -0,0 +1,161 @@
+GivePokerusAndConvertBerries:
+ call ConvertBerriesToBerryJuice
+ ld hl, wPartyMon1PokerusStatus
+ ld a, [wPartyCount]
+ ld b, a
+ ld de, PARTYMON_STRUCT_LENGTH
+; Check to see if any of your Pokemon already has Pokerus.
+; If so, sample its spread through your party.
+; This means that you cannot get Pokerus de novo while
+; a party member has an active infection.
+.loopMons
+ ld a, [hl]
+ and $f
+ jr nz, .TrySpreadPokerus
+ add hl, de
+ dec b
+ jr nz, .loopMons
+
+; If we haven't been to Goldenrod City at least once,
+; prevent the contraction of Pokerus.
+ ld hl, wStatusFlags2
+ bit STATUSFLAGS2_REACHED_GOLDENROD_F, [hl]
+ ret z
+ call Random
+ ldh a, [hRandomAdd]
+ and a
+ ret nz
+ ldh a, [hRandomSub]
+ cp 3
+ ret nc ; 3/65536 chance (00 00, 00 01 or 00 02)
+ ld a, [wPartyCount]
+ ld b, a
+.randomMonSelectLoop
+ call Random
+ and $7
+ cp b
+ jr nc, .randomMonSelectLoop
+ ld hl, wPartyMon1PokerusStatus
+ call GetPartyLocation ; get pokerus byte of random mon
+ ld a, [hl]
+ and $f0
+ ret nz ; if it already has pokerus, do nothing
+.randomPokerusLoop ; Simultaneously sample the strain and duration
+ call Random
+ and a
+ jr z, .randomPokerusLoop
+ ld b, a
+ and $f0
+ jr z, .load_pkrs
+ ld a, b
+ and $7
+ inc a
+.load_pkrs
+ ld b, a ; this should come before the label
+ swap b
+ and $3
+ inc a
+ add b
+ ld [hl], a
+ ret
+
+.TrySpreadPokerus:
+ call Random
+ cp 33 percent + 1
+ ret nc ; 1/3 chance
+
+ ld a, [wPartyCount]
+ cp 1
+ ret z ; only one mon, nothing to do
+
+ ld c, [hl]
+ ld a, b
+ cp 2
+ jr c, .checkPreviousMonsLoop ; no more mons after this one, go backwards
+
+ call Random
+ cp 50 percent + 1
+ jr c, .checkPreviousMonsLoop ; 1/2 chance, go backwards
+.checkFollowingMonsLoop
+ add hl, de
+ ld a, [hl]
+ and a
+ jr z, .infectMon
+ ld c, a
+ and $3
+ ret z ; if mon has cured pokerus, stop searching
+ dec b ; go on to next mon
+ ld a, b
+ cp 1
+ jr nz, .checkFollowingMonsLoop ; no more mons left
+ ret
+
+.checkPreviousMonsLoop
+ ld a, [wPartyCount]
+ cp b
+ ret z ; no more mons
+ ld a, l
+ sub e
+ ld l, a
+ ld a, h
+ sbc d
+ ld h, a
+ ld a, [hl]
+ and a
+ jr z, .infectMon
+ ld c, a
+ and $3
+ ret z ; if mon has cured pokerus, stop searching
+ inc b ; go on to next mon
+ jr .checkPreviousMonsLoop
+
+.infectMon
+ ld a, c
+ and $f0
+ ld b, a
+ ld a, c
+ swap a
+ and $3
+ inc a
+ add b
+ ld [hl], a
+ ret
+
+ConvertBerriesToBerryJuice:
+; If we haven't been to Goldenrod City at least once,
+; prevent Shuckle from turning held Berry into Berry Juice.
+ ld hl, wStatusFlags2
+ bit STATUSFLAGS2_REACHED_GOLDENROD_F, [hl]
+ ret z
+ call Random
+ cp 1 out_of 16 ; 6.25% chance
+ ret nc
+ ld hl, wPartyMons
+ ld a, [wPartyCount]
+.partyMonLoop
+ push af
+ push hl
+ ld a, [hl]
+ cp SHUCKLE
+ jr nz, .loopMon
+ ld bc, MON_ITEM
+ add hl, bc
+ ld a, [hl]
+ cp BERRY
+ jr z, .convertToJuice
+
+.loopMon
+ pop hl
+ ld bc, PARTYMON_STRUCT_LENGTH
+ add hl, bc
+ pop af
+ dec a
+ jr nz, .partyMonLoop
+ ret
+
+.convertToJuice
+ ld a, BERRY_JUICE
+ ld [hl], a
+ pop hl
+ pop af
+ ret
diff --git a/engine/events/print_photo.asm b/engine/events/print_photo.asm
new file mode 100644
index 00000000..056788b9
--- /dev/null
+++ b/engine/events/print_photo.asm
@@ -0,0 +1,50 @@
+PhotoStudio:
+ ld hl, .WhichMonPhotoText
+ call PrintText
+ farcall SelectMonFromParty
+ jr c, .cancel
+ ld a, [wCurPartySpecies]
+ cp EGG
+ jr z, .egg
+
+ ld hl, .HoldStillText
+ call PrintText
+ call DisableSpriteUpdates
+ farcall PrintPartymon
+ call ReturnToMapWithSpeechTextbox
+ ldh a, [hPrinter]
+ and a
+ jr nz, .cancel
+ ld hl, .PrestoAllDoneText
+ jr .print_text
+
+.cancel
+ ld hl, .NoPhotoText
+ jr .print_text
+
+.egg
+ ld hl, .EggPhotoText
+
+.print_text
+ call PrintText
+ ret
+
+.WhichMonPhotoText:
+ text_far _WhichMonPhotoText
+ text_end
+
+.HoldStillText:
+ text_far _HoldStillText
+ text_end
+
+.PrestoAllDoneText:
+ text_far _PrestoAllDoneText
+ text_end
+
+.NoPhotoText:
+ text_far _NoPhotoText
+ text_end
+
+.EggPhotoText:
+ text_far _EggPhotoText
+ text_end
diff --git a/engine/events/print_unown.asm b/engine/events/print_unown.asm
new file mode 100644
index 00000000..0d67ae72
--- /dev/null
+++ b/engine/events/print_unown.asm
@@ -0,0 +1,209 @@
+UNOWNSTAMP_BOLD_A EQU "♂" ; $ef
+UNOWNSTAMP_BOLD_B EQU "♀" ; $f5
+
+_UnownPrinter:
+ ld a, [wUnownDex]
+ and a
+ ret z
+
+ ldh a, [hInMenu]
+ push af
+ ld a, $1
+ ldh [hInMenu], a
+ ld a, [wOptions]
+ push af
+ set NO_TEXT_SCROLL, a
+ ld [wOptions], a
+ call ClearBGPalettes
+ call ClearTilemap
+
+ ld de, UnownDexATile
+ ld hl, vTiles0 tile UNOWNSTAMP_BOLD_A
+ lb bc, BANK(UnownDexATile), 1
+ call Request1bpp
+
+ ld de, UnownDexBTile
+ ld hl, vTiles0 tile UNOWNSTAMP_BOLD_B
+ lb bc, BANK(UnownDexBTile), 1
+ call Request1bpp
+
+ hlcoord 0, 0
+ lb bc, 3, 18
+ call Textbox
+
+ hlcoord 0, 5
+ lb bc, 7, 7
+ call Textbox
+
+ hlcoord 0, 14
+ lb bc, 2, 18
+ call Textbox
+
+ hlcoord 1, 2
+ ld de, AlphRuinsStampString
+ call PlaceString
+
+ hlcoord 1, 16
+ ld de, UnownDexDoWhatString
+ call PlaceString
+
+ hlcoord 10, 6
+ ld de, UnownDexMenuString
+ call PlaceString
+
+ xor a
+ ld [wJumptableIndex], a
+ call .UpdateUnownFrontpic
+ call WaitBGMap
+
+ ld a, UNOWN
+ ld [wCurPartySpecies], a
+ xor a
+ ld [wTempMonDVs], a
+ ld [wTempMonDVs + 1], a
+
+ ld b, SCGB_TRAINER_OR_MON_FRONTPIC_PALS
+ call GetSGBLayout
+ call SetPalettes
+
+.joy_loop
+ call JoyTextDelay
+
+ ldh a, [hJoyPressed]
+ and B_BUTTON
+ jr nz, .pressed_b
+
+ ldh a, [hJoyPressed]
+ and A_BUTTON
+ jr nz, .pressed_a
+
+ call .LeftRight
+ call DelayFrame
+ jr .joy_loop
+
+.pressed_a
+ ld a, [wJumptableIndex]
+ push af
+ farcall PrintUnownStamp
+ call RestartMapMusic
+ pop af
+ ld [wJumptableIndex], a
+ jr .joy_loop
+
+.pressed_b
+ pop af
+ ld [wOptions], a
+ pop af
+ ldh [hInMenu], a
+ call ReturnToMapFromSubmenu
+ ret
+
+.LeftRight:
+ ldh a, [hJoyLast]
+ and D_RIGHT
+ jr nz, .press_right
+ ldh a, [hJoyLast]
+ and D_LEFT
+ jr nz, .press_left
+ ret
+
+.press_left
+ ld hl, wJumptableIndex
+ ld a, [hl]
+ and a
+ jr nz, .wrap_around_left
+ ld [hl], NUM_UNOWN + 1
+.wrap_around_left
+ dec [hl]
+ jr .return
+
+.press_right
+ ld hl, wJumptableIndex
+ ld a, [hl]
+ cp NUM_UNOWN
+ jr c, .wrap_around_right
+ ld [hl], -1
+.wrap_around_right
+ inc [hl]
+
+.return
+ call .UpdateUnownFrontpic
+ ret
+
+.UpdateUnownFrontpic:
+ ld a, [wJumptableIndex]
+ cp NUM_UNOWN
+ jr z, .vacant
+ inc a
+ ld [wUnownLetter], a
+ ld a, UNOWN
+ ld [wCurPartySpecies], a
+ xor a
+ ld [wBoxAlignment], a
+ ld de, vTiles2
+ predef GetMonFrontpic
+ hlcoord 1, 6
+ xor a
+ ldh [hGraphicStartTile], a
+ lb bc, 7, 7
+ predef PlaceGraphic
+ ld de, vTiles2 tile $31
+ farcall RotateUnownFrontpic
+ ret
+
+.vacant
+ hlcoord 1, 6
+ lb bc, 7, 7
+ call ClearBox
+ hlcoord 1, 9
+ ld de, UnownDexVacantString
+ call PlaceString
+ xor a ; sScratch
+ call OpenSRAM
+ ld hl, sScratch
+ ld bc, $31 tiles
+ xor a
+ call ByteFill
+ ld hl, vTiles2 tile $31
+ ld de, sDecompressScratch
+ ld c, $31
+ ldh a, [hROMBank]
+ ld b, a
+ call Get2bpp
+ call CloseSRAM
+ ld c, 20
+ call DelayFrames
+ ret
+
+AlphRuinsStampString:
+ db " ALPH RUINS STAMP@"
+
+UnownDexDoWhatString:
+ db "Do what?@"
+
+UnownDexMenuString:
+ db UNOWNSTAMP_BOLD_A, "▶PRINT"
+ next UNOWNSTAMP_BOLD_B, "▶CANCEL"
+ next "L▶BEFORE"
+ next "R▶NEXT"
+ db "@"
+
+UnownDexVacantString:
+ db "VACANT@"
+
+UnownDexATile:
+INCBIN "gfx/printer/bold_a.1bpp"
+UnownDexBTile:
+INCBIN "gfx/printer/bold_b.1bpp"
+
+PlaceUnownPrinterFrontpic:
+ hlcoord 0, 0
+ ld bc, SCREEN_WIDTH * SCREEN_HEIGHT
+ ld a, " "
+ call ByteFill
+ hlcoord 7, 11
+ ld a, $31
+ ldh [hGraphicStartTile], a
+ lb bc, 7, 7
+ predef PlaceGraphic
+ ret
diff --git a/engine/events/prof_oaks_pc.asm b/engine/events/prof_oaks_pc.asm
new file mode 100644
index 00000000..40230d5b
--- /dev/null
+++ b/engine/events/prof_oaks_pc.asm
@@ -0,0 +1,193 @@
+ProfOaksPC:
+ ld hl, OakPCText1
+ call MenuTextbox
+ call YesNoBox
+ jr c, .shutdown
+ call ProfOaksPCBoot ; player chose "yes"?
+.shutdown
+ ld hl, OakPCText4
+ call PrintText
+ call JoyWaitAorB
+ call ExitMenu
+ ret
+
+ProfOaksPCBoot:
+ ld hl, OakPCText2
+ call PrintText
+ call Rate
+ call PlaySFX ; sfx loaded by previous Rate function call
+ call JoyWaitAorB
+ call WaitSFX
+ ret
+
+ProfOaksPCRating:
+ call Rate
+ push de
+ ld de, MUSIC_NONE
+ call PlayMusic
+ pop de
+ call PlaySFX
+ call JoyWaitAorB
+ call WaitSFX
+ ret
+
+Rate:
+; calculate Seen/Owned
+ ld hl, wPokedexSeen
+ ld b, wEndPokedexSeen - wPokedexSeen
+ call CountSetBits
+ ld [wceed], a
+ ld hl, wPokedexCaught
+ ld b, wEndPokedexCaught - wPokedexCaught
+ call CountSetBits
+ ld [wceee], a
+
+; print appropriate rating
+ call .UpdateRatingBuffers
+ ld hl, OakPCText3
+ call PrintText
+ call JoyWaitAorB
+ ld a, [wceee]
+ ld hl, OakRatings
+ call FindOakRating
+ push de
+ call PrintText
+ pop de
+ ret
+
+.UpdateRatingBuffers:
+ ld hl, wStringBuffer3
+ ld de, wceed
+ call .UpdateRatingBuffer
+ ld hl, wStringBuffer4
+ ld de, wceee
+ call .UpdateRatingBuffer
+ ret
+
+.UpdateRatingBuffer:
+ push hl
+ ld a, "@"
+ ld bc, ITEM_NAME_LENGTH
+ call ByteFill
+ pop hl
+ lb bc, PRINTNUM_LEFTALIGN | 1, 3
+ call PrintNum
+ ret
+
+FindOakRating:
+; return sound effect in de
+; return text pointer in hl
+ nop
+ ld c, a
+.loop
+ ld a, [hli]
+ cp c
+ jr nc, .match
+rept 4
+ inc hl
+endr
+ jr .loop
+
+.match
+ ld a, [hli]
+ ld e, a
+ ld a, [hli]
+ ld d, a
+ ld a, [hli]
+ ld h, [hl]
+ ld l, a
+ ret
+
+INCLUDE "data/events/pokedex_ratings.asm"
+
+OakPCText1:
+ text_far _OakPCText1
+ text_end
+
+OakPCText2:
+ text_far _OakPCText2
+ text_end
+
+OakPCText3:
+ text_far _OakPCText3
+ text_end
+
+OakRating01:
+ text_far _OakRating01
+ text_end
+
+OakRating02:
+ text_far _OakRating02
+ text_end
+
+OakRating03:
+ text_far _OakRating03
+ text_end
+
+OakRating04:
+ text_far _OakRating04
+ text_end
+
+OakRating05:
+ text_far _OakRating05
+ text_end
+
+OakRating06:
+ text_far _OakRating06
+ text_end
+
+OakRating07:
+ text_far _OakRating07
+ text_end
+
+OakRating08:
+ text_far _OakRating08
+ text_end
+
+OakRating09:
+ text_far _OakRating09
+ text_end
+
+OakRating10:
+ text_far _OakRating10
+ text_end
+
+OakRating11:
+ text_far _OakRating11
+ text_end
+
+OakRating12:
+ text_far _OakRating12
+ text_end
+
+OakRating13:
+ text_far _OakRating13
+ text_end
+
+OakRating14:
+ text_far _OakRating14
+ text_end
+
+OakRating15:
+ text_far _OakRating15
+ text_end
+
+OakRating16:
+ text_far _OakRating16
+ text_end
+
+OakRating17:
+ text_far _OakRating17
+ text_end
+
+OakRating18:
+ text_far _OakRating18
+ text_end
+
+OakRating19:
+ text_far _OakRating19
+ text_end
+
+OakPCText4:
+ text_far _OakPCText4
+ text_end
diff --git a/engine/events/repel.asm b/engine/events/repel.asm
new file mode 100644
index 00000000..e324239c
--- /dev/null
+++ b/engine/events/repel.asm
@@ -0,0 +1,10 @@
+RepelWoreOffScript::
+ opentext
+ writetext .RepelWoreOffText
+ waitbutton
+ closetext
+ end
+
+.RepelWoreOffText:
+ text_far _RepelWoreOffText
+ text_end
diff --git a/engine/events/shuckle.asm b/engine/events/shuckle.asm
index e83357b2..668a99b0 100755
--- a/engine/events/shuckle.asm
+++ b/engine/events/shuckle.asm
@@ -2,7 +2,7 @@ MANIA_OT_ID EQU 00518
GiveShuckle:
; Adding to the party.
- xor a
+ xor a ; PARTYMON
ld [wMonType], a
; Level 15 Shuckle.
@@ -50,7 +50,8 @@ GiveShuckle:
call CopyName2
; Engine flag for this event.
- SetFlag ENGINE_GOT_SHUCKIE_TODAY
+ ld hl, wDailyFlags1
+ set DAILYFLAGS1_GOT_SHUCKIE_TODAY_F, [hl]
ld a, 1
ld [wScriptVar], a
ret
@@ -62,6 +63,7 @@ GiveShuckle:
SpecialShuckleOT:
db "MANIA@"
+
SpecialShuckleNick:
db "SHUCKIE@"
diff --git a/engine/events/specials.asm b/engine/events/specials.asm
new file mode 100755
index 00000000..91ca4208
--- /dev/null
+++ b/engine/events/specials.asm
@@ -0,0 +1,463 @@
+Special::
+; Run script special de.
+ ld hl, SpecialsPointers
+ add hl, de
+ add hl, de
+ add hl, de
+ ld b, [hl]
+ inc hl
+ ld a, [hli]
+ ld h, [hl]
+ ld l, a
+ ld a, b
+ rst FarCall
+ ret
+
+INCLUDE "data/special_pointers.asm"
+
+DummySpecial_c389:
+ ret
+
+GameCornerPrizeMonCheckDex:
+ ld a, [wScriptVar]
+ dec a
+ call CheckCaughtMon
+ ret nz
+ ld a, [wScriptVar]
+ dec a
+ call SetSeenAndCaughtMon
+ call FadeToMenu
+ ld a, [wScriptVar]
+ ld [wNamedObjectIndexBuffer], a
+ farcall NewPokedexEntry
+ call ExitAllMenus
+ ret
+
+UnusedSetSeenMon:
+ ld a, [wScriptVar]
+ dec a
+ call SetSeenMon
+ ret
+
+FindPartyMonAboveLevel:
+ ld a, [wScriptVar]
+ ld b, a
+ farcall _FindPartyMonAboveLevel
+ jr z, FoundNone
+ jr FoundOne
+
+FindPartyMonAtLeastThatHappy:
+ ld a, [wScriptVar]
+ ld b, a
+ farcall _FindPartyMonAtLeastThatHappy
+ jr z, FoundNone
+ jr FoundOne
+
+FindPartyMonThatSpecies:
+ ld a, [wScriptVar]
+ ld b, a
+ farcall _FindPartyMonThatSpecies
+ jr z, FoundNone
+ jr FoundOne
+
+FindPartyMonThatSpeciesYourTrainerID:
+ ld a, [wScriptVar]
+ ld b, a
+ farcall _FindPartyMonThatSpeciesYourTrainerID
+ jr z, FoundNone
+ jr FoundOne
+
+FoundOne:
+ ld a, TRUE
+ ld [wScriptVar], a
+ ret
+
+FoundNone:
+ xor a
+ ld [wScriptVar], a
+ ret
+
+NameRival:
+ ld b, NAME_RIVAL
+ ld de, wRivalName
+ farcall _NamingScreen
+ ; default to "SILVER"
+ ld hl, wRivalName
+ ld de, .default
+ call InitName
+ ret
+
+.default
+IF DEF(_GOLD)
+ db "SILVER@"
+ELIF DEF(_SILVER)
+ db "GOLD@"
+ENDC
+
+NameRater:
+ farcall _NameRater
+ ret
+
+OverworldTownMap:
+ call FadeToMenu
+ farcall _TownMap
+ call ExitAllMenus
+ ret
+
+UnownPrinter:
+ call FadeToMenu
+ farcall _UnownPrinter
+ call ExitAllMenus
+ ret
+
+DisplayLinkRecord:
+ call FadeToMenu
+ farcall _DisplayLinkRecord
+ call ExitAllMenus
+ ret
+
+PlayersHousePC:
+ xor a
+ ld [wScriptVar], a
+ farcall _PlayersHousePC
+ ld a, c
+ ld [wScriptVar], a
+ ret
+
+CheckMysteryGift:
+ ld a, BANK(sMysteryGiftItem)
+ call OpenSRAM
+ ld a, [sMysteryGiftItem]
+ and a
+ jr z, .no
+ inc a
+
+.no
+ ld [wScriptVar], a
+ call CloseSRAM
+ ret
+
+GetMysteryGiftItem:
+ ld a, BANK(sMysteryGiftItem)
+ call OpenSRAM
+ ld a, [sMysteryGiftItem]
+ ld [wCurItem], a
+ ld a, 1
+ ld [wItemQuantityChangeBuffer], a
+ ld hl, wNumItems
+ call ReceiveItem
+ jr nc, .no_room
+ xor a
+ ld [sMysteryGiftItem], a
+ call CloseSRAM
+ ld a, [wCurItem]
+ ld [wNamedObjectIndexBuffer], a
+ call GetItemName
+ ld hl, .ReceiveItemText
+ call PrintText
+ ld a, TRUE
+ ld [wScriptVar], a
+ ret
+
+.no_room
+ call CloseSRAM
+ xor a
+ ld [wScriptVar], a
+ ret
+
+.ReceiveItemText:
+ text_far _ReceiveItemText
+ text_end
+
+BugContestJudging:
+ farcall _BugContestJudging
+ ld a, b
+ ld [wScriptVar], a
+ ret
+
+MapRadio:
+ ld a, [wScriptVar]
+ ld e, a
+ farcall PlayRadio
+ ret
+
+UnownPuzzle:
+ call FadeToMenu
+ farcall _UnownPuzzle
+ ld a, [wSolvedUnownPuzzle]
+ ld [wScriptVar], a
+ call ExitAllMenus
+ ret
+
+SlotMachine:
+ call CheckCoinsAndCoinCase
+ ret c
+ ld a, BANK(_SlotMachine)
+ ld hl, _SlotMachine
+ call StartGameCornerGame
+ ret
+
+CardFlip:
+ call CheckCoinsAndCoinCase
+ ret c
+ ld a, BANK(_CardFlip)
+ ld hl, _CardFlip
+ call StartGameCornerGame
+ ret
+
+DummyNonfunctionalGameCornerGame:
+ call CheckCoinsAndCoinCase
+ ret c
+ ld a, BANK(_DummyGame)
+ ld hl, _DummyGame
+ call StartGameCornerGame
+ ret
+
+StartGameCornerGame:
+ call FarQueueScript
+ call FadeToMenu
+ ld hl, wQueuedScriptBank
+ ld a, [hli]
+ push af
+ ld a, [hli]
+ ld h, [hl]
+ ld l, a
+ pop af
+ rst FarCall
+ call ExitAllMenus
+ ret
+
+CheckCoinsAndCoinCase:
+ ld hl, wCoins
+ ld a, [hli]
+ or [hl]
+ jr z, .no_coins
+ ld a, COIN_CASE
+ ld [wCurItem], a
+ ld hl, wNumItems
+ call CheckItem
+ jr nc, .no_coin_case
+ and a
+ ret
+
+.no_coins
+ ld hl, .NoCoinsText
+ jr .print
+
+.no_coin_case
+ ld hl, .NoCoinCaseText
+
+.print
+ call PrintText
+ scf
+ ret
+
+.NoCoinsText:
+ text_far _NoCoinsText
+ text_end
+
+.NoCoinCaseText:
+ text_far _NoCoinCaseText
+ text_end
+
+ClearBGPalettesBufferScreen:
+ call ClearBGPalettes
+ call BufferScreen
+ ret
+
+ScriptReturnCarry:
+ jr c, .carry
+ xor a
+ ld [wScriptVar], a
+ ret
+.carry
+ ld a, 1
+ ld [wScriptVar], a
+ ret
+
+UnusedCheckUnusedTwoDayTimer:
+ farcall CheckUnusedTwoDayTimer
+ ld a, [wUnusedTwoDayTimer]
+ ld [wScriptVar], a
+ ret
+
+ActivateFishingSwarm:
+ ld a, [wScriptVar]
+ ld [wFishingSwarmFlag], a
+ jr SetSwarmFlag
+
+StoreSwarmMapIndices::
+ ld a, d
+ ld [wSwarmMapGroup], a
+ ld a, e
+ ld [wSwarmMapNumber], a
+ ; fallthrough
+SetSwarmFlag:
+ ld hl, wDailyFlags1
+ set DAILYFLAGS1_SWARM_F, [hl]
+ ret
+
+CheckSwarmFlag::
+ ld hl, wDailyFlags1
+ bit DAILYFLAGS1_SWARM_F, [hl]
+ jr z, .clear_swarm
+ xor a
+ ld [wScriptVar], a
+ ret
+
+.clear_swarm
+ ld a, 1
+ ld [wScriptVar], a
+ xor a
+ ld [wFishingSwarmFlag], a
+ ld [wSwarmMapGroup], a
+ ld [wSwarmMapNumber], a
+ ret
+
+CheckPokerus:
+; Check if a monster in your party has Pokerus
+ farcall _CheckPokerus
+ jp ScriptReturnCarry
+
+ResetLuckyNumberShowFlag:
+ farcall RestartLuckyNumberCountdown
+ ld hl, wLuckyNumberShowFlag
+ res LUCKYNUMBERSHOW_GAME_OVER_F, [hl]
+ farcall LoadOrRegenerateLuckyIDNumber
+ ret
+
+CheckLuckyNumberShowFlag:
+ farcall _CheckLuckyNumberShowFlag
+ jp ScriptReturnCarry
+
+CountUnown:
+ ld hl, wUnownDex
+ ld b, $0
+.loop
+ ld a, [hli]
+ and a
+ ret z
+ inc b
+ ld a, b
+ cp NUM_UNOWN
+ jr c, .loop
+ ret
+
+SelectApricornForKurt:
+ farcall Kurt_SelectApricorn
+ ld a, c
+ ld [wScriptVar], a
+ and a
+ ret z
+ ld [wCurItem], a
+ ld a, $1
+ ld [wItemQuantityChangeBuffer], a
+ ld hl, wNumItems
+ call TossItem
+ ret
+
+SnorlaxAwake:
+; Check if the Poké Flute channel is playing, and if the player is standing
+; next to Snorlax.
+
+; outputs:
+; wScriptVar is 1 if the conditions are met, otherwise 0.
+
+; check background music
+ ld a, [wMapMusic]
+ cp MUSIC_POKE_FLUTE_CHANNEL
+ jr nz, .nope
+
+ ld a, [wXCoord]
+ ld b, a
+ ld a, [wYCoord]
+ ld c, a
+
+ ld hl, .ProximityCoords
+.loop
+ ld a, [hli]
+ cp -1
+ jr z, .nope
+ cp b
+ jr nz, .nextcoord
+ ld a, [hli]
+ cp c
+ jr nz, .loop
+
+ ld a, TRUE
+ jr .done
+
+.nextcoord
+ inc hl
+ jr .loop
+
+.nope
+ xor a
+.done
+ ld [wScriptVar], a
+ ret
+
+.ProximityCoords:
+ ; x, y
+ db 33, 8 ; left
+ db 34, 10 ; below
+ db 35, 10 ; below
+ db 36, 8 ; right
+ db 36, 9 ; right
+ db -1
+
+PlayCurMonCry:
+ ld a, [wCurPartySpecies]
+ jp PlayMonCry
+
+GameboyCheck:
+ ldh a, [hCGB]
+ and a
+ jr nz, .cgb
+
+ ldh a, [hSGB]
+ and a
+ jr nz, .sgb
+
+.gb
+ xor a ; GBCHECK_GB
+ jr .done
+.sgb
+ ld a, GBCHECK_SGB
+ jr .done
+.cgb
+ ld a, GBCHECK_CGB
+.done
+ ld [wScriptVar], a
+ ret
+
+FadeOutMusic:
+ ld a, LOW(MUSIC_NONE)
+ ld [wMusicFadeID], a
+ ld a, HIGH(MUSIC_NONE)
+ ld [wMusicFadeID + 1], a
+ ld a, $2
+ ld [wMusicFade], a
+ ret
+
+Diploma:
+ call FadeToMenu
+ farcall _Diploma
+ call ExitAllMenus
+ ret
+
+PrintDiploma:
+ call FadeToMenu
+ farcall _PrintDiploma
+ call ExitAllMenus
+ ret
+
+TrainerHouse:
+ ld a, BANK(sMysteryGiftTrainerHouseFlag)
+ call OpenSRAM
+ ld a, [sMysteryGiftTrainerHouseFlag]
+ ld [wScriptVar], a
+ jp CloseSRAM
+
+; unused
+ nop
diff --git a/engine/events/std_collision.asm b/engine/events/std_collision.asm
index bb44687c..8c54c041 100755
--- a/engine/events/std_collision.asm
+++ b/engine/events/std_collision.asm
@@ -7,12 +7,12 @@ CheckFacingTileForStdScript::
jr nc, .notintable
ld a, jumpstd_command
- ld [wcf2a], a
+ ld [wJumpStdScriptBuffer], a
inc hl
ld a, [hli]
- ld [wcf2b], a
+ ld [wJumpStdScriptBuffer + 1], a
ld a, [hli]
- ld [wTempTrainer], a
+ ld [wJumpStdScriptBuffer + 2], a
ld a, BANK(Script_JumpStdFromRAM)
ld hl, Script_JumpStdFromRAM
call CallScript
@@ -26,4 +26,4 @@ CheckFacingTileForStdScript::
INCLUDE "data/events/collision_stdscripts.asm"
Script_JumpStdFromRAM:
- jump wcf2a \ No newline at end of file
+ sjump wJumpStdScriptBuffer
diff --git a/engine/events/trainer_scripts.asm b/engine/events/trainer_scripts.asm
new file mode 100644
index 00000000..1fb0d291
--- /dev/null
+++ b/engine/events/trainer_scripts.asm
@@ -0,0 +1,31 @@
+TalkToTrainerScript::
+ faceplayer
+ trainerflagaction CHECK_FLAG
+ iftrue AlreadyBeatenTrainerScript
+ loadtemptrainer
+ encountermusic
+ sjump StartBattleWithMapTrainerScript
+
+SeenByTrainerScript::
+ loadtemptrainer
+ encountermusic
+ showemote EMOTE_SHOCK, LAST_TALKED, 30
+ callasm TrainerWalkToPlayer
+ applymovementlasttalked wMovementBuffer
+ writeobjectxy LAST_TALKED
+ faceobject PLAYER, LAST_TALKED
+ sjump StartBattleWithMapTrainerScript
+
+StartBattleWithMapTrainerScript:
+ opentext
+ trainertext TRAINERTEXT_SEEN
+ waitbutton
+ closetext
+ loadtemptrainer
+ startbattle
+ reloadmapafterbattle
+ trainerflagaction SET_FLAG
+ loadmem wRunningTrainerBattleScript, -1
+
+AlreadyBeatenTrainerScript:
+ scripttalkafter
diff --git a/engine/events/treemons.asm b/engine/events/treemons.asm
new file mode 100644
index 00000000..c96df83a
--- /dev/null
+++ b/engine/events/treemons.asm
@@ -0,0 +1,273 @@
+TreeMonEncounter:
+ xor a
+ ld [wTempWildMonSpecies], a
+ ld [wCurPartyLevel], a
+
+ ld hl, TreeMonMaps
+ call GetTreeMonSet
+ jr nc, .no_battle
+
+ call GetTreeMons
+ jr nc, .no_battle
+
+ call GetTreeMon
+ jr nc, .no_battle
+
+ ld a, BATTLETYPE_TREE
+ ld [wBattleType], a
+ ld a, 1
+ ld [wScriptVar], a
+ ret
+
+.no_battle
+ xor a
+ ld [wScriptVar], a
+ ret
+
+RockMonEncounter:
+ xor a
+ ld [wTempWildMonSpecies], a
+ ld [wCurPartyLevel], a
+
+ ld hl, RockMonMaps
+ call GetTreeMonSet
+ jr nc, .no_battle
+
+ call GetTreeMons
+ jr nc, .no_battle
+
+ ; 40% chance of an encounter
+ ld a, 10
+ call RandomRange
+ cp 4
+ jr nc, .no_battle
+
+ call SelectTreeMon
+ jr nc, .no_battle
+
+ ret
+
+.no_battle
+ xor a
+ ret
+
+ db $05 ; ????
+
+GetTreeMonSet:
+; Return carry and treemon set in a
+; if the current map is in table hl.
+ ld a, [wMapNumber]
+ ld e, a
+ ld a, [wMapGroup]
+ ld d, a
+.loop
+ ld a, [hli]
+ cp -1
+ jr z, .not_in_table
+
+ cp d
+ jr nz, .skip2
+
+ ld a, [hli]
+ cp e
+ jr nz, .skip1
+
+ jr .in_table
+
+.skip2
+ inc hl
+.skip1
+ inc hl
+ jr .loop
+
+.not_in_table
+ xor a
+ ret
+
+.in_table
+ ld a, [hl]
+ scf
+ ret
+
+INCLUDE "data/wild/treemon_maps.asm"
+
+GetTreeMons:
+; Return the address of TreeMon table a in hl.
+; Return nc if table a doesn't exist.
+
+ cp NUM_TREEMON_SETS
+ jr nc, .quit
+
+ and a
+ jr z, .quit
+
+ ld e, a
+ ld d, 0
+ ld hl, TreeMons
+ add hl, de
+ add hl, de
+
+ ld a, [hli]
+ ld h, [hl]
+ ld l, a
+
+ scf
+ ret
+
+.quit
+ xor a
+ ret
+
+INCLUDE "data/wild/treemons.asm"
+
+GetTreeMon:
+ push hl
+ call GetTreeScore
+ pop hl
+ and a ; TREEMON_SCORE_BAD
+ jr z, .bad
+ cp TREEMON_SCORE_GOOD
+ jr z, .good
+ cp TREEMON_SCORE_RARE
+ jr z, .rare
+ ret
+
+.bad
+ ; 10% chance of an encounter
+ ld a, 10
+ call RandomRange
+ and a
+ jr nz, NoTreeMon
+ jr SelectTreeMon
+
+.good
+ ; 50% chance of an encounter
+ ld a, 10
+ call RandomRange
+ cp 5
+ jr nc, NoTreeMon
+ jr SelectTreeMon
+
+.rare
+ ; 80% chance of an encounter
+ ld a, 10
+ call RandomRange
+ cp 8
+ jr nc, NoTreeMon
+ jr .skip
+.skip
+ ld a, [hli]
+ cp -1
+ jr nz, .skip
+ call SelectTreeMon
+ ret
+
+SelectTreeMon:
+; Read a TreeMons table and pick one monster at random.
+
+ ld a, 100
+ call RandomRange
+.loop
+ sub [hl]
+ jr c, .ok
+ inc hl
+ inc hl
+ inc hl
+ jr .loop
+
+.ok
+ ld a, [hli]
+ cp -1
+ jr z, NoTreeMon
+
+ ld a, [hli]
+ ld [wTempWildMonSpecies], a
+ ld a, [hl]
+ ld [wCurPartyLevel], a
+ scf
+ ret
+
+NoTreeMon:
+ xor a
+ ld [wTempWildMonSpecies], a
+ ld [wCurPartyLevel], a
+ ret
+
+GetTreeScore:
+ call .CoordScore
+ ld [wBuffer1], a
+ call .OTIDScore
+ ld [wBuffer2], a
+ ld c, a
+ ld a, [wBuffer1]
+ sub c
+ jr z, .rare
+ jr nc, .ok
+ add 10
+.ok
+ cp 5
+ jr c, .good
+
+.bad
+ xor a ; TREEMON_SCORE_BAD
+ ret
+
+.good
+ ld a, TREEMON_SCORE_GOOD
+ ret
+
+.rare
+ ld a, TREEMON_SCORE_RARE
+ ret
+
+.CoordScore:
+ call GetFacingTileCoord
+ ld hl, 0
+ ld c, e
+ ld b, 0
+ ld a, d
+
+ and a
+ jr z, .next
+.loop
+ add hl, bc
+ dec a
+ jr nz, .loop
+.next
+
+ add hl, bc
+ ld c, d
+ add hl, bc
+
+ ld a, h
+ ldh [hDividend], a
+ ld a, l
+ ldh [hDividend + 1], a
+ ld a, 5
+ ldh [hDivisor], a
+ ld b, 2
+ call Divide
+
+ ldh a, [hQuotient + 2]
+ ldh [hDividend], a
+ ldh a, [hQuotient + 3]
+ ldh [hDividend + 1], a
+ ld a, 10
+ ldh [hDivisor], a
+ ld b, 2
+ call Divide
+
+ ldh a, [hRemainder]
+ ret
+
+.OTIDScore:
+ ld a, [wPlayerID]
+ ldh [hDividend], a
+ ld a, [wPlayerID + 1]
+ ldh [hDividend + 1], a
+ ld a, 10
+ ldh [hDivisor], a
+ ld b, 2
+ call Divide
+ ldh a, [hRemainder]
+ ret
diff --git a/engine/events/whiteout.asm b/engine/events/whiteout.asm
index 01d7b388..635be636 100755
--- a/engine/events/whiteout.asm
+++ b/engine/events/whiteout.asm
@@ -1,6 +1,6 @@
Script_BattleWhiteout::
callasm BattleBGMap
- jump Script_Whiteout
+ sjump Script_Whiteout
Script_OverworldWhiteout::
refreshscreen
@@ -25,9 +25,8 @@ Script_Whiteout:
jumpstd bugcontestresultswarp
.WhitedOutText:
- ; is out of useable #MON! whited out!
- text_far UnknownText_0x1c0a4e
- db "@"
+ text_far _WhitedOutText
+ text_end
OverworldBGMap:
call ClearPalettes
@@ -58,19 +57,15 @@ HalveMoney:
ret
GetWhiteoutSpawn:
- ld a, [wd9fb]
+ ld a, [wLastSpawnMapGroup]
ld d, a
- ld a, [wd9fc]
+ ld a, [wLastSpawnMapNumber]
ld e, a
-
- ld a, $05
- ld hl, $5465
- rst $08
-
+ farcall IsSpawnPoint
ld a, c
jr c, .yes
xor a ; SPAWN_HOME
.yes
- ld [wceec], a
+ ld [wDefaultSpawnpoint], a
ret
diff --git a/engine/facings.asm b/engine/facings.asm
deleted file mode 100644
index a5669c2b..00000000
--- a/engine/facings.asm
+++ /dev/null
@@ -1,265 +0,0 @@
-Facings: ; 404a
- dw Facing00
- dw Facing01
- dw Facing02
- dw Facing03
- dw Facing04
- dw Facing05
- dw Facing06
- dw Facing07
- dw Facing08
- dw Facing09
- dw Facing10
- dw Facing11
- dw Facing12
- dw Facing13
- dw Facing14
- dw Facing15
- dw Facing16
- dw Facing17
- dw Facing18
- dw Facing19
- dw Facing20
- dw Facing21
- dw Facing22
- dw Facing23
- dw Facing24
- dw Facing25
- dw Facing26
- dw Facing27
- dw Facing28
- dw Facing29
- dw Facing30
- dw Facing31
-FacingsEnd: dw 0
-
-NUM_FACINGS EQU (FacingsEnd - Facings) / 2
-
-
-; Tables used as a reference to transform OAM data.
-
-; Format:
-; db y, x, attributes, tile index
-
-; Attributes:
-BEHIND_BG EQU 1 << OAM_PRIORITY
-
-Facing00:
-Facing02:
-Facing24:
-Facing26: ; standing down
- db 4 ; #
- db 0, 0, 0, $00
- db 0, 8, 0, $01
- db 8, 0, 2, $02
- db 8, 8, 2, $03
-; 409d
-
-Facing01: ; walking down 1
- db 4 ; #
- db 0, 0, 0, $80
- db 0, 8, 0, $81
- db 8, 0, 2, $82
- db 8, 8, 2, $83
-; 40ae
-
-Facing03: ; walking down 2
- db 4 ; #
- db 0, 8, X_FLIP, $80
- db 0, 0, X_FLIP, $81
- db 8, 8, 2 | X_FLIP, $82
- db 8, 0, 2 | X_FLIP, $83
-; 40bf
-
-Facing04:
-Facing06: ; standing up
- db 4 ; #
- db 0, 0, 0, $04
- db 0, 8, 0, $05
- db 8, 0, 2, $06
- db 8, 8, 2, $07
-; 40d0
-
-Facing05: ; walking up 1
- db 4 ; #
- db 0, 0, 0, $84
- db 0, 8, 0, $85
- db 8, 0, 2, $86
- db 8, 8, 2, $87
-; 40e1
-
-Facing07: ; walking up 2
- db 4 ; #
- db 0, 8, X_FLIP, $84
- db 0, 0, X_FLIP, $85
- db 8, 8, 2 | X_FLIP, $86
- db 8, 0, 2 | X_FLIP, $87
-; 40f2
-
-Facing08:
-Facing10: ; standing left
- db 4 ; #
- db 0, 0, 0, $08
- db 0, 8, 0, $09
- db 8, 0, 2, $0a
- db 8, 8, 2, $0b
-; 4103
-
-Facing12:
-Facing14: ; standing right
- db 4 ; #
- db 0, 8, X_FLIP, $08
- db 0, 0, X_FLIP, $09
- db 8, 8, 2 | X_FLIP, $0a
- db 8, 0, 2 | X_FLIP, $0b
-; 4114
-
-Facing09:
-Facing11: ; walking left
- db 4 ; #
- db 0, 0, 0, $88
- db 0, 8, 0, $89
- db 8, 0, 2, $8a
- db 8, 8, 2, $8b
-; 4125
-
-Facing13:
-Facing15: ; walking right
- db 4 ; #
- db 0, 8, X_FLIP, $88
- db 0, 0, X_FLIP, $89
- db 8, 8, 2 | X_FLIP, $8a
- db 8, 0, 2 | X_FLIP, $8b
-; 4136
-
-Facing16: ; fishing down
- db 5 ; #
- db 0, 0, 0, $00
- db 0, 8, 0, $01
- db 8, 0, 2, $02
- db 8, 8, 2, $03
- db 16, 0, 4, $fc
-; 414b
-
-Facing17: ; fishing up
- db 5 ; #
- db 0, 0, 0, $04
- db 0, 8, 0, $05
- db 8, 0, 2, $06
- db 8, 8, 2, $07
- db -8, 0, 4, $fc
-; 4160
-
-Facing18: ; fishing left
- db 5 ; #
- db 0, 0, 0, $08
- db 0, 8, 0, $09
- db 8, 0, 2, $0a
- db 8, 8, 2, $0b
- db 5, -8, 4 | X_FLIP, $fd
-; 4175
-
-Facing19: ; fishing right
- db 5 ; #
- db 0, 8, X_FLIP, $08
- db 0, 0, X_FLIP, $09
- db 8, 8, 2 | X_FLIP, $0a
- db 8, 0, 2 | X_FLIP, $0b
- db 5, 16, 4, $fd
-; 418a
-
-Facing20: ; emote
- db 4 ; #
- db 0, 0, 4, $f8
- db 0, 8, 4, $f9
- db 8, 0, 4, $fa
- db 8, 8, 4, $fb
-; 419b
-
-Facing21: ; shadow
- db 2 ; #
- db 0, 0, 4, $fc
- db 0, 8, 4 | X_FLIP, $fc
-; 41a4
-
-Facing23: ; big snorlax or lapras doll
- db 16 ; #
- db 0, 0, 0, $00
- db 0, 8, 0, $01
- db 8, 0, 0, $02
- db 8, 8, 0, $03
- db 16, 0, 0, $04
- db 16, 8, 0, $05
- db 24, 0, 0, $06
- db 24, 8, 0, $07
- db 0, 24, X_FLIP, $00
- db 0, 16, X_FLIP, $01
- db 8, 24, X_FLIP, $02
- db 8, 16, X_FLIP, $03
- db 16, 24, X_FLIP, $04
- db 16, 16, X_FLIP, $05
- db 24, 24, X_FLIP, $06
- db 24, 16, X_FLIP, $07
-; 41e5
-
-Facing25: ; 41e4
- db 4 ; #
- db 0, 0, 0, $04
- db 0, 8, 0, $05
- db 8, 0, 0, $06
- db 8, 8, 0, $07
-; 41f6
-
-Facing27: ; 41f5
- db 4 ; #
- db 0, 8, X_FLIP, $04
- db 0, 0, X_FLIP, $05
- db 8, 8, X_FLIP, $06
- db 8, 0, X_FLIP, $07
-; 4207
-
-Facing22: ; big doll other than snorlax or lapras
- db 14 ; #
- db 0, 0, 0, $00
- db 0, 8, 0, $01
- db 8, 0, 0, $04
- db 8, 8, 0, $05
- db 16, 8, 0, $07
- db 24, 8, 0, $0a
- db 0, 24, 0, $03
- db 0, 16, 0, $02
- db 8, 24, X_FLIP, $02
- db 8, 16, 0, $06
- db 16, 24, 0, $09
- db 16, 16, 0, $08
- db 24, 24, X_FLIP, $04
- db 24, 16, 0, $0b
-; 4240
-
-Facing28: ; boulder dust 1
- db 4 ; #
- db 0, 0, 4, $fe
- db 0, 8, 4, $fe
- db 8, 0, 4, $fe
- db 8, 8, 4, $fe
-; 4251
-
-Facing29: ; boulder dust 2
- db 4 ; #
- db 0, 0, 4, $ff
- db 0, 8, 4, $ff
- db 8, 0, 4, $ff
- db 8, 8, 4, $ff
-; 4262
-
-Facing30: ; 4261
- db 2 ; #
- db 8, 0, 0, $00
- db 8, 8, 0 | X_FLIP, $00
-; 426b
-
-Facing31: ; 426a
- db 2 ; #
- db 9, -1, 0, $00
- db 9, 9, 0 | X_FLIP, $00
-; 4274
diff --git a/engine/games/slot_machine.asm b/engine/games/slot_machine.asm
new file mode 100644
index 00000000..7c017a6a
--- /dev/null
+++ b/engine/games/slot_machine.asm
@@ -0,0 +1,2208 @@
+SLOTS_NO_BIAS EQU -1
+SLOTS_NO_MATCH EQU -1
+
+SLOTS_SEVEN EQU $00
+SLOTS_POKEBALL EQU $04
+SLOTS_CHERRY EQU $08
+SLOTS_PIKACHU EQU $0c
+SLOTS_SQUIRTLE EQU $10
+SLOTS_STARYU EQU $14
+
+REEL_SIZE EQU 15
+
+; Constants for slot_reel offsets (see macros/wram.asm)
+REEL_ACTION EQUS "(wReel1ReelAction - wReel1)"
+REEL_TILEMAP_ADDR EQUS "(wReel1TilemapAddr - wReel1)"
+REEL_POSITION EQUS "(wReel1Position - wReel1)"
+REEL_SPIN_DISTANCE EQUS "(wReel1SpinDistance - wReel1)"
+REEL_SPIN_RATE EQUS "(wReel1SpinRate - wReel1)"
+REEL_OAM_ADDR EQUS "(wReel1OAMAddr - wReel1)"
+REEL_X_COORD EQUS "(wReel1XCoord - wReel1)"
+REEL_MANIP_COUNTER EQUS "(wReel1ManipCounter - wReel1)"
+REEL_MANIP_DELAY EQUS "(wReel1ManipDelay - wReel1)"
+REEL_FIELD_0B EQUS "(wReel1Field0b - wReel1)"
+REEL_STOP_DELAY EQUS "(wReel1StopDelay - wReel1)"
+
+; SlotsJumptable constants
+ const_def
+ const SLOTS_INIT
+ const SLOTS_BET_AND_START
+ const SLOTS_WAIT_START
+ const SLOTS_WAIT_REEL1
+ const SLOTS_WAIT_STOP_REEL1
+ const SLOTS_WAIT_REEL2
+ const SLOTS_WAIT_STOP_REEL2
+ const SLOTS_WAIT_REEL3
+ const SLOTS_WAIT_STOP_REEL3
+ const SLOTS_NEXT_09
+ const SLOTS_NEXT_0A
+ const SLOTS_NEXT_0B
+ const SLOTS_FLASH_IF_WIN
+ const SLOTS_FLASH_SCREEN
+ const SLOTS_GIVE_EARNED_COINS
+ const SLOTS_PAYOUT_TEXT_AND_ANIM
+ const SLOTS_PAYOUT_ANIM
+ const SLOTS_RESTART_OF_QUIT
+ const SLOTS_QUIT
+SLOTS_END_LOOP_F EQU 7
+
+; ReelActionJumptable constants
+ const_def
+ const REEL_ACTION_DO_NOTHING
+ const REEL_ACTION_STOP_REEL_IGNORE_JOYPAD
+ const REEL_ACTION_QUADRUPLE_RATE
+ const REEL_ACTION_DOUBLE_RATE
+ const REEL_ACTION_NORMAL_RATE
+ const REEL_ACTION_HALF_RATE
+ const REEL_ACTION_QUARTER_RATE
+ const REEL_ACTION_STOP_REEL1
+ const REEL_ACTION_STOP_REEL2
+ const REEL_ACTION_STOP_REEL3
+ const REEL_ACTION_SET_UP_REEL2_SKIP_TO_7
+ const REEL_ACTION_WAIT_REEL2_SKIP_TO_7
+ const REEL_ACTION_FAST_SPIN_REEL2_UNTIL_LINED_UP_7S
+ const REEL_ACTION_UNUSED
+ const REEL_ACTION_CHECK_DROP_REEL
+ const REEL_ACTION_WAIT_DROP_REEL
+ const REEL_ACTION_START_SLOW_ADVANCE_REEL3
+ const REEL_ACTION_WAIT_SLOW_ADVANCE_REEL3
+ const REEL_ACTION_INIT_GOLEM
+ const REEL_ACTION_WAIT_GOLEM
+ const REEL_ACTION_END_GOLEM
+ const REEL_ACTION_INIT_CHANSEY
+ const REEL_ACTION_WAIT_CHANSEY
+ const REEL_ACTION_WAIT_EGG
+ const REEL_ACTION_DROP_REEL
+
+_SlotMachine:
+ ld hl, wOptions
+ set NO_TEXT_SCROLL, [hl]
+ call .InitGFX
+ call DelayFrame
+.loop
+ call SlotsLoop
+ jr nc, .loop
+ call WaitSFX
+ ld de, SFX_QUIT_SLOTS
+ call PlaySFX
+ call WaitSFX
+ call ClearBGPalettes
+ ld hl, wOptions
+ res NO_TEXT_SCROLL, [hl]
+ ld hl, rLCDC
+ res rLCDC_SPRITE_SIZE, [hl] ; 8x8
+ ret
+
+.InitGFX:
+ call ClearBGPalettes
+ call ClearTilemap
+ call ClearSprites
+ ld de, MUSIC_NONE
+ call PlayMusic
+ call DelayFrame
+ call DisableLCD
+ hlbgcoord 0, 0
+ ld bc, vBGMap1 - vBGMap0
+ ld a, " "
+ call ByteFill
+ ld b, SCGB_SLOT_MACHINE
+ call GetSGBLayout
+ callfar ClearSpriteAnims
+ ld hl, wSlots
+ ld bc, wSlotsDataEnd - wSlots
+ xor a
+ call ByteFill
+
+ ld hl, Slots2LZ
+ ld de, vTiles0 tile $00
+ call Decompress
+
+ ld hl, Slots3LZ
+ ld de, vTiles0 tile $40
+ call Decompress
+
+ ld hl, Slots1LZ
+ ld de, vTiles2 tile $00
+ call Decompress
+
+ ld hl, Slots2LZ
+ ld de, vTiles2 tile $25
+ call Decompress
+
+ ld hl, SlotsTilemap
+ decoord 0, 0
+ ld bc, SCREEN_WIDTH * 12
+ call CopyBytes
+
+ ld hl, rLCDC
+ set rLCDC_SPRITE_SIZE, [hl] ; 8x16
+ call EnableLCD
+ ld hl, wSlots
+ ld bc, wSlotsEnd - wSlots
+ xor a
+ call ByteFill
+ call Slots_InitReelTiles
+ call Slots_GetPals
+ ld a, $7
+ ld hl, wSpriteAnimDict
+ ld [hli], a
+ ld [hl], $40
+ xor a ; SLOTS_INIT
+ ld [wJumptableIndex], a
+ ld a, SLOTS_NO_BIAS
+ ld [wSlotBias], a
+ ld de, MUSIC_GAME_CORNER
+ call PlayMusic
+ xor a
+ ld [wKeepSevenBiasChance], a ; 87.5% chance
+ call Random
+ and %00101010
+ ret nz
+ ld a, 1
+ ld [wKeepSevenBiasChance], a ; 12.5% chance
+ ret
+
+Slots_GetPals:
+ ld a, %11100100
+ call DmgToCgbBGPals
+ lb de, %11100100, %11100100
+ ldh a, [hCGB]
+ and a
+ jr nz, .cgb
+ lb de, %11000000, %11100100
+.cgb
+ call DmgToCgbObjPals
+ ret
+
+SlotsLoop:
+ ld a, [wJumptableIndex]
+ bit SLOTS_END_LOOP_F, a
+ jr nz, .stop
+ call SlotsJumptable
+ call Slots_SpinReels
+ xor a
+ ld [wCurSpriteOAMAddr], a
+ callfar DoNextFrameForFirst16Sprites
+ call .PrintCoinsAndPayout
+ call .Stubbed_Function92d3c
+ call DelayFrame
+ and a
+ ret
+
+.stop
+ scf
+ ret
+
+.Stubbed_Function92d3c:
+; dummied out
+ ret
+ ld a, [wReel1ReelAction]
+ and a
+ ret nz
+ ld a, [wReel2ReelAction]
+ and a
+ ret nz
+ ld a, [wFirstTwoReelsMatchingSevens]
+ and a
+ jr nz, .matching_sevens
+ ld a, %11100100
+ call DmgToCgbBGPals
+ ret
+
+.matching_sevens
+ ld a, [wTextDelayFrames]
+ and $7
+ ret nz
+ ldh a, [rBGP]
+ xor %00001100
+ call DmgToCgbBGPals
+ ret
+
+.PrintCoinsAndPayout:
+ hlcoord 5, 1
+ ld de, wCoins
+ lb bc, PRINTNUM_LEADINGZEROS | 2, 4
+ call PrintNum
+ hlcoord 11, 1
+ ld de, wPayout
+ lb bc, PRINTNUM_LEADINGZEROS | 2, 4
+ call PrintNum
+ ret
+
+Unreferenced_Function92d7a:
+; debug function?
+ ld a, [wSlotBias]
+ add 0
+ daa
+ ld e, a
+ and $f
+ add "0"
+ hlcoord 1, 0
+ ld [hl], a
+ ld a, e
+ swap a
+ and $f
+ add "0"
+ hlcoord 0, 0
+ ld [hl], a
+ ret
+
+Unreferenced_Function92d95:
+; animate OAM tiles?
+ ld hl, wSlotsCE66
+ ld a, [hl]
+ inc [hl]
+ and $7
+ ret nz
+ ld hl, wVirtualOAMSprite16TileID
+ ld c, NUM_SPRITE_OAM_STRUCTS - 16
+.loop
+ ld a, [hl]
+ xor %00100000
+ ld [hli], a ; tile id
+rept SPRITEOAMSTRUCT_LENGTH - 1
+ inc hl
+endr
+ dec c
+ jr nz, .loop
+ ret
+
+SlotsJumptable:
+ jumptable .Jumptable, wJumptableIndex
+
+.Jumptable:
+ dw SlotsAction_Init ; 00
+ dw SlotsAction_BetAndStart ; 01
+ dw SlotsAction_WaitStart ; 02
+ dw SlotsAction_WaitReel1 ; 03
+ dw SlotsAction_WaitStopReel1 ; 04
+ dw SlotsAction_WaitReel2 ; 05
+ dw SlotsAction_WaitStopReel2 ; 06
+ dw SlotsAction_WaitReel3 ; 07
+ dw SlotsAction_WaitStopReel3 ; 08
+ dw SlotsAction_Next ; 09
+ dw SlotsAction_Next ; 0a
+ dw SlotsAction_Next ; 0b
+ dw SlotsAction_FlashIfWin ; 0c
+ dw SlotsAction_FlashScreen ; 0d
+ dw SlotsAction_GiveEarnedCoins ; 0e
+ dw SlotsAction_PayoutTextAndAnim ; 0f
+ dw SlotsAction_PayoutAnim ; 10
+ dw SlotsAction_RestartOrQuit ; 11
+ dw SlotsAction_Quit ; 12
+
+SlotsAction_Next:
+ ld hl, wJumptableIndex
+ inc [hl]
+ ret
+
+SlotsAction_Init:
+ call SlotsAction_Next
+ xor a
+ ld [wFirstTwoReelsMatching], a
+ ld [wFirstTwoReelsMatchingSevens], a
+ ld a, SLOTS_NO_MATCH
+ ld [wSlotMatched], a
+ ret
+
+SlotsAction_BetAndStart:
+ call Slots_AskBet
+ jr nc, .proceed
+ ld a, SLOTS_QUIT
+ ld [wJumptableIndex], a
+ ret
+
+.proceed
+ call SlotsAction_Next
+ call Slots_IlluminateBetLights
+ call Slots_InitBias
+ ld a, 32
+ ld [wSlotsDelay], a
+ ld a, REEL_ACTION_NORMAL_RATE
+ ld [wReel1ReelAction], a
+ ld [wReel2ReelAction], a
+ ld [wReel3ReelAction], a
+ ld a, 4
+ ld [wReel1ManipCounter], a
+ ld [wReel2ManipCounter], a
+ ld [wReel3ManipCounter], a
+ call WaitSFX
+ ld a, SFX_SLOT_MACHINE_START
+ call Slots_PlaySFX
+ ret
+
+SlotsAction_WaitStart:
+ ld hl, wSlotsDelay
+ ld a, [hl]
+ and a
+ jr z, .proceed
+ dec [hl]
+ ret
+
+.proceed
+ call SlotsAction_Next
+ xor a
+ ldh [hJoypadSum], a
+ ret
+
+SlotsAction_WaitReel1:
+ ld hl, hJoypadSum
+ ld a, [hl]
+ and A_BUTTON
+ ret z
+ call SlotsAction_Next
+ call Slots_StopReel1
+ ld [wReel1ReelAction], a
+SlotsAction_WaitStopReel1:
+ ld a, [wReel1ReelAction]
+ cp REEL_ACTION_DO_NOTHING
+ ret nz
+ ld a, SFX_STOP_SLOT
+ call Slots_PlaySFX
+ ld bc, wReel1
+ ld de, wReel1Stopped
+ call Slots_LoadReelState
+ call SlotsAction_Next
+ xor a
+ ldh [hJoypadSum], a
+SlotsAction_WaitReel2:
+ ld hl, hJoypadSum
+ ld a, [hl]
+ and A_BUTTON
+ ret z
+ call SlotsAction_Next
+ call Slots_StopReel2
+ ld [wReel2ReelAction], a
+SlotsAction_WaitStopReel2:
+ ld a, [wReel2ReelAction]
+ cp REEL_ACTION_DO_NOTHING
+ ret nz
+ ld a, SFX_STOP_SLOT
+ call Slots_PlaySFX
+ ld bc, wReel2
+ ld de, wReel2Stopped
+ call Slots_LoadReelState
+ call SlotsAction_Next
+ xor a
+ ldh [hJoypadSum], a
+SlotsAction_WaitReel3:
+ ld hl, hJoypadSum
+ ld a, [hl]
+ and A_BUTTON
+ ret z
+ call SlotsAction_Next
+ call Slots_StopReel3
+ ld [wReel3ReelAction], a
+SlotsAction_WaitStopReel3:
+ ld a, [wReel3ReelAction]
+ cp REEL_ACTION_DO_NOTHING
+ ret nz
+ ld a, SFX_STOP_SLOT
+ call Slots_PlaySFX
+ ld bc, wReel3
+ ld de, wReel3Stopped
+ call Slots_LoadReelState
+ call SlotsAction_Next
+ xor a
+ ldh [hJoypadSum], a
+ ret
+
+SlotsAction_FlashIfWin:
+ ld a, [wSlotMatched]
+ cp SLOTS_NO_MATCH
+ jr nz, .GotIt
+ call SlotsAction_Next
+ call SlotsAction_Next
+ ret
+
+.GotIt:
+ call SlotsAction_Next
+ ld a, 16
+ ld [wSlotsDelay], a
+SlotsAction_FlashScreen:
+ ld hl, wSlotsDelay
+ ld a, [hl]
+ and a
+ jr z, .done
+ dec [hl]
+ srl a
+ ret z
+
+ ldh a, [rOBP0]
+ xor $ff
+ ld e, a
+ ld d, a
+ call DmgToCgbObjPals
+ ret
+
+.done
+ call Slots_GetPals
+ call SlotsAction_Next
+ ret
+
+SlotsAction_GiveEarnedCoins:
+ xor a
+ ld [wFirstTwoReelsMatching], a
+ ld [wFirstTwoReelsMatchingSevens], a
+ ld a, %11100100
+ call DmgToCgbBGPals
+ call Slots_GetPayout
+ xor a
+ ld [wSlotsDelay], a
+ call SlotsAction_Next
+ ret
+
+SlotsAction_PayoutTextAndAnim:
+ call Slots_PayoutText
+ call SlotsAction_Next
+SlotsAction_PayoutAnim:
+ ld hl, wSlotsDelay
+ ld a, [hl]
+ inc [hl]
+ and $1
+ ret z
+ ld hl, wPayout
+ ld a, [hli]
+ ld d, a
+ or [hl]
+ jr z, .done
+ ld e, [hl]
+ dec de
+ ld [hl], e
+ dec hl
+ ld [hl], d
+ ld hl, wCoins
+ ld d, [hl]
+ inc hl
+ ld e, [hl]
+ call Slots_CheckCoinCaseFull
+ jr c, .okay
+ inc de
+.okay
+ ld [hl], e
+ dec hl
+ ld [hl], d
+ ld a, [wSlotsDelay]
+ and $7
+ ret z ; ret nz would be more appropriate
+ ld de, SFX_GET_COIN_FROM_SLOTS
+ call PlaySFX
+ ret
+
+.done
+ call SlotsAction_Next
+ ret
+
+SlotsAction_RestartOrQuit:
+ call Slots_DeilluminateBetLights
+ call WaitPressAorB_BlinkCursor
+ call Slots_AskPlayAgain
+ jr c, .exit_slots
+ ld a, SLOTS_INIT
+ ld [wJumptableIndex], a
+ ret
+
+.exit_slots
+ ld a, SLOTS_QUIT
+ ld [wJumptableIndex], a
+ ret
+
+SlotsAction_Quit:
+ ld hl, wJumptableIndex
+ set SLOTS_END_LOOP_F, [hl]
+ ret
+
+Slots_LoadReelState:
+ push de
+ call Slots_GetCurrentReelState
+ pop de
+ ld a, [hli]
+ ld [de], a
+ inc de
+ ld a, [hli]
+ ld [de], a
+ inc de
+ ld a, [hli]
+ ld [de], a
+ ret
+
+Slots_CheckCoinCaseFull:
+ ld a, d
+ cp HIGH(MAX_COINS)
+ jr c, .not_full
+ ld a, e
+ cp LOW(MAX_COINS)
+ jr c, .not_full
+ scf
+ ret
+
+.not_full
+ and a
+ ret
+
+Slots_GetCurrentReelState:
+ ld hl, REEL_POSITION
+ add hl, bc
+ ld a, [hl]
+ and a
+ jr nz, .okay
+ ld a, $f
+.okay
+ dec a
+ and $f
+ ld e, a
+ ld d, $0
+ ld hl, REEL_TILEMAP_ADDR
+ add hl, bc
+ ld a, [hli]
+ ld h, [hl]
+ ld l, a
+ add hl, de
+ ret
+
+Slots_StopReel1:
+; Always set the REEL_ACTION_STOP_REEL1 action.
+ ld a, REEL_ACTION_STOP_REEL1
+ ret
+
+Slots_StopReel2:
+; As long as, the following three meet, there's a 31.25% chance
+; to set action REEL_ACTION_SET_UP_REEL2_SKIP_TO_7:
+; - Bet is >= 2 coins
+; - There's a 7 symbol visible in reel #1
+; - Current spin isn't biased or is biased towards SEVEN
+; In any other case, REEL_ACTION_STOP_REEL2 is set.
+
+ ld a, [wSlotBet]
+ cp $2
+ jr c, .dont_jump
+ ld a, [wSlotBias]
+ and a
+ jr z, .skip
+ cp SLOTS_NO_BIAS
+ jr nz, .dont_jump
+.skip
+ call .CheckReel1ForASeven
+ jr nz, .dont_jump
+ call Random
+ cp 31 percent + 1
+ jr nc, .dont_jump
+ ld a, REEL_ACTION_SET_UP_REEL2_SKIP_TO_7
+ ret
+
+.dont_jump
+ ld a, REEL_ACTION_STOP_REEL2
+ ret
+
+.CheckReel1ForASeven:
+ ld a, [wReel1Stopped]
+ and a
+ ret z
+ ld a, [wReel1Stopped + 1]
+ and a
+ ret z
+ ld a, [wReel1Stopped + 2]
+ and a
+ ret
+
+Slots_StopReel3:
+; If no matching SEVEN symbols in reels #1 and #2:
+; - REEL_ACTION_STOP_REEL3, 100%
+
+; If matching SEVEN symbols and NO bias to SEVEN:
+; - REEL_ACTION_STOP_REEL3, 37.5%
+; - REEL_ACTION_START_SLOW_ADVANCE_REEL3, 31.3%
+; - REEL_ACTION_INIT_GOLEM, 31.3%
+; - REEL_ACTION_INIT_CHANSEY, 0%
+
+; If matching SEVEN symbols and bias to SEVEN:
+; - REEL_ACTION_STOP_REEL3, 29.7%
+; - REEL_ACTION_START_SLOW_ADVANCE_REEL3, 23.4%
+; - REEL_ACTION_INIT_GOLEM, 23.4%
+; - REEL_ACTION_INIT_CHANSEY, 23.4%
+
+ ld a, [wFirstTwoReelsMatching]
+ and a
+ jr z, .stop
+ ld a, [wFirstTwoReelsMatchingSevens]
+ and a
+ jr z, .stop
+ ld a, [wSlotBias]
+ and a
+ jr nz, .biased
+ call Random
+ cp 71 percent - 1
+ jr nc, .stop
+ cp 47 percent + 1
+ jr nc, .slow_advance
+ cp 24 percent - 1
+ jr nc, .golem
+ ld a, REEL_ACTION_INIT_CHANSEY
+ ret
+
+.biased
+ call Random
+ cp 63 percent
+ jr nc, .stop
+ cp 31 percent + 1
+ jr nc, .slow_advance
+.golem
+ ld a, REEL_ACTION_INIT_GOLEM
+ ret
+
+.slow_advance
+ ld a, REEL_ACTION_START_SLOW_ADVANCE_REEL3
+ ret
+
+.stop
+ ld a, REEL_ACTION_STOP_REEL3
+ ret
+
+Slots_InitReelTiles:
+ ld bc, wReel1
+ ld hl, REEL_OAM_ADDR
+ add hl, bc
+ ld de, wVirtualOAMSprite16
+ ld [hl], e
+ inc hl
+ ld [hl], d
+ ld hl, REEL_TILEMAP_ADDR
+ add hl, bc
+ ld de, Reel1Tilemap
+ ld [hl], e
+ inc hl
+ ld [hl], d
+ ld hl, REEL_X_COORD
+ add hl, bc
+ ld [hl], 6 * 8
+ call .OAM
+
+ ld bc, wReel2
+ ld hl, REEL_OAM_ADDR
+ add hl, bc
+ ld de, wVirtualOAMSprite24
+ ld [hl], e
+ inc hl
+ ld [hl], d
+ ld hl, REEL_TILEMAP_ADDR
+ add hl, bc
+ ld de, Reel2Tilemap
+ ld [hl], e
+ inc hl
+ ld [hl], d
+ ld hl, REEL_X_COORD
+ add hl, bc
+ ld [hl], 10 * 8
+ call .OAM
+
+ ld bc, wReel3
+ ld hl, REEL_OAM_ADDR
+ add hl, bc
+ ld de, wVirtualOAMSprite32
+ ld [hl], e
+ inc hl
+ ld [hl], d
+ ld hl, REEL_TILEMAP_ADDR
+ add hl, bc
+ ld de, Reel3Tilemap
+ ld [hl], e
+ inc hl
+ ld [hl], d
+ ld hl, REEL_X_COORD
+ add hl, bc
+ ld [hl], 14 * 8
+ call .OAM
+ ret
+
+.OAM:
+ ld hl, REEL_ACTION
+ add hl, bc
+ ld [hl], REEL_ACTION_DO_NOTHING
+ ld hl, REEL_POSITION
+ add hl, bc
+ ld [hl], REEL_SIZE - 1
+ ld hl, REEL_SPIN_DISTANCE
+ add hl, bc
+ ld [hl], REEL_ACTION_DO_NOTHING
+ call Slots_UpdateReelPositionAndOAM
+ ret
+
+Slots_SpinReels:
+ ld bc, wReel1
+ call .SpinReel
+ ld bc, wReel2
+ call .SpinReel
+ ld bc, wReel3
+ call .SpinReel
+ ret
+
+.SpinReel:
+ ld hl, REEL_SPIN_DISTANCE
+ add hl, bc
+ ld a, [hl]
+ and $f
+ jr nz, .skip
+ call ReelActionJumptable
+.skip
+ ld hl, REEL_SPIN_RATE
+ add hl, bc
+ ld a, [hl]
+ and a
+ ret z
+ ld d, a
+ ld hl, REEL_SPIN_DISTANCE
+ add hl, bc
+ add [hl]
+ ld [hl], a
+ and $f
+ jr z, Slots_UpdateReelPositionAndOAM
+ ld hl, REEL_OAM_ADDR
+ add hl, bc
+ ld a, [hli]
+ ld h, [hl]
+ ld l, a
+ ld e, $8
+.loop
+ ld a, [hl]
+ add d
+ ld [hli], a
+ inc hl
+ inc hl
+ inc hl
+ dec e
+ jr nz, .loop
+ ret
+
+Slots_UpdateReelPositionAndOAM:
+ ld hl, REEL_X_COORD
+ add hl, bc
+ ld a, [hl]
+ ld [wCurReelXCoord], a
+ ld a, 10 * 8
+ ld [wCurReelYCoord], a
+ ld hl, REEL_POSITION
+ add hl, bc
+ ld e, [hl]
+ ld d, 0
+ ld hl, REEL_TILEMAP_ADDR
+ add hl, bc
+ ld a, [hli]
+ ld h, [hl]
+ ld l, a
+ add hl, de
+ ld e, l
+ ld d, h
+ call .LoadOAM
+ ld hl, REEL_POSITION
+ add hl, bc
+ ld a, [hl]
+ inc a
+ and $f
+ cp REEL_SIZE
+ jr nz, .load
+ xor a
+.load
+ ld [hl], a
+ ret
+
+.LoadOAM:
+ ld hl, REEL_OAM_ADDR
+ add hl, bc
+ ld a, [hli]
+ ld h, [hl]
+ ld l, a
+.loop
+ ld a, [wCurReelYCoord]
+ ld [hli], a ; y
+ ld a, [wCurReelXCoord]
+ ld [hli], a ; x
+ ld a, [de]
+ ld [hli], a ; tile id
+ srl a
+ srl a
+ set OAM_PRIORITY, a
+ ld [hli], a ; attributes
+
+ ld a, [wCurReelYCoord]
+ ld [hli], a ; y
+ ld a, [wCurReelXCoord]
+ add 1 * TILE_WIDTH
+ ld [hli], a ; x
+ ld a, [de]
+ inc a
+ inc a
+ ld [hli], a ; tile id
+ srl a
+ srl a
+ set OAM_PRIORITY, a
+ ld [hli], a ; attributes
+ inc de
+ ld a, [wCurReelYCoord]
+ sub 2 * TILE_WIDTH
+ ld [wCurReelYCoord], a
+ cp 2 * TILE_WIDTH
+ jr nz, .loop
+ ret
+
+Unreferenced_Function93127:
+ push hl
+ srl a
+ srl a
+ add LOW(.Unknown_93137)
+ ld l, a
+ ld a, 0
+ adc HIGH(.Unknown_93137)
+ ld h, a
+ ld a, [hl]
+ pop hl
+ ret
+
+.Unknown_93137:
+ db 0, 1, 2, 3, 4, 5
+
+ReelActionJumptable:
+ ld hl, REEL_ACTION
+ add hl, bc
+ ld e, [hl]
+ ld d, 0
+ ld hl, .Jumptable
+ add hl, de
+ add hl, de
+ ld a, [hli]
+ ld h, [hl]
+ ld l, a
+ jp hl
+
+.Jumptable:
+ dw ReelAction_DoNothing ; 00
+ dw ReelAction_StopReelIgnoreJoypad ; 01
+ dw ReelAction_QuadrupleRate ; 02
+ dw ReelAction_DoubleRate ; 03
+ dw ReelAction_NormalRate ; 04
+ dw ReelAction_HalfRate ; 05
+ dw ReelAction_QuarterRate ; 06
+ dw ReelAction_StopReel1 ; 07
+ dw ReelAction_StopReel2 ; 08
+ dw ReelAction_StopReel3 ; 09
+ dw ReelAction_SetUpReel2SkipTo7 ; 0a
+ dw ReelAction_WaitReel2SkipTo7 ; 0b
+ dw ReelAction_FastSpinReel2UntilLinedUp7s ; 0c
+ dw ReelAction_Unused ; 0d
+ dw ReelAction_CheckDropReel ; 0e
+ dw ReelAction_WaitDropReel ; 0f
+ dw ReelAction_StartSlowAdvanceReel3 ; 10
+ dw ReelAction_WaitSlowAdvanceReel3 ; 11
+ dw ReelAction_InitGolem ; 12
+ dw ReelAction_WaitGolem ; 13
+ dw ReelAction_EndGolem ; 14
+ dw ReelAction_InitChansey ; 15
+ dw ReelAction_WaitChansey ; 16
+ dw ReelAction_WaitEgg ; 17
+ dw ReelAction_DropReel ; 18
+
+ReelAction_DoNothing:
+ ret
+
+ReelAction_QuadrupleRate:
+ ld hl, REEL_SPIN_RATE
+ add hl, bc
+ ld [hl], 16
+ ret
+
+ReelAction_DoubleRate:
+ ld hl, REEL_SPIN_RATE
+ add hl, bc
+ ld [hl], 8
+ ret
+
+ReelAction_NormalRate:
+ ld hl, REEL_SPIN_RATE
+ add hl, bc
+ ld [hl], 4
+ ret
+
+ReelAction_HalfRate:
+ ld hl, REEL_SPIN_RATE
+ add hl, bc
+ ld [hl], 2
+ ret
+
+ReelAction_QuarterRate:
+ ld hl, REEL_SPIN_RATE
+ add hl, bc
+ ld [hl], 1
+ ret
+
+Slots_StopReel:
+ ld hl, REEL_SPIN_RATE
+ add hl, bc
+ ld [hl], 0
+ ld hl, REEL_ACTION
+ add hl, bc
+ ld [hl], REEL_ACTION_STOP_REEL_IGNORE_JOYPAD
+ ld hl, REEL_STOP_DELAY
+ add hl, bc
+ ld [hl], 3
+ReelAction_StopReelIgnoreJoypad:
+ ld hl, REEL_STOP_DELAY
+ add hl, bc
+ ld a, [hl]
+ and a
+ jr z, .EndReel
+ dec [hl]
+ ret
+
+.EndReel:
+ ld hl, REEL_ACTION
+ add hl, bc
+ ld a, REEL_ACTION_DO_NOTHING
+ ld [hl], a
+ ret
+
+ReelAction_StopReel1:
+; If no bias: don't manipulate reel.
+; If bias: manipulate reel up to wReel1ManipCounter (i.e. 4) slots,
+; stoping early if the biased symbol shows up anywhere in reel #1,
+; even if the current bet won't allow lining it up.
+
+ ld a, [wSlotBias]
+ cp SLOTS_NO_BIAS
+ jr z, .NoBias
+ ld hl, REEL_MANIP_COUNTER
+ add hl, bc
+ ld a, [hl]
+ and a
+ jr z, .NoBias
+ dec [hl]
+ call .CheckForBias
+ ret nz
+.NoBias:
+ call Slots_StopReel
+ ret
+
+.CheckForBias:
+ call Slots_GetCurrentReelState
+ ld a, [wSlotBias]
+ ld e, a
+ ld a, [hli]
+ cp e
+ ret z
+ ld a, [hli]
+ cp e
+ ret z
+ ld a, [hl]
+ cp e
+ ret
+
+ReelAction_StopReel2:
+; If no bias: don't manipulate reel.
+; If bias: manipulate reel up to wReel2ManipCounter (i.e. 4) slots,
+; stoping early if the biased symbol is lined up in the first two
+; reels, according to the lines that the current bet allows.
+
+ call Slots_CheckMatchedFirstTwoReels
+ jr nc, .nope
+ ld a, [wSlotBuildingMatch]
+ ld hl, wSlotBias
+ cp [hl]
+ jr z, .NoBias
+.nope
+ ld a, [wSlotBias]
+ cp SLOTS_NO_BIAS
+ jr z, .NoBias
+ ld hl, REEL_MANIP_COUNTER
+ add hl, bc
+ ld a, [hl]
+ and a
+ jr z, .NoBias
+ dec [hl]
+ ret
+
+.NoBias:
+ call Slots_StopReel
+ ret
+
+ReelAction_StopReel3:
+; Manipulate the reel up to wReel3ManipCounter (i.e. 4) slots,
+; stopping early if the bias symbol is lined up for a win.
+; If not biased to any symbols, stop as soon as nothing is lined up.
+
+ call Slots_CheckMatchedAllThreeReels
+ jr nc, .NoMatch
+ ld hl, wSlotBias
+ cp [hl]
+ jr z, .NoBias
+ ld hl, REEL_MANIP_COUNTER
+ add hl, bc
+ ld a, [hl]
+ and a
+ ret z
+ dec [hl]
+ ret
+
+.NoMatch:
+ ld a, [wSlotBias]
+ cp SLOTS_NO_BIAS
+ jr z, .NoBias
+ ld hl, REEL_MANIP_COUNTER
+ add hl, bc
+ ld a, [hl]
+ and a
+ jr z, .NoBias
+ dec [hl]
+ ret
+
+.NoBias:
+ call Slots_StopReel
+ ret
+
+ReelAction_SetUpReel2SkipTo7:
+; Unique reel 2 action (see Slots_StopReel2)
+; Ensures that 7 symbols become lined up in the first two reels,
+; but more often than not, this is only a way to get our hopes up, as
+; it makes exciting reel #3 modes with no success hope more common.
+
+ call Slots_CheckMatchedFirstTwoReels
+ jr nc, .no_match
+ ld a, [wFirstTwoReelsMatchingSevens]
+ and a
+ jr z, .no_match
+ call Slots_StopReel
+ ret
+
+.no_match
+ ld a, SFX_STOP_SLOT
+ call Slots_PlaySFX
+ ld hl, REEL_ACTION
+ add hl, bc
+ inc [hl] ; REEL_ACTION_WAIT_REEL2_SKIP_TO_7
+ ld hl, REEL_MANIP_DELAY
+ add hl, bc
+ ld [hl], 32
+ ld hl, REEL_SPIN_RATE
+ add hl, bc
+ ld [hl], 0
+ ret
+
+ReelAction_WaitReel2SkipTo7:
+ ld hl, REEL_MANIP_DELAY
+ add hl, bc
+ ld a, [hl]
+ and a
+ jr z, .asm_9326b
+ dec [hl]
+ ret
+
+.asm_9326b
+ ld a, SFX_THROW_BALL
+ call Slots_PlaySFX
+ ld hl, REEL_ACTION
+ add hl, bc
+ inc [hl] ; REEL_ACTION_FAST_SPIN_REEL2_UNTIL_LINED_UP_7S
+ ld hl, REEL_SPIN_RATE
+ add hl, bc
+ ld [hl], 8
+ ret
+
+ReelAction_FastSpinReel2UntilLinedUp7s:
+ call Slots_CheckMatchedFirstTwoReels
+ ret nc
+ ld a, [wFirstTwoReelsMatchingSevens]
+ and a
+ ret z
+ call Slots_StopReel
+ ret
+
+ReelAction_InitGolem:
+; Ensures SEVENs are lined up if there's bias to SEVEN.
+; Ensures nothing is lined up if there's no bias symbols.
+; No other bias symbols are compatible with this mode.
+
+; This is achieved by throwing Golem until the desired result
+; is produced. The amount of Golem thrown can be anywhere from
+; 1 to 14 for SEVEN bias, and 4-8 for no bias.
+
+ call Slots_CheckMatchedAllThreeReels
+ ret c
+ ld a, SFX_STOP_SLOT
+ call Slots_PlaySFX
+ call Slots_WaitSFX
+ ld hl, REEL_ACTION
+ add hl, bc
+ inc [hl] ; REEL_ACTION_WAIT_GOLEM
+ ld hl, REEL_SPIN_RATE
+ add hl, bc
+ ld [hl], 0
+ call Slots_GetNumberOfGolems
+ push bc
+ push af
+ depixel 12, 13
+ ld a, SPRITE_ANIM_INDEX_SLOTS_GOLEM
+ call InitSpriteAnimStruct
+ ld hl, SPRITEANIMSTRUCT_0E
+ add hl, bc
+ pop af
+ ld [hl], a
+ pop bc
+ xor a
+ ld [wSlotsDelay], a
+ReelAction_WaitGolem:
+ ld a, [wSlotsDelay]
+ cp 2
+ jr z, .two
+ cp 1
+ jr z, .one
+ ret
+
+.two
+ call Slots_CheckMatchedAllThreeReels
+ call Slots_StopReel
+ ret
+
+.one
+ ld hl, REEL_ACTION
+ add hl, bc
+ inc [hl] ; REEL_ACTION_END_GOLEM
+ ld hl, REEL_SPIN_RATE
+ add hl, bc
+ ld [hl], 8
+ ret
+
+ReelAction_EndGolem:
+ xor a
+ ld [wSlotsDelay], a
+ ld hl, REEL_ACTION
+ add hl, bc
+ dec [hl] ; REEL_ACTION_WAIT_GOLEM
+ ld hl, REEL_SPIN_RATE
+ add hl, bc
+ ld [hl], 0
+ ret
+
+ReelAction_InitChansey:
+; Ensures the lining up of SEVEN symbols, but this mode is only possible
+; when there is bias to SEVEN symbols (and even then, it's still rare).
+; Chansey releases and egg and reel #3 is made to advance 17 slots very
+; quickly as many times as necessary for the match to SEVENs to show up.
+
+ call Slots_CheckMatchedAllThreeReels
+ ret c
+ ld a, SFX_STOP_SLOT
+ call Slots_PlaySFX
+ call Slots_WaitSFX
+ ld hl, REEL_ACTION
+ add hl, bc
+ inc [hl] ; REEL_ACTION_WAIT_CHANSEY
+ ld hl, REEL_SPIN_RATE
+ add hl, bc
+ ld [hl], 0
+ push bc
+ depixel 12, 0
+ ld a, SPRITE_ANIM_INDEX_SLOTS_CHANSEY
+ call InitSpriteAnimStruct
+ pop bc
+ xor a
+ ld [wSlotsDelay], a
+ ret
+
+ReelAction_WaitChansey:
+ ld a, [wSlotsDelay]
+ and a
+ ret z
+ ld hl, REEL_ACTION
+ add hl, bc
+ inc [hl] ; REEL_ACTION_WAIT_EGG
+ ld a, 2
+ ld [wSlotsDelay], a
+ReelAction_WaitEgg:
+ ld a, [wSlotsDelay]
+ cp $4
+ ret c
+ ld hl, REEL_ACTION
+ add hl, bc
+ inc [hl] ; REEL_ACTION_DROP_REEL
+ ld hl, REEL_SPIN_RATE
+ add hl, bc
+ ld [hl], 16
+ ld hl, REEL_MANIP_DELAY
+ add hl, bc
+ ld [hl], 17
+ReelAction_DropReel:
+ ld hl, REEL_MANIP_DELAY
+ add hl, bc
+ ld a, [hl]
+ and a
+ jr z, .check_match
+ dec [hl]
+ ret
+
+.check_match
+ call Slots_CheckMatchedAllThreeReels
+ jr nc, .EggAgain
+ and a
+ jr nz, .EggAgain
+ ld a, 5
+ ld [wSlotsDelay], a
+ call Slots_StopReel
+ ret
+
+.EggAgain:
+ ld hl, REEL_SPIN_RATE
+ add hl, bc
+ ld [hl], 0
+ ld hl, REEL_ACTION
+ add hl, bc
+ dec [hl]
+ dec [hl] ; REEL_ACTION_WAIT_CHANSEY
+ ld a, 1
+ ld [wSlotsDelay], a
+ ret
+
+ReelAction_Unused:
+ call Slots_CheckMatchedAllThreeReels
+ ret c
+ ld a, SFX_STOP_SLOT
+ call Slots_PlaySFX
+ call Slots_WaitSFX
+ ld hl, REEL_ACTION
+ add hl, bc
+ inc [hl] ; REEL_ACTION_CHECK_DROP_REEL
+ call Slots_GetNumberOfGolems
+ ld hl, REEL_MANIP_DELAY
+ add hl, bc
+ ld [hl], a
+ReelAction_CheckDropReel:
+ ld hl, REEL_MANIP_DELAY
+ add hl, bc
+ ld a, [hl]
+ and a
+ jr nz, .spin
+ call Slots_CheckMatchedAllThreeReels
+ call Slots_StopReel
+ ret
+
+.spin
+ dec [hl]
+ ld hl, REEL_ACTION
+ add hl, bc
+ inc [hl] ; REEL_ACTION_WAIT_DROP_REEL
+ ld hl, REEL_FIELD_0B
+ add hl, bc
+ ld [hl], 32
+ ld hl, REEL_SPIN_RATE
+ add hl, bc
+ ld [hl], 0
+ReelAction_WaitDropReel:
+ ld hl, REEL_FIELD_0B
+ add hl, bc
+ ld a, [hl]
+ and a
+ jr z, .DropReel
+ dec [hl]
+ ret
+
+.DropReel:
+ ld hl, REEL_ACTION
+ add hl, bc
+ dec [hl]
+ ld hl, REEL_SPIN_RATE
+ add hl, bc
+ ld [hl], 8
+ ret
+
+ReelAction_StartSlowAdvanceReel3:
+; Ensures SEVENs are lined up if there's bias to SEVEN.
+; Ensures nothing is lined up if there's no bias symbols.
+; No other bias symbols are compatible with this mode.
+
+; This is achieved by slowly advancing the reel a full round,
+; plus any necessary slot until the desired result is produced.
+
+ call Slots_CheckMatchedAllThreeReels
+ ret c
+ ld a, SFX_STOP_SLOT
+ call Slots_PlaySFX
+ call Slots_WaitSFX
+ ld hl, REEL_SPIN_RATE
+ add hl, bc
+ ld [hl], 1
+ ld hl, REEL_ACTION
+ add hl, bc
+ inc [hl] ; REEL_ACTION_WAIT_SLOW_ADVANCE_REEL3
+ ld hl, REEL_MANIP_DELAY
+ add hl, bc
+ ld [hl], 16
+ReelAction_WaitSlowAdvanceReel3:
+ ld hl, REEL_MANIP_DELAY
+ add hl, bc
+ ld a, [hl]
+ and a
+ jr z, .check1
+ dec [hl]
+.play_sfx
+ ld a, SFX_GOT_SAFARI_BALLS
+ call Slots_PlaySFX
+ ret
+
+.check1
+ ld a, [wSlotBias]
+ and a
+ jr nz, .check2
+ call Slots_CheckMatchedAllThreeReels
+ jr nc, .play_sfx
+ and a
+ jr nz, .play_sfx
+ call Slots_StopReel
+ call WaitSFX
+ ret
+
+.check2
+ call Slots_CheckMatchedAllThreeReels
+ jr c, .play_sfx
+ call Slots_StopReel
+ call WaitSFX
+ ret
+
+Slots_CheckMatchedFirstTwoReels:
+ xor a
+ ld [wFirstTwoReelsMatching], a
+ ld [wFirstTwoReelsMatchingSevens], a
+ call Slots_GetCurrentReelState
+ call Slots_CopyReelState
+ ld a, [wSlotBet]
+ and 3
+ ld e, a
+ ld d, 0
+ ld hl, .Jumptable
+ add hl, de
+ add hl, de
+ ld a, [hli]
+ ld h, [hl]
+ ld l, a
+ ld de, .return
+ push de
+ jp hl
+
+.return
+ ld a, [wFirstTwoReelsMatching]
+ and a
+ ret z
+ scf
+ ret
+
+.Jumptable:
+ dw .zero
+ dw .one
+ dw .two
+ dw .three
+
+.three
+ call .CheckUpwardsDiag
+ call .CheckDownwardsDiag
+
+.two
+ call .CheckBottomRow
+ call .CheckTopRow
+
+.one
+ call .CheckMiddleRow
+
+.zero
+ ret
+
+.CheckBottomRow:
+ ld hl, wCurReelStopped
+ ld a, [wReel1Stopped]
+ cp [hl]
+ call z, .StoreResult
+ ret
+
+.CheckUpwardsDiag:
+ ld hl, wCurReelStopped + 1
+ ld a, [wReel1Stopped]
+ cp [hl]
+ call z, .StoreResult
+ ret
+
+.CheckMiddleRow:
+ ld hl, wCurReelStopped + 1
+ ld a, [wReel1Stopped + 1]
+ cp [hl]
+ call z, .StoreResult
+ ret
+
+.CheckDownwardsDiag:
+ ld hl, wCurReelStopped + 1
+ ld a, [wReel1Stopped + 2]
+ cp [hl]
+ call z, .StoreResult
+ ret
+
+.CheckTopRow:
+ ld hl, wCurReelStopped + 2
+ ld a, [wReel1Stopped + 2]
+ cp [hl]
+ call z, .StoreResult
+ ret
+
+.StoreResult:
+ ld [wSlotBuildingMatch], a
+ and a
+ jr nz, .matching_sevens
+ ld a, 1
+ ld [wFirstTwoReelsMatchingSevens], a
+
+.matching_sevens
+ ld a, 1
+ ld [wFirstTwoReelsMatching], a
+ ret
+
+Slots_CheckMatchedAllThreeReels:
+ ld a, SLOTS_NO_MATCH
+ ld [wSlotMatched], a
+ call Slots_GetCurrentReelState
+ call Slots_CopyReelState
+ ld a, [wSlotBet]
+ and 3
+ ld e, a
+ ld d, 0
+ ld hl, .Jumptable
+ add hl, de
+ add hl, de
+ ld a, [hli]
+ ld h, [hl]
+ ld l, a
+ ld de, .return
+ push de
+ jp hl
+
+.return
+ ld a, [wSlotMatched]
+ cp SLOTS_NO_MATCH
+ jr nz, .matched_nontrivial
+ and a
+ ret
+
+.matched_nontrivial
+ scf
+ ret
+
+.Jumptable:
+ dw .zero
+ dw .one
+ dw .two
+ dw .three
+
+.three
+ call .CheckUpwardsDiag
+ call .CheckDownwardsDiag
+
+.two
+ call .CheckBottomRow
+ call .CheckTopRow
+
+.one
+ call .CheckMiddleRow
+
+.zero
+ ret
+
+.CheckBottomRow:
+ ld hl, wCurReelStopped
+ ld a, [wReel1Stopped]
+ cp [hl]
+ ret nz
+ ld hl, wReel2Stopped
+ cp [hl]
+ call z, .StoreResult
+ ret
+
+.CheckUpwardsDiag:
+ ld hl, wCurReelStopped + 2
+ ld a, [wReel1Stopped]
+ cp [hl]
+ ret nz
+ ld hl, wReel2Stopped + 1
+ cp [hl]
+ call z, .StoreResult
+ ret
+
+.CheckMiddleRow:
+ ld hl, wCurReelStopped + 1
+ ld a, [wReel1Stopped + 1]
+ cp [hl]
+ ret nz
+ ld hl, wReel2Stopped + 1
+ cp [hl]
+ call z, .StoreResult
+ ret
+
+.CheckDownwardsDiag:
+ ld hl, wCurReelStopped
+ ld a, [wReel1Stopped + 2]
+ cp [hl]
+ ret nz
+ ld hl, wReel2Stopped + 1
+ cp [hl]
+ call z, .StoreResult
+ ret
+
+.CheckTopRow:
+ ld hl, wCurReelStopped + 2
+ ld a, [wReel1Stopped + 2]
+ cp [hl]
+ ret nz
+ ld hl, wReel2Stopped + 2
+ cp [hl]
+ call z, .StoreResult
+ ret
+
+.StoreResult:
+ ld [wSlotMatched], a
+ ret
+
+Slots_CopyReelState:
+ ld de, wCurReelStopped
+ ld a, [hli]
+ ld [de], a
+ inc de
+ ld a, [hli]
+ ld [de], a
+ inc de
+ ld a, [hl]
+ ld [de], a
+ ret
+
+Slots_GetNumberOfGolems:
+ ld hl, REEL_POSITION
+ add hl, bc
+ ld a, [hl]
+ push af
+ push hl
+ call .Check7Bias
+ pop hl
+ pop af
+ ld [hl], a
+ ld a, e
+ ret
+
+.Check7Bias:
+ ld a, [wSlotBias]
+ and a
+ jr nz, .not_biased_to_seven
+ ld e, $0
+.loop1
+ ld hl, REEL_POSITION
+ add hl, bc
+ inc [hl]
+ inc e
+ push de
+ call Slots_CheckMatchedAllThreeReels
+ pop de
+ jr nc, .loop1
+ and a
+ jr nz, .loop1
+ ret
+
+.not_biased_to_seven
+ call Random
+ and $7
+ cp $8 / 2 ; 50%
+ jr c, .not_biased_to_seven
+ ld e, a
+.loop2
+ ld a, e
+ inc e
+ ld hl, REEL_POSITION
+ add hl, bc
+ add [hl]
+ ld [hl], a
+ push de
+ call Slots_CheckMatchedAllThreeReels
+ pop de
+ jr c, .loop2
+ ret
+
+Slots_InitBias:
+ ld a, [wSlotBias]
+ and a
+ ret z
+ ld hl, .Normal
+ ld a, [wScriptVar]
+ and a
+ jr z, .okay
+ ld hl, .Lucky
+.okay
+ call Random
+ ld c, a
+.loop
+ ld a, [hli]
+ cp c
+ jr nc, .done
+ inc hl
+ jr .loop
+
+.done
+ ld a, [hl]
+ ld [wSlotBias], a
+ ret
+
+.Normal:
+ db 1 percent - 1, SLOTS_SEVEN
+ db 1 percent + 1, SLOTS_POKEBALL
+ db 4 percent, SLOTS_STARYU
+ db 8 percent, SLOTS_SQUIRTLE
+ db 16 percent, SLOTS_PIKACHU
+ db 19 percent, SLOTS_CHERRY
+ db 100 percent, SLOTS_NO_BIAS
+
+.Lucky:
+ db 1 percent, SLOTS_SEVEN
+ db 1 percent + 1, SLOTS_POKEBALL
+ db 3 percent + 1, SLOTS_STARYU
+ db 6 percent + 1, SLOTS_SQUIRTLE
+ db 12 percent, SLOTS_PIKACHU
+ db 31 percent + 1, SLOTS_CHERRY
+ db 100 percent, SLOTS_NO_BIAS
+
+Slots_IlluminateBetLights:
+ ld b, $14 ; turned on
+ ld a, [wSlotBet]
+ dec a
+ jr z, Slots_Lights1OnOff
+ dec a
+ jr z, Slots_Lights2OnOff
+ jr Slots_Lights3OnOff
+
+Slots_DeilluminateBetLights:
+ ld b, $23 ; turned off
+Slots_Lights3OnOff:
+ hlcoord 3, 2
+ call Slots_TurnLightsOnOrOff
+ hlcoord 3, 10
+ call Slots_TurnLightsOnOrOff
+Slots_Lights2OnOff:
+ hlcoord 3, 4
+ call Slots_TurnLightsOnOrOff
+ hlcoord 3, 8
+ call Slots_TurnLightsOnOrOff
+Slots_Lights1OnOff:
+ hlcoord 3, 6
+
+Slots_TurnLightsOnOrOff:
+ ld a, b
+ ld [hl], a
+ ld de, SCREEN_WIDTH / 2 + 3
+ add hl, de
+ ld [hl], a
+ ld de, SCREEN_WIDTH / 2 - 3
+ add hl, de
+ inc a
+ ld [hl], a
+ ld de, SCREEN_WIDTH / 2 + 3
+ add hl, de
+ ld [hl], a
+ ret
+
+Slots_AskBet:
+.loop
+ ld hl, .SlotsBetHowManyCoinsText
+ call PrintText
+ ld hl, .MenuHeader
+ call LoadMenuHeader
+ call VerticalMenu
+ call CloseWindow
+ ret c
+ ld a, [wMenuCursorY]
+ ld b, a
+ ld a, 4
+ sub b
+ ld [wSlotBet], a
+ ld hl, wCoins
+ ld c, a
+ ld a, [hli]
+ and a
+ jr nz, .Start
+ ld a, [hl]
+ cp c
+ jr nc, .Start
+ ld hl, .SlotsNotEnoughCoinsText
+ call PrintText
+ jr .loop
+
+.Start:
+ ld hl, wCoins + 1
+ ld a, [hl]
+ sub c
+ ld [hld], a
+ jr nc, .ok
+ dec [hl]
+.ok
+ call WaitSFX
+ ld de, SFX_PAY_DAY
+ call PlaySFX
+ ld hl, .SlotsStartText
+ call PrintText
+ and a
+ ret
+
+.SlotsBetHowManyCoinsText:
+ text_far _SlotsBetHowManyCoinsText
+ text_end
+
+.SlotsStartText:
+ text_far _SlotsStartText
+ text_end
+
+.SlotsNotEnoughCoinsText:
+ text_far _SlotsNotEnoughCoinsText
+ text_end
+
+.MenuHeader:
+ db MENU_BACKUP_TILES ; flags
+ menu_coords 14, 10, SCREEN_WIDTH - 1, SCREEN_HEIGHT - 1
+ dw .MenuData
+ db 1 ; default option
+
+.MenuData:
+ db STATICMENU_CURSOR ; flags
+ db 3 ; items
+ db " 3@"
+ db " 2@"
+ db " 1@"
+
+Slots_AskPlayAgain:
+ ld hl, wCoins
+ ld a, [hli]
+ or [hl]
+ jr nz, .you_have_coins
+ ld hl, .SlotsRanOutOfCoinsText
+ call PrintText
+ ld c, 60
+ call DelayFrames
+ jr .exit_slots
+
+.you_have_coins
+ ld hl, .SlotsPlayAgainText
+ call PrintText
+ call LoadMenuTextbox
+ lb bc, 14, 12
+ call PlaceYesNoBox
+ ld a, [wMenuCursorY]
+ dec a
+ call CloseWindow
+ and a
+ jr nz, .exit_slots
+ and a
+ ret
+
+.exit_slots
+ scf
+ ret
+
+.SlotsRanOutOfCoinsText:
+ text_far _SlotsRanOutOfCoinsText
+ text_end
+
+.SlotsPlayAgainText:
+ text_far _SlotsPlayAgainText
+ text_end
+
+Slots_GetPayout:
+ ld a, [wSlotMatched]
+ cp SLOTS_NO_MATCH
+ jr z, .no_win
+ srl a
+ ld e, a
+ ld d, 0
+ ld hl, .PayoutTable
+ add hl, de
+ ld a, [hli]
+ ld [wPayout + 1], a
+ ld a, [hl]
+ ld [wPayout], a
+ ret
+
+.PayoutTable:
+ dw 300
+ dw 50
+ dw 6
+ dw 8
+ dw 10
+ dw 15
+
+.no_win
+ ld hl, wPayout
+ xor a
+ ld [hli], a
+ ld [hl], a
+ ret
+
+Slots_PayoutText:
+ ld a, [wSlotMatched]
+ cp SLOTS_NO_MATCH
+ jr nz, .MatchedSomething
+ ld hl, .SlotsDarnText
+ call PrintText
+ ret
+
+.MatchedSomething:
+ srl a
+ ld e, a
+ ld d, 0
+ ld hl, .PayoutStrings
+ add hl, de
+ add hl, de
+ add hl, de
+ ld de, wStringBuffer2
+ ld bc, 4
+ call CopyBytes
+ ld a, [hli]
+ ld h, [hl]
+ ld l, a
+ ld de, .return
+ push de
+ jp hl
+
+.return
+ ld hl, .Text_PrintPayout
+ call PrintText
+ ret
+
+.PayoutStrings:
+ dbw "300@", .LinedUpSevens
+ dbw "50@@", .LinedUpPokeballs
+ dbw "6@@@", .LinedUpMonOrCherry
+ dbw "8@@@", .LinedUpMonOrCherry
+ dbw "10@@", .LinedUpMonOrCherry
+ dbw "15@@", .LinedUpMonOrCherry
+
+.Text_PrintPayout:
+ text_asm
+ ld a, [wSlotMatched]
+ add $25
+ ldcoord_a 2, 13
+ inc a
+ ldcoord_a 2, 14
+ inc a
+ ldcoord_a 3, 13
+ inc a
+ ldcoord_a 3, 14
+ hlcoord 18, 17
+ ld [hl], "▼"
+ ld hl, .SlotsLinedUpText
+rept 4
+ inc bc
+endr
+ ret
+
+.SlotsLinedUpText:
+ text_far _SlotsLinedUpText
+ text_end
+
+.SlotsDarnText:
+ text_far _SlotsDarnText
+ text_end
+
+.LinedUpSevens:
+ ld a, SFX_2ND_PLACE
+ call Slots_PlaySFX
+ call WaitSFX
+
+; Oddly, the rarest mode (wKeepSevenBiasChance = 1) is the one with
+; the worse odds to favor seven symbol streaks (12.5% vs 25%).
+; it's possible that either the wKeepSevenBiasChance initialization
+; or this code was intended to lead to flipped percentages.
+ ld a, [wKeepSevenBiasChance]
+ and a
+ jr nz, .lower_seven_streak_odds
+ call Random
+ and %0010100
+ ret z ; 25% chance to stick with seven symbol bias
+ ld a, SLOTS_NO_BIAS
+ ld [wSlotBias], a
+ ret
+
+.lower_seven_streak_odds
+ call Random
+ and %0011100
+ ret z ; 12.5% chance to stick with seven symbol bias
+ ld a, SLOTS_NO_BIAS
+ ld [wSlotBias], a
+ ret
+
+.LinedUpPokeballs:
+ ld a, SFX_3RD_PLACE
+ call Slots_PlaySFX
+ call WaitSFX
+ ret
+
+.LinedUpMonOrCherry:
+ ld a, SFX_PRESENT
+ call Slots_PlaySFX
+ call WaitSFX
+ ret
+
+Slots_AnimateGolem:
+ ld hl, SPRITEANIMSTRUCT_JUMPTABLE_INDEX
+ add hl, bc
+ ld e, [hl]
+ ld d, 0
+ ld hl, .Jumptable
+ add hl, de
+ add hl, de
+ ld a, [hli]
+ ld h, [hl]
+ ld l, a
+ jp hl
+
+.Jumptable:
+ dw .init
+ dw .fall
+ dw .roll
+
+.init
+ ld hl, SPRITEANIMSTRUCT_0E
+ add hl, bc
+ ld a, [hl]
+ and a
+ jr nz, .retain
+ ld a, 2
+ ld [wSlotsDelay], a
+ ld hl, SPRITEANIMSTRUCT_INDEX
+ add hl, bc
+ ld [hl], $0
+ ret
+
+.retain
+ dec [hl]
+ ld hl, SPRITEANIMSTRUCT_JUMPTABLE_INDEX
+ add hl, bc
+ inc [hl]
+ ld hl, SPRITEANIMSTRUCT_0C
+ add hl, bc
+ ld [hl], $30
+ ld hl, SPRITEANIMSTRUCT_XOFFSET
+ add hl, bc
+ ld [hl], $0
+
+.fall
+ ld hl, SPRITEANIMSTRUCT_0C
+ add hl, bc
+ ld a, [hl]
+ cp $20
+ jr c, .play_sound
+ dec [hl]
+ ld e, a
+ ld d, 14 * 8
+ farcall BattleAnim_Sine_e
+ ld a, e
+ ld hl, SPRITEANIMSTRUCT_YOFFSET
+ add hl, bc
+ ld [hl], a
+ ret
+
+.play_sound
+ ld hl, SPRITEANIMSTRUCT_JUMPTABLE_INDEX
+ add hl, bc
+ inc [hl]
+ ld hl, SPRITEANIMSTRUCT_0D
+ add hl, bc
+ ld [hl], $2
+ ld a, 1
+ ld [wSlotsDelay], a
+ ld a, SFX_PLACE_PUZZLE_PIECE_DOWN
+ call Slots_PlaySFX
+ ret
+
+.roll
+ ld hl, SPRITEANIMSTRUCT_XOFFSET
+ add hl, bc
+ ld a, [hl]
+ inc [hl]
+ inc [hl]
+ cp 9 * 8
+ jr nc, .restart
+ and $3
+ ret nz
+ ld hl, SPRITEANIMSTRUCT_0D
+ add hl, bc
+ ld a, [hl]
+ xor $ff
+ inc a
+ ld [hl], a
+ ldh [hSCY], a
+ ret
+
+.restart
+ ld hl, SPRITEANIMSTRUCT_JUMPTABLE_INDEX
+ add hl, bc
+ xor a
+ ld [hl], a
+ ldh [hSCY], a
+ ret
+
+Slots_AnimateChansey:
+ ld hl, SPRITEANIMSTRUCT_JUMPTABLE_INDEX
+ add hl, bc
+ ld e, [hl]
+ ld d, 0
+ ld hl, .Jumptable
+ add hl, de
+ add hl, de
+ ld a, [hli]
+ ld h, [hl]
+ ld l, a
+ jp hl
+
+.Jumptable:
+ dw .walk
+ dw .one
+ dw .two
+
+.walk
+ ld hl, SPRITEANIMSTRUCT_XCOORD
+ add hl, bc
+ ld a, [hl]
+ inc [hl]
+ cp 13 * 8
+ jr z, .limit
+ and $f
+ ret nz
+ ld de, SFX_JUMP_OVER_LEDGE
+ call PlaySFX
+ ret
+
+.limit
+ ld hl, SPRITEANIMSTRUCT_JUMPTABLE_INDEX
+ add hl, bc
+ inc [hl]
+ ld a, 1
+ ld [wSlotsDelay], a
+
+.one
+ ld a, [wSlotsDelay]
+ cp $2
+ jr z, .retain
+ cp $5
+ ret nz
+ ld hl, SPRITEANIMSTRUCT_INDEX
+ add hl, bc
+ ld [hl], $0
+ ret
+
+.retain
+ ld hl, SPRITEANIMSTRUCT_JUMPTABLE_INDEX
+ add hl, bc
+ inc [hl]
+ ld hl, SPRITEANIMSTRUCT_0C
+ add hl, bc
+ ld [hl], $8
+.two
+ ld hl, SPRITEANIMSTRUCT_0C
+ add hl, bc
+ ld a, [hl]
+ and a
+ jr z, .spawn_egg
+ dec [hl]
+ ret
+
+.spawn_egg
+ ld hl, SPRITEANIMSTRUCT_JUMPTABLE_INDEX
+ add hl, bc
+ dec [hl]
+ push bc
+ depixel 12, 13, 0, 4
+ ld a, SPRITE_ANIM_INDEX_SLOTS_EGG
+ call InitSpriteAnimStruct
+ pop bc
+ ret
+
+Slots_WaitSFX:
+ push bc
+ ld c, 16
+ call DelayFrames
+ pop bc
+ ret
+
+Slots_PlaySFX:
+ push de
+ ld e, a
+ ld d, 0
+ call PlaySFX
+ pop de
+ ret
+
+; The first three positions are repeated to
+; avoid needing to check indices when copying.
+Reel1Tilemap:
+ db SLOTS_SEVEN ; 0
+ db SLOTS_CHERRY ; 1
+ db SLOTS_STARYU ; 2
+ db SLOTS_PIKACHU ; 3
+ db SLOTS_SQUIRTLE ; 4
+ db SLOTS_SEVEN ; 5
+ db SLOTS_CHERRY ; 6
+ db SLOTS_STARYU ; 7
+ db SLOTS_PIKACHU ; 8
+ db SLOTS_SQUIRTLE ; 9
+ db SLOTS_POKEBALL ; 10
+ db SLOTS_CHERRY ; 11
+ db SLOTS_STARYU ; 12
+ db SLOTS_PIKACHU ; 13
+ db SLOTS_SQUIRTLE ; 14
+ db SLOTS_SEVEN ; 0
+ db SLOTS_CHERRY ; 1
+ db SLOTS_STARYU ; 2
+
+Reel2Tilemap:
+ db SLOTS_SEVEN ; 0
+ db SLOTS_PIKACHU ; 1
+ db SLOTS_CHERRY ; 2
+ db SLOTS_SQUIRTLE ; 3
+ db SLOTS_STARYU ; 4
+ db SLOTS_POKEBALL ; 5
+ db SLOTS_PIKACHU ; 6
+ db SLOTS_CHERRY ; 7
+ db SLOTS_SQUIRTLE ; 8
+ db SLOTS_STARYU ; 9
+ db SLOTS_POKEBALL ; 10
+ db SLOTS_PIKACHU ; 11
+ db SLOTS_CHERRY ; 12
+ db SLOTS_SQUIRTLE ; 13
+ db SLOTS_STARYU ; 14
+ db SLOTS_SEVEN ; 0
+ db SLOTS_PIKACHU ; 1
+ db SLOTS_CHERRY ; 2
+
+Reel3Tilemap:
+ db SLOTS_SEVEN ; 0
+ db SLOTS_PIKACHU ; 1
+ db SLOTS_CHERRY ; 2
+ db SLOTS_SQUIRTLE ; 3
+ db SLOTS_STARYU ; 4
+ db SLOTS_PIKACHU ; 5
+ db SLOTS_CHERRY ; 6
+ db SLOTS_SQUIRTLE ; 7
+ db SLOTS_STARYU ; 8
+ db SLOTS_PIKACHU ; 9
+ db SLOTS_POKEBALL ; 10
+ db SLOTS_CHERRY ; 11
+ db SLOTS_SQUIRTLE ; 12
+ db SLOTS_STARYU ; 13
+ db SLOTS_PIKACHU ; 14
+ db SLOTS_SEVEN ; 0
+ db SLOTS_PIKACHU ; 1
+ db SLOTS_CHERRY ; 2
+
+SlotsTilemap:
+INCBIN "gfx/slots/slots.tilemap"
+
+Slots1LZ:
+INCBIN "gfx/slots/slots_1.2bpp.lz"
+
+Slots2LZ:
+INCBIN "gfx/slots/slots_2.2bpp.lz"
+
+Slots3LZ:
+INCBIN "gfx/slots/slots_3.2bpp.lz"
diff --git a/engine/gfx/cgb_layouts.asm b/engine/gfx/cgb_layouts.asm
new file mode 100755
index 00000000..a9a2038a
--- /dev/null
+++ b/engine/gfx/cgb_layouts.asm
@@ -0,0 +1,865 @@
+; Replaces the functionality of sgb.asm to work with CGB hardware.
+
+CheckCGB:
+ ldh a, [hCGB]
+ and a
+ ret
+
+LoadSGBLayoutCGB:
+ ld a, b
+ cp SCGB_RAM
+ jr nz, .not_ram
+ ld a, [wSGBPredef]
+.not_ram
+ cp SCGB_PARTY_MENU_HP_PALS
+ jp z, CGB_ApplyPartyMenuHPPals
+ call ResetBGPals
+ ld l, a
+ ld h, 0
+ add hl, hl
+ ld de, .dw
+ add hl, de
+ ld a, [hli]
+ ld h, [hl]
+ ld l, a
+ ld de, .ReturnFromJumpTable
+ push de
+ jp hl
+
+.ReturnFromJumpTable:
+ ret
+
+.dw
+ dw _CGB_BattleGrayscale
+ dw _CGB_BattleColors
+ dw _CGB_PokegearPals
+ dw _CGB_StatsScreenHPPals
+ dw _CGB_Pokedex
+ dw _CGB_SlotMachine
+ dw _CGB_BetaTitleScreen
+ dw _CGB_GSIntro
+ dw _CGB_Diploma
+ dw _CGB_MapPals
+ dw _CGB_PartyMenu
+ dw _CGB_Evolution
+ dw _CGB_GSTitleScreen
+ dw _CGB0d
+ dw _CGB_MoveList
+ dw _CGB_BetaPikachuMinigame
+ dw _CGB_PokedexSearchOption
+ dw _CGB_BetaPoker
+ dw _CGB_Pokepic
+ dw _CGB_MagnetTrain
+ dw _CGB_PackPals
+ dw _CGB_TrainerCard
+ dw _CGB_PokedexUnownMode
+ dw _CGB_BillsPC
+ dw _CGB_UnownPuzzle
+ dw _CGB_GamefreakLogo
+ dw _CGB_PlayerOrMonFrontpicPals
+ dw _CGB_TradeTube
+ dw _CGB_TrainerOrMonFrontpicPals
+ dw _CGB_MysteryGift
+ dw _CGB1e
+ dw _CGB_Pokedex_5_5
+
+_CGB_BattleGrayscale:
+ ld hl, PalPacket_BattleGrayscale + 1
+ ld de, wBGPals1
+ ld c, 4
+ call CopyPalettes
+ ld hl, PalPacket_BattleGrayscale + 1
+ ld de, wBGPals1 palette PAL_BATTLE_BG_EXP
+ ld c, 4
+ call CopyPalettes
+ ld hl, PalPacket_BattleGrayscale + 1
+ ld de, wOBPals1
+ ld c, 2
+ call CopyPalettes
+ jr _CGB_FinishBattleScreenLayout
+
+_CGB_BattleColors:
+ ld de, wBGPals1
+ call GetBattlemonBackpicPalettePointer
+ push hl
+ call LoadPalette_White_Col1_Col2_Black ; PAL_BATTLE_BG_PLAYER
+ call GetEnemyFrontpicPalettePointer
+ push hl
+ call LoadPalette_White_Col1_Col2_Black ; PAL_BATTLE_BG_ENEMY
+ ld a, [wEnemyHPPal]
+ ld l, a
+ ld h, $0
+ add hl, hl
+ add hl, hl
+ ld bc, HPBarPals
+ add hl, bc
+ call LoadPalette_White_Col1_Col2_Black ; PAL_BATTLE_BG_ENEMY_HP
+ ld a, [wPlayerHPPal]
+ ld l, a
+ ld h, $0
+ add hl, hl
+ add hl, hl
+ ld bc, HPBarPals
+ add hl, bc
+ call LoadPalette_White_Col1_Col2_Black ; PAL_BATTLE_BG_PLAYER_HP
+ ld hl, ExpBarPalette
+ call LoadPalette_White_Col1_Col2_Black ; PAL_BATTLE_BG_EXP
+ ld de, wOBPals1
+ pop hl
+ call LoadPalette_White_Col1_Col2_Black ; PAL_BATTLE_OB_ENEMY
+ pop hl
+ call LoadPalette_White_Col1_Col2_Black ; PAL_BATTLE_OB_PLAYER
+ ld a, SCGB_BATTLE_COLORS
+ ld [wSGBPredef], a
+ call ApplyPals
+_CGB_FinishBattleScreenLayout:
+ ld hl, TilesetBGPalette + 7 * 8
+ ld de, wBGPals1 palette 7
+ ld bc, $8
+ call CopyBytes
+ hlcoord 0, 0, wAttrmap
+ ld bc, SCREEN_WIDTH * SCREEN_HEIGHT
+ ld a, PAL_BATTLE_BG_ENEMY_HP
+ call ByteFill
+ hlcoord 0, 4, wAttrmap
+ lb bc, 8, 10
+ ld a, PAL_BATTLE_BG_PLAYER
+ call FillBoxCGB
+ hlcoord 10, 0, wAttrmap
+ lb bc, 7, 10
+ ld a, PAL_BATTLE_BG_ENEMY
+ call FillBoxCGB
+ hlcoord 0, 0, wAttrmap
+ lb bc, 4, 10
+ ld a, PAL_BATTLE_BG_ENEMY_HP
+ call FillBoxCGB
+ hlcoord 10, 7, wAttrmap
+ lb bc, 5, 10
+ ld a, PAL_BATTLE_BG_PLAYER_HP
+ call FillBoxCGB
+ hlcoord 10, 11, wAttrmap
+ lb bc, 1, 9
+ ld a, PAL_BATTLE_BG_EXP
+ call FillBoxCGB
+ hlcoord 0, 12, wAttrmap
+ ld bc, 6 * SCREEN_WIDTH
+ ld a, PAL_BATTLE_BG_TEXT
+ call ByteFill
+ ld hl, BattleObjectPals
+ ld de, wOBPals1 palette PAL_BATTLE_OB_GRAY
+ ld bc, 6 palettes
+ call CopyBytes
+ call ApplyAttrmap
+ ret
+
+_CGB_PokegearPals:
+ ld hl, PokegearPals
+ ld de, wBGPals1
+ ld bc, 6 palettes
+ call CopyBytes
+ call ApplyPals
+ ld a, $1
+ ldh [hCGBPalUpdate], a
+ ret
+
+_CGB_StatsScreenHPPals:
+ ld de, wBGPals1
+ ld a, [wCurHPPal]
+ ld l, a
+ ld h, $0
+ add hl, hl
+ add hl, hl
+ ld bc, HPBarPals
+ add hl, bc
+ call LoadPalette_White_Col1_Col2_Black ; hp palette
+ ld a, [wCurPartySpecies]
+ ld bc, wTempMonDVs
+ call GetPlayerOrMonPalettePointer
+ call LoadPalette_White_Col1_Col2_Black ; mon palette
+ ld hl, ExpBarPalette
+ call LoadPalette_White_Col1_Col2_Black ; exp palette
+ ld hl, StatsScreenPagePals
+ ld de, wBGPals1 palette 3
+ ld bc, 3 palettes ; pink, green, and blue page palettes
+ call CopyBytes
+ call WipeAttrmap
+
+ hlcoord 0, 0, wAttrmap
+ lb bc, 8, SCREEN_WIDTH
+ ld a, $1 ; mon palette
+ call FillBoxCGB
+
+ hlcoord 10, 16, wAttrmap
+ ld bc, 10
+ ld a, $2 ; exp palette
+ call ByteFill
+
+ hlcoord 13, 5, wAttrmap
+ lb bc, 2, 2
+ ld a, $3 ; pink page palette
+ call FillBoxCGB
+
+ hlcoord 15, 5, wAttrmap
+ lb bc, 2, 2
+ ld a, $4 ; green page palette
+ call FillBoxCGB
+
+ hlcoord 17, 5, wAttrmap
+ lb bc, 2, 2
+ ld a, $5 ; blue page palette
+ call FillBoxCGB
+
+ call ApplyAttrmap
+ call ApplyPals
+ ld a, $1
+ ldh [hCGBPalUpdate], a
+ ret
+
+StatsScreenPagePals:
+INCLUDE "gfx/stats/pages.pal"
+
+StatsScreenPals:
+INCLUDE "gfx/stats/stats.pal"
+
+_CGB_Pokedex:
+ call _CGB_Pokedex_Init
+ hlcoord 1, 1, wAttrmap
+ lb bc, 7, 7
+ ld a, $1
+ call FillBoxCGB
+ jp _CGB_Pokedex_Resume
+
+_CGB_Pokedex_5_5:
+ call _CGB_Pokedex_Init
+ hlcoord 1, 1, wAttrmap
+ lb bc, 5, 5
+ ld a, $1
+ call FillBoxCGB
+ jp _CGB_Pokedex_Resume
+
+_CGB_Pokedex_Init:
+ ld de, wBGPals1
+ ld a, PREDEFPAL_POKEDEX
+ call GetPredefPal
+ call LoadHLPaletteIntoDE ; dex interface palette
+ ld a, [wCurPartySpecies]
+ cp $ff
+ jr nz, .is_pokemon
+ ld hl, PokedexQuestionMarkPalette
+ call LoadHLPaletteIntoDE ; green question mark palette
+ jr .got_palette
+
+.is_pokemon
+ call GetMonPalettePointer
+ call LoadPalette_White_Col1_Col2_Black ; mon palette
+.got_palette
+ call WipeAttrmap
+ ret
+
+_CGB_Pokedex_Resume:
+ call InitPartyMenuOBPals
+ ld hl, PokedexCursorPalette
+ ld de, wOBPals1 palette 7 ; green cursor palette
+ ld bc, 1 palettes
+ call CopyBytes
+ call ApplyAttrmap
+ call ApplyPals
+ ld a, $1
+ ldh [hCGBPalUpdate], a
+ ret
+
+PokedexCursorPalette:
+INCLUDE "gfx/pokedex/cursor.pal"
+
+PokedexQuestionMarkPalette:
+INCLUDE "gfx/pokedex/question_mark.pal"
+
+_CGB_BillsPC:
+ ld de, wBGPals1
+ ld a, PREDEFPAL_POKEDEX
+ call GetPredefPal
+ call LoadHLPaletteIntoDE
+ ld a, [wCurPartySpecies]
+ cp $ff
+ jr nz, .GetMonPalette
+ ld hl, .BillsPCOrangePalette
+ call LoadHLPaletteIntoDE
+ jr .Resume
+
+.GetMonPalette:
+ ld bc, wTempMonDVs
+ call GetPlayerOrMonPalettePointer
+ call LoadPalette_White_Col1_Col2_Black
+.Resume:
+ call WipeAttrmap
+ hlcoord 1, 4, wAttrmap
+ lb bc, 7, 7
+ ld a, $1
+ call FillBoxCGB
+ call InitPartyMenuOBPals
+ call ApplyAttrmap
+ call ApplyPals
+ ld a, $1
+ ldh [hCGBPalUpdate], a
+ ret
+
+.Function9009:
+ ld hl, .BillsPCOrangePalette
+ call LoadHLPaletteIntoDE
+ jr .asm_95b1
+
+.unused
+ ld bc, wTempMonDVs
+ call GetPlayerOrMonPalettePointer
+ call LoadPalette_White_Col1_Col2_Black
+.asm_95b1
+ call WipeAttrmap
+ hlcoord 1, 1, wAttrmap
+ lb bc, 7, 7
+ ld a, $1
+ call FillBoxCGB
+ call InitPartyMenuOBPals
+ call ApplyAttrmap
+ call ApplyPals
+ ld a, $1
+ ldh [hCGBPalUpdate], a
+ ret
+
+.BillsPCOrangePalette:
+INCLUDE "gfx/pc/orange.pal"
+
+_CGB_PokedexUnownMode:
+ ld de, wBGPals1
+ ld a, PREDEFPAL_POKEDEX
+ call GetPredefPal
+ call LoadHLPaletteIntoDE
+ ld a, [wCurPartySpecies]
+ call GetMonPalettePointer
+ call LoadPalette_White_Col1_Col2_Black
+ call WipeAttrmap
+ hlcoord 7, 5, wAttrmap
+ lb bc, 7, 7
+ ld a, $1
+ call FillBoxCGB
+ call InitPartyMenuOBPals
+ call ApplyAttrmap
+ call ApplyPals
+ ld a, $1
+ ldh [hCGBPalUpdate], a
+ ret
+
+_CGB_SlotMachine:
+ ld hl, SlotMachinePals
+ ld de, wBGPals1
+ ld bc, 16 palettes
+ call CopyBytes
+ call WipeAttrmap
+ hlcoord 0, 2, wAttrmap
+ lb bc, 10, 3
+ ld a, $2
+ call FillBoxCGB
+ hlcoord 17, 2, wAttrmap
+ lb bc, 10, 3
+ ld a, $2
+ call FillBoxCGB
+ hlcoord 0, 4, wAttrmap
+ lb bc, 6, 3
+ ld a, $3
+ call FillBoxCGB
+ hlcoord 17, 4, wAttrmap
+ lb bc, 6, 3
+ ld a, $3
+ call FillBoxCGB
+ hlcoord 0, 6, wAttrmap
+ lb bc, 2, 3
+ ld a, $4
+ call FillBoxCGB
+ hlcoord 17, 6, wAttrmap
+ lb bc, 2, 3
+ ld a, $4
+ call FillBoxCGB
+ hlcoord 4, 2, wAttrmap
+ lb bc, 2, 12
+ ld a, $1
+ call FillBoxCGB
+ hlcoord 3, 2, wAttrmap
+ lb bc, 10, 1
+ ld a, $1
+ call FillBoxCGB
+ hlcoord 16, 2, wAttrmap
+ lb bc, 10, 1
+ ld a, $1
+ call FillBoxCGB
+ hlcoord 0, 12, wAttrmap
+ ld bc, $78
+ ld a, $7
+ call ByteFill
+ call ApplyAttrmap
+ call ApplyPals
+ ld a, $1
+ ldh [hCGBPalUpdate], a
+ ret
+
+_CGB_BetaTitleScreen:
+ ld hl, PalPacket_BetaTitleScreen + 1
+ call CopyFourPalettes
+ call WipeAttrmap
+ ld de, wOBPals1
+ ld a, PREDEFPAL_PACK
+ call GetPredefPal
+ call LoadHLPaletteIntoDE
+ hlcoord 0, 6, wAttrmap
+ lb bc, 12, SCREEN_WIDTH
+ ld a, $1
+ call FillBoxCGB
+ call ApplyAttrmap
+ call ApplyPals
+ ld a, $1
+ ldh [hCGBPalUpdate], a
+ ret
+
+_CGB_GSIntro:
+ ld b, 0
+ ld hl, .Jumptable
+ add hl, bc
+ add hl, bc
+ ld a, [hli]
+ ld h, [hl]
+ ld l, a
+ jp hl
+
+.Jumptable:
+ dw .ShellderLaprasScene
+ dw .JigglypuffPikachuScene
+ dw .StartersCharizardScene
+
+.ShellderLaprasScene:
+ ld hl, .ShellderLaprasBGPalette
+ ld de, wBGPals1
+ call LoadHLPaletteIntoDE
+ ld hl, .ShellderLaprasOBPals
+ ld de, wOBPals1
+ ld bc, 2 palettes
+ call CopyBytes
+ call WipeAttrmap
+ ret
+
+.ShellderLaprasBGPalette:
+ RGB 19, 31, 19
+ RGB 18, 23, 31
+ RGB 11, 21, 28
+ RGB 04, 16, 24
+
+.ShellderLaprasOBPals:
+ RGB 29, 29, 29
+ RGB 20, 19, 20
+ RGB 19, 06, 04
+ RGB 03, 04, 06
+
+ RGB 31, 31, 31
+ RGB 31, 31, 31
+ RGB 31, 00, 00
+ RGB 03, 04, 06
+
+.JigglypuffPikachuScene:
+ ld de, wBGPals1
+ ld a, PREDEFPAL_GS_INTRO_JIGGLYPUFF_PIKACHU_BG
+ call GetPredefPal
+ call LoadHLPaletteIntoDE
+
+ ld de, wOBPals1
+ ld a, PREDEFPAL_GS_INTRO_JIGGLYPUFF_PIKACHU_OB
+ call GetPredefPal
+ call LoadHLPaletteIntoDE
+ call WipeAttrmap
+ ret
+
+.StartersCharizardScene:
+ ld hl, PalPacket_Pack + 1
+ call CopyFourPalettes
+ ld de, wOBPals1
+ ld a, PREDEFPAL_GS_INTRO_STARTERS_TRANSITION
+ call GetPredefPal
+ call LoadHLPaletteIntoDE
+ call WipeAttrmap
+ ret
+
+_CGB_BetaPoker:
+ ld hl, BetaPokerPals
+ ld de, wBGPals1
+ ld bc, 5 palettes
+ call CopyBytes
+ call ApplyPals
+ call WipeAttrmap
+ call ApplyAttrmap
+ ret
+
+_CGB_Diploma:
+ ld hl, DiplomaPalettes
+ ld de, wBGPals1
+ ld bc, 16 palettes
+ call CopyBytes
+
+ ld hl, PalPacket_Diploma + 1
+ call CopyFourPalettes
+ call WipeAttrmap
+ call ApplyAttrmap
+ ret
+
+_CGB_MapPals:
+ call LoadMapPals
+ ld a, SCGB_MAPPALS
+ ld [wSGBPredef], a
+ ret
+
+_CGB_PartyMenu:
+ ld hl, PalPacket_PartyMenu + 1
+ call CopyFourPalettes
+ call InitPartyMenuOBPals
+ call ApplyAttrmap
+ ret
+
+_CGB_Evolution:
+ ld de, wBGPals1
+ ld a, c
+ and a
+ jr z, .pokemon
+ ld a, PREDEFPAL_BLACKOUT
+ call GetPredefPal
+ call LoadHLPaletteIntoDE
+ jr .got_palette
+
+.pokemon
+ ld hl, wPartyMon1DVs
+ ld bc, PARTYMON_STRUCT_LENGTH
+ ld a, [wCurPartyMon]
+ call AddNTimes
+ ld c, l
+ ld b, h
+ ld a, [wPlayerHPPal]
+ call GetPlayerOrMonPalettePointer
+ call LoadPalette_White_Col1_Col2_Black
+ ld hl, BattleObjectPals
+ ld de, wOBPals1 palette PAL_BATTLE_OB_GRAY
+ ld bc, 6 palettes
+ call CopyBytes
+
+.got_palette
+ call WipeAttrmap
+ call ApplyAttrmap
+ call ApplyPals
+ ld a, $1
+ ldh [hCGBPalUpdate], a
+ ret
+
+_CGB_GSTitleScreen:
+ ld hl, GSTitleBGPals
+ ld de, wBGPals1
+ ld bc, 5 palettes
+ call CopyBytes
+ ld hl, GSTitleOBPals
+ ld de, wOBPals1
+ ld bc, 2 palettes
+ call CopyBytes
+ ld a, SCGB_DIPLOMA
+ ld [wSGBPredef], a
+ call ApplyPals
+ ld a, $1
+ ldh [hCGBPalUpdate], a
+ ret
+
+_CGB0d:
+ ld hl, PalPacket_Diploma + 1
+ call CopyFourPalettes
+ call WipeAttrmap
+ call ApplyAttrmap
+ ret
+
+_CGB_UnownPuzzle:
+ ld hl, PalPacket_UnownPuzzle + 1
+ call CopyFourPalettes
+ ld de, wOBPals1
+ ld a, PREDEFPAL_UNOWN_PUZZLE
+ call GetPredefPal
+ call LoadHLPaletteIntoDE
+ ld hl, wOBPals1
+ ld a, LOW(palred 31 + palgreen 0 + palblue 0)
+ ld [hli], a
+ ld a, HIGH(palred 31 + palgreen 0 + palblue 0)
+ ld [hl], a
+ call WipeAttrmap
+ call ApplyAttrmap
+ ret
+
+_CGB_TrainerCard:
+ ld de, wBGPals1
+ xor a ; CHRIS
+ call GetTrainerPalettePointer
+ call LoadPalette_White_Col1_Col2_Black
+ ld a, FALKNER
+ call GetTrainerPalettePointer
+ call LoadPalette_White_Col1_Col2_Black
+ ld a, BUGSY
+ call GetTrainerPalettePointer
+ call LoadPalette_White_Col1_Col2_Black
+ ld a, WHITNEY
+ call GetTrainerPalettePointer
+ call LoadPalette_White_Col1_Col2_Black
+ ld a, MORTY
+ call GetTrainerPalettePointer
+ call LoadPalette_White_Col1_Col2_Black
+ ld a, CHUCK
+ call GetTrainerPalettePointer
+ call LoadPalette_White_Col1_Col2_Black
+ ld a, JASMINE
+ call GetTrainerPalettePointer
+ call LoadPalette_White_Col1_Col2_Black
+ ld a, PRYCE
+ call GetTrainerPalettePointer
+ call LoadPalette_White_Col1_Col2_Black
+ ld a, PREDEFPAL_CGB_BADGE
+ call GetPredefPal
+ call LoadHLPaletteIntoDE
+
+ ; card border
+ hlcoord 0, 0, wAttrmap
+ ld bc, SCREEN_WIDTH * SCREEN_HEIGHT
+ ld a, $1 ; FALKNER
+ call ByteFill
+ hlcoord 14, 1, wAttrmap
+ lb bc, 7, 5
+ xor a ; CHRIS
+ call FillBoxCGB
+ ; top-right corner still uses the border's palette
+ hlcoord 18, 1, wAttrmap
+ ld [hl], $1
+ hlcoord 2, 11, wAttrmap
+ lb bc, 2, 4
+ ld a, $1 ; falkner
+ call FillBoxCGB
+ hlcoord 6, 11, wAttrmap
+ lb bc, 2, 4
+ ld a, $2 ; bugsy
+ call FillBoxCGB
+ hlcoord 10, 11, wAttrmap
+ lb bc, 2, 4
+ ld a, $3 ; whitney
+ call FillBoxCGB
+ hlcoord 14, 11, wAttrmap
+ lb bc, 2, 4
+ ld a, $4 ; morty
+ call FillBoxCGB
+ hlcoord 2, 14, wAttrmap
+ lb bc, 2, 4
+ ld a, $5 ; chuck
+ call FillBoxCGB
+ hlcoord 6, 14, wAttrmap
+ lb bc, 2, 4
+ ld a, $6 ; jasmine
+ call FillBoxCGB
+ hlcoord 10, 14, wAttrmap
+ lb bc, 2, 4
+ ld a, $7 ; pryce
+ call FillBoxCGB
+ call ApplyAttrmap
+ call ApplyPals
+ ld a, $1
+ ldh [hCGBPalUpdate], a
+ ret
+
+_CGB_MoveList:
+ ld de, wBGPals1
+ ld a, PREDEFPAL_GOLDENROD
+ call GetPredefPal
+ call LoadHLPaletteIntoDE
+ ld a, [wPlayerHPPal]
+ ld l, a
+ ld h, 0
+ add hl, hl
+ add hl, hl
+ ld bc, HPBarPals
+ add hl, bc
+ call LoadPalette_White_Col1_Col2_Black
+ call WipeAttrmap
+ hlcoord 11, 1, wAttrmap
+ lb bc, 2, 9
+ ld a, $1
+ call FillBoxCGB
+ call ApplyAttrmap
+ call ApplyPals
+ ld a, $1
+ ldh [hCGBPalUpdate], a
+ ret
+
+_CGB_BetaPikachuMinigame:
+ ld hl, PalPacket_BetaPikachuMinigame + 1
+ call CopyFourPalettes
+ call WipeAttrmap
+ call ApplyAttrmap
+ call ApplyPals
+ ld a, $1
+ ldh [hCGBPalUpdate], a
+ ret
+
+_CGB_PokedexSearchOption:
+ ld de, wBGPals1
+ ld a, PREDEFPAL_POKEDEX
+ call GetPredefPal
+ call LoadHLPaletteIntoDE
+ call WipeAttrmap
+ call ApplyAttrmap
+ call ApplyPals
+ ld a, $1
+ ldh [hCGBPalUpdate], a
+ ret
+
+_CGB_PackPals:
+ ld de, wBGPals1
+ ld hl, .PackPals
+ ld bc, 8 palettes ; 6 palettes?
+ call CopyBytes
+ call WipeAttrmap
+ hlcoord 0, 0, wAttrmap
+ lb bc, 1, 10
+ ld a, $1
+ call FillBoxCGB
+ hlcoord 10, 0, wAttrmap
+ lb bc, 1, 10
+ ld a, $2
+ call FillBoxCGB
+ hlcoord 7, 2, wAttrmap
+ lb bc, 9, 1
+ ld a, $3
+ call FillBoxCGB
+ hlcoord 0, 7, wAttrmap
+ lb bc, 3, 5
+ ld a, $4
+ call FillBoxCGB
+ hlcoord 0, 3, wAttrmap
+ lb bc, 3, 5
+ ld a, $5
+ call FillBoxCGB
+ call ApplyAttrmap
+ call ApplyPals
+ ld a, $1
+ ldh [hCGBPalUpdate], a
+ ret
+
+.PackPals:
+INCLUDE "gfx/pack/pack.pal"
+
+_CGB_Pokepic:
+ call _CGB_MapPals
+ call SwapTextboxPalettes
+ ld de, SCREEN_WIDTH
+ hlcoord 0, 0, wAttrmap
+ ld a, [wMenuBorderTopCoord]
+.loop
+ and a
+ jr z, .found_top
+ dec a
+ add hl, de
+ jr .loop
+
+.found_top
+ ld a, [wMenuBorderLeftCoord]
+ ld e, a
+ ld d, $0
+ add hl, de
+ ld a, [wMenuBorderTopCoord]
+ ld b, a
+ ld a, [wMenuBorderBottomCoord]
+ inc a
+ sub b
+ ld b, a
+ ld a, [wMenuBorderLeftCoord]
+ ld c, a
+ ld a, [wMenuBorderRightCoord]
+ sub c
+ inc a
+ ld c, a
+ ld a, $0
+ call FillBoxCGB
+ call ApplyAttrmap
+ ret
+
+_CGB_MagnetTrain:
+ ld hl, PalPacket_MagnetTrain + 1
+ call CopyFourPalettes
+ call WipeAttrmap
+ hlcoord 0, 4, wAttrmap
+ lb bc, 10, SCREEN_WIDTH
+ ld a, $2
+ call FillBoxCGB
+ hlcoord 0, 6, wAttrmap
+ lb bc, 6, SCREEN_WIDTH
+ ld a, $1
+ call FillBoxCGB
+ call ApplyAttrmap
+ call ApplyPals
+ ld a, $1
+ ldh [hCGBPalUpdate], a
+ ret
+
+_CGB_GamefreakLogo:
+ ld de, wBGPals1
+ ld a, PREDEFPAL_GAMEFREAK_LOGO_BG
+ call GetPredefPal
+ call LoadHLPaletteIntoDE
+ ld de, wOBPals1
+ ld a, PREDEFPAL_GAMEFREAK_LOGO_OB
+ call GetPredefPal
+ call LoadHLPaletteIntoDE
+ ld de, wOBPals1 palette 1
+ ld a, PREDEFPAL_GAMEFREAK_LOGO_OB
+ call GetPredefPal
+ call LoadHLPaletteIntoDE
+ call WipeAttrmap
+ call ApplyAttrmap
+ call ApplyPals
+ ret
+
+_CGB_PlayerOrMonFrontpicPals:
+ ld de, wBGPals1
+ ld a, [wCurPartySpecies]
+ ld bc, wTempMonDVs
+ call GetPlayerOrMonPalettePointer
+ call LoadPalette_White_Col1_Col2_Black
+ call WipeAttrmap
+ call ApplyAttrmap
+ call ApplyPals
+ ret
+
+_CGB1e:
+ ld de, wBGPals1
+ ld a, [wCurPartySpecies]
+ call GetMonPalettePointer
+ call LoadPalette_White_Col1_Col2_Black
+ call WipeAttrmap
+ call ApplyAttrmap
+ ret
+
+_CGB_TradeTube:
+ ld hl, PalPacket_TradeTube + 1
+ call CopyFourPalettes
+ ld hl, PartyMenuOBPals
+ ld de, wOBPals1
+ ld bc, 1 palettes
+ call CopyBytes
+ ld de, wOBPals1 palette 7
+ ld a, PREDEFPAL_TRADE_TUBE
+ call GetPredefPal
+ call LoadHLPaletteIntoDE
+ call WipeAttrmap
+ ret
+
+_CGB_TrainerOrMonFrontpicPals:
+ ld de, wBGPals1
+ ld a, [wCurPartySpecies]
+ ld bc, wTempMonDVs
+ call GetFrontpicPalettePointer
+ call LoadPalette_White_Col1_Col2_Black
+ call WipeAttrmap
+ call ApplyAttrmap
+ call ApplyPals
+ ret
diff --git a/engine/gfx/color.asm b/engine/gfx/color.asm
new file mode 100755
index 00000000..a39ab794
--- /dev/null
+++ b/engine/gfx/color.asm
@@ -0,0 +1,1260 @@
+INCLUDE "engine/gfx/sgb_layouts.asm"
+
+SHINY_ATK_BIT EQU 5
+SHINY_DEF_VAL EQU 10
+SHINY_SPD_VAL EQU 10
+SHINY_SPC_VAL EQU 10
+
+CheckShininess:
+; Check if a mon is shiny by DVs at bc.
+; Return carry if shiny.
+
+ ld l, c
+ ld h, b
+
+; Attack
+ ld a, [hl]
+ and 1 << SHINY_ATK_BIT
+ jr z, .NotShiny
+
+; Defense
+ ld a, [hli]
+ and $f
+ cp SHINY_DEF_VAL
+ jr nz, .NotShiny
+
+; Speed
+ ld a, [hl]
+ and $f0
+ cp SHINY_SPD_VAL << 4
+ jr nz, .NotShiny
+
+; Special
+ ld a, [hl]
+ and $f
+ cp SHINY_SPC_VAL
+ jr nz, .NotShiny
+
+.Shiny:
+ scf
+ ret
+
+.NotShiny:
+ and a
+ ret
+
+Unused_CheckShininess:
+; Return carry if the DVs at hl are all 10 or higher.
+
+; Attack
+ ld a, [hl]
+ cp 10 << 4
+ jr c, .NotShiny
+
+; Defense
+ ld a, [hli]
+ and $f
+ cp 10
+ jr c, .NotShiny
+
+; Speed
+ ld a, [hl]
+ cp 10 << 4
+ jr c, .NotShiny
+
+; Special
+ ld a, [hl]
+ and $f
+ cp 10
+ jr c, .NotShiny
+
+.Shiny:
+ scf
+ ret
+
+.NotShiny:
+ and a
+ ret
+
+Function908e:
+ push de
+ push bc
+ ld hl, PalPacket_a155
+ ld de, wSGBPals
+ ld bc, PALPACKET_LENGTH
+ call CopyBytes
+ pop bc
+ pop de
+ ld a, c
+ ld [wSGBPals + 3], a
+ ld a, b
+ ld [wSGBPals + 4], a
+ ld a, e
+ ld [wSGBPals + 5], a
+ ld a, d
+ ld [wSGBPals + 6], a
+ ld hl, wSGBPals
+ call PushSGBPals
+ ld hl, BlkPacket_9ee5
+ call PushSGBPals
+ ret
+
+InitPartyMenuPalettes:
+ call CheckCGB
+ jr nz, .cgb
+ ld hl, BlkPacket_9fa5
+ ld de, wSGBPals + 1
+ ld bc, 6 palettes
+ jp CopyBytes
+
+.cgb
+ ld hl, PalPacket_PartyMenu + 1
+ call CopyFourPalettes
+ call InitPartyMenuOBPals
+ call WipeAttrmap
+ ret
+
+; SGB layout for SCGB_PARTY_MENU_HP_PALS
+SGB_ApplyPartyMenuHPPals:
+ ld hl, wHPPals
+ ld a, [wSGBPals]
+ ld e, a
+ ld d, $0
+ add hl, de
+ ld e, l
+ ld d, h
+ ld a, [de]
+ and a
+ ld e, $5
+ jr z, .okay
+ dec a
+ ld e, $a
+ jr z, .okay
+ ld e, $f
+.okay
+ push de
+ ld hl, wSGBPals + 10
+ ld bc, $6
+ ld a, [wSGBPals]
+ call AddNTimes
+ pop de
+ ld [hl], e
+ ret
+
+Unreferenced_Function9102:
+ call CheckCGB
+ ret z
+; CGB only
+ ld hl, .BGPal
+ ld de, wBGPals1
+ ld bc, 1 palettes
+ call CopyBytes
+
+ ld hl, .OBPal
+ ld de, wOBPals1
+ ld bc, 1 palettes
+ call CopyBytes
+
+ call ApplyPals
+ ld a, $1
+ ldh [hCGBPalUpdate], a
+ ret
+
+.BGPal:
+ RGB 31, 31, 31
+ RGB 18, 23, 31
+ RGB 15, 20, 31
+ RGB 00, 00, 00
+
+.OBPal:
+ RGB 31, 31, 31
+ RGB 31, 31, 12
+ RGB 08, 16, 28
+ RGB 00, 00, 00
+
+Unreferenced_Function9136:
+ call CheckCGB
+ ret nz
+ ldh a, [hSGB]
+ and a
+ ret z
+ ld hl, BlkPacket_9ee5
+ jp PushSGBPals
+
+Unreferenced_Function9144:
+ call CheckCGB
+ jr nz, .cgb
+ ldh a, [hSGB]
+ and a
+ ret z
+ ld hl, PalPacket_BetaIntroVenusaur
+ jp PushSGBPals
+
+.cgb
+ ld de, wOBPals1
+ ld a, PREDEFPAL_BETA_INTRO_VENUSAUR
+ call GetPredefPal
+ jp LoadHLPaletteIntoDE
+
+Unreferenced_Function915e:
+ call CheckCGB
+ jr nz, .cgb
+ ldh a, [hSGB]
+ and a
+ ret z
+ ld hl, PalPacket_Pack
+ jp PushSGBPals
+
+.cgb
+ ld de, wOBPals1
+ ld a, PREDEFPAL_PACK
+ call GetPredefPal
+ jp LoadHLPaletteIntoDE
+
+Unreferenced_Function9178:
+ call CheckCGB
+ jr nz, .cgb
+ ldh a, [hSGB]
+ and a
+ ret z
+ ld a, c
+ push af
+ ld hl, PalPacket_a155
+ ld de, wSGBPals
+ ld bc, PALPACKET_LENGTH
+ call CopyBytes
+ pop af
+ call GetMonPalettePointer
+ ld a, [hli]
+ ld [wSGBPals + 3], a
+ ld a, [hli]
+ ld [wSGBPals + 4], a
+ ld a, [hli]
+ ld [wSGBPals + 5], a
+ ld a, [hl]
+ ld [wSGBPals + 6], a
+ ld hl, wSGBPals
+ jp PushSGBPals
+
+.cgb
+ ld de, wOBPals1
+ ld a, c
+ call GetMonPalettePointer
+ call LoadPalette_White_Col1_Col2_Black
+ ret
+
+Unreferenced_Function91b4:
+ ldh a, [hCGB]
+ and a
+ jr nz, .cgb
+ ld hl, wc602
+ jp PushSGBPals
+
+.cgb
+ ld a, [wc606] ; col
+ ld c, a
+ ld a, [wc607] ; row
+ hlcoord 0, 0, wAttrmap
+ ld de, SCREEN_WIDTH
+.loop
+ and a
+ jr z, .done
+ add hl, de
+ dec a
+ jr .loop
+
+.done
+ ld b, $0
+ add hl, bc
+ lb bc, 6, 4
+ ld a, [wc605] ; value
+ and $3
+ call FillBoxCGB
+ call CopyTilemapAtOnce
+ ret
+
+ApplyMonOrTrainerPals:
+ call CheckCGB
+ ret z
+ ld a, e
+ and a
+ jr z, .get_trainer
+ ld a, [wCurPartySpecies]
+ call GetMonPalettePointer
+ jr .load_palettes
+
+.get_trainer
+ ld a, [wTrainerClass]
+ call GetTrainerPalettePointer
+
+.load_palettes
+ ld de, wBGPals1
+ call LoadPalette_White_Col1_Col2_Black
+ call WipeAttrmap
+ call ApplyAttrmap
+ call ApplyPals
+ ret
+
+ApplyHPBarPals:
+ ld a, [wWhichHPBar]
+ and a
+ jr z, .Enemy
+ cp $1
+ jr z, .Player
+ cp $2
+ jr z, .PartyMenu
+ ret
+
+.Enemy:
+ ld de, wBGPals2 palette PAL_BATTLE_BG_ENEMY_HP color 1
+ jr .okay
+
+.Player:
+ ld de, wBGPals2 palette PAL_BATTLE_BG_PLAYER_HP color 1
+
+.okay
+ ld l, c
+ ld h, $0
+ add hl, hl
+ add hl, hl
+ ld bc, HPBarPals
+ add hl, bc
+ ld bc, 4
+ call CopyBytes
+ ld a, $1
+ ldh [hCGBPalUpdate], a
+ ret
+
+.PartyMenu:
+ ld e, c
+ inc e
+ hlcoord 11, 1, wAttrmap
+ ld bc, 2 * SCREEN_WIDTH
+ ld a, [wCurPartyMon]
+.loop
+ and a
+ jr z, .done
+ add hl, bc
+ dec a
+ jr .loop
+
+.done
+ lb bc, 2, 8
+ ld a, e
+ call FillBoxCGB
+ ret
+
+LoadStatsScreenPals:
+ call CheckCGB
+ ret z
+ ld hl, StatsScreenPals
+ ld b, 0
+ dec c
+ add hl, bc
+ add hl, bc
+ ld a, [hli]
+ ld [wBGPals1 palette 0], a
+ ld [wBGPals1 palette 2], a
+ ld a, [hl]
+ ld [wBGPals1 palette 0 + 1], a
+ ld [wBGPals1 palette 2 + 1], a
+ call ApplyPals
+ ld a, $1
+ ldh [hCGBPalUpdate], a
+ ret
+
+LoadMailPalettes:
+ ld l, e
+ ld h, 0
+ add hl, hl
+ add hl, hl
+ add hl, hl
+ ld de, .MailPals
+ add hl, de
+ call CheckCGB
+ jr nz, .cgb
+ push hl
+ ld hl, PalPacket_a155
+ ld de, wSGBPals
+ ld bc, PALPACKET_LENGTH
+ call CopyBytes
+ pop hl
+ inc hl
+ inc hl
+ ld a, [hli]
+ ld [wSGBPals + 3], a
+ ld a, [hli]
+ ld [wSGBPals + 4], a
+ ld a, [hli]
+ ld [wSGBPals + 5], a
+ ld a, [hli]
+ ld [wSGBPals + 6], a
+ ld hl, wSGBPals
+ call PushSGBPals
+ ld hl, BlkPacket_9ee5
+ call PushSGBPals
+ ret
+
+.cgb
+ ld de, wBGPals1
+ ld bc, 1 palettes
+ call CopyBytes
+ call ApplyPals
+ call WipeAttrmap
+ call ApplyAttrmap
+ ret
+
+.MailPals:
+INCLUDE "gfx/mail/mail.pal"
+
+INCLUDE "engine/gfx/cgb_layouts.asm"
+
+_CGB_MysteryGift:
+ ld hl, .Palette
+ ld de, wBGPals1
+ ld bc, 1 palettes
+ call CopyBytes
+ call ApplyPals
+ call WipeAttrmap
+ call ApplyAttrmap
+ ret
+
+.Palette:
+ RGB 31, 31, 31
+ RGB 09, 31, 31
+ RGB 10, 12, 31
+ RGB 00, 03, 19
+
+CopyFourPalettes:
+ ld de, wBGPals1
+ ld c, 4
+
+CopyPalettes:
+.loop
+ push bc
+ ld a, [hli]
+ push hl
+ call GetPredefPal
+ call LoadHLPaletteIntoDE
+ pop hl
+ inc hl
+ pop bc
+ dec c
+ jr nz, .loop
+ ret
+
+GetPredefPal:
+ ld l, a
+ ld h, $0
+ add hl, hl
+ add hl, hl
+ add hl, hl
+ ld bc, PredefPals
+ add hl, bc
+ ret
+
+LoadHLPaletteIntoDE:
+ ld c, 1 palettes
+.loop
+ ld a, [hli]
+ ld [de], a
+ inc de
+ dec c
+ jr nz, .loop
+ ret
+
+LoadPalette_White_Col1_Col2_Black:
+ ld a, LOW(PALRGB_WHITE)
+ ld [de], a
+ inc de
+ ld a, HIGH(PALRGB_WHITE)
+ ld [de], a
+ inc de
+
+ ld c, 2 * PAL_COLOR_SIZE
+.loop
+ ld a, [hli]
+ ld [de], a
+ inc de
+ dec c
+ jr nz, .loop
+
+ xor a
+ ld [de], a
+ inc de
+ ld [de], a
+ inc de
+ ret
+
+FillBoxCGB:
+.row
+ push bc
+ push hl
+.col
+ ld [hli], a
+ dec c
+ jr nz, .col
+ pop hl
+ ld bc, SCREEN_WIDTH
+ add hl, bc
+ pop bc
+ dec b
+ jr nz, .row
+ ret
+
+ResetBGPals:
+ push af
+ push bc
+ push de
+ push hl
+ ld hl, wBGPals1
+ ld c, 1 palettes
+.loop
+ ld a, $ff
+ ld [hli], a
+ ld [hli], a
+ ld [hli], a
+ ld [hli], a
+ xor a
+ ld [hli], a
+ ld [hli], a
+ ld [hli], a
+ ld [hli], a
+ dec c
+ jr nz, .loop
+ pop hl
+ pop de
+ pop bc
+ pop af
+ ret
+
+WipeAttrmap:
+ hlcoord 0, 0, wAttrmap
+ ld bc, SCREEN_WIDTH * SCREEN_HEIGHT
+ xor a
+ call ByteFill
+ ret
+
+ApplyPals:
+ ld hl, wBGPals1
+ ld de, wBGPals2
+ ld bc, 16 palettes
+ call CopyBytes
+ ret
+
+ApplyAttrmap:
+ ldh a, [rLCDC]
+ bit rLCDC_ENABLE, a
+ jr z, .UpdateVBank1
+ ldh a, [hBGMapMode]
+ push af
+ ld a, $2
+ ldh [hBGMapMode], a
+ call DelayFrame
+ call DelayFrame
+ call DelayFrame
+ call DelayFrame
+ pop af
+ ldh [hBGMapMode], a
+ ret
+
+.UpdateVBank1:
+ hlcoord 0, 0, wAttrmap
+ debgcoord 0, 0
+ ld b, SCREEN_HEIGHT
+ ld a, $1
+ ldh [rVBK], a
+.row
+ ld c, SCREEN_WIDTH
+.col
+ ld a, [hli]
+ ld [de], a
+ inc de
+ dec c
+ jr nz, .col
+ ld a, BG_MAP_WIDTH - SCREEN_WIDTH
+ add e
+ jr nc, .okay
+ inc d
+.okay
+ ld e, a
+ dec b
+ jr nz, .row
+ ld a, $0
+ ldh [rVBK], a
+ ret
+
+; CGB layout for SCGB_PARTY_MENU_HP_PALS
+CGB_ApplyPartyMenuHPPals:
+ ld hl, wHPPals
+ ld a, [wSGBPals]
+ ld e, a
+ ld d, $0
+ add hl, de
+ ld e, l
+ ld d, h
+ ld a, [de]
+ inc a
+ ld e, a
+ hlcoord 11, 2, wAttrmap
+ ld bc, 2 * SCREEN_WIDTH
+ ld a, [wSGBPals]
+.loop
+ and a
+ jr z, .done
+ add hl, bc
+ dec a
+ jr .loop
+.done
+ lb bc, 2, 8
+ ld a, e
+ call FillBoxCGB
+ ret
+
+InitPartyMenuOBPals:
+ ld hl, PartyMenuOBPals
+ ld de, wOBPals1
+ ld bc, 2 palettes
+ call CopyBytes
+ ret
+
+GetBattlemonBackpicPalettePointer:
+ push de
+ farcall GetPartyMonDVs
+ ld c, l
+ ld b, h
+ ld a, [wTempBattleMonSpecies]
+ call GetPlayerOrMonPalettePointer
+ pop de
+ ret
+
+GetEnemyFrontpicPalettePointer:
+ push de
+ farcall GetEnemyMonDVs
+ ld c, l
+ ld b, h
+ ld a, [wTempEnemyMonSpecies]
+ call GetFrontpicPalettePointer
+ pop de
+ ret
+
+GetPlayerOrMonPalettePointer:
+ and a
+ jp nz, GetMonNormalOrShinyPalettePointer
+ ld hl, PlayerPalette
+ ret
+
+GetFrontpicPalettePointer:
+ and a
+ jp nz, GetMonNormalOrShinyPalettePointer
+ ld a, [wTrainerClass]
+
+GetTrainerPalettePointer:
+ ld l, a
+ ld h, 0
+ add hl, hl
+ add hl, hl
+ ld bc, TrainerPalettes
+ add hl, bc
+ ret
+
+GetMonPalettePointer:
+ call _GetMonPalettePointer
+ ret
+
+Unreferenced_Function9be8:
+ ret
+ call CheckCGB
+ ret z
+ ld hl, BattleObjectPals
+ ld a, $90
+ ldh [rOBPI], a
+ ld c, 6 palettes
+.loop
+ ld a, [hli]
+ ldh [rOBPD], a
+ dec c
+ jr nz, .loop
+ ld hl, BattleObjectPals
+ ld de, wOBPals1 palette 2
+ ld bc, 2 palettes
+ call CopyBytes
+ ret
+
+BattleObjectPals:
+INCLUDE "gfx/battle_anims/battle_anims.pal"
+
+Unreferenced_Function9c39:
+ call CheckCGB
+ ret z
+ ld a, $90
+ ldh [rOBPI], a
+ ld a, PREDEFPAL_TRADE_TUBE
+ call GetPredefPal
+ call .PushPalette
+ ld a, PREDEFPAL_RB_GREENMON
+ call GetPredefPal
+ call .PushPalette
+ ret
+
+.PushPalette:
+ ld c, 1 palettes
+.loop
+ ld a, [hli]
+ ldh [rOBPD], a
+ dec c
+ jr nz, .loop
+ ret
+
+_GetMonPalettePointer:
+ ld l, a
+ ld h, $0
+ add hl, hl
+ add hl, hl
+ add hl, hl
+ ld bc, PokemonPalettes
+ add hl, bc
+ ret
+
+GetMonNormalOrShinyPalettePointer:
+ push bc
+ call _GetMonPalettePointer
+ pop bc
+ push hl
+ call CheckShininess
+ pop hl
+ ret nc
+rept 4
+ inc hl
+endr
+ ret
+
+PushSGBPals:
+ ld a, [wd8ba]
+ push af
+ set 7, a
+ ld [wd8ba], a
+ call _PushSGBPals
+ pop af
+ ld [wd8ba], a
+ ret
+
+_PushSGBPals:
+ ld a, [hl]
+ and $7
+ ret z
+ ld b, a
+.loop
+ push bc
+ xor a
+ ldh [rJOYP], a
+ ld a, $30
+ ldh [rJOYP], a
+ ld b, $10
+.loop2
+ ld e, $8
+ ld a, [hli]
+ ld d, a
+.loop3
+ bit 0, d
+ ld a, $10
+ jr nz, .okay
+ ld a, $20
+.okay
+ ldh [rJOYP], a
+ ld a, $30
+ ldh [rJOYP], a
+ rr d
+ dec e
+ jr nz, .loop3
+ dec b
+ jr nz, .loop2
+ ld a, $20
+ ldh [rJOYP], a
+ ld a, $30
+ ldh [rJOYP], a
+ call SGBDelayCycles
+ pop bc
+ dec b
+ jr nz, .loop
+ ret
+
+InitSGBBorder:
+ call CheckCGB
+ ret nz
+; SGB/DMG only
+ di
+ ld a, [wd8ba]
+ push af
+ set 7, a
+ ld [wd8ba], a
+ xor a
+ ldh [rJOYP], a
+ ldh [hSGB], a
+ call PushSGBBorderPalsAndWait
+ jr nc, .skip
+ ld a, $1
+ ldh [hSGB], a
+ call _InitSGBBorderPals
+ call SGBBorder_PushBGPals
+ call SGBDelayCycles
+ call SGB_ClearVRAM
+ call PushSGBBorder
+ call SGBDelayCycles
+ call SGB_ClearVRAM
+ ld hl, MaskEnCancelPacket
+ call _PushSGBPals
+
+.skip
+ pop af
+ ld [wd8ba], a
+ ei
+ ret
+
+InitCGBPals::
+ call CheckCGB
+ ret z
+; CGB only
+ ld a, BANK(vTiles3)
+ ldh [rVBK], a
+ ld hl, vTiles3
+ ld bc, $200 tiles
+ xor a
+ call ByteFill
+ ld a, BANK(vTiles0)
+ ldh [rVBK], a
+ ld a, 1 << rBGPI_AUTO_INCREMENT
+ ldh [rBGPI], a
+ ld c, 4 * 8
+.bgpals_loop
+ ld a, LOW(PALRGB_WHITE)
+ ldh [rBGPD], a
+ ld a, HIGH(PALRGB_WHITE)
+ ldh [rBGPD], a
+ dec c
+ jr nz, .bgpals_loop
+ ld a, 1 << rOBPI_AUTO_INCREMENT
+ ldh [rOBPI], a
+ ld c, 4 * 8
+.obpals_loop
+ ld a, LOW(PALRGB_WHITE)
+ ldh [rOBPD], a
+ ld a, HIGH(PALRGB_WHITE)
+ ldh [rOBPD], a
+ dec c
+ jr nz, .obpals_loop
+ ld hl, wBGPals1
+ call .LoadWhitePals
+ ld hl, wBGPals2
+.LoadWhitePals:
+ ld c, 4 * 16
+.loop
+ ld a, LOW(PALRGB_WHITE)
+ ld [hli], a
+ ld a, HIGH(PALRGB_WHITE)
+ ld [hli], a
+ dec c
+ jr nz, .loop
+ ret
+
+_InitSGBBorderPals:
+ ld hl, .PacketPointerTable
+ ld c, 9
+.loop
+ push bc
+ ld a, [hli]
+ push hl
+ ld h, [hl]
+ ld l, a
+ call _PushSGBPals
+ pop hl
+ inc hl
+ pop bc
+ dec c
+ jr nz, .loop
+ ret
+
+.PacketPointerTable:
+ dw MaskEnFreezePacket
+ dw DataSndPacket1
+ dw DataSndPacket2
+ dw DataSndPacket3
+ dw DataSndPacket4
+ dw DataSndPacket5
+ dw DataSndPacket6
+ dw DataSndPacket7
+ dw DataSndPacket8
+
+Unreferenced_Function9d70:
+ di
+ xor a
+ ldh [rJOYP], a
+ ld hl, MaskEnFreezePacket
+ call _PushSGBPals
+ call PushSGBBorder
+ call SGBDelayCycles
+ call SGB_ClearVRAM
+ ld hl, MaskEnCancelPacket
+ call _PushSGBPals
+ ei
+ ret
+
+PushSGBBorder:
+ call .LoadSGBBorderPointers
+ push de
+ call SGBBorder_YetMorePalPushing
+ pop hl
+ call SGBBorder_MorePalPushing
+ ret
+
+.LoadSGBBorderPointers:
+ ld hl, SGBBorder
+ ld de, SGBBorderMap
+ ret
+
+SGB_ClearVRAM:
+ ld hl, VRAM_Begin
+ ld bc, VRAM_End - VRAM_Begin
+ xor a
+ call ByteFill
+ ret
+
+PushSGBBorderPalsAndWait:
+ ld hl, MltReq2Packet
+ call _PushSGBPals
+ call SGBDelayCycles
+ ldh a, [rJOYP]
+ and $3
+ cp $3
+ jr nz, .carry
+ ld a, $20
+ ldh [rJOYP], a
+ ldh a, [rJOYP]
+ ldh a, [rJOYP]
+ call SGBDelayCycles
+ call SGBDelayCycles
+ ld a, $30
+ ldh [rJOYP], a
+ call SGBDelayCycles
+ call SGBDelayCycles
+ ld a, $10
+ ldh [rJOYP], a
+rept 6
+ ldh a, [rJOYP]
+endr
+ call SGBDelayCycles
+ call SGBDelayCycles
+ ld a, $30
+ ldh [rJOYP], a
+ ldh a, [rJOYP]
+ ldh a, [rJOYP]
+ ldh a, [rJOYP]
+ call SGBDelayCycles
+ call SGBDelayCycles
+ ldh a, [rJOYP]
+ and $3
+ cp $3
+ jr nz, .carry
+ call .FinalPush
+ and a
+ ret
+
+.carry
+ call .FinalPush
+ scf
+ ret
+
+.FinalPush:
+ ld hl, MltReq1Packet
+ call _PushSGBPals
+ jp SGBDelayCycles
+
+SGBBorder_PushBGPals:
+ call DisableLCD
+ ld a, %11100100
+ ldh [rBGP], a
+ ld hl, PredefPals
+ ld de, vTiles1
+ ld bc, $100 tiles
+ call CopyData
+ call DrawDefaultTiles
+ ld a, LCDC_DEFAULT
+ ldh [rLCDC], a
+ ld hl, PalTrnPacket
+ call _PushSGBPals
+ xor a
+ ldh [rBGP], a
+ ret
+
+SGBBorder_MorePalPushing:
+ call DisableLCD
+ ld a, $e4
+ ldh [rBGP], a
+ ld de, vTiles1
+ ld bc, (6 + SCREEN_WIDTH + 6) * 5 * 2
+ call CopyData
+ ld b, SCREEN_HEIGHT
+.loop
+ push bc
+ ld bc, 6 * 2
+ call CopyData
+ ld bc, SCREEN_WIDTH * 2
+ call ClearBytes
+ ld bc, 6 * 2
+ call CopyData
+ pop bc
+ dec b
+ jr nz, .loop
+ ld bc, (6 + SCREEN_WIDTH + 6) * 5 * 2
+ call CopyData
+ ld bc, $100
+ call ClearBytes
+ ld bc, 16 palettes
+ call CopyData
+ call DrawDefaultTiles
+ ld a, LCDC_DEFAULT
+ ldh [rLCDC], a
+ ld hl, PctTrnPacket
+ call _PushSGBPals
+ xor a
+ ldh [rBGP], a
+ ret
+
+SGBBorder_YetMorePalPushing:
+ call DisableLCD
+ ld a, %11100100
+ ldh [rBGP], a
+ ld de, vTiles1
+ ld b, $80
+.loop
+ push bc
+ ld bc, 1 tiles
+ call CopyData
+ ld bc, 1 tiles
+ call ClearBytes
+ pop bc
+ dec b
+ jr nz, .loop
+ call DrawDefaultTiles
+ ld a, LCDC_DEFAULT
+ ldh [rLCDC], a
+ ld hl, ChrTrnPacket
+ call _PushSGBPals
+ xor a
+ ldh [rBGP], a
+ ret
+
+CopyData:
+; copy bc bytes of data from hl to de
+.loop
+ ld a, [hli]
+ ld [de], a
+ inc de
+ dec bc
+ ld a, c
+ or b
+ jr nz, .loop
+ ret
+
+ClearBytes:
+; clear bc bytes of data starting from de
+.loop
+ xor a
+ ld [de], a
+ inc de
+ dec bc
+ ld a, c
+ or b
+ jr nz, .loop
+ ret
+
+DrawDefaultTiles:
+; Draw 240 tiles (2/3 of the screen) from tiles in VRAM
+ hlbgcoord 0, 0 ; BG Map 0
+ ld de, BG_MAP_WIDTH - SCREEN_WIDTH
+ ld a, $80 ; starting tile
+ ld c, 12 + 1
+.line
+ ld b, 20
+.tile
+ ld [hli], a
+ inc a
+ dec b
+ jr nz, .tile
+; next line
+ add hl, de
+ dec c
+ jr nz, .line
+ ret
+
+SGBDelayCycles:
+ ld de, 7000
+.wait
+ nop
+ nop
+ nop
+ dec de
+ ld a, d
+ or e
+ jr nz, .wait
+ ret
+
+INCLUDE "gfx/sgb/blk_packets.asm"
+INCLUDE "gfx/sgb/pal_packets.asm"
+INCLUDE "data/sgb_ctrl_packets.asm"
+
+PredefPals:
+INCLUDE "gfx/sgb/predef.pal"
+
+IF DEF(_GOLD)
+SGBBorderMap:
+INCBIN "gfx/sgb/gold_border.sgb.tilemap"
+SGBBorderPalettes:
+INCLUDE "gfx/sgb/gold_border.pal"
+SGBBorder:
+INCBIN "gfx/sgb/gold_border.2bpp"
+
+ELIF DEF(_SILVER)
+SGBBorderMap:
+INCBIN "gfx/sgb/silver_border.sgb.tilemap"
+SGBBorderPalettes:
+INCLUDE "gfx/sgb/silver_border.pal"
+SGBBorder:
+INCBIN "gfx/sgb/silver_border.2bpp"
+ENDC
+
+HPBarPals:
+INCLUDE "gfx/battle/hp_bar.pal"
+
+ExpBarPalette:
+INCLUDE "gfx/battle/exp_bar.pal"
+
+INCLUDE "data/pokemon/palettes.asm"
+
+INCLUDE "data/trainers/palettes.asm"
+
+LoadMapPals:
+ ; Which palette group is based on whether we're outside or inside
+ ld a, [wEnvironment]
+ and 7
+ ld e, a
+ ld d, 0
+ ld hl, EnvironmentColorsPointers
+ add hl, de
+ add hl, de
+ ld a, [hli]
+ ld h, [hl]
+ ld l, a
+ ; Futher refine by time of day
+ ld a, [wTimeOfDayPal]
+ maskbits NUM_DAYTIMES
+ add a
+ add a
+ add a
+ ld e, a
+ ld d, 0
+ add hl, de
+ ld e, l
+ ld d, h
+ ld hl, wBGPals1
+ ld b, 8
+.outer_loop
+ ld a, [de] ; lookup index for TilesetBGPalette
+ push de
+ push hl
+ ld l, a
+ ld h, 0
+ add hl, hl
+ add hl, hl
+ add hl, hl
+ ld de, TilesetBGPalette
+ add hl, de
+ ld e, l
+ ld d, h
+ pop hl
+ ld c, 1 palettes
+.inner_loop
+ ld a, [de]
+ inc de
+ ld [hli], a
+ dec c
+ jr nz, .inner_loop
+ pop de
+ inc de
+ dec b
+ jr nz, .outer_loop
+ ld a, [wTimeOfDayPal]
+ maskbits NUM_DAYTIMES
+ ld bc, 8 palettes
+ ld hl, MapObjectPals
+ call AddNTimes
+ ld de, wOBPals1
+ ld bc, 8 palettes
+ call CopyBytes
+
+ ld a, [wEnvironment]
+ cp TOWN
+ jr z, .outside
+ cp ROUTE
+ ret nz
+.outside
+ ld a, [wMapGroup]
+ ld l, a
+ ld h, 0
+ add hl, hl
+ add hl, hl
+ add hl, hl
+ ld de, RoofPals
+ add hl, de
+ ld a, [wTimeOfDayPal]
+ maskbits NUM_DAYTIMES
+ cp NITE_F
+ jr c, .morn_day
+rept 4
+ inc hl
+endr
+.morn_day
+ ld de, wBGPals1 palette PAL_BG_ROOF color 1
+ ld bc, 4
+ call CopyBytes
+ ret
+
+INCLUDE "data/maps/environment_colors.asm"
+
+TilesetBGPalette:
+INCLUDE "gfx/tilesets/bg_tiles.pal"
+
+MapObjectPals::
+INCLUDE "gfx/overworld/npc_sprites.pal"
+
+RoofPals:
+INCLUDE "gfx/tilesets/roofs.pal"
+
+DiplomaPalettes:
+INCLUDE "gfx/diploma/diploma.pal"
+
+PartyMenuOBPals:
+INCLUDE "gfx/stats/party_menu_ob.pal"
+
+GSTitleBGPals:
+IF DEF(_GOLD)
+INCLUDE "gfx/title/title_bg_gold.pal"
+ELIF DEF(_SILVER)
+INCLUDE "gfx/title/title_bg_silver.pal"
+ENDC
+
+GSTitleOBPals:
+INCLUDE "gfx/title/title_fg.pal"
+
+PokegearPals:
+INCLUDE "gfx/pokegear/pokegear.pal"
+
+BetaPokerPals:
+INCLUDE "gfx/beta_poker/beta_poker.pal"
+
+SlotMachinePals:
+IF DEF(_GOLD)
+INCLUDE "gfx/slots/slots_gold.pal"
+ELIF DEF(_SILVER)
+INCLUDE "gfx/slots/slots_silver.pal"
+ENDC
diff --git a/engine/gfx/load_pics.asm b/engine/gfx/load_pics.asm
new file mode 100644
index 00000000..c9ee98b7
--- /dev/null
+++ b/engine/gfx/load_pics.asm
@@ -0,0 +1,428 @@
+GetUnownLetter:
+; Return Unown letter in wUnownLetter based on DVs at hl
+
+; Take the middle 2 bits of each DV and place them in order:
+; atk def spd spc
+; .ww..xx. .yy..zz.
+
+ ; atk
+ ld a, [hl]
+ and %01100000
+ sla a
+ ld b, a
+ ; def
+ ld a, [hli]
+ and %00000110
+ swap a
+ srl a
+ or b
+ ld b, a
+
+ ; spd
+ ld a, [hl]
+ and %01100000
+ swap a
+ sla a
+ or b
+ ld b, a
+ ; spc
+ ld a, [hl]
+ and %00000110
+ srl a
+ or b
+
+; Divide by 10 to get 0-25
+ ldh [hDividend + 3], a
+ xor a
+ ldh [hDividend], a
+ ldh [hDividend + 1], a
+ ldh [hDividend + 2], a
+ ld a, $ff / NUM_UNOWN + 1
+ ldh [hDivisor], a
+ ld b, 4
+ call Divide
+
+; Increment to get 1-26
+ ldh a, [hQuotient + 3]
+ inc a
+ ld [wUnownLetter], a
+ ret
+
+GetMonFrontpic:
+ call GetFrontpic
+ jp Load2bppToSRAM
+
+UnusedFrontpicPredef:
+ call GetFrontpic
+ push hl
+ farcall StubbedGetFrontpic
+ pop hl
+ jp Load2bppToSRAM
+
+GetFrontpic:
+ ld a, [wCurPartySpecies]
+ ld [wCurSpecies], a
+ and a
+ ret z
+ cp NUM_POKEMON + 1
+ ret z
+ cp EGG + 1
+ ret nc
+
+.is_a_pokemon
+ push de
+ call GetBaseData
+ ld a, [wBasePicSize]
+ and $f
+ ld b, a
+ push bc
+ ld a, BANK(sDecompressBuffer)
+ call OpenSRAM
+ ld hl, PokemonPicPointers ; UnownPicPointers
+ ld a, [wCurPartySpecies]
+ ld d, BANK(PokemonPicPointers)
+ cp UNOWN
+ jr z, .unown
+ cp EGG
+ jr nz, .not_egg
+ ld hl, EggPic
+ ld a, BANK(EggPic)
+ jr .ok
+
+.unown
+ ld a, [wUnownLetter]
+ ld d, BANK(UnownPicPointers)
+
+.not_egg
+ dec a
+ ld bc, 6
+ call AddNTimes
+ ld a, d
+ call GetFarByte
+ call FixPicBank
+ push af
+ inc hl
+ ld a, d
+ call GetFarHalfword
+ pop af
+
+.ok
+ ld de, sDecompressBuffer
+ call FarDecompress
+ pop bc
+ ld hl, sDecompressScratch
+ ld de, sDecompressBuffer
+ call PadFrontpic
+ pop hl
+ ret
+
+Load2bppToSRAM:
+ ld de, sDecompressScratch
+ ld c, 7 * 7
+ ldh a, [hROMBank]
+ ld b, a
+ call Get2bpp
+ jp CloseSRAM
+
+GetMonBackpic:
+ ld a, [wCurPartySpecies]
+ and a
+ ret z
+ cp NUM_POKEMON + 1
+ ret z
+ cp EGG + 1
+ ret nc
+
+.is_a_pokemon
+ push de
+ ld a, BANK(sDecompressBuffer)
+ call OpenSRAM
+
+ ; These are assumed to be at the same address in their respective banks.
+ ld hl, PokemonPicPointers ; UnownPicPointers
+ ld a, [wCurPartySpecies]
+ ld d, BANK(PokemonPicPointers)
+ cp UNOWN
+ jr nz, .ok
+ ld a, [wUnownLetter]
+ ld d, BANK(UnownPicPointers)
+.ok
+ dec a
+ ld bc, 6
+ call AddNTimes
+ ld bc, 3
+ add hl, bc
+ ld a, d
+ call GetFarByte
+ call FixPicBank
+ push af
+ inc hl
+ ld a, d
+ call GetFarByte
+ push af
+ inc hl
+ ld a, d
+ call GetFarByte
+ ld h, a
+ pop af
+ ld l, a
+ ld de, sDecompressBuffer
+ pop af
+ call FarDecompress
+ ld hl, sDecompressBuffer
+ ld c, 6 * 6
+ call FixBackpicAlignment
+ pop hl
+ ld de, sDecompressBuffer
+ ldh a, [hROMBank]
+ ld b, a
+ call Get2bpp
+ call CloseSRAM
+ ret
+
+FixPicBank:
+; Precondition: a = defined bank for pic
+; Postcondition: a = repaired bank for pic
+;
+; Pic bank values that will get repaired (and what they'll be repaired to):
+; $13 -> $1f
+; $14 -> $20
+; $1f -> $2e
+;
+; Otherwise, the repaired bank will match the defined bank.
+ push hl
+ push bc
+ ld b, a
+ ld hl, .FixPicBankTable
+.loop
+ ld a, [hli]
+ cp -1
+ jr z, .done
+ inc hl
+ cp b
+ jr nz, .loop
+ dec hl
+ ld b, [hl]
+
+.done
+ ld a, b
+ pop bc
+ pop hl
+ ret
+
+.FixPicBankTable:
+ db $13, $1f
+ db $14, $20
+ db $1f, $2e
+ db -1
+
+Function1587f:
+ ld a, c
+ push de
+ ld hl, PokemonPicPointers
+ dec a
+ ld bc, 6
+ call AddNTimes
+ ld a, BANK(PokemonPicPointers)
+ call GetFarByte
+ call FixPicBank
+ push af
+ inc hl
+ ld a, BANK(PokemonPicPointers)
+ call GetFarHalfword
+ pop af
+ pop de
+ call FarDecompress
+ ret
+
+GetTrainerPic:
+ ld a, [wTrainerClass]
+ and a
+ ret z
+ cp NUM_TRAINER_CLASSES
+ ret nc
+ ld a, 0
+ call WaitBGMap
+ xor a
+ ldh [hBGMapMode], a
+ ld a, BANK(sDecompressBuffer)
+ call OpenSRAM
+ push de
+ ld hl, TrainerPicPointers
+ ld a, [wTrainerClass]
+ dec a
+ ld bc, 3
+ call AddNTimes
+ ld a, BANK(TrainerPicPointers)
+ call GetFarByte
+ call FixPicBank
+ push af
+ inc hl
+ ld a, BANK(TrainerPicPointers)
+ call GetFarByte
+ push af
+ inc hl
+ ld a, BANK(TrainerPicPointers)
+ call GetFarByte
+ ld h, a
+ pop af
+ ld l, a
+ ld de, sDecompressBuffer
+ pop af
+ call FarDecompress
+ pop hl
+ ld de, sDecompressBuffer
+ ld c, 7 * 7
+ ldh a, [hROMBank]
+ ld b, a
+ call Get2bpp
+ call CloseSRAM
+ call WaitBGMap
+ ld a, 1
+ ldh [hBGMapMode], a
+ ret
+
+DecompressGet2bpp:
+ push de
+ push bc
+ ld a, BANK(sDecompressBuffer)
+ call OpenSRAM
+ ld a, b
+ ld de, sDecompressBuffer
+ call FarDecompress
+ pop bc
+ ld de, sDecompressBuffer
+ pop hl
+ ldh a, [hROMBank]
+ ld b, a
+ call Get2bpp
+ call CloseSRAM
+ ret
+
+FixBackpicAlignment:
+ push de
+ push bc
+ ld a, [wBoxAlignment]
+ and a
+ jr z, .keep_dims
+ ld a, c
+ cp 7 * 7
+ ld de, 7 * 7 tiles
+ jr z, .got_dims
+ cp 6 * 6
+ ld de, 6 * 6 tiles
+ jr z, .got_dims
+ ld de, 5 * 5 tiles
+
+.got_dims
+ ld a, [hl]
+ ld b, 0
+ ld c, 8
+.loop
+ rra
+ rl b
+ dec c
+ jr nz, .loop
+ ld a, b
+ ld [hli], a
+ dec de
+ ld a, e
+ or d
+ jr nz, .got_dims
+
+.keep_dims
+ pop bc
+ pop de
+ ret
+
+PadFrontpic:
+; pads frontpic to fill 7x7 box
+ ld a, b
+ cp 6
+ jr z, .six
+ cp 5
+ jr z, .five
+
+.seven_loop
+ ld c, 7 << 4
+ call LoadOrientedFrontpic
+ dec b
+ jr nz, .seven_loop
+ ret
+
+.six
+ ld c, 7 << 4
+ xor a
+ call .Fill
+.six_loop
+ ld c, (7 - 6) << 4
+ xor a
+ call .Fill
+ ld c, 6 << 4
+ call LoadOrientedFrontpic
+ dec b
+ jr nz, .six_loop
+ ret
+
+.five
+ ld c, 7 << 4
+ xor a
+ call .Fill
+.five_loop
+ ld c, (7 - 5) << 4
+ xor a
+ call .Fill
+ ld c, 5 << 4
+ call LoadOrientedFrontpic
+ dec b
+ jr nz, .five_loop
+ ld c, 7 << 4
+ xor a
+ call .Fill
+ ret
+
+.Fill:
+rept 4
+ srl c
+endr
+.loop
+rept 16
+ ld [hli], a
+endr
+ dec c
+ jr nz, .loop
+ ret
+
+LoadOrientedFrontpic:
+ ld a, [wBoxAlignment]
+ and a
+ jr nz, .x_flip
+rept 4
+ srl c
+endr
+.left_loop
+rept 16
+ ld a, [de]
+ inc de
+ ld [hli], a
+endr
+ dec c
+ jr nz, .left_loop
+ ret
+
+.x_flip
+ push bc
+.right_loop
+ ld a, [de]
+ inc de
+ ld b, a
+ xor a
+rept 8
+ rr b
+ rla
+endr
+ ld [hli], a
+ dec c
+ jr nz, .right_loop
+ pop bc
+ ret
diff --git a/engine/gfx/load_push_oam.asm b/engine/gfx/load_push_oam.asm
new file mode 100644
index 00000000..2e43c1ff
--- /dev/null
+++ b/engine/gfx/load_push_oam.asm
@@ -0,0 +1,21 @@
+WriteOAMDMACodeToHRAM::
+ ld c, LOW(hTransferVirtualOAM)
+ ld b, .PushOAMEnd - .PushOAM
+ ld hl, .PushOAM
+.loop
+ ld a, [hli]
+ ldh [c], a
+ inc c
+ dec b
+ jr nz, .loop
+ ret
+
+.PushOAM:
+ ld a, HIGH(wVirtualOAM)
+ ldh [rDMA], a
+ ld a, NUM_SPRITE_OAM_STRUCTS
+.pushoam_loop
+ dec a
+ jr nz, .pushoam_loop
+ ret
+.PushOAMEnd
diff --git a/engine/gfx/sgb_layouts.asm b/engine/gfx/sgb_layouts.asm
new file mode 100755
index 00000000..db4e929f
--- /dev/null
+++ b/engine/gfx/sgb_layouts.asm
@@ -0,0 +1,577 @@
+LoadSGBLayout:
+ call CheckCGB
+ jp nz, LoadSGBLayoutCGB
+
+ ld a, b
+ cp SCGB_RAM
+ jr nz, .not_ram
+ ld a, [wSGBPredef]
+.not_ram
+ cp SCGB_PARTY_MENU_HP_PALS
+ jp z, SGB_ApplyPartyMenuHPPals
+ ld l, a
+ ld h, 0
+ add hl, hl
+ ld de, .Jumptable
+ add hl, de
+ ld a, [hli]
+ ld h, [hl]
+ ld l, a
+ ld de, _LoadSGBLayout_ReturnFromJumpTable
+ push de
+ jp hl
+
+.Jumptable:
+ dw .SGB_BattleGrayscale
+ dw .SGB_BattleColors
+ dw .SGB_PokegearPals
+ dw .SGB_StatsScreenHPPals
+ dw .SGB_Pokedex
+ dw .SGB_SlotMachine
+ dw .SGB_BetaTitleScreen
+ dw .SGB_GSIntro
+ dw .SGB_Diploma
+ dw .SGB_MapPals
+ dw .SGB_PartyMenu
+ dw .SGB_Evolution
+ dw .SGB_GSTitleScreen
+ dw .SGB0d
+ dw .SGB_MoveList
+ dw .SGB_BetaPikachuMinigame
+ dw .SGB_PokedexSearchOption
+ dw .SGB_BetaPoker
+ dw .SGB_Pokepic
+ dw .SGB_MagnetTrain
+ dw .SGB_PackPals
+ dw .SGB_TrainerCard
+ dw .SGB_PokedexUnownMode
+ dw .SGB_BillsPC
+ dw .SGB_UnownPuzzle
+ dw .SGB_GamefreakLogo
+ dw .SGB_PlayerOrMonFrontpicPals
+ dw .SGB_TradeTube
+ dw .SGB_TrainerOrMonFrontpicPals
+ dw .SGB_MysteryGift
+ dw .SGB1e
+ dw .SGB_Pokedex_5_5
+
+.SGB_BattleGrayscale:
+ ld hl, PalPacket_BattleGrayscale
+ ld de, BlkPacket_Battle
+ ret
+
+.SGB_BattleColors:
+ ld hl, BlkPacket_Battle
+ call PushSGBPals
+
+ ld hl, PalPacket_a155
+ ld de, wSGBPals
+ ld bc, PALPACKET_LENGTH
+ call CopyBytes
+
+ ld a, [wPlayerHPPal]
+ ld l, a
+ ld h, 0
+ add hl, hl
+ add hl, hl
+ ld de, HPBarPals
+ add hl, de
+
+ ld a, [hli]
+ ld [wSGBPals + 3], a
+ ld a, [hli]
+ ld [wSGBPals + 4], a
+ ld a, [hli]
+ ld [wSGBPals + 5], a
+ ld a, [hl]
+ ld [wSGBPals + 6], a
+
+ ld a, [wEnemyHPPal]
+ ld l, a
+ ld h, 0
+ add hl, hl
+ add hl, hl
+
+ ld de, HPBarPals
+ add hl, de
+ ld a, [hli]
+ ld [wSGBPals + 9], a
+ ld a, [hli]
+ ld [wSGBPals + 10], a
+ ld a, [hli]
+ ld [wSGBPals + 11], a
+ ld a, [hl]
+ ld [wSGBPals + 12], a
+
+ ld hl, PalPacket_a165
+ ld de, wSGBPals + PALPACKET_LENGTH
+ ld bc, PALPACKET_LENGTH
+ call CopyBytes
+
+ call GetBattlemonBackpicPalettePointer
+
+ ld a, [hli]
+ ld [wSGBPals + 19], a
+ ld a, [hli]
+ ld [wSGBPals + 20], a
+ ld a, [hli]
+ ld [wSGBPals + 21], a
+ ld a, [hl]
+ ld [wSGBPals + 22], a
+ call GetEnemyFrontpicPalettePointer
+ ld a, [hli]
+ ld [wSGBPals + 25], a
+ ld a, [hli]
+ ld [wSGBPals + 26], a
+ ld a, [hli]
+ ld [wSGBPals + 27], a
+ ld a, [hl]
+ ld [wSGBPals + 28], a
+
+ ld hl, wSGBPals
+ ld de, wSGBPals + PALPACKET_LENGTH
+ ld a, SCGB_BATTLE_COLORS
+ ld [wSGBPredef], a
+ ret
+
+.SGB_MoveList:
+ ld hl, PalPacket_a045
+ ld de, wSGBPals
+ ld bc, PALPACKET_LENGTH
+ call CopyBytes
+
+ ld hl, wSGBPals + 1
+ ld [hl], $10
+ inc hl
+ inc hl
+
+ ld a, [wPlayerHPPal]
+ add PREDEFPAL_HP_GREEN
+ ld [hl], a
+ ld hl, wSGBPals
+ ld de, BlkPacket_MoveList
+ ret
+
+.SGB_PokegearPals:
+ ld hl, PalPacket_Pokegear
+ ld de, BlkPacket_9ee5
+ ret
+
+.SGB_StatsScreenHPPals:
+ ld hl, PalPacket_a155
+ ld de, wSGBPals
+ ld bc, PALPACKET_LENGTH
+ call CopyBytes
+ ld a, [wCurHPPal]
+ ld l, a
+ ld h, 0
+ add hl, hl
+ add hl, hl
+ ld de, HPBarPals
+ add hl, de
+ ld a, [hli]
+ ld [wSGBPals + 3], a
+ ld a, [hli]
+ ld [wSGBPals + 4], a
+ ld a, [hli]
+ ld [wSGBPals + 5], a
+ ld a, [hl]
+ ld [wSGBPals + 6], a
+ ld a, [wCurPartySpecies]
+ ld bc, wTempMonDVs
+ call GetPlayerOrMonPalettePointer
+ ld a, [hli]
+ ld [wSGBPals + 9], a
+ ld a, [hli]
+ ld [wSGBPals + 10], a
+ ld a, [hli]
+ ld [wSGBPals + 11], a
+ ld a, [hl]
+ ld [wSGBPals + 12], a
+ ld hl, wSGBPals
+ ld de, BlkPacket_StatsScreen
+ ret
+
+.SGB_PartyMenu:
+ ld hl, PalPacket_PartyMenu
+ ld de, wSGBPals + 1
+ ret
+
+.SGB_Pokedex:
+ ld hl, PalPacket_a155
+ ld de, wSGBPals
+ ld bc, PALPACKET_LENGTH
+ call CopyBytes
+ ld hl, wSGBPals + 3
+ ld [hl], LOW(palred 31 + palgreen 20 + palblue 10)
+ inc hl
+ ld [hl], HIGH(palred 31 + palgreen 20 + palblue 10)
+ inc hl
+ ld [hl], LOW(palred 26 + palgreen 10 + palblue 6)
+ inc hl
+ ld [hl], HIGH(palred 26 + palgreen 10 + palblue 6)
+ ld a, [wCurPartySpecies]
+ call GetMonPalettePointer
+ ld a, [hli]
+ ld [wSGBPals + 9], a
+ ld a, [hli]
+ ld [wSGBPals + 10], a
+ ld a, [hli]
+ ld [wSGBPals + 11], a
+ ld a, [hl]
+ ld [wSGBPals + 12], a
+ ld hl, wSGBPals
+ ld de, BlkPacket_Pokedex_PC
+ ret
+
+.SGB_Pokedex_5_5:
+ call .SGB_Pokedex
+ ld de, BlkPacket_9f65
+ ret
+
+.SGB_BillsPC:
+ ld hl, PalPacket_a155
+ ld de, wSGBPals
+ ld bc, PALPACKET_LENGTH
+ call CopyBytes
+ ld hl, wSGBPals + 3
+ ld [hl], LOW(palred 31 + palgreen 20 + palblue 10)
+ inc hl
+ ld [hl], HIGH(palred 31 + palgreen 20 + palblue 10)
+ inc hl
+ ld [hl], LOW(palred 26 + palgreen 10 + palblue 6)
+ inc hl
+ ld [hl], HIGH(palred 26 + palgreen 10 + palblue 6)
+ ld a, [wCurPartySpecies]
+ ld bc, wTempMonDVs
+ call GetPlayerOrMonPalettePointer
+ ld a, [hli]
+ ld [wSGBPals + 9], a
+ ld a, [hli]
+ ld [wSGBPals + 10], a
+ ld a, [hli]
+ ld [wSGBPals + 11], a
+ ld a, [hl]
+ ld [wSGBPals + 12], a
+ ld hl, wSGBPals
+ ld de, BlkPacket_9f55
+ ret
+
+.SGB_PokedexUnownMode:
+ call .SGB_Pokedex
+ ld de, BlkPacket_PokedexUnownMode
+ ret
+
+.SGB_PokedexSearchOption:
+ ld hl, PalPacket_a155
+ ld de, wSGBPals
+ ld bc, PALPACKET_LENGTH
+ call CopyBytes
+ ld hl, wSGBPals + 3
+ ld [hl], LOW(palred 31 + palgreen 20 + palblue 10)
+ inc hl
+ ld [hl], HIGH(palred 31 + palgreen 20 + palblue 10)
+ inc hl
+ ld [hl], LOW(palred 26 + palgreen 10 + palblue 6)
+ inc hl
+ ld [hl], HIGH(palred 26 + palgreen 10 + palblue 6)
+ ld hl, wSGBPals
+ ld de, BlkPacket_9ee5
+ ret
+
+.SGB_PackPals:
+ ld hl, PalPacket_Pack
+ ld de, BlkPacket_9ee5
+ ret
+
+.SGB_SlotMachine:
+ ld hl, PalPacket_SlotMachine
+ ld de, BlkPacket_SlotMachine
+ ret
+
+.SGB_BetaTitleScreen:
+ ld hl, PalPacket_BetaTitleScreen
+ ld de, BlkPacket_BetaTitleScreen
+ ret
+
+.SGB_Diploma:
+.SGB_MysteryGift:
+ ld hl, PalPacket_Diploma
+ ld de, BlkPacket_9ee5
+ ret
+
+.SGB_GSIntro:
+ ld b, 0
+ ld hl, .BlkPacketTable_GSIntro
+rept 4
+ add hl, bc
+endr
+ ld e, [hl]
+ inc hl
+ ld d, [hl]
+ inc hl
+ ld a, [hli]
+ ld h, [hl]
+ ld l, a
+ ret
+
+.BlkPacketTable_GSIntro:
+ dw BlkPacket_9ee5, PalPacket_GSIntroShellderLapras
+ dw BlkPacket_GSIntroJigglypuffPikachu, PalPacket_GSIntroJigglypuffPikachu
+ dw BlkPacket_9ee5, PalPacket_GSIntroStartersTransition
+
+.SGB_GSTitleScreen:
+ ld hl, PalPacket_GSTitleScreen
+ ld de, BlkPacket_GSTitleScreen
+ ld a, SCGB_DIPLOMA
+ ld [wSGBPredef], a
+ ret
+
+.SGB_MagnetTrain:
+ ld hl, PalPacket_MagnetTrain
+ ld de, BlkPacket_MagnetTrain
+ ret
+
+.SGB_BetaPikachuMinigame:
+ ld hl, PalPacket_BetaPikachuMinigame
+ ld de, BlkPacket_9ee5
+ ret
+
+.SGB_BetaPoker:
+ ld hl, BlkPacket_9ee5
+ ld de, wc602
+ ld bc, PALPACKET_LENGTH
+ call CopyBytes
+ ld hl, PalPacket_BetaPoker
+ ld de, BlkPacket_9ee5
+ ret
+
+.SGB_MapPals:
+ ld hl, PalPacket_a045
+ ld de, wSGBPals
+ ld bc, PALPACKET_LENGTH
+ call CopyBytes
+ call .GetMapPalsIndex
+ ld hl, wSGBPals + 1
+ ld [hld], a
+ ld de, BlkPacket_9ee5
+ ld a, SCGB_MAPPALS
+ ld [wSGBPredef], a
+ ret
+
+.SGB_Evolution:
+ push bc
+ ld hl, PalPacket_a155
+ ld de, wSGBPals
+ ld bc, PALPACKET_LENGTH
+ call CopyBytes
+ pop bc
+ ld a, c
+ and a
+ jr z, .partymon
+ ; Egg
+ ld hl, wSGBPals + 3
+ ld [hl], LOW(palred 7 + palgreen 7 + palblue 7)
+ inc hl
+ ld [hl], HIGH(palred 7 + palgreen 7 + palblue 7)
+ inc hl
+ ld [hl], LOW(palred 2 + palgreen 3 + palblue 3)
+ inc hl
+ ld [hl], HIGH(palred 2 + palgreen 3 + palblue 3)
+ jr .done
+
+.partymon
+ ld hl, wPartyMon1DVs
+ ld bc, PARTYMON_STRUCT_LENGTH
+ ld a, [wCurPartyMon]
+ call AddNTimes
+ ld c, l
+ ld b, h
+ ld a, [wPlayerHPPal]
+ call GetPlayerOrMonPalettePointer
+ ld a, [hli]
+ ld [wSGBPals + 3], a
+ ld a, [hli]
+ ld [wSGBPals + 4], a
+ ld a, [hli]
+ ld [wSGBPals + 5], a
+ ld a, [hl]
+ ld [wSGBPals + 6], a
+
+.done
+ ld hl, wSGBPals
+ ld de, BlkPacket_9ee5
+ ret
+
+.SGB0d:
+.SGB_TrainerCard:
+ ld hl, PalPacket_Diploma
+ ld de, BlkPacket_9ee5
+ ret
+
+.SGB_UnownPuzzle:
+ ld hl, PalPacket_UnownPuzzle
+ ld de, BlkPacket_9ee5
+ ret
+
+.SGB_Pokepic:
+ ld hl, PalPacket_a045
+ ld de, wSGBPals
+ ld bc, PALPACKET_LENGTH
+ call CopyBytes
+ ld hl, BlkPacket_9ee5
+ ld de, wSGBPals + PALPACKET_LENGTH
+ ld bc, PALPACKET_LENGTH
+ call CopyBytes
+ call .GetMapPalsIndex
+ ld hl, wSGBPals + 1
+ ld [hl], a
+ ld hl, wSGBPals + 3
+ ld [hl], $2e
+ ld hl, wSGBPals + $13
+ ld a, 5
+ ld [hli], a
+ ld a, [wMenuBorderLeftCoord]
+ ld [hli], a
+ ld a, [wMenuBorderTopCoord]
+ ld [hli], a
+ ld a, [wMenuBorderRightCoord]
+ ld [hli], a
+ ld a, [wMenuBorderBottomCoord]
+ ld [hl], a
+ ld hl, wSGBPals
+ ld de, wSGBPals + PALPACKET_LENGTH
+ ret
+
+.SGB1e:
+ ld hl, PalPacket_a155
+ ld de, wSGBPals
+ ld bc, PALPACKET_LENGTH
+ call CopyBytes
+ ld a, [wCurPartySpecies]
+ ld l, a
+ ld h, 0
+ add hl, hl
+ add hl, hl
+ add hl, hl
+ ld de, PokemonPalettes
+ add hl, de
+ ld a, [wce65]
+ and 3
+ sla a
+ sla a
+ ld c, a
+ ld b, 0
+ add hl, bc
+ ld a, [hli]
+ ld [wSGBPals + 3], a
+ ld a, [hli]
+ ld [wSGBPals + 4], a
+ ld a, [hli]
+ ld [wSGBPals + 5], a
+ ld a, [hl]
+ ld [wSGBPals + 6], a
+ ld hl, wSGBPals
+ ld de, BlkPacket_9ee5
+ ret
+
+.SGB_GamefreakLogo:
+ ld hl, PalPacket_GamefreakLogo
+ ld de, BlkPacket_9ee5
+ ret
+
+.SGB_PlayerOrMonFrontpicPals:
+ ld hl, PalPacket_a155
+ ld de, wSGBPals
+ ld bc, PALPACKET_LENGTH
+ call CopyBytes
+ ld a, [wCurPartySpecies]
+ ld bc, wTempMonDVs
+ call GetPlayerOrMonPalettePointer
+ ld a, [hli]
+ ld [wSGBPals + 3], a
+ ld a, [hli]
+ ld [wSGBPals + 4], a
+ ld a, [hli]
+ ld [wSGBPals + 5], a
+ ld a, [hl]
+ ld [wSGBPals + 6], a
+ ld hl, wSGBPals
+ ld de, BlkPacket_9ee5
+ ret
+
+.SGB_TradeTube:
+ ld hl, PalPacket_TradeTube
+ ld de, BlkPacket_9ee5
+ ret
+
+.SGB_TrainerOrMonFrontpicPals:
+ ld hl, PalPacket_a155
+ ld de, wSGBPals
+ ld bc, PALPACKET_LENGTH
+ call CopyBytes
+ ld a, [wCurPartySpecies]
+ ld bc, wTempMonDVs
+ call GetFrontpicPalettePointer
+ ld a, [hli]
+ ld [wSGBPals + 3], a
+ ld a, [hli]
+ ld [wSGBPals + 4], a
+ ld a, [hli]
+ ld [wSGBPals + 5], a
+ ld a, [hl]
+ ld [wSGBPals + 6], a
+ ld hl, wSGBPals
+ ld de, BlkPacket_9ee5
+ ret
+
+.GetMapPalsIndex:
+ ld a, [wTimeOfDayPal]
+ cp NITE_F
+ jr c, .morn_day
+ ld a, PREDEFPAL_NITE
+ ret
+
+.morn_day
+ ld a, [wEnvironment]
+ cp ROUTE
+ jr z, .route
+ cp CAVE
+ jr z, .cave
+ cp DUNGEON
+ jr z, .cave
+ cp ENVIRONMENT_5
+ jr z, .env5
+ cp GATE
+ jr z, .gate
+ ld a, [wMapGroup]
+ ld e, a
+ ld d, 0
+ ld hl, MapGroupRoofSGBPalInds
+ add hl, de
+ ld a, [hl]
+ ret
+
+.route
+ ld a, PREDEFPAL_ROUTES
+ ret
+
+.cave
+ ld a, PREDEFPAL_DUNGEONS
+ ret
+
+.env5
+ ld a, PREDEFPAL_VERMILION
+ ret
+
+.gate
+ ld a, PREDEFPAL_PEWTER
+ ret
+
+INCLUDE "data/maps/sgb_roof_pal_inds.asm"
+
+_LoadSGBLayout_ReturnFromJumpTable:
+ push de
+ call PushSGBPals
+ pop hl
+ jp PushSGBPals
diff --git a/engine/sprite_anims.asm b/engine/gfx/sprite_anims.asm
index 2877539d..2877539d 100755
--- a/engine/sprite_anims.asm
+++ b/engine/gfx/sprite_anims.asm
diff --git a/engine/sprites.asm b/engine/gfx/sprites.asm
index b9267d66..b9267d66 100755
--- a/engine/sprites.asm
+++ b/engine/gfx/sprites.asm
diff --git a/engine/items.asm b/engine/items.asm
deleted file mode 100755
index deafa60c..00000000
--- a/engine/items.asm
+++ /dev/null
@@ -1,551 +0,0 @@
-_ReceiveItem:: ; d1e2 (3:51e2)
- call CheckBagOrPC
- jp nz, PutItemInPocketOrPC
- push hl
- call CheckItemPocket
- pop de
- ld a, [wItemAttributeParamBuffer]
- dec a
- ld hl, .Jumptable
- rst JumpTable
- ret
-
-.Jumptable
- dw ReceiveNormalItem
- dw ReceiveKeyItem
- dw ReceiveBall
- dw ReceiveTMHM
-
-ReceiveNormalItem:
- ld h, d
- ld l, e
- jp PutItemInPocketOrPC
-
-ReceiveKeyItem:
- ld h, d
- ld l, e
- jp PutItemInKeyItemPocket
-
-ReceiveBall:
- ld hl, wNumBalls
- jp PutItemInPocketOrPC
-
-ReceiveTMHM:
- ld h, d
- ld l, e
- ld a, [wd002]
- ld c, a
- call GetTMHMNumber
- jp PutItemInTMPocket
-
-_TossItem:: ; d21a (3:521a)
- call CheckBagOrPC
- jr nz, remove_item_from_bag_or_pc
- push hl
- call CheckItemPocket
- pop de
- ld a, [wItemAttributeParamBuffer]
- dec a
- ld hl, .Jumptable ; $522d
- rst JumpTable
- ret
-
-.Jumptable
- dw RemoveNormalItem
- dw RemoveKeyItem
- dw RemoveBall
- dw RemoveTMHM
-
-RemoveBall:
- ld hl, wNumBalls
- jp RemoveItemAndQuantity
-
-RemoveTMHM:
- ld h, d
- ld l, e
- ld a, [wd002]
- ld c, a
- call GetTMHMNumber
- jp RemoveTMorHM
-
-RemoveKeyItem:
- ld h, d
- ld l, e
- jp RemoveItemWithoutQuantity
-
-RemoveNormalItem:
- ld h, d
- ld l, e
-remove_item_from_bag_or_pc
- jp RemoveItemAndQuantity
-
-_CheckItem:: ; d251 (3:5251)
- call CheckBagOrPC
- jr nz, check_item_in_bag_or_pc
- push hl
- call CheckItemPocket
- pop de
- ld a, [wItemAttributeParamBuffer]
- dec a
- ld hl, .Jumptable
- rst JumpTable
- ret
-
-.Jumptable
- dw CheckNormalItem
- dw CheckKeyItem
- dw CheckBall
- dw CheckTMHM
-
-CheckBall:
- ld hl, wNumBalls
- jp CheckItemWithQuantity
-
-CheckTMHM:
- ld h, d
- ld l, e
- ld a, [wd002]
- ld c, a
- call GetTMHMNumber
- jp CheckTMorHM
-
-CheckKeyItem:
- ld h, d
- ld l, e
- jp CheckItemWithoutQuantity
-
-CheckNormalItem:
- ld h, d
- ld l, e
-check_item_in_bag_or_pc
- jp CheckItemWithQuantity
-
-CheckBagOrPC: ; d288 (3:5288)
- ld a, l
- cp wNumItems % $100
- ret nz
- ld a, h
- cp wNumItems / $100
- ret
-
-GetPocketCapacity: ; d290 (3:5290)
- ld c, MAX_ITEMS
- ld a, e
- cp wNumItems % $100
- jr nz, .asm_d29b
- ld a, d
- cp wNumItems / $100
- ret z
-.asm_d29b
- ld c, MAX_PC_ITEMS
- ld a, e
- cp wPCItems % $100
- jr nz, .asm_d2a6
- ld a, d
- cp wPCItems / $100
- ret z
-.asm_d2a6
- ld c, MAX_BALLS
- ret
-
-PutItemInPocketOrPC: ; d2a9 (3:52a9)
- ld d, h
- ld e, l
- inc hl
- ld a, [wd002]
- ld c, a
- ld b, $0
-.asm_d2b2
- ld a, [hli]
- cp $ff
- jr z, .asm_d2ca
- cp c
- jr nz, .asm_d2c7
- ld a, $63
- sub [hl]
- add b
- ld b, a
- ld a, [wItemQuantityChangeBuffer]
- cp b
- jr z, .asm_d2d3
- jr c, .asm_d2d3
-.asm_d2c7
- inc hl
- jr .asm_d2b2
-
-.asm_d2ca
- call GetPocketCapacity
- ld a, [de]
- cp c
- jr c, .asm_d2d3
- and a
- ret
-
-.asm_d2d3
- ld h, d
- ld l, e
- ld a, [wd002]
- ld c, a
- ld a, [wItemQuantityChangeBuffer]
- ld [wItemQuantityBuffer], a
-.asm_d2df
- inc hl
- ld a, [hli]
- cp $ff
- jr z, .asm_d2fc
- cp c
- jr nz, .asm_d2df
- ld a, [wItemQuantityBuffer]
- add [hl]
- cp $64
- jr nc, .asm_d2f3
- ld [hl], a
- jr .asm_d30a
-
-.asm_d2f3
- ld [hl], $63
- sub $63
- ld [wItemQuantityBuffer], a
- jr .asm_d2df
-
-.asm_d2fc
- dec hl
- ld a, [wd002]
- ld [hli], a
- ld a, [wItemQuantityBuffer]
- ld [hli], a
- ld [hl], $ff
- ld h, d
- ld l, e
- inc [hl]
-.asm_d30a
- scf
- ret
-
-RemoveItemAndQuantity: ; d30c (3:530c)
- ld d, h
- ld e, l
- ld a, [hli]
- ld c, a
- ld a, [wd003]
- cp c
- jr nc, .asm_d325
- ld c, a
- ld b, $0
- add hl, bc
- add hl, bc
- ld a, [wd002]
- cp [hl]
- inc hl
- jr z, .asm_d334
- ld h, d
- ld l, e
- inc hl
-.asm_d325
- ld a, [wd002]
- ld b, a
-.asm_d329
- ld a, [hli]
- cp b
- jr z, .asm_d334
- cp $ff
- jr z, .asm_d354
- inc hl
- jr .asm_d329
-
-.asm_d334
- ld a, [wItemQuantityChangeBuffer]
- ld b, a
- ld a, [hl]
- sub b
- jr c, .asm_d354
- ld [hl], a
- ld [wItemQuantityBuffer], a
- and a
- jr nz, .asm_d352
- dec hl
- ld b, h
- ld c, l
- inc hl
- inc hl
-.asm_d348
- ld a, [hli]
- ld [bc], a
- inc bc
- cp $ff
- jr nz, .asm_d348
- ld h, d
- ld l, e
- dec [hl]
-.asm_d352
- scf
- ret
-
-.asm_d354
- and a
- ret
-
-CheckItemWithQuantity: ; d356 (3:5356)
- ld a, [wd002]
- ld c, a
-.asm_d35a
- inc hl
- ld a, [hli]
- cp $ff
- jr z, .asm_d365
- cp c
- jr nz, .asm_d35a
- scf
- ret
-
-.asm_d365
- and a
- ret
-
-PutItemInKeyItemPocket: ; d367 (3:5367)
- ld hl, wItemsEnd
- ld a, [hli]
- cp $19
- jr nc, .asm_d37f
- ld c, a
- ld b, $0
- add hl, bc
- ld a, [wd002]
- ld [hli], a
- ld [hl], $ff
- ld hl, wNumKeyItems
- inc [hl]
- scf
- ret
-
-.asm_d37f
- and a
- ret
-
-RemoveItemWithoutQuantity: ; d381 (3:5381)
- ld a, [wd003]
- ld e, a
- ld d, $0
- ld hl, wItemsEnd
- ld a, [hl]
- cp e
- jr nc, .asm_d394
- call FindAndTossKeyItem
- ret nc
- jr .asm_d397
-
-.asm_d394
- dec [hl]
- inc hl
- add hl, de
-.asm_d397
- ld d, h
- ld e, l
- inc hl
-.asm_d39a
- ld a, [hli]
- ld [de], a
- inc de
- cp $ff
- jr nz, .asm_d39a
- scf
- ret
-
-FindAndTossKeyItem: ; d3a3 (3:53a3)
- ld hl, wItemsEnd
- ld a, [wd002]
- ld c, a
-.asm_d3aa
- inc hl
- ld a, [hl]
- cp c
- jr z, .asm_d3b5
- cp $ff
- jr nz, .asm_d3aa
- xor a
- ret
-
-.asm_d3b5
- ld a, [wNumKeyItems]
- dec a
- ld [wNumKeyItems], a
- scf
- ret
-
-CheckItemWithoutQuantity: ; d3be (3:53be)
- ld a, [wd002]
- ld c, a
- ld hl, wKeyItems
-.asm_d3c5
- ld a, [hli]
- cp c
- jr z, .asm_d3cf
- cp $ff
- jr nz, .asm_d3c5
- and a
- ret
-
-.asm_d3cf
- scf
- ret
-
-PutItemInTMPocket: ; d3d1 (3:53d1)
- dec c
- ld b, $0
- ld hl, wTMsHMs
- add hl, bc
- ld a, [wItemQuantityChangeBuffer]
- add [hl]
- cp $64
- jr nc, .asm_d3e3
- ld [hl], a
- scf
- ret
-
-.asm_d3e3
- and a
- ret
-
-RemoveTMorHM: ; d3e5 (3:53e5)
- dec c
- ld b, $0
- ld hl, wTMsHMs
- add hl, bc
- ld a, [wItemQuantityChangeBuffer]
- ld b, a
- ld a, [hl]
- sub b
- jr c, .asm_d406
- ld [hl], a
- ld [wItemQuantityBuffer], a
- jr nz, .asm_d404
- ld a, [wcfd2]
- and a
- jr z, .asm_d404
- dec a
- ld [wcfd2], a
-.asm_d404
- scf
- ret
-
-.asm_d406
- and a
- ret
-
-CheckTMorHM: ; d408 (3:5408)
- dec c
- ld b, $0
- ld hl, wTMsHMs
- add hl, bc
- ld a, [hl]
- and a
- ret z
- scf
- ret
-
-GetTMHMNumber:: ; d414 (3:5414)
- ld a, c
- cp ITEM_C3
- jr c, .asm_d41f
- cp ITEM_DC
- jr c, .asm_d41e
- dec a
-.asm_d41e
- dec a
-.asm_d41f
- sub $bf
- inc a
- ld c, a
- ret
-
-GetNumberedTM:
- ld a, c
- cp ITEM_C3 - (TM01 - 1)
- jr c, .asm_d42f
- cp ITEM_DC - (TM01 - 1) - 1
- jr c, .asm_d42e
- inc a
-.asm_d42e
- inc a
-.asm_d42f
- add TM01
- dec a
- ld c, a
- ret
-
-_CheckTossableItem:: ; d434 (3:5434)
- ld a, $4
- call GetItemAttr
- bit 7, a
- jr nz, ItemAttr_ReturnCarry
- and a
- ret
-
-CheckSelectableItem:
- ld a, $4
- call GetItemAttr
- bit 6, a
- jr nz, ItemAttr_ReturnCarry
- and a
- ret
-
-CheckItemPocket: ; d44a (3:544a)
- ld a, $5
- call GetItemAttr
- and $f
- ld [wItemAttributeParamBuffer], a
- ret
-
-CheckItemContext:
- ld a, $6
- call GetItemAttr
- and $f
- ld [wItemAttributeParamBuffer], a
- ret
-
-CheckItemMenu:
- ld a, $6
- call GetItemAttr
- swap a
- and $f
- ld [wItemAttributeParamBuffer], a
- ret
-
-GetItemAttr: ; d46d (3:546d)
- push hl
- push bc
- ld hl, ItemAttributes
- ld c, a
- ld b, $0
- add hl, bc
- xor a
- ld [wItemAttributeParamBuffer], a
- ld a, [wd002]
- dec a
- ld c, a
- ld a, $7
- call AddNTimes
- ld a, BANK(ItemAttributes)
- call GetFarByte
- pop bc
- pop hl
- ret
-
-ItemAttr_ReturnCarry
- ld a, $1
- ld [wItemAttributeParamBuffer], a
- scf
- ret
-
-GetItemPrice:
- push hl
- push bc
- ld a, $0
- call GetItemAttr
- ld e, a
- ld a, $1
- call GetItemAttr
- ld d, a
- pop bc
- pop hl
- ret
diff --git a/engine/items/buy_sell_toss.asm b/engine/items/buy_sell_toss.asm
new file mode 100644
index 00000000..45c3dfcf
--- /dev/null
+++ b/engine/items/buy_sell_toss.asm
@@ -0,0 +1,218 @@
+SelectQuantityToToss:
+ ld hl, TossItem_MenuHeader
+ call LoadMenuHeader
+ call Toss_Sell_Loop
+ ret
+
+SelectQuantityToBuy:
+ farcall GetItemPrice
+ 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
+ push de
+ ret
+
+ret_24ff3:
+ ret
+
+DisplayPurchasePrice:
+ call BuySell_MultiplyPrice
+ call BuySell_DisplaySubtotal
+ ret
+
+DisplaySellingPrice:
+ call BuySell_MultiplyPrice
+ call Sell_HalvePrice
+ call BuySell_DisplaySubtotal
+ ret
+
+BuySell_MultiplyPrice:
+ xor a
+ ldh [hMultiplicand + 0], a
+ ld a, [wBuffer1]
+ ldh [hMultiplicand + 1], a
+ ld a, [wBuffer2]
+ ldh [hMultiplicand + 2], a
+ ld a, [wItemQuantityChangeBuffer]
+ ldh [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
+ ldh a, [hProduct + 1]
+ ld [hli], a
+ ldh a, [hProduct + 2]
+ ld [hli], a
+ ldh 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_24ff3
+ 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 100755
index 00000000..35a7cd6c
--- /dev/null
+++ b/engine/items/item_effects.asm
@@ -0,0 +1,2891 @@
+_DoItemEffect::
+ ld a, [wCurItem]
+ ld [wNamedObjectIndexBuffer], 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 ; ITEM_46
+ 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_I
+ 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 ; ITEM_73
+ dw NoEffect ; ITEM_74
+ 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 ; ITEM_81
+ 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 OpenSRAM
+ 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, ItemUsedText
+ 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
+ ldh [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
+ ldh [hMultiplier], a
+ xor a
+ ldh [hDividend + 0], a
+ ldh [hMultiplicand + 0], a
+ ldh [hMultiplicand + 1], a
+ call Multiply
+ pop bc
+
+ ld a, b
+ ldh [hDivisor], a
+ ld b, 4
+ call Divide
+
+ ldh a, [hQuotient + 3]
+ 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
+ ldh [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, BallBrokeFreeText
+ jp z, .shake_and_break_free
+ cp $2
+ ld hl, BallAppearedCaughtText
+ jp z, .shake_and_break_free
+ cp $3
+ ld hl, BallAlmostHadItText
+ jp z, .shake_and_break_free
+ cp $4
+ ld hl, BallSoCloseText
+ 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 [wTempSpecies], a
+ ld a, [wBattleType]
+ cp BATTLETYPE_TUTORIAL
+ jp z, .FinishTutorial
+
+ ld hl, Text_GotchaMonWasCaught
+ call PrintText
+
+ call ClearSprites
+
+ ld a, [wTempSpecies]
+ dec a
+ call CheckCaughtMon
+
+ ld a, c
+ push af
+ ld a, [wTempSpecies]
+ dec a
+ call SetSeenAndCaughtMon
+ pop af
+ and a
+ jr nz, .skip_pokedex
+
+ call CheckReceivedDex
+ jr z, .skip_pokedex
+
+ ld hl, NewDexDataText
+ call PrintText
+
+ call ClearSprites
+
+ ld a, [wEnemyMonSpecies]
+ ld [wTempSpecies], a
+ predef NewPokedexEntry
+
+.skip_pokedex
+ ld a, [wBattleType]
+ cp BATTLETYPE_CONTEST
+ jp z, .catch_bug_contest_mon
+ ld a, [wPartyCount]
+ cp PARTY_LENGTH
+ jr z, .SendToPC
+
+ xor a ; PARTYMON
+ ld [wMonType], a
+ call ClearSprites
+
+ predef TryAddMonToParty
+
+ 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, AskGiveNicknameText
+ call PrintText
+
+ ld a, [wCurPartySpecies]
+ ld [wNamedObjectIndexBuffer], 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, NAME_MON
+ farcall NamingScreen
+
+ call RotateThreePalettesRight
+
+ call LoadStandardFont
+
+ pop hl
+ ld de, wStringBuffer1
+ call InitName
+
+ jp .return_from_capture
+
+.SendToPC:
+ call ClearSprites
+
+ predef SendMonIntoBox
+
+ ld a, BANK(sBoxCount)
+ call OpenSRAM
+
+ 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, AskGiveNicknameText
+ call PrintText
+
+ ld a, [wCurPartySpecies]
+ ld [wNamedObjectIndexBuffer], a
+ call GetPokemonName
+
+ call YesNoBox
+ jr c, .SkipBoxMonNickname
+
+ xor a
+ ld [wCurPartyMon], a
+ ld a, BOXMON
+ ld [wMonType], a
+ ld de, wMonOrItemNameBuffer
+ ld b, NAME_MON
+ farcall NamingScreen
+
+ ld a, BANK(sBoxMonNicknames)
+ call OpenSRAM
+
+ 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 OpenSRAM
+
+ ld hl, sBoxMonNicknames
+ ld de, wMonOrItemNameBuffer
+ ld bc, MON_NAME_LENGTH
+ call CopyBytes
+
+ call CloseSRAM
+
+ ld hl, BallSentToPCText
+ 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
+
+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]
+ dec a
+ ld hl, PokedexDataPointerTable
+ ld e, a
+ ld d, 0
+ add hl, de
+ add hl, de
+ rlca
+ rlca
+ and %11
+ add BANK("Pokedex Entries 001-064")
+ ld d, a
+ ld a, BANK(PokedexDataPointerTable)
+ call GetFarHalfword
+
+.SkipText:
+ ld a, d
+ call GetFarByte
+ inc hl
+ cp "@"
+ jr nz, .SkipText
+
+ ld a, d
+ 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.
+
+BallDodgedText:
+ text_far _BallDodgedText
+ text_end
+
+BallMissedText:
+ text_far _BallMissedText
+ text_end
+
+BallBrokeFreeText:
+ text_far _BallBrokeFreeText
+ text_end
+
+BallAppearedCaughtText:
+ text_far _BallAppearedCaughtText
+ text_end
+
+BallAlmostHadItText:
+ text_far _BallAlmostHadItText
+ text_end
+
+BallSoCloseText:
+ text_far _BallSoCloseText
+ text_end
+
+Text_GotchaMonWasCaught:
+ ; Gotcha! @ was caught!@ @
+ text_far Text_BallCaught
+ text_asm
+ call WaitSFX
+ push bc
+ ld de, MUSIC_NONE
+ call PlayMusic
+ call DelayFrame
+ ld de, MUSIC_CAPTURE
+ call PlayMusic
+ pop bc
+ ld hl, WaitButtonText
+ ret
+
+WaitButtonText:
+ text_far _WaitButtonText
+ text_end
+
+BallSentToPCText:
+ text_far _BallSentToPCText
+ text_end
+
+NewDexDataText:
+ text_far _NewDexDataText
+ text_end
+
+AskGiveNicknameText:
+ text_far _AskGiveNicknameText
+ text_end
+
+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, ItemStatRoseText
+ call PrintText
+
+ ld c, HAPPINESS_USEDITEM
+ farcall ChangeHappiness
+
+ jp UseDisposableItem
+
+NoEffectMessage:
+ ld hl, ItemWontHaveEffectText
+ 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
+
+ItemStatRoseText:
+ text_far _ItemStatRoseText
+ text_end
+
+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 [wTempSpecies], 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
+
+ ldh a, [hMultiplicand + 0]
+ ld [hli], a
+ ldh a, [hMultiplicand + 1]
+ ld [hli], a
+ ldh 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
+ ld c, 1
+ farcall ChangeHappiness
+
+ 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 [wTempSpecies], 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
+ ldh [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
+ ldh [hBGMapMode], a
+ hlcoord 0, 0
+ ld bc, wTilemapEnd - wTilemap
+ ld a, " "
+ call ByteFill
+ ld a, [wPartyMenuActionText]
+ call ItemActionText
+ ld a, $1
+ ldh [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]
+ ldh [hDividend + 0], a
+ ld a, [hl]
+ ldh [hDividend + 1], a
+ ld a, 5
+ ldh [hDivisor], a
+ ld b, 2
+ call Divide
+ ldh a, [hQuotient + 2]
+ ld d, a
+ ldh a, [hQuotient + 3]
+ 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, .ItemCantUseOnMonText
+ call MenuTextboxBackup
+ pop bc
+ jr .loop
+
+.ItemCantUseOnMonText:
+ text_far _ItemCantUseOnMonText
+ text_end
+
+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, RepelUsedEarlierIsStillInEffectText
+ jp nz, PrintText
+
+ ld a, b
+ ld [wRepelEffect], a
+ jp UseItemText
+
+RepelUsedEarlierIsStillInEffectText:
+ text_far _RepelUsedEarlierIsStillInEffectText
+ text_end
+
+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_f4f6
+ inc a
+ ld [wForcedSwitch], a
+ ; set battle draw
+ inc a
+ ld [wBattleResult], a
+ jp UseItemText
+
+.asm_f4f6
+ 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
+ ldh [hBattleTurn], a
+ ld [wAttackMissed], a
+ ld [wEffectFailed], a
+ farcall RaiseStat
+ 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 [wceed], 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, [wceed]
+ and a
+ ld hl, .PlayedFluteText
+ jp z, PrintText
+ ld hl, .PlayedTheFlute
+ call PrintText
+
+ ld a, [wLowHealthAlarm]
+ and 1 << DANGER_ON_F
+ jr nz, .dummy2
+.dummy2
+ ld hl, .FluteWakeUpText
+ 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 [wceed], a
+.not_asleep
+ pop af
+ and b
+ ld [hl], a
+ add hl, de
+ dec c
+ jr nz, .loop
+ ret
+
+.PlayedFluteText:
+ text_far _PlayedFluteText
+ text_end
+
+.FluteWakeUpText:
+ text_far _FluteWakeUpText
+ text_end
+
+.PlayedTheFlute:
+ ; played the # FLUTE.@ @
+ text_far Text_PlayedPokeFlute
+ text_asm
+ ld a, [wBattleMode]
+ and a
+ jr nz, .battle
+
+ push de
+ ld de, SFX_POKEFLUTE
+ call WaitPlaySFX
+ call WaitSFX
+ pop de
+
+.battle
+ ld hl, .terminator
+ ret
+
+.terminator
+ db "@"
+
+CoinCaseEffect:
+ ld hl, .CoinCaseCountText
+ jp MenuTextboxWaitButton
+
+.CoinCaseCountText:
+ text_far _CoinCaseCountText
+ text_end
+
+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 [wceed], 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, [wceed]
+ cp MAX_ELIXER
+ jp z, Elixer_RestorePPofAllMoves
+ cp ELIXER
+ jp z, Elixer_RestorePPofAllMoves
+
+ ld hl, RaiseThePPOfWhichMoveText
+ ld a, [wceed]
+ cp PP_UP
+ jr z, .ppup
+ ld hl, RestoreThePPOfWhichMoveText
+
+.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 [wNamedObjectIndexBuffer], a
+ call GetMoveName
+ call CopyName1
+ pop hl
+
+ ld a, [wceed]
+ 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, PPIsMaxedOutText
+ call PrintText
+ jr .loop2
+
+.do_ppup
+ ld a, [hl]
+ add PP_UP_ONE
+ ld [hl], a
+ ld a, TRUE
+ ld [wUsePPUp], a
+ call ApplyPPUp
+ call Play_SFX_FULL_HEAL
+
+ ld hl, PPsIncreasedText
+ 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, PPRestoredText
+ 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, [wTempPP]
+ ld b, a
+ ld a, [hl]
+ and PP_MASK
+ cp b
+ jr nc, .dont_restore
+
+ ld a, [wceed]
+ 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
+
+RaiseThePPOfWhichMoveText:
+ text_far _RaiseThePPOfWhichMoveText
+ text_end
+
+RestoreThePPOfWhichMoveText:
+ text_far _RestoreThePPOfWhichMoveText
+ text_end
+
+PPIsMaxedOutText:
+ text_far _PPIsMaxedOutText
+ text_end
+
+PPsIncreasedText:
+ text_far _PPsIncreasedText
+ text_end
+
+PPRestoredText:
+ text_far _PPRestoredText
+ text_end
+
+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, .SentTrophyHomeText
+ call PrintText
+
+ jp UseDisposableItem
+
+.SentTrophyHomeText:
+ text_far _SentTrophyHomeText
+ text_end
+
+NoEffect:
+ jp IsntTheTimeMessage
+
+Play_SFX_FULL_HEAL:
+ push de
+ ld de, SFX_FULL_HEAL
+ call WaitPlaySFX
+ pop de
+ ret
+
+UseItemText:
+ ld hl, ItemUsedText
+ 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
+ ldh [hBattleTurn], a
+ ld [wNumHits], a
+ predef PlayBattleAnim
+ ld hl, BallBlockedText
+ call PrintText
+ ld hl, BallDontBeAThiefText
+ call PrintText
+ jr UseDisposableItem
+
+WontHaveAnyEffect_NotUsedMessage:
+ ld hl, ItemWontHaveEffectText
+ call PrintText
+
+ ; Item wasn't used.
+ ld a, $2
+ ld [wItemEffectSucceeded], a
+ ret
+
+LooksBitterMessage:
+ ld hl, ItemLooksBitterText
+ jp PrintText
+
+Ball_BoxIsFullMessage:
+ ld hl, BallBoxFullText
+ call PrintText
+
+ ; Item wasn't used.
+ ld a, $2
+ ld [wItemEffectSucceeded], a
+ ret
+
+CantUseOnEggMessage:
+ ld hl, ItemCantUseOnEggText
+ jr CantUseItemMessage
+
+IsntTheTimeMessage:
+ ld hl, ItemOakWarningText
+ jr CantUseItemMessage
+
+WontHaveAnyEffectMessage:
+ ld hl, ItemWontHaveEffectText
+ jr CantUseItemMessage
+
+BelongsToSomeoneElseMessage:
+ ld hl, ItemBelongsToSomeoneElseText
+ jr CantUseItemMessage
+
+CyclingIsntAllowedMessage:
+ ld hl, NoCyclingText
+ jr CantUseItemMessage
+
+CantGetOnYourBikeMessage:
+ ld hl, ItemCantGetOnText
+
+CantUseItemMessage:
+; Item couldn't be used.
+ xor a
+ ld [wItemEffectSucceeded], a
+ jp PrintText
+
+ItemLooksBitterText:
+ text_far _ItemLooksBitterText
+ text_end
+
+ItemCantUseOnEggText:
+ text_far _ItemCantUseOnEggText
+ text_end
+
+ItemOakWarningText:
+ text_far _ItemOakWarningText
+ text_end
+
+ItemBelongsToSomeoneElseText:
+ text_far _ItemBelongsToSomeoneElseText
+ text_end
+
+ItemWontHaveEffectText:
+ text_far _ItemWontHaveEffectText
+ text_end
+
+BallBlockedText:
+ text_far _BallBlockedText
+ text_end
+
+BallDontBeAThiefText:
+ text_far _BallDontBeAThiefText
+ text_end
+
+NoCyclingText:
+ text_far _NoCyclingText
+ text_end
+
+ItemCantGetOnText:
+ text_far _ItemCantGetOnText
+ text_end
+
+BallBoxFullText:
+ text_far _BallBoxFullText
+ text_end
+
+ItemUsedText:
+ text_far _ItemUsedText
+ text_end
+
+ItemGotOnText:
+ text_far _ItemGotOnText
+ text_end
+
+ItemGotOffText:
+ text_far _ItemGotOffText
+ text_end
+
+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, [wUsePPUp]
+ dec a ; FALSE?
+ 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]
+ ldh [hDividend + 3], a
+ xor a
+ ldh [hDividend], a
+ ldh [hDividend + 1], a
+ ldh [hDividend + 2], a
+ ld a, 5
+ ldh [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.
+ ldh a, [hQuotient + 3]
+ cp $8
+ jr c, .okay
+ ld a, $7
+
+.okay
+ add b
+ ld b, a
+ ld a, [wTempPP]
+ 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, [wTempPP]
+ 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 [wTempPP], a
+ ld a, b ; this gets lost anyway
+ call ComputeMaxPP
+ ld a, [hl]
+ and PP_MASK
+ ld [wTempPP], 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 100755
index 00000000..ef0f10dd
--- /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(wNumPCItems)
+ jr nz, .not_pc
+ ld a, d
+ cp HIGH(wNumPCItems)
+ 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 00000000..3978ef33
--- /dev/null
+++ b/engine/items/mart.asm
@@ -0,0 +1,811 @@
+ 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
+
+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
+
+OpenMartDialog::
+ call GetMart
+ ld a, c
+ ld [wMartType], a
+ call LoadMartPointer
+ ld a, [wMartType]
+ ld hl, .dialogs
+ rst JumpTable
+ ret
+
+.dialogs
+ dw MartDialog
+ dw HerbShop
+ dw BargainShop
+ dw Pharmacist
+
+MartDialog:
+ ld a, MARTTYPE_STANDARD
+ ld [wMartType], a
+ xor a ; STANDARDMART_HOWMAYIHELPYOU
+ ld [wMartJumptableIndex], a
+ call StandardMart
+ ret
+
+HerbShop:
+ call FarReadMart
+ call LoadStandardMenuHeader
+ ld hl, HerbShopLadyIntroText
+ call MartTextbox
+ call BuyMenu
+ ld hl, HerbalLadyComeAgainText
+ call MartTextbox
+ ret
+
+BargainShop:
+ ld b, BANK(BargainShopData)
+ ld de, BargainShopData
+ call LoadMartPointer
+ call ReadMart
+ call LoadStandardMenuHeader
+ ld hl, BargainShopIntroText
+ call MartTextbox
+ call BuyMenu
+ ld hl, wBargainShopFlags
+ ld a, [hli]
+ or [hl]
+ jr z, .skip_set
+ ld hl, wDailyFlags1
+ set DAILYFLAGS1_GOLDENROD_UNDERGROUND_BARGAIN_F, [hl]
+
+.skip_set
+ ld hl, BargainShopComeAgainText
+ call MartTextbox
+ ret
+
+Pharmacist:
+ call FarReadMart
+ call LoadStandardMenuHeader
+ ld hl, PharmacyIntroText
+ call MartTextbox
+ call BuyMenu
+ ld hl, PharmacyComeAgainText
+ call MartTextbox
+ ret
+
+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 ; STANDARDMART_HOWMAYIHELPYOU
+ ld [wMartJumptableIndex], a
+ ld [wBargainShopFlags], a
+ ld [wFacingDirection], a
+ 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_EXIT EQU -1
+
+StandardMart:
+.loop
+ ld a, [wMartJumptableIndex]
+ ld hl, .MartFunctions
+ rst JumpTable
+ ld [wMartJumptableIndex], a
+ cp STANDARDMART_EXIT
+ 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, MartWelcomeText
+ 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, MartComeAgainText
+ call MartTextbox
+ ld a, STANDARDMART_EXIT
+ ret
+
+.AnythingElse:
+ call LoadStandardMenuHeader
+ ld hl, MartAskMoreText
+ 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 wMartType
+; 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
+ jp BargainShopAskPurchaseQuantity
+
+GetMartDialogGroup:
+ ld a, [wMartType]
+ 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
+
+.StandardMartPointers:
+ dw MartHowManyText
+ dw MartFinalPriceText
+ dw MartNoMoneyText
+ dw MartPackFullText
+ dw MartThanksText
+ dw BuyMenuLoop
+
+.HerbShopPointers:
+ dw HerbalLadyHowManyText
+ dw HerbalLadyFinalPriceText
+ dw HerbalLadyNoMoneyText
+ dw HerbalLadyPackFullText
+ dw HerbalLadyThanksText
+ dw BuyMenuLoop
+
+.BargainShopPointers:
+ dw BuyMenuLoop
+ dw BargainShopFinalPriceText
+ dw BargainShopNoFundsText
+ dw BargainShopPackFullText
+ dw BargainShopThanksText
+ dw BargainShopSoldOutText
+
+.PharmacyPointers:
+ dw PharmacyHowManyText
+ dw PharmacyFinalPriceText
+ dw PharmacyNoMoneyText
+ dw PharmacyPackFullText
+ dw PharmacyThanksText
+ 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]
+ ldh [hMoneyTemp + 2], a
+ ld a, [hl]
+ ldh [hMoneyTemp + 1], a
+ xor a
+ ldh [hMoneyTemp], a
+ and a
+ ret
+
+.SoldOut:
+ ld a, MARTTEXT_SOLD_OUT
+ call LoadBuyMenuText
+ call JoyWaitAorB
+ scf
+ ret
+
+MartHowManyText:
+ text_far _MartHowManyText
+ text_end
+
+MartFinalPriceText:
+ text_far _MartFinalPriceText
+ text_end
+
+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 SCROLLINGMENU_ITEMS_NORMAL ; item format
+ 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
+
+HerbShopLadyIntroText:
+ text_far _HerbShopLadyIntroText
+ text_end
+
+HerbalLadyHowManyText:
+ text_far _HerbalLadyHowManyText
+ text_end
+
+HerbalLadyFinalPriceText:
+ text_far _HerbalLadyFinalPriceText
+ text_end
+
+HerbalLadyThanksText:
+ text_far _HerbalLadyThanksText
+ text_end
+
+HerbalLadyPackFullText:
+ text_far _HerbalLadyPackFullText
+ text_end
+
+HerbalLadyNoMoneyText:
+ text_far _HerbalLadyNoMoneyText
+ text_end
+
+HerbalLadyComeAgainText:
+ text_far _HerbalLadyComeAgainText
+ text_end
+
+BargainShopIntroText:
+ text_far _BargainShopIntroText
+ text_end
+
+BargainShopFinalPriceText:
+ text_far _BargainShopFinalPriceText
+ text_end
+
+BargainShopThanksText:
+ text_far _BargainShopThanksText
+ text_end
+
+BargainShopPackFullText:
+ text_far _BargainShopPackFullText
+ text_end
+
+BargainShopSoldOutText:
+ text_far _BargainShopSoldOutText
+ text_end
+
+BargainShopNoFundsText:
+ text_far _BargainShopNoFundsText
+ text_end
+
+BargainShopComeAgainText:
+ text_far _BargainShopComeAgainText
+ text_end
+
+PharmacyIntroText:
+ text_far _PharmacyIntroText
+ text_end
+
+PharmacyHowManyText:
+ text_far _PharmacyHowManyText
+ text_end
+
+PharmacyFinalPriceText:
+ text_far _PharmacyFinalPriceText
+ text_end
+
+PharmacyThanksText:
+ text_far _PharmacyThanksText
+ text_end
+
+PharmacyPackFullText:
+ text_far _PharmacyPackFullText
+ text_end
+
+PharmacyNoMoneyText:
+ text_far _PharmacyNoMoneyText
+ text_end
+
+PharmacyComeAgainText:
+ text_far _PharmacyComeAgainText
+ text_end
+
+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:
+ text_far _NothingToSellText
+ text_end
+
+.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, MartCantBuyText
+ call PrintText
+ and a
+ ret
+
+.okay_to_sell
+ ld hl, MartSellHowManyText
+ call PrintText
+ farcall PlaceMoneyAtTopLeftOfTextbox
+ farcall SelectQuantityToSell
+ call ExitMenu
+ jr c, .declined
+ hlcoord 1, 14
+ lb bc, 3, 18
+ call ClearBox
+ ld hl, MartSellPriceText
+ 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, MartBoughtText
+ call PrintTextboxText
+ call PlayTransactionSound
+ farcall PlaceMoneyBottomLeft
+ call JoyWaitAorB
+
+.declined
+ call ExitMenu
+ and a
+ ret
+
+MartSellHowManyText:
+ text_far _MartSellHowManyText
+ text_end
+
+MartSellPriceText:
+ text_far _MartSellPriceText
+ text_end
+
+.UnusedString161d2:
+ db "!ダミー!@"
+
+MartWelcomeText:
+ text_far _MartWelcomeText
+ text_end
+
+MenuHeader_BuySell:
+ db MENU_BACKUP_TILES ; flags
+ menu_coords 0, 0, 11, 8
+ dw .MenuData
+ db 1 ; default option
+
+.MenuData
+ db STATICMENU_CURSOR ; strings
+ db 3 ; items
+ db "BUY@"
+ db "SELL@"
+ db "QUIT@"
+
+MartThanksText:
+ text_far _MartThanksText
+ text_end
+
+MartNoMoneyText:
+ text_far _MartNoMoneyText
+ text_end
+
+MartPackFullText:
+ text_far _MartPackFullText
+ text_end
+
+MartCantBuyText:
+ text_far _MartCantBuyText
+ text_end
+
+MartComeAgainText:
+ text_far _MartComeAgainText
+ text_end
+
+MartAskMoreText:
+ text_far _MartAskMoreText
+ text_end
+
+MartBoughtText:
+ text_far _MartBoughtText
+ text_end
+
+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 100755
index 00000000..e7caceca
--- /dev/null
+++ b/engine/items/pack.asm
@@ -0,0 +1,1584 @@
+; 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, [wCurPocket]
+ 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
+ ldh [hBGMapMode], a
+ call Pack_InitGFX
+ ld a, [wPackJumptableIndex]
+ ld [wJumptableIndex], a
+ call Pack_InitColors
+ ret
+
+.InitItemsPocket:
+ xor a ; ITEM_POCKET
+ ld [wCurPocket], 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 [wCurPocket], 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 [wCurPocket], a
+ call ClearPocketList
+ call DrawPocketName
+ xor a
+ ldh [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 0, 7, SCREEN_WIDTH - 14, 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 0, 5, SCREEN_WIDTH - 14, 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
+ ldh [hBGMapMode], a
+ call Pack_InitGFX
+ call WaitBGMap_DrawPackGFX
+ call Pack_InitColors
+ ret
+
+.InitBallsPocket:
+ ld a, BALL_POCKET
+ ld [wCurPocket], 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 0, 2, SCREEN_WIDTH - 14, TEXTBOX_Y
+ 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 0, 3, SCREEN_WIDTH - 14, 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 0, 7, SCREEN_WIDTH - 14, 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 0, 5, SCREEN_WIDTH - 14, 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 0, 3, SCREEN_WIDTH - 14, 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 0, 5, SCREEN_WIDTH - 14, 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, OakThisIsntTheTimeText
+ call Pack_PrintTextNoScroll
+ ret
+
+.Current:
+ call DoItemEffect
+ ret
+
+.Party:
+ ld a, [wPartyCount]
+ and a
+ jr z, .NoPokemon
+ call DoItemEffect
+ xor a
+ ldh [hBGMapMode], a
+ call Pack_InitGFX
+ call WaitBGMap_DrawPackGFX
+ call Pack_InitColors
+ ret
+
+.NoPokemon:
+ ld hl, YouDontHaveAMonText
+ 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, AskThrowAwayText
+ call Pack_PrintTextNoScroll
+ farcall SelectQuantityToToss
+ push af
+ call ExitMenu
+ pop af
+ jr c, .finish
+ call Pack_GetItemName
+ ld hl, AskQuantityThrowAwayText
+ 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, ThrewAwayText
+ call Pack_PrintTextNoScroll
+.finish
+ ret
+
+Unreferenced_ResetPocketCursorPositions:
+ ld a, [wCurPocket]
+ 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, [wCurPocket]
+ 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, RegisteredItemText
+ call Pack_PrintTextNoScroll
+ ret
+
+.cant_register
+ ld hl, CantRegisterText
+ 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, .AnEggCantHoldAnItemText
+ 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
+ ldh [hBGMapMode], a
+ call Pack_InitGFX
+ call WaitBGMap_DrawPackGFX
+ call Pack_InitColors
+ ret
+
+.NoPokemon:
+ ld hl, YouDontHaveAMonText
+ call Pack_PrintTextNoScroll
+ ret
+.AnEggCantHoldAnItemText:
+ text_far _AnEggCantHoldAnItemText
+ text_end
+
+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, [wCurPocket]
+ 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
+ ldh [hBGMapMode], a
+ call Pack_InitGFX
+ ld a, [wPackJumptableIndex]
+ ld [wJumptableIndex], a
+ call Pack_InitColors
+ ret
+
+.InitItemsPocket:
+ xor a ; ITEM_POCKET
+ ld [wCurPocket], 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 [wCurPocket], 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 [wCurPocket], a
+ call ClearPocketList
+ call DrawPocketName
+ xor a
+ ldh [hBGMapMode], a
+ call WaitBGMap_DrawPackGFX
+ ld hl, PackEmptyText
+ 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 [wCurPocket], 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 0, 7, TEXTBOX_HEIGHT, 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 0, 9, SCREEN_WIDTH - 14, 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, OakThisIsntTheTimeText
+ 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
+ ldh [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 [wCurPocket], 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
+ ldh [hBGMapMode], a
+ ld [wJumptableIndex], a ; PACKSTATE_INITGFX
+ ld [wPackJumptableIndex], a ; PACKSTATE_INITGFX
+ ld [wCurPocket], 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 [wCurPocket], 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, [wCurPocket]
+ maskbits NUM_POCKETS
+ ld e, a
+ ld d, 0
+ 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
+
+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, AskItemMoveText
+ 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
+ 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, [wCurPocket]
+ ; * 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 SCROLLINGMENU_ITEMS_QUANTITY ; item format
+ 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 SCROLLINGMENU_ITEMS_QUANTITY ; item format
+ 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 SCROLLINGMENU_ITEMS_NORMAL ; item format
+ 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 SCROLLINGMENU_ITEMS_NORMAL ; item format
+ 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 SCROLLINGMENU_ITEMS_QUANTITY ; item format
+ 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 SCROLLINGMENU_ITEMS_QUANTITY ; item format
+ dbw 0, wNumBalls
+ dba PlaceMenuItemName
+ dba PlaceMenuItemQuantity
+ dba UpdateItemDescription
+
+PackNoItemText:
+ text_far _PackNoItemText
+ text_end
+
+AskThrowAwayText:
+ text_far _AskThrowAwayText
+ text_end
+
+AskQuantityThrowAwayText:
+ text_far _AskQuantityThrowAwayText
+ text_end
+
+ThrewAwayText:
+ text_far _ThrewAwayText
+ text_end
+
+OakThisIsntTheTimeText:
+ text_far _OakThisIsntTheTimeText
+ text_end
+
+YouDontHaveAMonText:
+ text_far _YouDontHaveAMonText
+ text_end
+
+RegisteredItemText:
+ text_far _RegisteredItemText
+ text_end
+
+CantRegisterText:
+ text_far _CantRegisterText
+ text_end
+
+AskItemMoveText:
+ text_far _AskItemMoveText
+ text_end
+
+PackEmptyText:
+ text_far _PackEmptyText
+ text_end
+
+YouCantUseItInABattleText:
+ text_far _YouCantUseItInABattleText
+ text_end
+
+PackMenuGFX:
+INCBIN "gfx/pack/pack_menu.2bpp"
+PackGFX:
+INCBIN "gfx/pack/pack.2bpp"
diff --git a/engine/items/print_item_description.asm b/engine/items/print_item_description.asm
new file mode 100644
index 00000000..89a949ad
--- /dev/null
+++ b/engine/items/print_item_description.asm
@@ -0,0 +1,32 @@
+PrintItemDescription:
+; Print the description for item [wCurSpecies] at de.
+
+ ld a, [wCurSpecies]
+ cp TM01
+ jr c, .not_a_tm
+
+ ld [wCurItem], a
+ push de
+ call GetTMHMItemMove
+ pop hl
+ ld a, [wTempTMHM]
+ ld [wCurSpecies], a
+ call PrintMoveDesc
+ ret
+
+.not_a_tm
+ push de
+ ld hl, ItemDescriptions
+ ld a, [wCurSpecies]
+ dec a
+ ld c, a
+ ld b, 0
+ add hl, bc
+ add hl, bc
+ ld a, BANK(ItemDescriptions)
+ call GetFarHalfword
+ ld d, h
+ ld e, l
+ pop hl
+ ld a, BANK(ItemDescriptions)
+ jp FarString
diff --git a/engine/items/switch_items.asm b/engine/items/switch_items.asm
new file mode 100644
index 00000000..cb1554d7
--- /dev/null
+++ b/engine/items/switch_items.asm
@@ -0,0 +1,272 @@
+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 Function248cf
+ jp c, Function248f9
+ ld a, [wScrollingMenuCursorPosition]
+ ld c, a
+ ld a, [wSwitchItem]
+ cp c
+ jr c, .asm_248a2
+ jr .asm_24872
+
+.init
+ ld a, [wScrollingMenuCursorPosition]
+ inc a
+ ld [wSwitchItem], a
+ ret
+
+.trivial
+ xor a
+ ld [wSwitchItem], a
+ ret
+
+.asm_24872
+ ld a, [wSwitchItem]
+ call Function24968
+ ld a, [wScrollingMenuCursorPosition]
+ ld d, a
+ ld a, [wSwitchItem]
+ ld e, a
+ call Function24994
+ push bc
+ ld a, [wSwitchItem]
+ call ItemSwitch_GetNthItem
+ dec hl
+ push hl
+ call ItemSwitch_ConvertItemFormatToDW
+ add hl, bc
+ ld d, h
+ ld e, l
+ pop hl
+ pop bc
+ call Function249d3
+ ld a, [wScrollingMenuCursorPosition]
+ call Function24975
+ xor a
+ ld [wSwitchItem], a
+ ret
+
+.asm_248a2
+ ld a, [wSwitchItem]
+ call Function24968
+ ld a, [wScrollingMenuCursorPosition]
+ ld d, a
+ ld a, [wSwitchItem]
+ ld e, a
+ call Function24994
+ push bc
+ ld a, [wSwitchItem]
+ call ItemSwitch_GetNthItem
+ ld d, h
+ ld e, l
+ call ItemSwitch_ConvertItemFormatToDW
+ add hl, bc
+ pop bc
+ call CopyBytes
+ ld a, [wScrollingMenuCursorPosition]
+ call Function24975
+ xor a
+ ld [wSwitchItem], a
+ ret
+
+Function248cf:
+ 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_248f5
+ ld a, [wScrollingMenuCursorPosition]
+ call Function249bf
+ cp 99
+ jr z, .asm_248f5
+ ld a, [wSwitchItem]
+ call Function249bf
+ cp 99
+ jr nz, .asm_248f7
+.asm_248f5
+ and a
+ ret
+
+.asm_248f7
+ scf
+ ret
+
+Function248f9:
+ 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_24929
+ 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_24929
+ 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_2494d
+ dec [hl]
+ ld a, [wSwitchItem]
+ call ItemSwitch_GetNthItem
+ ld [hl], $ff
+ xor a
+ ld [wSwitchItem], a
+ ret
+
+.asm_2494d
+ dec [hl]
+ call ItemSwitch_ConvertItemFormatToDW
+ push bc
+ ld a, [wSwitchItem]
+ call ItemSwitch_GetNthItem
+ pop bc
+ push hl
+ add hl, bc
+ pop de
+.asm_2495c
+ ld a, [hli]
+ ld [de], a
+ inc de
+ cp $ff
+ jr nz, .asm_2495c
+ xor a
+ ld [wSwitchItem], a
+ ret
+
+Function24968:
+ call ItemSwitch_GetNthItem
+ ld de, wceed
+ call ItemSwitch_ConvertItemFormatToDW
+ call CopyBytes
+ ret
+
+Function24975:
+ call ItemSwitch_GetNthItem
+ ld d, h
+ ld e, l
+ ld hl, wceed
+ call ItemSwitch_ConvertItemFormatToDW
+ call CopyBytes
+ ret
+
+ItemSwitch_GetNthItem:
+ push af
+ call ItemSwitch_ConvertItemFormatToDW
+ ld hl, wMenuData_ItemsPointerAddr
+ ld a, [hli]
+ ld h, [hl]
+ ld l, a
+ inc hl
+ pop af
+ call AddNTimes
+ ret
+
+Function24994:
+ push hl
+ call ItemSwitch_ConvertItemFormatToDW
+ 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_ConvertItemFormatToDW:
+ push hl
+ ld a, [wMenuData_ScrollingMenuItemFormat]
+ ld c, a
+ ld b, 0
+ ld hl, .format_dws
+ add hl, bc
+ add hl, bc
+ ld c, [hl]
+ inc hl
+ ld b, [hl]
+ pop hl
+ ret
+
+.format_dws
+ dw 0
+ dw 1
+ dw 2
+
+Function249bf:
+ push af
+ call ItemSwitch_ConvertItemFormatToDW
+ 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
+
+Function249d3:
+.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 00000000..f5261123
--- /dev/null
+++ b/engine/items/tmhm.asm
@@ -0,0 +1,552 @@
+TMHMPocket:
+ ld a, $1
+ ldh [hInMenu], a
+ call TMHM_PocketLoop
+ ld a, $0
+ ldh [hInMenu], a
+ ret nc
+ call PlaceHollowCursor
+ call WaitBGMap
+ ld a, [wCurItem]
+ dec a
+ ld [wCurItemQuantity], a
+ ld hl, wTMsHMs
+ ld c, a
+ ld b, 0
+ add hl, bc
+ ld a, [hl]
+ ld [wItemQuantityBuffer], a
+ call .ConvertItemToTMHMNumber
+ scf
+ ret
+
+.ConvertItemToTMHMNumber:
+ ld a, [wCurItem]
+ ld c, a
+ callfar GetNumberedTMHM
+ ld a, c
+ ld [wCurItem], a
+ ret
+
+ConvertCurItemIntoCurTMHM:
+ ld a, [wCurItem]
+ ld c, a
+ callfar GetTMHMNumber
+ ld a, c
+ ld [wTempTMHM], a
+ ret
+
+GetTMHMItemMove:
+ call ConvertCurItemIntoCurTMHM
+ predef GetTMHMMove
+ ret
+
+AskTeachTMHM:
+ ld hl, wOptions
+ ld a, [hl]
+ push af
+ res NO_TEXT_SCROLL, [hl]
+ ld a, [wCurItem]
+ cp TM01
+ jr c, .NotTMHM
+ call GetTMHMItemMove
+ ld a, [wTempTMHM]
+ ld [wPutativeTMHMMove], a
+ call GetMoveName
+ call CopyName1
+ ld hl, BootedTMText ; Booted up a TM
+ ld a, [wCurItem]
+ cp HM01
+ jr c, .TM
+ ld hl, BootedHMText ; Booted up an HM
+.TM:
+ call PrintText
+ ld hl, ContainedMoveText
+ call PrintText
+ call YesNoBox
+.NotTMHM:
+ pop bc
+ ld a, b
+ ld [wOptions], a
+ ret
+
+ChooseMonToLearnTMHM:
+ ld hl, wStringBuffer2
+ ld de, wTMHMMoveNameBackup
+ ld bc, 12
+ call CopyBytes
+ call ClearBGPalettes
+ChooseMonToLearnTMHM_NoRefresh:
+ farcall LoadPartyMenuGFX
+ farcall InitPartyMenuWithCancel
+ farcall InitPartyMenuGFX
+ ld a, PARTYMENUACTION_TEACH_TMHM
+ ld [wPartyMenuActionText], a
+.loopback
+ farcall WritePartyMenuTilemap
+ farcall PrintPartyMenuText
+ call WaitBGMap
+ call SetPalettes
+ call DelayFrame
+ farcall PartyMenuSelect
+ push af
+ ld a, [wCurPartySpecies]
+ cp EGG
+ pop bc ; now contains the former contents of af
+ jr z, .egg
+ push bc
+ ld hl, wTMHMMoveNameBackup
+ ld de, wStringBuffer2
+ ld bc, 12
+ call CopyBytes
+ pop af ; now contains the original contents of af
+ ret
+
+.egg
+ push hl
+ push de
+ push bc
+ push af
+ ld de, SFX_WRONG
+ call PlaySFX
+ call WaitSFX
+ pop af
+ pop bc
+ pop de
+ pop hl
+ jr .loopback
+
+TeachTMHM:
+ predef CanLearnTMHMMove
+
+ push bc
+ ld a, [wCurPartyMon]
+ ld hl, wPartyMonNicknames
+ call GetNick
+ pop bc
+
+ ld a, c
+ and a
+ jr nz, .compatible
+ push de
+ ld de, SFX_WRONG
+ call PlaySFX
+ pop de
+ ld hl, TMHMNotCompatibleText
+ call PrintText
+ jr .nope
+
+.compatible
+ callfar KnowsMove
+ jr c, .nope
+
+ predef LearnMove
+ ld a, b
+ and a
+ jr z, .nope
+
+ ld a, [wCurItem]
+ call IsHM
+ ret c
+
+ ld c, HAPPINESS_LEARNMOVE
+ callfar ChangeHappiness
+ call ConsumeTM
+ jr .learned_move
+
+.nope
+ and a
+ ret
+
+.unused
+ ld a, 2
+ ld [wItemEffectSucceeded], a
+.learned_move
+ scf
+ ret
+
+BootedTMText:
+ text_far _BootedTMText
+ text_end
+
+BootedHMText:
+ text_far _BootedHMText
+ text_end
+
+ContainedMoveText:
+ text_far _ContainedMoveText
+ text_end
+
+TMHMNotCompatibleText:
+ text_far _TMHMNotCompatibleText
+ text_end
+
+TMHM_PocketLoop:
+ xor a
+ ldh [hBGMapMode], a
+ call TMHM_DisplayPocketItems
+ ld a, 2
+ ld [w2DMenuCursorInitY], a
+ ld a, 7
+ ld [w2DMenuCursorInitX], a
+ ld a, 1
+ ld [w2DMenuNumCols], a
+ ld a, 5
+ sub d
+ inc a
+ cp 6
+ jr nz, .okay
+ dec a
+.okay
+ ld [w2DMenuNumRows], a
+ ld a, $c
+ ld [w2DMenuFlags1], a
+ xor a
+ ld [w2DMenuFlags2], a
+ ld a, $20
+ ld [w2DMenuCursorOffsets], a
+ ld a, A_BUTTON | B_BUTTON | D_UP | D_DOWN | D_LEFT | D_RIGHT
+ ld [wMenuJoypadFilter], a
+ ld a, [wTMHMPocketCursor]
+ inc a
+ ld [wMenuCursorY], a
+ ld a, $1
+ ld [wMenuCursorX], a
+ jr TMHM_ShowTMMoveDescription
+
+TMHM_JoypadLoop:
+ call TMHM_DisplayPocketItems
+ call StaticMenuJoypad
+ ld b, a
+ ld a, [wMenuCursorY]
+ dec a
+ ld [wTMHMPocketCursor], a
+ xor a
+ ldh [hBGMapMode], a
+ ld a, [w2DMenuFlags2]
+ bit 7, a
+ jp nz, TMHM_ScrollPocket
+ ld a, b
+ ld [wMenuJoypad], a
+ bit A_BUTTON_F, a
+ jp nz, TMHM_ChooseTMorHM
+ bit B_BUTTON_F, a
+ jp nz, TMHM_ExitPack
+ bit D_RIGHT_F, a
+ jp nz, TMHM_ExitPocket
+ bit D_LEFT_F, a
+ jp nz, TMHM_ExitPocket
+TMHM_ShowTMMoveDescription:
+ call TMHM_CheckHoveringOverCancel
+ jp nc, TMHM_ExitPocket
+ hlcoord 0, 12
+ ld b, 4
+ ld c, SCREEN_WIDTH - 2
+ call Textbox
+ ld a, [wCurItem]
+ cp NUM_TMS + NUM_HMS + 1
+ jr nc, TMHM_JoypadLoop
+ ld [wTempTMHM], a
+ predef GetTMHMMove
+ ld a, [wTempTMHM]
+ ld [wCurSpecies], a
+ hlcoord 1, 14
+ call PrintMoveDesc
+ jp TMHM_JoypadLoop
+
+TMHM_ChooseTMorHM:
+ call TMHM_PlaySFX_ReadText2
+ call CountTMsHMs ; This stores the count to wTempTMHM.
+ ld a, [wMenuCursorY]
+ dec a
+ ld b, a
+ ld a, [wTMHMPocketScrollPosition]
+ add b
+ ld b, a
+ ld a, [wTempTMHM]
+ cp b
+ jr z, _TMHM_ExitPack ; our cursor was hovering over CANCEL
+TMHM_CheckHoveringOverCancel:
+ call TMHM_GetCurrentPocketPosition
+ ld a, [wMenuCursorY]
+ ld b, a
+.loop
+ inc c
+ ld a, c
+ cp NUM_TMS + NUM_HMS + 1
+ jr nc, .okay
+ ld a, [hli]
+ and a
+ jr z, .loop
+ dec b
+ jr nz, .loop
+ ld a, c
+.okay
+ ld [wCurItem], a
+ cp -1
+ ret
+
+TMHM_ExitPack:
+ call TMHM_PlaySFX_ReadText2
+_TMHM_ExitPack:
+ ld a, $2
+ ld [wMenuJoypad], a
+ and a
+ ret
+
+TMHM_ExitPocket:
+ and a
+ ret
+
+TMHM_ScrollPocket:
+ ld a, b
+ bit 7, a
+ jr nz, .skip
+ ld hl, wTMHMPocketScrollPosition
+ ld a, [hl]
+ and a
+ jp z, TMHM_JoypadLoop
+ dec [hl]
+ call TMHM_DisplayPocketItems
+ jp TMHM_ShowTMMoveDescription
+
+.skip
+ call TMHM_GetCurrentPocketPosition
+ ld b, 5
+.loop
+ inc c
+ ld a, c
+ cp NUM_TMS + NUM_HMS + 1
+ jp nc, TMHM_JoypadLoop
+ ld a, [hli]
+ and a
+ jr z, .loop
+ dec b
+ jr nz, .loop
+ ld hl, wTMHMPocketScrollPosition
+ inc [hl]
+ call TMHM_DisplayPocketItems
+ jp TMHM_ShowTMMoveDescription
+
+TMHM_DisplayPocketItems:
+ ld a, [wBattleType]
+ cp BATTLETYPE_TUTORIAL
+ jp z, Tutorial_TMHMPocket
+
+ hlcoord 5, 2
+ lb bc, 10, 15
+ ld a, " "
+ call ClearBox
+ call TMHM_GetCurrentPocketPosition
+ ld d, $5
+.loop2
+ inc c
+ ld a, c
+ cp NUM_TMS + NUM_HMS + 1
+ jr nc, .NotTMHM
+ ld a, [hli]
+ and a
+ jr z, .loop2
+ ld b, a
+ ld a, c
+ ld [wTempTMHM], a
+ push hl
+ push de
+ push bc
+ call TMHMPocket_GetCurrentLineCoord
+ push hl
+ ld a, [wTempTMHM]
+ cp NUM_TMS + 1
+ jr nc, .HM
+ ld de, wTempTMHM
+ lb bc, PRINTNUM_LEADINGZEROS | 1, 2
+ call PrintNum
+ jr .okay
+
+.HM:
+ push af
+ sub NUM_TMS
+ ld [wTempTMHM], a
+ ld [hl], "H"
+ inc hl
+ ld de, wTempTMHM
+ lb bc, PRINTNUM_LEFTALIGN | 1, 2
+ call PrintNum
+ pop af
+ ld [wTempTMHM], a
+.okay
+ predef GetTMHMMove
+ ld a, [wNamedObjectIndexBuffer]
+ ld [wPutativeTMHMMove], a
+ call GetMoveName
+ pop hl
+ ld bc, 3
+ add hl, bc
+ push hl
+ call PlaceString
+ pop hl
+ pop bc
+ ld a, c
+ push bc
+ cp NUM_TMS + 1
+ jr nc, .hm2
+ ld bc, SCREEN_WIDTH + 9
+ add hl, bc
+ ld [hl], "×"
+ inc hl
+ ld a, "0" ; why are we doing this?
+ pop bc
+ push bc
+ ld a, b
+ ld [wTempTMHM], a
+ ld de, wTempTMHM
+ lb bc, 1, 2
+ call PrintNum
+.hm2
+ pop bc
+ pop de
+ pop hl
+ dec d
+ jr nz, .loop2
+ jr .done
+
+.NotTMHM:
+ call TMHMPocket_GetCurrentLineCoord
+ inc hl
+ inc hl
+ inc hl
+ push de
+ ld de, TMHM_String_Cancel
+ call PlaceString
+ pop de
+.done
+ ret
+
+TMHMPocket_GetCurrentLineCoord:
+ hlcoord 5, 0
+ ld bc, 2 * SCREEN_WIDTH
+ ld a, 6
+ sub d
+ ld e, a
+ ; AddNTimes
+.loop
+ add hl, bc
+ dec e
+ jr nz, .loop
+ ret
+
+Unreferenced_Function2c89a:
+ pop hl
+ ld bc, 3
+ add hl, bc
+ predef GetTMHMMove
+ ld a, [wTempTMHM]
+ ld [wPutativeTMHMMove], a
+ call GetMoveName
+ push hl
+ call PlaceString
+ pop hl
+ ret
+
+TMHM_String_Cancel:
+ db "CANCEL@"
+
+TMHM_GetCurrentPocketPosition:
+ ld hl, wTMsHMs
+ ld a, [wTMHMPocketScrollPosition]
+ ld b, a
+ inc b
+ ld c, 0
+.loop
+ inc c
+ ld a, [hli]
+ and a
+ jr z, .loop
+ dec b
+ jr nz, .loop
+ dec hl
+ dec c
+ ret
+
+Tutorial_TMHMPocket:
+ hlcoord 9, 3
+ push de
+ ld de, TMHM_String_Cancel
+ call PlaceString
+ pop de
+ ret
+
+TMHM_PlaySFX_ReadText2:
+ push de
+ ld de, SFX_READ_TEXT_2
+ call PlaySFX
+ pop de
+ ret
+
+Unreferenced_Function2c8e4:
+ call ConvertCurItemIntoCurTMHM
+ call .CheckHaveRoomForTMHM
+ ld hl, .NoRoomTMHMText
+ jr nc, .print
+ ld hl, .ReceivedTMHMText
+.print
+ jp PrintText
+
+.NoRoomTMHMText:
+ text_far _NoRoomTMHMText
+ text_end
+
+.ReceivedTMHMText:
+ text_far _ReceivedTMHMText
+ text_end
+
+.CheckHaveRoomForTMHM:
+ ld a, [wTempTMHM]
+ dec a
+ ld hl, wTMsHMs
+ ld b, 0
+ ld c, a
+ add hl, bc
+ ld a, [hl]
+ inc a
+ cp NUM_TMS * 2
+ ret nc
+ ld [hl], a
+ ret
+
+ConsumeTM:
+ call ConvertCurItemIntoCurTMHM
+ ld a, [wTempTMHM]
+ dec a
+ ld hl, wTMsHMs
+ ld b, 0
+ ld c, a
+ add hl, bc
+ ld a, [hl]
+ and a
+ ret z
+ dec a
+ ld [hl], a
+ ret nz
+ ld a, [wTMHMPocketScrollPosition]
+ and a
+ ret z
+ dec a
+ ld [wTMHMPocketScrollPosition], a
+ ret
+
+CountTMsHMs:
+ ld b, 0
+ ld c, NUM_TMS + NUM_HMS
+ ld hl, wTMsHMs
+.loop
+ ld a, [hli]
+ and a
+ jr z, .skip
+ inc b
+.skip
+ dec c
+ jr nz, .loop
+ ld a, b
+ ld [wTempTMHM], a
+ ret
diff --git a/engine/items/tmhm2.asm b/engine/items/tmhm2.asm
new file mode 100755
index 00000000..eb3eb58e
--- /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_11a45
+ inc c
+ jr .loop
+
+.asm_11a45
+ 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, [wTempTMHM]
+ dec a
+ ld hl, TMHMMoves
+ ld b, 0
+ ld c, a
+ add hl, bc
+ ld a, [hl]
+ ld [wTempTMHM], 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 00000000..da56732a
--- /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
diff --git a/engine/learn.asm b/engine/learn.asm
deleted file mode 100644
index f61b0c6c..00000000
--- a/engine/learn.asm
+++ /dev/null
@@ -1,220 +0,0 @@
-LearnMove:
- call LoadTilemapToTempTilemap
- ld a, [wCurPartyMon]
- ld hl, wPartyMon1Nickname
- call GetNick
- ld hl, wStringBuffer1
- ld de, wMonOrItemNameBuffer
- ld bc, $b
- call CopyBytes
-.loop
- ld hl, wPartyMon1Moves
- ld bc, $30
- ld a, [wCurPartyMon]
- call AddNTimes
- ld d, h
- ld e, l
- ld b, $4
-.asm_660f
- ld a, [hl]
- and a
- jr z, .asm_6643
- inc hl
- dec b
- jr nz, .asm_660f
- push de
- call .AlreadyHaveFourMoves
- pop de
- jp c, .ConfirmStopLearning
- push hl
- push de
- ld [wd151], a
- ld b, a
- ld a, [wBattleMode]
- and a
- jr z, .asm_6638
- ld a, [wcbd3]
- cp b
- jr nz, .asm_6638
- xor a
- ld [wcbd3], a
- ld [wcb53], a
-.asm_6638
- call GetMoveName
- ld hl, Text_1_2_and_Poof
- call PrintText
- pop de
- pop hl
-.asm_6643
- ld a, [wd14d]
- ld [hl], a
- ld bc, $15
- add hl, bc
- push hl
- push de
- dec a
- ld hl, Moves + MOVE_PP ; $5b03
- ld bc, $7
- call AddNTimes
- ld a, BANK(Moves)
- call GetFarByte
- pop de
- pop hl
- ld [hl], a
- ld a, [wBattleMode]
- and a
- jp z, .LearnedMove
- ld a, [wCurPartyMon]
- ld b, a
- ld a, [wCurBattleMon]
- cp b
- jp nz, .LearnedMove
- ld a, [wPlayerSubStatus5]
- bit 3, a
- jp nz, .LearnedMove
- ld h, d
- ld l, e
- ld de, wBattleMonMoves
- ld bc, $4
- call CopyBytes
- ld bc, $11
- add hl, bc
- ld de, wBattleMonPP
- ld bc, $4
- call CopyBytes
- jp .LearnedMove
-
-.ConfirmStopLearning: ; 6694 (1:6694)
- ld hl, Text_StopLearning
- call PrintText
- call YesNoBox
- jp c, .loop
- ld hl, Text_DidNotLearn
- call PrintText
- ld b, $0
- ret
-
-.LearnedMove: ; 66a9 (1:66a9)
- ld hl, Text_LearnedMove
- call PrintText
- ld b, $1
- ret
-
-.AlreadyHaveFourMoves: ; 66b2 (1:66b2)
- push hl
- ld hl, Text_TryingToLearn
- call PrintText
- call YesNoBox
- pop hl
- ret c
- ld bc, -4
- add hl, bc
- push hl
- ld de, wd149
- ld bc, $4
- call CopyBytes
- pop hl
-.asm_66cd
- push hl
- ld hl, Text_ForgetWhich
- call PrintText
- hlcoord 5, 2
- ld b, $8
- ld c, $d
- call Textbox
- hlcoord 7, 4
- ld a, $28
- ld [wBuffer1], a
- predef ListMoves
- ld a, $4
- ld [wMenuDataEnd], a
- ld a, $6
- ld [wced9], a
- ld a, [wcfe3]
- inc a
- ld [wceda], a
- ld a, $1
- ld [wcedb], a
- ld [wMenuCursorY], a
- ld [wcee1], a
- ld a, $3
- ld [wMenuJoypadFilter], a
- ld a, $20
- ld [w2DMenuFlags1], a
- xor a
- ld [wcedd], a
- ld a, $20
- ld [wcede], a
- call StaticMenuJoypad
- push af
- call SafeLoadTempTilemapToTilemap
- pop af
- pop hl
- bit 1, a
- jr nz, .asm_6748
- push hl
- ld a, [wMenuCursorY]
- dec a
- ld c, a
- ld b, $0
- add hl, bc
- ld a, [hl]
- push af
- push bc
- call IsHMMove
- pop bc
- pop de
- ld a, d
- jr c, .asm_673f
- pop hl
- add hl, bc
- and a
- ret
-
-.asm_673f
- ld hl, Text_CantForgetHM
- call PrintText
- pop hl
- jr .asm_66cd
-
-.asm_6748
- scf
- ret
-
-Text_LearnedMove:
- text_far Text_LearnedMove_
- db "@"
-
-Text_ForgetWhich:
- text_far Text_ForgetWhich_
- db "@"
-
-Text_StopLearning:
- text_far Text_StopLearning_
- db "@"
-
-Text_DidNotLearn:
- text_far Text_DidNotLearn_
- db "@"
-
-Text_TryingToLearn:
- text_far Text_TryingToLearn_
- db "@"
-
-Text_1_2_and_Poof:
- text_far Text_1_2_and_Poof_
- text_asm
- push de
- ld de, SFX_SWITCH_POKEMON
- call PlaySFX
- pop de
- ld hl, .PoofForgot
- ret
-
-.PoofForgot:
- text_far Text_PoofForgot_
- db "@"
-
-Text_CantForgetHM:
- text_far Text_CantForgetHM_
- db "@"
diff --git a/engine/learn_tm.asm b/engine/learn_tm.asm
deleted file mode 100755
index 530ecf41..00000000
--- a/engine/learn_tm.asm
+++ /dev/null
@@ -1,107 +0,0 @@
-CanLearnTMHMMove: ; 11a25 (4:5a25)
- ld a, [wCurPartySpecies]
- ld [wCurSpecies], a
- call GetBaseData
- ld hl, wd138
- push hl
- ld a, [wd14d]
- ld b, a
- ld c, $0
- ld hl, TMMovesList
-.asm_11a3b
- ld a, [hli]
- and a
- jr z, .asm_11a52
- cp b
- jr z, .asm_11a45
- inc c
- jr .asm_11a3b
-
-.asm_11a45
- pop hl
- ld b, CHECK_FLAG
- push de
- ld d, $0
- predef SmallFarFlagAction
- pop de
- ret
-
-.asm_11a52
- pop hl
- ld c, $0
- ret
-
-GetTMHMMove: ; 11a56 (4:5a56)
- ld a, [wd151]
- dec a
- ld hl, TMMovesList
- ld b, $0
- ld c, a
- add hl, bc
- ld a, [hl]
- ld [wd151], a
- ret
-
-TMMovesList:
- db DYNAMICPUNCH
- db HEADBUTT
- db CURSE
- db ROLLOUT
- db ROAR
- db TOXIC
- db ZAP_CANNON
- db ROCK_SMASH
- db PSYCH_UP
- db HIDDEN_POWER
- db SUNNY_DAY
- db SWEET_SCENT
- db SNORE
- db BLIZZARD
- db HYPER_BEAM
- db ICY_WIND
- db PROTECT
- db RAIN_DANCE
- db GIGA_DRAIN
- db ENDURE
- db FRUSTRATION
- db SOLARBEAM
- db IRON_TAIL
- db DRAGONBREATH
- db THUNDER
- db EARTHQUAKE
- db RETURN
- db DIG
- db PSYCHIC_M
- db SHADOW_BALL
- db MUD_SLAP
- db DOUBLE_TEAM
- db ICE_PUNCH
- db SWAGGER
- db SLEEP_TALK
- db SLUDGE_BOMB
- db SANDSTORM
- db FIRE_BLAST
- db SWIFT
- db DEFENSE_CURL
- db THUNDERPUNCH
- db DREAM_EATER
- db DETECT
- db REST
- db ATTRACT
- db THIEF
- db STEEL_WING
- db FIRE_PUNCH
- db FURY_CUTTER
- db NIGHTMARE
- db CUT
- db FLY
- db SURF
- db STRENGTH
- db FLASH
- db WHIRLPOOL
- db WATERFALL
-
- db 0
- db 0
- db 0
- db 0
diff --git a/engine/link/link.asm b/engine/link/link.asm
new file mode 100644
index 00000000..5f88a087
--- /dev/null
+++ b/engine/link/link.asm
@@ -0,0 +1,2345 @@
+LinkCommunications:
+ ld c, 80
+ call DelayFrames
+ call ClearTilemap
+ call ClearSprites
+ call UpdateSprites
+ call WaitBGMap
+ call SetTradeRoomBGPals
+ xor a
+ ldh [hSCX], a
+ ldh [hSCY], a
+ ld c, 80
+ call DelayFrames
+ call ClearTilemap
+ call UpdateSprites
+ call LoadStandardFont
+ call LoadFontsBattleExtra
+ call LoadTradeScreenBorder
+ call SetTradeRoomBGPals
+ call WaitBGMap
+ hlcoord 3, 8
+ ld b, 2
+ ld c, 12
+ call LinkTextboxAtHL
+ hlcoord 4, 10
+ ld de, String_PleaseWait
+ call PlaceString
+ ld hl, wce5d
+ xor a ; LOW($5000)
+ ld [hli], a
+ ld [hl], HIGH($5000)
+ ld a, [wLinkMode]
+ cp LINK_TIMECAPSULE
+ jp nz, Gen2ToGen2LinkComms
+
+Gen2ToGen1LinkComms:
+ call ClearLinkData
+ call Link_PrepPartyData_Gen1
+ call FixDataForLinkTransfer
+ xor a
+ ld [wPlayerLinkAction], a
+ call WaitLinkTransfer
+ ldh a, [hSerialConnectionStatus]
+ cp USING_INTERNAL_CLOCK
+ jr nz, .player_1
+
+ ld c, 3
+ call DelayFrames
+ xor a
+ ldh [hSerialSend], a
+ ld a, (0 << rSC_ON) | (1 << rSC_CLOCK)
+ ldh [rSC], a
+ ld a, (1 << rSC_ON) | (1 << rSC_CLOCK)
+ ldh [rSC], a
+
+ call DelayFrame
+ xor a
+ ldh [hSerialSend], a
+ ld a, (0 << rSC_ON) | (1 << rSC_CLOCK)
+ ldh [rSC], a
+ ld a, (1 << rSC_ON) | (1 << rSC_CLOCK)
+ ldh [rSC], a
+
+.player_1
+ ld de, MUSIC_NONE
+ call PlayMusic
+ ld c, 3
+ call DelayFrames
+ xor a
+ ldh [rIF], a
+ ld a, 1 << SERIAL
+ ldh [rIE], a
+ ld hl, wd0dc
+ ld de, wEnemyMonSpecies
+ ld bc, $11
+ call Serial_ExchangeBytes
+ ld a, SERIAL_NO_DATA_BYTE
+ ld [de], a
+ ld hl, wLinkData
+ ld de, wOTPlayerName
+ ld bc, $1a8
+ call Serial_ExchangeBytes
+ ld a, SERIAL_NO_DATA_BYTE
+ ld [de], a
+ ld hl, wc508
+ ld de, wTrademons
+ ld bc, wTrademons - wc508
+ call Serial_ExchangeBytes
+ xor a
+ ldh [rIF], a
+ ld a, (1 << JOYPAD) | (1 << SERIAL) | (1 << TIMER) | (1 << VBLANK)
+ ldh [rIE], a
+ call Link_CopyRandomNumbers
+ ld hl, wOTPlayerName
+ call Link_FindFirstNonControlCharacter_SkipZero
+ push hl
+ ld bc, NAME_LENGTH
+ add hl, bc
+ ld a, [hl]
+ pop hl
+ and a
+ jp z, Function28a04
+ cp $7
+ jp nc, Function28a04
+ ld de, wLinkData
+ ld bc, $1a2
+ call Link_CopyOTData
+ ld de, wPlayerTrademonSpecies
+ ld hl, wTimeCapsulePartyMon1Species
+ ld c, 2
+.loop
+ ld a, [de]
+ inc de
+ and a
+ jr z, .loop
+ cp SERIAL_PREAMBLE_BYTE
+ jr z, .loop
+ cp SERIAL_NO_DATA_BYTE
+ jr z, .loop
+ cp SERIAL_PATCH_LIST_PART_TERMINATOR
+ jr z, .next
+ push hl
+ push bc
+ ld b, 0
+ dec a
+ ld c, a
+ add hl, bc
+ ld a, SERIAL_NO_DATA_BYTE
+ ld [hl], a
+ pop bc
+ pop hl
+ jr .loop
+
+.next
+ ld hl, wc80f
+ dec c
+ jr nz, .loop
+ ld hl, wLinkPlayerName
+ ld de, wOTPlayerName
+ ld bc, NAME_LENGTH
+ call CopyBytes
+ ld de, wOTPartyCount
+ ld a, [hli]
+ ld [de], a
+ inc de
+.party_loop
+ ld a, [hli]
+ cp -1
+ jr z, .done_party
+ ld [wTempSpecies], a
+ push hl
+ push de
+ callfar ConvertMon_1to2
+ pop de
+ pop hl
+ ld a, [wTempSpecies]
+ ld [de], a
+ inc de
+ jr .party_loop
+
+.done_party
+ ld [de], a
+ ld hl, wTimeCapsulePartyMon1Species
+ call Function285db
+ ld a, LOW(wOTPartyMonOT)
+ ld [wUnusedCFFE], a
+ ld a, HIGH(wOTPartyMonOT)
+ ld [wUnusedCFFE + 1], a
+ ld de, MUSIC_NONE
+ call PlayMusic
+ ldh a, [hSerialConnectionStatus]
+ cp USING_INTERNAL_CLOCK
+ ld c, 66
+ call z, DelayFrames
+ ld de, MUSIC_ROUTE_30
+ call PlayMusic
+ jp InitTradeMenuDisplay
+
+Gen2ToGen2LinkComms:
+ call ClearLinkData
+ call Link_PrepPartyData_Gen2
+ call FixDataForLinkTransfer
+ call Function29bf4
+ ld a, [wScriptVar]
+ and a
+ jp z, LinkTimeout
+ ldh a, [hSerialConnectionStatus]
+ cp USING_INTERNAL_CLOCK
+ jr nz, .Player1
+
+ ld c, 3
+ call DelayFrames
+ xor a
+ ldh [hSerialSend], a
+ ld a, (0 << rSC_ON) | (1 << rSC_CLOCK)
+ ldh [rSC], a
+ ld a, (1 << rSC_ON) | (1 << rSC_CLOCK)
+ ldh [rSC], a
+
+ call DelayFrame
+ xor a
+ ldh [hSerialSend], a
+ ld a, (0 << rSC_ON) | (1 << rSC_CLOCK)
+ ldh [rSC], a
+ ld a, (1 << rSC_ON) | (1 << rSC_CLOCK)
+ ldh [rSC], a
+
+.Player1:
+ ld de, MUSIC_NONE
+ call PlayMusic
+ ld c, 3
+ call DelayFrames
+ xor a
+ ldh [rIF], a
+ ld a, 1 << SERIAL
+ ldh [rIE], a
+ ld hl, wd0dc
+ ld de, wEnemyMonSpecies
+ ld bc, $11
+ call Serial_ExchangeBytes
+ ld a, SERIAL_NO_DATA_BYTE
+ ld [de], a
+ ld hl, wLinkData
+ ld de, wOTPlayerName
+ ld bc, $1c2
+ call Serial_ExchangeBytes
+ ld a, SERIAL_NO_DATA_BYTE
+ ld [de], a
+ ld hl, wc508
+ ld de, wTrademons
+ ld bc, wTrademons - wc508
+ call Serial_ExchangeBytes
+ ld a, [wLinkMode]
+ cp LINK_TRADECENTER
+ jr nz, .not_trading
+ ld hl, wc8f4
+ ld de, wca84
+ ld bc, $186
+ call ExchangeBytes
+
+.not_trading
+ xor a
+ ldh [rIF], a
+ ld a, (1 << JOYPAD) | (1 << SERIAL) | (1 << TIMER) | (1 << VBLANK)
+ ldh [rIE], a
+ ld de, MUSIC_NONE
+ call PlayMusic
+ call Link_CopyRandomNumbers
+ ld hl, wOTPlayerName
+ call Link_FindFirstNonControlCharacter_SkipZero
+ ld de, wLinkData
+ ld bc, $1b9
+ call Link_CopyOTData
+ ld de, wPlayerTrademonSpecies
+ ld hl, wLinkPlayerPartyMon1Species
+ ld c, 2
+.loop1
+ ld a, [de]
+ inc de
+ and a
+ jr z, .loop1
+ cp SERIAL_PREAMBLE_BYTE
+ jr z, .loop1
+ cp SERIAL_NO_DATA_BYTE
+ jr z, .loop1
+ cp SERIAL_PATCH_LIST_PART_TERMINATOR
+ jr z, .next1
+ push hl
+ push bc
+ ld b, 0
+ dec a
+ ld c, a
+ add hl, bc
+ ld a, SERIAL_NO_DATA_BYTE
+ ld [hl], a
+ pop bc
+ pop hl
+ jr .loop1
+
+.next1
+ ld hl, wc80f
+ dec c
+ jr nz, .loop1
+ ld a, [wLinkMode]
+ cp LINK_TRADECENTER
+ jr nz, .skip_mail
+ ld hl, wca84
+.loop2
+ ld a, [hli]
+ cp MAIL_MSG_LENGTH
+ jr nz, .loop2
+.loop3
+ ld a, [hli]
+ cp SERIAL_NO_DATA_BYTE
+ jr z, .loop3
+ cp MAIL_MSG_LENGTH
+ jr z, .loop3
+ dec hl
+ ld de, wca84
+ ld bc, $190 ; 400
+ call CopyBytes
+ ld hl, wca84
+ ld bc, $c6 ; 198
+.loop4
+ ld a, [hl]
+ cp MAIL_MSG_LENGTH + 1
+ jr nz, .okay1
+ ld [hl], SERIAL_NO_DATA_BYTE
+.okay1
+ inc hl
+ dec bc
+ ld a, b
+ or c
+ jr nz, .loop4
+ ld de, wcb9e
+.loop5
+ ld a, [de]
+ inc de
+ cp SERIAL_PATCH_LIST_PART_TERMINATOR
+ jr z, .start_copying_mail
+ ld hl, wcb4a
+ dec a
+ ld b, $0
+ ld c, a
+ add hl, bc
+ ld [hl], SERIAL_NO_DATA_BYTE
+ jr .loop5
+
+.start_copying_mail
+ ld hl, wca84
+ ld de, wc8f4
+ ld b, PARTY_LENGTH
+.copy_mail_loop
+ push bc
+ ld bc, MAIL_MSG_LENGTH + 1
+ call CopyBytes
+ ld a, LOW(MAIL_STRUCT_LENGTH - (MAIL_MSG_LENGTH + 1))
+ add e
+ ld e, a
+ ld a, HIGH(MAIL_STRUCT_LENGTH - (MAIL_MSG_LENGTH + 1))
+ adc d
+ ld d, a
+ pop bc
+ dec b
+ jr nz, .copy_mail_loop
+ ld de, wc8f4
+ ld b, PARTY_LENGTH
+.fix_mail_loop
+ push bc
+ ld a, LOW(MAIL_MSG_LENGTH + 1)
+ add e
+ ld e, a
+ ld a, HIGH(MAIL_MSG_LENGTH + 1)
+ adc d
+ ld d, a
+ ld bc, MAIL_STRUCT_LENGTH - (MAIL_MSG_LENGTH + 1)
+ call CopyBytes
+ pop bc
+ dec b
+ jr nz, .fix_mail_loop
+ ld de, wca0e
+ xor a
+ ld [de], a
+
+.skip_mail
+ ld hl, wLinkPlayerName
+ ld de, wOTPlayerName
+ ld bc, NAME_LENGTH
+ call CopyBytes
+ ld de, wOTPartyCount
+ ld bc, 1 + PARTY_LENGTH + 1
+ call CopyBytes
+ ld de, wOTPlayerID
+ ld bc, 2
+ call CopyBytes
+ ld de, wOTPartyMons
+ ld bc, wOTPartyDataEnd - wOTPartyMons
+ call CopyBytes
+ ld a, LOW(wOTPartyMonOT)
+ ld [wUnusedCFFE], a
+ ld a, HIGH(wOTPartyMonOT)
+ ld [wUnusedCFFE + 1], a
+ ld de, MUSIC_NONE
+ call PlayMusic
+ ldh a, [hSerialConnectionStatus]
+ cp USING_INTERNAL_CLOCK
+ ld c, 66
+ call z, DelayFrames
+ ld a, [wLinkMode]
+ cp LINK_COLOSSEUM
+ jr nz, .ready_to_trade
+ ld a, CAL
+ ld [wOtherTrainerClass], a
+ call ClearTilemap
+ call WaitBGMap
+ ld hl, wOptions
+ ld a, [hl]
+ push af
+ and 1 << STEREO
+ or TEXT_DELAY_MED
+ ld [hl], a
+ ld hl, wOTPlayerName
+ ld de, wOTClassName
+ ld bc, NAME_LENGTH
+ call CopyBytes
+ call ReturnToMapFromSubmenu
+
+ ; LET'S DO THIS
+ ld a, [wDisableTextAcceleration]
+ push af
+ ld a, 1
+ ld [wDisableTextAcceleration], a
+
+ predef StartBattle
+
+ pop af
+ ld [wDisableTextAcceleration], a
+ pop af
+ ld [wOptions], a
+ farcall LoadPokemonData
+ jp Function28a04
+
+.ready_to_trade
+ ld de, MUSIC_ROUTE_30
+ call PlayMusic
+ jp InitTradeMenuDisplay
+
+LinkTimeout:
+ ld de, .LinkTimeoutText
+ ld b, 10
+.loop
+ call DelayFrame
+ call LinkDataReceived
+ dec b
+ jr nz, .loop
+ xor a
+ ld [hld], a
+ ld [hl], a
+ ldh [hVBlank], a
+ push de
+ hlcoord 0, 12
+ ld b, 4
+ ld c, 18
+ call LinkTextboxAtHL
+ pop hl
+ bccoord 1, 14
+ jp PlaceHLTextAtBC
+
+.LinkTimeoutText:
+ text_far _LinkTimeoutText
+ text_end
+
+ExchangeBytes:
+ ld a, TRUE
+ ldh [hSerialIgnoringInitialData], a
+.loop
+ ld a, [hl]
+ ldh [hSerialSend], a
+ call Serial_ExchangeByte
+ push bc
+ ld b, a
+ inc hl
+ ld a, 48
+.delay_cycles
+ dec a
+ jr nz, .delay_cycles
+ ldh a, [hSerialIgnoringInitialData]
+ and a
+ ld a, b
+ pop bc
+ jr z, .load
+ dec hl
+ xor a
+ ldh [hSerialIgnoringInitialData], a
+ jr .loop
+
+.load
+ ld [de], a
+ inc de
+ dec bc
+ ld a, b
+ or c
+ jr nz, .loop
+ ret
+
+String_PleaseWait:
+ db "PLEASE WAIT!@"
+
+ClearLinkData:
+ ld hl, wLinkData
+ ld bc, wLinkDataEnd - wLinkData
+.loop
+ xor a
+ ld [hli], a
+ dec bc
+ ld a, b
+ or c
+ jr nz, .loop
+ ret
+
+FixDataForLinkTransfer:
+ ld hl, wd0dc
+ ld a, SERIAL_PREAMBLE_BYTE
+ ld b, wLinkBattleRNs - wd0dc
+.loop1
+ ld [hli], a
+ dec b
+ jr nz, .loop1
+ ld b, wTempEnemyMonSpecies - wLinkBattleRNs
+.loop2
+ call Random
+ cp SERIAL_PREAMBLE_BYTE
+ jr nc, .loop2
+ ld [hli], a
+ dec b
+ jr nz, .loop2
+ ld hl, wc508
+ ld a, SERIAL_PREAMBLE_BYTE
+ ld [hli], a
+ ld [hli], a
+ ld [hli], a
+ ld b, $c8
+ xor a
+.loop3
+ ld [hli], a
+ dec b
+ jr nz, .loop3
+ ld hl, wTimeCapsulePartyMon1 - 1 + PARTY_LENGTH
+ ld de, wc512
+ lb bc, 0, 0
+.loop4
+ inc c
+ ld a, c
+ cp SERIAL_PREAMBLE_BYTE
+ jr z, .next1
+ ld a, b
+ dec a
+ jr nz, .next2
+ push bc
+ ld a, [wLinkMode]
+ cp LINK_TIMECAPSULE
+ ld b, $d
+ jr z, .got_value
+ ld b, $27
+.got_value
+ ld a, c
+ cp b
+ pop bc
+ jr z, .done
+.next2
+ inc hl
+ ld a, [hl]
+ cp SERIAL_NO_DATA_BYTE
+ jr nz, .loop4
+ ld a, c
+ ld [de], a
+ inc de
+ ld [hl], SERIAL_PATCH_LIST_PART_TERMINATOR
+ jr .loop4
+
+.next1
+ ld a, SERIAL_PATCH_LIST_PART_TERMINATOR
+ ld [de], a
+ inc de
+ lb bc, 1, 0
+ jr .loop4
+
+.done
+ ld a, SERIAL_PATCH_LIST_PART_TERMINATOR
+ ld [de], a
+ ret
+
+Link_PrepPartyData_Gen1:
+ ld de, wLinkData
+ ld a, SERIAL_PREAMBLE_BYTE
+ ld b, PARTY_LENGTH
+.loop1
+ ld [de], a
+ inc de
+ dec b
+ jr nz, .loop1
+ ld hl, wPlayerName
+ ld bc, NAME_LENGTH
+ call CopyBytes
+ push de
+ ld hl, wPartyCount
+ ld a, [hli]
+ ld [de], a
+ inc de
+.loop2
+ ld a, [hli]
+ cp -1
+ jr z, .done_party
+ ld [wTempSpecies], a
+ push hl
+ push de
+ callfar ConvertMon_2to1
+ pop de
+ pop hl
+ ld a, [wTempSpecies]
+ ld [de], a
+ inc de
+ jr .loop2
+
+.done_party
+ ld [de], a
+ pop de
+ ld hl, 1 + PARTY_LENGTH + 1
+ add hl, de
+ ld d, h
+ ld e, l
+ ld hl, wPartyMon1Species
+ ld c, PARTY_LENGTH
+.mon_loop
+ push bc
+ call .ConvertPartyStruct2to1
+ ld bc, PARTYMON_STRUCT_LENGTH
+ add hl, bc
+ pop bc
+ dec c
+ jr nz, .mon_loop
+ ld hl, wPartyMonOT
+ call .copy_ot_nicks
+ ld hl, wPartyMonNicknames
+.copy_ot_nicks
+ ld bc, PARTY_LENGTH * NAME_LENGTH
+ jp CopyBytes
+
+.ConvertPartyStruct2to1:
+ ld b, h
+ ld c, l
+ push de
+ push bc
+ ld a, [hl]
+ ld [wTempSpecies], a
+ callfar ConvertMon_2to1
+ pop bc
+ pop de
+ ld a, [wTempSpecies]
+ ld [de], a
+ inc de
+ ld hl, MON_HP
+ add hl, bc
+ ld a, [hli]
+ ld [de], a
+ inc de
+ ld a, [hl]
+ ld [de], a
+ inc de
+ xor a
+ ld [de], a
+ inc de
+ ld hl, MON_STATUS
+ add hl, bc
+ ld a, [hl]
+ ld [de], a
+ inc de
+ ld a, [bc]
+ cp MAGNEMITE
+ jr z, .steel_type
+ cp MAGNETON
+ jr nz, .skip_steel
+
+.steel_type
+ ld a, ELECTRIC
+ ld [de], a
+ inc de
+ ld [de], a
+ inc de
+ jr .done_steel
+
+.skip_steel
+ push bc
+ dec a
+ ld hl, BaseData + BASE_TYPES
+ ld bc, BASE_DATA_SIZE
+ call AddNTimes
+ ld bc, BASE_CATCH_RATE - BASE_TYPES
+ ld a, BANK(BaseData)
+ call FarCopyBytes
+ pop bc
+
+.done_steel
+ push bc
+ ld hl, MON_ITEM
+ add hl, bc
+ ld bc, MON_HAPPINESS - MON_ITEM
+ call CopyBytes
+ pop bc
+
+ ld hl, MON_LEVEL
+ add hl, bc
+ ld a, [hl]
+ ld [de], a
+ ld [wCurPartyLevel], a
+ inc de
+
+ push bc
+ ld hl, MON_MAXHP
+ add hl, bc
+ ld bc, MON_SAT - MON_MAXHP
+ call CopyBytes
+ pop bc
+
+ push de
+ push bc
+
+ ld a, [bc]
+ dec a
+ push bc
+ ld b, 0
+ ld c, a
+ ld hl, KantoMonSpecials
+ add hl, bc
+ ld a, BANK(KantoMonSpecials)
+ call GetFarByte
+ ld [wBaseSpecialAttack], a
+ pop bc
+
+ ld hl, MON_STAT_EXP - 1
+ add hl, bc
+ ld c, STAT_SATK
+ ld b, TRUE
+ predef CalcMonStatC
+
+ pop bc
+ pop de
+
+ ldh a, [hQuotient + 2]
+ ld [de], a
+ inc de
+ ldh a, [hQuotient + 3]
+ ld [de], a
+ inc de
+ ld h, b
+ ld l, c
+ ret
+
+Link_PrepPartyData_Gen2:
+ ld de, wLinkData
+ ld a, SERIAL_PREAMBLE_BYTE
+ ld b, PARTY_LENGTH
+.loop1
+ ld [de], a
+ inc de
+ dec b
+ jr nz, .loop1
+ ld hl, wPlayerName
+ ld bc, NAME_LENGTH
+ call CopyBytes
+ ld hl, wPartyCount
+ ld bc, 1 + PARTY_LENGTH + 1
+ call CopyBytes
+ ld hl, wPlayerID
+ ld bc, 2
+ call CopyBytes
+ ld hl, wPartyMon1Species
+ ld bc, PARTY_LENGTH * PARTYMON_STRUCT_LENGTH
+ call CopyBytes
+ ld hl, wPartyMonOT
+ ld bc, PARTY_LENGTH * NAME_LENGTH
+ call CopyBytes
+ ld hl, wPartyMonNicknames
+ ld bc, PARTY_LENGTH * MON_NAME_LENGTH
+ call CopyBytes
+
+; Okay, we did all that. Now, are we in the trade center?
+ ld a, [wLinkMode]
+ cp LINK_TRADECENTER
+ ret nz
+
+; Fill 5 bytes at wc8f4 with $20
+ ld de, wc8f4
+ ld a, $20
+ call Function285d3
+
+; Copy all the mail messages to wc9f9
+ ld a, BANK(sPartyMail)
+ call OpenSRAM
+ ld hl, sPartyMail
+ ld b, PARTY_LENGTH
+.loop2
+ push bc
+ ld bc, MAIL_MSG_LENGTH + 1
+ call CopyBytes
+ ld bc, sPartyMon1MailEnd - sPartyMon1MailAuthor
+ add hl, bc
+ pop bc
+ dec b
+ jr nz, .loop2
+; Copy the mail data to wcabf
+ ld hl, sPartyMail
+ ld b, PARTY_LENGTH
+.loop3
+ push bc
+ ld bc, MAIL_MSG_LENGTH + 1
+ add hl, bc
+ ld bc, sPartyMon1MailEnd - sPartyMon1MailAuthor
+ call CopyBytes
+ pop bc
+ dec b
+ jr nz, .loop3
+
+ call CloseSRAM
+ ld hl, wc8f9
+ ld bc, PARTY_LENGTH * (sPartyMon1MailAuthor - sPartyMon1Mail)
+.loop4
+ ld a, [hl]
+ cp SERIAL_NO_DATA_BYTE
+ jr nz, .skip2
+ ld [hl], sPartyMon1MailAuthor - sPartyMon1Mail
+
+.skip2
+ inc hl
+ dec bc
+ ld a, b
+ or c
+ jr nz, .loop4
+ ld hl, wc9bf
+ ld de, wca13
+ ld b, PARTY_LENGTH * (sPartyMon1MailEnd - sPartyMon1MailAuthor)
+ ld c, $0
+.loop5
+ inc c
+ ld a, [hl]
+ cp SERIAL_NO_DATA_BYTE
+ jr nz, .skip3
+ ld [hl], SERIAL_PATCH_LIST_PART_TERMINATOR
+ ld a, c
+ ld [de], a
+ inc de
+
+.skip3
+ inc hl
+ dec b
+ jr nz, .loop5
+ ld a, SERIAL_PATCH_LIST_PART_TERMINATOR
+ ld [de], a
+ ret
+
+Function285d3:
+ ld c, 5
+.loop
+ ld [de], a
+ inc de
+ dec c
+ jr nz, .loop
+ ret
+
+Function285db:
+ push hl
+ ld d, h
+ ld e, l
+ ld bc, wLinkOTPartyMonTypes
+ ld hl, wcae8
+ ld a, c
+ ld [hli], a
+ ld [hl], b
+ ld hl, wOTPartyMon1Species
+ ld c, PARTY_LENGTH
+.loop
+ push bc
+ call .ConvertToGen2
+ pop bc
+ dec c
+ jr nz, .loop
+ pop hl
+ ld bc, PARTY_LENGTH * REDMON_STRUCT_LENGTH
+ add hl, bc
+ ld de, wOTPartyMonOT
+ ld bc, PARTY_LENGTH * NAME_LENGTH
+ call CopyBytes
+ ld de, wOTPartyMonNicknames
+ ld bc, PARTY_LENGTH * MON_NAME_LENGTH
+ jp CopyBytes
+
+.ConvertToGen2:
+ ld b, h
+ ld c, l
+ ld a, [de]
+ inc de
+ push bc
+ push de
+ ld [wTempSpecies], a
+ callfar ConvertMon_1to2
+ pop de
+ pop bc
+ ld a, [wTempSpecies]
+ ld [bc], a
+ ld [wCurSpecies], a
+ ld hl, MON_HP
+ add hl, bc
+ ld a, [de]
+ inc de
+ ld [hli], a
+ ld a, [de]
+ inc de
+ ld [hl], a
+ inc de
+ ld hl, MON_STATUS
+ add hl, bc
+ ld a, [de]
+ inc de
+ ld [hl], a
+ ld hl, wcae8
+ ld a, [hli]
+ ld h, [hl]
+ ld l, a
+ ld a, [de]
+ ld [hli], a
+ inc de
+ ld a, [de]
+ ld [hli], a
+ inc de
+ ld a, l
+ ld [wcae8], a
+ ld a, h
+ ld [wcae8 + 1], a
+ push bc
+ ld hl, MON_ITEM
+ add hl, bc
+ push hl
+ ld h, d
+ ld l, e
+ pop de
+ push bc
+ ld a, [hli]
+ ld b, a
+ call TimeCapsule_ReplaceTeruSama
+ ld a, b
+ ld [de], a
+ inc de
+ pop bc
+ ld bc, $19
+ call CopyBytes
+ pop bc
+ ld d, h
+ ld e, l
+ ld hl, $1f
+ add hl, bc
+ ld a, [de]
+ inc de
+ ld [hl], a
+ ld [wCurPartyLevel], a
+ push bc
+ ld hl, $24
+ add hl, bc
+ push hl
+ ld h, d
+ ld l, e
+ pop de
+ ld bc, 8
+ call CopyBytes
+ pop bc
+ call GetBaseData
+ push de
+ push bc
+ ld d, h
+ ld e, l
+ ld hl, MON_STAT_EXP - 1
+ add hl, bc
+ ld c, STAT_SATK
+ ld b, TRUE
+ predef CalcMonStatC
+ pop bc
+ pop hl
+ ldh a, [hQuotient + 2]
+ ld [hli], a
+ ldh a, [hQuotient + 3]
+ ld [hli], a
+ push hl
+ push bc
+ ld hl, MON_STAT_EXP - 1
+ add hl, bc
+ ld c, STAT_SDEF
+ ld b, TRUE
+ predef CalcMonStatC
+ pop bc
+ pop hl
+ ldh a, [hQuotient + 2]
+ ld [hli], a
+ ldh a, [hQuotient + 3]
+ ld [hli], a
+ push hl
+ ld hl, $1b
+ add hl, bc
+ ld a, $46
+ ld [hli], a
+ xor a
+ ld [hli], a
+ ld [hli], a
+ ld [hl], a
+ pop hl
+ inc de
+ inc de
+ ret
+
+TimeCapsule_ReplaceTeruSama:
+ ld a, b
+ and a
+ ret z
+ push hl
+ ld hl, TimeCapsule_CatchRateItems
+.loop
+ ld a, [hli]
+ and a
+ jr z, .end
+ cp b
+ jr z, .found
+ inc hl
+ jr .loop
+
+.found
+ ld b, [hl]
+
+.end
+ pop hl
+ ret
+
+INCLUDE "data/items/catch_rate_items.asm"
+
+Link_CopyOTData:
+.loop
+ ld a, [hli]
+ cp SERIAL_NO_DATA_BYTE
+ jr z, .loop
+ ld [de], a
+ inc de
+ dec bc
+ ld a, b
+ or c
+ jr nz, .loop
+ ret
+
+Link_CopyRandomNumbers:
+ ldh a, [hSerialConnectionStatus]
+ cp USING_INTERNAL_CLOCK
+ ret z
+ ld hl, wEnemyMonSpecies
+ call Link_FindFirstNonControlCharacter_AllowZero
+ ld de, wLinkBattleRNs
+ ld c, 10
+.loop
+ ld a, [hli]
+ cp SERIAL_NO_DATA_BYTE
+ jr z, .loop
+ cp SERIAL_PREAMBLE_BYTE
+ jr z, .loop
+ ld [de], a
+ inc de
+ dec c
+ jr nz, .loop
+ ret
+
+Link_FindFirstNonControlCharacter_SkipZero:
+.loop
+ ld a, [hli]
+ and a
+ jr z, .loop
+ cp SERIAL_PREAMBLE_BYTE
+ jr z, .loop
+ cp SERIAL_NO_DATA_BYTE
+ jr z, .loop
+ dec hl
+ ret
+
+Link_FindFirstNonControlCharacter_AllowZero:
+.loop
+ ld a, [hli]
+ cp SERIAL_PREAMBLE_BYTE
+ jr z, .loop
+ cp SERIAL_NO_DATA_BYTE
+ jr z, .loop
+ dec hl
+ ret
+
+InitTradeMenuDisplay:
+ call ClearTilemap
+ call LoadTradeScreenBorder
+ call Function28dcf
+ call Function28a16
+ xor a
+ ld hl, wOtherPlayerLinkMode
+ ld [hli], a
+ ld [hli], a
+ ld [hli], a
+ ld [hl], a
+ ld a, 1
+ ld [wMenuCursorY], a
+ inc a
+ ld [wPlayerLinkAction], a
+ jp LinkTrade_PlayerPartyMenu
+
+LinkTrade_OTPartyMenu:
+ ld a, OTPARTYMON
+ ld [wMonType], a
+ ld a, A_BUTTON | D_UP | D_DOWN
+ ld [wMenuJoypadFilter], a
+ ld a, [wOTPartyCount]
+ ld [w2DMenuNumRows], a
+ ld a, 1
+ ld [w2DMenuNumCols], a
+ ld a, 9
+ ld [w2DMenuCursorInitY], a
+ ld a, 6
+ ld [w2DMenuCursorInitX], a
+ ld a, 1
+ ld [wMenuCursorX], a
+ ln a, 1, 0
+ ld [w2DMenuCursorOffsets], a
+ ld a, MENU_UNUSED_3
+ ld [w2DMenuFlags1], a
+ xor a
+ ld [w2DMenuFlags2], a
+
+LinkTradeOTPartymonMenuLoop:
+ call ScrollingMenuJoypad
+ and a
+ jp z, LinkTradePartiesMenuMasterLoop
+ bit A_BUTTON_F, a
+ jr z, .not_a_button
+ ld a, INIT_ENEMYOT_LIST
+ ld [wInitListType], a
+ callfar InitList
+ ld hl, wOTPartyMon1Species
+ call LinkMonStatsScreen
+ jp LinkTradePartiesMenuMasterLoop
+
+.not_a_button
+ bit D_UP_F, a
+ jr z, .not_d_up
+ ld a, [wMenuCursorY]
+ ld b, a
+ ld a, [wOTPartyCount]
+ cp b
+ jp nz, LinkTradePartiesMenuMasterLoop
+ xor a
+ ld [wMonType], a
+ call HideCursor
+ ld a, [wPartyCount]
+ ld [wMenuCursorY], a
+ jr LinkTrade_PlayerPartyMenu
+
+.not_d_up
+ bit D_DOWN_F, a
+ jp z, LinkTradePartiesMenuMasterLoop
+ jp Function289c2
+
+LinkTrade_PlayerPartyMenu:
+ xor a
+ ld [wMonType], a
+ ld a, A_BUTTON | D_UP | D_DOWN
+ ld [wMenuJoypadFilter], a
+ ld a, [wPartyCount]
+ ld [w2DMenuNumRows], a
+ ld a, 1
+ ld [w2DMenuNumCols], a
+ ld a, 1
+ ld [w2DMenuCursorInitY], a
+ ld a, 6
+ ld [w2DMenuCursorInitX], a
+ ld a, 1
+ ld [wMenuCursorX], a
+ ln a, 1, 0
+ ld [w2DMenuCursorOffsets], a
+ ld a, MENU_UNUSED_3
+ ld [w2DMenuFlags1], a
+ xor a
+ ld [w2DMenuFlags2], a
+
+LinkTradePartymonMenuLoop:
+ call ScrollingMenuJoypad
+ and a
+ jr nz, .check_joypad
+ jp LinkTradePartiesMenuMasterLoop
+
+.check_joypad
+ bit A_BUTTON_F, a
+ jr z, .not_a_button
+ jp Function2884a
+
+.not_a_button
+ bit D_DOWN_F, a
+ jr z, .not_d_down
+ ld a, [wMenuCursorY]
+ dec a
+ jp nz, LinkTradePartiesMenuMasterLoop
+ ld a, OTPARTYMON
+ ld [wMonType], a
+ call HideCursor
+ ld a, 1
+ ld [wMenuCursorY], a
+ jp LinkTrade_OTPartyMenu
+
+.not_d_down
+ bit D_UP_F, a
+ jr z, LinkTradePartiesMenuMasterLoop
+ ld a, [wMenuCursorY]
+ ld b, a
+ ld a, [wPartyCount]
+ cp b
+ jr nz, LinkTradePartiesMenuMasterLoop
+ call HideCursor
+ ld a, 1
+ ld [wMenuCursorY], a
+ jp LinkTrade_PlayerPartyMenu
+
+LinkTradePartiesMenuMasterLoop:
+ ld a, [wMonType]
+ and a
+ jp z, LinkTradePartymonMenuLoop ; PARTYMON
+ jp LinkTradeOTPartymonMenuLoop ; OTPARTYMON
+
+Function2884a:
+ call HideCursor
+ call LoadTilemapToTempTilemap
+ call PlaceHollowCursor
+ ld a, [wMenuCursorY]
+ push af
+ hlcoord 0, 15
+ ld b, 1
+ ld c, 18
+ call LinkTextboxAtHL
+ hlcoord 2, 16
+ ld de, .String_Stats_Trade
+ call PlaceString
+
+.joy_loop
+ ld a, " "
+ ldcoord_a 11, 16
+ ld a, A_BUTTON | B_BUTTON | D_RIGHT
+ ld [wMenuJoypadFilter], a
+ ld a, 1
+ ld [w2DMenuNumRows], a
+ ld a, 1
+ ld [w2DMenuNumCols], a
+ ld a, 16
+ ld [w2DMenuCursorInitY], a
+ ld a, 1
+ ld [w2DMenuCursorInitX], a
+ ld a, 1
+ ld [wMenuCursorY], a
+ ld [wMenuCursorX], a
+ ln a, 2, 0
+ ld [w2DMenuCursorOffsets], a
+ xor a
+ ld [w2DMenuFlags1], a
+ ld [w2DMenuFlags2], a
+ call ScrollingMenuJoypad
+ bit D_RIGHT_F, a
+ jr nz, .d_right
+ bit B_BUTTON_F, a
+ jr z, .show_stats
+.b_button
+ pop af
+ ld [wMenuCursorY], a
+ call SafeLoadTempTilemapToTilemap
+ jp LinkTrade_PlayerPartyMenu
+
+.d_right
+ ld a, " "
+ ldcoord_a 1, 16
+ ld a, A_BUTTON | B_BUTTON | D_LEFT
+ ld [wMenuJoypadFilter], a
+ ld a, 1
+ ld [w2DMenuNumRows], a
+ ld a, 1
+ ld [w2DMenuNumCols], a
+ ld a, 16
+ ld [w2DMenuCursorInitY], a
+ ld a, 11
+ ld [w2DMenuCursorInitX], a
+ ld a, 1
+ ld [wMenuCursorY], a
+ ld [wMenuCursorX], a
+ ln a, 2, 0
+ ld [w2DMenuCursorOffsets], a
+ xor a
+ ld [w2DMenuFlags1], a
+ ld [w2DMenuFlags2], a
+ call ScrollingMenuJoypad
+ bit D_LEFT_F, a
+ jp nz, .joy_loop
+ bit B_BUTTON_F, a
+ jr nz, .b_button
+ jr .try_trade
+
+.show_stats
+ pop af
+ ld [wMenuCursorY], a
+ ld a, INIT_PLAYEROT_LIST
+ ld [wInitListType], a
+ callfar InitList
+ call LinkMonStatsScreen
+ call SafeLoadTempTilemapToTilemap
+ jp LinkTrade_PlayerPartyMenu
+
+.try_trade
+ call PlaceHollowCursor
+ pop af
+ ld [wMenuCursorY], a
+ dec a
+ ld [wceed], a
+ ld [wPlayerLinkAction], a
+ call Serial_PrintWaitingTextAndSyncAndExchangeNybble
+ ld a, [wOtherPlayerLinkMode]
+ cp $f
+ jp z, InitTradeMenuDisplay
+ ld [wceee], a
+ call Function28a3c
+ ld c, 100
+ call DelayFrames
+ farcall ValidateOTTrademon
+ jr c, .abnormal
+ farcall Functionfb6ed
+ jp nc, LinkTrade
+ xor a
+ ld [wce57], a
+ ld [wOtherPlayerLinkAction], a
+ hlcoord 0, 12
+ ld b, 4
+ ld c, 18
+ call LinkTextboxAtHL
+ ld hl, .LinkTradeCantBattleText
+ bccoord 1, 14
+ call PlaceHLTextAtBC
+ jr .cancel_trade
+
+.abnormal
+ xor a
+ ld [wce57], a
+ ld [wOtherPlayerLinkAction], a
+ ld a, [wceee]
+ ld hl, wOTPartySpecies
+ ld c, a
+ ld b, 0
+ add hl, bc
+ ld a, [hl]
+ ld [wNamedObjectIndexBuffer], a
+ call GetPokemonName
+ hlcoord 0, 12
+ ld b, 4
+ ld c, 18
+ call LinkTextboxAtHL
+ ld hl, .LinkAbnormalMonText
+ bccoord 1, 14
+ call PlaceHLTextAtBC
+
+.cancel_trade
+ hlcoord 0, 12
+ ld b, 4
+ ld c, 18
+ call LinkTextboxAtHL
+ hlcoord 1, 14
+ ld de, String_TooBadTheTradeWasCanceled
+ call PlaceString
+ ld a, $1
+ ld [wPlayerLinkAction], a
+ call Serial_PrintWaitingTextAndSyncAndExchangeNybble
+ ld c, 100
+ call DelayFrames
+ jp InitTradeMenuDisplay
+
+.LinkTradeCantBattleText:
+ text_far _LinkTradeCantBattleText
+ text_end
+
+.String_Stats_Trade:
+ db "STATS TRADE@"
+
+.LinkAbnormalMonText:
+ text_far _LinkAbnormalMonText
+ text_end
+
+Function289c2:
+ ld a, [wMenuCursorY]
+ cp 1
+ jp nz, LinkTradePartiesMenuMasterLoop
+ call HideCursor
+Function289cd:
+.loop1
+ ld a, "▶"
+ ldcoord_a 1, 16
+.loop2
+ call JoyTextDelay
+ ldh a, [hJoyLast]
+ and a
+ jr z, .loop2
+ bit A_BUTTON_F, a
+ jr nz, .a_button
+ bit D_UP_F, a
+ jr z, .loop2
+ ld a, " "
+ ldcoord_a 1, 16
+ ld a, [wOTPartyCount]
+ ld [wMenuCursorY], a
+ jp LinkTrade_OTPartyMenu
+
+.a_button
+ ld a, "▷"
+ ldcoord_a 1, 16
+ ld a, $f
+ ld [wPlayerLinkAction], a
+ call Serial_PrintWaitingTextAndSyncAndExchangeNybble
+ ld a, [wOtherPlayerLinkMode]
+ cp $f
+ jr nz, .loop1
+Function28a04:
+ xor a
+ ld [wd8b7], a
+ xor a
+ ldh [rSB], a
+ ldh [hSerialSend], a
+ ld a, (0 << rSC_ON) | (1 << rSC_CLOCK)
+ ldh [rSC], a
+ ld a, (1 << rSC_ON) | (1 << rSC_CLOCK)
+ ldh [rSC], a
+ ret
+
+Function28a16:
+ hlcoord 0, 16
+ ld a, "┘"
+ ld bc, 2 * SCREEN_WIDTH
+ call ByteFill
+ hlcoord 1, 16
+ ld a, " "
+ ld bc, SCREEN_WIDTH - 2
+ call ByteFill
+ hlcoord 2, 16
+ ld de, .Cancel
+ jp PlaceString
+
+.Cancel:
+ db "CANCEL@"
+
+Function28a3c:
+ ld a, [wOtherPlayerLinkMode]
+ hlcoord 6, 9
+ ld bc, SCREEN_WIDTH
+ call AddNTimes
+ ld [hl], "▷"
+ ret
+
+LinkMonStatsScreen:
+ ld a, [wMenuCursorY]
+ dec a
+ ld [wCurPartyMon], a
+ call LowVolume
+ predef StatsScreenInit
+ ld a, [wCurPartyMon]
+ inc a
+ ld [wMenuCursorY], a
+ call ClearTilemap
+ call ClearBGPalettes
+ call MaxVolume
+ call LoadTradeScreenBorder
+ call SetTradeRoomBGPals
+ call WaitBGMap
+ call Function28dcf
+ jp Function28a16
+
+LinkTrade:
+ xor a
+ ld [wce57], a
+ ld [wOtherPlayerLinkAction], a
+ hlcoord 0, 12
+ ld b, 4
+ ld c, 18
+ call LinkTextboxAtHL
+ ld a, [wceed]
+ ld hl, wPartySpecies
+ ld c, a
+ ld b, 0
+ add hl, bc
+ ld a, [hl]
+ ld [wNamedObjectIndexBuffer], a
+ call GetPokemonName
+ ld hl, wStringBuffer1
+ ld de, wceef
+ ld bc, MON_NAME_LENGTH
+ call CopyBytes
+ ld a, [wceee]
+ ld hl, wOTPartySpecies
+ ld c, a
+ ld b, 0
+ add hl, bc
+ ld a, [hl]
+ ld [wNamedObjectIndexBuffer], a
+ call GetPokemonName
+ ld hl, LinkAskTradeForText
+ bccoord 1, 14
+ call PlaceHLTextAtBC
+ call LoadTilemapToTempTilemap
+ hlcoord 10, 7
+ ld b, 3
+ ld c, 7
+ call LinkTextboxAtHL
+ ld de, String28d44
+ hlcoord 12, 8
+ call PlaceString
+ ld a, 8
+ ld [w2DMenuCursorInitY], a
+ ld a, 11
+ ld [w2DMenuCursorInitX], a
+ ld a, 1
+ ld [w2DMenuNumCols], a
+ ld a, 2
+ ld [w2DMenuNumRows], a
+ xor a
+ ld [w2DMenuFlags1], a
+ ld [w2DMenuFlags2], a
+ ld a, $20
+ ld [w2DMenuCursorOffsets], a
+ ld a, A_BUTTON | B_BUTTON
+ ld [wMenuJoypadFilter], a
+ ld a, 1
+ ld [wMenuCursorY], a
+ ld [wMenuCursorX], a
+ call ScrollingMenuJoypad
+ push af
+ call SafeLoadTempTilemapToTilemap
+ pop af
+ bit 1, a
+ jr nz, .asm_28b16
+ ld a, [wMenuCursorY]
+ dec a
+ jr z, .asm_28b34
+
+.asm_28b16
+ ld a, $1
+ ld [wPlayerLinkAction], a
+ hlcoord 0, 12
+ ld b, 4
+ ld c, 18
+ call LinkTextboxAtHL
+ hlcoord 1, 14
+ ld de, String_TooBadTheTradeWasCanceled
+ call PlaceString
+ call Serial_PrintWaitingTextAndSyncAndExchangeNybble
+ jp Function28d3c
+
+.asm_28b34
+ ld a, $2
+ ld [wPlayerLinkAction], a
+ call Serial_PrintWaitingTextAndSyncAndExchangeNybble
+ ld a, [wOtherPlayerLinkMode]
+ dec a
+ jr nz, .asm_28b58
+ hlcoord 0, 12
+ ld b, 4
+ ld c, 18
+ call LinkTextboxAtHL
+ hlcoord 1, 14
+ ld de, String_TooBadTheTradeWasCanceled
+ call PlaceString
+ jp Function28d3c
+
+.asm_28b58
+ ld hl, sPartyMail
+ ld a, [wceed]
+ ld bc, MAIL_STRUCT_LENGTH
+ call AddNTimes
+ ld a, BANK(sPartyMail)
+ call OpenSRAM
+ ld d, h
+ ld e, l
+ ld bc, MAIL_STRUCT_LENGTH
+ add hl, bc
+ ld a, [wceed]
+ ld c, a
+.asm_28b73
+ inc c
+ ld a, c
+ cp PARTY_LENGTH
+ jr z, .asm_28b83
+ push bc
+ ld bc, MAIL_STRUCT_LENGTH
+ call CopyBytes
+ pop bc
+ jr .asm_28b73
+
+.asm_28b83
+ ld hl, sPartyMail
+ ld a, [wPartyCount]
+ dec a
+ ld bc, MAIL_STRUCT_LENGTH
+ call AddNTimes
+ push hl
+ ld hl, wc8f4
+ ld a, [wceee]
+ ld bc, MAIL_STRUCT_LENGTH
+ call AddNTimes
+ pop de
+ ld bc, MAIL_STRUCT_LENGTH
+ call CopyBytes
+ call CloseSRAM
+ ld hl, wPlayerName
+ ld de, wPlayerTrademonSenderName
+ ld bc, NAME_LENGTH
+ call CopyBytes
+ ld a, [wceed]
+ ld hl, wPartySpecies
+ ld b, 0
+ ld c, a
+ add hl, bc
+ ld a, [hl]
+ ld [wPlayerTrademonSpecies], a
+ push af
+ ld a, [wceed]
+ ld hl, wPartyMonOT
+ call SkipNames
+ ld de, wPlayerTrademonOTName
+ ld bc, NAME_LENGTH
+ call CopyBytes
+ ld hl, wPartyMon1ID
+ ld a, [wceed]
+ call GetPartyLocation
+ ld a, [hli]
+ ld [wPlayerTrademonID], a
+ ld a, [hl]
+ ld [wPlayerTrademonID + 1], a
+ ld hl, wPartyMon1DVs
+ ld a, [wceed]
+ call GetPartyLocation
+ ld a, [hli]
+ ld [wPlayerTrademonDVs], a
+ ld a, [hl]
+ ld [wPlayerTrademonDVs + 1], a
+ ld hl, wOTPlayerName
+ ld de, wOTTrademonSenderName
+ ld bc, NAME_LENGTH
+ call CopyBytes
+ ld a, [wceee]
+ ld hl, wOTPartySpecies
+ ld b, 0
+ ld c, a
+ add hl, bc
+ ld a, [hl]
+ ld [wOTTrademonSpecies], a
+ ld a, [wceee]
+ ld hl, wOTPartyMonOT
+ call SkipNames
+ ld de, wOTTrademonOTName
+ ld bc, NAME_LENGTH
+ call CopyBytes
+ ld hl, wOTPartyMon1ID
+ ld a, [wceee]
+ call GetPartyLocation
+ ld a, [hli]
+ ld [wOTTrademonID], a
+ ld a, [hl]
+ ld [wOTTrademonID + 1], a
+ ld hl, wOTPartyMon1DVs
+ ld a, [wceee]
+ call GetPartyLocation
+ ld a, [hli]
+ ld [wOTTrademonDVs], a
+ ld a, [hl]
+ ld [wOTTrademonDVs + 1], a
+ ld a, [wceed]
+ ld [wCurPartyMon], a
+ ld hl, wPartySpecies
+ ld b, 0
+ ld c, a
+ add hl, bc
+ ld a, [hl]
+ ld [wceed], a
+ xor a ; REMOVE_PARTY
+ ld [wPokemonWithdrawDepositParameter], a
+ callfar RemoveMonFromPartyOrBox
+ ld a, [wPartyCount]
+ dec a
+ ld [wCurPartyMon], a
+ ld a, TRUE
+ ld [wForceEvolution], a
+ ld a, [wceee]
+ push af
+ ld hl, wOTPartySpecies
+ ld b, 0
+ ld c, a
+ add hl, bc
+ ld a, [hl]
+ ld [wceee], a
+ ld c, 100
+ call DelayFrames
+ call ClearTilemap
+ call LoadFontsBattleExtra
+ ldh a, [hSerialConnectionStatus]
+ cp USING_EXTERNAL_CLOCK
+ jr z, .player_2
+ predef TradeAnimation
+ jr .done_animation
+
+.player_2
+ predef TradeAnimationPlayer2
+
+.done_animation
+ pop af
+ ld c, a
+ ld [wCurPartyMon], a
+ ld hl, wOTPartySpecies
+ ld d, 0
+ ld e, a
+ add hl, de
+ ld a, [hl]
+ ld [wCurPartySpecies], a
+ ld hl, wOTPartyMon1Species
+ ld a, c
+ call GetPartyLocation
+ ld de, wTempMonSpecies
+ ld bc, PARTYMON_STRUCT_LENGTH
+ call CopyBytes
+ predef AddTempmonToParty
+ ld a, [wPartyCount]
+ dec a
+ ld [wCurPartyMon], a
+ callfar EvolvePokemon
+ call ClearTilemap
+ call LoadTradeScreenBorder
+ call SetTradeRoomBGPals
+ call WaitBGMap
+ ld b, $1
+ pop af
+ ld c, a
+ cp MEW
+ jr z, .loop
+ ld a, [wCurPartySpecies]
+ cp MEW
+ jr z, .loop
+ ld b, $2
+ ld a, c
+ cp CELEBI
+ jr z, .loop
+ ld a, [wCurPartySpecies]
+ cp CELEBI
+ jr z, .loop
+ ld b, $0
+
+.loop
+ ld a, b
+ ld [wPlayerLinkAction], a
+ push bc
+ call Serial_PrintWaitingTextAndSyncAndExchangeNybble
+ pop bc
+ ld a, [wLinkMode]
+ cp LINK_TIMECAPSULE
+ jr z, .save
+ ld a, b
+ and a
+ jr z, .save
+ ld a, [wOtherPlayerLinkAction]
+ cp b
+ jr nz, .loop
+
+.save
+ farcall SaveAfterLinkTrade
+ ld c, 40
+ call DelayFrames
+ hlcoord 0, 12
+ ld b, 4
+ ld c, 18
+ call LinkTextboxAtHL
+ hlcoord 1, 14
+ ld de, String28d56
+ call PlaceString
+ ld c, 50
+ call DelayFrames
+ ld a, [wLinkMode]
+ cp LINK_TIMECAPSULE
+ jp z, Gen2ToGen1LinkComms
+ jp Gen2ToGen2LinkComms
+
+Function28d3c:
+ ld c, 100
+ call DelayFrames
+ jp InitTradeMenuDisplay
+
+String28d44:
+ db "TRADE"
+ next "CANCEL@"
+
+LinkAskTradeForText:
+ text_far _LinkAskTradeForText
+ text_end
+
+String28d56:
+ db "Trade completed!@"
+
+String_TooBadTheTradeWasCanceled:
+ db "Too bad! The trade"
+ next "was canceled!@"
+
+LinkTextboxAtHL:
+ push hl
+ ld a, $78
+ ld [hli], a
+ inc a
+ call .PlaceRow
+ inc a
+ ld [hl], a
+ pop hl
+ ld de, SCREEN_WIDTH
+ add hl, de
+.loop
+ push hl
+ ld a, $7b
+ ld [hli], a
+ ld a, " "
+ call .PlaceRow
+ ld [hl], $77
+ pop hl
+ ld de, SCREEN_WIDTH
+ add hl, de
+ dec b
+ jr nz, .loop
+
+ ld a, $7c
+ ld [hli], a
+ ld a, $76
+ call .PlaceRow
+ ld [hl], $7d
+ ret
+
+.PlaceRow
+ ld d, c
+.row_loop
+ ld [hli], a
+ dec d
+ jr nz, .row_loop
+ ret
+
+LoadTradeScreenBorder:
+ ld de, LinkCommsBorderGFX
+ ld hl, vTiles2 tile $76
+ lb bc, BANK(LinkCommsBorderGFX), 9
+ jp Get2bpp
+
+SetTradeRoomBGPals:
+ ld b, SCGB_DIPLOMA
+ call GetSGBLayout
+ jp SetPalettes
+
+Function28dcf:
+ hlcoord 0, 0
+ ld b, 6
+ ld c, 18
+ call LinkTextboxAtHL
+ hlcoord 0, 8
+ ld b, 6
+ ld c, 18
+ call LinkTextboxAtHL
+ farcall PlaceTradePartnerNamesAndParty
+ ret
+
+INCLUDE "engine/movie/trade_animation.asm"
+
+CheckTimeCapsuleCompatibility:
+; Checks to see if your party is compatible with the Gen 1 games.
+; Returns the following in wScriptVar:
+; 0: Party is okay
+; 1: At least one Pokémon was introduced in Gen 2
+; 2: At least one Pokémon has a move that was introduced in Gen 2
+; 3: At least one Pokémon is holding mail
+
+; If any party Pokémon was introduced in the Gen 2 games, don't let it in.
+ ld hl, wPartySpecies
+ ld b, PARTY_LENGTH
+.loop
+ ld a, [hli]
+ cp -1
+ jr z, .checkitem
+ cp JOHTO_POKEMON
+ jr nc, .mon_too_new
+ dec b
+ jr nz, .loop
+
+; If any party Pokémon is holding mail, don't let it in.
+.checkitem
+ ld a, [wPartyCount]
+ ld b, a
+ ld hl, wPartyMon1Item
+.itemloop
+ push hl
+ push bc
+ ld d, [hl]
+ farcall ItemIsMail
+ pop bc
+ pop hl
+ jr c, .mon_has_mail
+ ld de, PARTYMON_STRUCT_LENGTH
+ add hl, de
+ dec b
+ jr nz, .itemloop
+
+; If any party Pokémon has a move that was introduced in the Gen 2 games, don't let it in.
+ ld hl, wPartyMon1Moves
+ ld a, [wPartyCount]
+ ld b, a
+.move_loop
+ ld c, NUM_MOVES
+.move_next
+ ld a, [hli]
+ cp STRUGGLE + 1
+ jr nc, .move_too_new
+ dec c
+ jr nz, .move_next
+ ld de, PARTYMON_STRUCT_LENGTH - NUM_MOVES
+ add hl, de
+ dec b
+ jr nz, .move_loop
+ xor a
+ jr .done
+
+.mon_too_new
+ ld [wNamedObjectIndexBuffer], a
+ call GetPokemonName
+ ld a, $1
+ jr .done
+
+.move_too_new
+ push bc
+ ld [wNamedObjectIndexBuffer], a
+ call GetMoveName
+ call CopyName1
+ pop bc
+ call Function29ab3
+ ld a, $2
+ jr .done
+
+.mon_has_mail
+ call Function29ab3
+ ld a, $3
+
+.done
+ ld [wScriptVar], a
+ ret
+
+Function29ab3:
+ ld a, [wPartyCount]
+ sub b
+ ld c, a
+ inc c
+ ld b, 0
+ ld hl, wPartyCount
+ add hl, bc
+ ld a, [hl]
+ ld [wNamedObjectIndexBuffer], a
+ call GetPokemonName
+ ret
+
+EnterTimeCapsule:
+ ld a, $4
+ call Link_EnsureSync
+ ld c, 40
+ call DelayFrames
+ xor a
+ ldh [hVBlank], a
+ inc a ; LINK_TIMECAPSULE
+ ld [wLinkMode], a
+ ret
+
+WaitForOtherPlayerToExit:
+ ld c, 3
+ call DelayFrames
+ ld a, CONNECTION_NOT_ESTABLISHED
+ ldh [hSerialConnectionStatus], a
+ xor a
+ ldh [rSB], a
+ ldh [hSerialReceive], a
+ ld a, (0 << rSC_ON) | (1 << rSC_CLOCK)
+ ldh [rSC], a
+ ld a, (1 << rSC_ON) | (1 << rSC_CLOCK)
+ ldh [rSC], a
+ ld c, 3
+ call DelayFrames
+ xor a
+ ldh [rSB], a
+ ldh [hSerialReceive], a
+ ld a, (0 << rSC_ON) | (0 << rSC_CLOCK)
+ ldh [rSC], a
+ ld a, (1 << rSC_ON) | (0 << rSC_CLOCK)
+ ldh [rSC], a
+ ld c, 3
+ call DelayFrames
+ xor a
+ ldh [rSB], a
+ ldh [hSerialReceive], a
+ ldh [rSC], a
+ ld c, 3
+ call DelayFrames
+ ld a, CONNECTION_NOT_ESTABLISHED
+ ldh [hSerialConnectionStatus], a
+ ld hl, wLinkTimeoutFrames
+ xor a
+ ld [hli], a
+ ld [hl], a
+ ldh [hVBlank], a
+ ld [wLinkMode], a
+ ret
+
+SetBitsForLinkTradeRequest:
+ ld a, LINK_TRADECENTER - 1
+ ld [wPlayerLinkAction], a
+ ld [wChosenCableClubRoom], a
+ ret
+
+SetBitsForBattleRequest:
+ ld a, LINK_COLOSSEUM - 1
+ ld [wPlayerLinkAction], a
+ ld [wChosenCableClubRoom], a
+ ret
+
+SetBitsForTimeCapsuleRequest:
+ ld a, $2
+ ldh [rSB], a
+ xor a
+ ldh [hSerialReceive], a
+ ld a, (0 << rSC_ON) | (0 << rSC_CLOCK)
+ ldh [rSC], a
+ ld a, (1 << rSC_ON) | (0 << rSC_CLOCK)
+ ldh [rSC], a
+ xor a ; LINK_TIMECAPSULE - 1
+ ld [wPlayerLinkAction], a
+ ld [wChosenCableClubRoom], a
+ ret
+
+WaitForLinkedFriend:
+ ld a, [wPlayerLinkAction]
+ and a
+ jr z, .no_link_action
+ ld a, $2
+ ldh [rSB], a
+ xor a
+ ldh [hSerialReceive], a
+ ld a, (0 << rSC_ON) | (0 << rSC_CLOCK)
+ ldh [rSC], a
+ ld a, (1 << rSC_ON) | (0 << rSC_CLOCK)
+ ldh [rSC], a
+ call DelayFrame
+ call DelayFrame
+ call DelayFrame
+
+.no_link_action
+ ld a, $2
+ ld [wLinkTimeoutFrames + 1], a
+ ld a, $ff
+ ld [wLinkTimeoutFrames], a
+.loop
+ ldh a, [hSerialConnectionStatus]
+ cp USING_INTERNAL_CLOCK
+ jr z, .connected
+ cp USING_EXTERNAL_CLOCK
+ jr z, .connected
+ ld a, CONNECTION_NOT_ESTABLISHED
+ ldh [hSerialConnectionStatus], a
+ ld a, $2
+ ldh [rSB], a
+ xor a
+ ldh [hSerialReceive], a
+ ld a, (0 << rSC_ON) | (0 << rSC_CLOCK)
+ ldh [rSC], a
+ ld a, (1 << rSC_ON) | (0 << rSC_CLOCK)
+ ldh [rSC], a
+ ld a, [wLinkTimeoutFrames]
+ dec a
+ ld [wLinkTimeoutFrames], a
+ jr nz, .not_done
+ ld a, [wLinkTimeoutFrames + 1]
+ dec a
+ ld [wLinkTimeoutFrames + 1], a
+ jr z, .done
+
+.not_done
+ ld a, $1
+ ldh [rSB], a
+ ld a, (0 << rSC_ON) | (1 << rSC_CLOCK)
+ ldh [rSC], a
+ ld a, (1 << rSC_ON) | (1 << rSC_CLOCK)
+ ldh [rSC], a
+ call DelayFrame
+ jr .loop
+
+.connected
+ call LinkDataReceived
+ call DelayFrame
+ call LinkDataReceived
+ ld c, 50
+ call DelayFrames
+ ld a, $1
+ ld [wScriptVar], a
+ ret
+
+.done
+ xor a
+ ld [wScriptVar], a
+ ret
+
+CheckLinkTimeout:
+ ld a, $1
+ ld [wPlayerLinkAction], a
+ ld hl, wLinkTimeoutFrames
+ ld a, $3
+ ld [hli], a
+ xor a
+ ld [hl], a
+ call WaitBGMap
+ ld a, $2
+ ldh [hVBlank], a
+ call DelayFrame
+ call DelayFrame
+ call Link_CheckCommunicationError
+ xor a
+ ldh [hVBlank], a
+ ld a, [wScriptVar]
+ and a
+ ret nz
+ jp Link_ResetSerialRegistersAfterLinkClosure
+
+Function29bf4:
+ ld a, $5
+ ld [wPlayerLinkAction], a
+ ld hl, wLinkTimeoutFrames
+ ld a, $3
+ ld [hli], a
+ xor a
+ ld [hl], a
+ call WaitBGMap
+ ld a, $2
+ ldh [hVBlank], a
+ call DelayFrame
+ call DelayFrame
+ call Link_CheckCommunicationError
+ ld a, [wScriptVar]
+ and a
+ jr z, .vblank
+ ld bc, -1
+.wait
+ dec bc
+ ld a, b
+ or c
+ jr nz, .wait
+ ld a, [wOtherPlayerLinkMode]
+ cp $5
+ jr nz, .script_var
+ ld a, $6
+ ld [wPlayerLinkAction], a
+ ld hl, wLinkTimeoutFrames
+ ld a, $1
+ ld [hli], a
+ ld [hl], $32
+ call Link_CheckCommunicationError
+ ld a, [wOtherPlayerLinkMode]
+ cp $6
+ jr z, .vblank
+
+.script_var
+ xor a
+ ld [wScriptVar], a
+ ret
+
+.vblank
+ xor a
+ ldh [hVBlank], a
+ ret
+
+Link_CheckCommunicationError:
+ xor a
+ ldh [hSerialReceivedNewData], a
+ call WaitLinkTransfer
+ ld hl, wLinkTimeoutFrames
+ ld a, [hli]
+ inc a
+ jr nz, .load_true
+ ld a, [hl]
+ inc a
+ jr nz, .load_true
+ ld b, 10
+
+.acknowledge_serial
+.loop
+ call DelayFrame
+ call LinkDataReceived
+ dec b
+ jr nz, .loop
+
+ xor a
+ jr .load_scriptvar
+
+.load_true
+ ld a, $1
+
+.load_scriptvar
+ ld [wScriptVar], a
+ ld hl, wLinkTimeoutFrames
+ xor a
+ ld [hli], a
+ ld [hl], a
+ ret
+
+TryQuickSave:
+ ld a, [wChosenCableClubRoom]
+ push af
+ farcall Link_SaveGame
+ ld a, TRUE
+ jr nc, .return_result
+ xor a ; FALSE
+.return_result
+ ld [wScriptVar], a
+ ld c, 30
+ call DelayFrames
+ pop af
+ ld [wChosenCableClubRoom], a
+ ret
+
+CheckBothSelectedSameRoom:
+ ld a, [wChosenCableClubRoom]
+ call Link_EnsureSync
+ push af
+ call LinkDataReceived
+ call DelayFrame
+ call LinkDataReceived
+ pop af
+ ld b, a
+ ld a, [wChosenCableClubRoom]
+ cp b
+ jr nz, .fail
+ ld a, [wChosenCableClubRoom]
+ inc a
+ ld [wLinkMode], a
+ xor a
+ ldh [hVBlank], a
+ ld a, TRUE
+ ld [wScriptVar], a
+ ret
+
+.fail
+ xor a ; FALSE
+ ld [wScriptVar], a
+ ret
+
+TimeCapsule:
+ ld a, LINK_TIMECAPSULE
+ ld [wLinkMode], a
+ call DisableSpriteUpdates
+ callfar LinkCommunications
+ call EnableSpriteUpdates
+ xor a
+ ldh [hVBlank], a
+ ret
+
+TradeCenter:
+ ld a, LINK_TRADECENTER
+ ld [wLinkMode], a
+ call DisableSpriteUpdates
+ callfar LinkCommunications
+ call EnableSpriteUpdates
+ xor a
+ ldh [hVBlank], a
+ ret
+
+Colosseum:
+ ld a, LINK_COLOSSEUM
+ ld [wLinkMode], a
+ call DisableSpriteUpdates
+ callfar LinkCommunications
+ call EnableSpriteUpdates
+ xor a
+ ldh [hVBlank], a
+ ret
+
+CloseLink:
+ ld c, 3
+ call DelayFrames
+ jp Link_ResetSerialRegistersAfterLinkClosure
+
+FailedLinkToPast:
+ ld c, 40
+ call DelayFrames
+ ld a, $e
+ jp Link_EnsureSync
+
+Link_ResetSerialRegistersAfterLinkClosure:
+ ld c, 3
+ call DelayFrames
+ ld a, CONNECTION_NOT_ESTABLISHED
+ ldh [hSerialConnectionStatus], a
+ ld a, $2
+ ldh [rSB], a
+ xor a
+ ldh [hSerialReceive], a
+ ldh [rSC], a
+ ret
+
+Link_EnsureSync:
+ add $d0
+ ld [wPlayerLinkAction], a
+ ld [wce57], a
+ ld a, $2
+ ldh [hVBlank], a
+ call DelayFrame
+ call DelayFrame
+.receive_loop
+ call Serial_ExchangeLinkMenuSelection
+ ld a, [wOtherPlayerLinkMode]
+ ld b, a
+ and $f0
+ cp $d0
+ jr z, .done
+ ld a, [wOtherPlayerLinkAction]
+ ld b, a
+ and $f0
+ cp $d0
+ jr nz, .receive_loop
+
+.done
+ xor a
+ ldh [hVBlank], a
+ ld a, b
+ and $f
+ ret
+
+CableClubCheckWhichChris:
+ ldh a, [hSerialConnectionStatus]
+ cp USING_EXTERNAL_CLOCK
+ ld a, TRUE
+ jr z, .yes
+ dec a ; FALSE
+
+.yes
+ ld [wScriptVar], a
+ ret
+
+LinkCommsBorderGFX:
+INCBIN "gfx/trade/border_tiles.2bpp"
+
+Unreferenced_Function29fe4:
+ ld a, BANK(sPartyMail)
+ call OpenSRAM
+ ld d, FALSE
+ ld b, CHECK_FLAG
+ predef SmallFarFlagAction
+ call CloseSRAM
+ ld a, c
+ and a
+ ret
diff --git a/engine/link/mystery_gift.asm b/engine/link/mystery_gift.asm
new file mode 100644
index 00000000..55a35982
--- /dev/null
+++ b/engine/link/mystery_gift.asm
@@ -0,0 +1,1077 @@
+DoMysteryGift:
+ call ClearTilemap
+ call ClearSprites
+ call WaitBGMap
+ farcall InitMysteryGiftLayout
+ hlcoord 3, 8
+ ld de, .String_PressAToLink_BToCancel
+ call PlaceString
+ call WaitBGMap
+ farcall PrepMysteryGiftDataToSend
+ call MysteryGift_ClearTrainerData
+ ld a, $2
+ ld [wc901], a
+ ld a, $14
+ ld [wc902], a
+ ldh a, [rIE]
+ push af
+
+ call Function29fc9
+
+ ld d, a
+ xor a
+ ldh [rIF], a
+ pop af
+ ldh [rIE], a
+ push de
+ call ClearTilemap
+ call EnableLCD
+ call WaitBGMap
+ ld b, SCGB_DIPLOMA
+ call GetSGBLayout
+ call SetPalettes
+ pop de
+ hlcoord 2, 8
+ ld a, d
+ ld de, .MysteryGiftCanceledText ; Link has been canceled
+ cp $10
+ jp z, .LinkCanceled
+ cp $6c
+ jp nz, .CommunicationError
+ ld a, [wc800]
+ cp 3
+ jr z, .skip_checks
+ call .CheckAlreadyGotFiveGiftsToday
+ ld hl, .MysteryGiftFiveADayText ; Only 5 gifts a day
+ jp nc, .PrintTextAndExit
+ call .CheckAlreadyGotAGiftFromThatPerson
+ ld hl, .MysteryGiftOneADayText ; Only one gift a day per person
+ jp c, .PrintTextAndExit
+.skip_checks
+ ld a, [wMysteryGiftPlayerBackupItem]
+ and a
+ jr nz, .GiftWaiting
+ ld a, [wMysteryGiftPartnerBackupItem]
+ and a
+ jr nz, .FriendNotReady
+ ld a, [wc800]
+ cp 3
+ jr z, .skip_append_save
+ call .AddMysteryGiftPartnerID
+ ld a, [wc800]
+ cp 4
+ jr z, .skip_append_save
+ call .SaveMysteryGiftTrainerName
+.skip_append_save
+ ld a, [wMysteryGiftPartnerSentDeco]
+ and a
+ jr z, .item
+ ld a, [wMysteryGiftPartnerWhichDeco]
+ ld c, a
+ farcall MysteryGiftGetDecoration
+ push bc
+ call MysteryGift_CheckAndSetDecorationAlreadyReceived
+ pop bc
+ jr nz, .item
+ callfar GetDecorationName_c
+ ld h, d
+ ld l, e
+ ld de, wStringBuffer1
+ ld bc, ITEM_NAME_LENGTH
+ call CopyBytes
+ ld hl, .MysteryGiftSentHomeText ; sent decoration to home
+ jr .PrintTextAndExit
+
+.item
+ call GetMysteryGiftBank
+ ld a, [wMysteryGiftPartnerWhichItem]
+ ld c, a
+ farcall MysteryGiftGetItemHeldEffect
+ ld a, c
+ ld [sBackupMysteryGiftItem], a
+ ld [wNamedObjectIndexBuffer], a
+ call CloseSRAM
+ call GetItemName
+ ld hl, .MysteryGiftSentText ; sent item
+ jr .PrintTextAndExit
+
+.LinkCanceled:
+ ld hl, .MysteryGiftCanceledText ; Link has been canceled
+ jr .PrintTextAndExit
+
+.CommunicationError:
+ ld hl, .MysteryGiftCommErrorText ; Communication error
+ call PrintText
+ jp DoMysteryGift
+
+.GiftWaiting:
+ ld hl, .RetrieveMysteryGiftText ; receive gift at counter
+ jr .PrintTextAndExit
+
+.FriendNotReady:
+ ld hl, .YourFriendIsNotReadyText ; friend not ready
+
+.PrintTextAndExit:
+ call PrintText
+ ld a, LCDC_DEFAULT
+ ldh [rLCDC], a
+ ret
+
+.String_PressAToLink_BToCancel:
+ db "Press A to"
+ next "link IR-Device"
+ next "Press B to"
+ next "cancel it."
+ db "@"
+
+.MysteryGiftCanceledText:
+ text_far _MysteryGiftCanceledText
+ text_end
+
+.MysteryGiftCommErrorText:
+ text_far _MysteryGiftCommErrorText
+ text_end
+
+.RetrieveMysteryGiftText:
+ text_far _RetrieveMysteryGiftText
+ text_end
+
+.YourFriendIsNotReadyText:
+ text_far _YourFriendIsNotReadyText
+ text_end
+
+.MysteryGiftFiveADayText:
+ text_far _MysteryGiftFiveADayText
+ text_end
+
+.MysteryGiftOneADayText:
+ text_far _MysteryGiftOneADayText
+ text_end
+
+.MysteryGiftSentText:
+ text_far _MysteryGiftSentText
+ text_end
+
+.MysteryGiftSentHomeText:
+ text_far _MysteryGiftSentHomeText
+ text_end
+
+.CheckAlreadyGotFiveGiftsToday:
+ call GetMysteryGiftBank
+ ld a, [sNumDailyMysteryGiftPartnerIDs]
+ cp $5
+ jp CloseSRAM
+
+.CheckAlreadyGotAGiftFromThatPerson:
+ call GetMysteryGiftBank
+ ld a, [wMysteryGiftPartnerID]
+ ld b, a
+ ld a, [wMysteryGiftPartnerID + 1]
+ ld c, a
+ ld a, [sNumDailyMysteryGiftPartnerIDs]
+ ld d, a
+ ld hl, sDailyMysteryGiftPartnerIDs
+.loop
+ ld a, d
+ and a
+ jr z, .No
+ ld a, [hli]
+ cp b
+ jr nz, .skip
+ ld a, [hl]
+ cp c
+ jr z, .Yes
+.skip
+ inc hl
+ dec d
+ jr .loop
+.Yes:
+ scf
+.No:
+ jp CloseSRAM
+
+.AddMysteryGiftPartnerID:
+ call GetMysteryGiftBank
+ ld hl, sNumDailyMysteryGiftPartnerIDs
+ ld a, [hl]
+ inc [hl]
+ ld hl, sDailyMysteryGiftPartnerIDs ; inc hl
+ ld e, a
+ ld d, $0
+ add hl, de
+ add hl, de
+ ld a, [wMysteryGiftPartnerID]
+ ld [hli], a
+ ld a, [wMysteryGiftPartnerID + 1]
+ ld [hl], a
+ jp CloseSRAM
+
+.SaveMysteryGiftTrainerName:
+ call GetMysteryGiftBank
+ ld a, $1
+ ld [sMysteryGiftTrainerHouseFlag], a
+ ld hl, wMysteryGiftPartnerName
+ ld de, sMysteryGiftPartnerName
+ ld bc, NAME_LENGTH
+ call CopyBytes
+ ld a, $1
+ ld [de], a
+ inc de
+ ld hl, wMysteryGiftTrainerData
+ ld bc, (1 + 1 + NUM_MOVES) * PARTY_LENGTH + 2
+ call CopyBytes
+ jp CloseSRAM
+
+Function29fc9:
+ farcall ClearChannels
+ call Function2a18c
+
+.loop2
+ call Function2a1c4
+ call Function2a20b
+ ldh a, [hMGStatusFlags]
+ cp $10
+ jp z, Function2a103
+ cp $6c
+ jr nz, .loop2
+
+ ldh a, [hPrintNumBuffer + 8]
+ cp $2
+ jr z, Function2a055
+ ld hl, hPrintNumBuffer
+ ld b, $1
+ call Function2a184
+ jr nz, .ly_loop
+ call Function2a07c
+ jp nz, Function2a103
+ jr Function2a03d
+ ; Delay frame
+.ly_loop
+ ldh a, [rLY]
+ cp LY_VBLANK
+ jr c, .ly_loop
+ ld c, LOW(rRP)
+ ld a, $c0
+ ldh [c], a
+ ld b, 240 ; This might have been intended as a 4-second timeout buffer.
+ ; However, it is reset with each frame.
+.loop3
+ push bc
+ call MysteryGift_ReadJoypad
+
+ ld b, $2
+ ld c, LOW(rRP)
+ ; Delay frame
+.ly_loop2
+ ldh a, [c]
+ and b
+ ld b, a
+ ldh a, [rLY]
+ cp LY_VBLANK
+ jr nc, .ly_loop2
+.ly_loop3
+ ldh a, [c]
+ and b
+ ld b, a
+ ldh a, [rLY]
+ cp LY_VBLANK
+ jr c, .ly_loop3
+
+ ld a, b
+ pop bc
+ dec b
+ jr z, .loop2 ; we never jump here
+ or a
+ jr nz, .loop2
+ ; Check if we've pressed the B button
+ ldh a, [hMGJoypadReleased]
+ bit B_BUTTON_F, a
+ jr z, .loop3
+ ld a, $10
+ ldh [hMGStatusFlags], a
+ jp Function2a103
+
+Function2a037:
+ call Function2a073
+ jp nz, Function2a103
+; fall through
+Function2a03d:
+ call Function2a166
+ jp nz, Function2a103
+ call Function2a0bb
+ jp nz, Function2a103
+ call Function2a171
+ jp nz, Function2a103
+ call Function2a461
+ jp Function2a103
+
+Function2a055:
+ call Function2a0bb
+ jp nz, Function2a103
+ call Function2a171
+ jp nz, Function2a103
+ call Function2a073
+ jp nz, Function2a103
+ call Function2a166
+ jp nz, Function2a103
+ call Function2a45c
+ jp Function2a103
+
+Function2a073:
+ ld hl, hPrintNumBuffer
+ ld b, $1
+ call Function2a184
+ ret nz
+; fall through
+Function2a07c:
+ call Function2a461
+ ldh a, [hMGStatusFlags]
+ cp $6c
+ ret nz
+ ldh a, [hPrintNumBuffer]
+ cp $96
+ jp nz, Function2a160
+ ld a, $90
+ ldh [hPrintNumBuffer], a
+ call Function2a166
+ ret nz
+ ld hl, hPrintNumBuffer
+ ld b, $1
+ call Function2a17c
+ ret nz
+ call Function2a45c
+ ldh a, [hMGStatusFlags]
+ cp $6c
+ ret nz
+ call Function2a171
+ ret nz
+ ld hl, wMysteryGiftTrainerData
+ ld a, [wc902]
+ ld b, a
+ call Function2a184
+ ret nz
+ call Function2a461
+ ldh a, [hMGStatusFlags]
+ cp $6c
+ ret
+
+Function2a0bb:
+ ld a, $96
+ ldh [hPrintNumBuffer], a
+ ld hl, hPrintNumBuffer
+ ld b, $1
+ call Function2a17c
+ ret nz
+ call Function2a45c
+ ldh a, [hMGStatusFlags]
+ cp $6c
+ ret nz
+ call Function2a171
+ ret nz
+ ld hl, hPrintNumBuffer
+ ld b, $1
+ call Function2a184
+ ret nz
+ call Function2a461
+ ldh a, [hMGStatusFlags]
+ cp $6c
+ ret nz
+ ldh a, [hPrintNumBuffer]
+ cp $90
+ jp nz, Function2a160
+ call Function2a166
+ ret nz
+ ld hl, wLinkData
+ ld a, [wc902]
+ ld b, a
+ call Function2a17c
+ ret nz
+ call Function2a45c
+ ldh a, [hMGStatusFlags]
+ cp $6c
+ ret
+
+Function2a103:
+ nop
+ ldh a, [hMGStatusFlags]
+ cp $10
+ jr z, .quit
+ cp $6c
+ jr nz, .quit
+ ld hl, wc901
+ dec [hl]
+ jr z, .quit
+ ld hl, wMysteryGiftTrainerData
+ ld de, wMysteryGiftPartnerData
+ ld bc, wMysteryGiftPartnerDataEnd - wMysteryGiftPartnerData
+ call CopyBytes
+ ld a, [wMysteryGiftTrainerData]
+ cp $3
+ jr nc, .quit
+ farcall StagePartyDataForMysteryGift
+ call MysteryGift_ClearTrainerData
+ ld a, $26
+ ld [wc902], a
+ ldh a, [hPrintNumBuffer + 8]
+ cp $2
+ jr z, .asm_2a143
+ call Function2a171
+ jr nz, Function2a103
+ jp Function2a037
+
+.asm_2a143
+ call Function2a166
+ jr nz, Function2a103
+ jp Function2a055
+
+.quit:
+ xor a
+ ldh [rIF], a
+ ldh a, [rIE]
+ or 1 << VBLANK
+ ldh [rIE], a
+ ei
+ call DelayFrame
+ ldh a, [hMGStatusFlags]
+ push af
+ call Function2a1ce
+ pop af
+ ret
+
+Function2a160:
+ ld a, $80
+ ldh [hMGStatusFlags], a
+ and a
+ ret
+
+Function2a166:
+ call Function2a1c4
+ call Function2a274
+ ldh a, [hMGStatusFlags]
+ cp $6c
+ ret
+
+Function2a171:
+ call Function2a1c4
+ call Function2a22c
+ ldh a, [hMGStatusFlags]
+ cp $6c
+ ret
+
+Function2a17c:
+ call Function2a2c1
+ ldh a, [hMGStatusFlags]
+ cp $6c
+ ret
+
+Function2a184:
+ call Function2a385
+ ldh a, [hMGStatusFlags]
+ cp $6c
+ ret
+
+Function2a18c:
+ call Function2a1a2
+ ld a, 1 << TIMER
+ ldh [rIE], a
+ xor a
+ ldh [rIF], a
+ call Function2a1c4
+ xor a
+ ld b, a
+.asm_2a19b
+ inc a
+ jr nz, .asm_2a19b
+ inc b
+ jr nz, .asm_2a19b
+ ret
+
+Function2a1a2:
+ xor a
+ ldh [rTAC], a
+ ld a, $fe
+ ldh [rTMA], a
+ ldh [rTIMA], a
+ ld a, $2
+ ldh [rTAC], a
+ or $4
+ ldh [rTAC], a
+ ret
+
+Function2a1b4:
+ xor a
+ ldh [rTAC], a
+ ldh [rTMA], a
+ ldh [rTIMA], a
+ ld a, $2
+ ldh [rTAC], a
+ or $4
+ ldh [rTAC], a
+ ret
+
+Function2a1c4:
+ ld a, $c0
+ call Function2a2ba
+ ld a, $1
+ ldh [hPrintNumBuffer + 8], a
+ ret
+
+Function2a1ce:
+ xor a
+ call Function2a2ba
+ ld a, $2
+ ldh [rTAC], a
+ ret
+
+Function2a1d7:
+ inc d
+ ret z
+ xor a
+ ldh [rIF], a
+ halt
+ ldh a, [c]
+ bit 1, a
+ jr z, Function2a1d7
+ or a
+ ret
+
+Function2a1e5:
+ inc d
+ ret z
+ xor a
+ ldh [rIF], a
+ halt
+ ldh a, [c]
+ bit 1, a
+ jr nz, Function2a1e5
+ or a
+ ret
+
+Function2a1f3:
+ ld a, $c1
+ ldh [c], a
+.wait
+ dec d
+ ret z
+ xor a
+ ldh [rIF], a
+ halt
+ jr .wait
+
+Function2a1ff:
+ ld a, $c0
+ ldh [c], a
+.wait
+ dec d
+ ret z
+ xor a
+ ldh [rIF], a
+ halt
+ jr .wait
+
+Function2a20b:
+ ld d, $0
+ ld e, d
+ ld a, $1
+ ldh [hPrintNumBuffer + 8], a
+.loop
+ call MysteryGift_ReadJoypad
+ ld b, $2
+ ld c, LOW(rRP)
+ ldh a, [hMGJoypadReleased]
+ bit B_BUTTON_F, a
+ jr z, .next
+ ld a, $10
+ ldh [hMGStatusFlags], a
+ ret
+
+.next
+ bit 0, a
+ jr nz, Function2a268
+ ldh a, [c]
+ and b
+ jr nz, .loop
+
+Function2a22c:
+ ld c, LOW(rRP)
+ ld d, $0
+ ld e, d
+ call Function2a1e5
+ jp z, Function2a370
+ ld d, e
+ call Function2a1d7
+ jp z, Function2a370
+ call Function2a1e5
+ jp z, Function2a370
+ call Function2a1d7
+ jp z, Function2a370
+ ld a, $6c
+ ldh [hMGStatusFlags], a
+ ld d, $3d
+ call Function2a1ff
+ ld d, $5
+ call Function2a1f3
+ ld d, $15
+ call Function2a1ff
+ ld d, $5
+ call Function2a1f3
+ ld d, $5
+ call Function2a1ff
+ ret
+
+Function2a268:
+ ; Wait a random amount of time
+ call Random
+ ld e, a
+ and $f
+ ld d, a
+.loop
+ dec de
+ ld a, d
+ or e
+ jr nz, .loop
+Function2a274:
+ ld a, $2
+ ldh [hPrintNumBuffer + 8], a
+ ld c, LOW(rRP)
+ ld d, $0
+ ld e, d
+ ld d, $3d
+ call Function2a1ff
+ ld d, $5
+ call Function2a1f3
+ ld d, $15
+ call Function2a1ff
+ ld d, $5
+ call Function2a1f3
+ ld d, $5
+ call Function2a1ff
+ ld d, e
+ call Function2a1e5
+ jp z, Function2a370
+ ld d, e
+ call Function2a1d7
+ jp z, Function2a370
+ call Function2a1e5
+ jp z, Function2a370
+ call Function2a1d7
+ jp z, Function2a370
+ ld d, $3d
+ call Function2a1ff
+ ld a, $6c
+ ldh [hMGStatusFlags], a
+ ret
+
+Function2a2ba:
+ ldh [rRP], a
+ ld a, $ff
+ ldh [hMGStatusFlags], a
+ ret
+
+Function2a2c1:
+ xor a
+ ldh [hPrintNumBuffer + 4], a
+ ldh [hPrintNumBuffer + 5], a
+ push hl
+ push bc
+ ld c, LOW(rRP)
+ ld d, $3d
+ call Function2a1ff
+ ld hl, hPrintNumBuffer + 1
+ ld a, $5a
+ ld [hli], a
+ ld [hl], b
+ dec hl
+ ld b, $2
+ call Function2a304
+ pop bc
+ pop hl
+ call Function2a304
+ ldh a, [hPrintNumBuffer + 4]
+ ldh [hPrintNumBuffer + 1], a
+ ldh a, [hPrintNumBuffer + 5]
+ ldh [hPrintNumBuffer + 2], a
+ push hl
+ ld hl, hPrintNumBuffer + 1
+ ld b, $2
+ call Function2a304
+ ld hl, hMGStatusFlags
+ ld b, $1
+ call Function2a3dd
+ ldh a, [hPrintNumBuffer + 1]
+ ldh [hPrintNumBuffer + 4], a
+ ldh a, [hPrintNumBuffer + 2]
+ ldh [hPrintNumBuffer + 5], a
+ pop hl
+ ret
+
+Function2a304:
+ ld c, LOW(rRP)
+ ld d, $5
+ call Function2a1ff
+ ld d, $5
+ call Function2a1f3
+ ld d, $15
+ call Function2a1ff
+ ld a, b
+ cpl
+ ld b, a
+ ld a, $f4
+ ldh [rTMA], a
+.asm_2a31c
+ inc b
+ jr z, .asm_2a35c
+ ld a, $8
+ ldh [hPrintNumBuffer + 3], a
+ ld a, [hli]
+ ld e, a
+ ldh a, [hPrintNumBuffer + 4]
+ add e
+ ldh [hPrintNumBuffer + 4], a
+ ldh a, [hPrintNumBuffer + 5]
+ adc 0
+ ldh [hPrintNumBuffer + 5], a
+.asm_2a330
+ xor a
+ ldh [rIF], a
+ halt
+ ld a, $c1
+ ldh [rRP], a
+ ld d, $1
+ ld a, e
+ rlca
+ ld e, a
+ jr nc, .asm_2a341
+ inc d
+.asm_2a341
+ ldh a, [rTIMA]
+ cp $f8
+ jr c, .asm_2a341
+ ld a, $c0
+ ldh [rRP], a
+ dec d
+ jr z, .asm_2a353
+ xor a
+ ldh [rIF], a
+ halt
+.asm_2a353
+ ldh a, [hPrintNumBuffer + 3]
+ dec a
+ jr z, .asm_2a31c
+ ldh [hPrintNumBuffer + 3], a
+ jr .asm_2a330
+.asm_2a35c
+ ld a, $fe
+ ldh [rTMA], a
+ xor a
+ ldh [rIF], a
+ halt
+ ld d, $5
+ call Function2a1f3
+ ld d, $11
+ call Function2a1ff
+ ret
+
+Function2a370:
+ ldh a, [hMGStatusFlags]
+ or $2
+ ldh [hMGStatusFlags], a
+ ret
+
+Function2a377:
+ ldh a, [hMGStatusFlags]
+ or $1
+ ldh [hMGStatusFlags], a
+ ret
+
+Function2a37e:
+ ldh a, [hMGStatusFlags]
+ or $80
+ ldh [hMGStatusFlags], a
+ ret
+
+Function2a385:
+ xor a
+ ldh [hPrintNumBuffer + 4], a
+ ldh [hPrintNumBuffer + 5], a
+ push bc
+ push hl
+ ld hl, hPrintNumBuffer + 1
+ ld b, $2
+ call Function2a3dd
+ ldh a, [hPrintNumBuffer + 2]
+ ldh [hPrintNumBuffer + 7], a
+ ld b, a
+ pop hl
+ pop af
+ cp b
+ jp c, Function2a37e
+ ldh a, [hPrintNumBuffer + 1]
+ cp $5a
+ jp nz, Function2a37e
+ call Function2a3dd
+ ldh a, [hPrintNumBuffer + 4]
+ ld d, a
+ ldh a, [hPrintNumBuffer + 5]
+ ld e, a
+ push hl
+ push de
+ ld hl, hPrintNumBuffer + 1
+ ld b, $2
+ call Function2a3dd
+ pop de
+ ld hl, hPrintNumBuffer + 1
+ ld a, [hli]
+ xor d
+ ld b, a
+ ld a, [hl]
+ xor e
+ or b
+ call nz, Function2a377
+ push de
+ ld d, $3d
+ call Function2a1ff
+ ld hl, hMGStatusFlags
+ ld b, $1
+ call Function2a304
+ pop de
+ pop hl
+ ld a, d
+ ldh [hPrintNumBuffer + 4], a
+ ld a, e
+ ldh [hPrintNumBuffer + 5], a
+ ret
+
+Function2a3dd:
+ ld c, LOW(rRP)
+ ld d, $0
+ call Function2a1e5
+ jp z, Function2a370
+ ld d, $0
+ call Function2a1d7
+ jp z, Function2a370
+ ld d, $0
+ call Function2a1e5
+ jp z, Function2a370
+ ld a, b
+ cpl
+ ld b, a
+ xor a
+ ldh [hMGPrevTIMA], a
+ call Function2a1b4
+.asm_2a400
+ inc b
+ jr z, .asm_2a448
+ ld a, $8
+ ldh [hPrintNumBuffer + 3], a
+.asm_2a407
+ ld d, $0
+.asm_2a409
+ inc d
+ jr z, .asm_2a413
+ ldh a, [c]
+ bit 1, a
+ jr z, .asm_2a409
+ ld d, $0
+.asm_2a413
+ inc d
+ jr z, .asm_2a41b
+ ldh a, [c]
+ bit 1, a
+ jr nz, .asm_2a413
+.asm_2a41b
+ ldh a, [hMGPrevTIMA]
+ ld d, a
+ ldh a, [rTIMA]
+ ldh [hMGPrevTIMA], a
+ sub d
+ cp $12
+ jr c, .asm_2a42b
+ set 0, e
+ jr .asm_2a42d
+.asm_2a42b
+ res 0, e
+.asm_2a42d
+ ldh a, [hPrintNumBuffer + 3]
+ dec a
+ ldh [hPrintNumBuffer + 3], a
+ jr z, .asm_2a439
+ ld a, e
+ rlca
+ ld e, a
+ jr .asm_2a407
+.asm_2a439
+ ld a, e
+ ld [hli], a
+ ldh a, [hPrintNumBuffer + 4]
+ add e
+ ldh [hPrintNumBuffer + 4], a
+ ldh a, [hPrintNumBuffer + 5]
+ adc 0
+ ldh [hPrintNumBuffer + 5], a
+ jr .asm_2a400
+.asm_2a448
+ call Function2a1a2
+ xor a
+ ldh [rIF], a
+ ld d, $0
+ call Function2a1d7
+ jp z, Function2a370
+ ld d, $10
+ call Function2a1ff
+ ret
+
+Function2a45c:
+ ld b, $0
+ jp Function2a2c1
+
+Function2a461:
+ ld b, $0
+ jp Function2a385
+
+MysteryGift_ReadJoypad:
+; We can only get four inputs at a time.
+; We take d-pad first for no particular reason.
+ ld a, R_DPAD
+ ldh [rJOYP], a
+; Read twice to give the request time to take.
+ ldh a, [rJOYP]
+ ldh a, [rJOYP]
+
+; The Joypad register output is in the lo nybble (inversed).
+; We make the hi nybble of our new container d-pad input.
+ cpl
+ and $f
+ swap a
+
+; We'll keep this in b for now.
+ ld b, a
+
+; Buttons make 8 total inputs (A, B, Select, Start).
+; We can fit this into one byte.
+ ld a, R_BUTTONS
+ ldh [rJOYP], a
+; Wait for input to stabilize.
+rept 6
+ ldh a, [rJOYP]
+endr
+; Buttons take the lo nybble.
+ cpl
+ and $f
+ or b
+ ld c, a
+; To get the delta we xor the last frame's input with the new one.
+ ldh a, [hMGJoypadPressed]
+ xor c
+; Released this frame:
+ and c
+ ldh [hMGJoypadReleased], a
+; Pressed this frame:
+ ld a, c
+ ldh [hMGJoypadPressed], a
+ ld a, $30
+; Reset the joypad register since we're done with it.
+ ldh [rJOYP], a
+ ret
+
+MysteryGift_CheckAndSetDecorationAlreadyReceived:
+ call GetMysteryGiftBank
+ ld d, $0
+ ld b, CHECK_FLAG
+ ld hl, sMysteryGiftDecorationsReceived
+ predef_id SmallFarFlagAction
+ push hl
+ push bc
+ call Predef
+ call CloseSRAM
+ ld a, c
+ and a
+ pop bc
+ pop hl
+ ret nz
+ call GetMysteryGiftBank
+ ld b, SET_FLAG
+ predef SmallFarFlagAction
+ call CloseSRAM
+ xor a
+ ret
+
+MysteryGift_CopyReceivedDecosToPC:
+ call GetMysteryGiftBank
+ ld c, $0
+.loop
+ push bc
+ ld d, $0
+ ld b, CHECK_FLAG
+ ld hl, sMysteryGiftDecorationsReceived
+ predef SmallFarFlagAction
+ ld a, c
+ and a
+ pop bc
+ jr z, .skip
+ push bc
+ callfar SetSpecificDecorationFlag
+ pop bc
+.skip
+ inc c
+ ld a, c
+ cp TrophyIDs - DecorationIDs
+ jr c, .loop
+ jp CloseSRAM
+
+UnlockMysteryGift:
+ call GetMysteryGiftBank
+ ld hl, sMysteryGiftUnlocked
+ ld a, [hl]
+ inc a
+ jr nz, .ok
+ ld [hld], a
+ ld [hl], a
+.ok
+ jp CloseSRAM
+
+Function2a4f6:
+ call GetMysteryGiftBank
+ ld a, [sNumDailyMysteryGiftPartnerIDs]
+ cp $ff
+ jr z, .okay
+ xor a
+ ld [sNumDailyMysteryGiftPartnerIDs], a
+.okay
+ jp CloseSRAM
+
+BackupMysteryGift:
+ call GetMysteryGiftBank
+ ld hl, sMysteryGiftItem
+ ld de, sBackupMysteryGiftItem
+ ld a, [hli]
+ ld [de], a
+ inc de
+ ld a, [hl]
+ ld [de], a
+ jp CloseSRAM
+
+RestoreMysteryGift:
+ call GetMysteryGiftBank
+ ld hl, sBackupMysteryGiftItem
+ ld de, sMysteryGiftItem
+ ld a, [hli]
+ ld [de], a
+ inc de
+ ld a, [hl]
+ ld [de], a
+ jp CloseSRAM
+
+MysteryGift_ClearTrainerData:
+ ld hl, wMysteryGiftTrainerData
+ xor a
+ ld b, wMysteryGiftTrainerDataEnd - wMysteryGiftTrainerData
+.loop
+ ld [hli], a
+ dec b
+ jr nz, .loop
+ ret
+
+GetMysteryGiftBank:
+ ld a, BANK(sBackupMysteryGiftItem)
+ jp OpenSRAM
diff --git a/engine/link/mystery_gift_2.asm b/engine/link/mystery_gift_2.asm
new file mode 100644
index 00000000..493db05c
--- /dev/null
+++ b/engine/link/mystery_gift_2.asm
@@ -0,0 +1,150 @@
+PrepMysteryGiftDataToSend:
+ ld de, wMysteryGiftStaging
+ ld a, $1 + GS_VERSION
+ ld [de], a
+ inc de ; wc701
+ ld a, BANK(sGameData)
+ call OpenSRAM
+ ld hl, sPlayerData + wPlayerID - wPlayerData
+ ld a, [hli]
+ ld [de], a
+ ld b, a
+ inc de ; wc702
+ ld a, [hl]
+ ld [de], a
+ ld c, a
+ inc de ; wc703
+ push bc
+ ld hl, sPlayerData + wPlayerName - wPlayerData
+ ld bc, NAME_LENGTH
+ call CopyBytes
+ push de ; wc70e
+ ld hl, sPokemonData + wPokedexCaught - wPokemonData
+ ld b, wEndPokedexCaught - wPokedexCaught
+ call CountSetBits
+ pop de
+ pop bc
+ ld a, [wNumSetBits]
+ ld [de], a
+ inc de ; wc70f
+ call CloseSRAM
+ call Random
+ and 1
+ ld [de], a
+ inc de ; wc710
+ call .RandomSample
+ ld [de], a
+ inc de ; wc711
+ ld a, c
+ ld c, b
+ ld b, a
+ call .RandomSample
+ ld [de], a
+ inc de ; wc712
+ ld a, BANK(sBackupMysteryGiftItem)
+ call OpenSRAM
+ ld a, [sBackupMysteryGiftItem]
+ ld [de], a
+ inc de
+ ld a, [sBackupMysteryGiftItem + 1]
+ ld [de], a
+ ld a, $14
+ ld [wc900], a
+ call CloseSRAM
+ ld hl, wMysteryGiftStaging
+ ld de, wMysteryGiftPlayerData
+ ld bc, wMysteryGiftPlayerDataEnd - wMysteryGiftPlayerData
+ jp CopyBytes
+
+.RandomSample:
+ push de
+ call Random
+ cp 10 percent
+ jr c, .tenpercent
+ call Random
+ and %111
+ ld d, a
+ rl d
+ ld e, $80
+.loop
+ rlc e
+ dec a
+ jr nz, .loop
+ ld a, e
+ and c
+ jr z, .skip
+ ld a, $1
+.skip
+ add d
+ jr .done
+
+.tenpercent
+ call Random
+ cp 20 percent - 1
+ jr c, .twopercent
+ call Random
+ and %011
+ ld d, a
+ rl d
+ ld e, $80
+.loop2
+ rlc e
+ dec a
+ jr nz, .loop2
+ ld a, e
+ and b
+ jr z, .skip2
+ ld a, $1
+.skip2
+ add d
+ add $10
+ jr .done
+
+.twopercent
+ call Random
+ cp 20 percent - 1
+ jr c, .pointfourpercent
+ ld a, b
+ swap a
+ and $7
+ add $18
+ jr .done
+
+.pointfourpercent
+ ld a, b
+ and $80
+ ld a, $20
+ jr z, .done
+ ld a, $21
+
+.done
+ pop de
+ ret
+
+MysteryGiftGetItemHeldEffect:
+ ld a, c
+ cp MysteryGiftItems.End - MysteryGiftItems
+ jr nc, MysteryGiftFallbackItem
+ ld hl, MysteryGiftItems
+ ld b, 0
+ add hl, bc
+ ld c, [hl]
+ ret
+
+MysteryGiftGetDecoration:
+ ld a, c
+ cp MysteryGiftDecos.End - MysteryGiftDecos
+ jr nc, MysteryGiftFallbackItem
+ ld hl, MysteryGiftDecos
+ ld b, 0
+ add hl, bc
+ ld c, [hl]
+ ret
+
+MysteryGiftFallbackItem:
+ ld c, DECO_POLKADOT_BED ; GREAT_BALL
+ ret
+
+INCLUDE "data/items/mystery_gift_items.asm"
+
+INCLUDE "data/decorations/mystery_gift_decos.asm"
diff --git a/engine/link/place_waiting_text.asm b/engine/link/place_waiting_text.asm
index dc1fe215..5c31c314 100755
--- a/engine/link/place_waiting_text.asm
+++ b/engine/link/place_waiting_text.asm
@@ -22,3 +22,6 @@ PlaceWaitingText::
.Waiting:
db "Waiting...!@"
+
+DummyPredef1:
+ ret
diff --git a/engine/main_menu.asm b/engine/main_menu.asm
deleted file mode 100755
index 6f460a5c..00000000
--- a/engine/main_menu.asm
+++ /dev/null
@@ -1,1093 +0,0 @@
-MainMenu_:
- ld de, MUSIC_NONE
- call PlayMusic
- call DelayFrame
- ld de, MUSIC_MAIN_MENU
- ld a, e
- ld [wMapMusic], a
- call PlayMusic
-.asm_5a60
- xor a
- ld [wDisableTextAcceleration], a
- call Function5bf7
- ld b, $8
- call GetSGBLayout
- ld hl, wGameTimerPause
- res 0, [hl]
- call Function5ae4
- ld [wWhichIndexSet], a
- call Function5b27
- ld hl, .MenuDataHeader
- call LoadMenuHeader
- call Function5b0a
- call CloseWindow
- jr c, .asm_5a94
- call ClearTilemap
- ld a, [wMenuSelection]
- ld hl, .Jumptable
- rst JumpTable
- jr .asm_5a60
-
-.asm_5a94
- jp StartTitleScreen
-
-.MenuDataHeader:
- db $40
- db 00, 00
- db 07, 14
- dw .MenuData2
- db 1
-
-.MenuData2:
- db $80
- db 0
- dw MainMenuItems
- dw PlaceMenuStrings
- dw .Strings
-
-.Strings:
- db "CONTINUE@"
- db "NEW GAME@"
- db "OPTION@"
- db "MYSTERY GIFT@"
-
-.Jumptable:
- dw MainMenu_Continue ; 5dd9
- dw MainMenu_NewGame ; 5c1e
- dw MainMenu_Options ; 5c17
- dw MainMenu_MysteryGift ; 5c07
-
-CONTINUE EQU 0
-NEW_GAME EQU 1
-OPTION EQU 2
-MYSTERY_GIFT EQU 3
-
-MainMenuItems:
- db 2
- db NEW_GAME
- db OPTION
- db -1
-
- db 3
- db CONTINUE
- db NEW_GAME
- db OPTION
- db -1
-
- db 4
- db CONTINUE
- db NEW_GAME
- db OPTION
- db MYSTERY_GIFT
- db -1
-
-Function5ae4: ; 5ae4 (1:5ae4)
- nop
- nop
- nop
- ld a, [wSaveFileExists]
- and a
- jr nz, .asm_5af0
- ld a, $0
- ret
-
-.asm_5af0
- ldh a, [hCGB]
- cp $1
- ld a, $1
- ret nz
- ld a, $0
- call OpenSRAM
- ld a, [$abe5]
- cp $ff
- call CloseSRAM
- ld a, $1
- ret z
- ld a, $2
- ret
-
-Function5b0a: ; 5b0a (1:5b0a)
- call SetUpMenu
-.asm_5b0d
- call Function5b27
- call GetScrollingMenuJoypad
- ld a, [wMenuJoypad]
- cp $2
- jr z, .asm_5b25
- cp $1
- jr z, .asm_5b20
- jr .asm_5b0d
-
-.asm_5b20
- call PlayClickSFX
- and a
- ret
-
-.asm_5b25
- scf
- ret
-
-Function5b27: ; 5b27 (1:5b27)
- ld a, [wSaveFileExists]
- and a
- ret z
- xor a
- ldh [hBGMapMode], a
- call Function5b45
- ld hl, wOptions
- ld a, [hl]
- push af
- set 4, [hl]
- call Function5b5b
- pop af
- ld [wOptions], a
- ld a, $1
- ldh [hBGMapMode], a
- ret
-
-Function5b45: ; 5b45 (1:5b45)
- call CheckRTCStatus
- and $80
- jr nz, .asm_5b57
- hlcoord 0, 12
- ld b, $4
- ld c, $d
- call Textbox
- ret
-
-.asm_5b57
- call SpeechTextbox
- ret
-
-Function5b5b: ; 5b5b (1:5b5b)
- ld a, [wSaveFileExists]
- and a
- ret z
- call CheckRTCStatus
- and $80
- jp nz, Function5b9c
- call UpdateTime
- hlcoord 1, 13
- ld bc, IncGradGBPalTable_11 + 1
- call ClearBox
- call GetWeekday
- ld b, a
- decoord 1, 14
- call Function5bb8
- decoord 4, 16
- ldh a, [hHours]
- ld c, a
- farcall PrintHour
- ld [hl], $9c
- inc hl
- ld de, hMinutes
- lb bc, PRINTNUM_LEADINGZEROS | 1, 2
- call PrintNum
- ret
-
-.min
- db "min.@"
-
-Function5b9c: ; 5b9c (1:5b9c)
- hlcoord 1, 14
- ld de, .TimeNotSet
- call PlaceString
- ret
-
-.TimeNotSet
- db "TIME NOT SET@"
-
-.UnusedText
- text_far _ClockTimeUnknownText
- db "@"
-
-Function5bb8: ; 5bb8 (1:5bb8)
- push de
- ld hl, .Days
- ld a, b
- call GetNthString
- ld d, h
- ld e, l
- pop hl
- call PlaceString
- ld h, b
- ld l, c
- ld de, .Day
- call PlaceString
- ret
-
-.Days:
- db "SUN@"
- db "MON@"
- db "TUES@"
- db "WEDNES@"
- db "THURS@"
- db "FRI@"
- db "SATUR@"
-.Day:
- db "DAY@"
-
-Function5bf7: ; 5bf7 (1:5bf7)
- xor a
- ldh [hMapAnims], a
- call ClearTilemap
- call LoadFontsExtra
- call Functiond9e
- call ClearWindowData
- ret
-
-MainMenu_MysteryGift:
- call UpdateTime
- farcall Function11934
- farcall Function29dff
- ret
-
-MainMenu_Options:
- farcall OptionsMenu
- ret
-
-MainMenu_NewGame:
- xor a
- ld [wDebugFlags], a
- call Function5c3a
- call Function5bf7
- call OakSpeech
- call InitializeWorld
- ld a, $0
- ld [wceec], a
- ld a, $f1
- ldh [hMapEntryMethod], a
- jp FinishContinueFunction
-
-Function5c3a: ; 5c3a (1:5c3a)
- xor a
- ldh [hBGMapMode], a
- call Function5c41
- ret
-
-Function5c41: ; 5c41 (1:5c41)
- ld hl, wVirtualOAM
- ld bc, wOptions - wVirtualOAM
- xor a
- call ByteFill
-
- ld hl, wGameData
- ld bc, wGameDataEnd - wGameData
- xor a
- call ByteFill
-
- ldh a, [rLY]
- ldh [hSecondsBackup], a
- call DelayFrame
- ldh a, [hRandomSub]
- ld [wPlayerID], a
-
- ldh a, [rLY]
- ldh [hSecondsBackup], a
- call DelayFrame
- ldh a, [hRandomAdd]
- ld [wPlayerID + 1], a
-
- ld hl, wPartyCount
- call Function5d15
-
- xor a
- ld [wCurBox], a
- ld [wSavedAtLeastOnce], a
-
- call Function5d1a
-
- ld a, BANK(sBoxCount)
- call OpenSRAM
- ld hl, sBoxCount
- call Function5d15
- call CloseSRAM
-
- ld hl, wNumItems
- call Function5d15
- ld hl, wNumKeyItems
- call Function5d15
- ld hl, wNumBalls
- call Function5d15
- ld hl, wPCItems
- call Function5d15
-
- xor a
- ld [wRoamMon1Species], a
- ld [wRoamMon2Species], a
- ld [wRoamMon3Species], a
- ld a, $ff
- ld [wRoamMon1MapGroup], a
- ld [wRoamMon2MapGroup], a
- ld [wRoamMon3MapGroup], a
- ld [wRoamMon1MapNumber], a
- ld [wRoamMon2MapNumber], a
- ld [wRoamMon3MapNumber], a
-
- ld a, BANK(s0_abe2)
- call OpenSRAM
- ld hl, s0_abe2
- xor a
- ld [hli], a
- dec a
- ld [hl], a
- call CloseSRAM
-
- call LoadOrRegenerateLuckyIDNumber
- call InitializeMagikarpHouse
-
- xor a
- ld [wMonType], a
-
- ld [wJohtoBadges], a
- ld [wKantoBadges], a
-
- ld [wCoins], a
- ld [wCoins + 1], a
-
-IF START_MONEY / $10000
- ld a, START_MONEY / $10000
-ENDC
- ld [wMoney], a
- ld a, START_MONEY / $100 % $100
- ld [wMoney + 1], a
- ld a, START_MONEY % $100
- ld [wMoney + 2], a
-
- xor a
- ld [wd961], a
-
- ld hl, wMomItemTriggerBalance
- ld [hl], 2300 / $10000
- inc hl
- ld [hl], 2300 / $100 % $100
- inc hl
- ld [hl], 2300 % $100
-
- call Function5d5d
-
- farcall InitDecorations
-
- farcall DeletePartyMonMail
-
- call ResetGameTime
- ret
-
-Function5d15: ; 5d15 (1:5d15)
- xor a
- ld [hli], a
- dec a
- ld [hl], a
- ret
-
-Function5d1a: ; 5d1a (1:5d1a)
- ld hl, wBoxNames
- ld c, $0
-.asm_5d1f
- push hl
- ld de, .Box
- call CopyName2
- dec hl
- ld a, c
- inc a
- cp 10
- jr c, .asm_5d32
- sub 10
- ld [hl], "1"
- inc hl
-.asm_5d32
- add "0"
- ld [hli], a
- ld [hl], "@"
- pop hl
- ld de, 9
- add hl, de
- inc c
- ld a, c
- cp NUM_BOXES
- jr c, .asm_5d1f
- ret
-
-.Box db "BOX@"
-
-InitializeMagikarpHouse: ; 5d47 (1:5d47)
- ld hl, wBestMagikarpLengthFeet
- ld a, 3
- ld [hli], a
- ld a, 6
- ld [hli], a
- ld de, .Ralph
- call CopyName2
- ret
-
-.Ralph db "RALPH@"
-
-Function5d5d: ; 5d5d (1:5d5d)
- ld hl, .Rival
- ld de, wRivalName
- call .CopyName
- ld hl, .Mom
- ld de, wMomsName
- call .CopyName
- ld hl, .Red
- ld de, wRedsName
- call .CopyName
- ld hl, .Green
- ld de, wGreensName
-.CopyName:
- ld bc, NAME_LENGTH
- call CopyBytes
- ret
-
-.Rival: db "???@"
-.Red: db "RED@"
-.Green: db "GREEN@"
-.Mom: db "MOM@"
-
-InitializeWorld: ; 5d97 (1:5d97)
- call ShrinkPlayer
- farcall SpawnPlayer
- farcall InitializeStartDay_
- ret
-
-LoadOrRegenerateLuckyIDNumber: ; 5da7 (1:5da7)
- ld a, $0
- call OpenSRAM
- ld a, [wCurDay]
- inc a
- ld b, a
- ld a, [s0_ac68]
- cp b
- ld a, [s0_ac6a]
- ld c, a
- ld a, [s0_ac69]
- jr z, .asm_5dc9
- ld a, b
- ld [s0_ac68], a
- call Random
- ld c, a
- call Random
-.asm_5dc9
- ld [wd9e9], a
- ld [s0_ac69], a
- ld a, c
- ld [wd9ea], a
- ld [s0_ac6a], a
- jp CloseSRAM
-
-MainMenu_Continue:
- farcall TryLoadSaveFile
- jr c, .asm_5e41
- call LoadStandardMenuHeader
- call DisplaySaveInfoOnContinue
- ld a, $1
- ldh [hBGMapMode], a
- ld c, 20
- call DelayFrames
- call ConfirmContinue
- jr nc, .asm_5dfa
- call CloseWindow
- jr .asm_5e41
-
-.asm_5dfa
- call Continue_CheckRTC_RestartClock
- jr nc, .asm_5e04
- call CloseWindow
- jr .asm_5e41
-
-.asm_5e04
- ld a, $8
- ld [wMusicFade], a
- ld a, MUSIC_NONE % $100
- ld [wMusicFadeID], a
- ld a, MUSIC_NONE / $100
- ld [wMusicFadeID + 1], a
- call ClearBGPalettes
- call CloseWindow
- call ClearTilemap
- ld c, 20
- call DelayFrames
- farcall JumpRoamMons
- farcall MysteryGift_CopyReceivedDecosToPC
- farcall ClockContinue
- ld a, [wd1db]
- cp $1
- jr z, .asm_5e42
- ld a, $f2
- ldh [hMapEntryMethod], a
- jp FinishContinueFunction
-
-.asm_5e41
- ret
-
-.asm_5e42
- ld a, $e
- ld [wceec], a
- call PostCreditsSpawn
- jp FinishContinueFunction
-
-SpawnAfterRed: ; 5e4d (1:5e4d)
- ld a, $1a
- ld [wceec], a
-PostCreditsSpawn: ; 5e52 (1:5e52)
- xor a
- ld [wd1db], a
- ld a, $f1
- ldh [hMapEntryMethod], a
- ret
-
-ConfirmContinue: ; 5e5b (1:5e5b)
- call DelayFrame
- call GetJoypad
- ld hl, hJoyPressed
- bit 0, [hl]
- jr nz, .asm_5e6e
- bit 1, [hl]
- jr z, ConfirmContinue
- scf
- ret
-
-.asm_5e6e
- ret
-
-Continue_CheckRTC_RestartClock: ; 5e6f (1:5e6f)
- call CheckRTCStatus
- and $80
- jr z, .asm_5e82
- ld a, $8
- ld hl, $4021
- rst FarCall
- ld a, c
- and a
- jr z, .asm_5e82
- scf
- ret
-
-.asm_5e82
- xor a
- ret
-
-FinishContinueFunction: ; 5e84 (1:5e84)
- xor a
- ld [wDontPlayMapMusicOnReload], a
- ld hl, wGameTimerPause
- set 0, [hl]
- farcall OverworldLoop
- ld a, [wd1db]
- cp $2
- jr z, .asm_5e9d
- jp Reset
-
-.asm_5e9d
- call SpawnAfterRed
- jr FinishContinueFunction
-
-DisplaySaveInfoOnContinue: ; 5ea2 (1:5ea2)
- call CheckRTCStatus
- and $80
- jr z, .asm_5eb0
- lb de, 4, 8
- call DisplayContinueDataWithRTCError
- ret
-
-.asm_5eb0
- lb de, 4, 8
- call DisplayNormalContinueData
- ret
-
-DisplayNormalContinueData: ; 5eb7 (1:5eb7)
- call Continue_LoadMenuHeader
- call Continue_DisplayBadgesDex
- call Continue_PrintGameTime
- call LoadFontsExtra
- call UpdateSprites
- ret
-
-DisplayContinueDataWithRTCError: ; 5ec7 (1:5ec7)
- call Continue_LoadMenuHeader
- call Continue_DisplayBadgesDex
- call Continue_UnknownGameTime
- call LoadFontsExtra
- call UpdateSprites
- ret
-
-Continue_LoadMenuHeader: ; 5ed7 (1:5ed7)
- xor a
- ldh [hBGMapMode], a
- ld hl, .MenuDataHeader_Dex
- CheckFlag ENGINE_POKEDEX
- jr nz, .asm_5ee7
- ld hl, .MenuDataHeader_NoDex
-.asm_5ee7
- call _OffsetMenuHeader
- call MenuBox
- call PlaceVerticalMenuItems
- ret
-
-.MenuDataHeader_Dex:
- db $40
- db 00, 00
- db 09, 15
- dw .MenuData2_Dex
- db 1
-
-.MenuData2_Dex
- db $00
- db 4
- db "PLAYER <PLAYER>@"
- db "BADGES@"
- db "#DEX@"
- db "TIME@"
-
-.MenuDataHeader_NoDex:
- db $40
- db 00, 00
- db 09, 15
- dw .MenuData2_NoDex
- db 1
-
-.MenuData2_NoDex
- db $00
- db 4
- db "PLAYER <PLAYER>@"
- db "BADGES@"
- db " @"
- db "TIME@"
-
-Continue_DisplayBadgesDex: ; 5f36 (1:5f36)
- call MenuBoxCoord2Tile
- push hl
- decoord 13, 4, 0
- add hl, de
- call Continue_DisplayBadgeCount
- pop hl
- push hl
- decoord 12, 6, 0
- add hl, de
- call Continue_DisplayPokedexNumCaught
- pop hl
- ret
-
-Continue_PrintGameTime: ; 5f4c (1:5f4c)
- decoord 9, 8, 0
- add hl, de
- call Continue_DisplayGameTime
- ret
-
-Continue_UnknownGameTime: ; 5f54 (1:5f54)
- decoord 9, 8, 0
- add hl, de
- ld de, .three_question_marks
- call PlaceString
- ret
-
-.three_question_marks
- db " ???@"
-
-Continue_DisplayBadgeCount: ; 5f64 (1:5f64)
- push hl
- ld hl, wJohtoBadges
- ld b, $2
- call CountSetBits
- pop hl
- ld de, wd151
- lb bc, 1, 2
- jp PrintNum
-
-Continue_DisplayPokedexNumCaught: ; 5f77 (1:5f77)
- CheckFlag ENGINE_POKEDEX
- ret z
- push hl
- ld hl, wPokedexCaught
-IF NUM_POKEMON % 8
- ld b, NUM_POKEMON / 8 + 1
-ELSE
- ld b, NUM_POKEMON / 8
-ENDC
- call CountSetBits
- pop hl
- ld de, wd151
- lb bc, 1, 3
- jp PrintNum
-
-Continue_DisplayGameTime: ; 5f90 (1:5f90)
- ld de, wGameTimeHours
- lb bc, 2, 3
- call PrintNum
- ld [hl], $6d
- inc hl
- ld de, wGameTimeMinutes
- lb bc, PRINTNUM_LEADINGZEROS | 1, 2
- jp PrintNum
-
-OakSpeech: ; 5fa5 (1:5fa5)
- farcall InitClock ; What time is it?
-
- call RotateFourPalettesLeft
- call ClearTilemap
-
- ld de, MUSIC_ROUTE_30
- call PlayMusic
-
- call RotateFourPalettesRight
- call RotateThreePalettesRight
-
- xor a
- ld [wCurPartySpecies], a
- ld a, POKEMON_PROF
- ld [wTrainerClass], a
- call Intro_PrepTrainerPic
-
- ld b, SCGB_TRAINER_OR_MON_FRONTPIC_PALS
- call GetSGBLayout
-
- call Intro_FadeInFrontpic
-
- ld hl, OakText1
- call PrintText
-
- call RotateThreePalettesRight
- call ClearTilemap
-
- ld a, MARILL
- ld [wCurSpecies], a
- ld [wCurPartySpecies], a
- call GetBaseData
- hlcoord 6, 4
- hlcoord 6, 4 ; TriHard
- call PrepMonFrontpic
-
- xor a
- ld [wTempMonDVs], a
- ld [wTempMonDVs + 1], a
- ld b, SCGB_TRAINER_OR_MON_FRONTPIC_PALS
- call GetSGBLayout
-
- call Intro_WipeInFrontpic
-
- ld hl, OakText2
- call PrintText
-
- ld hl, OakText4
- call PrintText
-
- call RotateThreePalettesRight
- call ClearTilemap
-
- xor a
- ld [wCurPartySpecies], a
- ld a, POKEMON_PROF
- ld [wTrainerClass], a
- call Intro_PrepTrainerPic
-
- ld b, SCGB_TRAINER_OR_MON_FRONTPIC_PALS
- call GetSGBLayout
-
- call Intro_FadeInFrontpic
-
- ld hl, OakText5
- call PrintText
-
- call RotateThreePalettesRight
- call ClearTilemap
-
- xor a
- ld [wCurPartySpecies], a
- ld a, CAL
- ld [wTrainerClass], a
- call Intro_PrepTrainerPic
-
- ld b, SCGB_TRAINER_OR_MON_FRONTPIC_PALS
- call GetSGBLayout
-
- call Intro_FadeInFrontpic
-
- ld hl, OakText6
- call PrintText
-
- call NamePlayer
-
- ld hl, OakText7
- call PrintText
- ret
-
-OakText1:
- text_far _OakText1
- db "@"
-
-OakText2:
- text_far _OakText2
- text_asm
- ld a, MARILL
- call PlayMonCry
- call WaitSFX
- ld hl, OakText3 ; $606c
- ret
-
-OakText3:
- text_far _OakText3
- db "@"
-
-OakText4:
- text_far _OakText4
- db "@"
-
-OakText5:
- text_far _OakText5
- db "@"
-
-OakText6:
- text_far _OakText6
- db "@"
-
-OakText7:
- text_far _OakText7
- db "@"
-
-NamePlayer: ; 6085 (1:6085)
- call MovePlayerPicRight
- ld hl, .PlayerNamingChoices ; $60d9
- call SelectPresetName
- ld a, [wMenuCursorY]
- dec a
- jr z, .NewName
- ld de, wPlayerName
- call StorePlayerName
- farcall ApplyMonOrTrainerPals
- call MovePlayerPicLeft
- ret
-
-.NewName
- ld b, $1
- ld de, wPlayerName
- farcall NamingScreen
- call RotateThreePalettesRight
- call ClearTilemap
- call LoadFontsExtra
- call WaitBGMap
- xor a
- ld [wCurPartySpecies], a
- ld a, CAL
- ld [wTrainerClass], a
- call Intro_PrepTrainerPic
- ld b, SCGB_TRAINER_OR_MON_FRONTPIC_PALS
- call GetSGBLayout
- call RotateThreePalettesLeft
- ld hl, wPlayerName
- ld de, .GoldSilver
- call InitName
- ret
-
-.PlayerNamingChoices:
- db $40
- db 00, 00
- db 11, 10
- dw .MenuData2
- db 1
-
-.MenuData2:
- db $91
- db 5
- db "NEW NAME@"
-.GoldSilver:
-IF DEF(GOLD)
- db "GOLD@"
- db "HIRO@"
- db "TAYLOR@"
- db "KARL@"
-ENDC
-IF DEF(SILVER)
- db "SILVER@"
- db "KAMON@"
- db "OSCAR@"
- db "MAX@"
-ENDC
- db 2, "NAME@"
-
-SelectPresetName: ; 6108 (1:6108)
- call LoadMenuHeader
- call VerticalMenu
- ld a, [wMenuCursorY]
- dec a
- call CopyNameFromMenu
- call CloseWindow
- ret
-
-StorePlayerName: ; 6119 (1:6119)
- ld hl, wStringBuffer2
- ld bc, NAME_LENGTH
- call CopyBytes
- ret
-
-ShrinkPlayer: ; 6123 (1:6123)
- ldh a, [hROMBank]
- push af
-
- ld a, 0 << 7 | 32 ; fade out
- ld [wMusicFade], a
- ld de, MUSIC_NONE
- ld a, e
- ld [wMusicFadeID], a
- ld a, d
- ld [wMusicFadeID + 1], a
-
- ld de, SFX_ESCAPE_ROPE
- call PlaySFX
- pop af
- rst Bankswitch
-
- ld c, 8
- call DelayFrames
-
- ld hl, Shrink1Pic
- ld b, BANK(Shrink1Pic)
- call ShrinkFrame
-
- ld c, 8
- call DelayFrames
-
- ld hl, Shrink2Pic
- ld b, BANK(Shrink2Pic)
- call ShrinkFrame
-
- ld c, 8
- call DelayFrames
-
- hlcoord 6, 5
- ld b, 7
- ld c, 7
- call ClearBox
-
- ld c, 3
- call DelayFrames
-
- call Intro_PlacePlayerSprite
- call LoadFontsExtra
-
- ld c, 50
- call DelayFrames
-
- call RotateThreePalettesRight
- call ClearTilemap
- ret
-
-MovePlayerPicRight: ; 617e (1:617e)
- hlcoord 6, 4
- ld de, $1
- jr MovePlayerPic
-
-MovePlayerPicLeft: ; 6186 (1:6186)
- hlcoord 13, 4
- ld de, -1
-MovePlayerPic
- ld c, $8
-.asm_618e
- push bc
- push hl
- push de
- xor a
- ldh [hBGMapMode], a
- lb bc, 7, 7
- predef PlaceGraphic
- xor a
- ldh [hBGMapThird], a
- call WaitBGMap
- call DelayFrame
- pop de
- pop hl
- add hl, de
- pop bc
- dec c
- jr nz, .asm_618e
- ret
-
-Intro_FadeInFrontpic: ; 61ad (1:61ad)
- ld hl, IntroFadePalettes
- ld b, $6
-.asm_61b2
- ld a, [hli]
- call DmgToCgbBGPals
- ld c, $a
- call DelayFrames
- dec b
- jr nz, .asm_61b2
- ret
-
-IntroFadePalettes:
- db %01010100
- db %10101000
- db %11111100
- db %11111000
- db %11110100
- db %11100100
-
-Intro_WipeInFrontpic: ; 61c5 (1:61c5)
- ld a, $77
- ldh [hWX], a
- call DelayFrame
- ld a, $e4
- call DmgToCgbBGPals
-.asm_61d1
- call DelayFrame
- ldh a, [hWX]
- sub $8
- cp $ff
- ret z
- ldh [hWX], a
- jr .asm_61d1
-
-Intro_PrepTrainerPic: ; 61df, 61e0 (1:61df, 1:61e0)
- ld de, $9000
- ld a, $14
- ld hl, $58a0
- rst FarCall
- xor a
- ldh [hGraphicStartTile], a
- hlcoord 6, 4
- lb bc, 7, 7
- predef PlaceGraphic
- ret
-
-ShrinkFrame: ; 61f7 (1:61f7)
- ld de, $9000
- ld c, $31
- predef DecompressGet2bpp
- xor a
- ldh [hGraphicStartTile], a
- hlcoord 6, 4
- lb bc, 7, 7
- predef PlaceGraphic
- ret
-
-Intro_PlacePlayerSprite: ; 6210 (1:6210)
- ld de, PlayerSpriteGFX
- lb bc, BANK(PlayerSpriteGFX), 12
- ld hl, $8000
- call Request2bpp
- ld hl, wVirtualOAM
- ld de, .OAMData
- ld a, [de]
- inc de
- ld c, a
-.asm_6225
- ld a, [de]
- inc de
- ld [hli], a
- ld a, [de]
- inc de
- ld [hli], a
- ld a, [de]
- inc de
- ld [hli], a
- xor a
- ld [hli], a
- dec c
- jr nz, .asm_6225
- ret
-
-.OAMData
- db 4
- db 9 * 8 + 4, 9 * 8, 0
- db 9 * 8 + 4, 10 * 8, 1
- db 10 * 8 + 4, 9 * 8, 2
- db 10 * 8 + 4, 10 * 8, 3
diff --git a/engine/math.asm b/engine/math/math.asm
index cdac2d37..d5df3c34 100755
--- a/engine/math.asm
+++ b/engine/math/math.asm
@@ -1,11 +1,10 @@
-_Multiply:: ; 67bd
-
+_Multiply::
; hMultiplier is one byte.
ld a, 8
ld b, a
xor a
- ldh [hProduct], a
+ ldh [hMultiplicand - 1], a
ldh [hMathBuffer + 1], a
ldh [hMathBuffer + 2], a
ldh [hMathBuffer + 3], a
@@ -37,7 +36,7 @@ _Multiply:: ; 67bd
ldh a, [hMathBuffer + 1]
ld c, a
- ldh a, [hProduct]
+ ldh a, [hMultiplicand - 1]
adc c
ldh [hMathBuffer + 1], a
@@ -59,9 +58,9 @@ _Multiply:: ; 67bd
rla
ldh [hMultiplicand + 0], a
- ldh a, [hProduct]
+ ldh a, [hMultiplicand - 1]
rla
- ldh [hProduct], a
+ ldh [hMultiplicand - 1], a
jr .loop
@@ -80,7 +79,7 @@ _Multiply:: ; 67bd
ret
-_Divide:: ; 681d
+_Divide::
xor a
ldh [hMathBuffer + 0], a
ldh [hMathBuffer + 1], a
@@ -173,18 +172,18 @@ _Divide:: ; 681d
.done
ldh a, [hDividend + 1]
- ldh [hDivisor], a
+ ldh [hRemainder], a
ldh a, [hMathBuffer + 4]
- ldh [hDividend + 3], a
+ ldh [hQuotient + 3], a
ldh a, [hMathBuffer + 3]
- ldh [hDividend + 2], a
+ ldh [hQuotient + 2], a
ldh a, [hMathBuffer + 2]
- ldh [hDividend + 1], a
+ ldh [hQuotient + 1], a
ldh a, [hMathBuffer + 1]
- ldh [hDividend + 0], a
+ ldh [hQuotient + 0], a
ret
diff --git a/engine/math/sine.asm b/engine/math/sine.asm
new file mode 100644
index 00000000..5db3bd60
--- /dev/null
+++ b/engine/math/sine.asm
@@ -0,0 +1,7 @@
+_Sine::
+; a = d * sin(e * pi/256)
+ ld a, e
+ calc_sine_wave .SineWave
+
+.SineWave:
+ sine_table $100
diff --git a/engine/menus/empty_sram.asm b/engine/menus/empty_sram.asm
new file mode 100644
index 00000000..264f0813
--- /dev/null
+++ b/engine/menus/empty_sram.asm
@@ -0,0 +1,19 @@
+EmptyAllSRAMBanks:
+ ld a, 0
+ call .EmptyBank
+ ld a, 1
+ call .EmptyBank
+ ld a, 2
+ call .EmptyBank
+ ld a, 3
+ call .EmptyBank
+ ret
+
+.EmptyBank:
+ call OpenSRAM
+ ld hl, SRAM_Begin
+ ld bc, SRAM_End - SRAM_Begin
+ xor a
+ call ByteFill
+ call CloseSRAM
+ ret
diff --git a/engine/menus/intro_menu.asm b/engine/menus/intro_menu.asm
new file mode 100644
index 00000000..c85b56f6
--- /dev/null
+++ b/engine/menus/intro_menu.asm
@@ -0,0 +1,1133 @@
+MainMenu_NewGame:
+NewGame:
+ xor a
+ ld [wDebugFlags], a
+ call ResetWRAM
+ call ClearTilemapEtc
+ call OakSpeech
+ call InitializeWorld
+
+ ld a, SPAWN_HOME
+ ld [wDefaultSpawnpoint], a
+
+ ld a, MAPSETUP_WARP
+ ldh [hMapEntryMethod], a
+ jp FinishContinueFunction
+
+ResetWRAM:
+ xor a
+ ldh [hBGMapMode], a
+ call _ResetWRAM
+ ret
+
+_ResetWRAM:
+ ld hl, wVirtualOAM
+ ld bc, wOptions - wVirtualOAM
+ xor a
+ call ByteFill
+
+ ld hl, wGameData
+ ld bc, wGameDataEnd - wGameData
+ xor a
+ call ByteFill
+
+ ldh a, [rLY]
+ ldh [hUnusedBackup], a
+ call DelayFrame
+ ldh a, [hRandomSub]
+ ld [wPlayerID], a
+
+ ldh a, [rLY]
+ ldh [hUnusedBackup], a
+ call DelayFrame
+ ldh a, [hRandomAdd]
+ ld [wPlayerID + 1], a
+
+ ld hl, wPartyCount
+ call .InitList
+
+ xor a
+ ld [wCurBox], a
+ ld [wSavedAtLeastOnce], a
+
+ call SetDefaultBoxNames
+
+ ld a, BANK(sBoxCount)
+ call OpenSRAM
+ ld hl, sBoxCount
+ call .InitList
+ call CloseSRAM
+
+ ld hl, wNumItems
+ call .InitList
+
+ ld hl, wNumKeyItems
+ call .InitList
+
+ ld hl, wNumBalls
+ call .InitList
+
+ ld hl, wNumPCItems
+ call .InitList
+
+ xor a
+ ld [wRoamMon1Species], a
+ ld [wRoamMon2Species], a
+ ld [wRoamMon3Species], a
+ ld a, -1
+ ld [wRoamMon1MapGroup], a
+ ld [wRoamMon2MapGroup], a
+ ld [wRoamMon3MapGroup], a
+ ld [wRoamMon1MapNumber], a
+ ld [wRoamMon2MapNumber], a
+ ld [wRoamMon3MapNumber], a
+
+ ld a, BANK(sMysteryGiftItem)
+ call OpenSRAM
+ ld hl, sMysteryGiftItem
+ xor a
+ ld [hli], a
+ dec a
+ ld [hl], a
+ call CloseSRAM
+
+ call LoadOrRegenerateLuckyIDNumber
+ call InitializeMagikarpHouse
+
+ xor a
+ ld [wMonType], a
+
+ ld [wJohtoBadges], a
+ ld [wKantoBadges], a
+
+ ld [wCoins], a
+ ld [wCoins + 1], a
+
+if START_MONEY >= $10000
+ ld a, HIGH(START_MONEY >> 8)
+endc
+ ld [wMoney], a
+ ld a, HIGH(START_MONEY) ; mid
+ ld [wMoney + 1], a
+ ld a, LOW(START_MONEY)
+ ld [wMoney + 2], a
+
+ xor a
+ ld [wWhichMomItem], a
+
+ ld hl, wMomItemTriggerBalance
+ ld [hl], HIGH(MOM_MONEY >> 8)
+ inc hl
+ ld [hl], HIGH(MOM_MONEY) ; mid
+ inc hl
+ ld [hl], LOW(MOM_MONEY)
+
+ call InitializeNPCNames
+
+ farcall InitDecorations
+
+ farcall DeletePartyMonMail
+
+ call ResetGameTime
+ ret
+
+.InitList:
+; Loads 0 in the count and -1 in the first item or mon slot.
+ xor a
+ ld [hli], a
+ dec a
+ ld [hl], a
+ ret
+
+SetDefaultBoxNames:
+ ld hl, wBoxNames
+ ld c, 0
+.loop
+ push hl
+ ld de, .Box
+ call CopyName2
+ dec hl
+ ld a, c
+ inc a
+ cp 10
+ jr c, .less
+ sub 10
+ ld [hl], "1"
+ inc hl
+
+.less
+ add "0"
+ ld [hli], a
+ ld [hl], "@"
+ pop hl
+ ld de, 9
+ add hl, de
+ inc c
+ ld a, c
+ cp NUM_BOXES
+ jr c, .loop
+ ret
+
+.Box:
+ db "BOX@"
+
+InitializeMagikarpHouse:
+ ld hl, wBestMagikarpLengthFeet
+ ld a, $3
+ ld [hli], a
+ ld a, $6
+ ld [hli], a
+ ld de, .Ralph
+ call CopyName2
+ ret
+
+.Ralph:
+ db "RALPH@"
+
+InitializeNPCNames:
+ ld hl, .Rival
+ ld de, wRivalName
+ call .Copy
+
+ ld hl, .Mom
+ ld de, wMomsName
+ call .Copy
+
+ ld hl, .Red
+ ld de, wRedsName
+ call .Copy
+
+ ld hl, .Green
+ ld de, wGreensName
+
+.Copy:
+ ld bc, NAME_LENGTH
+ call CopyBytes
+ ret
+
+.Rival: db "???@"
+.Red: db "RED@"
+.Green: db "GREEN@"
+.Mom: db "MOM@"
+
+InitializeWorld:
+ call ShrinkPlayer
+ farcall SpawnPlayer
+ farcall _InitializeStartDay
+ ret
+
+LoadOrRegenerateLuckyIDNumber:
+ ld a, BANK(sLuckyIDNumber)
+ call OpenSRAM
+ ld a, [wCurDay]
+ inc a
+ ld b, a
+ ld a, [sLuckyNumberDay]
+ cp b
+ ld a, [sLuckyIDNumber + 1]
+ ld c, a
+ ld a, [sLuckyIDNumber]
+ jr z, .skip
+ ld a, b
+ ld [sLuckyNumberDay], a
+ call Random
+ ld c, a
+ call Random
+
+.skip
+ ld [wLuckyIDNumber], a
+ ld [sLuckyIDNumber], a
+ ld a, c
+ ld [wLuckyIDNumber + 1], a
+ ld [sLuckyIDNumber + 1], a
+ jp CloseSRAM
+
+MainMenu_Continue:
+Continue:
+ farcall TryLoadSaveFile
+ jr c, .FailToLoad
+ call LoadStandardMenuHeader
+ call DisplaySaveInfoOnContinue
+ ld a, $1
+ ldh [hBGMapMode], a
+ ld c, 20
+ call DelayFrames
+ call ConfirmContinue
+ jr nc, .Check1Pass
+ call CloseWindow
+ jr .FailToLoad
+
+.Check1Pass:
+ call Continue_CheckRTC_RestartClock
+ jr nc, .Check2Pass
+ call CloseWindow
+ jr .FailToLoad
+
+.Check2Pass:
+ ld a, $8
+ ld [wMusicFade], a
+ ld a, LOW(MUSIC_NONE)
+ ld [wMusicFadeID], a
+ ld a, HIGH(MUSIC_NONE)
+ ld [wMusicFadeID + 1], a
+ call ClearBGPalettes
+ call CloseWindow
+ call ClearTilemap
+ ld c, 20
+ call DelayFrames
+ farcall JumpRoamMons
+ farcall MysteryGift_CopyReceivedDecosToPC ; Mystery Gift
+ farcall ClockContinue
+ ld a, [wSpawnAfterChampion]
+ cp SPAWN_LANCE
+ jr z, .SpawnAfterE4
+ ld a, MAPSETUP_CONTINUE
+ ldh [hMapEntryMethod], a
+ jp FinishContinueFunction
+
+.FailToLoad:
+ ret
+
+.SpawnAfterE4:
+ ld a, SPAWN_NEW_BARK
+ ld [wDefaultSpawnpoint], a
+ call PostCreditsSpawn
+ jp FinishContinueFunction
+
+SpawnAfterRed:
+ ld a, SPAWN_MT_SILVER
+ ld [wDefaultSpawnpoint], a
+
+PostCreditsSpawn:
+ xor a
+ ld [wSpawnAfterChampion], a
+ ld a, MAPSETUP_WARP
+ ldh [hMapEntryMethod], a
+ ret
+
+ConfirmContinue:
+.loop
+ call DelayFrame
+ call GetJoypad
+ ld hl, hJoyPressed
+ bit A_BUTTON_F, [hl]
+ jr nz, .PressA
+ bit B_BUTTON_F, [hl]
+ jr z, .loop
+ scf
+ ret
+
+.PressA:
+ ret
+
+Continue_CheckRTC_RestartClock:
+ call CheckRTCStatus
+ and %10000000 ; Day count exceeded 16383
+ jr z, .pass
+ farcall RestartClock
+ ld a, c
+ and a
+ jr z, .pass
+ scf
+ ret
+
+.pass
+ xor a
+ ret
+
+FinishContinueFunction:
+.loop
+ xor a
+ ld [wDontPlayMapMusicOnReload], a
+ ld hl, wGameTimerPause
+ set GAMETIMERPAUSE_TIMER_PAUSED_F, [hl]
+ farcall OverworldLoop
+ ld a, [wSpawnAfterChampion]
+ cp SPAWN_RED
+ jr z, .AfterRed
+ jp Reset
+
+.AfterRed:
+ call SpawnAfterRed
+ jr .loop
+
+DisplaySaveInfoOnContinue:
+ call CheckRTCStatus
+ and %10000000
+ jr z, .clock_ok
+ lb de, 4, 8
+ call DisplayContinueDataWithRTCError
+ ret
+
+.clock_ok
+ lb de, 4, 8
+ call DisplayNormalContinueData
+ ret
+
+DisplayNormalContinueData:
+ call Continue_LoadMenuHeader
+ call Continue_DisplayBadgesDex
+ call Continue_PrintGameTime
+ call LoadFontsExtra
+ call UpdateSprites
+ ret
+
+DisplayContinueDataWithRTCError:
+ call Continue_LoadMenuHeader
+ call Continue_DisplayBadgesDex
+ call Continue_UnknownGameTime
+ call LoadFontsExtra
+ call UpdateSprites
+ ret
+
+Continue_LoadMenuHeader:
+ xor a
+ ldh [hBGMapMode], a
+ ld hl, .MenuHeader_Dex
+ ld a, [wStatusFlags]
+ bit STATUSFLAGS_POKEDEX_F, a
+ jr nz, .show_menu
+ ld hl, .MenuHeader_NoDex
+
+.show_menu
+ call _OffsetMenuHeader
+ call MenuBox
+ call PlaceVerticalMenuItems
+ ret
+
+.MenuHeader_Dex:
+ db MENU_BACKUP_TILES ; flags
+ menu_coords 0, 0, 15, 9
+ dw .MenuData_Dex
+ db 1 ; default option
+
+.MenuData_Dex:
+ db 0 ; flags
+ db 4 ; items
+ db "PLAYER <PLAYER>@"
+ db "BADGES@"
+ db "#DEX@"
+ db "TIME@"
+
+.MenuHeader_NoDex:
+ db MENU_BACKUP_TILES ; flags
+ menu_coords 0, 0, 15, 9
+ dw .MenuData_NoDex
+ db 1 ; default option
+
+.MenuData_NoDex:
+ db 0 ; flags
+ db 4 ; items
+ db "PLAYER <PLAYER>@"
+ db "BADGES@"
+ db " @"
+ db "TIME@"
+
+Continue_DisplayBadgesDex:
+ call MenuBoxCoord2Tile
+ push hl
+ decoord 13, 4, 0
+ add hl, de
+ call Continue_DisplayBadgeCount
+ pop hl
+ push hl
+ decoord 12, 6, 0
+ add hl, de
+ call Continue_DisplayPokedexNumCaught
+ pop hl
+ ret
+
+Continue_PrintGameTime:
+ decoord 9, 8, 0
+ add hl, de
+ call Continue_DisplayGameTime
+ ret
+
+Continue_UnknownGameTime:
+ decoord 9, 8, 0
+ add hl, de
+ ld de, .three_question_marks
+ call PlaceString
+ ret
+
+.three_question_marks
+ db " ???@"
+
+Continue_DisplayBadgeCount:
+ push hl
+ ld hl, wJohtoBadges
+ ld b, 2
+ call CountSetBits
+ pop hl
+ ld de, wNumSetBits
+ lb bc, 1, 2
+ jp PrintNum
+
+Continue_DisplayPokedexNumCaught:
+ ld a, [wStatusFlags]
+ bit STATUSFLAGS_POKEDEX_F, a
+ ret z
+ push hl
+ ld hl, wPokedexCaught
+if NUM_POKEMON % 8
+ ld b, NUM_POKEMON / 8 + 1
+else
+ ld b, NUM_POKEMON / 8
+endc
+ call CountSetBits
+ pop hl
+ ld de, wNumSetBits
+ lb bc, 1, 3
+ jp PrintNum
+
+Continue_DisplayGameTime:
+ ld de, wGameTimeHours
+ lb bc, 2, 3
+ call PrintNum
+ ld [hl], "<COLON>"
+ inc hl
+ ld de, wGameTimeMinutes
+ lb bc, PRINTNUM_LEADINGZEROS | 1, 2
+ jp PrintNum
+
+OakSpeech:
+ farcall InitClock
+ call RotateFourPalettesLeft
+ call ClearTilemap
+
+ ld de, MUSIC_ROUTE_30
+ call PlayMusic
+
+ call RotateFourPalettesRight
+ call RotateThreePalettesRight
+ xor a
+ ld [wCurPartySpecies], a
+ ld a, POKEMON_PROF
+ ld [wTrainerClass], a
+ call Intro_PrepTrainerPic
+
+ ld b, SCGB_TRAINER_OR_MON_FRONTPIC_PALS
+ call GetSGBLayout
+ call Intro_RotatePalettesLeftFrontpic
+
+ ld hl, OakText1
+ call PrintText
+ call RotateThreePalettesRight
+ call ClearTilemap
+
+ ld a, MARILL
+ ld [wCurSpecies], a
+ ld [wCurPartySpecies], a
+ call GetBaseData
+
+ hlcoord 6, 4
+ hlcoord 6, 4 ; TriHard
+ call PrepMonFrontpic
+
+ xor a
+ ld [wTempMonDVs], a
+ ld [wTempMonDVs + 1], a
+
+ ld b, SCGB_TRAINER_OR_MON_FRONTPIC_PALS
+ call GetSGBLayout
+ call Intro_WipeInFrontpic
+
+ ld hl, OakText2
+ call PrintText
+ ld hl, OakText4
+ call PrintText
+ call RotateThreePalettesRight
+ call ClearTilemap
+
+ xor a
+ ld [wCurPartySpecies], a
+ ld a, POKEMON_PROF
+ ld [wTrainerClass], a
+ call Intro_PrepTrainerPic
+
+ ld b, SCGB_TRAINER_OR_MON_FRONTPIC_PALS
+ call GetSGBLayout
+ call Intro_RotatePalettesLeftFrontpic
+
+ ld hl, OakText5
+ call PrintText
+ call RotateThreePalettesRight
+ call ClearTilemap
+
+ xor a
+ ld [wCurPartySpecies], a
+ ld a, CAL
+ ld [wTrainerClass], a
+ call Intro_PrepTrainerPic
+
+ ld b, SCGB_TRAINER_OR_MON_FRONTPIC_PALS
+ call GetSGBLayout
+ call Intro_RotatePalettesLeftFrontpic
+
+ ld hl, OakText6
+ call PrintText
+ call NamePlayer
+ ld hl, OakText7
+ call PrintText
+ ret
+
+OakText1:
+ text_far _OakText1
+ text_end
+
+OakText2:
+ text_far _OakText2
+ text_asm
+ ld a, MARILL
+ call PlayMonCry
+ call WaitSFX
+ ld hl, OakText3
+ ret
+
+OakText3:
+ text_far _OakText3
+ text_end
+
+OakText4:
+ text_far _OakText4
+ text_end
+
+OakText5:
+ text_far _OakText5
+ text_end
+
+OakText6:
+ text_far _OakText6
+ text_end
+
+OakText7:
+ text_far _OakText7
+ text_end
+
+NamePlayer:
+ call MovePlayerPicRight
+ ld hl, NameMenuHeader
+ call ShowPlayerNamingChoices
+ ld a, [wMenuCursorY]
+ dec a
+ jr z, .NewName
+ ld de, wPlayerName
+ call StorePlayerName
+ farcall ApplyMonOrTrainerPals
+ call MovePlayerPicLeft
+ ret
+
+.NewName:
+ ld b, NAME_PLAYER
+ ld de, wPlayerName
+ farcall NamingScreen
+
+ call RotateThreePalettesRight
+ call ClearTilemap
+
+ call LoadFontsExtra
+ call WaitBGMap
+
+ xor a
+ ld [wCurPartySpecies], a
+ ld a, CAL
+ ld [wTrainerClass], a
+ call Intro_PrepTrainerPic
+
+ ld b, SCGB_TRAINER_OR_MON_FRONTPIC_PALS
+ call GetSGBLayout
+ call RotateThreePalettesLeft
+
+ ld hl, wPlayerName
+ ld de, PlayerNameArray
+ call InitName
+ ret
+
+INCLUDE "data/player_names.asm"
+
+ShowPlayerNamingChoices:
+ call LoadMenuHeader
+ call VerticalMenu
+ ld a, [wMenuCursorY]
+ dec a
+ call CopyNameFromMenu
+ call CloseWindow
+ ret
+
+StorePlayerName:
+ ld hl, wStringBuffer2
+ ld bc, NAME_LENGTH
+ call CopyBytes
+ ret
+
+ShrinkPlayer:
+ ldh a, [hROMBank]
+ push af
+
+ ld a, 32 ; fade time
+ ld [wMusicFade], a
+ ld de, MUSIC_NONE
+ ld a, e
+ ld [wMusicFadeID], a
+ ld a, d
+ ld [wMusicFadeID + 1], a
+
+ ld de, SFX_ESCAPE_ROPE
+ call PlaySFX
+ pop af
+ rst Bankswitch
+
+ ld c, 8
+ call DelayFrames
+
+ ld hl, Shrink1Pic
+ ld b, BANK(Shrink1Pic)
+ call ShrinkFrame
+
+ ld c, 8
+ call DelayFrames
+
+ ld hl, Shrink2Pic
+ ld b, BANK(Shrink2Pic)
+ call ShrinkFrame
+
+ ld c, 8
+ call DelayFrames
+
+ hlcoord 6, 5
+ ld b, 7
+ ld c, 7
+ call ClearBox
+
+ ld c, 3
+ call DelayFrames
+
+ call Intro_PlaceChrisSprite
+ call LoadFontsExtra
+
+ ld c, 50
+ call DelayFrames
+
+ call RotateThreePalettesRight
+ call ClearTilemap
+ ret
+
+MovePlayerPicRight:
+ hlcoord 6, 4
+ ld de, $1
+ jr MovePlayerPic
+
+MovePlayerPicLeft:
+ hlcoord 13, 4
+ ld de, -1
+MovePlayerPic:
+ ld c, $8
+.loop
+ push bc
+ push hl
+ push de
+ xor a
+ ldh [hBGMapMode], a
+ lb bc, 7, 7
+ predef PlaceGraphic
+ xor a
+ ldh [hBGMapThird], a
+ call WaitBGMap
+ call DelayFrame
+ pop de
+ pop hl
+ add hl, de
+ pop bc
+ dec c
+ jr nz, .loop
+ ret
+
+Intro_RotatePalettesLeftFrontpic:
+ ld hl, IntroFadePalettes
+ ld b, IntroFadePalettes.End - IntroFadePalettes
+.loop
+ ld a, [hli]
+ call DmgToCgbBGPals
+ ld c, 10
+ call DelayFrames
+ dec b
+ jr nz, .loop
+ ret
+
+IntroFadePalettes:
+ dc 1, 1, 1, 0
+ dc 2, 2, 2, 0
+ dc 3, 3, 3, 0
+ dc 3, 3, 2, 0
+ dc 3, 3, 1, 0
+ dc 3, 2, 1, 0
+.End
+
+Intro_WipeInFrontpic:
+ ld a, $77
+ ldh [hWX], a
+ call DelayFrame
+ ld a, %11100100
+ call DmgToCgbBGPals
+.loop
+ call DelayFrame
+ ldh a, [hWX]
+ sub $8
+ cp -1
+ ret z
+ ldh [hWX], a
+ jr .loop
+
+Intro_PrepTrainerPic:
+ ld de, vTiles2
+ farcall GetTrainerPic
+ xor a
+ ldh [hGraphicStartTile], a
+ hlcoord 6, 4
+ lb bc, 7, 7
+ predef PlaceGraphic
+ ret
+
+ShrinkFrame:
+ ld de, vTiles2
+ ld c, 7 * 7
+ predef DecompressGet2bpp
+ xor a
+ ldh [hGraphicStartTile], a
+ hlcoord 6, 4
+ lb bc, 7, 7
+ predef PlaceGraphic
+ ret
+
+Intro_PlaceChrisSprite:
+ ld de, ChrisSpriteGFX
+ lb bc, BANK(ChrisSpriteGFX), 12
+ ld hl, vTiles0
+ call Request2bpp
+
+ ld hl, wVirtualOAMSprite00
+ ld de, .sprites
+ ld a, [de]
+ inc de
+
+ ld c, a
+.loop
+ ld a, [de]
+ inc de
+ ld [hli], a ; y
+ ld a, [de]
+ inc de
+ ld [hli], a ; x
+ ld a, [de]
+ inc de
+ ld [hli], a ; tile id
+ xor a ; PAL_OW_RED
+ ld [hli], a
+ dec c
+ jr nz, .loop
+ ret
+
+.sprites
+ db 4
+ ; y pxl, x pxl, tile offset
+ db 9 * 8 + 4, 9 * 8, 0
+ db 9 * 8 + 4, 10 * 8, 1
+ db 10 * 8 + 4, 9 * 8, 2
+ db 10 * 8 + 4, 10 * 8, 3
+
+IntroSequence:
+ callfar Copyright_GFPresents
+ jr c, StartTitleScreen
+ callfar GoldSilverIntro
+
+ ; fallthrough
+
+StartTitleScreen:
+ call TitleScreen
+ call DelayFrame
+.loop
+ call RunTitleScreen
+ jr nc, .loop
+
+ call ClearSprites
+ call ClearBGPalettes
+
+ ld hl, rLCDC
+ res rLCDC_SPRITE_SIZE, [hl] ; 8x8
+ call ClearTilemap
+ xor a
+ ldh [hLCDCPointer], a
+ ld b, SCGB_DIPLOMA
+ call GetSGBLayout
+ call UpdateTimePals
+ ld a, [wIntroSceneFrameCounter]
+ cp $5
+ jr c, .ok
+ xor a
+.ok
+ ld e, a
+ ld d, 0
+ ld hl, .dw
+ add hl, de
+ add hl, de
+ ld a, [hli]
+ ld h, [hl]
+ ld l, a
+ jp hl
+
+.dw
+ dw MainMenu
+ dw DeleteSaveData
+ dw IntroSequence
+ dw IntroSequence
+ dw ResetClock
+
+INCLUDE "engine/movie/title.asm"
+
+RunTitleScreen:
+ call Function63fe
+ ld a, [wJumptableIndex]
+ bit 7, a
+ jr nz, .done_title
+ call TitleScreenScene
+ ld a, $1
+ ldh [hOAMUpdate], a
+ farcall PlaySpriteAnimations
+ xor a
+ ldh [hOAMUpdate], a
+ call Function64b1
+ call DelayFrame
+ and a
+ ret
+
+.done_title
+ scf
+ ret
+
+Function63fe:
+IF DEF(_GOLD)
+ ldh a, [hVBlankCounter]
+ and $7
+ ret nz
+ENDC
+ ld hl, wLYOverrides + $5f
+ ld a, [hl]
+ dec a
+ ld bc, 2 * SCREEN_WIDTH
+ call ByteFill
+ ret
+
+TitleScreenScene:
+ ld e, a
+ ld d, 0
+ ld hl, .scenes
+ add hl, de
+ add hl, de
+ ld a, [hli]
+ ld h, [hl]
+ ld l, a
+ jp hl
+
+.scenes
+ dw TitleScreenTimer
+ dw TitleScreenMain
+ dw TitleScreenEnd
+
+.Unreferenced_NextScene:
+ ld hl, wJumptableIndex
+ inc [hl]
+ ret
+
+TitleScreenTimer:
+; Next scene
+ ld hl, wJumptableIndex
+ inc [hl]
+
+; Start a timer
+ ld hl, wTitleScreenTimer
+IF DEF(_GOLD)
+ ld de, 84 * 60 + 16
+ELIF DEF(_SILVER)
+ ld de, 73 * 60 + 36
+ENDC
+ ld [hl], e
+ inc hl
+ ld [hl], d
+ ret
+
+TitleScreenMain:
+; Run the timer down.
+ ld hl, wTitleScreenTimer
+ ld e, [hl]
+ inc hl
+ ld d, [hl]
+ ld a, e
+ or d
+ jr z, .end
+
+ dec de
+ ld [hl], d
+ dec hl
+ ld [hl], e
+
+; Save data can be deleted by pressing Up + B + Select.
+ call GetJoypad
+ ld hl, hJoyDown
+ ld a, [hl]
+ and D_UP + B_BUTTON + SELECT
+ cp D_UP + B_BUTTON + SELECT
+ jr z, .delete_save_data
+
+; Clock can be reset by pressing Down + B + Select.
+ ld a, [hl]
+ and D_DOWN + B_BUTTON + SELECT
+ cp D_DOWN + B_BUTTON + SELECT
+ jr z, .clock_reset
+ ld a, [hl]
+ and START | A_BUTTON
+ jr nz, .incave
+ ret
+
+.incave
+ ld a, 0
+ jr .done
+
+.delete_save_data
+ ld a, 1
+
+.done
+ ld [wIntroSceneFrameCounter], a
+
+; Return to the intro sequence.
+ ld hl, wJumptableIndex
+ set 7, [hl]
+ ret
+
+.end
+; Next scene
+ ld hl, wJumptableIndex
+ inc [hl]
+
+; Fade out the title screen music
+ xor a ; MUSIC_NONE
+ ld [wMusicFadeID], a
+ ld [wMusicFadeID + 1], a
+ ld hl, wMusicFade
+ ld [hl], 8 ; 1 second
+
+ ld hl, wTitleScreenTimer
+ inc [hl]
+ ret
+
+.clock_reset
+ ld a, 4
+ ld [wIntroSceneFrameCounter], a
+
+; Return to the intro sequence.
+ ld hl, wJumptableIndex
+ set 7, [hl]
+ ret
+
+TitleScreenEnd:
+; Wait until the music is done fading.
+
+ ld hl, wTitleScreenTimer
+ inc [hl]
+
+ ld a, [wMusicFade]
+ and a
+ ret nz
+
+ ld a, 2
+ ld [wIntroSceneFrameCounter], a
+
+; Back to the intro.
+ ld hl, wJumptableIndex
+ set 7, [hl]
+ ret
+
+DeleteSaveData:
+ farcall _DeleteSaveData
+ jp Init
+
+ResetClock:
+ farcall _ResetClock
+ jp Init
+
+Function64b1:
+ ; If bit 0 or 1 of [wTitleScreenTimer] is set, we don't need to be here.
+ ld a, [wTitleScreenTimer]
+ and %00000011
+ ret nz
+IF DEF(_GOLD)
+ ld bc, wSpriteAnim10
+ ld hl, SPRITEANIMSTRUCT_FRAME
+ add hl, bc
+ ld l, [hl]
+ ld h, 0
+ add hl, hl
+ add hl, hl
+ ld de, .Data_64e0
+ add hl, de
+ ; If bit 2 of [wTitleScreenTimer] is set, get the second dw; else, get the first dw
+ ld a, [wTitleScreenTimer]
+ and %00000100
+ srl a
+ srl a
+ ld e, a
+ ld d, 0
+ add hl, de
+ add hl, de
+ ld a, [hli]
+ and a
+ ret z
+ ld e, a
+ ld d, [hl]
+ELIF DEF(_SILVER)
+ depixel 15, 11, 4, 0
+ENDC
+ ld a, SPRITE_ANIM_INDEX_GS_TITLE_TRAIL
+ call InitSpriteAnimStruct
+ ret
+
+IF DEF(_GOLD)
+.Data_64e0:
+; frame 0 y, x; frame 1 y, x
+ db 11 * 8 + 4, 10 * 8, 0 * 8, 0 * 8
+ db 11 * 8 + 4, 13 * 8, 11 * 8 + 4, 11 * 8
+ db 11 * 8 + 4, 13 * 8, 11 * 8 + 4, 15 * 8
+ db 11 * 8 + 4, 17 * 8, 11 * 8 + 4, 15 * 8
+ db 0 * 8, 0 * 8, 11 * 8 + 4, 15 * 8
+ db 0 * 8, 0 * 8, 11 * 8 + 4, 11 * 8
+ENDC
+
+Copyright:
+ call ClearTilemap
+ call LoadFontsExtra
+ ld de, CopyrightGFX
+ ld hl, vTiles2 tile $60
+ lb bc, BANK(CopyrightGFX), 30
+ call Request2bpp
+ hlcoord 2, 7
+ ld de, CopyrightString
+ jp PlaceString
+
+CopyrightString:
+ ; ©1995-2000 Nintendo
+ db $60, $61, $62, $63, $7a, $7b, $7c, $7d
+ db $65, $66, $67, $68, $69, $6a
+
+ ; ©1995-2000 Creatures inc.
+ next $60, $61, $62, $63, $7a, $7b, $7c, $7d
+ db $6b, $6c, $6d, $6e, $6f, $70, $71, $72
+
+ ; ©1995-2000 GAME FREAK inc.
+ next $60, $61, $62, $63, $7a, $7b, $7c, $7d
+ db $73, $74, $75, $76, $77, $78, $79, $71, $72
+
+ db "@"
+
+GameInit::
+ call ClearWindowData
+ farcall TryLoadSaveData
+ jp IntroSequence
diff --git a/engine/menus/main_menu.asm b/engine/menus/main_menu.asm
new file mode 100644
index 00000000..4e9113a8
--- /dev/null
+++ b/engine/menus/main_menu.asm
@@ -0,0 +1,253 @@
+MainMenu:
+ ld de, MUSIC_NONE
+ call PlayMusic
+ call DelayFrame
+ ld de, MUSIC_MAIN_MENU
+ ld a, e
+ ld [wMapMusic], a
+ call PlayMusic
+.loop
+ xor a
+ ld [wDisableTextAcceleration], a
+ call ClearTilemapEtc
+ ld b, SCGB_DIPLOMA
+ call GetSGBLayout
+ ld hl, wGameTimerPause
+ res GAMETIMERPAUSE_TIMER_PAUSED_F, [hl]
+ call MainMenu_GetWhichMenu
+ ld [wWhichIndexSet], a
+ call MainMenu_PrintCurrentTimeAndDay
+ ld hl, .MenuHeader
+ call LoadMenuHeader
+ call MainMenuJoypadLoop
+ call CloseWindow
+ jr c, .quit
+ call ClearTilemap
+ ld a, [wMenuSelection]
+ ld hl, .Jumptable
+ rst JumpTable
+ jr .loop
+
+.quit
+ jp StartTitleScreen
+
+.MenuHeader:
+ db MENU_BACKUP_TILES ; flags
+ menu_coords 0, 0, 14, 7
+ dw .MenuData
+ db 1 ; default option
+
+.MenuData:
+ db STATICMENU_CURSOR ; flags
+ db 0 ; items
+ dw MainMenuItems
+ dw PlaceMenuStrings
+ dw .Strings
+
+.Strings:
+ db "CONTINUE@"
+ db "NEW GAME@"
+ db "OPTION@"
+ db "MYSTERY GIFT@"
+
+.Jumptable:
+ dw MainMenu_Continue
+ dw MainMenu_NewGame
+ dw MainMenu_Options
+ dw MainMenu_MysteryGift
+
+CONTINUE EQU 0
+NEW_GAME EQU 1
+OPTION EQU 2
+MYSTERY_GIFT EQU 3
+
+MainMenuItems:
+
+NewGameMenu:
+ db 2
+ db NEW_GAME
+ db OPTION
+ db -1
+
+ContinueMenu:
+ db 3
+ db CONTINUE
+ db NEW_GAME
+ db OPTION
+ db -1
+
+MysteryMenu:
+ db 4
+ db CONTINUE
+ db NEW_GAME
+ db OPTION
+ db MYSTERY_GIFT
+ db -1
+
+MainMenu_GetWhichMenu:
+ nop
+ nop
+ nop
+ ld a, [wSaveFileExists]
+ and a
+ jr nz, .next
+ ld a, $0 ; New Game
+ ret
+
+.next
+ ldh a, [hCGB]
+ cp $1
+ ld a, $1
+ ret nz
+ ld a, BANK(sNumDailyMysteryGiftPartnerIDs)
+ call OpenSRAM
+ ld a, [sNumDailyMysteryGiftPartnerIDs]
+ cp -1
+ call CloseSRAM
+ ld a, $1 ; Continue
+ ret z
+ ld a, $2 ; New Game
+ ret
+
+MainMenuJoypadLoop:
+ call SetUpMenu
+.loop
+ call MainMenu_PrintCurrentTimeAndDay
+ call GetScrollingMenuJoypad
+ ld a, [wMenuJoypad]
+ cp B_BUTTON
+ jr z, .b_button
+ cp A_BUTTON
+ jr z, .a_button
+ jr .loop
+
+.a_button
+ call PlayClickSFX
+ and a
+ ret
+
+.b_button
+ scf
+ ret
+
+MainMenu_PrintCurrentTimeAndDay:
+ ld a, [wSaveFileExists]
+ and a
+ ret z
+ xor a
+ ldh [hBGMapMode], a
+ call .PlaceBox
+ ld hl, wOptions
+ ld a, [hl]
+ push af
+ set NO_TEXT_SCROLL, [hl]
+ call .PlaceTime
+ pop af
+ ld [wOptions], a
+ ld a, $1
+ ldh [hBGMapMode], a
+ ret
+
+.PlaceBox:
+ call CheckRTCStatus
+ and $80
+ jr nz, .TimeFail
+ hlcoord 0, 12
+ ld b, 4
+ ld c, 13
+ call Textbox
+ ret
+
+.TimeFail:
+ call SpeechTextbox
+ ret
+
+.PlaceTime:
+ ld a, [wSaveFileExists]
+ and a
+ ret z
+ call CheckRTCStatus
+ and %10000000 ; Day count exceeded 16383
+ jp nz, .PrintTimeNotSet
+ call UpdateTime
+ hlcoord 1, 13
+ lb bc, 4, 13
+ call ClearBox
+ call GetWeekday
+ ld b, a
+ decoord 1, 14
+ call .PlaceCurrentDay
+ decoord 4, 16
+ ldh a, [hHours]
+ ld c, a
+ farcall PrintHour
+ ld [hl], ":"
+ inc hl
+ ld de, hMinutes
+ lb bc, PRINTNUM_LEADINGZEROS | 1, 2
+ call PrintNum
+ ret
+
+.min
+; unused
+ db "min.@"
+
+.PrintTimeNotSet:
+ hlcoord 1, 14
+ ld de, .TimeNotSet
+ call PlaceString
+ ret
+
+.TimeNotSet:
+ db "TIME NOT SET@"
+
+.MainMenuTimeUnknownText:
+ text_far _MainMenuTimeUnknownText
+ text_end
+
+.PlaceCurrentDay:
+ push de
+ ld hl, .Days
+ ld a, b
+ call GetNthString
+ ld d, h
+ ld e, l
+ pop hl
+ call PlaceString
+ ld h, b
+ ld l, c
+ ld de, .Day
+ call PlaceString
+ ret
+
+.Days:
+ db "SUN@"
+ db "MON@"
+ db "TUES@"
+ db "WEDNES@"
+ db "THURS@"
+ db "FRI@"
+ db "SATUR@"
+.Day:
+ db "DAY@"
+
+ClearTilemapEtc:
+ xor a
+ ldh [hMapAnims], a
+ call ClearTilemap
+ call LoadFontsExtra
+ call LoadStandardFont
+ call ClearWindowData
+ ret
+
+MainMenu_MysteryGift:
+MysteryGift:
+ call UpdateTime
+ farcall DoMysteryGiftIfDayHasPassed
+ farcall DoMysteryGift
+ ret
+
+MainMenu_Options:
+OptionsMenu:
+ farcall _OptionsMenu
+ ret
diff --git a/engine/menus/menu.asm b/engine/menus/menu.asm
new file mode 100644
index 00000000..b678d714
--- /dev/null
+++ b/engine/menus/menu.asm
@@ -0,0 +1,675 @@
+_2DMenu_::
+ xor a
+ ldh [hBGMapMode], a
+ call MenuBox
+ call Place2DMenuItemStrings
+ call UpdateSprites
+ call ApplyTilemap
+ call Init2DMenuCursorPosition
+ call StaticMenuJoypad
+ call MenuClickSound
+ ld a, [wMenuDataFlags]
+ bit 1, a
+ jr z, .skip
+ call GetMenuJoypad
+ bit SELECT_F, a
+ jr nz, .quit1
+
+.skip
+ ld a, [wMenuDataFlags]
+ bit 0, a
+ jr nz, .skip2
+ call GetMenuJoypad
+ bit B_BUTTON_F, a
+ jr nz, .quit2
+
+.skip2
+ ld a, [w2DMenuNumCols]
+ ld c, a
+ ld a, [wMenuCursorY]
+ dec a
+ call SimpleMultiply
+ ld c, a
+ ld a, [wMenuCursorX]
+ add c
+ ld [wMenuCursorBuffer], a
+ and a
+ ret
+
+.quit1
+ scf
+ ret
+
+.quit2
+ scf
+ ret
+
+Get2DMenuNumberOfColumns:
+ ld a, [wMenuData_2DMenuDimensions]
+ and $f
+ ret
+
+Get2DMenuNumberOfRows:
+ ld a, [wMenuData_2DMenuDimensions]
+ swap a
+ and $f
+ ret
+
+Place2DMenuItemStrings:
+ ld hl, wMenuData_2DMenuItemStringsAddr
+ ld e, [hl]
+ inc hl
+ ld d, [hl]
+ call GetMenuTextStartCoord
+ call Coord2Tile
+ call Get2DMenuNumberOfRows
+ ld b, a
+.row
+ push bc
+ push hl
+ call Get2DMenuNumberOfColumns
+ ld c, a
+.col
+ push bc
+ ld a, [wMenuData_2DMenuItemStringsBank]
+ call Place2DMenuItemName
+ inc de
+ ld a, [wMenuData_2DMenuSpacing]
+ ld c, a
+ ld b, 0
+ add hl, bc
+ pop bc
+ dec c
+ jr nz, .col
+ pop hl
+ ld bc, 2 * SCREEN_WIDTH
+ add hl, bc
+ pop bc
+ dec b
+ jr nz, .row
+ ld hl, wMenuData_2DMenuFunctionAddr
+ ld a, [hli]
+ ld h, [hl]
+ ld l, a
+ or h
+ ret z
+ ld a, [wMenuData_2DMenuFunctionBank]
+ rst FarCall
+ ret
+
+Init2DMenuCursorPosition:
+ call GetMenuTextStartCoord
+ ld a, b
+ ld [w2DMenuCursorInitY], a
+ dec c
+ ld a, c
+ ld [w2DMenuCursorInitX], a
+ call Get2DMenuNumberOfRows
+ ld [w2DMenuNumRows], a
+ call Get2DMenuNumberOfColumns
+ ld [w2DMenuNumCols], a
+ call .InitFlags_a
+ call .InitFlags_b
+ call .InitFlags_c
+ ld a, [w2DMenuNumCols]
+ ld e, a
+ ld a, [wMenuCursorBuffer]
+ ld b, a
+ xor a
+ ld d, 0
+.loop
+ inc d
+ add e
+ cp b
+ jr c, .loop
+ sub e
+ ld c, a
+ ld a, b
+ sub c
+ and a
+ jr z, .reset1
+ cp e
+ jr z, .okay1
+ jr c, .okay1
+.reset1
+ ld a, 1
+.okay1
+ ld [wMenuCursorX], a
+ ld a, [w2DMenuNumRows]
+ ld e, a
+ ld a, d
+ and a
+ jr z, .reset2
+ cp e
+ jr z, .okay2
+ jr c, .okay2
+.reset2
+ ld a, 1
+.okay2
+ ld [wMenuCursorY], a
+ xor a
+ ld [wCursorOffCharacter], a
+ ld [wCursorCurrentTile], a
+ ld [wCursorCurrentTile + 1], a
+ ret
+
+.InitFlags_a:
+ xor a
+ ld hl, w2DMenuFlags1
+ ld [hli], a
+ ld [hld], a
+ ld a, [wMenuDataFlags]
+ bit 5, a
+ ret z
+ set 5, [hl]
+ set 4, [hl]
+ ret
+
+.InitFlags_b:
+ ld a, [wMenuData_2DMenuSpacing]
+ or $20
+ ld [w2DMenuCursorOffsets], a
+ ret
+
+.InitFlags_c:
+ ld hl, wMenuDataFlags
+ ld a, A_BUTTON
+ bit 0, [hl]
+ jr nz, .skip
+ or B_BUTTON
+.skip
+ bit 1, [hl]
+ jr z, .skip2
+ or SELECT
+.skip2
+ ld [wMenuJoypadFilter], a
+ ret
+
+_StaticMenuJoypad::
+ call Place2DMenuCursor
+_ScrollingMenuJoypad::
+ ld hl, w2DMenuFlags2
+ res 7, [hl]
+ ldh a, [hBGMapMode]
+ push af
+
+.menu_joypad_loop
+ call Move2DMenuCursor
+ ldh a, [hOAMUpdate]
+ push af
+ ld a, $1
+ ldh [hOAMUpdate], a
+ call WaitBGMap
+ pop af
+ ldh [hOAMUpdate], a
+ xor a
+ ldh [hBGMapMode], a
+
+.loopRTC
+ call UpdateTimeAndPals
+ call Menu_WasButtonPressed
+ jr c, .pressed
+ ld a, [w2DMenuFlags1]
+ bit 7, a
+ jp nz, .done
+ jr .loopRTC
+
+.pressed
+ call _2DMenuInterpretJoypad
+ jp c, .done
+ ld a, [w2DMenuFlags1]
+ bit 7, a
+ jr nz, .done
+ call GetMenuJoypad
+ ld b, a
+ ld a, [wMenuJoypadFilter]
+ and b
+ jp z, .menu_joypad_loop
+
+.done
+ pop af
+ ldh [hBGMapMode], a
+ call GetMenuJoypad
+ ret
+
+Menu_WasButtonPressed:
+ ld a, [w2DMenuFlags1]
+ bit 6, a
+ jr z, .skip_to_joypad
+ callfar PlaySpriteAnimationsAndDelayFrame
+
+.skip_to_joypad
+ call JoyTextDelay
+ call GetMenuJoypad
+ and a
+ ret z
+ scf
+ ret
+
+_2DMenuInterpretJoypad:
+ call GetMenuJoypad
+ bit A_BUTTON_F, a
+ jp nz, .a_b_start_select
+ bit B_BUTTON_F, a
+ jp nz, .a_b_start_select
+ bit SELECT_F, a
+ jp nz, .a_b_start_select
+ bit START_F, a
+ jp nz, .a_b_start_select
+ bit D_RIGHT_F, a
+ jr nz, .d_right
+ bit D_LEFT_F, a
+ jr nz, .d_left
+ bit D_UP_F, a
+ jr nz, .d_up
+ bit D_DOWN_F, a
+ jr nz, .d_down
+ and a
+ ret
+
+.set_bit_7
+ ld hl, w2DMenuFlags2
+ set 7, [hl]
+ scf
+ ret
+
+.d_down
+ ld hl, wMenuCursorY
+ ld a, [w2DMenuNumRows]
+ cp [hl]
+ jr z, .check_wrap_around_down
+ inc [hl]
+ xor a
+ ret
+
+.check_wrap_around_down
+ ld a, [w2DMenuFlags1]
+ bit 5, a
+ jr nz, .wrap_around_down
+ bit 3, a
+ jp nz, .set_bit_7
+ xor a
+ ret
+
+.wrap_around_down
+ ld [hl], $1
+ xor a
+ ret
+
+.d_up
+ ld hl, wMenuCursorY
+ ld a, [hl]
+ dec a
+ jr z, .check_wrap_around_up
+ ld [hl], a
+ xor a
+ ret
+
+.check_wrap_around_up
+ ld a, [w2DMenuFlags1]
+ bit 5, a
+ jr nz, .wrap_around_up
+ bit 2, a
+ jp nz, .set_bit_7
+ xor a
+ ret
+
+.wrap_around_up
+ ld a, [w2DMenuNumRows]
+ ld [hl], a
+ xor a
+ ret
+
+.d_left
+ ld hl, wMenuCursorX
+ ld a, [hl]
+ dec a
+ jr z, .check_wrap_around_left
+ ld [hl], a
+ xor a
+ ret
+
+.check_wrap_around_left
+ ld a, [w2DMenuFlags1]
+ bit 4, a
+ jr nz, .wrap_around_left
+ bit 1, a
+ jp nz, .set_bit_7
+ xor a
+ ret
+
+.wrap_around_left
+ ld a, [w2DMenuNumCols]
+ ld [hl], a
+ xor a
+ ret
+
+.d_right
+ ld hl, wMenuCursorX
+ ld a, [w2DMenuNumCols]
+ cp [hl]
+ jr z, .check_wrap_around_right
+ inc [hl]
+ xor a
+ ret
+
+.check_wrap_around_right
+ ld a, [w2DMenuFlags1]
+ bit 4, a
+ jr nz, .wrap_around_right
+ bit 0, a
+ jp nz, .set_bit_7
+ xor a
+ ret
+
+.wrap_around_right
+ ld [hl], $1
+ xor a
+ ret
+
+.a_b_start_select
+ xor a
+ ret
+
+Move2DMenuCursor:
+ ld hl, wCursorCurrentTile
+ ld a, [hli]
+ ld h, [hl]
+ ld l, a
+ ld a, [hl]
+ cp "▶"
+ jr nz, Place2DMenuCursor
+ ld a, [wCursorOffCharacter]
+ ld [hl], a
+Place2DMenuCursor:
+ ld a, [w2DMenuCursorInitY]
+ ld b, a
+ ld a, [w2DMenuCursorInitX]
+ ld c, a
+ call Coord2Tile
+ ld a, [w2DMenuCursorOffsets]
+ swap a
+ and $f
+ ld c, a
+ ld a, [wMenuCursorY]
+ ld b, a
+ xor a
+ dec b
+ jr z, .got_row
+.row_loop
+ add c
+ dec b
+ jr nz, .row_loop
+
+.got_row
+ ld c, SCREEN_WIDTH
+ call AddNTimes
+ ld a, [w2DMenuCursorOffsets]
+ and $f
+ ld c, a
+ ld a, [wMenuCursorX]
+ ld b, a
+ xor a
+ dec b
+ jr z, .got_col
+.col_loop
+ add c
+ dec b
+ jr nz, .col_loop
+
+.got_col
+ ld c, a
+ add hl, bc
+ ld a, [hl]
+ cp "▶"
+ jr z, .cursor_on
+ ld [wCursorOffCharacter], a
+ ld [hl], "▶"
+
+.cursor_on
+ ld a, l
+ ld [wCursorCurrentTile], a
+ ld a, h
+ ld [wCursorCurrentTile + 1], a
+ ret
+
+_PushWindow::
+ xor a ; BANK(sWindowStack)
+ call OpenSRAM
+
+ ld hl, wWindowStackPointer
+ ld e, [hl]
+ inc hl
+ ld d, [hl]
+ push de
+ ld b, $10
+ ld hl, wMenuFlags
+.loop
+ ld a, [hli]
+ ld [de], a
+ dec de
+ dec b
+ jr nz, .loop
+
+; If bit 6 or 7 of the menu flags is set, set bit 0 of the address
+; at 7:[wWindowStackPointer], and draw the menu using the coordinates from the header.
+; Otherwise, reset bit 0 of 7:[wWindowStackPointer].
+ ld a, [wMenuFlags]
+ bit 6, a
+ jr nz, .bit_6
+ bit 7, a
+ jr z, .not_bit_7
+
+.bit_6
+ ld hl, wWindowStackPointer
+ ld a, [hli]
+ ld h, [hl]
+ ld l, a
+ set 0, [hl]
+ call MenuBoxCoord2Tile
+ call GetMenuBoxDims
+ inc b
+ inc c
+ call .ret ; empty function
+
+.row
+ push bc
+ push hl
+
+.col
+ ld a, [hli]
+ ld [de], a
+ dec de
+ dec c
+ jr nz, .col
+
+ pop hl
+ ld bc, SCREEN_WIDTH
+ add hl, bc
+ pop bc
+ dec b
+ jr nz, .row
+ jr .done
+
+.not_bit_7
+ pop hl ; last-pushed register was de
+ push hl
+ ld a, [hld]
+ ld l, [hl]
+ ld h, a
+ res 0, [hl]
+
+.done
+ pop hl
+ call .ret ; empty function
+ ld a, h
+ ld [de], a
+ dec de
+ ld a, l
+ ld [de], a
+ dec de
+ ld hl, wWindowStackPointer
+ ld [hl], e
+ inc hl
+ ld [hl], d
+
+ call CloseSRAM
+ ld hl, wWindowStackSize
+ inc [hl]
+ ret
+
+.ret
+ ret
+
+_ExitMenu::
+ xor a
+ ldh [hBGMapMode], a
+
+ xor a ; BANK(sWindowStack)
+ call OpenSRAM
+
+ call GetWindowStackTop
+ ld a, l
+ or h
+ jp z, Error_Cant_ExitMenu
+ ld a, l
+ ld [wWindowStackPointer], a
+ ld a, h
+ ld [wWindowStackPointer + 1], a
+ call PopWindow
+ ld a, [wMenuFlags]
+ bit 0, a
+ jr z, .loop
+ ld d, h
+ ld e, l
+ call RestoreTileBackup
+
+.loop
+ call GetWindowStackTop
+ ld a, h
+ or l
+ jr z, .done
+ call PopWindow
+
+.done
+ call CloseSRAM
+ ld hl, wWindowStackSize
+ dec [hl]
+ call Function2434b
+ ld a, [wSpriteUpdatesEnabled]
+ cp 0
+ ret z
+ call ReloadPalettes
+ ret
+
+Function2434b:
+ ld a, [wVramState]
+ bit 0, a
+ ret z
+ xor a ; sScratch
+ call OpenSRAM
+ hlcoord 0, 0
+ ld de, sScratch
+ ld bc, SCREEN_WIDTH * SCREEN_HEIGHT
+ call CopyBytes
+ call CloseSRAM
+ call OverworldTextModeSwitch
+ xor a ; sScratch
+ call OpenSRAM
+ ld hl, sScratch
+ decoord 0, 0
+ ld bc, SCREEN_WIDTH * SCREEN_HEIGHT
+.loop
+ ld a, [hl]
+ cp $61
+ jr c, .next
+ ld [de], a
+.next
+ inc hl
+ inc de
+ dec bc
+ ld a, c
+ or b
+ jr nz, .loop
+ call CloseSRAM
+ ret
+
+Error_Cant_ExitMenu:
+ ld hl, .WindowPoppingErrorText
+ call PrintText
+ call WaitBGMap
+.infinite_loop
+ jr .infinite_loop
+
+.WindowPoppingErrorText:
+ text_far _WindowPoppingErrorText
+ text_end
+
+_InitVerticalMenuCursor::
+ ld a, [wMenuDataFlags]
+ ld b, a
+ ld hl, w2DMenuCursorInitY
+ ld a, [wMenuBorderTopCoord]
+ inc a
+ bit 6, b
+ jr nz, .skip_offset
+ inc a
+.skip_offset
+ ld [hli], a
+; w2DMenuCursorInitX
+ ld a, [wMenuBorderLeftCoord]
+ inc a
+ ld [hli], a
+; w2DMenuNumRows
+ ld a, [wMenuDataItems]
+ ld [hli], a
+; w2DMenuNumCols
+ ld a, 1
+ ld [hli], a
+; w2DMenuFlags1
+ ld [hl], $0
+ bit 5, b
+ jr z, .skip_bit_5
+ set 5, [hl]
+.skip_bit_5
+ ld a, [wMenuFlags]
+ bit 4, a
+ jr z, .skip_bit_6
+ set 6, [hl]
+.skip_bit_6
+ inc hl
+; w2DMenuFlags2
+ xor a
+ ld [hli], a
+; w2DMenuCursorOffsets
+ ln a, 2, 0
+ ld [hli], a
+; wMenuJoypadFilter
+ ld a, A_BUTTON
+ bit 0, b
+ jr nz, .skip_bit_1
+ add B_BUTTON
+.skip_bit_1
+ ld [hli], a
+; wMenuCursorY
+ ld a, [wMenuCursorBuffer]
+ and a
+ jr z, .load_at_the_top
+ ld c, a
+ ld a, [wMenuDataItems]
+ cp c
+ jr nc, .load_position
+.load_at_the_top
+ ld c, 1
+.load_position
+ ld [hl], c
+ inc hl
+; wMenuCursorX
+ ld a, 1
+ ld [hli], a
+; wCursorOffCharacter, wCursorCurrentTile
+ xor a
+ ld [hli], a
+ ld [hli], a
+ ld [hli], a
+ ret
diff --git a/engine/menus/menu_2.asm b/engine/menus/menu_2.asm
new file mode 100644
index 00000000..2fd65e2b
--- /dev/null
+++ b/engine/menus/menu_2.asm
@@ -0,0 +1,298 @@
+PlaceMenuItemName:
+ push de
+ ld a, [wMenuSelection]
+ ld [wNamedObjectIndexBuffer], a
+ call GetItemName
+ pop hl
+ call PlaceString
+ ret
+
+PlaceMenuItemQuantity:
+ push de
+ ld a, [wMenuSelection]
+ ld [wCurItem], a
+ farcall _CheckTossableItem
+ ld a, [wItemAttributeParamBuffer]
+ pop hl
+ and a
+ jr nz, .done
+ ld de, $15
+ add hl, de
+ ld [hl], "×"
+ inc hl
+ ld de, wMenuSelectionQuantity
+ lb bc, 1, 2
+ call PrintNum
+
+.done
+ ret
+
+PlaceMoneyTopRight:
+ ld hl, MenuHeader_0x24a3d
+ call CopyMenuHeader
+ jr PlaceMoneyTextbox
+
+PlaceMoneyBottomLeft:
+ ld hl, MenuHeader_0x24a45
+ call CopyMenuHeader
+ jr PlaceMoneyTextbox
+
+PlaceMoneyAtTopLeftOfTextbox:
+ ld hl, MenuHeader_0x24a3d
+ lb de, 0, 11
+ call OffsetMenuHeader
+
+PlaceMoneyTextbox:
+ call MenuBox
+ call MenuBoxCoord2Tile
+ ld de, SCREEN_WIDTH + 1
+ add hl, de
+ ld de, wMoney
+ lb bc, PRINTNUM_MONEY | 3, 6
+ call PrintNum
+ ret
+
+MenuHeader_0x24a3d:
+ db MENU_BACKUP_TILES ; flags
+ menu_coords 11, 0, SCREEN_WIDTH - 1, 2
+ dw NULL
+ db 1 ; default option
+
+MenuHeader_0x24a45:
+ db MENU_BACKUP_TILES ; flags
+ menu_coords 0, 11, 8, 13
+ dw NULL
+ db 1 ; default option
+
+DisplayCoinCaseBalance:
+ ; Place a text box of size 1x7 at 11, 0.
+ hlcoord 11, 0
+ ld b, 1
+ ld c, 7
+ call Textbox
+ hlcoord 12, 0
+ ld de, CoinString
+ call PlaceString
+ hlcoord 17, 1
+ ld de, ShowMoney_TerminatorString
+ call PlaceString
+ ld de, wCoins
+ lb bc, 2, 4
+ hlcoord 13, 1
+ call PrintNum
+ ret
+
+DisplayMoneyAndCoinBalance:
+ hlcoord 5, 0
+ ld b, 3
+ ld c, 13
+ call Textbox
+ hlcoord 6, 1
+ ld de, MoneyString
+ call PlaceString
+ hlcoord 12, 1
+ ld de, wMoney
+ lb bc, PRINTNUM_MONEY | 3, 6
+ call PrintNum
+ hlcoord 6, 3
+ ld de, CoinString
+ call PlaceString
+ hlcoord 15, 3
+ ld de, wCoins
+ lb bc, 2, 4
+ call PrintNum
+ ret
+
+MoneyString:
+ db "MONEY@"
+CoinString:
+ db "COIN@"
+ShowMoney_TerminatorString:
+ db "@@"
+
+Unreferenced_Function24ab8:
+; related to safari?
+ ld hl, wOptions
+ ld a, [hl]
+ push af
+ set NO_TEXT_SCROLL, [hl]
+ hlcoord 0, 0
+ ld b, 3
+ ld c, 7
+ call Textbox
+ hlcoord 1, 1
+ ld de, wSafariTimeRemaining
+ lb bc, 2, 3
+ call PrintNum
+ hlcoord 4, 1
+ ld de, .slash_500
+ call PlaceString
+ hlcoord 1, 3
+ ld de, .booru_ko
+ call PlaceString
+ hlcoord 5, 3
+ ld de, wSafariBallsRemaining
+ lb bc, 1, 2
+ call PrintNum
+ pop af
+ ld [wOptions], a
+ ret
+
+.slash_500
+ db "/500@"
+.booru_ko
+ db "ボール   こ@"
+
+StartMenu_DrawBugContestStatusBox:
+ hlcoord 0, 0
+ ld b, 5
+ ld c, 17
+ call Textbox
+ ret
+
+StartMenu_PrintBugContestStatus:
+ ld hl, wOptions
+ ld a, [hl]
+ push af
+ set NO_TEXT_SCROLL, [hl]
+ call StartMenu_DrawBugContestStatusBox
+ hlcoord 1, 5
+ ld de, .Balls_EN
+ call PlaceString
+ hlcoord 8, 5
+ ld de, wParkBallsRemaining
+ lb bc, PRINTNUM_LEFTALIGN | 1, 2
+ call PrintNum
+ hlcoord 1, 1
+ ld de, .CAUGHT
+ call PlaceString
+ ld a, [wContestMon]
+ and a
+ ld de, .None
+ jr z, .no_contest_mon
+ ld [wNamedObjectIndexBuffer], a
+ call GetPokemonName
+
+.no_contest_mon
+ hlcoord 8, 1
+ call PlaceString
+ ld a, [wContestMon]
+ and a
+ jr z, .skip_level
+ hlcoord 1, 3
+ ld de, .LEVEL
+ call PlaceString
+ ld a, [wContestMonLevel]
+ ld h, b
+ ld l, c
+ inc hl
+ ld c, 3
+ call Print8BitNumLeftAlign
+
+.skip_level
+ pop af
+ ld [wOptions], a
+ ret
+
+.Balls_JP:
+ db "ボール   こ@"
+.CAUGHT:
+ db "CAUGHT@"
+.Balls_EN:
+ db "BALLS:@"
+.None:
+ db "None@"
+.LEVEL:
+ db "LEVEL@"
+
+Kurt_SelectApricorn:
+ call FindApricornsInBag
+ jr c, .nope
+ ld hl, .MenuHeader
+ call LoadMenuHeader
+ call DoNthMenu
+ call CloseWindow
+ jr c, .nope
+ ld a, [wMenuSelection]
+ jr .done
+
+.nope
+ xor a ; FALSE
+
+.done
+ ld c, a
+ ret
+
+.MenuHeader:
+ db MENU_BACKUP_TILES ; flags
+ menu_coords 0, 0, 14, 17
+ dw .MenuData
+ db 1 ; default option
+
+.MenuData:
+ db SCROLLINGMENU_ENABLE_SELECT | SCROLLINGMENU_ENABLE_FUNCTION3
+ dbw 0, wBuffer1
+ dw .Name
+ dw NULL
+
+.Name:
+ ld a, [wMenuSelection]
+ and a
+ jp nz, PlaceMenuItemName
+ ld h, d
+ ld l, e
+ ld de, .Cancel
+ call PlaceString
+ ret
+
+.Cancel
+ db "CANCEL@"
+
+FindApricornsInBag:
+; Checks the bag for Apricorns.
+ ld hl, wBuffer1
+ xor a
+ ld [hli], a
+ dec a
+ ld bc, 10
+ call ByteFill
+
+ ld hl, ApricornBalls
+.loop
+ ld a, [hl]
+ cp -1
+ jr z, .done
+ push hl
+ ld [wCurItem], a
+ ld hl, wNumItems
+ call CheckItem
+ pop hl
+ jr nc, .nope
+ ld a, [hl]
+ call .addtobuffer
+.nope
+ inc hl
+ inc hl
+ jr .loop
+
+.done
+ xor a
+ call .addtobuffer
+ ld a, [wBuffer1]
+ cp 1
+ ret nz
+ scf
+ ret
+
+.addtobuffer
+ push hl
+ ld hl, wBuffer1
+ inc [hl]
+ ld e, [hl]
+ ld d, 0
+ add hl, de
+ ld [hl], a
+ pop hl
+ ret
+
+INCLUDE "data/items/apricorn_balls.asm"
diff --git a/engine/menus/naming_screen.asm b/engine/menus/naming_screen.asm
new file mode 100644
index 00000000..34e2c6f2
--- /dev/null
+++ b/engine/menus/naming_screen.asm
@@ -0,0 +1,1377 @@
+NAMINGSCREEN_CURSOR EQU $7e
+
+NAMINGSCREEN_BORDER EQU "■" ; $60
+NAMINGSCREEN_MIDDLELINE EQU "→" ; $eb
+NAMINGSCREEN_UNDERLINE EQU "<DOT>" ; $f2
+
+_NamingScreen:
+ call DisableSpriteUpdates
+ call NamingScreen
+ call ReturnToMapWithSpeechTextbox
+ ret
+
+NamingScreen:
+ ld hl, wNamingScreenDestinationPointer
+ ld [hl], e
+ inc hl
+ ld [hl], d
+ ld hl, wNamingScreenType
+ ld [hl], b
+ ld hl, wOptions
+ ld a, [hl]
+ push af
+ set NO_TEXT_SCROLL, [hl]
+ ldh a, [hMapAnims]
+ push af
+ xor a
+ ldh [hMapAnims], a
+ ldh a, [hInMenu]
+ push af
+ ld a, $1
+ ldh [hInMenu], a
+ call .SetUpNamingScreen
+ call DelayFrame
+.loop
+ call NamingScreenJoypadLoop
+ jr nc, .loop
+ pop af
+ ldh [hInMenu], a
+ pop af
+ ldh [hMapAnims], a
+ pop af
+ ld [wOptions], a
+ call ClearJoypad
+ ret
+
+.SetUpNamingScreen:
+ call ClearBGPalettes
+ ld b, SCGB_DIPLOMA
+ call GetSGBLayout
+ call DisableLCD
+ call LoadNamingScreenGFX
+ call NamingScreen_InitText
+ ld a, LCDC_DEFAULT
+ ldh [rLCDC], a
+ call .GetNamingScreenSetup
+ call WaitBGMap
+ call WaitTop
+ call SetPalettes
+ call NamingScreen_InitNameEntry
+ ret
+
+.GetNamingScreenSetup:
+ ld a, [wNamingScreenType]
+ maskbits NUM_NAME_TYPES
+ ld e, a
+ ld d, 0
+ ld hl, .Jumptable
+ add hl, de
+ add hl, de
+ ld a, [hli]
+ ld h, [hl]
+ ld l, a
+ jp hl
+
+.Jumptable:
+; entries correspond to NAME_* constants
+ dw .Pokemon
+ dw .Player
+ dw .Rival
+ dw .Mom
+ dw .Box
+ dw .Pokemon
+ dw .Pokemon
+ dw .Pokemon
+
+.Pokemon:
+ ld a, [wCurPartySpecies]
+ ld [wTempIconSpecies], a
+ ld hl, LoadMenuMonIcon
+ ld a, BANK(LoadMenuMonIcon)
+ ld e, MONICON_NAMINGSCREEN
+ rst FarCall
+ ld a, [wCurPartySpecies]
+ ld [wNamedObjectIndexBuffer], a
+ call GetPokemonName
+ hlcoord 5, 2
+ call PlaceString
+ ld l, c
+ ld h, b
+ ld de, .NicknameStrings
+ call PlaceString
+ inc de
+ hlcoord 5, 4
+ call PlaceString
+ farcall GetGender
+ jr c, .genderless
+ ld a, "♂"
+ jr nz, .place_gender
+ ld a, "♀"
+.place_gender
+ hlcoord 1, 2
+ ld [hl], a
+.genderless
+ call .StoreMonIconParams
+ ret
+
+.NicknameStrings:
+ db "'S@"
+ db "NICKNAME?@"
+
+.Player:
+ ld de, ChrisSpriteGFX
+ call .LoadSprite
+ hlcoord 5, 2
+ ld de, .PlayerNameString
+ call PlaceString
+ call .StoreSpriteIconParams
+ ret
+
+.PlayerNameString:
+ db "YOUR NAME?@"
+
+.Rival:
+ ld de, SilverSpriteGFX
+ call .LoadSprite
+ hlcoord 5, 2
+ ld de, .RivalNameString
+ call PlaceString
+ call .StoreSpriteIconParams
+ ret
+
+.RivalNameString:
+ db "RIVAL'S NAME?@"
+
+.Mom:
+ ld de, MomSpriteGFX
+ call .LoadSprite
+ hlcoord 5, 2
+ ld de, .MomNameString
+ call PlaceString
+ call .StoreSpriteIconParams
+ ret
+
+.MomNameString:
+ db "MOTHER'S NAME?@"
+
+.Box:
+ ld de, PokeBallSpriteGFX
+ ld hl, vTiles0 tile $00
+ lb bc, BANK(PokeBallSpriteGFX), 4
+ call Request2bpp
+ xor a
+ ld hl, wSpriteAnimDict
+ ld [hli], a
+ ld [hl], a
+ depixel 4, 4, 4, 0
+ ld a, SPRITE_ANIM_INDEX_RED_WALK
+ call InitSpriteAnimStruct
+ ld hl, SPRITEANIMSTRUCT_FRAMESET_ID
+ add hl, bc
+ ld [hl], $0
+ hlcoord 5, 2
+ ld de, .BoxNameString
+ call PlaceString
+ call .StoreBoxIconParams
+ ret
+
+.BoxNameString:
+ db "BOX NAME?@"
+
+.LoadSprite:
+ push de
+ ld hl, vTiles0 tile $00
+ lb bc, BANK(ChrisSpriteGFX), 4
+ call Request2bpp
+ pop de
+ ld hl, 12 tiles
+ add hl, de
+ ld e, l
+ ld d, h
+ ld hl, vTiles0 tile $04
+ lb bc, BANK(ChrisSpriteGFX), 4
+ call Request2bpp
+ xor a
+ ld hl, wSpriteAnimDict
+ ld [hli], a
+ ld [hl], a
+ lb de, $24, $20
+ ld a, SPRITE_ANIM_INDEX_RED_WALK
+ call InitSpriteAnimStruct
+ ret
+
+.StoreMonIconParams:
+ ld a, MON_NAME_LENGTH - 1
+ hlcoord 5, 6
+ jr .StoreParams
+
+.StoreSpriteIconParams:
+ ld a, PLAYER_NAME_LENGTH - 1
+ hlcoord 5, 6
+ jr .StoreParams
+
+.StoreBoxIconParams:
+ ld a, BOX_NAME_LENGTH - 1
+ hlcoord 5, 4
+ jr .StoreParams
+
+.StoreParams:
+ ld [wNamingScreenMaxNameLength], a
+ ld a, l
+ ld [wNamingScreenStringEntryCoord], a
+ ld a, h
+ ld [wNamingScreenStringEntryCoord + 1], a
+ ret
+
+NamingScreen_IsTargetBox:
+ push bc
+ push af
+ ld a, [wNamingScreenType]
+ sub $3
+ ld b, a
+ pop af
+ dec b
+ pop bc
+ ret
+
+NamingScreen_InitText:
+ call WaitTop
+ hlcoord 0, 0
+ ld bc, SCREEN_WIDTH * SCREEN_HEIGHT
+ ld a, NAMINGSCREEN_BORDER
+ call ByteFill
+ hlcoord 1, 1
+ lb bc, 6, 18
+ call NamingScreen_IsTargetBox
+ jr nz, .not_box
+ lb bc, 4, 18
+
+.not_box
+ call ClearBox
+ ld de, NameInputUpper
+NamingScreen_ApplyTextInputMode:
+ call NamingScreen_IsTargetBox
+ jr nz, .not_box
+ ld hl, BoxNameInputLower - NameInputLower
+ add hl, de
+ ld d, h
+ ld e, l
+
+.not_box
+ push de
+ hlcoord 1, 8
+ lb bc, 7, 18
+ call NamingScreen_IsTargetBox
+ jr nz, .not_box_2
+ hlcoord 1, 6
+ lb bc, 9, 18
+
+.not_box_2
+ call ClearBox
+ hlcoord 1, 16
+ lb bc, 1, 18
+ call ClearBox
+ pop de
+ hlcoord 2, 8
+ ld b, $5
+ call NamingScreen_IsTargetBox
+ jr nz, .row
+ hlcoord 2, 6
+ ld b, $6
+
+.row
+ ld c, $11
+.col
+ ld a, [de]
+ ld [hli], a
+ inc de
+ dec c
+ jr nz, .col
+ push de
+ ld de, 2 * SCREEN_WIDTH - $11
+ add hl, de
+ pop de
+ dec b
+ jr nz, .row
+ ret
+
+NamingScreenJoypadLoop:
+ call JoyTextDelay
+ ld a, [wJumptableIndex]
+ bit 7, a
+ jr nz, .quit
+ call .RunJumptable
+ farcall PlaySpriteAnimationsAndDelayFrame
+ call .UpdateStringEntry
+ call DelayFrame
+ and a
+ ret
+
+.quit
+ callfar ClearSpriteAnims
+ call ClearSprites
+ xor a
+ ldh [hSCX], a
+ ldh [hSCY], a
+ scf
+ ret
+
+.UpdateStringEntry:
+ xor a
+ ldh [hBGMapMode], a
+ hlcoord 1, 5
+ call NamingScreen_IsTargetBox
+ jr nz, .got_coords
+ hlcoord 1, 3
+
+.got_coords
+ lb bc, 1, 18
+ call ClearBox
+ ld hl, wNamingScreenDestinationPointer
+ ld e, [hl]
+ inc hl
+ ld d, [hl]
+ ld hl, wNamingScreenStringEntryCoord
+ ld a, [hli]
+ ld h, [hl]
+ ld l, a
+ call PlaceString
+ ld a, $1
+ ldh [hBGMapMode], a
+ ret
+
+.RunJumptable:
+ ld a, [wJumptableIndex]
+ ld e, a
+ ld d, $0
+ ld hl, .Jumptable
+ add hl, de
+ add hl, de
+ ld a, [hli]
+ ld h, [hl]
+ ld l, a
+ jp hl
+
+.Jumptable:
+ dw .InitCursor
+ dw .ReadButtons
+
+.InitCursor:
+ depixel 10, 3
+ call NamingScreen_IsTargetBox
+ jr nz, .got_cursor_position
+ ld d, 8 * 8
+.got_cursor_position
+ ld a, SPRITE_ANIM_INDEX_NAMING_SCREEN_CURSOR
+ call InitSpriteAnimStruct
+ ld a, c
+ ld [wNamingScreenCursorObjectPointer], a
+ ld a, b
+ ld [wNamingScreenCursorObjectPointer + 1], a
+ ld hl, SPRITEANIMSTRUCT_FRAMESET_ID
+ add hl, bc
+ ld a, [hl]
+ ld hl, SPRITEANIMSTRUCT_0E
+ add hl, bc
+ ld [hl], a
+ ld hl, wJumptableIndex
+ inc [hl]
+ ret
+
+.ReadButtons:
+ ld hl, hJoyPressed
+ ld a, [hl]
+ and A_BUTTON
+ jr nz, .a
+ ld a, [hl]
+ and B_BUTTON
+ jr nz, .b
+ ld a, [hl]
+ and START
+ jr nz, .start
+ ld a, [hl]
+ and SELECT
+ jr nz, .select
+ ret
+
+.a
+ call .GetCursorPosition
+ cp $1
+ jr z, .select
+ cp $2
+ jr z, .b
+ cp $3
+ jr z, .end
+ call NamingScreen_GetLastCharacter
+ call NamingScreen_TryAddCharacter
+ ret nc
+
+.start
+ ld hl, wNamingScreenCursorObjectPointer
+ ld c, [hl]
+ inc hl
+ ld b, [hl]
+ ld hl, SPRITEANIMSTRUCT_0C
+ add hl, bc
+ ld [hl], $8
+ ld hl, SPRITEANIMSTRUCT_0D
+ add hl, bc
+ ld [hl], $4
+ call NamingScreen_IsTargetBox
+ ret nz
+ inc [hl]
+ ret
+
+.b
+ call NamingScreen_DeleteCharacter
+ ret
+
+.end
+ call NamingScreen_StoreEntry
+ ld hl, wJumptableIndex
+ set 7, [hl]
+ ret
+
+.select
+ ld hl, wNamingScreenLetterCase
+ ld a, [hl]
+ xor 1
+ ld [hl], a
+ jr z, .upper
+ ld de, NameInputLower
+ call NamingScreen_ApplyTextInputMode
+ ret
+
+.upper
+ ld de, NameInputUpper
+ call NamingScreen_ApplyTextInputMode
+ ret
+
+.GetCursorPosition:
+ ld hl, wNamingScreenCursorObjectPointer
+ ld c, [hl]
+ inc hl
+ ld b, [hl]
+
+NamingScreen_GetCursorPosition:
+ ld hl, SPRITEANIMSTRUCT_0D
+ add hl, bc
+ ld a, [hl]
+ push bc
+ ld b, $4
+ call NamingScreen_IsTargetBox
+ jr nz, .not_box
+ inc b
+.not_box
+ cp b
+ pop bc
+ jr nz, .not_bottom_row
+ ld hl, SPRITEANIMSTRUCT_0C
+ add hl, bc
+ ld a, [hl]
+ cp $3
+ jr c, .case_switch
+ cp $6
+ jr c, .delete
+ ld a, $3
+ ret
+
+.case_switch
+ ld a, $1
+ ret
+
+.delete
+ ld a, $2
+ ret
+
+.not_bottom_row
+ xor a
+ ret
+
+NamingScreen_AnimateCursor:
+ call .GetDPad
+ ld hl, SPRITEANIMSTRUCT_0D
+ add hl, bc
+ ld a, [hl]
+ ld e, a
+ swap e
+ ld hl, SPRITEANIMSTRUCT_YOFFSET
+ add hl, bc
+ ld [hl], e
+ ld d, $4
+ call NamingScreen_IsTargetBox
+ jr nz, .ok
+ inc d
+.ok
+ cp d
+ ld de, .LetterEntries
+ ld a, SPRITE_ANIM_FRAMESET_TEXT_ENTRY_CURSOR - SPRITE_ANIM_FRAMESET_TEXT_ENTRY_CURSOR ; 0
+ jr nz, .ok2
+ ld de, .CaseDelEnd
+ ld a, SPRITE_ANIM_FRAMESET_TEXT_ENTRY_CURSOR_BIG - SPRITE_ANIM_FRAMESET_TEXT_ENTRY_CURSOR ; 1
+.ok2
+ ld hl, SPRITEANIMSTRUCT_0E
+ add hl, bc
+ add [hl] ; default SPRITE_ANIM_FRAMESET_TEXT_ENTRY_CURSOR
+ ld hl, SPRITEANIMSTRUCT_FRAMESET_ID
+ add hl, bc
+ ld [hl], a
+ ld hl, SPRITEANIMSTRUCT_0C
+ add hl, bc
+ ld l, [hl]
+ ld h, $0
+ add hl, de
+ ld a, [hl]
+ ld hl, SPRITEANIMSTRUCT_XOFFSET
+ add hl, bc
+ ld [hl], a
+ ret
+
+.LetterEntries:
+ db $00, $10, $20, $30, $40, $50, $60, $70, $80
+
+.CaseDelEnd:
+ db $00, $00, $00, $30, $30, $30, $60, $60, $60
+
+.GetDPad:
+ ld hl, hJoyLast
+ ld a, [hl]
+ and D_UP
+ jr nz, .up
+ ld a, [hl]
+ and D_DOWN
+ jr nz, .down
+ ld a, [hl]
+ and D_LEFT
+ jr nz, .left
+ ld a, [hl]
+ and D_RIGHT
+ jr nz, .right
+ ret
+
+.right
+ call NamingScreen_GetCursorPosition
+ and a
+ jr nz, .asm_11e76
+ ld hl, SPRITEANIMSTRUCT_0C
+ add hl, bc
+ ld a, [hl]
+ cp $8
+ jr nc, .asm_11e73
+ inc [hl]
+ ret
+
+.asm_11e73
+ ld [hl], $0
+ ret
+
+.asm_11e76
+ cp $3
+ jr nz, .asm_11e7b
+ xor a
+.asm_11e7b
+ ld e, a
+ add a
+ add e
+ ld hl, SPRITEANIMSTRUCT_0C
+ add hl, bc
+ ld [hl], a
+ ret
+
+.left
+ call NamingScreen_GetCursorPosition
+ and a
+ jr nz, .asm_11e97
+ ld hl, SPRITEANIMSTRUCT_0C
+ add hl, bc
+ ld a, [hl]
+ and a
+ jr z, .asm_11e94
+ dec [hl]
+ ret
+
+.asm_11e94
+ ld [hl], $8
+ ret
+
+.asm_11e97
+ cp $1
+ jr nz, .asm_11e9d
+ ld a, $4
+.asm_11e9d
+ dec a
+ dec a
+ ld e, a
+ add a
+ add e
+ ld hl, SPRITEANIMSTRUCT_0C
+ add hl, bc
+ ld [hl], a
+ ret
+
+.down
+ ld hl, SPRITEANIMSTRUCT_0D
+ add hl, bc
+ ld a, [hl]
+ call NamingScreen_IsTargetBox
+ jr nz, .asm_11eb8
+ cp $5
+ jr nc, .asm_11ebe
+ inc [hl]
+ ret
+
+.asm_11eb8
+ cp $4
+ jr nc, .asm_11ebe
+ inc [hl]
+ ret
+
+.asm_11ebe
+ ld [hl], $0
+ ret
+
+.up
+ ld hl, SPRITEANIMSTRUCT_0D
+ add hl, bc
+ ld a, [hl]
+ and a
+ jr z, .asm_11ecb
+ dec [hl]
+ ret
+
+.asm_11ecb
+ ld [hl], $4
+ call NamingScreen_IsTargetBox
+ ret nz
+ inc [hl]
+ ret
+
+NamingScreen_TryAddCharacter:
+ ld a, [wNamingScreenLastCharacter]
+ ld hl, Dakutens
+ cp "゙" ; $e5
+ jr z, asm_11f06
+ ld hl, Handakutens
+ cp "゚" ; $e4
+ jr z, asm_11f06
+
+MailComposition_TryAddCharacter:
+ ld a, [wNamingScreenMaxNameLength]
+ ld c, a
+ ld a, [wNamingScreenCurNameLength]
+ cp c
+ ret nc
+
+ ld a, [wNamingScreenLastCharacter]
+
+NamingScreen_LoadNextCharacter:
+ call NamingScreen_GetTextCursorPosition
+ ld [hl], a
+
+NamingScreen_AdvanceCursor_CheckEndOfString:
+ ld hl, wNamingScreenCurNameLength
+ inc [hl]
+ call NamingScreen_GetTextCursorPosition
+ ld a, [hl]
+ cp "@"
+ jr z, .end_of_string
+ ld [hl], NAMINGSCREEN_UNDERLINE
+ and a
+ ret
+
+.end_of_string
+ scf
+ ret
+
+asm_11f06:
+ ld a, [wNamingScreenCurNameLength]
+ and a
+ ret z
+ push hl
+ ld hl, wNamingScreenCurNameLength
+ dec [hl]
+ call NamingScreen_GetTextCursorPosition
+ ld c, [hl]
+ pop hl
+
+.loop
+ ld a, [hli]
+ cp $ff
+ jr z, NamingScreen_AdvanceCursor_CheckEndOfString
+ cp c
+ jr z, .done
+ inc hl
+ jr .loop
+
+.done
+ ld a, [hl]
+ jr NamingScreen_LoadNextCharacter
+
+INCLUDE "data/text/dakutens.asm"
+
+NamingScreen_DeleteCharacter:
+ ld hl, wNamingScreenCurNameLength
+ ld a, [hl]
+ and a
+ ret z
+ dec [hl]
+ call NamingScreen_GetTextCursorPosition
+ ld [hl], NAMINGSCREEN_UNDERLINE
+ inc hl
+ ld a, [hl]
+ cp NAMINGSCREEN_UNDERLINE
+ ret nz
+ ld [hl], NAMINGSCREEN_MIDDLELINE
+ ret
+
+NamingScreen_GetTextCursorPosition:
+ push af
+ ld hl, wNamingScreenDestinationPointer
+ ld a, [hli]
+ ld h, [hl]
+ ld l, a
+ ld a, [wNamingScreenCurNameLength]
+ ld e, a
+ ld d, 0
+ add hl, de
+ pop af
+ ret
+
+NamingScreen_InitNameEntry:
+; load NAMINGSCREEN_UNDERLINE, (NAMINGSCREEN_MIDDLELINE * [wNamingScreenMaxNameLength]), "@" into the dw address at wNamingScreenDestinationPointer
+ ld hl, wNamingScreenDestinationPointer
+ ld a, [hli]
+ ld h, [hl]
+ ld l, a
+ ld [hl], NAMINGSCREEN_UNDERLINE
+ inc hl
+ ld a, [wNamingScreenMaxNameLength]
+ dec a
+ ld c, a
+ ld a, NAMINGSCREEN_MIDDLELINE
+.loop
+ ld [hli], a
+ dec c
+ jr nz, .loop
+ ld [hl], "@"
+ ret
+
+NamingScreen_StoreEntry:
+ ld hl, wNamingScreenDestinationPointer
+ ld a, [hli]
+ ld h, [hl]
+ ld l, a
+ ld a, [wNamingScreenMaxNameLength]
+ ld c, a
+.loop
+ ld a, [hl]
+ cp NAMINGSCREEN_MIDDLELINE
+ jr z, .terminator
+ cp NAMINGSCREEN_UNDERLINE
+ jr nz, .not_terminator
+.terminator
+ ld [hl], "@"
+.not_terminator
+ inc hl
+ dec c
+ jr nz, .loop
+ ret
+
+NamingScreen_GetLastCharacter:
+ ld hl, wNamingScreenCursorObjectPointer
+ ld c, [hl]
+ inc hl
+ ld b, [hl]
+ ld hl, SPRITEANIMSTRUCT_XOFFSET
+ add hl, bc
+ ld a, [hl]
+ ld hl, SPRITEANIMSTRUCT_XCOORD
+ add hl, bc
+ add [hl]
+ sub $8
+ srl a
+ srl a
+ srl a
+ ld e, a
+ ld hl, SPRITEANIMSTRUCT_YOFFSET
+ add hl, bc
+ ld a, [hl]
+ ld hl, SPRITEANIMSTRUCT_YCOORD
+ add hl, bc
+ add [hl]
+ sub $10
+ srl a
+ srl a
+ srl a
+ ld d, a
+ hlcoord 0, 0
+ ld bc, SCREEN_WIDTH
+.loop
+ ld a, d
+ and a
+ jr z, .done
+ add hl, bc
+ dec d
+ jr .loop
+
+.done
+ add hl, de
+ ld a, [hl]
+ ld [wNamingScreenLastCharacter], a
+ ret
+
+LoadNamingScreenGFX:
+ call ClearSprites
+ callfar ClearSpriteAnims
+ call LoadStandardFont
+ call LoadFontsExtra
+
+ ld de, NamingScreenGFX_MiddleLine
+ ld hl, vTiles0 tile NAMINGSCREEN_MIDDLELINE
+ lb bc, BANK(NamingScreenGFX_MiddleLine), 1
+ call Get1bpp
+
+ ld de, NamingScreenGFX_UnderLine
+ ld hl, vTiles0 tile NAMINGSCREEN_UNDERLINE
+ lb bc, BANK(NamingScreenGFX_UnderLine), 1
+ call Get1bpp
+
+ ld de, vTiles2 tile NAMINGSCREEN_BORDER
+ ld hl, NamingScreenGFX_Border
+ ld bc, 1 tiles
+ ld a, BANK(NamingScreenGFX_Border)
+ call FarCopyBytes
+
+ ld de, vTiles0 tile NAMINGSCREEN_CURSOR
+ ld hl, NamingScreenGFX_Cursor
+ ld bc, 2 tiles
+ ld a, BANK(NamingScreenGFX_Cursor)
+ call FarCopyBytes
+
+ ld a, $5
+ ld hl, wSpriteAnimDict + 9 * 2
+ ld [hli], a
+ ld [hl], NAMINGSCREEN_CURSOR
+ xor a
+ ldh [hSCY], a
+ ld [wGlobalAnimYOffset], a
+ ldh [hSCX], a
+ ld [wGlobalAnimXOffset], a
+ ld [wJumptableIndex], a
+ ld [wNamingScreenLetterCase], a
+ ldh [hBGMapMode], a
+ ld [wNamingScreenCurNameLength], a
+ ld a, $7
+ ldh [hWX], a
+ ret
+
+NamingScreenGFX_Border:
+INCBIN "gfx/naming_screen/border.2bpp"
+
+NamingScreenGFX_Cursor:
+INCBIN "gfx/naming_screen/cursor.2bpp"
+
+INCLUDE "data/text/name_input_chars.asm"
+
+NamingScreenGFX_End: ; unused
+INCBIN "gfx/naming_screen/end.1bpp"
+
+NamingScreenGFX_MiddleLine:
+INCBIN "gfx/naming_screen/middle_line.1bpp"
+
+NamingScreenGFX_UnderLine:
+INCBIN "gfx/naming_screen/underline.1bpp"
+
+_ComposeMailMessage:
+ ld hl, wNamingScreenDestinationPointer
+ ld [hl], e
+ inc hl
+ ld [hl], d
+ ldh a, [hMapAnims]
+ push af
+ xor a
+ ldh [hMapAnims], a
+ ldh a, [hInMenu]
+ push af
+ ld a, $1
+ ldh [hInMenu], a
+ call .InitBlankMail
+ call DelayFrame
+
+.loop
+ call .DoMailEntry
+ jr nc, .loop
+
+ pop af
+ ldh [hInMenu], a
+ pop af
+ ldh [hMapAnims], a
+ ret
+
+.InitBlankMail:
+ call ClearBGPalettes
+ call DisableLCD
+ call LoadNamingScreenGFX
+ ld de, vTiles0 tile $00
+ ld hl, .MailIcon
+ ld bc, 8 tiles
+ ld a, BANK(.MailIcon)
+ call FarCopyBytes
+ xor a
+ ld hl, wSpriteAnimDict
+ ld [hli], a
+ ld [hl], a
+
+ ; init mail icon
+ depixel 3, 2
+ ld a, SPRITE_ANIM_INDEX_PARTY_MON
+ call InitSpriteAnimStruct
+
+ ld hl, SPRITEANIMSTRUCT_ANIM_SEQ_ID
+ add hl, bc
+ ld [hl], $0
+ call .InitCharset
+ ld a, LCDC_DEFAULT
+ ldh [rLCDC], a
+ call .initwNamingScreenMaxNameLength
+ ld b, SCGB_DIPLOMA
+ call GetSGBLayout
+ call WaitBGMap
+ call WaitTop
+ ld a, %11100100
+ call DmgToCgbBGPals
+ ld a, %11100100
+ call DmgToCgbObjPal0
+ call NamingScreen_InitNameEntry
+ ld hl, wNamingScreenDestinationPointer
+ ld e, [hl]
+ inc hl
+ ld d, [hl]
+ ld hl, MAIL_LINE_LENGTH
+ add hl, de
+ ld [hl], "<NEXT>"
+ ret
+
+.MailIcon:
+INCBIN "gfx/icons/mail_big.2bpp"
+
+.initwNamingScreenMaxNameLength
+ ld a, MAIL_MSG_LENGTH + 1
+ ld [wNamingScreenMaxNameLength], a
+ ret
+
+.UnusedString11f7a:
+ db "メールを かいてね@"
+
+.InitCharset:
+ call WaitTop
+ hlcoord 0, 0
+ ld bc, 6 * SCREEN_WIDTH
+ ld a, NAMINGSCREEN_BORDER
+ call ByteFill
+ hlcoord 0, 6
+ ld bc, 12 * SCREEN_WIDTH
+ ld a, " "
+ call ByteFill
+ hlcoord 1, 1
+ lb bc, 4, SCREEN_WIDTH - 2
+ call ClearBox
+ ld de, MailEntry_Uppercase
+
+.PlaceMailCharset:
+ hlcoord 1, 7
+ ld b, 6
+.next
+ ld c, SCREEN_WIDTH - 1
+.loop_
+ ld a, [de]
+ ld [hli], a
+ inc de
+ dec c
+ jr nz, .loop_
+ push de
+ ld de, SCREEN_WIDTH + 1
+ add hl, de
+ pop de
+ dec b
+ jr nz, .next
+ ret
+
+.DoMailEntry:
+ call JoyTextDelay
+ ld a, [wJumptableIndex]
+ bit 7, a
+ jr nz, .exit_mail
+ call .DoJumptable
+ farcall PlaySpriteAnimationsAndDelayFrame
+ call .Update
+ call DelayFrame
+ and a
+ ret
+
+.exit_mail
+ callfar ClearSpriteAnims
+ call ClearSprites
+ xor a
+ ldh [hSCX], a
+ ldh [hSCY], a
+ scf
+ ret
+
+.Update:
+ xor a
+ ldh [hBGMapMode], a
+ hlcoord 1, 1
+ lb bc, 4, 18
+ call ClearBox
+ ld hl, wNamingScreenDestinationPointer
+ ld e, [hl]
+ inc hl
+ ld d, [hl]
+ hlcoord 2, 2
+ call PlaceString
+ ld a, $1
+ ldh [hBGMapMode], a
+ ret
+
+.DoJumptable:
+ ld a, [wJumptableIndex]
+ ld e, a
+ ld d, 0
+ ld hl, .Jumptable
+ add hl, de
+ add hl, de
+ ld a, [hli]
+ ld h, [hl]
+ ld l, a
+ jp hl
+
+.Jumptable:
+ dw .init_blinking_cursor
+ dw .process_joypad
+
+.init_blinking_cursor
+ depixel 9, 2
+ ld a, SPRITE_ANIM_INDEX_COMPOSE_MAIL_CURSOR
+ call InitSpriteAnimStruct
+ ld a, c
+ ld [wNamingScreenCursorObjectPointer], a
+ ld a, b
+ ld [wNamingScreenCursorObjectPointer + 1], a
+ ld hl, SPRITEANIMSTRUCT_FRAMESET_ID
+ add hl, bc
+ ld a, [hl]
+ ld hl, SPRITEANIMSTRUCT_0E
+ add hl, bc
+ ld [hl], a
+ ld hl, wJumptableIndex
+ inc [hl]
+ ret
+
+.process_joypad
+ ld hl, hJoyPressed
+ ld a, [hl]
+ and A_BUTTON
+ jr nz, .a
+ ld a, [hl]
+ and B_BUTTON
+ jr nz, .b
+ ld a, [hl]
+ and START
+ jr nz, .start
+ ld a, [hl]
+ and SELECT
+ jr nz, .select
+ ret
+
+.a
+ call NamingScreen_PressedA_GetCursorCommand
+ cp $1
+ jr z, .select
+ cp $2
+ jr z, .b
+ cp $3
+ jr z, .finished
+ call NamingScreen_GetLastCharacter
+ call MailComposition_TryAddLastCharacter
+ jr c, .start
+ ld hl, wNamingScreenCurNameLength
+ ld a, [hl]
+ cp MAIL_LINE_LENGTH
+ ret nz
+ inc [hl]
+ call NamingScreen_GetTextCursorPosition
+ ld [hl], NAMINGSCREEN_UNDERLINE
+ dec hl
+ ld [hl], "<NEXT>"
+ ret
+
+.start
+ ld hl, wNamingScreenCursorObjectPointer
+ ld c, [hl]
+ inc hl
+ ld b, [hl]
+ ld hl, SPRITEANIMSTRUCT_0C
+ add hl, bc
+ ld [hl], $9
+ ld hl, SPRITEANIMSTRUCT_0D
+ add hl, bc
+ ld [hl], $5
+ ret
+
+.b
+ call NamingScreen_DeleteCharacter
+ ld hl, wNamingScreenCurNameLength
+ ld a, [hl]
+ cp MAIL_LINE_LENGTH
+ ret nz
+ dec [hl]
+ call NamingScreen_GetTextCursorPosition
+ ld [hl], NAMINGSCREEN_UNDERLINE
+ inc hl
+ ld [hl], "<NEXT>"
+ ret
+
+.finished
+ call NamingScreen_StoreEntry
+ ld hl, wJumptableIndex
+ set 7, [hl]
+ ret
+
+.select
+ ld hl, wNamingScreenLetterCase
+ ld a, [hl]
+ xor 1
+ ld [hl], a
+ jr nz, .switch_to_lowercase
+ ld de, MailEntry_Uppercase
+ call .PlaceMailCharset
+ ret
+
+.switch_to_lowercase
+ ld de, MailEntry_Lowercase
+ call .PlaceMailCharset
+ ret
+
+; called from engine/sprite_anims.asm
+
+ComposeMail_AnimateCursor:
+ call .GetDPad
+ ld hl, SPRITEANIMSTRUCT_0D
+ add hl, bc
+ ld a, [hl]
+ ld e, a
+ swap e
+ ld hl, SPRITEANIMSTRUCT_YOFFSET
+ add hl, bc
+ ld [hl], e
+ cp $5
+ ld de, .LetterEntries
+ ld a, 0
+ jr nz, .got_pointer
+ ld de, .CaseDelEnd
+ ld a, 1
+.got_pointer
+ ld hl, SPRITEANIMSTRUCT_0E
+ add hl, bc
+ add [hl]
+ ld hl, SPRITEANIMSTRUCT_FRAMESET_ID
+ add hl, bc
+ ld [hl], a
+ ld hl, SPRITEANIMSTRUCT_0C
+ add hl, bc
+ ld l, [hl]
+ ld h, 0
+ add hl, de
+ ld a, [hl]
+ ld hl, SPRITEANIMSTRUCT_XOFFSET
+ add hl, bc
+ ld [hl], a
+ ret
+
+.LetterEntries:
+ db $00, $10, $20, $30, $40, $50, $60, $70, $80, $90
+
+.CaseDelEnd:
+ db $00, $00, $00, $30, $30, $30, $60, $60, $60, $60
+
+.GetDPad:
+ ld hl, hJoyLast
+ ld a, [hl]
+ and D_UP
+ jr nz, .up
+ ld a, [hl]
+ and D_DOWN
+ jr nz, .down
+ ld a, [hl]
+ and D_LEFT
+ jr nz, .left
+ ld a, [hl]
+ and D_RIGHT
+ jr nz, .right
+ ret
+
+.right
+ call ComposeMail_GetCursorPosition
+ and a
+ jr nz, .case_del_done_right
+ ld hl, SPRITEANIMSTRUCT_0C
+ add hl, bc
+ ld a, [hl]
+ cp $9
+ jr nc, .wrap_around_letter_right
+ inc [hl]
+ ret
+
+.wrap_around_letter_right
+ ld [hl], $0
+ ret
+
+.case_del_done_right
+ cp $3
+ jr nz, .wrap_around_command_right
+ xor a
+.wrap_around_command_right
+ ld e, a
+ add a
+ add e
+ ld hl, SPRITEANIMSTRUCT_0C
+ add hl, bc
+ ld [hl], a
+ ret
+
+.left
+ call ComposeMail_GetCursorPosition
+ and a
+ jr nz, .caps_del_done_left
+ ld hl, SPRITEANIMSTRUCT_0C
+ add hl, bc
+ ld a, [hl]
+ and a
+ jr z, .wrap_around_letter_left
+ dec [hl]
+ ret
+
+.wrap_around_letter_left
+ ld [hl], $9
+ ret
+
+.caps_del_done_left
+ cp $1
+ jr nz, .wrap_around_command_left
+ ld a, $4
+.wrap_around_command_left
+ dec a
+ dec a
+ ld e, a
+ add a
+ add e
+ ld hl, SPRITEANIMSTRUCT_0C
+ add hl, bc
+ ld [hl], a
+ ret
+
+.down
+ ld hl, SPRITEANIMSTRUCT_0D
+ add hl, bc
+ ld a, [hl]
+ cp $5
+ jr nc, .wrap_around_down
+ inc [hl]
+ ret
+
+.wrap_around_down
+ ld [hl], $0
+ ret
+
+.up
+ ld hl, SPRITEANIMSTRUCT_0D
+ add hl, bc
+ ld a, [hl]
+ and a
+ jr z, .wrap_around_up
+ dec [hl]
+ ret
+
+.wrap_around_up
+ ld [hl], $5
+ ret
+
+NamingScreen_PressedA_GetCursorCommand:
+ ld hl, wNamingScreenCursorObjectPointer
+ ld c, [hl]
+ inc hl
+ ld b, [hl]
+
+ComposeMail_GetCursorPosition:
+ ld hl, SPRITEANIMSTRUCT_0D
+ add hl, bc
+ ld a, [hl]
+ cp $5
+ jr nz, .letter
+ ld hl, SPRITEANIMSTRUCT_0C
+ add hl, bc
+ ld a, [hl]
+ cp $3
+ jr c, .case
+ cp $6
+ jr c, .del
+ ld a, $3
+ ret
+
+.case
+ ld a, $1
+ ret
+
+.del
+ ld a, $2
+ ret
+
+.letter
+ xor a
+ ret
+
+MailComposition_TryAddLastCharacter:
+ ld a, [wNamingScreenLastCharacter]
+ ld hl, Dakutens
+ cp "゙" ; $e5
+ jr z, .asm_1258b
+ ld hl, Handakutens
+ cp "゚" ; $e4
+ jp nz, MailComposition_TryAddCharacter
+
+.asm_1258b
+ ld a, [wNamingScreenCurNameLength]
+ and a
+ ret z
+ cp $11
+ jr nz, .asm_1259c
+ push hl
+ ld hl, wNamingScreenCurNameLength
+ dec [hl]
+ dec [hl]
+ jr .asm_125a1
+
+.asm_1259c
+ push hl
+ ld hl, wNamingScreenCurNameLength
+ dec [hl]
+
+.asm_125a1
+ call NamingScreen_GetTextCursorPosition
+ ld c, [hl]
+ pop hl
+.asm_125a6
+ ld a, [hli]
+ cp $ff
+ jp z, NamingScreen_AdvanceCursor_CheckEndOfString
+ cp c
+ jr z, .asm_125b2
+ inc hl
+ jr .asm_125a6
+
+.asm_125b2
+ ld a, [hl]
+ jp NamingScreen_LoadNextCharacter
+
+INCLUDE "data/text/mail_input_chars.asm"
diff --git a/engine/menus/save.asm b/engine/menus/save.asm
new file mode 100644
index 00000000..f8207204
--- /dev/null
+++ b/engine/menus/save.asm
@@ -0,0 +1,1092 @@
+SaveMenu:
+ call LoadStandardMenuHeader
+ lb de, 4, 0
+ farcall DisplayNormalContinueData
+ call SpeechTextbox
+ call UpdateSprites
+ farcall SaveMenu_CopyTilemapAtOnce
+ ld hl, WouldYouLikeToSaveTheGameText
+ call SaveTheGame_yesorno
+ jr nz, .refused
+ call AskOverwriteSaveFile
+ jr c, .refused
+ call PauseGameLogic
+ call SavingDontTurnOffThePower
+ call ResumeGameLogic
+ call ExitMenu
+ and a
+ ret
+
+.refused
+ call ExitMenu
+ call ReloadPalettes
+ farcall SaveMenu_CopyTilemapAtOnce
+ scf
+ ret
+
+SaveAfterLinkTrade:
+ call PauseGameLogic
+ farcall StageRTCTimeForSave
+ farcall BackupMysteryGift
+ call SavePokemonData
+ call SaveChecksum
+ call SaveBackupPokemonData
+ call SaveBackupChecksum
+ farcall BackupPartyMonMail
+ farcall SaveRTC
+ call ResumeGameLogic
+ ret
+
+ChangeBoxSaveGame:
+ push de
+ ld hl, ChangeBoxSaveText
+ call MenuTextbox
+ call YesNoBox
+ call ExitMenu
+ jr c, .refused
+ call AskOverwriteSaveFile
+ jr c, .refused
+ call PauseGameLogic
+ call SaveBox
+ pop de
+ ld a, e
+ ld [wCurBox], a
+ call LoadBox
+ call SavingDontTurnOffThePower
+ call ResumeGameLogic
+ and a
+ ret
+.refused
+ pop de
+ ret
+
+Link_SaveGame:
+ call AskOverwriteSaveFile
+ jr c, .refused
+ call PauseGameLogic
+ call SavingDontTurnOffThePower
+ call ResumeGameLogic
+ and a
+
+.refused
+ ret
+
+MoveMonWOMail_SaveGame:
+ call PauseGameLogic
+ push de
+ call SaveBox
+ pop de
+ ld a, e
+ ld [wCurBox], a
+ call LoadBox
+ call ResumeGameLogic
+ ret
+
+MoveMonWOMail_InsertMon_SaveGame:
+ call PauseGameLogic
+ push de
+ call SaveBox
+ pop de
+ ld a, e
+ ld [wCurBox], a
+ ld a, TRUE
+ ld [wSaveFileExists], a
+ farcall StageRTCTimeForSave
+ farcall BackupMysteryGift
+ call ValidateSave
+ call SaveOptions
+ call SavePlayerData
+ call SavePokemonData
+ call SaveChecksum
+ call ValidateBackupSave
+ call SaveBackupOptions
+ call SaveBackupPlayerData
+ call SaveBackupPokemonData
+ call SaveBackupChecksum
+ farcall BackupPartyMonMail
+ farcall SaveRTC
+ call LoadBox
+ call ResumeGameLogic
+ ld de, SFX_SAVE
+ call PlaySFX
+ ld c, 24
+ call DelayFrames
+ ret
+
+StartMoveMonWOMail_SaveGame:
+ ld hl, MoveMonWOMailSaveText
+ call MenuTextbox
+ call YesNoBox
+ call ExitMenu
+ jr c, .refused
+ call AskOverwriteSaveFile
+ jr c, .refused
+ call PauseGameLogic
+ call SavingDontTurnOffThePower
+ call ResumeGameLogic
+ and a
+ ret
+
+.refused
+ scf
+ ret
+
+PauseGameLogic:
+ ld a, TRUE
+ ld [wGameLogicPaused], a
+ ret
+
+ResumeGameLogic:
+ xor a ; FALSE
+ ld [wGameLogicPaused], a
+ ret
+
+AddHallOfFameEntry:
+ ld a, BANK(sHallOfFame)
+ call OpenSRAM
+ ld hl, sHallOfFame + HOF_LENGTH * (NUM_HOF_TEAMS - 1) - 1
+ ld de, sHallOfFame + HOF_LENGTH * NUM_HOF_TEAMS - 1
+ ld bc, HOF_LENGTH * (NUM_HOF_TEAMS - 1)
+.loop
+ ld a, [hld]
+ ld [de], a
+ dec de
+ dec bc
+ ld a, c
+ or b
+ jr nz, .loop
+ ld hl, wHallOfFamePokemonList
+ ld de, sHallOfFame
+ ld bc, wHallOfFamePokemonListEnd - wHallOfFamePokemonList + 1
+ call CopyBytes
+ call CloseSRAM
+ ret
+
+SaveGameData:
+ call _SaveGameData
+ ret
+
+AskOverwriteSaveFile:
+ ld a, [wSaveFileExists]
+ and a
+ jr z, .erase
+ call CompareLoadedAndSavedPlayerID
+ jr z, .yoursavefile
+ ld hl, AnotherSaveFileText
+ call SaveTheGame_yesorno
+ jr nz, .refused
+ jr .erase
+
+.yoursavefile
+ ld hl, AlreadyASaveFileText
+ call SaveTheGame_yesorno
+ jr nz, .refused
+ jr .ok
+
+.erase
+ call ErasePreviousSave
+
+.ok
+ and a
+ ret
+
+.refused
+ scf
+ ret
+
+SaveTheGame_yesorno:
+ ld b, BANK(WouldYouLikeToSaveTheGameText)
+ call MapTextbox
+ call LoadMenuTextbox
+ lb bc, 0, 7
+ call PlaceYesNoBox
+ ld a, [wMenuCursorY]
+ dec a
+ call CloseWindow
+ push af
+ call ReloadPalettes
+ pop af
+ and a
+ ret
+
+CompareLoadedAndSavedPlayerID:
+ ld a, BANK(sPlayerData)
+ call OpenSRAM
+ ld hl, sPlayerData + (wPlayerID - wPlayerData)
+ ld a, [hli]
+ ld c, [hl]
+ ld b, a
+ call CloseSRAM
+ ld a, [wPlayerID]
+ cp b
+ ret nz
+ ld a, [wPlayerID + 1]
+ cp c
+ ret
+
+SavingDontTurnOffThePower:
+ ; Prevent joypad interrupts
+ xor a
+ ldh [hJoypadReleased], a
+ ldh [hJoypadPressed], a
+ ldh [hJoypadSum], a
+ ldh [hJoypadDown], a
+ ; Save the text speed setting to the stack
+ ld a, [wOptions]
+ push af
+ ; Set the text speed to medium
+ ld a, TEXT_DELAY_MED
+ ld [wOptions], a
+ ; SAVING... DON'T TURN OFF THE POWER.
+ ld hl, SavingDontTurnOffThePowerText
+ call PrintText
+ ; Restore the text speed setting
+ pop af
+ ld [wOptions], a
+ ; Wait for 16 frames
+ ld c, 16
+ call DelayFrames
+ call _SaveGameData
+ ; wait 32 frames
+ ld c, 32
+ call DelayFrames
+ ; copy the original text speed setting to the stack
+ ld a, [wOptions]
+ push af
+ ; set text speed to medium
+ ld a, TEXT_DELAY_MED
+ ld [wOptions], a
+ ; <PLAYER> saved the game!
+ ld hl, SavedTheGameText
+ call PrintText
+ ; restore the original text speed setting
+ pop af
+ ld [wOptions], a
+ ld de, SFX_SAVE
+ call WaitPlaySFX
+ call WaitSFX
+ ; wait 30 frames
+ ld c, 30
+ call DelayFrames
+ ret
+
+_SaveGameData:
+ ld a, TRUE
+ ld [wSaveFileExists], a
+ farcall StageRTCTimeForSave
+ farcall BackupMysteryGift
+ call ValidateSave
+ call SaveOptions
+ call SavePlayerData
+ call SavePokemonData
+ call SaveBox
+ call SaveChecksum
+ call ValidateBackupSave
+ call SaveBackupOptions
+ call SaveBackupPlayerData
+ call SaveBackupPokemonData
+ call SaveBackupChecksum
+ call UpdateStackTop
+ farcall BackupPartyMonMail
+ farcall SaveRTC
+ ret
+
+UpdateStackTop:
+; sStackTop appears to be unused.
+; It could have been used to debug stack overflow during saving.
+ call FindStackTop
+ ld a, BANK(sStackTop)
+ call OpenSRAM
+ ld a, [sStackTop + 0]
+ ld e, a
+ ld a, [sStackTop + 1]
+ ld d, a
+ or e
+ jr z, .update
+ ld a, e
+ sub l
+ ld a, d
+ sbc h
+ jr c, .done
+
+.update
+ ld a, l
+ ld [sStackTop + 0], a
+ ld a, h
+ ld [sStackTop + 1], a
+
+.done
+ call CloseSRAM
+ ret
+
+FindStackTop:
+; Find the furthest point that sp has traversed to.
+; This is distinct from the current value of sp.
+ ld hl, wStackTop - $fc
+.loop
+ ld a, [hl]
+ or a
+ ret nz
+ inc hl
+ jr .loop
+
+ErasePreviousSave:
+ call EraseBoxes
+ call EraseHallOfFame
+ call EraseLinkBattleStats
+ call EraseMysteryGift
+ ld a, BANK(sStackTop)
+ call OpenSRAM
+ xor a
+ ld [sStackTop + 0], a
+ ld [sStackTop + 1], a
+ call CloseSRAM
+ ld a, $1
+ ld [wSavedAtLeastOnce], a
+ ret
+
+EraseLinkBattleStats:
+ ld a, BANK(sLinkBattleStats)
+ call OpenSRAM
+ ld hl, sLinkBattleStats
+ ld bc, sLinkBattleStatsEnd - sLinkBattleStats
+ xor a
+ call ByteFill
+ jp CloseSRAM
+
+EraseMysteryGift:
+ ld a, BANK(sBackupMysteryGiftItem)
+ call OpenSRAM
+ ld hl, sBackupMysteryGiftItem
+ ld bc, sBackupMysteryGiftItemEnd - sBackupMysteryGiftItem
+ xor a
+ call ByteFill
+ jp CloseSRAM
+
+EraseHallOfFame:
+ ld a, BANK(sHallOfFame)
+ call OpenSRAM
+ ld hl, sHallOfFame
+ ld bc, sHallOfFameEnd - sHallOfFame
+ xor a
+ call ByteFill
+ jp CloseSRAM
+
+ValidateSave:
+ ld a, BANK(sCheckValue1) ; aka BANK(sCheckValue2)
+ call OpenSRAM
+ ld a, SAVE_CHECK_VALUE_1
+ ld [sCheckValue1], a
+ ld a, SAVE_CHECK_VALUE_2
+ ld [sCheckValue2], a
+ jp CloseSRAM
+
+SaveOptions:
+ ld a, BANK(sOptions)
+ call OpenSRAM
+ ld hl, wOptions
+ ld de, sOptions
+ ld bc, wOptionsEnd - wOptions
+ call CopyBytes
+ ld a, [wOptions]
+ and $ff ^ (1 << NO_TEXT_SCROLL)
+ ld [sOptions], a
+ jp CloseSRAM
+
+SavePlayerData:
+ ld a, BANK(sPlayerData)
+ call OpenSRAM
+ ld hl, wPlayerData
+ ld de, sPlayerData
+ ld bc, wPlayerDataEnd - wPlayerData
+ call CopyBytes
+ ld hl, wCurMapData
+ ld de, sCurMapData
+ ld bc, wCurMapDataEnd - wCurMapData
+ call CopyBytes
+ jp CloseSRAM
+
+SavePokemonData:
+ ld a, BANK(sPokemonData)
+ call OpenSRAM
+ ld hl, wPokemonData
+ ld de, sPokemonData
+ ld bc, wPokemonDataEnd - wPokemonData
+ call CopyBytes
+ call CloseSRAM
+ ret
+
+SaveBox:
+ call GetBoxAddress
+ call SaveBoxAddress
+ ret
+
+SaveChecksum:
+ ld hl, sGameData
+ ld bc, sGameDataEnd - sGameData
+ ld a, BANK(sGameData)
+ call OpenSRAM
+ call Checksum
+ ld a, e
+ ld [sChecksum + 0], a
+ ld a, d
+ ld [sChecksum + 1], a
+ call CloseSRAM
+ ret
+
+ValidateBackupSave:
+ ld a, BANK(sBackupCheckValue1) ; aka BANK(sBackupCheckValue2)
+ call OpenSRAM
+ ld a, SAVE_CHECK_VALUE_1
+ ld [sBackupCheckValue1], a
+ ld a, SAVE_CHECK_VALUE_2
+ ld [sBackupCheckValue2], a
+ call CloseSRAM
+ ret
+
+SaveBackupOptions:
+ ld a, BANK(sBackupOptions)
+ call OpenSRAM
+ ld hl, wOptions
+ ld de, sBackupOptions
+ ld bc, wOptionsEnd - wOptions
+ call CopyBytes
+ call CloseSRAM
+ ret
+
+SaveBackupPlayerData:
+ ld a, BANK(sBackupPlayerData3)
+ call OpenSRAM
+ ld hl, wPlayerData3
+ ld de, sBackupPlayerData3
+ ld bc, wPlayerData3End - wPlayerData3
+ call CopyBytes
+ ld a, BANK(sBackupPlayerData1)
+ call OpenSRAM
+ ld hl, wPlayerData1
+ ld de, sBackupPlayerData1
+ ld bc, wPlayerData1End - wPlayerData1
+ call CopyBytes
+ ld a, BANK(sBackupPlayerData2)
+ call OpenSRAM
+ ld hl, wPlayerData2
+ ld de, sBackupPlayerData2
+ ld bc, wPlayerData2End - wPlayerData2
+ call CopyBytes
+ ld a, BANK(sBackupCurMapData)
+ call OpenSRAM
+ ld hl, wCurMapData
+ ld de, sBackupCurMapData
+ ld bc, wCurMapDataEnd - wCurMapData
+ call CopyBytes
+ call CloseSRAM
+ ret
+
+SaveBackupPokemonData:
+ ld a, BANK(sBackupPokemonData)
+ call OpenSRAM
+ ld hl, wPokemonData
+ ld de, sBackupPokemonData
+ ld bc, wPokemonDataEnd - wPokemonData
+ call CopyBytes
+ call CloseSRAM
+ ret
+
+SaveBackupChecksum:
+ ld a, BANK(sBackupPlayerData3)
+ call OpenSRAM
+ ld hl, sBackupPlayerData3
+ ld bc, wPlayerData3End - wPlayerData3
+ call Checksum
+ push de
+ ld hl, sBackupPokemonData
+ ld bc, wPokemonDataEnd - wPokemonData
+ call Checksum
+ pop hl
+ add hl, de
+ ld a, BANK(sBackupPlayerData1)
+ call OpenSRAM
+ push hl
+ ld hl, sBackupPlayerData1
+ ld bc, wPlayerData1End - wPlayerData1
+ call Checksum
+ pop hl
+ add hl, de
+ ld a, BANK(sBackupPlayerData2)
+ call OpenSRAM
+ push hl
+ ld hl, sBackupPlayerData2
+ ld bc, wPlayerData2End - wPlayerData2
+ call Checksum
+ pop hl
+ add hl, de
+ ld a, BANK(sBackupCurMapData)
+ call OpenSRAM
+ push hl
+ ld hl, sBackupCurMapData
+ ld bc, wCurMapDataEnd - wCurMapData
+ call Checksum
+ pop hl
+ add hl, de
+ ld a, l
+ ld [sBackupChecksum + 0], a
+ ld a, h
+ ld [sBackupChecksum + 1], a
+ call CloseSRAM
+ ret
+
+TryLoadSaveFile:
+ call VerifyChecksum
+ jr nz, .backup
+ call LoadPlayerData
+ call LoadPokemonData
+ call LoadBox
+ farcall RestorePartyMonMail
+ farcall RestoreMysteryGift
+ call ValidateBackupSave
+ call SaveBackupOptions
+ call SaveBackupPlayerData
+ call SaveBackupPokemonData
+ call SaveBackupChecksum
+ and a
+ ret
+
+.backup
+ call VerifyBackupChecksum
+ jr nz, .corrupt
+ call LoadBackupPlayerData
+ call LoadBackupPokemonData
+ call LoadBox
+ farcall RestorePartyMonMail
+ farcall RestoreMysteryGift
+ call ValidateSave
+ call SaveOptions
+ call SavePlayerData
+ call SavePokemonData
+ call SaveChecksum
+ and a
+ ret
+
+.corrupt
+ ld a, [wOptions]
+ push af
+ set NO_TEXT_SCROLL, a
+ ld [wOptions], a
+ ld hl, SaveFileCorruptedText
+ call PrintText
+ pop af
+ ld [wOptions], a
+ scf
+ ret
+
+TryLoadSaveData:
+ xor a ; FALSE
+ ld [wSaveFileExists], a
+ call CheckPrimarySaveFile
+ ld a, [wSaveFileExists]
+ and a
+ jr z, .backup
+
+ ld a, BANK(sPlayerData)
+ call OpenSRAM
+ ld hl, sPlayerData + wStartDay - wPlayerData
+ ld de, wStartDay
+ ld bc, $e
+ call CopyBytes
+ call CloseSRAM
+ ret
+
+.backup
+ call CheckBackupSaveFile
+ ld a, [wSaveFileExists]
+ and a
+ jr z, .corrupt
+
+ ld a, BANK(sBackupPlayerData1)
+ call OpenSRAM
+ ld hl, sBackupPlayerData1 + wStartDay - wPlayerData
+ ld de, wStartDay
+ ld bc, $e
+ call CopyBytes
+ call CloseSRAM
+ ret
+
+.corrupt
+ ld hl, DefaultOptions
+ ld de, wOptions
+ ld bc, wOptionsEnd - wOptions
+ call CopyBytes
+ call ClearClock
+ ret
+
+INCLUDE "data/default_options.asm"
+
+CheckPrimarySaveFile:
+ ld a, BANK(sCheckValue1) ; aka BANK(sCheckValue2)
+ call OpenSRAM
+ ld a, [sCheckValue1]
+ cp SAVE_CHECK_VALUE_1
+ jr nz, .nope
+ ld a, [sCheckValue2]
+ cp SAVE_CHECK_VALUE_2
+ jr nz, .nope
+ ld hl, sOptions
+ ld de, wOptions
+ ld bc, wOptionsEnd - wOptions
+ call CopyBytes
+ call CloseSRAM
+ call CheckTextDelay
+ ld a, TRUE
+ ld [wSaveFileExists], a
+
+.nope
+ call CloseSRAM
+ ret
+
+CheckBackupSaveFile:
+ ld a, BANK(sBackupCheckValue1) ; aka BANK(sBackupCheckValue2)
+ call OpenSRAM
+ ld a, [sBackupCheckValue1]
+ cp SAVE_CHECK_VALUE_1
+ jr nz, .nope
+ ld a, [sBackupCheckValue2]
+ cp SAVE_CHECK_VALUE_2
+ jr nz, .nope
+ ld hl, sBackupOptions
+ ld de, wOptions
+ ld bc, wOptionsEnd - wOptions
+ call CopyBytes
+ call CheckTextDelay
+ ld a, $2
+ ld [wSaveFileExists], a
+
+.nope
+ call CloseSRAM
+ ret
+
+CheckTextDelay:
+; Fix options if text delay is invalid
+ ld hl, wTextboxFlags
+ res NO_TEXT_DELAY_F, [hl]
+ ld a, [wOptions]
+ and TEXT_DELAY_MASK
+ cp TEXT_DELAY_FAST
+ ret z
+ cp TEXT_DELAY_MED
+ ret z
+ cp TEXT_DELAY_SLOW
+ ret z
+ ld a, [wOptions]
+ and $ff ^ TEXT_DELAY_MASK
+ or (1 << FAST_TEXT_DELAY_F) | (1 << NO_TEXT_DELAY_F)
+ ld [wOptions], a
+ ret
+
+LoadPlayerData:
+ ld a, BANK(sPlayerData)
+ call OpenSRAM
+ ld hl, sPlayerData
+ ld de, wPlayerData
+ ld bc, wPlayerDataEnd - wPlayerData
+ call CopyBytes
+ ld hl, sCurMapData
+ ld de, wCurMapData
+ ld bc, wCurMapDataEnd - wCurMapData
+ call CopyBytes
+ call CloseSRAM
+ ret
+
+LoadPokemonData:
+ ld a, BANK(sPokemonData)
+ call OpenSRAM
+ ld hl, sPokemonData
+ ld de, wPokemonData
+ ld bc, wPokemonDataEnd - wPokemonData
+ call CopyBytes
+ call CloseSRAM
+ ret
+
+LoadBox:
+ call GetBoxAddress
+ call LoadBoxAddress
+ ret
+
+VerifyChecksum:
+ ld hl, sGameData
+ ld bc, sGameDataEnd - sGameData
+ ld a, BANK(sGameData)
+ call OpenSRAM
+ call Checksum
+ ld a, [sChecksum + 0]
+ cp e
+ jr nz, .fail
+ ld a, [sChecksum + 1]
+ cp d
+.fail
+ push af
+ call CloseSRAM
+ pop af
+ ret
+
+LoadBackupPlayerData:
+ ld a, BANK(sBackupPlayerData3)
+ call OpenSRAM
+ ld hl, sBackupPlayerData3
+ ld de, wPlayerData3
+ ld bc, wPlayerData3End - wPlayerData3
+ call CopyBytes
+
+ ld a, BANK(sBackupPlayerData1)
+ call OpenSRAM
+ ld hl, sBackupPlayerData1
+ ld de, wPlayerData1
+ ld bc, wPlayerData1End - wPlayerData1
+ call CopyBytes
+
+ ld a, BANK(sBackupPlayerData2)
+ call OpenSRAM
+ ld hl, sBackupPlayerData2
+ ld de, wPlayerData2
+ ld bc, wPlayerData2End - wPlayerData2
+ call CopyBytes
+
+ ld a, BANK(sBackupCurMapData)
+ call OpenSRAM
+ ld hl, sBackupCurMapData
+ ld de, wCurMapData
+ ld bc, wCurMapDataEnd - wCurMapData
+ call CopyBytes
+ call CloseSRAM
+ ret
+
+LoadBackupPokemonData:
+ ld a, BANK(sBackupPokemonData)
+ call OpenSRAM
+ ld hl, sBackupPokemonData
+ ld de, wPokemonData
+ ld bc, wPokemonDataEnd - wPokemonData
+ call CopyBytes
+ call CloseSRAM
+ ret
+
+VerifyBackupChecksum:
+ ld a, BANK(sBackupPokemonData)
+ call OpenSRAM
+ ld hl, sBackupPokemonData
+ ld bc, wPokemonDataEnd - wPokemonData
+ call Checksum
+ push de
+
+ ld hl, sBackupPlayerData3
+ ld bc, wPlayerData3End - wPlayerData3
+ call Checksum
+ pop hl
+ add hl, de
+
+ ld a, BANK(sBackupPlayerData1)
+ call OpenSRAM
+ push hl
+ ld hl, sBackupPlayerData1
+ ld bc, wPlayerData1End - wPlayerData1
+ call Checksum
+ pop hl
+ add hl, de
+
+ ld a, BANK(sBackupPlayerData2)
+ call OpenSRAM
+ push hl
+ ld hl, sBackupPlayerData2
+ ld bc, wPlayerData2End - wPlayerData2
+ call Checksum
+ pop hl
+ add hl, de
+
+ ld a, BANK(sBackupCurMapData)
+ call OpenSRAM
+ push hl
+ ld hl, sBackupCurMapData
+ ld bc, wCurMapDataEnd - wCurMapData
+ call Checksum
+ pop hl
+ add hl, de
+ ld d, h
+ ld e, l
+ ld a, [sBackupChecksum + 0]
+ cp e
+ jr nz, .fail
+ ld a, [sBackupChecksum + 1]
+ cp d
+.fail
+ push af
+ call CloseSRAM
+ pop af
+ ret
+
+GetBoxAddress:
+ ld a, [wCurBox]
+ cp NUM_BOXES
+ jr c, .ok
+ xor a
+ ld [wCurBox], a
+
+.ok
+ ld e, a
+ ld d, 0
+ ld hl, BoxAddresses
+rept 5
+ add hl, de
+endr
+ ld a, [hli]
+ push af
+ ld a, [hli]
+ ld e, a
+ ld a, [hli]
+ ld d, a
+ ld a, [hli]
+ ld h, [hl]
+ ld l, a
+ pop af
+ ret
+
+SaveBoxAddress:
+; Save box via wBoxPartialData.
+; We do this in three steps because the size of wBoxPartialData is less than
+; the size of sBox.
+ push hl
+; Load the first part of the active box.
+ push af
+ push de
+ ld a, BANK(sBox)
+ call OpenSRAM
+ ld hl, sBox
+ ld de, wBoxPartialData
+ ld bc, (wBoxPartialDataEnd - wBoxPartialData)
+ call CopyBytes
+ call CloseSRAM
+ pop de
+ pop af
+; Save it to the target box.
+ push af
+ push de
+ call OpenSRAM
+ ld hl, wBoxPartialData
+ ld bc, (wBoxPartialDataEnd - wBoxPartialData)
+ call CopyBytes
+ call CloseSRAM
+
+; Load the second part of the active box.
+ ld a, BANK(sBox)
+ call OpenSRAM
+ ld hl, sBox + (wBoxPartialDataEnd - wBoxPartialData)
+ ld de, wBoxPartialData
+ ld bc, (wBoxPartialDataEnd - wBoxPartialData)
+ call CopyBytes
+ call CloseSRAM
+ pop de
+ pop af
+
+ ld hl, (wBoxPartialDataEnd - wBoxPartialData)
+ add hl, de
+ ld e, l
+ ld d, h
+; Save it to the next part of the target box.
+ push af
+ push de
+ call OpenSRAM
+ ld hl, wBoxPartialData
+ ld bc, (wBoxPartialDataEnd - wBoxPartialData)
+ call CopyBytes
+ call CloseSRAM
+
+; Load the third and final part of the active box.
+ ld a, BANK(sBox)
+ call OpenSRAM
+ ld hl, sBox + (wBoxPartialDataEnd - wBoxPartialData) * 2
+ ld de, wBoxPartialData
+ ld bc, sBoxEnd - (sBox + (wBoxPartialDataEnd - wBoxPartialData) * 2) ; $8e
+ call CopyBytes
+ call CloseSRAM
+ pop de
+ pop af
+
+ ld hl, (wBoxPartialDataEnd - wBoxPartialData)
+ add hl, de
+ ld e, l
+ ld d, h
+; Save it to the final part of the target box.
+ call OpenSRAM
+ ld hl, wBoxPartialData
+ ld bc, sBoxEnd - (sBox + (wBoxPartialDataEnd - wBoxPartialData) * 2) ; $8e
+ call CopyBytes
+ call CloseSRAM
+
+ pop hl
+ ret
+
+LoadBoxAddress:
+; Load box via wBoxPartialData.
+; We do this in three steps because the size of wBoxPartialData is less than
+; the size of sBox.
+ push hl
+ ld l, e
+ ld h, d
+; Load part 1
+ push af
+ push hl
+ call OpenSRAM
+ ld de, wBoxPartialData
+ ld bc, (wBoxPartialDataEnd - wBoxPartialData)
+ call CopyBytes
+ call CloseSRAM
+ ld a, BANK(sBox)
+ call OpenSRAM
+ ld hl, wBoxPartialData
+ ld de, sBox
+ ld bc, (wBoxPartialDataEnd - wBoxPartialData)
+ call CopyBytes
+ call CloseSRAM
+ pop hl
+ pop af
+
+ ld de, (wBoxPartialDataEnd - wBoxPartialData)
+ add hl, de
+; Load part 2
+ push af
+ push hl
+ call OpenSRAM
+ ld de, wBoxPartialData
+ ld bc, (wBoxPartialDataEnd - wBoxPartialData)
+ call CopyBytes
+ call CloseSRAM
+ ld a, BANK(sBox)
+ call OpenSRAM
+ ld hl, wBoxPartialData
+ ld de, sBox + (wBoxPartialDataEnd - wBoxPartialData)
+ ld bc, (wBoxPartialDataEnd - wBoxPartialData)
+ call CopyBytes
+ call CloseSRAM
+ pop hl
+ pop af
+; Load part 3
+ ld de, (wBoxPartialDataEnd - wBoxPartialData)
+ add hl, de
+ call OpenSRAM
+ ld de, wBoxPartialData
+ ld bc, sBoxEnd - (sBox + (wBoxPartialDataEnd - wBoxPartialData) * 2) ; $8e
+ call CopyBytes
+ call CloseSRAM
+ ld a, BANK(sBox)
+ call OpenSRAM
+ ld hl, wBoxPartialData
+ ld de, sBox + (wBoxPartialDataEnd - wBoxPartialData) * 2
+ ld bc, sBoxEnd - (sBox + (wBoxPartialDataEnd - wBoxPartialData) * 2) ; $8e
+ call CopyBytes
+ call CloseSRAM
+
+ pop hl
+ ret
+
+EraseBoxes:
+ ld hl, BoxAddresses
+ ld c, NUM_BOXES
+.next
+ push bc
+ ld a, [hli]
+ call OpenSRAM
+ ld a, [hli]
+ ld e, a
+ ld a, [hli]
+ ld d, a
+ xor a
+ ld [de], a
+ inc de
+ ld a, -1
+ ld [de], a
+ inc de
+ ld bc, sBoxEnd - (sBox + 2)
+.clear
+ xor a
+ ld [de], a
+ inc de
+ dec bc
+ ld a, b
+ or c
+ jr nz, .clear
+ ld a, [hli]
+ ld e, a
+ ld a, [hli]
+ ld d, a
+ ld a, -1
+ ld [de], a
+ inc de
+ xor a
+ ld [de], a
+ call CloseSRAM
+ pop bc
+ dec c
+ jr nz, .next
+ ret
+
+BoxAddresses:
+; dbww bank, address, address
+ dbww BANK(sBox1), sBox1, sBox1End
+ dbww BANK(sBox2), sBox2, sBox2End
+ dbww BANK(sBox3), sBox3, sBox3End
+ dbww BANK(sBox4), sBox4, sBox4End
+ dbww BANK(sBox5), sBox5, sBox5End
+ dbww BANK(sBox6), sBox6, sBox6End
+ dbww BANK(sBox7), sBox7, sBox7End
+ dbww BANK(sBox8), sBox8, sBox8End
+ dbww BANK(sBox9), sBox9, sBox9End
+ dbww BANK(sBox10), sBox10, sBox10End
+ dbww BANK(sBox11), sBox11, sBox11End
+ dbww BANK(sBox12), sBox12, sBox12End
+ dbww BANK(sBox13), sBox13, sBox13End
+ dbww BANK(sBox14), sBox14, sBox14End
+
+Checksum:
+ ld de, 0
+.loop
+ ld a, [hli]
+ add e
+ ld e, a
+ ld a, 0
+ adc d
+ ld d, a
+ dec bc
+ ld a, b
+ or c
+ jr nz, .loop
+ ret
+
+WouldYouLikeToSaveTheGameText:
+ text_far _WouldYouLikeToSaveTheGameText
+ text_end
+
+SavingDontTurnOffThePowerText:
+ text_far _SavingDontTurnOffThePowerText
+ text_end
+
+SavedTheGameText:
+ text_far _SavedTheGameText
+ text_end
+
+AlreadyASaveFileText:
+ text_far _AlreadyASaveFileText
+ text_end
+
+AnotherSaveFileText:
+ text_far _AnotherSaveFileText
+ text_end
+
+SaveFileCorruptedText:
+ text_far _SaveFileCorruptedText
+ text_end
+
+ChangeBoxSaveText:
+ text_far _ChangeBoxSaveText
+ text_end
+
+MoveMonWOMailSaveText:
+ text_far _MoveMonWOMailSaveText
+ text_end
diff --git a/engine/menus/scrolling_menu.asm b/engine/menus/scrolling_menu.asm
new file mode 100644
index 00000000..f051e71c
--- /dev/null
+++ b/engine/menus/scrolling_menu.asm
@@ -0,0 +1,519 @@
+_InitScrollingMenu::
+ xor a
+ ld [wMenuJoypad], a
+ ldh [hBGMapMode], a
+ inc a
+ ldh [hInMenu], a
+ call InitScrollingMenuCursor
+ call ScrollingMenu_InitFlags
+ call ScrollingMenu_ValidateSwitchItem
+ call ScrollingMenu_InitDisplay
+ call ApplyTilemap
+ xor a
+ ldh [hBGMapMode], a
+ ret
+
+_ScrollingMenu::
+.loop
+ call ScrollingMenuJoyAction
+ jp c, .exit
+ call z, .zero
+ jr .loop
+
+.exit
+ call MenuClickSound
+ ld [wMenuJoypad], a
+ ld a, 0
+ ldh [hInMenu], a
+ ret
+
+.zero
+ call ScrollingMenu_InitDisplay
+ ld a, 1
+ ldh [hBGMapMode], a
+ ld c, 3
+ call DelayFrames
+ xor a
+ ldh [hBGMapMode], a
+ ret
+
+ScrollingMenu_InitDisplay:
+ xor a
+ ldh [hBGMapMode], a
+ ld hl, wOptions
+ ld a, [hl]
+ push af
+ set NO_TEXT_SCROLL, [hl]
+ call ScrollingMenu_UpdateDisplay
+ call ScrollingMenu_PlaceCursor
+ call ScrollingMenu_CheckCallFunction3
+ pop af
+ ld [wOptions], a
+ ret
+
+ScrollingMenuJoyAction:
+.loop
+ call ScrollingMenuJoypad
+ ldh a, [hJoyLast]
+ and D_PAD
+ ld b, a
+ ldh a, [hJoyPressed]
+ and BUTTONS
+ or b
+ bit A_BUTTON_F, a
+ jp nz, .a_button
+ bit B_BUTTON_F, a
+ jp nz, .b_button
+ bit SELECT_F, a
+ jp nz, .select
+ bit START_F, a
+ jp nz, .start
+ bit D_RIGHT_F, a
+ jp nz, .d_right
+ bit D_LEFT_F, a
+ jp nz, .d_left
+ bit D_UP_F, a
+ jp nz, .d_up
+ bit D_DOWN_F, a
+ jp nz, .d_down
+ jr .loop
+
+.unreferenced ; unused
+ ld a, -1
+ and a
+ ret
+
+.a_button
+ call PlaceHollowCursor
+ ld a, [wMenuCursorY]
+ dec a
+ call ScrollingMenu_GetListItemCoordAndFunctionArgs
+ ld a, [wMenuSelection]
+ ld [wCurItem], a
+ ld a, [wMenuSelectionQuantity]
+ ld [wItemQuantityBuffer], a
+ call ScrollingMenu_GetCursorPosition
+ dec a
+ ld [wScrollingMenuCursorPosition], a
+ ld [wCurItemQuantity], a
+ ld a, [wMenuSelection]
+ cp -1
+ jr z, .b_button
+ ld a, A_BUTTON
+ scf
+ ret
+
+.b_button
+ ld a, B_BUTTON
+ scf
+ ret
+
+.select
+ ld a, [wMenuDataFlags]
+ bit 7, a
+ jp z, xor_a_dec_a
+ ld a, [wMenuCursorY]
+ dec a
+ call ScrollingMenu_GetListItemCoordAndFunctionArgs
+ ld a, [wMenuSelection]
+ cp -1
+ jp z, xor_a_dec_a
+ call ScrollingMenu_GetCursorPosition
+ dec a
+ ld [wScrollingMenuCursorPosition], a
+ ld a, SELECT
+ scf
+ ret
+
+.start
+ ld a, [wMenuDataFlags]
+ bit 6, a
+ jp z, xor_a_dec_a
+ ld a, START
+ scf
+ ret
+
+.d_left
+ ld hl, w2DMenuFlags2
+ bit 7, [hl]
+ jp z, xor_a_dec_a
+ ld a, [wMenuDataFlags]
+ bit 3, a
+ jp z, xor_a_dec_a
+ ld a, D_LEFT
+ scf
+ ret
+
+.d_right
+ ld hl, w2DMenuFlags2
+ bit 7, [hl]
+ jp z, xor_a_dec_a
+ ld a, [wMenuDataFlags]
+ bit 2, a
+ jp z, xor_a_dec_a
+ ld a, D_RIGHT
+ scf
+ ret
+
+.d_up
+ ld hl, w2DMenuFlags2
+ bit 7, [hl]
+ jp z, xor_a
+ ld hl, wMenuScrollPosition
+ ld a, [hl]
+ and a
+ jr z, .xor_dec_up
+ dec [hl]
+ jp xor_a
+
+.xor_dec_up
+ jp xor_a_dec_a
+
+.d_down
+ ld hl, w2DMenuFlags2
+ bit 7, [hl]
+ jp z, xor_a
+ ld hl, wMenuScrollPosition
+ ld a, [wMenuData_ScrollingMenuHeight]
+ add [hl]
+ ld b, a
+ ld a, [wScrollingMenuListSize]
+ cp b
+ jr c, .xor_dec_down
+ inc [hl]
+ jp xor_a
+
+.xor_dec_down
+ jp xor_a_dec_a
+
+ScrollingMenu_GetCursorPosition:
+ ld a, [wMenuScrollPosition]
+ ld c, a
+ ld a, [wMenuCursorY]
+ add c
+ ld c, a
+ ret
+
+ScrollingMenu_ClearLeftColumn:
+ call MenuBoxCoord2Tile
+ ld de, SCREEN_WIDTH
+ add hl, de
+ ld de, 2 * SCREEN_WIDTH
+ ld a, [wMenuData_ScrollingMenuHeight]
+.loop
+ ld [hl], " "
+ add hl, de
+ dec a
+ jr nz, .loop
+ ret
+
+InitScrollingMenuCursor:
+ ld hl, wMenuData_ItemsPointerAddr
+ ld a, [hli]
+ ld h, [hl]
+ ld l, a
+ ld a, [wMenuData_ItemsPointerBank]
+ call GetFarByte
+ ld [wScrollingMenuListSize], a
+ ld a, [wMenuData_ScrollingMenuHeight]
+ ld c, a
+ ld a, [wMenuScrollPosition]
+ add c
+ ld c, a
+ ld a, [wScrollingMenuListSize]
+ inc a
+ cp c
+ jr nc, .skip
+ ld a, [wMenuData_ScrollingMenuHeight]
+ ld c, a
+ ld a, [wScrollingMenuListSize]
+ inc a
+ sub c
+ jr nc, .store
+ xor a
+
+.store
+ ld [wMenuScrollPosition], a
+
+.skip
+ ld a, [wMenuScrollPosition]
+ ld c, a
+ ld a, [wMenuCursorBuffer]
+ add c
+ ld b, a
+ ld a, [wScrollingMenuListSize]
+ inc a
+ cp b
+ jr c, .wrap
+ jr nc, .done
+
+.wrap
+ xor a
+ ld [wMenuScrollPosition], a
+ ld a, $1
+ ld [wMenuCursorBuffer], a
+
+.done
+ ret
+
+ScrollingMenu_InitFlags:
+ ld a, [wMenuDataFlags]
+ ld c, a
+ ld a, [wScrollingMenuListSize]
+ ld b, a
+ ld a, [wMenuBorderTopCoord]
+ add 1
+ ld [w2DMenuCursorInitY], a
+ ld a, [wMenuBorderLeftCoord]
+ add 0
+ ld [w2DMenuCursorInitX], a
+ ld a, [wMenuData_ScrollingMenuHeight]
+ cp b
+ jr c, .no_extra_row
+ jr z, .no_extra_row
+ ld a, b
+ inc a
+.no_extra_row
+ ld [w2DMenuNumRows], a
+ ld a, 1
+ ld [w2DMenuNumCols], a
+ ld a, $8c
+ bit 2, c
+ jr z, .skip_set_0
+ set 0, a
+
+.skip_set_0
+ bit 3, c
+ jr z, .skip_set_1
+ set 1, a
+
+.skip_set_1
+ ld [w2DMenuFlags1], a
+ xor a
+ ld [w2DMenuFlags2], a
+ ld a, $20
+ ld [w2DMenuCursorOffsets], a
+ ld a, A_BUTTON | B_BUTTON | D_UP | D_DOWN
+ bit 7, c
+ jr z, .disallow_select
+ add SELECT
+
+.disallow_select
+ bit 6, c
+ jr z, .disallow_start
+ add START
+
+.disallow_start
+ ld [wMenuJoypadFilter], a
+ ld a, [w2DMenuNumRows]
+ ld b, a
+ ld a, [wMenuCursorBuffer]
+ and a
+ jr z, .reset_cursor
+ cp b
+ jr z, .cursor_okay
+ jr c, .cursor_okay
+
+.reset_cursor
+ ld a, 1
+
+.cursor_okay
+ ld [wMenuCursorY], a
+ ld a, 1
+ ld [wMenuCursorX], a
+ xor a
+ ld [wCursorCurrentTile], a
+ ld [wCursorCurrentTile + 1], a
+ ld [wCursorOffCharacter], a
+ ret
+
+ScrollingMenu_ValidateSwitchItem:
+ ld a, [wScrollingMenuListSize]
+ ld c, a
+ ld a, [wSwitchItem]
+ and a
+ jr z, .done
+ dec a
+ cp c
+ jr c, .done
+ xor a
+ ld [wSwitchItem], a
+
+.done
+ ret
+
+ScrollingMenu_UpdateDisplay:
+ call ClearWholeMenuBox
+ ld a, [wMenuDataFlags]
+ bit 4, a ; place arrows
+ jr z, .okay
+ ld a, [wMenuScrollPosition]
+ and a
+ jr z, .okay
+ ld a, [wMenuBorderTopCoord]
+ ld b, a
+ ld a, [wMenuBorderRightCoord]
+ ld c, a
+ call Coord2Tile
+ ld [hl], "▲"
+
+.okay
+ call MenuBoxCoord2Tile
+ ld bc, SCREEN_WIDTH + 1
+ add hl, bc
+ ld a, [wMenuData_ScrollingMenuHeight]
+ ld b, a
+ ld c, $0
+.loop
+ ld a, [wMenuScrollPosition]
+ add c
+ ld [wScrollingMenuCursorPosition], a
+ ld a, c
+ call ScrollingMenu_GetListItemCoordAndFunctionArgs
+ ld a, [wMenuSelection]
+ cp -1
+ jr z, .cancel
+ push bc
+ push hl
+ call ScrollingMenu_CallFunctions1and2
+ pop hl
+ ld bc, 2 * SCREEN_WIDTH
+ add hl, bc
+ pop bc
+ inc c
+ ld a, c
+ cp b
+ jr nz, .loop
+ ld a, [wMenuDataFlags]
+ bit 4, a ; place arrows
+ jr z, .done
+ ld a, [wMenuBorderBottomCoord]
+ ld b, a
+ ld a, [wMenuBorderRightCoord]
+ ld c, a
+ call Coord2Tile
+ ld [hl], "▼"
+
+.done
+ ret
+
+.cancel
+ ld a, [wMenuDataFlags]
+ bit 0, a ; call function on cancel
+ jr nz, .call_function
+ ld de, .string_24787
+ call PlaceString
+ ret
+
+.string_24787
+ db "CANCEL@"
+
+.call_function
+ ld d, h
+ ld e, l
+ ld hl, wMenuData_ScrollingMenuFunction1
+ jp CallPointerAt
+
+ScrollingMenu_CallFunctions1and2:
+ push hl
+ ld d, h
+ ld e, l
+ ld hl, wMenuData_ScrollingMenuFunction1
+ call CallPointerAt
+ pop hl
+ ld a, [wMenuData_ScrollingMenuWidth]
+ and a
+ jr z, .done
+ ld e, a
+ ld d, $0
+ add hl, de
+ ld d, h
+ ld e, l
+ ld hl, wMenuData_ScrollingMenuFunction2
+ call CallPointerAt
+
+.done
+ ret
+
+ScrollingMenu_PlaceCursor:
+ ld a, [wSwitchItem]
+ and a
+ jr z, .done
+ ld b, a
+ ld a, [wMenuScrollPosition]
+ cp b
+ jr nc, .done
+ ld c, a
+ ld a, [wMenuData_ScrollingMenuHeight]
+ add c
+ cp b
+ jr c, .done
+ ld a, b
+ sub c
+ dec a
+ add a
+ add $1
+ ld c, a
+ ld a, [wMenuBorderTopCoord]
+ add c
+ ld b, a
+ ld a, [wMenuBorderLeftCoord]
+ add $0
+ ld c, a
+ call Coord2Tile
+ ld [hl], "▷"
+
+.done
+ ret
+
+ScrollingMenu_CheckCallFunction3:
+ ld a, [wMenuDataFlags]
+ bit 5, a ; call function 3
+ ret z
+ bit 1, a ; call function 3 if not switching items
+ jr z, .call
+ ld a, [wSwitchItem]
+ and a
+ ret nz
+
+.call
+ ld a, [wMenuCursorY]
+ dec a
+ call ScrollingMenu_GetListItemCoordAndFunctionArgs
+ ld hl, wMenuData_ScrollingMenuFunction3
+ call CallPointerAt
+ ret
+
+ScrollingMenu_GetListItemCoordAndFunctionArgs:
+ push de
+ push hl
+ ld e, a
+ ld a, [wMenuScrollPosition]
+ add e
+ ld e, a
+ ld d, $0
+ ld hl, wMenuData_ItemsPointerAddr
+ ld a, [hli]
+ ld h, [hl]
+ ld l, a
+ inc hl ; items
+ ld a, [wMenuData_ScrollingMenuItemFormat]
+ cp SCROLLINGMENU_ITEMS_NORMAL
+ jr z, .got_spacing
+ cp SCROLLINGMENU_ITEMS_QUANTITY
+ jr z, .pointless_jump
+.pointless_jump
+ add hl, de
+.got_spacing
+ add hl, de
+ ld a, [wMenuData_ItemsPointerBank]
+ call GetFarByte
+ ld [wMenuSelection], a
+ ld [wCurItem], a
+ inc hl
+ ld a, [wMenuData_ItemsPointerBank]
+ call GetFarByte
+ ld [wMenuSelectionQuantity], a
+ pop hl
+ pop de
+ ret
diff --git a/engine/menus/start_menu.asm b/engine/menus/start_menu.asm
new file mode 100644
index 00000000..dbadf637
--- /dev/null
+++ b/engine/menus/start_menu.asm
@@ -0,0 +1,541 @@
+; StartMenu.Items indexes
+ const_def
+ const STARTMENUITEM_POKEDEX ; 0
+ const STARTMENUITEM_POKEMON ; 1
+ const STARTMENUITEM_PACK ; 2
+ const STARTMENUITEM_STATUS ; 3
+ const STARTMENUITEM_SAVE ; 4
+ const STARTMENUITEM_OPTION ; 5
+ const STARTMENUITEM_EXIT ; 6
+ const STARTMENUITEM_POKEGEAR ; 7
+ const STARTMENUITEM_QUIT ; 8
+
+StartMenu::
+ call ClearWindowData
+
+ ld de, SFX_MENU
+ call PlaySFX
+
+ farcall ReanchorBGMap_NoOAMUpdate
+
+ ld hl, wStatusFlags2
+ bit STATUSFLAGS2_BUG_CONTEST_TIMER_F, [hl]
+ ld hl, .MenuHeader
+ jr z, .GotMenuData
+ ld hl, .ContestMenuHeader
+
+.GotMenuData:
+ call LoadMenuHeader
+ call .SetUpMenuItems
+ ld a, [wBattleMenuCursorBuffer]
+ ld [wMenuCursorBuffer], a
+ call .DrawMenuAccount
+ call DrawVariableLengthMenuBox
+ call .DrawBugContestStatusBox
+ call SafeUpdateSprites
+ call _OpenAndCloseMenu_HDMATransferTilemapAndAttrmap
+ farcall LoadFonts_NoOAMUpdate
+ call .DrawBugContestStatus
+ call UpdateTimePals
+ jr .Select
+
+.Reopen:
+ call UpdateSprites
+ call UpdateTimePals
+ call .SetUpMenuItems
+ ld a, [wBattleMenuCursorBuffer]
+ ld [wMenuCursorBuffer], a
+
+.Select:
+ call .GetInput
+ jr c, .Exit
+ call ._DrawMenuAccount
+ ld a, [wMenuCursorBuffer]
+ ld [wBattleMenuCursorBuffer], a
+ call PlayClickSFX
+ call PlaceHollowCursor
+ call .OpenMenu
+
+; Menu items have different return functions.
+; For example, saving exits the menu.
+ ld hl, .MenuReturns
+ ld e, a
+ ld d, 0
+ add hl, de
+ add hl, de
+ ld a, [hli]
+ ld h, [hl]
+ ld l, a
+ jp hl
+
+.MenuReturns:
+ dw .Reopen
+ dw .Exit
+ dw .ExitMenuCallFuncCloseText
+ dw .ExitMenuRunScriptCloseText
+ dw .ExitMenuRunScript
+ dw .ReturnEnd
+ dw .ReturnRedraw
+
+.Exit:
+ ldh a, [hOAMUpdate]
+ push af
+ ld a, 1
+ ldh [hOAMUpdate], a
+ call LoadFontsExtra
+ pop af
+ ldh [hOAMUpdate], a
+.ReturnEnd:
+ call ExitMenu
+.ReturnEnd2:
+ call CloseText
+ call UpdateTimePals
+ ret
+
+.GetInput:
+; Return carry on exit, and no-carry on selection.
+ xor a
+ ldh [hBGMapMode], a
+ call ._DrawMenuAccount
+ call SetUpMenu
+ ld a, $ff
+ ld [wMenuSelection], a
+.loop
+ call .PrintMenuAccount
+ call GetScrollingMenuJoypad
+ ld a, [wMenuJoypad]
+ cp B_BUTTON
+ jr z, .b
+ cp A_BUTTON
+ jr z, .a
+ jr .loop
+.a
+ call PlayClickSFX
+ and a
+ ret
+.b
+ scf
+ ret
+
+.ExitMenuRunScript:
+ call ExitMenu
+ ld a, HMENURETURN_SCRIPT
+ ldh [hMenuReturn], a
+ ret
+
+.ExitMenuRunScriptCloseText:
+ call ExitMenu
+ ld a, HMENURETURN_SCRIPT
+ ldh [hMenuReturn], a
+ jr .ReturnEnd2
+
+.ExitMenuCallFuncCloseText:
+ call ExitMenu
+ ld hl, wQueuedScriptAddr
+ ld a, [hli]
+ ld h, [hl]
+ ld l, a
+ ld a, [wQueuedScriptBank]
+ rst FarCall
+ jr .ReturnEnd2
+
+.ReturnRedraw:
+ call .Clear
+ jp .Reopen
+
+.Clear:
+ call ClearBGPalettes
+ call Call_ExitMenu
+ call ReloadTilesetAndPalettes
+ call .DrawMenuAccount
+ call DrawVariableLengthMenuBox
+ call .DrawBugContestStatus
+ call UpdateSprites
+ call ReloadPalettes
+ call FinishExitMenu
+ ret
+
+.MenuHeader:
+ db MENU_BACKUP_TILES ; flags
+ menu_coords 10, 0, SCREEN_WIDTH - 1, SCREEN_HEIGHT - 1
+ dw .MenuData
+ db 1 ; default selection
+
+.ContestMenuHeader:
+ db MENU_BACKUP_TILES ; flags
+ menu_coords 10, 2, SCREEN_WIDTH - 1, SCREEN_HEIGHT - 1
+ dw .MenuData
+ db 1 ; default selection
+
+.MenuData:
+ db STATICMENU_CURSOR | STATICMENU_WRAP | STATICMENU_ENABLE_START ; flags
+ dn 0, 0 ; rows, columns
+ dw wMenuItemsList
+ dw .MenuString
+ dw .Items
+
+.Items:
+; entries correspond to STARTMENUITEM_* constants
+ dw StartMenu_Pokedex, .PokedexString, .PokedexDesc
+ dw StartMenu_Pokemon, .PartyString, .PartyDesc
+ dw StartMenu_Pack, .PackString, .PackDesc
+ dw StartMenu_Status, .StatusString, .StatusDesc
+ dw StartMenu_Save, .SaveString, .SaveDesc
+ dw StartMenu_Option, .OptionString, .OptionDesc
+ dw StartMenu_Exit, .ExitString, .ExitDesc
+ dw StartMenu_Pokegear, .PokegearString, .PokegearDesc
+ dw StartMenu_Quit, .QuitString, .QuitDesc
+
+.PokedexString: db "#DEX@"
+.PartyString: db "#MON@"
+.PackString: db "PACK@"
+.StatusString: db "<PLAYER>@"
+.SaveString: db "SAVE@"
+.OptionString: db "OPTION@"
+.ExitString: db "EXIT@"
+.PokegearString: db "<POKE>GEAR@"
+.QuitString: db "QUIT@"
+
+.PokedexDesc:
+ db "#MON"
+ next "database@"
+
+.PartyDesc:
+ db "Party <PKMN>"
+ next "status@"
+
+.PackDesc:
+ db "Contains"
+ next "items@"
+
+.PokegearDesc:
+ db "Trainer's"
+ next "key device@"
+
+.StatusDesc:
+ db "Your own"
+ next "status@"
+
+.SaveDesc:
+ db "Save your"
+ next "progress@"
+
+.OptionDesc:
+ db "Change"
+ next "settings@"
+
+.ExitDesc:
+ db "Close this"
+ next "menu@"
+
+.QuitDesc:
+ db "Quit and"
+ next "be judged.@"
+
+.OpenMenu:
+ ld a, [wMenuSelection]
+ call .GetMenuAccountTextPointer
+ ld a, [hli]
+ ld h, [hl]
+ ld l, a
+ jp hl
+
+.MenuString:
+ push de
+ ld a, [wMenuSelection]
+ call .GetMenuAccountTextPointer
+ inc hl
+ inc hl
+ ld a, [hli]
+ ld d, [hl]
+ ld e, a
+ pop hl
+ call PlaceString
+ ret
+
+.MenuDesc:
+ push de
+ ld a, [wMenuSelection]
+ cp $ff
+ jr z, .none
+ call .GetMenuAccountTextPointer
+rept 4
+ inc hl
+endr
+ ld a, [hli]
+ ld d, [hl]
+ ld e, a
+ pop hl
+ call PlaceString
+ ret
+.none
+ pop de
+ ret
+
+.GetMenuAccountTextPointer:
+ ld e, a
+ ld d, 0
+ ld hl, wMenuDataPointerTableAddr
+ ld a, [hli]
+ ld h, [hl]
+ ld l, a
+rept 6
+ add hl, de
+endr
+ ret
+
+.SetUpMenuItems:
+ xor a
+ ld [wWhichIndexSet], a
+ call .FillMenuList
+
+ ld hl, wStatusFlags
+ bit STATUSFLAGS_POKEDEX_F, [hl]
+ jr z, .no_pokedex
+ ld a, STARTMENUITEM_POKEDEX
+ call .AppendMenuList
+.no_pokedex
+
+ ld a, [wPartyCount]
+ and a
+ jr z, .no_pokemon
+ ld a, STARTMENUITEM_POKEMON
+ call .AppendMenuList
+.no_pokemon
+
+ ld a, [wLinkMode]
+ and a
+ jr nz, .no_pack
+ ld hl, wStatusFlags2
+ bit STATUSFLAGS2_BUG_CONTEST_TIMER_F, [hl]
+ jr nz, .no_pack
+ ld a, STARTMENUITEM_PACK
+ call .AppendMenuList
+.no_pack
+
+ ld hl, wPokegearFlags
+ bit POKEGEAR_OBTAINED_F, [hl]
+ jr z, .no_pokegear
+ ld a, STARTMENUITEM_POKEGEAR
+ call .AppendMenuList
+.no_pokegear
+
+ ld a, STARTMENUITEM_STATUS
+ call .AppendMenuList
+
+ ld a, [wLinkMode]
+ and a
+ jr nz, .no_save
+ ld hl, wStatusFlags2
+ bit STATUSFLAGS2_BUG_CONTEST_TIMER_F, [hl]
+ ld a, STARTMENUITEM_QUIT
+ jr nz, .write
+ ld a, STARTMENUITEM_SAVE
+.write
+ call .AppendMenuList
+.no_save
+
+ ld a, STARTMENUITEM_OPTION
+ call .AppendMenuList
+ ld a, STARTMENUITEM_EXIT
+ call .AppendMenuList
+ ld a, c
+ ld [wMenuItemsList], a
+ ret
+
+.FillMenuList:
+ xor a
+ ld hl, wMenuItemsList
+ ld [hli], a
+ ld a, -1
+ ld bc, wMenuItemsListEnd - (wMenuItemsList + 1)
+ call ByteFill
+ ld de, wMenuItemsList + 1
+ ld c, 0
+ ret
+
+.AppendMenuList:
+ ld [de], a
+ inc de
+ inc c
+ ret
+
+.DrawMenuAccount:
+ jp ._DrawMenuAccount
+
+.PrintMenuAccount:
+ call .IsMenuAccountOn
+ ret z
+ call ._DrawMenuAccount
+ decoord 0, 14
+ jp .MenuDesc
+
+._DrawMenuAccount:
+ call .IsMenuAccountOn
+ ret z
+ hlcoord 0, 13
+ lb bc, 5, 10
+ call ClearBox
+ hlcoord 0, 13
+ ld b, 3
+ ld c, 8
+ jp TextboxPalette
+
+.IsMenuAccountOn:
+ ld a, [wOptions2]
+ and 1 << MENU_ACCOUNT
+ ret
+
+.DrawBugContestStatusBox:
+ ld hl, wStatusFlags2
+ bit STATUSFLAGS2_BUG_CONTEST_TIMER_F, [hl]
+ ret z
+ farcall StartMenu_DrawBugContestStatusBox
+ ret
+
+.DrawBugContestStatus:
+ ld hl, wStatusFlags2
+ bit STATUSFLAGS2_BUG_CONTEST_TIMER_F, [hl]
+ jr nz, .contest
+ ret
+.contest
+ farcall StartMenu_PrintBugContestStatus
+ ret
+
+StartMenu_Exit:
+; Exit the menu.
+
+ ld a, 1
+ ret
+
+StartMenu_Quit:
+; Retire from the bug catching contest.
+
+ ld hl, .StartMenuContestEndText
+ call StartMenuYesNo
+ jr c, .DontEndContest
+ ld a, BANK(BugCatchingContestReturnToGateScript)
+ ld hl, BugCatchingContestReturnToGateScript
+ call FarQueueScript
+ ld a, 4
+ ret
+
+.DontEndContest:
+ ld a, 0
+ ret
+
+.StartMenuContestEndText:
+ text_far _StartMenuContestEndText
+ text_end
+
+StartMenu_Save:
+; Save the game.
+
+ call BufferScreen
+ farcall SaveMenu
+ jr nc, .asm_12ce0
+ ld a, 0
+ ret
+.asm_12ce0
+ ld a, 1
+ ret
+
+StartMenu_Option:
+; Game options.
+
+ call FadeToMenu
+ farcall OptionsMenu
+ ld a, 6
+ ret
+
+StartMenu_Status:
+; Player status.
+
+ call FadeToMenu
+ farcall TrainerCard
+ call CloseSubmenu
+ ld a, 0
+ ret
+
+StartMenu_Pokedex:
+ ld a, [wPartyCount]
+ and a
+ jr z, .asm_12de0
+
+ call FadeToMenu
+ farcall Pokedex
+ call CloseSubmenu
+
+.asm_12de0
+ ld a, 0
+ ret
+
+StartMenu_Pokegear:
+ call FadeToMenu
+ farcall PokeGear
+ call CloseSubmenu
+ ld a, 0
+ ret
+
+StartMenu_Pack:
+ call FadeToMenu
+ farcall Pack
+ ld a, [wPackUsedItem]
+ and a
+ jr nz, .used_item
+ call CloseSubmenu
+ ld a, 0
+ ret
+
+.used_item
+ call ExitAllMenus
+ ld a, 4
+ ret
+
+StartMenu_Pokemon:
+ ld a, [wPartyCount]
+ and a
+ jr z, .return
+
+ call FadeToMenu
+
+.choosemenu
+ xor a
+ ld [wPartyMenuActionText], a ; Choose a POKéMON.
+ call ClearBGPalettes
+
+.menu
+ farcall LoadPartyMenuGFX
+ farcall InitPartyMenuWithCancel
+ farcall InitPartyMenuGFX
+
+.menunoreload
+ farcall WritePartyMenuTilemap
+ farcall PrintPartyMenuText
+ call WaitBGMap
+ call SetPalettes ; load regular palettes?
+ call DelayFrame
+ farcall PartyMenuSelect
+ jr c, .return ; if cancelled or pressed B
+
+ call PokemonActionSubmenu
+ cp 3
+ jr z, .menu
+ cp 0
+ jr z, .choosemenu
+ cp 1
+ jr z, .menunoreload
+ cp 2
+ jr z, .quit
+
+.return
+ call CloseSubmenu
+ ld a, 0
+ ret
+
+.quit
+ ld a, b
+ push af
+ call ExitAllMenus
+ pop af
+ ret
diff --git a/engine/menus/trainer_card.asm b/engine/menus/trainer_card.asm
new file mode 100644
index 00000000..7061d4bd
--- /dev/null
+++ b/engine/menus/trainer_card.asm
@@ -0,0 +1,624 @@
+; TrainerCard.Jumptable indexes
+ const_def
+ const TRAINERCARDSTATE_PAGE1_LOADGFX ; 0
+ const TRAINERCARDSTATE_PAGE1_JOYPAD ; 1
+ const TRAINERCARDSTATE_PAGE2_LOADGFX ; 2
+ const TRAINERCARDSTATE_PAGE2_JOYPAD ; 3
+ const TRAINERCARDSTATE_PAGE3_LOADGFX ; 4
+ const TRAINERCARDSTATE_PAGE3_JOYPAD ; 5
+ const TRAINERCARDSTATE_QUIT ; 6
+
+TrainerCard:
+ ld a, [wVramState]
+ push af
+ xor a
+ ld [wVramState], a
+ ld hl, wOptions
+ ld a, [hl]
+ push af
+ set NO_TEXT_SCROLL, [hl]
+ call .InitRAM
+.loop
+ call UpdateTime
+ call JoyTextDelay
+ ld a, [wJumptableIndex]
+ bit 7, a
+ jr nz, .quit
+ ldh a, [hJoyLast]
+ and B_BUTTON
+ jr nz, .quit
+ call .RunJumptable
+ call DelayFrame
+ jr .loop
+
+.quit
+ pop af
+ ld [wOptions], a
+ pop af
+ ld [wVramState], a
+ ret
+
+.InitRAM:
+ call ClearBGPalettes
+ call ClearSprites
+ call ClearTilemap
+ call DisableLCD
+
+ ld hl, ChrisCardPic
+ ld de, vTiles2
+ ld bc, 41 tiles
+ ld a, BANK(ChrisCardPic)
+ call FarCopyBytes
+
+ ld hl, CardStatusGFX
+ ld de, vTiles2 tile $29
+ ld bc, 86 tiles
+ ld a, BANK(CardStatusGFX)
+ call FarCopyBytes
+
+ call TrainerCard_PrintTopHalfOfCard
+
+ hlcoord 0, 8
+ ld d, 6
+ call TrainerCard_InitBorder
+
+ call EnableLCD
+ call WaitBGMap
+ ld b, SCGB_TRAINER_CARD
+ call GetSGBLayout
+ call SetPalettes
+ call WaitBGMap
+ ld hl, wJumptableIndex
+ xor a ; TRAINERCARDSTATE_PAGE1_LOADGFX
+ ld [hli], a ; wJumptableIndex
+ ld [hli], a ; wTrainerCardBadgeFrameCounter
+ ld [hli], a ; wTrainerCardBadgeTileID
+ ld [hl], a ; wTrainerCardBadgeAttributes
+ ret
+
+.RunJumptable:
+ jumptable .Jumptable, wJumptableIndex
+
+.Jumptable:
+; entries correspond to TRAINERCARDSTATE_* constants
+ dw TrainerCard_Page1_LoadGFX
+ dw TrainerCard_Page1_Joypad
+ dw TrainerCard_Page2_LoadGFX
+ dw TrainerCard_Page2_Joypad
+ dw TrainerCard_Page3_LoadGFX
+ dw TrainerCard_Page3_Joypad
+ dw TrainerCard_Quit
+
+TrainerCard_IncrementJumptable:
+ ld hl, wJumptableIndex
+ inc [hl]
+ ret
+
+TrainerCard_Quit:
+ ld hl, wJumptableIndex
+ set 7, [hl]
+ ret
+
+TrainerCard_Page1_LoadGFX:
+ call ClearSprites
+ hlcoord 0, 8
+ ld d, 6
+ call TrainerCard_InitBorder
+ call WaitBGMap
+ ld de, CardStatusGFX
+ ld hl, vTiles2 tile $29
+ lb bc, BANK(CardStatusGFX), 86
+ call Request2bpp
+ call TrainerCard_Page1_PrintDexCaught_GameTime
+ call TrainerCard_IncrementJumptable
+ ret
+
+TrainerCard_Page1_Joypad:
+ call TrainerCard_Page1_PrintGameTime
+ ld hl, hJoyLast
+ ld a, [hl]
+ and D_RIGHT | A_BUTTON
+ jr nz, .pressed_right_a
+ ret
+
+.pressed_right_a
+ ld a, TRAINERCARDSTATE_PAGE2_LOADGFX
+ ld [wJumptableIndex], a
+ ret
+
+.Unreferenced_KantoCheck:
+ ld a, [wKantoBadges]
+ and a
+ ret z
+ ld a, TRAINERCARDSTATE_PAGE3_LOADGFX
+ ld [wJumptableIndex], a
+ ret
+
+TrainerCard_Page2_LoadGFX:
+ call ClearSprites
+ hlcoord 0, 8
+ ld d, 6
+ call TrainerCard_InitBorder
+ call WaitBGMap
+ ld de, LeaderGFX
+ ld hl, vTiles2 tile $29
+ lb bc, BANK(LeaderGFX), 86
+ call Request2bpp
+ ld de, BadgeGFX
+ ld hl, vTiles0 tile $00
+ lb bc, BANK(BadgeGFX), 44
+ call Request2bpp
+ call TrainerCard_Page2_3_InitObjectsAndStrings
+ call TrainerCard_IncrementJumptable
+ ret
+
+TrainerCard_Page2_Joypad:
+ ld hl, TrainerCard_JohtoBadgesOAM
+ call TrainerCard_Page2_3_AnimateBadges
+ ld hl, hJoyLast
+ ld a, [hl]
+ and A_BUTTON
+ jr nz, .Quit
+ ld a, [hl]
+ and D_LEFT
+ jr nz, .d_left
+ ret
+
+.d_left
+ ld a, TRAINERCARDSTATE_PAGE1_LOADGFX
+ ld [wJumptableIndex], a
+ ret
+
+.Unreferenced_KantoCheck:
+ ld a, [wKantoBadges]
+ and a
+ ret z
+ ld a, TRAINERCARDSTATE_PAGE3_LOADGFX
+ ld [wJumptableIndex], a
+ ret
+
+.Quit:
+ ld a, TRAINERCARDSTATE_QUIT
+ ld [wJumptableIndex], a
+ ret
+
+TrainerCard_Page3_LoadGFX:
+ call ClearSprites
+ hlcoord 0, 8
+ ld d, 6
+ call TrainerCard_InitBorder
+ call WaitBGMap
+ ld de, LeaderGFX2
+ ld hl, vTiles2 tile $29
+ lb bc, BANK(LeaderGFX2), 86
+ call Request2bpp
+ ld de, BadgeGFX2
+ ld hl, vTiles0 tile $00
+ lb bc, BANK(BadgeGFX2), 44
+ call Request2bpp
+ call TrainerCard_Page2_3_InitObjectsAndStrings
+ call TrainerCard_IncrementJumptable
+ ret
+
+TrainerCard_Page3_Joypad:
+ ld hl, TrainerCard_JohtoBadgesOAM
+ call TrainerCard_Page2_3_AnimateBadges
+ ld hl, hJoyLast
+ ld a, [hl]
+ and D_LEFT
+ jr nz, .left
+ ld a, [hl]
+ and D_RIGHT
+ jr nz, .right
+ ret
+
+.left
+ ld a, TRAINERCARDSTATE_PAGE2_LOADGFX
+ ld [wJumptableIndex], a
+ ret
+
+.right
+ ld a, TRAINERCARDSTATE_PAGE1_LOADGFX
+ ld [wJumptableIndex], a
+ ret
+
+TrainerCard_PrintTopHalfOfCard:
+ hlcoord 0, 0
+ ld d, 5
+ call TrainerCard_InitBorder
+ hlcoord 2, 2
+ ld de, .Name_Money
+ call PlaceString
+ hlcoord 2, 4
+ ld de, .ID_No
+ call TrainerCardSetup_PlaceTilemapString
+ hlcoord 7, 2
+ ld de, wPlayerName
+ call PlaceString
+ hlcoord 5, 4
+ ld de, wPlayerID
+ lb bc, PRINTNUM_LEADINGZEROS | 2, 5
+ call PrintNum
+ hlcoord 7, 6
+ ld de, wMoney
+ lb bc, PRINTNUM_MONEY | 3, 6
+ call PrintNum
+ hlcoord 1, 3
+ ld de, .HorizontalDivider
+ call TrainerCardSetup_PlaceTilemapString
+ hlcoord 14, 1
+ ld de, SCREEN_WIDTH
+ xor a
+ ld b, 7
+
+.row
+ ld c, 5
+ push hl
+
+.col
+ ld [hli], a
+ inc a
+ dec c
+ jr nz, .col
+ pop hl
+ add hl, de
+ dec b
+ jr nz, .row
+ ret
+
+.Name_Money:
+ db "NAME/"
+ next ""
+ next "MONEY@"
+
+.ID_No:
+ db $27, $28, -1 ; ID NO
+
+.HorizontalDivider:
+ db $25, $25, $25, $25, $25, $25, $25, $25, $25, $25, $25, $25, $26, -1 ; ____________>
+
+TrainerCard_Page1_PrintDexCaught_GameTime:
+ hlcoord 2, 10
+ ld de, .Dex_PlayTime
+ call PlaceString
+ hlcoord 12, 15
+ ld de, .Badges
+ call PlaceString
+ ld hl, wPokedexCaught
+ ld b, wEndPokedexCaught - wPokedexCaught
+ call CountSetBits
+ ld de, wNumSetBits
+ hlcoord 15, 10
+ lb bc, 1, 3
+ call PrintNum
+ call TrainerCard_Page1_PrintGameTime
+ hlcoord 2, 8
+ ld de, .StatusTilemap
+ call TrainerCardSetup_PlaceTilemapString
+ ld a, [wStatusFlags]
+ bit STATUSFLAGS_POKEDEX_F, a
+ ret nz
+ hlcoord 1, 9
+ lb bc, 2, 17
+ call ClearBox
+ ret
+
+.Dex_PlayTime:
+ db "#DEX"
+ next "PLAY TIME@"
+
+ db "@" ; unused
+
+.Badges:
+ db "BADGES▶@"
+
+.StatusTilemap:
+ db $29, $2a, $2b, $2c, $2d, -1
+
+TrainerCard_Page2_3_InitObjectsAndStrings:
+ hlcoord 2, 8
+ ld de, .BadgesTilemap
+ call TrainerCardSetup_PlaceTilemapString
+ hlcoord 2, 10
+ ld a, $29
+ ld c, 4
+.loop
+ call TrainerCard_Page2_3_PlaceLeadersFaces
+rept 4
+ inc hl
+endr
+ dec c
+ jr nz, .loop
+ hlcoord 2, 13
+ ld a, $51
+ ld c, 4
+.loop2
+ call TrainerCard_Page2_3_PlaceLeadersFaces
+rept 4
+ inc hl
+endr
+ dec c
+ jr nz, .loop2
+ xor a
+ ld [wTrainerCardBadgeFrameCounter], a
+ ld hl, TrainerCard_JohtoBadgesOAM
+ call TrainerCard_Page2_3_OAMUpdate
+ ret
+
+.BadgesTilemap:
+ db $79, $7a, $7b, $7c, $7d, -1 ; "BADGES"
+
+TrainerCardSetup_PlaceTilemapString:
+.loop
+ ld a, [de]
+ cp -1
+ ret z
+ ld [hli], a
+ inc de
+ jr .loop
+
+TrainerCard_InitBorder:
+ ld e, SCREEN_WIDTH
+.loop1
+ ld a, $23
+ ld [hli], a
+ dec e
+ jr nz, .loop1
+
+ ld a, $23
+ ld [hli], a
+ ld e, SCREEN_HEIGHT - 1
+ ld a, " "
+.loop2
+ ld [hli], a
+ dec e
+ jr nz, .loop2
+
+ ld a, $4
+ ld [hli], a
+ ld a, $23
+ ld [hli], a
+.loop3
+ ld a, $23
+ ld [hli], a
+
+ ld e, SCREEN_HEIGHT
+ ld a, " "
+.loop4
+ ld [hli], a
+ dec e
+ jr nz, .loop4
+
+ ld a, $23
+ ld [hli], a
+ dec d
+ jr nz, .loop3
+
+ ld a, $23
+ ld [hli], a
+ ld a, $24
+ ld [hli], a
+
+ ld e, SCREEN_HEIGHT - 1
+ ld a, " "
+.loop5
+ ld [hli], a
+ dec e
+ jr nz, .loop5
+ ld a, $23
+ ld [hli], a
+ ld e, SCREEN_WIDTH
+.loop6
+ ld a, $23
+ ld [hli], a
+ dec e
+ jr nz, .loop6
+ ret
+
+TrainerCard_Page2_3_PlaceLeadersFaces:
+ push de
+ push hl
+ ld [hli], a
+ inc a
+ ld [hli], a
+ inc a
+ ld [hli], a
+ inc a
+ ld [hli], a
+ inc a
+ ld de, SCREEN_WIDTH - 3
+ add hl, de
+ ld [hli], a
+ inc a
+ ld [hli], a
+ inc a
+ ld [hli], a
+ inc a
+ ld de, SCREEN_WIDTH - 3
+ add hl, de
+ ld [hli], a
+ inc a
+ ld [hli], a
+ inc a
+ ld [hli], a
+ inc a
+ pop hl
+ pop de
+ ret
+
+TrainerCard_Page1_PrintGameTime:
+ hlcoord 11, 12
+ ld de, wGameTimeHours
+ lb bc, 2, 4
+ call PrintNum
+ inc hl
+ ld de, wGameTimeMinutes
+ lb bc, PRINTNUM_LEADINGZEROS | 1, 2
+ call PrintNum
+ ldh a, [hVBlankCounter]
+ and $1f
+ ret nz
+ hlcoord 15, 12
+ ld a, [hl]
+ xor " " ^ $2e ; alternate between space and small colon ($2e) tiles
+ ld [hl], a
+ ret
+
+TrainerCard_Page2_3_AnimateBadges:
+ ldh a, [hVBlankCounter]
+ and %111
+ ret nz
+ ld a, [wTrainerCardBadgeFrameCounter]
+ inc a
+ and %111
+ ld [wTrainerCardBadgeFrameCounter], a
+ jr TrainerCard_Page2_3_OAMUpdate
+
+TrainerCard_Page2_3_OAMUpdate:
+; copy flag array pointer
+ ld a, [hli]
+ ld e, a
+ ld a, [hli]
+; get flag array
+ ld d, a
+ ld a, [de]
+ ld c, a
+ ld de, wVirtualOAMSprite00
+ ld b, NUM_JOHTO_BADGES
+.loop
+ srl c
+ push bc
+ jr nc, .skip_badge
+ push hl
+ ld a, [hli] ; y
+ ld b, a
+ ld a, [hli] ; x
+ ld c, a
+ ld a, [hli] ; pal
+ ld [wTrainerCardBadgeAttributes], a
+ ld a, [wTrainerCardBadgeFrameCounter]
+ add l
+ ld l, a
+ ld a, 0
+ adc h
+ ld h, a
+ ld a, [hl]
+ ld [wTrainerCardBadgeTileID], a
+ call .PrepOAM
+ pop hl
+.skip_badge
+ ld bc, $b ; 3 + 2 * 4
+ add hl, bc
+ pop bc
+ dec b
+ jr nz, .loop
+ ret
+
+.PrepOAM:
+ ld a, [wTrainerCardBadgeTileID]
+ and 1 << 7
+ jr nz, .xflip
+ ld hl, .facing1
+ jr .loop2
+
+.xflip
+ ld hl, .facing2
+.loop2
+ ld a, [hli]
+ cp -1
+ ret z
+ add b
+ ld [de], a ; y
+ inc de
+
+ ld a, [hli]
+ add c
+ ld [de], a ; x
+ inc de
+
+ ld a, [wTrainerCardBadgeTileID]
+ and $ff ^ (1 << 7)
+ add [hl]
+ ld [de], a ; tile id
+ inc hl
+ inc de
+
+ ld a, [wTrainerCardBadgeAttributes]
+ add [hl]
+ ld [de], a ; attributes
+ inc hl
+ inc de
+ jr .loop2
+
+.facing1
+ dbsprite 0, 0, 0, 0, $00, 0
+ dbsprite 1, 0, 0, 0, $01, 0
+ dbsprite 0, 1, 0, 0, $02, 0
+ dbsprite 1, 1, 0, 0, $03, 0
+ db -1
+
+.facing2
+ dbsprite 0, 0, 0, 0, $01, 0 | X_FLIP
+ dbsprite 1, 0, 0, 0, $00, 0 | X_FLIP
+ dbsprite 0, 1, 0, 0, $03, 0 | X_FLIP
+ dbsprite 1, 1, 0, 0, $02, 0 | X_FLIP
+ db -1
+
+TrainerCard_JohtoBadgesOAM:
+; Template OAM data for each badge on the trainer card.
+; Format:
+ ; y, x, palette
+ ; cycle 1: face tile, in1 tile, in2 tile, in3 tile
+ ; cycle 2: face tile, in1 tile, in2 tile, in3 tile
+
+ dw wJohtoBadges
+
+ ; Zephyrbadge
+ db $68, $18, 0
+ db $00, $20, $24, $20 | (1 << 7)
+ db $00, $20, $24, $20 | (1 << 7)
+
+ ; Hivebadge
+ db $68, $38, 0
+ db $04, $20, $24, $20 | (1 << 7)
+ db $04, $20, $24, $20 | (1 << 7)
+
+ ; Plainbadge
+ db $68, $58, 0
+ db $08, $20, $24, $20 | (1 << 7)
+ db $08, $20, $24, $20 | (1 << 7)
+
+ ; Fogbadge
+ db $68, $78, 0
+ db $0c, $20, $24, $20 | (1 << 7)
+ db $0c, $20, $24, $20 | (1 << 7)
+
+ ; Mineralbadge
+ db $80, $38, 0
+ db $10, $20, $24, $20 | (1 << 7)
+ db $10, $20, $24, $20 | (1 << 7)
+
+ ; Stormbadge
+ db $80, $18, 0
+ db $14, $20, $24, $20 | (1 << 7)
+ db $14, $20, $24, $20 | (1 << 7)
+
+ ; Glacierbadge
+ db $80, $58, 0
+ db $18, $20, $24, $20 | (1 << 7)
+ db $18, $20, $24, $20 | (1 << 7)
+
+ ; Risingbadge
+ ; X-flips on alternate cycles.
+ db $80, $78, 0
+ db $1c, $20, $24, $20 | (1 << 7)
+ db $1c | (1 << 7), $20, $24, $20 | (1 << 7)
+
+ChrisCardPic: INCBIN "gfx/trainer_card/chris_card.2bpp"
+CardGFX: INCBIN "gfx/trainer_card/trainer_card.2bpp"
+CardStatusGFX: INCBIN "gfx/trainer_card/card_status.2bpp"
+
+LeaderGFX: INCBIN "gfx/trainer_card/leaders.2bpp"
+LeaderGFX2: INCBIN "gfx/trainer_card/leaders.2bpp"
+BadgeGFX: INCBIN "gfx/trainer_card/badges.2bpp"
+BadgeGFX2: INCBIN "gfx/trainer_card/badges.2bpp"
diff --git a/engine/movement_pattern.asm b/engine/movement_pattern.asm
deleted file mode 100755
index 1909f480..00000000
--- a/engine/movement_pattern.asm
+++ /dev/null
@@ -1,651 +0,0 @@
-RestoreDefaultMovement:
- ld hl, $1
- add hl, bc
- ld a, [hl]
- cp $ff
- jr z, .asm_4756
- push bc
- call GetMapObject
- ld hl, $4
- add hl, bc
- ld a, [hl]
- pop bc
- ret
-
-.asm_4756
- ld a, $6
- ret
-
-ClearObjectMovementByteIndex:
- ld hl, $1b
- add hl, bc
- ld [hl], $0
- ret
-
-IncrementObjectMovementByteIndex:
- ld hl, $1b
- add hl, bc
- inc [hl]
- ret
-
-DecrementObjectMovementByteIndex:
- ld hl, $1b
- add hl, bc
- dec [hl]
- ret
-
-MovementAnonymousJumptable:
- ld hl, $1b
- add hl, bc
- ld a, [hl]
- pop hl
- rst JumpTable
- ret
-
-ClearObjectStructField28:
- ld hl, $1c
- add hl, bc
- ld [hl], $0
- ret
-
-IncrementObjectStructField28:
- ld hl, $1c
- add hl, bc
- inc [hl]
- ret
-
-Object28AnonymousJumptable:
- ld hl, $1c
- add hl, bc
- ld a, [hl]
- pop hl
- rst JumpTable
- ret
-
-GetValueObjectStructField28:
- ld hl, $1c
- add hl, bc
- ld a, [hl]
- ret
-
-SetValueObjectStructField28:
- ld hl, $1c
- add hl, bc
- ld [hl], a
- ret
-
-ObjectMovementReset: ; 4795 (1:4795)
- ld hl, $10
- add hl, bc
- ld d, [hl]
- ld hl, $11
- add hl, bc
- ld e, [hl]
- push bc
- call GetCoordTile
- pop bc
- ld hl, $e
- add hl, bc
- ld [hl], a
- call CopyNextCoordsTileToStandingCoordsTile
- call EndSpriteMovement
- ld hl, $9
- add hl, bc
- ld [hl], $1
- ret
-
-MapObjectMovementPattern: ; 47b6 (1:47b6)
- call ClearObjectStructField28
- call GetSpriteMovementFunction
- ld a, [hl]
- ld hl, .Pointers
- rst JumpTable
- ret
-
-.Pointers:
- dw Function47fa
- dw Function47fb
- dw Function4805
- dw Function4811
- dw Function481b
- dw Function482a
- dw Function4842
- dw Function4855
- dw Function485b
- dw Function4861
- dw Function4867
- dw Function486a
- dw Function486d
- dw Function4870
- dw Function4876
- dw Function4879
- dw Function487f
- dw Function4885
- dw Function48d8
- dw Function49be
- dw Function49fa
- dw Function4931
- dw Function4947
- dw Function4a95
- dw Function4966
- dw Function495d
- dw Function4a1f
- dw Function4a62
-
-Function47fa:
- ret
-
-Function47fb: ; 47fb (1:47fb)
- call Random
- ldh a, [hRandom]
- and $1
- jp Function4ac9
-
-Function4805: ; 4805 (1:4805)
- call Random
- ldh a, [hRandom]
- and $1
- or $2
- jp Function4ac9
-
-Function4811: ; 4811 (1:4811)
- call Random
- ldh a, [hRandom]
- and $3
- jp Function4ac9
-
-Function481b: ; 481b (1:481b)
- call Random
- ldh a, [hRandom]
- and $c
- ld hl, $8
- add hl, bc
- ld [hl], a
- jp Function4af6
-
-Function482a: ; 482a (1:482a)
- ld hl, $8
- add hl, bc
- ld a, [hl]
- and $c
- ld d, a
- call Random
- ldh a, [hRandom]
- and $c
- cp d
- jr nz, .asm_483e
- xor $c
-.asm_483e
- ld [hl], a
- jp Function4aff
-
-Function4842: ; 4842 (1:4842)
- call Function4603
- call EndSpriteMovement
- ld hl, $b
- add hl, bc
- ld [hl], $1
- ld hl, $9
- add hl, bc
- ld [hl], $5
- ret
-
-Function4855: ; 4855 (1:4855)
- ld hl, $4fa8
- jp Function4fe9
-
-Function485b: ; 485b (1:485b)
- ld hl, $4fbd
- jp Function4fe9
-
-Function4861: ; 4861 (1:4861)
- ld hl, $4fce
- jp Function4fe9
-
-Function4867: ; 4867 (1:4867)
- jp Function4fdf
-
-Function486a: ; 486a (1:486a)
- jp Function4fdf
-
-Function486d: ; 486d (1:486d)
- jp Function4fdf
-
-Function4870: ; 4870 (1:4870)
- ld hl, $4fa8
- jp Function4fe9
-
-Function4876: ; 4876 (1:4876)
- jp Function4fdf
-
-Function4879: ; 4879 (1:4879)
- ld hl, $5485
- jp Function4fe9
-
-Function487f: ; 487f (1:487f)
- ld hl, $4fb6
- jp Function4fe9
-
-Function4885: ; 4885 (1:4885)
- call MovementAnonymousJumptable
- dw .asm_488c
- dw .asm_48d1
-
-.asm_488c
- ld hl, $e
- add hl, bc
- ld a, [hl]
- call CheckPitTile
- jr z, .asm_48ce
- ld hl, $5
- add hl, bc
- bit 2, [hl]
- res 2, [hl]
- jr z, .asm_48c7
- ld hl, $20
- add hl, bc
- ld a, [hl]
- and $3
- or $0
- call InitStep
- call CheckNPCMovementPermissions
- jr c, .asm_48c4
- ld de, $1b
- call PlaySFX
- call Function54d7
- call UpdateGrassPriority
- ld hl, $9
- add hl, bc
- ld [hl], $f
- ret
-
-.asm_48c4
- call Function4603
-.asm_48c7
- ld hl, $7
- add hl, bc
- ld [hl], $ff
- ret
-
-.asm_48ce
- call IncrementObjectMovementByteIndex
-.asm_48d1
- ld hl, $7
- add hl, bc
- ld [hl], $ff
- ret
-
-Function48d8: ; 48d8 (1:48d8)
- ld hl, $10
- add hl, bc
- ld d, [hl]
- ld hl, $11
- add hl, bc
- ld e, [hl]
- ld hl, $20
- add hl, bc
- ld a, [hl]
- push bc
- call GetObjectStruct
- ld hl, $7
- add hl, bc
- ld a, [hl]
- cp $ff
- jr z, .asm_4923
- ld hl, $12
- add hl, bc
- ld a, [hl]
- cp d
- jr z, .asm_4906
- jr c, .asm_4902
- ld a, $3
- jr .asm_4916
-
-.asm_4902
- ld a, $2
- jr .asm_4916
-
-.asm_4906
- ld hl, $13
- add hl, bc
- ld a, [hl]
- cp e
- jr z, .asm_4923
- jr c, .asm_4914
- ld a, $0
- jr .asm_4916
-
-.asm_4914
- ld a, $1
-.asm_4916
- ld d, a
- ld hl, $7
- add hl, bc
- ld a, [hl]
- and $c
- or d
- pop bc
- jp Function53b1
-
-.asm_4923
- pop bc
- ld hl, $7
- add hl, bc
- ld [hl], $ff
- ld hl, $b
- add hl, bc
- ld [hl], $1
- ret
-
-Function4931: ; 4931 (1:4931)
- call EndSpriteMovement
- ld hl, $7
- add hl, bc
- ld [hl], $ff
- ld hl, $b
- add hl, bc
- ld [hl], $9
- ld hl, $9
- add hl, bc
- ld [hl], $4
- ret
-
-Function4947: ; 4947 (1:4947)
- call EndSpriteMovement
- ld hl, $7
- add hl, bc
- ld [hl], $ff
- ld hl, $b
- add hl, bc
- ld [hl], $a
- ld hl, $9
- add hl, bc
- ld [hl], $4
- ret
-
-Function495d: ; 495d (1:495d)
- call MovementAnonymousJumptable
- dw Function496f
- dw Function4975
- dw Function4991
-
-Function4966: ; 4966 (1:4966)
- call MovementAnonymousJumptable
- dw Function496f
- dw Function4975
- dw Function499d
-
-Function496f:
- call EndSpriteMovement
- call IncrementObjectMovementByteIndex
-Function4975:
- ld hl, $b
- add hl, bc
- ld [hl], $1
- ld hl, $20
- add hl, bc
- ld a, [hl]
- ld a, $10
- ld hl, $a
- add hl, bc
- ld [hl], a
- ld hl, $9
- add hl, bc
- ld [hl], $3
- call IncrementObjectMovementByteIndex
- ret
-
-Function4991:
- ld de, .data
- call Function49a9
- jr Function495d
-
-.data
- db OW_RIGHT, OW_LEFT, OW_DOWN, OW_UP
-
-Function499d:
- ld de, .data
- call Function49a9
- jr Function4966
-
-.data
- db OW_LEFT, OW_RIGHT, OW_UP, OW_DOWN
-
-Function49a9: ; 49a9 (1:49a9)
- ld hl, $8
- add hl, bc
- ld a, [hl]
- and $c
- rrca
- rrca
- push hl
- ld l, a
- ld h, $0
- add hl, de
- ld a, [hl]
- pop hl
- ld [hl], a
- call DecrementObjectMovementByteIndex
- ret
-
-Function49be: ; 49be (1:49be)
- call Function4a81
- ld hl, $b
- add hl, bc
- ld [hl], $7
- ld hl, $a
- add hl, de
- ld a, [hl]
- inc a
- add a
- add $0
- ld hl, $a
- add hl, bc
- ld [hl], a
- ld hl, $7
- add hl, de
- ld a, [hl]
- and $3
- ld d, $e
- cp $0
- jr z, .asm_49e8
- cp $1
- jr z, .asm_49e8
- ld d, $c
-.asm_49e8
- ld hl, $1a
- add hl, bc
- ld [hl], d
- ld hl, $19
- add hl, bc
- ld [hl], $0
- ld hl, $9
- add hl, bc
- ld [hl], $13
- ret
-
-Function49fa: ; 49fa (1:49fa)
- call EndSpriteMovement
- call Function4a81
- ld hl, $b
- add hl, bc
- ld [hl], $8
- ld hl, $a
- add hl, bc
- ld [hl], $0
- ld hl, $1a
- add hl, bc
- ld [hl], $f0
- ld hl, $19
- add hl, bc
- ld [hl], $0
- ld hl, $9
- add hl, bc
- ld [hl], $13
- ret
-
-Function4a1f: ; 4a1f (1:4a1f)
- call EndSpriteMovement
- call Function4a81
- ld hl, $b
- add hl, bc
- ld [hl], $e
- ld hl, $a
- add hl, de
- ld a, [hl]
- inc a
- add a
- ld hl, $a
- add hl, bc
- ld [hl], a
- ld hl, $7
- add hl, de
- ld a, [hl]
- and $3
- ld e, a
- ld d, $0
- ld hl, .data
- add hl, de
- add hl, de
- ld d, [hl]
- inc hl
- ld e, [hl]
- ld hl, $19
- add hl, bc
- ld [hl], d
- ld hl, $1a
- add hl, bc
- ld [hl], e
- ld hl, $9
- add hl, bc
- ld [hl], $13
- ret
-
-.data
- ; x, y
- db 0, -4
- db 0, 8
- db 6, 2
- db -6, 2
-
-Function4a62: ; 4a62 (1:4a62)
- call EndSpriteMovement
- call Function4a81
- ld hl, $b
- add hl, bc
- ld [hl], $f
- ld hl, $a
- add hl, de
- ld a, [hl]
- add $ff
- ld hl, $a
- add hl, bc
- ld [hl], a
- ld hl, $9
- add hl, bc
- ld [hl], $13
- ret
-
-Function4a81: ; 4a81 (1:4a81)
- ld hl, $20
- add hl, bc
- ld a, [hl]
- push bc
- call GetObjectStruct
- ld d, b
- ld e, c
- pop bc
- ld hl, $1d
- add hl, bc
- ld [hl], e
- inc hl
- ld [hl], d
- ret
-
-Function4a95: ; 4a95 (1:4a95)
- call EndSpriteMovement
- ld hl, $b
- add hl, bc
- ld [hl], $0
- ld hl, $20
- add hl, bc
- ld a, [hl]
- call Function4ab7
- ld hl, $a
- add hl, bc
- ld [hl], e
- ld hl, $1e
- add hl, bc
- ld [hl], a
- ld hl, $9
- add hl, bc
- ld [hl], $15
- ret
-
-Function4ab7: ; 4ab7 (1:4ab7)
- ld d, a
- and $3f
- ld e, a
- ld a, d
- rlca
- rlca
- and $3
- ld d, a
- inc d
- ld a, $1
-.asm_4ac4
- dec d
- ret z
- add a
- jr .asm_4ac4
-
-Function4ac9: ; 4ac9 (1:4ac9)
- call InitStep
- call CheckNPCMovementPermissions
- jr c, .asm_4af0
- call UpdateGrassPriority
- ld hl, $b
- add hl, bc
- ld [hl], $2
- ld hl, wCenteredObject
- ldh a, [hConnectionStripLength]
- cp [hl]
- jr z, .asm_4ae9
- ld hl, $9
- add hl, bc
- ld [hl], $7
- ret
-
-.asm_4ae9
- ld hl, $9
- add hl, bc
- ld [hl], $6
- ret
-
-.asm_4af0
- call EndSpriteMovement
- call Function4603
-Function4af6: ; 4af6 (1:4af6)
- call Random
- ldh a, [hRandom]
- and $7f
- jr asm_4b06
-
-Function4aff: ; 4aff (1:4aff)
- call Random
- ldh a, [hRandomAdd]
- and $1f
-asm_4b06
- ld hl, $a
- add hl, bc
- ld [hl], a
- ld hl, $7
- add hl, bc
- ld [hl], $ff
- ld hl, $b
- add hl, bc
- ld [hl], $1
- ld hl, $9
- add hl, bc
- ld [hl], $3
- ret
diff --git a/engine/movie/gamefreak_presents.asm b/engine/movie/gamefreak_presents.asm
index 7e9519f4..2676c9f6 100644
--- a/engine/movie/gamefreak_presents.asm
+++ b/engine/movie/gamefreak_presents.asm
@@ -41,9 +41,9 @@ Copyright_GFPresents: ; e49a8 (39:49a8)
call GFPresents_PlayFrame
jr nc, .loop
- ; high bits of wJumpTableIndex are recycled for some flags
+ ; high bits of wJumptableIndex are recycled for some flags
; this was set if user canceled by pressing a button
- ld a, [wJumpTableIndex]
+ ld a, [wJumptableIndex]
bit 6, a
jr nz, .canceled
@@ -68,16 +68,16 @@ GFPresents_Init: ; e49f3 (39:49f3)
lb bc, BANK(GFPresentsGFX2), 5
call Request2bpp
- farcall ClearAnimatedObjectBuffer
+ farcall ClearSpriteAnims
- ld hl, wAnimatedObjectDynamicVTileOffsets
+ ld hl, wSpriteAnimDict
ld a, 6
ld [hli], a
ld a, $8d
ld [hl], a
xor a
- ld [wJumpTableIndex], a
+ ld [wJumptableIndex], a
ld [$ce64], a
ld [wIntroSceneTimer], a
ldh [hSCX], a
@@ -102,13 +102,13 @@ GFPresents_PlayFrame: ; e4a37 (39:4a37)
and BUTTONS
jr nz, .pressed_button
- ; high bits of wJumpTableIndex are recycled for some flags
+ ; high bits of wJumptableIndex are recycled for some flags
; this is set when the sequence finished
- ld a, [wJumpTableIndex]
+ ld a, [wJumptableIndex]
bit 7, a
jr nz, .finish
- farcall AnimatedObjects_PlayFrame
+ farcall PlaySpriteAnimations
call GFPresents_HandleFrame
call DelayFrame
@@ -118,12 +118,12 @@ GFPresents_PlayFrame: ; e4a37 (39:4a37)
ret
.pressed_button
- ; high bits of wJumpTableIndex are recycled for some flags
- ld hl, wJumpTableIndex
+ ; high bits of wJumptableIndex are recycled for some flags
+ ld hl, wJumptableIndex
set 6, [hl]
.finish
- callfar ClearAnimatedObjectBuffer
+ callfar ClearSpriteAnims
call ClearTilemap
call ClearSprites
@@ -136,7 +136,7 @@ GFPresents_PlayFrame: ; e4a37 (39:4a37)
GFPresents_HandleFrame: ; e4a6d (39:4a6d)
; Dispatch to the current scene handler
- ld a, [wJumpTableIndex]
+ ld a, [wJumptableIndex]
ld e, a
ld d, 0
ld hl, .scenes
@@ -156,7 +156,7 @@ GFPresents_HandleFrame: ; e4a6d (39:4a6d)
dw GFPresents_SetDoneFlag
GFPresents_NextScene: ; e4a88 (39:4a88)
- ld hl, wJumpTableIndex
+ ld hl, wJumptableIndex
inc [hl]
ret
@@ -257,7 +257,7 @@ GFPresents_PlacePresents: ; e4af4 (39:4af4)
GFPresents_SetDoneFlag: ; e4b0d (39:4b0d)
; Tell GFPresents_PlayFrame and TitleScreenFrame (01:63da) that we're finished.
- ld hl, wJumpTableIndex
+ ld hl, wJumptableIndex
set 7, [hl]
ret
diff --git a/engine/movie/title.asm b/engine/movie/title.asm
new file mode 100644
index 00000000..93345798
--- /dev/null
+++ b/engine/movie/title.asm
@@ -0,0 +1,192 @@
+TitleScreen:
+ call ClearBGPalettes
+ xor a
+ ld [wTimeOfDayPal], a
+ ld de, MUSIC_NONE
+ call PlayMusic
+ call ClearTilemap
+ call DisableLCD
+ call ClearSprites
+ xor a
+ ldh [hBGMapMode], a
+ ldh [hMapAnims], a
+ ldh [hSCY], a
+ ldh [hSCX], a
+
+ ld hl, vTiles0
+ ld bc, $200 tiles
+ xor a
+ call ByteFill
+ farcall ClearSpriteAnims
+
+ ld hl, TitleScreenGFX1
+ ld de, vTiles2
+ ld a, BANK(TitleScreenGFX1)
+ call FarDecompress
+
+ ld hl, TitleScreenGFX2
+ ld de, vTiles1
+ ld a, BANK(TitleScreenGFX2)
+ call FarDecompress
+
+ ld hl, TitleScreenGFX4
+ ld de, vTiles0
+ ld a, BANK(TitleScreenGFX4)
+ call FarDecompress
+
+ ld hl, TitleScreenGFX3
+ ld de, vTiles1 tile $78
+ ld bc, 8 tiles
+ ld a, BANK(TitleScreenGFX3)
+ call FarCopyBytes
+
+ call FillTitleScreenPals
+ call Function63b6
+ ld hl, wSpriteAnimDict
+ xor a
+ ld [hli], a
+ ld [hl], a
+ ld hl, rLCDC
+ set rLCDC_SPRITE_SIZE, [hl]
+ call EnableLCD
+ xor a
+ ld hl, wJumptableIndex
+ ld [hli], a ; wJumptableIndex
+ ld [hli], a ; wIntroSceneFrameCounter
+ ld [hli], a ; wTitleScreenTimer
+ ld [hl], a ; wTitleScreenTimer + 1
+ ld de, $6058
+ ld a, SPRITE_ANIM_INDEX_GS_INTRO_HO_OH
+ call InitSpriteAnimStruct
+ ld hl, wSpriteAnim1
+ ld de, wSpriteAnim10
+ ld bc, NUM_SPRITE_ANIM_STRUCTS
+ call CopyBytes
+ ld hl, wSpriteAnim1
+ ld [hl], $0
+ ld hl, wLYOverrides
+ ld bc, wLYOverridesEnd - wLYOverrides
+ xor a
+ call ByteFill
+
+; Let LCD Stat know we're messing around with SCX
+ ld a, LOW(rSCX)
+ ldh [hLCDCPointer], a
+ ld b, SCGB_GS_TITLE_SCREEN
+ call GetSGBLayout
+ call LoadTitleScreenPals
+ ld de, MUSIC_TITLE
+ call PlayMusic
+ ret
+
+LoadTitleScreenPals:
+ ldh a, [hCGB]
+ and a
+ jr nz, .cgb
+ ldh a, [hSGB]
+ and a
+ jr nz, .sgb
+ ld a, %11011000
+ ldh [rBGP], a
+IF DEF(_GOLD)
+ ld a, %11111111
+ ldh [rOBP0], a
+ ld a, %11111000
+ ldh [rOBP1], a
+ELIF DEF(_SILVER)
+ ld a, %11110000
+ ldh [rOBP0], a
+ ld a, %11110000
+ ldh [rOBP1], a
+ENDC
+ ret
+
+.sgb
+ ld a, %11100100
+ ldh [rBGP], a
+IF DEF(_GOLD)
+ ld a, %11111111
+ ldh [rOBP0], a
+ ld a, %11100100
+ ldh [rOBP1], a
+ELIF DEF(_SILVER)
+ ld a, %11110000
+ ldh [rOBP0], a
+ ld a, %11100000
+ ldh [rOBP1], a
+ENDC
+ ret
+
+.cgb
+ ld a, %11100100
+ call DmgToCgbBGPals
+IF DEF(_SILVER)
+ ld a, %11100000
+ENDC
+ call DmgToCgbObjPal0
+ ret
+
+FillTitleScreenPals:
+ ldh a, [hCGB]
+ and a
+ ret z
+ ld a, 1
+ ldh [rVBK], a
+ hlbgcoord 0, 0
+ ld bc, 18 * BG_MAP_WIDTH
+ xor a
+ call ByteFill
+ ld hl, vBGMap2
+ lb bc, 7, SCREEN_WIDTH
+ ld a, 1
+ call DrawTitleGraphic
+ hlbgcoord 5, 6, vBGMap2
+ lb bc, 1, 10
+ ld a, 3
+ call DrawTitleGraphic
+ hlbgcoord 0, 12, vBGMap2
+ ld bc, 5 * BG_MAP_WIDTH
+ ld a, 4
+ call ByteFill
+ ld a, 0
+ ldh [rVBK], a
+ ret
+
+DrawTitleGraphic:
+.bgrows
+ push bc
+ push hl
+.col
+ ld [hli], a
+ dec c
+ jr nz, .col
+ pop hl
+ ld bc, BG_MAP_WIDTH
+ add hl, bc
+ pop bc
+ dec b
+ jr nz, .bgrows
+ ret
+
+Function63b6:
+ ld hl, GSIntroTilemap
+ debgcoord 0, 0
+.asm_63bc
+ ld a, BANK(GSIntroTilemap)
+ call GetFarByte
+ cp -1
+ jr z, .asm_63ca
+ inc hl
+ ld [de], a
+ inc de
+ jr .asm_63bc
+
+.asm_63ca
+ ldh a, [hCGB]
+ and a
+ ret nz
+ hlbgcoord 0, 11
+ ld bc, BG_MAP_WIDTH
+ ld a, "@"
+ call ByteFill
+ ret
diff --git a/engine/movie/trade_animation.asm b/engine/movie/trade_animation.asm
new file mode 100644
index 00000000..410c3c7c
--- /dev/null
+++ b/engine/movie/trade_animation.asm
@@ -0,0 +1,1389 @@
+TRADEANIM_RIGHT_ARROW EQU "▶" ; $ed
+TRADEANIM_LEFT_ARROW EQU "▼" ; $ee
+
+; TradeAnim_TubeAnimJumptable.Jumptable indexes
+ const_def
+ const TRADEANIMSTATE_0 ; 0
+ const TRADEANIMSTATE_1 ; 1
+ const TRADEANIMSTATE_2 ; 2
+ const TRADEANIMSTATE_3 ; 3
+TRADEANIMJUMPTABLE_LENGTH EQU const_value
+
+TradeAnimation:
+ ld hl, wPlayerTrademonSenderName
+ ld de, wOTTrademonSenderName
+ call LinkTradeAnim_LoadTradePlayerNames
+ ld hl, wPlayerTrademonSpecies
+ ld de, wOTTrademonSpecies
+ call LinkTradeAnim_LoadTradeMonSpecies
+ ld de, .script
+ jr RunTradeAnimScript
+
+.script
+ tradeanim_setup_givemon_scroll
+ tradeanim_show_givemon_data
+ tradeanim_do_givemon_scroll
+ tradeanim_wait_80
+ tradeanim_poof
+ tradeanim_rocking_ball
+ tradeanim_enter_link_tube
+ tradeanim_wait_anim
+ tradeanim_bulge_through_tube
+ tradeanim_wait_anim
+ tradeanim_textbox_scroll
+ tradeanim_give_trademon_sfx
+ tradeanim_tube_to_ot
+ tradeanim_sent_to_ot_text
+ tradeanim_scroll_out_right
+
+ tradeanim_ot_sends_text_1
+ tradeanim_ot_bids_farewell
+ tradeanim_scroll_out_right
+ tradeanim_get_trademon_sfx
+ tradeanim_tube_to_player
+ tradeanim_enter_link_tube
+ tradeanim_drop_ball
+ tradeanim_exit_link_tube
+ tradeanim_wait_anim
+ tradeanim_show_getmon_data
+ tradeanim_poof
+ tradeanim_wait_anim
+ tradeanim_frontpic_scroll
+ tradeanim_wait_80
+ tradeanim_textbox_scroll
+ tradeanim_take_care_of_text
+ tradeanim_scroll_out_right
+ tradeanim_end
+
+TradeAnimationPlayer2:
+ ld hl, wOTTrademonSenderName
+ ld de, wPlayerTrademonSenderName
+ call LinkTradeAnim_LoadTradePlayerNames
+ ld hl, wOTTrademonSpecies
+ ld de, wPlayerTrademonSpecies
+ call LinkTradeAnim_LoadTradeMonSpecies
+ ld de, .script
+ jr RunTradeAnimScript
+
+.script
+ tradeanim_ot_sends_text_2
+ tradeanim_ot_bids_farewell
+ tradeanim_scroll_out_right
+ tradeanim_get_trademon_sfx
+ tradeanim_tube_to_ot
+ tradeanim_enter_link_tube
+ tradeanim_drop_ball
+ tradeanim_exit_link_tube
+ tradeanim_wait_anim
+ tradeanim_show_getmon_data
+ tradeanim_poof
+ tradeanim_wait_anim
+ tradeanim_frontpic_scroll
+ tradeanim_wait_80
+ tradeanim_textbox_scroll
+ tradeanim_take_care_of_text
+ tradeanim_scroll_out_right
+
+ tradeanim_setup_givemon_scroll
+ tradeanim_show_givemon_data
+ tradeanim_do_givemon_scroll
+ tradeanim_wait_80
+ tradeanim_poof
+ tradeanim_rocking_ball
+ tradeanim_enter_link_tube
+ tradeanim_wait_anim
+ tradeanim_bulge_through_tube
+ tradeanim_wait_anim
+ tradeanim_textbox_scroll
+ tradeanim_give_trademon_sfx
+ tradeanim_tube_to_player
+ tradeanim_sent_to_ot_text
+ tradeanim_scroll_out_right
+ tradeanim_end
+
+RunTradeAnimScript:
+ ld hl, wTradeAnimAddress
+ ld [hl], e
+ inc hl
+ ld [hl], d
+ ldh a, [hMapAnims]
+ push af
+ xor a
+ ldh [hMapAnims], a
+ ld hl, wVramState
+ ld a, [hl]
+ push af
+ res 0, [hl]
+ ld hl, wOptions
+ ld a, [hl]
+ push af
+ set NO_TEXT_SCROLL, [hl]
+ call .TradeAnimLayout
+ ld de, MUSIC_EVOLUTION
+ call PlayMusic2
+.anim_loop
+ call DoTradeAnimation
+ jr nc, .anim_loop
+ pop af
+ ld [wOptions], a
+ pop af
+ ld [wVramState], a
+ pop af
+ ldh [hMapAnims], a
+ ret
+
+.TradeAnimLayout:
+ xor a
+ ld [wJumptableIndex], a
+ call ClearBGPalettes
+ call ClearSprites
+ call ClearTilemap
+ call DisableLCD
+ call LoadFontsBattleExtra
+ callfar ClearSpriteAnims
+ ldh a, [hCGB]
+ and a
+ jr z, .NotCGB
+ ld a, $1
+ ldh [rVBK], a
+ ld hl, vTiles0
+ ld bc, sScratch - vTiles0
+ xor a
+ call ByteFill
+ ld a, $0
+ ldh [rVBK], a
+
+.NotCGB:
+ hlbgcoord 0, 0
+ ld bc, sScratch - vBGMap0
+ ld a, " "
+ call ByteFill
+ ld hl, TradeGameBoyLZ
+ ld de, vTiles2 tile $31
+ call Decompress
+ ld hl, TradeArrowRightGFX
+ ld de, vTiles0 tile TRADEANIM_RIGHT_ARROW
+ ld bc, 1 tiles
+ ld a, BANK(TradeArrowRightGFX)
+ call FarCopyBytes
+ ld hl, TradeArrowLeftGFX
+ ld de, vTiles0 tile TRADEANIM_LEFT_ARROW
+ ld bc, 1 tiles
+ ld a, BANK(TradeArrowLeftGFX)
+ call FarCopyBytes
+ xor a
+ ldh [hSCX], a
+ ldh [hSCY], a
+ ld a, $7
+ ldh [hWX], a
+ ld a, $90
+ ldh [hWY], a
+ call EnableLCD
+ call LoadTradeBallAndCableGFX
+ ld a, [wPlayerTrademonSpecies]
+ ld hl, wPlayerTrademonDVs
+ ld de, vTiles0
+ call TradeAnim_GetFrontpic
+ ld a, [wOTTrademonSpecies]
+ ld hl, wOTTrademonDVs
+ ld de, vTiles0 tile $31
+ call TradeAnim_GetFrontpic
+ ld a, [wPlayerTrademonSpecies]
+ ld de, wPlayerTrademonSpeciesName
+ call TradeAnim_GetNickname
+ ld a, [wOTTrademonSpecies]
+ ld de, wOTTrademonSpeciesName
+ call TradeAnim_GetNickname
+ call TradeAnim_NormalPals
+ ret
+
+DoTradeAnimation:
+ ld a, [wJumptableIndex]
+ bit 7, a
+ jr nz, .finished
+ call .DoTradeAnimCommand
+ callfar PlaySpriteAnimations
+ ld hl, wce65
+ inc [hl]
+ call DelayFrame
+ and a
+ ret
+
+.finished
+ call LoadStandardFont
+ scf
+ ret
+
+.DoTradeAnimCommand:
+ ld a, [wJumptableIndex]
+ ld e, a
+ ld d, 0
+ ld hl, .JumpTable
+ add hl, de
+ add hl, de
+ ld a, [hli]
+ ld h, [hl]
+ ld l, a
+ jp hl
+
+.JumpTable:
+; entries correspond to macros/scripts/trade_anims.asm enumeration
+ dw TradeAnim_AdvanceScriptPointer ; 00
+ dw TradeAnim_ShowGivemonData ; 01
+ dw TradeAnim_ShowGetmonData ; 02
+ dw TradeAnim_EnterLinkTube1 ; 03
+ dw TradeAnim_EnterLinkTube2 ; 04
+ dw TradeAnim_ExitLinkTube ; 05
+ dw TradeAnim_TubeToOT1 ; 06
+ dw TradeAnim_TubeToOT2 ; 07
+ dw TradeAnim_TubeToOT3 ; 08
+ dw TradeAnim_TubeToOT4 ; 09
+ dw TradeAnim_TubeToOT5 ; 0a
+ dw TradeAnim_TubeToOT6 ; 0b
+ dw TradeAnim_TubeToOT7 ; 0c
+ dw TradeAnim_TubeToOT8 ; 0d
+ dw TradeAnim_TubeToPlayer1 ; 0e
+ dw TradeAnim_TubeToPlayer2 ; 0f
+ dw TradeAnim_TubeToPlayer3 ; 10
+ dw TradeAnim_TubeToPlayer4 ; 11
+ dw TradeAnim_TubeToPlayer5 ; 12
+ dw TradeAnim_TubeToPlayer6 ; 13
+ dw TradeAnim_TubeToPlayer7 ; 14
+ dw TradeAnim_TubeToPlayer8 ; 15
+ dw TradeAnim_SentToOTText ; 16
+ dw TradeAnim_OTBidsFarewell ; 17
+ dw TradeAnim_TakeCareOfText ; 18
+ dw TradeAnim_OTSendsText1 ; 19
+ dw TradeAnim_OTSendsText2 ; 1a
+ dw TradeAnim_SetupGivemonScroll ; 1b
+ dw TradeAnim_DoGivemonScroll ; 1c
+ dw TradeAnim_FrontpicScrollStart ; 1d
+ dw TradeAnim_TextboxScrollStart ; 1e
+ dw TradeAnim_ScrollOutRight ; 1f
+ dw TradeAnim_ScrollOutRight2 ; 20
+ dw TradeAnim_Wait80 ; 21
+ dw TradeAnim_RockingBall ; 22
+ dw TradeAnim_DropBall ; 23
+ dw TradeAnim_WaitAnim ; 24
+ dw TradeAnim_Poof ; 25
+ dw TradeAnim_BulgeThroughTube ; 26
+ dw TradeAnim_GiveTrademonSFX ; 27
+ dw TradeAnim_GetTrademonSFX ; 28
+ dw TradeAnim_End ; 29
+
+TradeAnim_IncrementJumptableIndex:
+ ld hl, wJumptableIndex
+ inc [hl]
+ ret
+
+TradeAnim_AdvanceScriptPointer:
+ ld hl, wTradeAnimAddress
+ ld e, [hl]
+ inc hl
+ ld d, [hl]
+ ld a, [de]
+ ld [wJumptableIndex], a
+ inc de
+ ld [hl], d
+ dec hl
+ ld [hl], e
+ ret
+
+TradeAnim_End:
+ ld hl, wJumptableIndex
+ set 7, [hl]
+ ret
+
+TradeAnim_TubeToOT1:
+ ld a, TRADEANIM_RIGHT_ARROW
+ call TradeAnim_PlaceTrademonStatsOnTubeAnim
+ ld a, [wLinkTradeSendmonSpecies]
+ ld [wTempIconSpecies], a
+ xor a
+ depixel 5, 11, 4, 0
+ ld b, $0
+ jr TradeAnim_InitTubeAnim
+
+TradeAnim_TubeToPlayer1:
+ ld a, TRADEANIM_LEFT_ARROW
+ call TradeAnim_PlaceTrademonStatsOnTubeAnim
+ ld a, [wLinkTradeGetmonSpecies]
+ ld [wTempIconSpecies], a
+ ld a, TRADEANIMSTATE_2
+ depixel 9, 18, 4, 4
+ ld b, $4
+TradeAnim_InitTubeAnim:
+ push bc
+ push de
+ push bc
+ push de
+
+ push af
+ call DisableLCD
+ callfar ClearSpriteAnims
+ hlbgcoord 20, 3
+ ld bc, 12
+ ld a, $60
+ call ByteFill
+ pop af
+
+ call TradeAnim_TubeAnimJumptable
+
+ xor a
+ ldh [hSCX], a
+ ld a, $7
+ ldh [hWX], a
+ ld a, $70
+ ldh [hWY], a
+ call EnableLCD
+ call LoadTradeBubbleGFX
+
+ pop de
+ ld a, SPRITE_ANIM_INDEX_TRADEMON_ICON
+ call InitSpriteAnimStruct
+
+ ld hl, SPRITEANIMSTRUCT_JUMPTABLE_INDEX
+ add hl, bc
+ pop bc
+ ld [hl], b
+
+ pop de
+ ld a, SPRITE_ANIM_INDEX_TRADEMON_BUBBLE
+ call InitSpriteAnimStruct
+
+ ld hl, SPRITEANIMSTRUCT_JUMPTABLE_INDEX
+ add hl, bc
+ pop bc
+ ld [hl], b
+
+ call WaitBGMap
+ ld b, SCGB_TRADE_TUBE
+ call GetSGBLayout
+ ld a, %11100100 ; 3,2,1,0
+ call DmgToCgbBGPals
+ ld a, %11010000
+ call DmgToCgbObjPal0
+
+ call TradeAnim_IncrementJumptableIndex
+ ld a, 92
+ ld [wFrameCounter], a
+ ret
+
+TradeAnim_TubeToOT2:
+ call TradeAnim_FlashBGPals
+ ldh a, [hSCX]
+ add $2
+ ldh [hSCX], a
+ cp $50
+ ret nz
+ ld a, TRADEANIMSTATE_1
+ call TradeAnim_TubeAnimJumptable
+ call TradeAnim_IncrementJumptableIndex
+ ret
+
+TradeAnim_TubeToOT3:
+ call TradeAnim_FlashBGPals
+ ldh a, [hSCX]
+ add $2
+ ldh [hSCX], a
+ cp $a0
+ ret nz
+ ld a, TRADEANIMSTATE_2
+ call TradeAnim_TubeAnimJumptable
+ call TradeAnim_IncrementJumptableIndex
+ ret
+
+TradeAnim_TubeToOT4:
+ call TradeAnim_FlashBGPals
+ ldh a, [hSCX]
+ add $2
+ ldh [hSCX], a
+ and a
+ ret nz
+ call TradeAnim_IncrementJumptableIndex
+ ret
+
+TradeAnim_TubeToPlayer3:
+ call TradeAnim_FlashBGPals
+ ldh a, [hSCX]
+ sub $2
+ ldh [hSCX], a
+ cp $b0
+ ret nz
+ ld a, TRADEANIMSTATE_1
+ call TradeAnim_TubeAnimJumptable
+ call TradeAnim_IncrementJumptableIndex
+ ret
+
+TradeAnim_TubeToPlayer4:
+ call TradeAnim_FlashBGPals
+ ldh a, [hSCX]
+ sub $2
+ ldh [hSCX], a
+ cp $60
+ ret nz
+ xor a ; TRADEANIMSTATE_0
+ call TradeAnim_TubeAnimJumptable
+ call TradeAnim_IncrementJumptableIndex
+ ret
+
+TradeAnim_TubeToPlayer5:
+ call TradeAnim_FlashBGPals
+ ldh a, [hSCX]
+ sub $2
+ ldh [hSCX], a
+ and a
+ ret nz
+ call TradeAnim_IncrementJumptableIndex
+ ret
+
+TradeAnim_TubeToOT6:
+TradeAnim_TubeToPlayer6:
+ ld a, 128
+ ld [wFrameCounter], a
+ call TradeAnim_IncrementJumptableIndex
+ ret
+
+TradeAnim_TubeToOT8:
+TradeAnim_TubeToPlayer8:
+ call ClearBGPalettes
+ call ClearTilemap
+ call ClearSprites
+ call DisableLCD
+ callfar ClearSpriteAnims
+ hlbgcoord 0, 0
+ ld bc, sScratch - vBGMap0
+ ld a, " "
+ call ByteFill
+ xor a
+ ldh [hSCX], a
+ ld a, $90
+ ldh [hWY], a
+ call EnableLCD
+ call LoadTradeBallAndCableGFX
+ call WaitBGMap
+ call TradeAnim_NormalPals
+ call TradeAnim_AdvanceScriptPointer
+ ret
+
+TradeAnim_TubeToOT5:
+TradeAnim_TubeToOT7:
+TradeAnim_TubeToPlayer2:
+TradeAnim_TubeToPlayer7:
+ call TradeAnim_FlashBGPals
+ ld hl, wFrameCounter
+ ld a, [hl]
+ and a
+ jr z, .done
+ dec [hl]
+ ret
+
+.done
+ call TradeAnim_IncrementJumptableIndex
+ ret
+
+TradeAnim_GiveTrademonSFX:
+ call TradeAnim_AdvanceScriptPointer
+ ld de, SFX_GIVE_TRADEMON
+ call PlaySFX
+ ret
+
+TradeAnim_GetTrademonSFX:
+ call TradeAnim_AdvanceScriptPointer
+ ld de, SFX_GET_TRADEMON
+ call PlaySFX
+ ret
+
+TradeAnim_TubeAnimJumptable:
+ maskbits TRADEANIMJUMPTABLE_LENGTH
+ ld e, a
+ ld d, 0
+ ld hl, .Jumptable
+ add hl, de
+ add hl, de
+ ld a, [hli]
+ ld h, [hl]
+ ld l, a
+ jp hl
+
+.Jumptable:
+; entries correspond to TRADEANIMSTATE_* constants
+ dw .Zero
+ dw .One
+ dw .Two
+ dw .Three
+
+.Zero:
+.Three:
+ call TradeAnim_BlankTilemap
+ hlcoord 9, 3
+ ld [hl], $5b
+ inc hl
+ ld bc, 10
+ ld a, $60
+ call ByteFill
+ hlcoord 3, 2
+ call TradeAnim_CopyTradeGameBoyTilemap
+ ret
+
+.One:
+ call TradeAnim_BlankTilemap
+ hlcoord 0, 3
+ ld bc, SCREEN_WIDTH
+ ld a, $60
+ call ByteFill
+ ret
+
+.Two:
+ call TradeAnim_BlankTilemap
+ hlcoord 0, 3
+ ld bc, $11
+ ld a, $60
+ call ByteFill
+ hlcoord 17, 3
+ ld a, $5d
+ ld [hl], a
+
+ ld a, $61
+ ld de, SCREEN_WIDTH
+ ld c, $3
+.loop
+ add hl, de
+ ld [hl], a
+ dec c
+ jr nz, .loop
+
+ add hl, de
+ ld a, $5f
+ ld [hld], a
+ ld a, $5b
+ ld [hl], a
+ hlcoord 10, 6
+ call TradeAnim_CopyTradeGameBoyTilemap
+ ret
+
+TradeAnim_CopyTradeGameBoyTilemap:
+ ld de, TradeGameBoyTilemap
+ lb bc, 8, 6
+ call TradeAnim_CopyBoxFromDEtoHL
+ ret
+
+TradeAnim_PlaceTrademonStatsOnTubeAnim:
+ push af
+ call ClearBGPalettes
+ call WaitTop
+ ld a, HIGH(vBGMap1)
+ ldh [hBGMapAddress + 1], a
+ call ClearTilemap
+ hlcoord 0, 0
+ ld bc, SCREEN_WIDTH
+ ld a, "─"
+ call ByteFill
+ hlcoord 0, 1
+ ld de, wLinkPlayer1Name
+ call PlaceString
+ ld hl, wLinkPlayer2Name
+ ld de, 0
+.find_name_end_loop
+ ld a, [hli]
+ cp "@"
+ jr z, .done
+ dec de
+ jr .find_name_end_loop
+
+.done
+ hlcoord 0, 4
+ add hl, de
+ ld de, wLinkPlayer2Name
+ call PlaceString
+ hlcoord 7, 2
+ ld bc, 6
+ pop af
+ call ByteFill
+ call WaitBGMap
+ call WaitTop
+ ld a, HIGH(vBGMap0)
+ ldh [hBGMapAddress + 1], a
+ call ClearTilemap
+ ret
+
+TradeAnim_EnterLinkTube1:
+ call ClearTilemap
+ call WaitTop
+ ld a, $a0
+ ldh [hSCX], a
+ call DelayFrame
+ hlcoord 8, 2
+ ld de, TradeLinkTubeTilemap
+ lb bc, 3, 12
+ call TradeAnim_CopyBoxFromDEtoHL
+ call WaitBGMap
+ ld b, SCGB_TRADE_TUBE
+ call GetSGBLayout
+ ld a, %11100100 ; 3,2,1,0
+ call DmgToCgbBGPals
+ lb de, %11100100, %11100100 ; 3,2,1,0, 3,2,1,0
+ call DmgToCgbObjPals
+ ld de, SFX_POTION
+ call PlaySFX
+ call TradeAnim_IncrementJumptableIndex
+ ret
+
+TradeAnim_EnterLinkTube2:
+ ldh a, [hSCX]
+ and a
+ jr z, .done
+ add $4
+ ldh [hSCX], a
+ ret
+
+.done
+ ld c, 80
+ call DelayFrames
+ call TradeAnim_AdvanceScriptPointer
+ ret
+
+TradeAnim_ExitLinkTube:
+ ldh a, [hSCX]
+ cp $a0
+ jr z, .done
+ sub $4
+ ldh [hSCX], a
+ ret
+
+.done
+ call ClearTilemap
+ xor a
+ ldh [hSCX], a
+ call TradeAnim_AdvanceScriptPointer
+ ret
+
+TradeAnim_SetupGivemonScroll:
+ ld a, $8f
+ ldh [hWX], a
+ ld a, $88
+ ldh [hSCX], a
+ ld a, $50
+ ldh [hWY], a
+ call TradeAnim_AdvanceScriptPointer
+ ret
+
+TradeAnim_DoGivemonScroll:
+ ldh a, [hWX]
+ cp $7
+ jr z, .done
+ sub $4
+ ldh [hWX], a
+ ldh a, [hSCX]
+ sub $4
+ ldh [hSCX], a
+ ret
+
+.done
+ ld a, $7
+ ldh [hWX], a
+ xor a
+ ldh [hSCX], a
+ call TradeAnim_AdvanceScriptPointer
+ ret
+
+TradeAnim_FrontpicScrollStart:
+ ld a, $7
+ ldh [hWX], a
+ ld a, $50
+ ldh [hWY], a
+ call TradeAnim_AdvanceScriptPointer
+ ret
+
+TradeAnim_TextboxScrollStart:
+ ld a, $7
+ ldh [hWX], a
+ ld a, $90
+ ldh [hWY], a
+ call TradeAnim_AdvanceScriptPointer
+ ret
+
+TradeAnim_ScrollOutRight:
+ call WaitTop
+ ld a, HIGH(vBGMap1)
+ ldh [hBGMapAddress + 1], a
+ call WaitBGMap
+ ld a, $7
+ ldh [hWX], a
+ xor a
+ ldh [hWY], a
+ call DelayFrame
+ call WaitTop
+ ld a, HIGH(vBGMap0)
+ ldh [hBGMapAddress + 1], a
+ call ClearTilemap
+ call TradeAnim_IncrementJumptableIndex
+ ret
+
+TradeAnim_ScrollOutRight2:
+ ldh a, [hWX]
+ cp $a1
+ jr nc, .done
+ inc a
+ inc a
+ ldh [hWX], a
+ ret
+
+.done
+ ld a, HIGH(vBGMap1)
+ ldh [hBGMapAddress + 1], a
+ call WaitBGMap
+ ld a, $7
+ ldh [hWX], a
+ ld a, $90
+ ldh [hWY], a
+ ld a, HIGH(vBGMap0)
+ ldh [hBGMapAddress + 1], a
+ call TradeAnim_AdvanceScriptPointer
+ ret
+
+TradeAnim_ShowGivemonData:
+ call ShowPlayerTrademonStats
+ ld a, [wPlayerTrademonSpecies]
+ ld [wCurPartySpecies], a
+ ld a, [wPlayerTrademonDVs]
+ ld [wTempMonDVs], a
+ ld a, [wPlayerTrademonDVs + 1]
+ ld [wTempMonDVs + 1], a
+ ld b, SCGB_PLAYER_OR_MON_FRONTPIC_PALS
+ call GetSGBLayout
+ ld a, %11100100 ; 3,2,1,0
+ call DmgToCgbBGPals
+ call TradeAnim_ShowGivemonFrontpic
+
+ ld a, [wPlayerTrademonSpecies]
+ call GetCryIndex
+ jr c, .skip_cry
+ ld e, c
+ ld d, b
+ call PlayCry
+.skip_cry
+
+ call TradeAnim_AdvanceScriptPointer
+ ret
+
+TradeAnim_ShowGetmonData:
+ call ShowOTTrademonStats
+ ld a, [wOTTrademonSpecies]
+ ld [wCurPartySpecies], a
+ ld a, [wOTTrademonDVs]
+ ld [wTempMonDVs], a
+ ld a, [wOTTrademonDVs + 1]
+ ld [wTempMonDVs + 1], a
+ ld b, SCGB_PLAYER_OR_MON_FRONTPIC_PALS
+ call GetSGBLayout
+ ld a, %11100100 ; 3,2,1,0
+ call DmgToCgbBGPals
+ call TradeAnim_ShowGetmonFrontpic
+
+ ld a, [wOTTrademonSpecies]
+ call GetCryIndex
+ jr c, .skip_cry
+ ld e, c
+ ld d, b
+ call PlayCry
+.skip_cry
+
+ call TradeAnim_AdvanceScriptPointer
+ ret
+
+TradeAnim_GetFrontpic:
+ push de
+ push af
+ predef GetUnownLetter
+ pop af
+ ld [wCurPartySpecies], a
+ ld [wCurSpecies], a
+ call GetBaseData
+ pop de
+ predef GetMonFrontpic
+ ret
+
+TradeAnim_GetNickname:
+ push de
+ ld [wNamedObjectIndexBuffer], a
+ call GetPokemonName
+ ld hl, wStringBuffer1
+ pop de
+ ld bc, NAME_LENGTH
+ call CopyBytes
+ ret
+
+TradeAnim_ShowGivemonFrontpic:
+ ld de, vTiles0
+ jr TradeAnim_ShowFrontpic
+
+TradeAnim_ShowGetmonFrontpic:
+ ld de, vTiles0 tile $31
+TradeAnim_ShowFrontpic:
+ call DelayFrame
+ ld hl, vTiles2
+ lb bc, 10, $31
+ call Request2bpp
+ call WaitTop
+ call TradeAnim_BlankTilemap
+ hlcoord 7, 2
+ xor a
+ ldh [hGraphicStartTile], a
+ lb bc, 7, 7
+ predef PlaceGraphic
+ call WaitBGMap
+ ret
+
+TradeAnim_Wait80:
+ ld c, 80
+ call DelayFrames
+ call TradeAnim_AdvanceScriptPointer
+ ret
+
+ShowPlayerTrademonStats:
+ ld de, wPlayerTrademonSpecies
+ ld a, [de]
+ cp EGG
+ jr z, TrademonStats_Egg
+ call TrademonStats_MonTemplate
+ ld de, wPlayerTrademonSpecies
+ call TrademonStats_PrintSpeciesNumber
+ ld de, wPlayerTrademonSpeciesName
+ call TrademonStats_PrintSpeciesName
+ ld de, wPlayerTrademonOTName
+ call TrademonStats_PrintOTName
+ ld de, wPlayerTrademonID
+ call TrademonStats_PrintTrademonID
+ call TrademonStats_WaitBGMap
+ ret
+
+ShowOTTrademonStats:
+ ld de, wOTTrademonSpecies
+ ld a, [de]
+ cp EGG
+ jr z, TrademonStats_Egg
+ call TrademonStats_MonTemplate
+ ld de, wOTTrademonSpecies
+ call TrademonStats_PrintSpeciesNumber
+ ld de, wOTTrademonSpeciesName
+ call TrademonStats_PrintSpeciesName
+ ld de, wOTTrademonOTName
+ call TrademonStats_PrintOTName
+ ld de, wOTTrademonID
+ call TrademonStats_PrintTrademonID
+ call TrademonStats_WaitBGMap
+ ret
+
+TrademonStats_MonTemplate:
+ call WaitTop
+ call TradeAnim_BlankTilemap
+ ld a, HIGH(vBGMap1)
+ ldh [hBGMapAddress + 1], a
+ hlcoord 3, 0
+ ld b, $6
+ ld c, $d
+ call Textbox
+ hlcoord 4, 0
+ ld de, .OTMonData
+ call PlaceString
+ ret
+
+.OTMonData:
+ db "─── №."
+ next ""
+ next "OT/"
+ next "<ID>№.@"
+
+TrademonStats_Egg:
+ call WaitTop
+ call TradeAnim_BlankTilemap
+ ld a, HIGH(vBGMap1)
+ ldh [hBGMapAddress + 1], a
+ hlcoord 3, 0
+ ld b, 6
+ ld c, 13
+ call Textbox
+ hlcoord 4, 2
+ ld de, .EggData
+ call PlaceString
+ call TrademonStats_WaitBGMap
+ ret
+
+.EggData:
+ db "EGG"
+ next "OT/?????"
+ next "<ID>№.?????@"
+
+TrademonStats_WaitBGMap:
+ call WaitBGMap
+ call WaitTop
+ ld a, HIGH(vBGMap0)
+ ldh [hBGMapAddress + 1], a
+ ret
+
+TrademonStats_PrintSpeciesNumber:
+ hlcoord 10, 0
+ lb bc, PRINTNUM_LEADINGZEROS | 1, 3
+ call PrintNum
+ ret
+
+TrademonStats_PrintSpeciesName:
+ hlcoord 4, 2
+ call PlaceString
+ ret
+
+TrademonStats_PrintOTName:
+ hlcoord 7, 4
+ call PlaceString
+ ret
+
+TrademonStats_PrintTrademonID:
+ hlcoord 7, 6
+ lb bc, PRINTNUM_LEADINGZEROS | 2, 5
+ call PrintNum
+ ret
+
+TradeAnim_RockingBall:
+ depixel 10, 11, 4, 0
+ ld a, SPRITE_ANIM_INDEX_TRADE_POKE_BALL
+ call InitSpriteAnimStruct
+ call TradeAnim_AdvanceScriptPointer
+ ld a, 64
+ ld [wFrameCounter], a
+ ret
+
+TradeAnim_DropBall:
+ depixel 10, 11, 4, 0
+ ld a, SPRITE_ANIM_INDEX_TRADE_POKE_BALL
+ call InitSpriteAnimStruct
+ ld hl, SPRITEANIMSTRUCT_JUMPTABLE_INDEX
+ add hl, bc
+ ld [hl], $1
+ ld hl, SPRITEANIMSTRUCT_YOFFSET
+ add hl, bc
+ ld [hl], $dc
+ call TradeAnim_AdvanceScriptPointer
+ ld a, 56
+ ld [wFrameCounter], a
+ ret
+
+TradeAnim_Poof:
+ depixel 10, 11, 4, 0
+ ld a, SPRITE_ANIM_INDEX_TRADE_POOF
+ call InitSpriteAnimStruct
+ call TradeAnim_AdvanceScriptPointer
+ ld a, 16
+ ld [wFrameCounter], a
+ ld de, SFX_BALL_POOF
+ call PlaySFX
+ ret
+
+TradeAnim_BulgeThroughTube:
+ ld a, %11100100 ; 3,2,1,0
+ call DmgToCgbObjPal0
+ depixel 5, 11
+ ld a, SPRITE_ANIM_INDEX_TRADE_TUBE_BULGE
+ call InitSpriteAnimStruct
+ call TradeAnim_AdvanceScriptPointer
+ ld a, 128
+ ld [wFrameCounter], a
+ ret
+
+TradeAnim_AnimateTrademonInTube:
+ ld hl, SPRITEANIMSTRUCT_JUMPTABLE_INDEX
+ add hl, bc
+ ld e, [hl]
+ ld d, 0
+ ld hl, .Jumptable
+ add hl, de
+ add hl, de
+ ld a, [hli]
+ ld h, [hl]
+ ld l, a
+ jp hl
+
+.Jumptable:
+ dw .InitTimer
+ dw .WaitTimer1
+ dw .MoveRight
+ dw .MoveDown
+ dw .MoveUp
+ dw .MoveLeft
+ dw .WaitTimer2
+
+.JumptableNext:
+ ld hl, SPRITEANIMSTRUCT_JUMPTABLE_INDEX
+ add hl, bc
+ inc [hl]
+ ret
+
+.InitTimer:
+ call .JumptableNext
+ ld hl, SPRITEANIMSTRUCT_0C
+ add hl, bc
+ ld [hl], $80
+ ret
+
+.WaitTimer1:
+ ld hl, SPRITEANIMSTRUCT_0C
+ add hl, bc
+ ld a, [hl]
+ dec [hl]
+ and a
+ ret nz
+ call .JumptableNext
+
+.MoveRight:
+ ld hl, SPRITEANIMSTRUCT_XCOORD
+ add hl, bc
+ ld a, [hl]
+ cp $94
+ jr nc, .done_move_right
+ inc [hl]
+ ret
+
+.done_move_right
+ call .JumptableNext
+
+.MoveDown:
+ ld hl, SPRITEANIMSTRUCT_YCOORD
+ add hl, bc
+ ld a, [hl]
+ cp $4c
+ jr nc, .done_move_down
+ inc [hl]
+ ret
+
+.done_move_down
+ ld hl, SPRITEANIMSTRUCT_INDEX
+ add hl, bc
+ ld [hl], $0
+ ret
+
+.MoveUp:
+ ld hl, SPRITEANIMSTRUCT_YCOORD
+ add hl, bc
+ ld a, [hl]
+ cp $2c
+ jr z, .done_move_up
+ dec [hl]
+ ret
+
+.done_move_up
+ call .JumptableNext
+
+.MoveLeft:
+ ld hl, SPRITEANIMSTRUCT_XCOORD
+ add hl, bc
+ ld a, [hl]
+ cp $58
+ jr z, .done_move_left
+ dec [hl]
+ ret
+
+.done_move_left
+ call .JumptableNext
+ ld hl, SPRITEANIMSTRUCT_0C
+ add hl, bc
+ ld [hl], $80
+ ret
+
+.WaitTimer2:
+ ld hl, SPRITEANIMSTRUCT_0C
+ add hl, bc
+ ld a, [hl]
+ dec [hl]
+ and a
+ ret nz
+ ld hl, SPRITEANIMSTRUCT_INDEX
+ add hl, bc
+ ld [hl], $0
+ ret
+
+TradeAnim_SentToOTText:
+ ld a, [wLinkMode]
+ cp LINK_TIMECAPSULE
+ jr z, .time_capsule
+ ld hl, .MonNameSentToText
+ call PrintText
+ ld c, 189
+ call DelayFrames
+ ld hl, .MonWasSentToText
+ call PrintText
+ call TradeAnim_Wait80Frames
+ ld c, 128
+ call DelayFrames
+ call TradeAnim_AdvanceScriptPointer
+ ret
+
+.time_capsule
+ ld hl, .MonWasSentToText
+ call PrintText
+ call TradeAnim_Wait80Frames
+ call TradeAnim_AdvanceScriptPointer
+ ret
+
+.MonWasSentToText:
+ text_far _MonWasSentToText
+ text_end
+
+.MonNameSentToText:
+ text_far _MonNameSentToText
+ text_end
+
+TradeAnim_OTBidsFarewell:
+ ld hl, .BidsFarewellToMonText
+ call PrintText
+ call TradeAnim_Wait80Frames
+ ld hl, .MonNameBidsFarewellText
+ call PrintText
+ call TradeAnim_Wait80Frames
+ call TradeAnim_AdvanceScriptPointer
+ ret
+
+.BidsFarewellToMonText:
+ text_far _BidsFarewellToMonText
+ text_end
+
+.MonNameBidsFarewellText:
+ text_far _MonNameBidsFarewellText
+ text_end
+
+TradeAnim_TakeCareOfText:
+ call WaitTop
+ hlcoord 0, 10
+ ld bc, 8 * SCREEN_WIDTH
+ ld a, " "
+ call ByteFill
+ call WaitBGMap
+ ld hl, .TakeGoodCareOfMonText
+ call PrintText
+ call TradeAnim_Wait80Frames
+ call TradeAnim_AdvanceScriptPointer
+ ret
+
+.TakeGoodCareOfMonText:
+ text_far _TakeGoodCareOfMonText
+ text_end
+
+TradeAnim_OTSendsText1:
+ ld hl, .ForYourMonSendsText
+ call PrintText
+ call TradeAnim_Wait80Frames
+ ld hl, .OTSendsText
+ call PrintText
+ call TradeAnim_Wait80Frames
+ ld c, 14
+ call DelayFrames
+ call TradeAnim_AdvanceScriptPointer
+ ret
+
+.ForYourMonSendsText:
+ text_far _ForYourMonSendsText
+ text_end
+
+.OTSendsText:
+ text_far _OTSendsText
+ text_end
+
+TradeAnim_OTSendsText2:
+ ld hl, .WillTradeText
+ call PrintText
+ call TradeAnim_Wait80Frames
+ ld hl, .ForYourMonWillTradeText
+ call PrintText
+ call TradeAnim_Wait80Frames
+ ld c, 14
+ call DelayFrames
+ call TradeAnim_AdvanceScriptPointer
+ ret
+
+.WillTradeText:
+ text_far _WillTradeText
+ text_end
+
+.ForYourMonWillTradeText:
+ text_far _ForYourMonWillTradeText
+ text_end
+
+TradeAnim_Wait80Frames:
+ ld c, 80
+ call DelayFrames
+ ret
+
+TradeAnim_BlankTilemap:
+ hlcoord 0, 0
+ ld bc, SCREEN_WIDTH * SCREEN_HEIGHT
+ ld a, " "
+ call ByteFill
+ ret
+
+TradeAnim_CopyBoxFromDEtoHL:
+.row
+ push bc
+ push hl
+.col
+ ld a, [de]
+ inc de
+ ld [hli], a
+ dec c
+ jr nz, .col
+ pop hl
+ ld bc, SCREEN_WIDTH
+ add hl, bc
+ pop bc
+ dec b
+ jr nz, .row
+ ret
+
+TradeAnim_NormalPals:
+ ldh a, [hSGB]
+ and a
+ ld a, %11100100 ; 3,2,1,0
+ jr z, .not_sgb
+ ld a, $f0
+
+.not_sgb
+ call DmgToCgbObjPal0
+ ld a, %11100100 ; 3,2,1,0
+ call DmgToCgbBGPals
+ ret
+
+LinkTradeAnim_LoadTradePlayerNames:
+ push de
+ ld de, wLinkPlayer1Name
+ ld bc, NAME_LENGTH
+ call CopyBytes
+ pop hl
+ ld de, wLinkPlayer2Name
+ ld bc, NAME_LENGTH
+ call CopyBytes
+ ret
+
+LinkTradeAnim_LoadTradeMonSpecies:
+ ld a, [hl]
+ ld [wLinkTradeSendmonSpecies], a
+ ld a, [de]
+ ld [wLinkTradeGetmonSpecies], a
+ ret
+
+TradeAnim_FlashBGPals:
+ ld a, [wce65]
+ and $7
+ ret nz
+ ldh a, [rBGP]
+ xor %00111100
+ call DmgToCgbBGPals
+ ret
+
+LoadTradeBallAndCableGFX:
+ call DelayFrame
+ ld de, TradeBallGFX
+ ld hl, vTiles0 tile $62
+ lb bc, BANK(TradeBallGFX), 6
+ call Request2bpp
+ ld de, TradePoofGFX
+ ld hl, vTiles0 tile $68
+ lb bc, BANK(TradePoofGFX), 12
+ call Request2bpp
+ ld de, TradeCableGFX
+ ld hl, vTiles0 tile $74
+ lb bc, BANK(TradeCableGFX), 4
+ call Request2bpp
+ xor a
+ ld hl, wSpriteAnimDict
+ ld [hli], a
+ ld [hl], $62
+ ret
+
+LoadTradeBubbleGFX:
+ call DelayFrame
+ ld e, MONICON_TRADE
+ callfar LoadMenuMonIcon
+ ld de, TradeBubbleGFX
+ ld hl, vTiles0 tile $72
+ lb bc, BANK(TradeBubbleGFX), 4
+ call Request2bpp
+ xor a
+ ld hl, wSpriteAnimDict
+ ld [hli], a
+ ld [hl], $62
+ ret
+
+TradeAnim_WaitAnim:
+ ld hl, wFrameCounter
+ ld a, [hl]
+ and a
+ jr z, .done
+ dec [hl]
+ ret
+
+.done
+ call TradeAnim_AdvanceScriptPointer
+ ret
+
+Unreferenced_DebugTrade:
+; This function is not referenced.
+; It was meant for use in Japanese versions, so the
+; constant used for copy length was changed by accident.
+
+ ld hl, .DebugTradeData
+
+ ld a, [hli]
+ ld [wPlayerTrademonSpecies], a
+ ld de, wPlayerTrademonSenderName
+ ld c, NAME_LENGTH + 2 ; JP: NAME_LENGTH_JAPANESE + 2
+.loop1
+ ld a, [hli]
+ ld [de], a
+ inc de
+ dec c
+ jr nz, .loop1
+
+ ld a, [hli]
+ ld [wOTTrademonSpecies], a
+ ld de, wOTTrademonSenderName
+ ld c, NAME_LENGTH + 2 ; JP: NAME_LENGTH_JAPANESE + 2
+.loop2
+ ld a, [hli]
+ ld [de], a
+ inc de
+ dec c
+ jr nz, .loop2
+ ret
+
+debugtrade: MACRO
+; species, ot name, ot id (?)
+ db \1, \2
+ dw \3
+ENDM
+
+.DebugTradeData:
+ debugtrade VENUSAUR, "ゲーフり@@", $0123 ; GAME FREAK
+ debugtrade CHARIZARD, "クりーチャ@", $0456 ; Creatures Inc.
+
+TradeGameBoyTilemap:
+; 6x8
+ db $31, $32, $32, $32, $32, $33
+ db $34, $35, $36, $36, $37, $38
+ db $34, $39, $3a, $3a, $3b, $38
+ db $3c, $3d, $3e, $3e, $3f, $40
+ db $41, $42, $43, $43, $44, $45
+ db $46, $47, $43, $48, $49, $4a
+ db $41, $43, $4b, $4c, $4d, $4e
+ db $4f, $50, $50, $50, $51, $52
+
+TradeLinkTubeTilemap:
+; 12x3
+ db $43, $55, $56, $53, $53, $53, $53, $53, $53, $53, $53, $53
+ db $43, $57, $58, $54, $54, $54, $54, $54, $54, $54, $54, $54
+ db $43, $59, $5a, $43, $43, $43, $43, $43, $43, $43, $43, $43
+
+TradeArrowRightGFX: INCBIN "gfx/trade/arrow_right.2bpp"
+TradeArrowLeftGFX: INCBIN "gfx/trade/arrow_left.2bpp"
+TradeCableGFX: INCBIN "gfx/trade/cable.2bpp"
+TradeBubbleGFX: INCBIN "gfx/trade/bubble.2bpp"
+TradeGameBoyLZ: INCBIN "gfx/trade/game_boy.2bpp.lz"
+TradeBallGFX: INCBIN "gfx/trade/ball.2bpp"
+TradePoofGFX: INCBIN "gfx/trade/poof.2bpp"
diff --git a/engine/namingscreen.asm b/engine/namingscreen.asm
deleted file mode 100644
index f907c463..00000000
--- a/engine/namingscreen.asm
+++ /dev/null
@@ -1,1391 +0,0 @@
-NamingScreen_: ; 11aa3 (4:5aa3)
- call DisableSpriteUpdates
- call NamingScreen
- call ReturnToMapWithSpeechTextbox
- ret
-
-NamingScreen: ; 11aad (4:5aad)
- ld hl, wNamingScreenDestinationPointer
- ld [hl], e
- inc hl
- ld [hl], d
- ld hl, wNamingScreenType
- ld [hl], b
- ld hl, wOptions
- ld a, [hl]
- push af
- set NO_TEXT_SCROLL, [hl]
- ldh a, [hMapAnims]
- push af
- xor a
- ldh [hMapAnims], a
- ldh a, [hInMenu]
- push af
- ld a, $1
- ldh [hInMenu], a
- call Function11ae4
- call DelayFrame
-.asm_11ad1
- call Function11cd4
- jr nc, .asm_11ad1
- pop af
- ldh [hInMenu], a
- pop af
- ldh [hMapAnims], a
- pop af
- ld [wOptions], a
- call ClearJoypad
- ret
-
-Function11ae4: ; 11ae4 (4:5ae4)
- call ClearBGPalettes
- ld b, $8
- call GetSGBLayout
- call DisableLCD
- call Function1201e
- call Function11c67
- ld a, $e3
- ldh [rLCDC], a
- call Function11b09
- call WaitBGMap
- call WaitTop
- call SetPalettes
- call Function11fad
- ret
-
-Function11b09: ; 11b09 (4:5b09)
- ld a, [wNamingScreenType]
- and $7
- ld e, a
- ld d, $0
- ld hl, .Jumptable
- add hl, de
- add hl, de
- ld a, [hli]
- ld h, [hl]
- ld l, a
- jp hl
-
-.Jumptable
- dw Function11b2a
- dw Function11b79
- dw Function11b97
- dw Function11bb8
- dw Function11bda
- dw Function11b2a
- dw Function11b2a
- dw Function11b2a
-
-Function11b2a:
- ld a, [wCurPartySpecies]
- ld [wd151], a
- ld hl, LoadMenuMonIcon
- ld a, BANK(LoadMenuMonIcon)
- ld e, $1
- rst FarCall
- ld a, [wCurPartySpecies]
- ld [wd151], a
- call GetPokemonName
- hlcoord 5, 2
- call PlaceString
- ld l, c
- ld h, b
- ld de, .Strings
- call PlaceString
- inc de
- hlcoord 5, 4
- call PlaceString
- farcall GetGender
- jr c, .asm_11b68
- ld a, "♂"
- jr nz, .place_gender
- ld a, "♀"
-.place_gender
- hlcoord 1, 2
- ld [hl], a
-.asm_11b68
- call Function11c3a
- ret
-
-.Strings:
- db "'S@"
- db "NICKNAME?@"
-
-Function11b79:
- ld de, PlayerSpriteGFX ; $4000
- call Function11c11
- hlcoord 5, 2
- ld de, .String
- call PlaceString
- call Function11c41
- ret
-
-.String:
- db "YOUR NAME?@"
-
-Function11b97:
- ld de, SilverSpriteGFX ; $43c0
- call Function11c11
- hlcoord 5, 2
- ld de, .String
- call PlaceString
- call Function11c41
- ret
-
-.String:
- db "RIVAL'S NAME?@"
-
-Function11bb8:
- ld de, MomSpriteGFX ; $4fc0
- call Function11c11
- hlcoord 5, 2
- ld de, .String
- call PlaceString
- call Function11c41
- ret
-
-.String:
- db "MOTHER'S NAME?@"
-
-Function11bda:
- ld de, $7380
- ld hl, $8000
- lb bc, $31, 4
- call Request2bpp
- xor a
- ld hl, wMisc
- ld [hli], a
- ld [hl], a
- lb de, $24, $20
- ld a, $1c
- call InitSpriteAnimStruct
- ld hl, $1
- add hl, bc
- ld [hl], $0
- hlcoord 5, 2
- ld de, .String
- call PlaceString
- call Function11c48
- ret
-
-.String:
- db "BOX NAME?@"
-
-Function11c11: ; 11c11 (4:5c11)
- push de
- ld hl, $8000
- lb bc, BANK(PlayerSpriteGFX), 4
- call Request2bpp
- pop de
- ld hl, $c0
- add hl, de
- ld e, l
- ld d, h
- ld hl, $8040
- lb bc, BANK(PlayerSpriteGFX), 4
- call Request2bpp
- xor a
- ld hl, wMisc
- ld [hli], a
- ld [hl], a
- lb de, $24, $20
- ld a, $1c
- call InitSpriteAnimStruct
- ret
-
-Function11c3a: ; 11c3a (4:5c3a)
- ld a, $a
- hlcoord 5, 6
- jr asm_11c4f
-
-Function11c41: ; 11c41 (4:5c41)
- ld a, $7
- hlcoord 5, 6
- jr asm_11c4f
-
-Function11c48: ; 11c48 (4:5c48)
- ld a, $8
- hlcoord 5, 4
- jr asm_11c4f
-
-asm_11c4f
- ld [wc5d3], a
- ld a, l
- ld [wc5d8], a
- ld a, h
- ld [wc5d9], a
- ret
-
-Function11c5b: ; 11c5b (4:5c5b)
- push bc
- push af
- ld a, [wNamingScreenType]
- sub $3
- ld b, a
- pop af
- dec b
- pop bc
- ret
-
-Function11c67: ; 11c67 (4:5c67)
- call WaitTop
- hlcoord 0, 0
- ld bc, SCREEN_HEIGHT * SCREEN_WIDTH
- ld a, $60
- call ByteFill
- hlcoord 1, 1
- lb bc, $6, $12
- call Function11c5b
- jr nz, .asm_11c83
- lb bc, $4, $12
-.asm_11c83
- call ClearBox
- ld de, NameInputUpper ; $616f
-Function11c89: ; 11c89 (4:5c89)
- call Function11c5b
- jr nz, .asm_11c94
- ld hl, $55
- add hl, de
- ld d, h
- ld e, l
-.asm_11c94
- push de
- hlcoord 1, 8
- lb bc, $7, $12
- call Function11c5b
- jr nz, .asm_11ca6
- hlcoord 1, 6
- lb bc, $9, $12
-.asm_11ca6
- call ClearBox
- hlcoord 1, 16
- lb bc, $1, $12
- call ClearBox
- pop de
- hlcoord 2, 8
- ld b, $5
- call Function11c5b
- jr nz, .asm_11cc2
- hlcoord 2, 6
- ld b, $6
-.asm_11cc2
- ld c, $11
-.asm_11cc4
- ld a, [de]
- ld [hli], a
- inc de
- dec c
- jr nz, .asm_11cc4
- push de
- ld de, $17
- add hl, de
- pop de
- dec b
- jr nz, .asm_11cc2
- ret
-
-Function11cd4: ; 11cd4 (4:5cd4)
- call JoyTextDelay
- ld a, [wce63]
- bit 7, a
- jr nz, .asm_11cef
- call Function11d27
- farcall AnimatedObjects_PlayFrameAndDelay
- call Function11cff
- call DelayFrame
- and a
- ret
-
-.asm_11cef
- callfar ClearAnimatedObjectBuffer
- call ClearSprites
- xor a
- ldh [hSCX], a
- ldh [hSCY], a
- scf
- ret
-
-Function11cff: ; 11cff (4:5cff)
- xor a
- ldh [hBGMapMode], a
- hlcoord 1, 5
- call Function11c5b
- jr nz, .asm_11d0d
- hlcoord 1, 3
-.asm_11d0d
- ld bc, $112
- call ClearBox
- ld hl, wNamingScreenDestinationPointer
- ld e, [hl]
- inc hl
- ld d, [hl]
- ld hl, wc5d8
- ld a, [hli]
- ld h, [hl]
- ld l, a
- call PlaceString
- ld a, $1
- ldh [hBGMapMode], a
- ret
-
-Function11d27: ; 11d27 (4:5d27)
- ld a, [wce63]
- ld e, a
- ld d, $0
- ld hl, $5d36
- add hl, de
- add hl, de
- ld a, [hli]
- ld h, [hl]
- ld l, a
- jp hl
-
-.Jumptable:
- dw Function11d3a
- dw Function11d60
-
-Function11d3a:
- lb de, $50, $18
- call Function11c5b
- jr nz, .asm_11d44
- ld d, $40
-.asm_11d44
- ld a, $14
- call InitSpriteAnimStruct
- ld a, c
- ld [wc5d5], a
- ld a, b
- ld [wc5d6], a
- ld hl, $1
- add hl, bc
- ld a, [hl]
- ld hl, $e
- add hl, bc
- ld [hl], a
- ld hl, wce63
- inc [hl]
- ret
-
-Function11d60:
- ld hl, hJoyPressed
- ld a, [hl]
- and $1
- jr nz, .asm_11d78
- ld a, [hl]
- and $2
- jr nz, .asm_11da6
- ld a, [hl]
- and $8
- jr nz, .asm_11d8e
- ld a, [hl]
- and $4
- jr nz, .asm_11db3
- ret
-
-.asm_11d78
- call Function11dca
- cp $1
- jr z, .asm_11db3
- cp $2
- jr z, .asm_11da6
- cp $3
- jr z, .asm_11daa
- call Function11fde
- call Function11ed3
- ret nc
-.asm_11d8e
- ld hl, wc5d5
- ld c, [hl]
- inc hl
- ld b, [hl]
- ld hl, $c
- add hl, bc
- ld [hl], $8
- ld hl, $d
- add hl, bc
- ld [hl], $4
- call Function11c5b
- ret nz
- inc [hl]
- ret
-
-.asm_11da6
- call Function11f89
- ret
-
-.asm_11daa
- call Function11fc4
- ld hl, wce63
- set 7, [hl]
- ret
-
-.asm_11db3
- ld hl, wce64
- ld a, [hl]
- xor $1
- ld [hl], a
- jr z, .asm_11dc3
- ld de, $60b4
- call Function11c89
- ret
-
-.asm_11dc3
- ld de, $616f
- call Function11c89
- ret
-
-Function11dca: ; 11dca (4:5dca)
- ld hl, wc5d5
- ld c, [hl]
- inc hl
- ld b, [hl]
-Function11dd0: ; 11dd0 (4:5dd0)
- ld hl, $d
- add hl, bc
- ld a, [hl]
- push bc
- ld b, $4
- call Function11c5b
- jr nz, .asm_11dde
- inc b
-.asm_11dde
- cp b
- pop bc
- jr nz, .asm_11df8
- ld hl, $c
- add hl, bc
- ld a, [hl]
- cp $3
- jr c, .asm_11df2
- cp $6
- jr c, .asm_11df5
- ld a, $3
- ret
-
-.asm_11df2
- ld a, $1
- ret
-
-.asm_11df5
- ld a, $2
- ret
-
-.asm_11df8
- xor a
- ret
-
-Function11dfa:
- call Function11e4a
- ld hl, $d
- add hl, bc
- ld a, [hl]
- ld e, a
- swap e
- ld hl, $7
- add hl, bc
- ld [hl], e
- ld d, $4
- call Function11c5b
- jr nz, .asm_11e12
- inc d
-.asm_11e12
- cp d
- ld de, .LetterEntries
- ld a, $0
- jr nz, .asm_11e1f
- ld de, .CaseDelEnd
- ld a, $1
-.asm_11e1f
- ld hl, $e
- add hl, bc
- add [hl]
- ld hl, $1
- add hl, bc
- ld [hl], a
- ld hl, $c
- add hl, bc
- ld l, [hl]
- ld h, $0
- add hl, de
- ld a, [hl]
- ld hl, $6
- add hl, bc
- ld [hl], a
- ret
-
-.LetterEntries:
- db $00, $10, $20, $30, $40, $50, $60, $70, $80
-
-.CaseDelEnd:
- db $00, $00, $00, $30, $30, $30, $60, $60, $60
-
-Function11e4a: ; 11e4a (4:5e4a)
- ld hl, hJoyLast
- ld a, [hl]
- and $40
- jr nz, .asm_11ec1
- ld a, [hl]
- and $80
- jr nz, .asm_11ea8
- ld a, [hl]
- and $20
- jr nz, .asm_11e84
- ld a, [hl]
- and $10
- jr nz, .asm_11e62
- ret
-
-.asm_11e62
- call Function11dd0
- and a
- jr nz, .asm_11e76
- ld hl, $c
- add hl, bc
-.asm_11e6c
- ld a, [hl]
- cp $8
- jr nc, .asm_11e73
- inc [hl]
- ret
-
-.asm_11e73
- ld [hl], $0
- ret
-
-.asm_11e76
- cp $3
- jr nz, .asm_11e7b
- xor a
-.asm_11e7b
- ld e, a
- add a
- add e
- ld hl, $c
- add hl, bc
- ld [hl], a
- ret
-
-.asm_11e84
- call Function11dd0
- and a
- jr nz, .asm_11e97
- ld hl, $c
- add hl, bc
- ld a, [hl]
- and a
- jr z, .asm_11e94
- dec [hl]
- ret
-
-.asm_11e94
- ld [hl], $8
- ret
-
-.asm_11e97
- cp $1
- jr nz, .asm_11e9d
- ld a, $4
-.asm_11e9d
- dec a
- dec a
- ld e, a
- add a
- add e
- ld hl, $c
- add hl, bc
- ld [hl], a
- ret
-
-.asm_11ea8
- ld hl, $d
- add hl, bc
- ld a, [hl]
- call Function11c5b
- jr nz, .asm_11eb8
- cp $5
- jr nc, .asm_11ebe
- inc [hl]
- ret
-
-.asm_11eb8
- cp $4
- jr nc, .asm_11ebe
- inc [hl]
- ret
-
-.asm_11ebe
- ld [hl], $0
- ret
-
-.asm_11ec1
- ld hl, $d
- add hl, bc
- ld a, [hl]
- and a
- jr z, .asm_11ecb
- dec [hl]
- ret
-
-.asm_11ecb
- ld [hl], $4
- call Function11c5b
- ret nz
- inc [hl]
- ret
-
-Function11ed3: ; 11ed3 (4:5ed3)
- ld a, [wc5d7]
- ld hl, Dakutens
- cp $e5
- jr z, asm_11f06
- ld hl, Handakutens
- cp $e4
- jr z, asm_11f06
-Function11ee4: ; 11ee4 (4:5ee4)
- ld a, [wc5d3]
- ld c, a
- ld a, [wc5d2]
- cp c
- ret nc
- ld a, [wc5d7]
-asm_11ef0
- call Function11f9d
- ld [hl], a
-asm_11ef4
- ld hl, wc5d2
- inc [hl]
- call Function11f9d
- ld a, [hl]
- cp $50
- jr z, .asm_11f04
- ld [hl], $f2
- and a
- ret
-
-.asm_11f04
- scf
- ret
-
-asm_11f06
- ld a, [wc5d2]
- and a
- ret z
- push hl
- ld hl, wc5d2
- dec [hl]
- call Function11f9d
- ld c, [hl]
- pop hl
-.asm_11f15
- ld a, [hli]
- cp $ff
- jr z, asm_11ef4
- cp c
- jr z, .asm_11f20
- inc hl
- jr .asm_11f15
-
-.asm_11f20
- ld a, [hl]
- jr asm_11ef0
-
-Dakutens: ; Dummied out
- db "かが", "きぎ", "くぐ", "けげ", "こご"
- db "さざ", "しじ", "すず", "せぜ", "そぞ"
- db "ただ", "ちぢ", "つづ", "てで", "とど"
- db "はば", "ひび", "ふぶ", "へべ", "ほぼ"
- db "カガ", "キギ", "クグ", "ケゲ", "コゴ"
- db "サザ", "シジ", "スズ", "セゼ", "ソゾ"
- db "タダ", "チヂ", "ツヅ", "テデ", "トド"
- db "ハバ", "ヒビ", "フブ", "へべ", "ホボ"
- db $ff
-
-Handakutens: ; Dummied out
- db "はぱ", "ひぴ", "ふぷ", "へぺ", "ほぽ"
- db "ハパ", "ヒピ", "フプ", "へぺ", "ホポ"
- db $ff
-
-Function11f89: ; 11f89 (4:5f89)
- ld hl, wc5d2
- ld a, [hl]
- and a
- ret z
- dec [hl]
- call Function11f9d
- ld [hl], $f2
- inc hl
- ld a, [hl]
- cp $f2
- ret nz
- ld [hl], $eb
- ret
-
-Function11f9d: ; 11f9d (4:5f9d)
- push af
- ld hl, wNamingScreenDestinationPointer
- ld a, [hli]
- ld h, [hl]
- ld l, a
- ld a, [wc5d2]
- ld e, a
- ld d, $0
- add hl, de
- pop af
- ret
-
-Function11fad: ; 11fad (4:5fad)
- ld hl, wNamingScreenDestinationPointer
- ld a, [hli]
- ld h, [hl]
- ld l, a
- ld [hl], $f2
- inc hl
- ld a, [wc5d3]
- dec a
- ld c, a
- ld a, $eb
-.asm_11fbd
- ld [hli], a
- dec c
- jr nz, .asm_11fbd
- ld [hl], $50
- ret
-
-Function11fc4: ; 11fc4 (4:5fc4)
- ld hl, wNamingScreenDestinationPointer
- ld a, [hli]
- ld h, [hl]
- ld l, a
- ld a, [wc5d3]
- ld c, a
-.asm_11fce
- ld a, [hl]
- cp $eb
- jr z, .asm_11fd7
- cp $f2
- jr nz, .asm_11fd9
-.asm_11fd7
- ld [hl], $50
-.asm_11fd9
- inc hl
- dec c
- jr nz, .asm_11fce
- ret
-
-Function11fde: ; 11fde (4:5fde)
- ld hl, wc5d5
- ld c, [hl]
- inc hl
- ld b, [hl]
- ld hl, $6
- add hl, bc
- ld a, [hl]
- ld hl, $4
- add hl, bc
- add [hl]
- sub $8
- srl a
- srl a
- srl a
- ld e, a
- ld hl, $7
- add hl, bc
- ld a, [hl]
- ld hl, $5
- add hl, bc
- add [hl]
- sub $10
- srl a
- srl a
- srl a
- ld d, a
- hlcoord 0, 0
- ld bc, $14
-.asm_12010
- ld a, d
- and a
- jr z, .asm_12018
- add hl, bc
- dec d
- jr .asm_12010
-
-.asm_12018
- add hl, de
- ld a, [hl]
- ld [wc5d7], a
- ret
-
-Function1201e: ; 1201e (4:601e)
- call ClearSprites
- callfar ClearAnimatedObjectBuffer
- call Functiond9e
- call LoadFontsExtra
- ld de, NamingScreenGFX_MiddleLine ; $6232
- ld hl, $8eb0
- lb bc, BANK(NamingScreenGFX_MiddleLine), 1
- call Get1bpp
- ld de, NamingScreenGFX_UnderLine ; $623a
- ld hl, $8f20
- lb bc, BANK(NamingScreenGFX_UnderLine), 1
- call Get1bpp
- ld de, $9600
- ld hl, NamingScreenGFX_Border
- ld bc, $10
- ld a, BANK(NamingScreenGFX_Border)
- call FarCopyBytes
- ld de, $87e0
- ld hl, NamingScreenGFX_Cursor
- ld bc, $20
- ld a, BANK(NamingScreenGFX_Cursor)
- call FarCopyBytes
- ld a, $5
- ld hl, wAnimatedObjectDynamicVTileOffsets + 9 * 2
- ld [hli], a
- ld [hl], $7e
- xor a
- ldh [hSCY], a
- ld [wGlobalAnimYOffset], a
- ldh [hSCX], a
- ld [wGlobalAnimXOffset], a
- ld [wce63], a
- ld [wce64], a
- ldh [hBGMapMode], a
- ld [wc5d2], a
- ld a, $7
- ldh [hWX], a
- ret
-
-NamingScreenGFX_Border: INCBIN "gfx/namingscreen/border.2bpp"
-NamingScreenGFX_Cursor: INCBIN "gfx/namingscreen/cursor.2bpp"
-
-NameInputLower:
- db "a b c d e f g h i"
- db "j k l m n o p q r"
- db "s t u v w x y z "
- db "× ( ) : ; [ ] <PK> <MN>"
- db "UPPER DEL END "
-
-BoxNameInputLower:
- db "a b c d e f g h i"
- db "j k l m n o p q r"
- db "s t u v w x y z "
- db "é 'd 'l 'm 'r 's 't 'v 0"
- db "1 2 3 4 5 6 7 8 9"
- db "UPPER DEL END "
-
-NameInputUpper:
- db "A B C D E F G H I"
- db "J K L M N O P Q R"
- db "S T U V W X Y Z "
- db "- ? ! / . , "
- db "lower DEL END "
-
-BoxNameInputUpper:
- db "A B C D E F G H I"
- db "J K L M N O P Q R"
- db "S T U V W X Y Z "
- db "× ( ) : ; [ ] <PK> <MN>"
- db "- ? ! ♂ ♀ / . , &"
- db "lower DEL END "
-
-NamingScreenGFX_ED: INCBIN "gfx/namingscreen/ed.1bpp" ; leftover from gen 1
-NamingScreenGFX_MiddleLine: INCBIN "gfx/namingscreen/middleline.1bpp"
-NamingScreenGFX_UnderLine: INCBIN "gfx/namingscreen/underline.1bpp"
-
-ComposeMailMessage:
- ld hl, wNamingScreenDestinationPointer
- ld [hl], e
- inc hl
- ld [hl], d
- ldh a, [hMapAnims]
- push af
- xor a
- ldh [hMapAnims], a
- ldh a, [hInMenu]
- push af
- ld a, $1
- ldh [hInMenu], a
- call Function12267
- call DelayFrame
-.asm_1225b
- call Function1238d
- jr nc, .asm_1225b
- pop af
- ldh [hInMenu], a
- pop af
- ldh [hMapAnims], a
- ret
-
-Function12267: ; 12267 (4:6267)
- call ClearBGPalettes
- call DisableLCD
- call Function1201e
- ld de, $8000
- ld hl, MailIcon ; $62c1
- ld bc, $80
- ld a, BANK(MailIcon)
- call FarCopyBytes
- xor a
- ld hl, wTilemapEnd
- ld [hli], a
- ld [hl], a
- lb de, $18, $10
- ld a, $0
- call InitSpriteAnimStruct
- ld hl, $2
- add hl, bc
- ld [hl], $0
- call Function12351
- ld a, $e3
- ldh [rLCDC], a
- call Function12341
- ld b, $8
- call GetSGBLayout
- call WaitBGMap
- call WaitTop
- ld a, $e4
- call DmgToCgbBGPals
- ld a, $e4
- call DmgToCgbObjPal0
- call Function11fad
- ld hl, wNamingScreenDestinationPointer
- ld e, [hl]
- inc hl
- ld d, [hl]
- ld hl, $10
- add hl, de
- ld [hl], $4e
- ret
-
-MailIcon: INCBIN "gfx/namingscreen/mail_icon.2bpp"
-
-Function12341: ; 12341 (4:6341)
- ld a, $21
- ld [wc5d3], a
- ret
-
- db "メールを かいてね@"
-
-Function12351: ; 12351 (4:6351)
- call WaitTop
- hlcoord 0, 0
- ld bc, $78
- ld a, $60
- call ByteFill
- hlcoord 0, 6
- ld bc, $f0
- ld a, $7f
- call ByteFill
- hlcoord 1, 1
- ld bc, IncGradGBPalTable_13
- call ClearBox
- ld de, MailEntry_Uppercase
-Function12376: ; 12376 (4:6376)
- hlcoord 1, 7
- ld b, $6
-.asm_1237b
- ld c, $13
-.asm_1237d
- ld a, [de]
- ld [hli], a
- inc de
- dec c
- jr nz, .asm_1237d
- push de
- ld de, $15
- add hl, de
- pop de
- dec b
- jr nz, .asm_1237b
- ret
-
-Function1238d: ; 1238d (4:638d)
- call JoyTextDelay
- ld a, [wce63]
- bit 7, a
- jr nz, .asm_123a8
- call Function123d5
- farcall AnimatedObjects_PlayFrameAndDelay
- call Function123b8
- call DelayFrame
- and a
- ret
-
-.asm_123a8
- callfar ClearAnimatedObjectBuffer
- call ClearSprites
- xor a
- ldh [hSCX], a
- ldh [hSCY], a
- scf
- ret
-
-Function123b8: ; 123b8 (4:63b8)
- xor a
- ldh [hBGMapMode], a
- hlcoord 1, 1
- lb bc, 4, 18
- call ClearBox
- ld hl, wNamingScreenDestinationPointer
- ld e, [hl]
- inc hl
- ld d, [hl]
- hlcoord 2, 2
- call PlaceString
- ld a, $1
- ldh [hBGMapMode], a
- ret
-
-Function123d5: ; 123d5 (4:63d5)
- ld a, [wce63]
- ld e, a
- ld d, $0
- ld hl, .Jumptable ; $63e4
- add hl, de
- add hl, de
- ld a, [hli]
- ld h, [hl]
- ld l, a
- jp hl
-
-.Jumptable:
- dw Function123e8
- dw Function12407
-
-Function123e8:
- lb de, $48, $10
- ld a, $1b
- call InitSpriteAnimStruct
- ld a, c
- ld [wc5d5], a
- ld a, b
- ld [wc5d6], a
- ld hl, $1
- add hl, bc
- ld a, [hl]
- ld hl, $e
- add hl, bc
- ld [hl], a
- ld hl, wce63
- inc [hl]
- ret
-
-Function12407:
- ld hl, hJoyPressed
- ld a, [hl]
- and $1
- jr nz, .asm_1241f
- ld a, [hl]
- and $2
- jr nz, .asm_1245a
- ld a, [hl]
- and $8
- jr nz, .asm_12447
- ld a, [hl]
- and $4
- jr nz, .asm_12477
- ret
-
-.asm_1241f
- call Function12552
- cp $1
- jr z, .asm_12477
- cp $2
- jr z, .asm_1245a
- cp $3
- jr z, .asm_1246e
- call Function11fde
- call Function12579
- jr c, .asm_12447
- ld hl, wc5d2
- ld a, [hl]
- cp $10
- ret nz
- inc [hl]
- call Function11f9d
- ld [hl], $f2
- dec hl
- ld [hl], $4e
- ret
-
-.asm_12447
- ld hl, wc5d5
- ld c, [hl]
- inc hl
- ld b, [hl]
- ld hl, $c
- add hl, bc
- ld [hl], $9
- ld hl, $d
- add hl, bc
- ld [hl], $5
- ret
-
-.asm_1245a
- call Function11f89
- ld hl, wc5d2
- ld a, [hl]
- cp $10
- ret nz
- dec [hl]
- call Function11f9d
- ld [hl], $f2
- inc hl
- ld [hl], $4e
- ret
-
-.asm_1246e
- call Function11fc4
- ld hl, wce63
- set 7, [hl]
- ret
-
-.asm_12477
- ld hl, wce64
- ld a, [hl]
- xor $1
- ld [hl], a
- jr nz, .asm_12487
- ld de, MailEntry_Uppercase ; $65b6
- call Function12376
- ret
-
-.asm_12487
- ld de, MailEntry_Lowercase ; $6628
- call Function12376
- ret
-
-Function1248e:
- call Function124d9
- ld hl, $d
- add hl, bc
- ld a, [hl]
- ld e, a
- swap e
- ld hl, $7
- add hl, bc
- ld [hl], e
- cp $5
- ld de, .LetterEntries
- ld a, $0
- jr nz, .asm_124ac
- ld de, .CaseDelEnd
- ld a, $1
-.asm_124ac
- ld hl, $e
- add hl, bc
- add [hl]
- ld hl, $1
- add hl, bc
- ld [hl], a
- ld hl, $c
- add hl, bc
- ld l, [hl]
- ld h, $0
- add hl, de
- ld a, [hl]
- ld hl, $6
- add hl, bc
- ld [hl], a
- ret
-
-.LetterEntries:
- db $00, $10, $20, $30, $40, $50, $60, $70, $80, $90
-
-.CaseDelEnd:
- db $00, $00, $00, $30, $30, $30, $60, $60, $60, $60
-
-Function124d9: ; 124d9 (4:64d9)
- ld hl, hJoyLast
- ld a, [hl]
- and $40
- jr nz, .asm_12545
- ld a, [hl]
- and $80
- jr nz, .asm_12537
- ld a, [hl]
- and $20
- jr nz, .asm_12513
- ld a, [hl]
- and $10
- jr nz, .asm_124f1
- ret
-
-.asm_124f1
- call Function12558
- and a
- jr nz, .asm_12505
- ld hl, $c
-.asm_124f9
- add hl, bc
- ld a, [hl]
- cp $9
- jr nc, .asm_12502
- inc [hl]
- ret
-
-.asm_12502
- ld [hl], $0
-.asm_12504
- ret
-
-.asm_12505
- cp $3
- jr nz, .asm_1250a
- xor a
-.asm_1250a
- ld e, a
- add a
- add e
- ld hl, $c
- add hl, bc
- ld [hl], a
- ret
-
-.asm_12513
- call Function12558
- and a
- jr nz, .asm_12526
- ld hl, $c
- add hl, bc
- ld a, [hl]
- and a
- jr z, .asm_12523
- dec [hl]
- ret
-
-.asm_12523
- ld [hl], $9
- ret
-
-.asm_12526
- cp $1
- jr nz, .asm_1252c
- ld a, $4
-.asm_1252c
- dec a
- dec a
- ld e, a
- add a
- add e
- ld hl, $c
- add hl, bc
- ld [hl], a
-.asm_12536
- ret
-
-.asm_12537
- ld hl, $d
- add hl, bc
- ld a, [hl]
- cp $5
- jr nc, .asm_12542
- inc [hl]
- ret
-
-.asm_12542
- ld [hl], $0
- ret
-
-.asm_12545
- ld hl, $d
- add hl, bc
- ld a, [hl]
- and a
- jr z, .asm_1254f
- dec [hl]
- ret
-
-.asm_1254f
- ld [hl], $5
- ret
-
-Function12552: ; 12552 (4:6552)
- ld hl, wc5d5
- ld c, [hl]
- inc hl
- ld b, [hl]
-Function12558: ; 12558 (4:6558)
- ld hl, $d
- add hl, bc
- ld a, [hl]
- cp $5
- jr nz, .asm_12577
- ld hl, $c
- add hl, bc
- ld a, [hl]
- cp $3
- jr c, .asm_12571
- cp $6
- jr c, .asm_12574
- ld a, $3
- ret
-
-.asm_12571
- ld a, $1
- ret
-
-.asm_12574
- ld a, $2
- ret
-
-.asm_12577
- xor a
- ret
-
-Function12579: ; 12579 (4:6579)
- ld a, [wc5d7]
- ld hl, $5f23
- cp $e5
- jr z, .asm_1258b
- ld hl, $5f74
- cp $e4
- jp nz, Function11ee4
-.asm_1258b
- ld a, [wc5d2]
- and a
- ret z
- cp $11
- jr nz, .asm_1259c
- push hl
- ld hl, wc5d2
- dec [hl]
- dec [hl]
- jr .asm_125a1
-
-.asm_1259c
- push hl
- ld hl, wc5d2
- dec [hl]
-.asm_125a1
- call Function11f9d
- ld c, [hl]
- pop hl
-.asm_125a6
- ld a, [hli]
- cp $ff
- jp z, asm_11ef4
- cp c
- jr z, .asm_125b2
- inc hl
- jr .asm_125a6
-
-.asm_125b2
- ld a, [hl]
- jp asm_11ef0
-
-MailEntry_Uppercase:
- db "A B C D E F G H I J"
- db "K L M N O P Q R S T"
- db "U V W X Y Z , ? !"
- db "1 2 3 4 5 6 7 8 9 0"
- db "<PK> <MN> <PO> <KE> é ♂ ♀ ¥ … ×"
- db "lower DEL END "
-
-MailEntry_Lowercase:
- db "a b c d e f g h i j"
- db "k l m n o p q r s t"
- db "u v w x y z . - /"
- db "'d 'l 'm 'r 's 't 'v & ( )"
- db "<``> <''> [ ] ' : ; "
- db "UPPER DEL END "
diff --git a/engine/overworld/decorations.asm b/engine/overworld/decorations.asm
new file mode 100644
index 00000000..c9889472
--- /dev/null
+++ b/engine/overworld/decorations.asm
@@ -0,0 +1,1168 @@
+InitDecorations:
+ ld a, DECO_FEATHERY_BED
+ ld [wDecoBed], a
+ ld a, DECO_TOWN_MAP
+ ld [wDecoPoster], a
+ ret
+
+_PlayerDecorationMenu:
+ ld a, [wWhichIndexSet]
+ push af
+ ld hl, .MenuHeader
+ call LoadMenuHeader
+ xor a
+ ld [wBuffer5], a
+ ld a, $1
+ ld [wBuffer6], a
+.top_loop
+ ld a, [wBuffer6]
+ ld [wMenuCursorBuffer], a
+ call .FindCategoriesWithOwnedDecos
+ call DoNthMenu
+ ld a, [wMenuCursorY]
+ ld [wBuffer6], a
+ jr c, .exit_menu
+ ld a, [wMenuSelection]
+ ld hl, .pointers
+ call MenuJumptable
+ jr nc, .top_loop
+
+.exit_menu
+ call ExitMenu
+ pop af
+ ld [wWhichIndexSet], a
+ ld a, [wBuffer5]
+ ld c, a
+ ret
+
+.MenuHeader:
+ db MENU_BACKUP_TILES ; flags
+ menu_coords 5, 0, SCREEN_WIDTH - 1, SCREEN_HEIGHT - 1
+ dw .MenuData
+ db 1 ; default option
+
+.MenuData:
+ db STATICMENU_CURSOR | STATICMENU_WRAP ; flags
+ db 0 ; items
+ dw wceed
+ dw PlaceNthMenuStrings
+ dw .pointers
+
+.pointers
+ dw DecoBedMenu, .bed
+ dw DecoCarpetMenu, .carpet
+ dw DecoPlantMenu, .plant
+ dw DecoPosterMenu, .poster
+ dw DecoConsoleMenu, .game
+ dw DecoOrnamentMenu, .ornament
+ dw DecoBigDollMenu, .big_doll
+ dw DecoExitMenu, .exit
+
+.bed db "BED@"
+.carpet db "CARPET@"
+.plant db "PLANT@"
+.poster db "POSTER@"
+.game db "GAME CONSOLE@"
+.ornament db "ORNAMENT@"
+.big_doll db "BIG DOLL@"
+.exit db "EXIT@"
+
+.FindCategoriesWithOwnedDecos:
+ xor a
+ ld [wWhichIndexSet], a
+ call .ClearStringBuffer2
+ call .FindOwndDecos
+ ld a, 7
+ call .AppendToStringBuffer2
+ ld hl, wStringBuffer2
+ ld de, wceed
+ ld bc, ITEM_NAME_LENGTH
+ call CopyBytes
+ ret
+
+.ClearStringBuffer2:
+ ld hl, wStringBuffer2
+ xor a
+ ld [hli], a
+ ld bc, ITEM_NAME_LENGTH - 1
+ ld a, -1
+ call ByteFill
+ ret
+
+.AppendToStringBuffer2:
+ ld hl, wStringBuffer2
+ inc [hl]
+ ld e, [hl]
+ ld d, 0
+ add hl, de
+ ld [hl], a
+ ret
+
+.FindOwndDecos:
+ ld hl, .dw
+.loop
+ ld a, [hli]
+ ld e, a
+ ld a, [hli]
+ ld d, a
+ or e
+ jr z, .done
+ push hl
+ call _de_
+ pop hl
+ jr nc, .next
+ ld a, [hl]
+ push hl
+ call .AppendToStringBuffer2
+ pop hl
+.next
+ inc hl
+ jr .loop
+.done
+ ret
+
+.dw
+ dwb FindOwnedBeds, 0 ; bed
+ dwb FindOwnedCarpets, 1 ; carpet
+ dwb FindOwnedPlants, 2 ; plant
+ dwb FindOwnedPosters, 3 ; poster
+ dwb FindOwnedConsoles, 4 ; game console
+ dwb FindOwnedOrnaments, 5 ; ornament
+ dwb FindOwnedBigDolls, 6 ; big doll
+ dw 0 ; end
+
+Deco_FillTempWithMinusOne:
+ xor a
+ ld hl, wceed
+ ld [hli], a
+ ld a, -1
+ ld bc, $10
+ call ByteFill
+ ret
+
+CheckAllDecorationFlags:
+.loop
+ ld a, [hli]
+ cp -1
+ jr z, .done
+ push hl
+ push af
+ ld b, CHECK_FLAG
+ call DecorationFlagAction
+ ld a, c
+ and a
+ pop bc
+ ld a, b
+ call nz, AppendDecoIndex
+ pop hl
+ jr .loop
+
+.done
+ ret
+
+AppendDecoIndex:
+ ld hl, wceed
+ inc [hl]
+ ld e, [hl]
+ ld d, $0
+ add hl, de
+ ld [hl], a
+ ret
+
+FindOwnedDecosInCategory:
+ push bc
+ push hl
+ call Deco_FillTempWithMinusOne
+ pop hl
+ call CheckAllDecorationFlags
+ pop bc
+ ld a, [wceed]
+ and a
+ ret z
+
+ ld a, c
+ call AppendDecoIndex
+ ld a, 0
+ call AppendDecoIndex
+ scf
+ ret
+
+DecoBedMenu:
+ call FindOwnedBeds
+ call PopulateDecoCategoryMenu
+ xor a
+ ret
+
+FindOwnedBeds:
+ ld hl, .beds
+ ld c, BEDS
+ jp FindOwnedDecosInCategory
+
+.beds
+ db DECO_FEATHERY_BED ; 2
+ db DECO_PINK_BED ; 3
+ db DECO_POLKADOT_BED ; 4
+ db DECO_PIKACHU_BED ; 5
+ db -1
+
+DecoCarpetMenu:
+ call FindOwnedCarpets
+ call PopulateDecoCategoryMenu
+ xor a
+ ret
+
+FindOwnedCarpets:
+ ld hl, .carpets
+ ld c, CARPETS
+ jp FindOwnedDecosInCategory
+
+.carpets
+ db DECO_RED_CARPET ; 7
+ db DECO_BLUE_CARPET ; 8
+ db DECO_YELLOW_CARPET ; 9
+ db DECO_GREEN_CARPET ; a
+ db -1
+
+DecoPlantMenu:
+ call FindOwnedPlants
+ call PopulateDecoCategoryMenu
+ xor a
+ ret
+
+FindOwnedPlants:
+ ld hl, .plants
+ ld c, PLANTS
+ jp FindOwnedDecosInCategory
+
+.plants
+ db DECO_MAGNAPLANT ; c
+ db DECO_TROPICPLANT ; d
+ db DECO_JUMBOPLANT ; e
+ db -1
+
+DecoPosterMenu:
+ call FindOwnedPosters
+ call PopulateDecoCategoryMenu
+ xor a
+ ret
+
+FindOwnedPosters:
+ ld hl, .posters
+ ld c, POSTERS
+ jp FindOwnedDecosInCategory
+
+.posters
+ db DECO_TOWN_MAP ; 10
+ db DECO_PIKACHU_POSTER ; 11
+ db DECO_CLEFAIRY_POSTER ; 12
+ db DECO_JIGGLYPUFF_POSTER ; 13
+ db -1
+
+DecoConsoleMenu:
+ call FindOwnedConsoles
+ call PopulateDecoCategoryMenu
+ xor a
+ ret
+
+FindOwnedConsoles:
+ ld hl, .consoles
+ ld c, CONSOLES
+ jp FindOwnedDecosInCategory
+
+.consoles
+ db DECO_FAMICOM ; 15
+ db DECO_SNES ; 16
+ db DECO_N64 ; 17
+ db DECO_VIRTUAL_BOY ; 18
+ db -1
+
+DecoOrnamentMenu:
+ call FindOwnedOrnaments
+ call PopulateDecoCategoryMenu
+ xor a
+ ret
+
+FindOwnedOrnaments:
+ ld hl, .ornaments
+ ld c, DOLLS
+ jp FindOwnedDecosInCategory
+
+.ornaments
+ db DECO_PIKACHU_DOLL ; 1e
+ db DECO_SURF_PIKACHU_DOLL ; 1f
+ db DECO_CLEFAIRY_DOLL ; 20
+ db DECO_JIGGLYPUFF_DOLL ; 21
+ db DECO_BULBASAUR_DOLL ; 22
+ db DECO_CHARMANDER_DOLL ; 23
+ db DECO_SQUIRTLE_DOLL ; 24
+ db DECO_POLIWAG_DOLL ; 25
+ db DECO_DIGLETT_DOLL ; 26
+ db DECO_STARMIE_DOLL ; 27
+ db DECO_MAGIKARP_DOLL ; 28
+ db DECO_ODDISH_DOLL ; 29
+ db DECO_GENGAR_DOLL ; 2a
+ db DECO_SHELLDER_DOLL ; 2b
+ db DECO_GRIMER_DOLL ; 2c
+ db DECO_VOLTORB_DOLL ; 2d
+ db DECO_WEEDLE_DOLL ; 2e
+ db DECO_UNOWN_DOLL ; 2f
+ db DECO_GEODUDE_DOLL ; 30
+ db DECO_MACHOP_DOLL ; 31
+ db DECO_TENTACOOL_DOLL ; 32
+ db DECO_GOLD_TROPHY_DOLL ; 33
+ db DECO_SILVER_TROPHY_DOLL ; 34
+ db -1
+
+DecoBigDollMenu:
+ call FindOwnedBigDolls
+ call PopulateDecoCategoryMenu
+ xor a
+ ret
+
+FindOwnedBigDolls:
+ ld hl, .big_dolls
+ ld c, BIG_DOLLS
+ jp FindOwnedDecosInCategory
+
+.big_dolls
+ db DECO_BIG_SNORLAX_DOLL ; 1a
+ db DECO_BIG_ONIX_DOLL ; 1b
+ db DECO_BIG_LAPRAS_DOLL ; 1c
+ db -1
+
+DecoExitMenu:
+ scf
+ ret
+
+PopulateDecoCategoryMenu:
+ ld a, [wceed]
+ and a
+ jr z, .empty
+ cp 8
+ jr nc, .beyond_eight
+ xor a
+ ld [wWhichIndexSet], a
+ ld hl, .NonscrollingMenuHeader
+ call LoadMenuHeader
+ call DoNthMenu
+ jr c, .no_action_1
+ call DoDecorationAction2
+
+.no_action_1
+ call ExitMenu
+ ret
+
+.beyond_eight
+ ld hl, wceed
+ ld e, [hl]
+ dec [hl]
+ ld d, 0
+ add hl, de
+ ld [hl], -1
+ call LoadStandardMenuHeader
+ ld hl, .ScrollingMenuHeader
+ call CopyMenuHeader
+ xor a
+ ldh [hBGMapMode], a
+ call InitScrollingMenu
+ xor a
+ ld [wMenuScrollPosition], a
+ call ScrollingMenu
+ ld a, [wMenuJoypad]
+ cp 2
+ jr z, .no_action_2
+ call DoDecorationAction2
+
+.no_action_2
+ call ExitMenu
+ ret
+
+.empty
+ ld hl, .NothingToChooseText
+ call MenuTextboxBackup
+ ret
+
+.NothingToChooseText:
+ text_far _NothingToChooseText
+ text_end
+
+.NonscrollingMenuHeader:
+ db MENU_BACKUP_TILES ; flags
+ menu_coords 0, 0, SCREEN_WIDTH - 1, SCREEN_HEIGHT - 1
+ dw .NonscrollingMenuData
+ db 1 ; default option
+
+.NonscrollingMenuData:
+ db STATICMENU_CURSOR | STATICMENU_WRAP ; flags
+ db 0 ; items
+ dw wceed
+ dw DecorationMenuFunction
+ dw DecorationAttributes
+
+.ScrollingMenuHeader:
+ db MENU_BACKUP_TILES ; flags
+ menu_coords 1, 1, SCREEN_WIDTH - 2, SCREEN_HEIGHT - 2
+ dw .ScrollingMenuData
+ db 1 ; default option
+
+.ScrollingMenuData:
+ db SCROLLINGMENU_DISPLAY_ARROWS ; flags
+ db 8, 0 ; rows, columns
+ db SCROLLINGMENU_ITEMS_NORMAL ; item format
+ dbw 0, wceed ; text pointer
+ dba DecorationMenuFunction
+ dbw 0, 0
+ dbw 0, 0
+
+GetDecorationData:
+ ld hl, DecorationAttributes
+ ld bc, 6
+ call AddNTimes
+ ret
+
+GetDecorationName:
+ push hl
+ call GetDecorationData
+ call GetDecoName
+ pop hl
+ call CopyName2
+ ret
+
+DecorationMenuFunction:
+ ld a, [wMenuSelection]
+ push de
+ call GetDecorationData
+ call GetDecoName
+ pop hl
+ call PlaceString
+ ret
+
+DoDecorationAction2:
+ ld a, [wMenuSelection]
+ call GetDecorationData
+ ld de, 2 ; function 2
+ add hl, de
+ ld a, [hl]
+ ld hl, .DecoActions
+ rst JumpTable
+ ret
+
+.DecoActions:
+ dw DecoAction_nothing
+ dw DecoAction_setupbed
+ dw DecoAction_putawaybed
+ dw DecoAction_setupcarpet
+ dw DecoAction_putawaycarpet
+ dw DecoAction_setupplant
+ dw DecoAction_putawayplant
+ dw DecoAction_setupposter
+ dw DecoAction_putawayposter
+ dw DecoAction_setupconsole
+ dw DecoAction_putawayconsole
+ dw DecoAction_setupbigdoll
+ dw DecoAction_putawaybigdoll
+ dw DecoAction_setupornament
+ dw DecoAction_putawayornament
+
+GetDecorationFlag:
+ call GetDecorationData
+ ld de, 3 ; event flag
+ add hl, de
+ ld a, [hli]
+ ld d, [hl]
+ ld e, a
+ ret
+
+DecorationFlagAction:
+ push bc
+ call GetDecorationFlag
+ pop bc
+ call EventFlagAction
+ ret
+
+GetDecorationSprite:
+ ld a, c
+ call GetDecorationData
+ ld de, 5 ; sprite
+ add hl, de
+ ld a, [hl]
+ ld c, a
+ ret
+
+INCLUDE "data/decorations/attributes.asm"
+
+INCLUDE "data/decorations/names.asm"
+
+GetDecoName:
+ ld a, [hli]
+ ld e, [hl]
+ ld bc, wStringBuffer2
+ push bc
+ ld hl, .NameFunctions
+ rst JumpTable
+ pop de
+ ret
+
+.NameFunctions:
+ dw .invalid
+ dw .plant
+ dw .bed
+ dw .carpet
+ dw .poster
+ dw .doll
+ dw .bigdoll
+
+.invalid
+ ret
+
+.plant
+ ld a, e
+ jr .getdeconame
+
+.bed
+ call .plant
+ ld a, _BED
+ jr .getdeconame
+
+.carpet
+ call .plant
+ ld a, _CARPET
+ jr .getdeconame
+
+.poster
+ ld a, e
+ call .getpokename
+ ld a, _POSTER
+ jr .getdeconame
+
+.doll
+ ld a, e
+ call .getpokename
+ ld a, _DOLL
+ jr .getdeconame
+
+.bigdoll
+ push de
+ ld a, BIG_
+ call .getdeconame
+ pop de
+ ld a, e
+ jr .getpokename
+
+.getpokename
+ push bc
+ ld [wNamedObjectIndexBuffer], a
+ call GetPokemonName
+ pop bc
+ jr .copy
+
+.getdeconame
+ call ._getdeconame
+ jr .copy
+
+._getdeconame
+ push bc
+ ld hl, DecorationNames
+ call GetNthString
+ ld d, h
+ ld e, l
+ pop bc
+ ret
+
+.copy
+ ld h, b
+ ld l, c
+ call CopyName2
+ dec hl
+ ld b, h
+ ld c, l
+ ret
+
+DecoAction_nothing:
+ scf
+ ret
+
+DecoAction_setupbed:
+ ld hl, wDecoBed
+ jp DecoAction_TrySetItUp
+
+DecoAction_putawaybed:
+ ld hl, wDecoBed
+ jp DecoAction_TryPutItAway
+
+DecoAction_setupcarpet:
+ ld hl, wDecoCarpet
+ jp DecoAction_TrySetItUp
+
+DecoAction_putawaycarpet:
+ ld hl, wDecoCarpet
+ jp DecoAction_TryPutItAway
+
+DecoAction_setupplant:
+ ld hl, wDecoPlant
+ jp DecoAction_TrySetItUp
+
+DecoAction_putawayplant:
+ ld hl, wDecoPlant
+ jp DecoAction_TryPutItAway
+
+DecoAction_setupposter:
+ ld hl, wDecoPoster
+ jp DecoAction_TrySetItUp
+
+DecoAction_putawayposter:
+ ld hl, wDecoPoster
+ jp DecoAction_TryPutItAway
+
+DecoAction_setupconsole:
+ ld hl, wDecoConsole
+ jp DecoAction_TrySetItUp
+
+DecoAction_putawayconsole:
+ ld hl, wDecoConsole
+ jp DecoAction_TryPutItAway
+
+DecoAction_setupbigdoll:
+ ld hl, wDecoBigDoll
+ jp DecoAction_TrySetItUp
+
+DecoAction_putawaybigdoll:
+ ld hl, wDecoBigDoll
+ jp DecoAction_TryPutItAway
+
+DecoAction_TrySetItUp:
+ ld a, [hl]
+ ld [wBuffer1], a
+ push hl
+ call DecoAction_SetItUp
+ jr c, .failed
+ ld a, 1
+ ld [wBuffer5], a
+ pop hl
+ ld a, [wMenuSelection]
+ ld [hl], a
+ xor a
+ ret
+
+.failed
+ pop hl
+ xor a
+ ret
+
+DecoAction_SetItUp:
+; See if there's anything of the same type already out
+ ld a, [wBuffer1]
+ and a
+ jr z, .nothingthere
+; See if that item is already out
+ ld b, a
+ ld a, [wMenuSelection]
+ cp b
+ jr z, .alreadythere
+; Put away the item that's already out, and set up the new one
+ ld a, [wMenuSelection]
+ ld hl, wStringBuffer4
+ call GetDecorationName
+ ld a, [wBuffer1]
+ ld hl, wStringBuffer3
+ call GetDecorationName
+ ld hl, PutAwayAndSetUpText
+ call MenuTextboxBackup
+ xor a
+ ret
+
+.nothingthere
+ ld a, [wMenuSelection]
+ ld hl, wStringBuffer3
+ call GetDecorationName
+ ld hl, SetUpTheDecoText
+ call MenuTextboxBackup
+ xor a
+ ret
+
+.alreadythere
+ ld hl, AlreadySetUpText
+ call MenuTextboxBackup
+ scf
+ ret
+
+DecoAction_TryPutItAway:
+; If there is no item of that type already set, there is nothing to put away.
+ ld a, [hl]
+ ld [wBuffer1], a
+ xor a
+ ld [hl], a
+ ld a, [wBuffer1]
+ and a
+ jr z, .nothingthere
+; Put it away.
+ ld a, $1
+ ld [wBuffer5], a
+ ld a, [wBuffer1]
+ ld [wMenuSelection], a
+ ld hl, wStringBuffer3
+ call GetDecorationName
+ ld hl, PutAwayTheDecoText
+ call MenuTextboxBackup
+ xor a
+ ret
+
+.nothingthere
+ ld hl, NothingToPutAwayText
+ call MenuTextboxBackup
+ xor a
+ ret
+
+DecoAction_setupornament:
+ ld hl, WhichSidePutOnText
+ call DecoAction_AskWhichSide
+ jr c, .cancel
+ call DecoAction_SetItUp_Ornament
+ jr c, .cancel
+ ld a, $1
+ ld [wBuffer5], a
+ jr DecoAction_FinishUp_Ornament
+
+.cancel
+ xor a
+ ret
+
+DecoAction_putawayornament:
+ ld hl, WhichSidePutAwayText
+ call DecoAction_AskWhichSide
+ jr nc, .incave
+ xor a
+ ret
+
+.incave
+ call DecoAction_PutItAway_Ornament
+
+DecoAction_FinishUp_Ornament:
+ call QueryWhichSide
+ ld a, [wSelectedDecoration]
+ ld [hl], a
+ ld a, [wOtherDecoration]
+ ld [de], a
+ xor a
+ ret
+
+DecoAction_SetItUp_Ornament:
+ ld a, [wSelectedDecoration]
+ and a
+ jr z, .nothingthere
+ ld b, a
+ ld a, [wMenuSelection]
+ cp b
+ jr z, .failed
+ ld a, b
+ ld hl, wStringBuffer3
+ call GetDecorationName
+ ld a, [wMenuSelection]
+ ld hl, wStringBuffer4
+ call GetDecorationName
+ ld a, [wMenuSelection]
+ ld [wSelectedDecoration], a
+ call .getwhichside
+ ld hl, PutAwayAndSetUpText
+ call MenuTextboxBackup
+ xor a
+ ret
+
+.nothingthere
+ ld a, [wMenuSelection]
+ ld [wSelectedDecoration], a
+ call .getwhichside
+ ld a, [wMenuSelection]
+ ld hl, wStringBuffer3
+ call GetDecorationName
+ ld hl, SetUpTheDecoText
+ call MenuTextboxBackup
+ xor a
+ ret
+
+.failed
+ ld hl, AlreadySetUpText
+ call MenuTextboxBackup
+ scf
+ ret
+
+.getwhichside
+ ld a, [wMenuSelection]
+ ld b, a
+ ld a, [wOtherDecoration]
+ cp b
+ ret nz
+ xor a
+ ld [wOtherDecoration], a
+ ret
+
+WhichSidePutOnText:
+ text_far _WhichSidePutOnText
+ text_end
+
+DecoAction_PutItAway_Ornament:
+ ld a, [wSelectedDecoration]
+ and a
+ jr z, .nothingthere
+ ld hl, wStringBuffer3
+ call GetDecorationName
+ ld a, $1
+ ld [wBuffer5], a
+ xor a
+ ld [wSelectedDecoration], a
+ ld hl, PutAwayTheDecoText
+ call MenuTextboxBackup
+ xor a
+ ret
+
+.nothingthere
+ ld hl, NothingToPutAwayText
+ call MenuTextboxBackup
+ xor a
+ ret
+
+WhichSidePutAwayText:
+ text_far _WhichSidePutAwayText
+ text_end
+
+DecoAction_AskWhichSide:
+ call MenuTextbox
+ ld hl, MenuHeader_0x2707e
+ call GetMenu2
+ call ExitMenu
+ call CopyMenuData
+ jr c, .nope
+ ld a, [wMenuCursorY]
+ cp 3
+ jr z, .nope
+ ld [wBuffer2], a
+ call QueryWhichSide
+ ld a, [hl]
+ ld [wSelectedDecoration], a
+ ld a, [de]
+ ld [wOtherDecoration], a
+ xor a
+ ret
+
+.nope
+ scf
+ ret
+
+QueryWhichSide:
+ ld hl, wDecoRightOrnament
+ ld de, wDecoLeftOrnament
+ ld a, [wBuffer2]
+ cp 1
+ ret z
+ push hl
+ ld h, d
+ ld l, e
+ pop de
+ ret
+
+MenuHeader_0x2707e:
+ db MENU_BACKUP_TILES ; flags
+ menu_coords 0, 0, 12, 7
+ dw MenuData_0x27086
+ db 1 ; default option
+
+MenuData_0x27086:
+ db STATICMENU_CURSOR ; flags
+ db 3 ; items
+ db "RIGHT SIDE@"
+ db "LEFT SIDE@"
+ db "CANCEL@"
+
+PutAwayTheDecoText:
+ text_far _PutAwayTheDecoText
+ text_end
+
+NothingToPutAwayText:
+ text_far _NothingToPutAwayText
+ text_end
+
+SetUpTheDecoText:
+ text_far _SetUpTheDecoText
+ text_end
+
+PutAwayAndSetUpText:
+ text_far _PutAwayAndSetUpText
+ text_end
+
+AlreadySetUpText:
+ text_far _AlreadySetUpText
+ text_end
+
+GetDecorationName_c_de:
+ ld a, c
+ ld h, d
+ ld l, e
+ call GetDecorationName
+ ret
+
+DecorationFlagAction_c:
+ ld a, c
+ jp DecorationFlagAction
+
+GetDecorationName_c:
+ ld a, c
+ call GetDecorationID
+ ld hl, wStringBuffer1
+ push hl
+ call GetDecorationName
+ pop de
+ ret
+
+SetSpecificDecorationFlag:
+ ld a, c
+ call GetDecorationID
+ ld b, SET_FLAG
+ call DecorationFlagAction
+ ret
+
+GetDecorationID:
+ push hl
+ push de
+ ld e, a
+ ld d, 0
+ ld hl, DecorationIDs
+ add hl, de
+ ld a, [hl]
+ pop de
+ pop hl
+ ret
+
+SetAllDecorationFlags:
+ ld hl, DecorationIDs
+.loop
+ ld a, [hli]
+ cp -1
+ jr z, .done
+ push hl
+ ld b, SET_FLAG
+ call DecorationFlagAction
+ pop hl
+ jr .loop
+
+.done
+ ret
+
+INCLUDE "data/decorations/decorations.asm"
+
+DescribeDecoration::
+ ld a, b
+ ld hl, .JumpTable
+ rst JumpTable
+ ret
+
+.JumpTable:
+; entries correspond to DECODESC_* constants
+ dw DecorationDesc_Poster
+ dw DecorationDesc_LeftOrnament
+ dw DecorationDesc_RightOrnament
+ dw DecorationDesc_GiantOrnament
+ dw DecorationDesc_Console
+
+DecorationDesc_Poster:
+ ld a, [wDecoPoster]
+ ld hl, DecorationDesc_PosterPointers
+ ld de, 3
+ call IsInArray
+ jr c, .nope
+ ld de, DecorationDesc_NullPoster
+ ld b, BANK(DecorationDesc_NullPoster)
+ ret
+
+.nope
+ ld b, BANK(DecorationDesc_TownMapPoster)
+ inc hl
+ ld a, [hli]
+ ld d, [hl]
+ ld e, a
+ ret
+
+DecorationDesc_PosterPointers:
+ dbw DECO_TOWN_MAP, DecorationDesc_TownMapPoster
+ dbw DECO_PIKACHU_POSTER, DecorationDesc_PikachuPoster
+ dbw DECO_CLEFAIRY_POSTER, DecorationDesc_ClefairyPoster
+ dbw DECO_JIGGLYPUFF_POSTER, DecorationDesc_JigglypuffPoster
+ db -1
+
+DecorationDesc_TownMapPoster:
+ opentext
+ writetext .LookTownMapText
+ waitbutton
+ special OverworldTownMap
+ closetext
+ end
+
+.LookTownMapText:
+ text_far _LookTownMapText
+ text_end
+
+DecorationDesc_PikachuPoster:
+ jumptext .LookPikachuPosterText
+
+.LookPikachuPosterText:
+ text_far _LookPikachuPosterText
+ text_end
+
+DecorationDesc_ClefairyPoster:
+ jumptext .LookClefairyPosterText
+
+.LookClefairyPosterText:
+ text_far _LookClefairyPosterText
+ text_end
+
+DecorationDesc_JigglypuffPoster:
+ jumptext .LookJigglypuffPosterText
+
+.LookJigglypuffPosterText:
+ text_far _LookJigglypuffPosterText
+ text_end
+
+DecorationDesc_NullPoster:
+ end
+
+DecorationDesc_LeftOrnament:
+ ld a, [wDecoLeftOrnament]
+ jr DecorationDesc_OrnamentOrConsole
+
+DecorationDesc_RightOrnament:
+ ld a, [wDecoRightOrnament]
+ jr DecorationDesc_OrnamentOrConsole
+
+DecorationDesc_Console:
+ ld a, [wDecoConsole]
+ jr DecorationDesc_OrnamentOrConsole
+
+DecorationDesc_OrnamentOrConsole:
+ ld c, a
+ ld de, wStringBuffer3
+ call GetDecorationName_c_de
+ ld b, BANK(.OrnamentConsoleScript)
+ ld de, .OrnamentConsoleScript
+ ret
+
+.OrnamentConsoleScript:
+ jumptext .LookAdorableDecoText
+
+.LookAdorableDecoText:
+ text_far _LookAdorableDecoText
+ text_end
+
+DecorationDesc_GiantOrnament:
+ ld b, BANK(.BigDollScript)
+ ld de, .BigDollScript
+ ret
+
+.BigDollScript:
+ jumptext .LookGiantDecoText
+
+.LookGiantDecoText:
+ text_far _LookGiantDecoText
+ text_end
+
+ToggleMaptileDecorations:
+ ; tile coordinates work the same way as for changeblock
+ lb de, 0, 4 ; bed coordinates
+ ld a, [wDecoBed]
+ call SetDecorationTile
+ lb de, 7, 4 ; plant coordinates
+ ld a, [wDecoPlant]
+ call SetDecorationTile
+ lb de, 6, 0 ; poster coordinates
+ ld a, [wDecoPoster]
+ call SetDecorationTile
+ call SetPosterVisibility
+ lb de, 0, 0 ; carpet top-left coordinates
+ call PadCoords_de
+ ld a, [wDecoCarpet]
+ and a
+ ret z
+ call _GetDecorationSprite
+ ld [hl], a
+ push af
+ lb de, 0, 2 ; carpet bottom-left coordinates
+ call PadCoords_de
+ pop af
+ inc a
+ ld [hli], a ; carpet bottom-left block
+ inc a
+ ld [hli], a ; carpet bottom-middle block
+ dec a
+ ld [hl], a ; carpet bottom-right block
+ ret
+
+SetPosterVisibility:
+ ld b, SET_FLAG
+ ld a, [wDecoPoster]
+ and a
+ jr nz, .ok
+ ld b, RESET_FLAG
+
+.ok
+ ld de, EVENT_PLAYERS_ROOM_POSTER
+ jp EventFlagAction
+
+SetDecorationTile:
+ push af
+ call PadCoords_de
+ pop af
+ and a
+ ret z
+ call _GetDecorationSprite
+ ld [hl], a
+ ret
+
+ToggleDecorationsVisibility:
+ ld de, EVENT_PLAYERS_HOUSE_2F_CONSOLE
+ ld hl, wVariableSprites + SPRITE_CONSOLE - SPRITE_VARS
+ ld a, [wDecoConsole]
+ call ToggleDecorationVisibility
+ ld de, EVENT_PLAYERS_HOUSE_2F_DOLL_1
+ ld hl, wVariableSprites + SPRITE_DOLL_1 - SPRITE_VARS
+ ld a, [wDecoLeftOrnament]
+ call ToggleDecorationVisibility
+ ld de, EVENT_PLAYERS_HOUSE_2F_DOLL_2
+ ld hl, wVariableSprites + SPRITE_DOLL_2 - SPRITE_VARS
+ ld a, [wDecoRightOrnament]
+ call ToggleDecorationVisibility
+ ld de, EVENT_PLAYERS_HOUSE_2F_BIG_DOLL
+ ld hl, wVariableSprites + SPRITE_BIG_DOLL - SPRITE_VARS
+ ld a, [wDecoBigDoll]
+ call ToggleDecorationVisibility
+ ret
+
+ToggleDecorationVisibility:
+ and a
+ jr z, .hide
+ call _GetDecorationSprite
+ ld [hl], a
+ ld b, RESET_FLAG
+ jp EventFlagAction
+
+.hide
+ ld b, SET_FLAG
+ jp EventFlagAction
+
+_GetDecorationSprite:
+ ld c, a
+ push de
+ push hl
+ farcall GetDecorationSprite
+ pop hl
+ pop de
+ ld a, c
+ ret
+
+PadCoords_de:
+; adjusts coordinates, the same way as Script_changeblock
+ ld a, d
+ add 4
+ ld d, a
+ ld a, e
+ add 4
+ ld e, a
+ call GetBlockLocation
+ ret
diff --git a/engine/overworld/events.asm b/engine/overworld/events.asm
new file mode 100644
index 00000000..794fa074
--- /dev/null
+++ b/engine/overworld/events.asm
@@ -0,0 +1,1585 @@
+INCLUDE "constants.asm"
+
+
+SECTION "Events", ROMX
+
+OverworldLoop::
+ xor a ; MAPSTATUS_START
+ ld [wMapStatus], a
+.loop
+ ld a, [wMapStatus]
+ ld hl, .jumps
+ rst JumpTable
+ ld a, [wMapStatus]
+ cp MAPSTATUS_DONE
+ jr nz, .loop
+.done
+ ret
+
+.jumps
+; entries correspond to MAPSTATUS_* constants
+ dw StartMap
+ dw EnterMap
+ dw HandleMap
+ dw .done
+
+DisableEvents:
+ xor a
+ ld [wScriptFlags3], a
+ ret
+
+EnableEvents::
+ ld a, $ff
+ ld [wScriptFlags3], a
+ ret
+
+CheckBit5_ScriptFlags3:
+ ld hl, wScriptFlags3
+ bit 5, [hl]
+ ret
+
+DisableWarpsConnxns:
+ ld hl, wScriptFlags3
+ res 2, [hl]
+ ret
+
+DisableCoordEvents:
+ ld hl, wScriptFlags3
+ res 1, [hl]
+ ret
+
+DisableStepCount:
+ ld hl, wScriptFlags3
+ res 0, [hl]
+ ret
+
+DisableWildEncounters:
+ ld hl, wScriptFlags3
+ res 4, [hl]
+ ret
+
+EnableWarpsConnxns:
+ ld hl, wScriptFlags3
+ set 2, [hl]
+ ret
+
+EnableCoordEvents:
+ ld hl, wScriptFlags3
+ set 1, [hl]
+ ret
+
+EnableStepCount:
+ ld hl, wScriptFlags3
+ set 0, [hl]
+ ret
+
+EnableWildEncounters:
+ ld hl, wScriptFlags3
+ set 4, [hl]
+ ret
+
+CheckWarpConnxnScriptFlag:
+ ld hl, wScriptFlags3
+ bit 2, [hl]
+ ret
+
+CheckCoordEventScriptFlag:
+ ld hl, wScriptFlags3
+ bit 1, [hl]
+ ret
+
+CheckStepCountScriptFlag:
+ ld hl, wScriptFlags3
+ bit 0, [hl]
+ ret
+
+CheckWildEncountersScriptFlag:
+ ld hl, wScriptFlags3
+ bit 4, [hl]
+ ret
+
+StartMap:
+ xor a
+ ld [wScriptRunning], a
+ ld hl, wMapStatus
+ ld bc, wMapStatusEnd - wMapStatus
+ call ByteFill
+ farcall InitCallReceiveDelay
+ call ClearJoypad
+EnterMap:
+ xor a
+ ld [wXYComparePointer], a
+ ld [wXYComparePointer + 1], a
+ call SetUpFiveStepWildEncounterCooldown
+ farcall RunMapSetupScript
+ call DisableEvents
+
+ ldh a, [hMapEntryMethod]
+ cp MAPSETUP_CONNECTION
+ jr nz, .dont_enable
+ call EnableEvents
+.dont_enable
+
+ ldh a, [hMapEntryMethod]
+ cp MAPSETUP_RELOADMAP
+ jr nz, .dontresetpoison
+ xor a
+ ld [wPoisonStepCount], a
+.dontresetpoison
+
+ xor a ; end map entry
+ ldh [hMapEntryMethod], a
+ ld a, MAPSTATUS_HANDLE
+ ld [wMapStatus], a
+ ret
+
+UnusedWait30Frames:
+ ld c, 30
+ call DelayFrames
+ ret
+
+HandleMap:
+ call ResetOverworldDelay
+ call HandleMapTimeAndJoypad
+ farcall HandleCmdQueue ; no need to farcall
+ call MapEvents
+
+; Not immediately entering a connected map will cause problems.
+ ld a, [wMapStatus]
+ cp MAPSTATUS_HANDLE
+ ret nz
+
+ call HandleMapObjects
+ call NextOverworldFrame
+ call HandleMapBackground
+ call CheckPlayerState
+ ret
+
+MapEvents:
+ ld a, [wMapEventStatus]
+ ld hl, .jumps
+ rst JumpTable
+ ret
+
+.jumps
+; entries correspond to MAPEVENTS_* constants
+ dw .events
+ dw .no_events
+
+.events
+ call PlayerEvents
+ call DisableEvents
+ farcall ScriptEvents
+ ret
+
+.no_events
+ ret
+
+MaxOverworldDelay:
+ db 2
+
+ResetOverworldDelay:
+ ld a, [MaxOverworldDelay]
+ ld [wOverworldDelay], a
+ ret
+
+NextOverworldFrame:
+ ld a, [wOverworldDelay]
+ and a
+ ret z
+ ld c, a
+ call DelayFrames
+ ret
+
+HandleMapTimeAndJoypad:
+ ld a, [wMapEventStatus]
+ cp MAPEVENTS_OFF
+ ret z
+
+ call UpdateTime
+ call GetJoypad
+ call TimeOfDayPals
+ ret
+
+HandleMapObjects:
+ farcall HandleNPCStep ; engine/map_objects.asm
+ farcall _HandlePlayerStep
+ call _CheckObjectEnteringVisibleRange
+ ret
+
+HandleMapBackground:
+ farcall _UpdateSprites
+ farcall ScrollScreen
+ ret
+
+CheckPlayerState:
+ ld a, [wPlayerStepFlags]
+ bit PLAYERSTEP_CONTINUE_F, a
+ jr z, .events
+ bit PLAYERSTEP_STOP_F, a
+ jr z, .noevents
+ bit PLAYERSTEP_MIDAIR_F, a
+ jr nz, .noevents
+ call EnableEvents
+.events
+ ld a, MAPEVENTS_ON
+ ld [wMapEventStatus], a
+ ret
+
+.noevents
+ ld a, MAPEVENTS_OFF
+ ld [wMapEventStatus], a
+ ret
+
+_CheckObjectEnteringVisibleRange:
+ ld hl, wPlayerStepFlags
+ bit PLAYERSTEP_STOP_F, [hl]
+ ret z
+ farcall CheckObjectEnteringVisibleRange
+ ret
+
+PlayerEvents:
+ xor a
+; If there's already a player event, don't interrupt it.
+ ld a, [wScriptRunning]
+ and a
+ ret nz
+
+ call Dummy_CheckScriptFlags3Bit5 ; This is a waste of time
+
+ call CheckTrainerBattle_GetPlayerEvent
+ jr c, .ok
+
+ call CheckTileEvent
+ jr c, .ok
+
+ call RunMemScript
+ jr c, .ok
+
+ call RunSceneScript
+ jr c, .ok
+
+ call CheckTimeEvents
+ jr c, .ok
+
+ call OWPlayerInput
+ jr c, .ok
+
+ xor a
+ ret
+
+.ok
+ push af
+ farcall EnableScriptMode
+ pop af
+ ld [wScriptRunning], a
+ call DoPlayerEvent
+ scf
+ ret
+
+CheckTrainerBattle_GetPlayerEvent:
+ nop
+ nop
+ call CheckTrainerBattle
+ jr nc, .nope
+
+ ld a, PLAYEREVENT_SEENBYTRAINER
+ scf
+ ret
+
+.nope
+ xor a
+ ret
+
+CheckTileEvent:
+; Check for warps, coord events, or wild battles.
+
+ call CheckWarpConnxnScriptFlag
+ jr z, .connections_disabled
+
+ call CheckMovingOffEdgeOfMap
+ jr c, .map_connection
+
+ call CheckWarpTile
+ jr c, .warp_tile
+
+.connections_disabled
+ call CheckCoordEventScriptFlag
+ jr z, .coord_events_disabled
+
+ call CheckCurrentMapCoordEvents
+ jr c, .coord_event
+
+.coord_events_disabled
+ call CheckStepCountScriptFlag
+ jr z, .step_count_disabled
+
+ call CountStep
+ ret c
+
+.step_count_disabled
+ call CheckWildEncountersScriptFlag
+ jr z, .ok
+
+ call RandomEncounter
+ ret c
+ jr .ok ; pointless
+
+.ok
+ xor a
+ ret
+
+.map_connection
+ ld a, PLAYEREVENT_CONNECTION
+ scf
+ ret
+
+.warp_tile
+ ld a, [wPlayerStandingTile]
+ call CheckPitTile
+ jr nz, .not_pit
+ ld a, PLAYEREVENT_FALL
+ scf
+ ret
+
+.not_pit
+ ld a, PLAYEREVENT_WARP
+ scf
+ ret
+
+.coord_event
+ ld hl, wCurCoordEventScriptAddr
+ ld a, [hli]
+ ld h, [hl]
+ ld l, a
+ call GetMapScriptsBank
+ call CallScript
+ ret
+
+CheckWildEncounterCooldown::
+ ld hl, wWildEncounterCooldown
+ ld a, [hl]
+ and a
+ ret z
+ dec [hl]
+ ret z
+ scf
+ ret
+
+SetUpFiveStepWildEncounterCooldown:
+ ld a, 5
+ ld [wWildEncounterCooldown], a
+ ret
+
+ret_96804:
+ ret
+
+SetMinTwoStepWildEncounterCooldown:
+ ld a, [wWildEncounterCooldown]
+ cp 2
+ ret nc
+ ld a, 2
+ ld [wWildEncounterCooldown], a
+ ret
+
+Dummy_CheckScriptFlags3Bit5:
+ call CheckBit5_ScriptFlags3
+ ret z
+ call Function2ffe
+ ret
+
+RunSceneScript:
+ ld a, [wCurMapSceneScriptCount]
+ and a
+ jr z, .nope
+
+ ld c, a
+ call CheckScenes
+ cp c
+ jr nc, .nope
+
+ ld e, a
+ ld d, 0
+ ld hl, wCurMapSceneScriptsPointer
+ ld a, [hli]
+ ld h, [hl]
+ ld l, a
+rept SCENE_SCRIPT_SIZE
+ add hl, de
+endr
+
+ call GetMapScriptsBank
+ call GetFarHalfword
+ call GetMapScriptsBank
+ call CallScript
+
+ ld hl, wScriptFlags
+ res 3, [hl]
+
+ farcall EnableScriptMode
+ farcall ScriptEvents
+
+ ld hl, wScriptFlags
+ bit 3, [hl]
+ jr z, .nope
+
+ ld hl, wPriorityScriptAddr
+ ld a, [hli]
+ ld h, [hl]
+ ld l, a
+ ld a, [wPriorityScriptBank]
+ call CallScript
+ scf
+ ret
+
+.nope
+ xor a
+ ret
+
+CheckTimeEvents:
+ ld a, [wLinkMode]
+ and a
+ jr nz, .nothing
+
+ ld hl, wStatusFlags2
+ bit STATUSFLAGS2_BUG_CONTEST_TIMER_F, [hl]
+ jr z, .do_daily
+
+ farcall CheckBugContestTimer
+ jr c, .end_bug_contest
+ xor a
+ ret
+
+.do_daily
+ farcall CheckDailyResetTimer
+ farcall CheckSwarmFlag
+ farcall CheckPokerusTick
+ farcall CheckPhoneCall
+ ret c
+
+.nothing
+ xor a
+ ret
+
+.end_bug_contest
+ ld a, BANK(BugCatchingContestOverScript)
+ ld hl, BugCatchingContestOverScript
+ call CallScript
+ scf
+ ret
+
+.unused
+ ld a, 8
+ scf
+ ret
+
+OWPlayerInput:
+ call PlayerMovement
+ ret c
+ and a
+ jr nz, .NoAction
+
+; Can't perform button actions while sliding on ice.
+ farcall CheckStandingOnIce
+ jr c, .NoAction
+
+ call CheckAPressOW
+ jr c, .Action
+
+ call CheckMenuOW
+ jr c, .Action
+
+.NoAction:
+ xor a
+ ret
+
+.Action:
+ push af
+ farcall StopPlayerForEvent
+ pop af
+ scf
+ ret
+
+CheckAPressOW:
+ ldh a, [hJoyPressed]
+ and A_BUTTON
+ ret z
+ call TryObjectEvent
+ ret c
+ call TryBGEvent
+ ret c
+ call TryTileCollisionEvent
+ ret c
+ xor a
+ ret
+
+PlayTalkObject:
+ push de
+ ld de, SFX_READ_TEXT_2
+ call PlaySFX
+ pop de
+ ret
+
+TryObjectEvent:
+ farcall CheckFacingObject
+ jr c, .IsObject
+ xor a
+ ret
+
+.IsObject:
+ call PlayTalkObject
+ ldh a, [hObjectStructIndexBuffer]
+ call GetObjectStruct
+ ld hl, OBJECT_MAP_OBJECT_INDEX
+ add hl, bc
+ ld a, [hl]
+ ldh [hLastTalked], a
+
+ ldh a, [hLastTalked]
+ call GetMapObject
+ ld hl, MAPOBJECT_COLOR
+ add hl, bc
+ ld a, [hl]
+ and %00001111
+
+; Bug: If IsInArray returns nc, data at bc will be executed as code.
+ push bc
+ ld de, 3
+ ld hl, .pointers
+ call IsInArray
+ jr nc, .nope
+ pop bc
+
+ inc hl
+ ld a, [hli]
+ ld h, [hl]
+ ld l, a
+ jp hl
+
+.nope
+ ; pop bc
+ xor a
+ ret
+
+.pointers
+ dbw OBJECTTYPE_SCRIPT, .script
+ dbw OBJECTTYPE_ITEMBALL, .itemball
+ dbw OBJECTTYPE_TRAINER, .trainer
+ ; the remaining four are dummy events
+ dbw OBJECTTYPE_3, .three
+ dbw OBJECTTYPE_4, .four
+ dbw OBJECTTYPE_5, .five
+ dbw OBJECTTYPE_6, .six
+ db -1
+
+.script
+ ld hl, MAPOBJECT_SCRIPT_POINTER
+ add hl, bc
+ ld a, [hli]
+ ld h, [hl]
+ ld l, a
+ call GetMapScriptsBank
+ call CallScript
+ ret
+
+.itemball
+ ld hl, MAPOBJECT_SCRIPT_POINTER
+ add hl, bc
+ ld a, [hli]
+ ld h, [hl]
+ ld l, a
+ call GetMapScriptsBank
+ ld de, wItemBallData
+ ld bc, wItemBallDataEnd - wItemBallData
+ call FarCopyBytes
+ ld a, PLAYEREVENT_ITEMBALL
+ scf
+ ret
+
+.trainer
+ call TalkToTrainer
+ ld a, PLAYEREVENT_TALKTOTRAINER
+ scf
+ ret
+
+.three
+ xor a
+ ret
+
+.four
+ xor a
+ ret
+
+.five
+ xor a
+ ret
+
+.six
+ xor a
+ ret
+
+TryBGEvent:
+ call CheckFacingBGEvent
+ jr c, .is_bg_event
+ xor a
+ ret
+
+.is_bg_event:
+ ld a, [wCurBGEventType]
+ ld hl, .bg_events
+ rst JumpTable
+ ret
+
+.bg_events
+ dw .read
+ dw .up
+ dw .down
+ dw .right
+ dw .left
+ dw .ifset
+ dw .ifnotset
+ dw .itemifset
+ dw .copy
+
+.up
+ ld b, OW_UP
+ jr .checkdir
+.down
+ ld b, OW_DOWN
+ jr .checkdir
+.right
+ ld b, OW_RIGHT
+ jr .checkdir
+.left
+ ld b, OW_LEFT
+ jr .checkdir
+
+.checkdir
+ ld a, [wPlayerDirection]
+ and %1100
+ cp b
+ jp nz, .dontread
+
+.read
+ call PlayTalkObject
+ ld hl, wCurBGEventScriptAddr
+ ld a, [hli]
+ ld h, [hl]
+ ld l, a
+ call GetMapScriptsBank
+ call CallScript
+ scf
+ ret
+
+.itemifset
+ call CheckBGEventFlag
+ jp nz, .dontread
+ call PlayTalkObject
+ call GetMapScriptsBank
+ ld de, wHiddenItemData
+ ld bc, wHiddenItemDataEnd - wHiddenItemData
+ call FarCopyBytes
+ ld a, BANK(HiddenItemScript)
+ ld hl, HiddenItemScript
+ call CallScript
+ scf
+ ret
+
+.copy
+ call CheckBGEventFlag
+ jr nz, .dontread
+ call GetMapScriptsBank
+ ld de, wHiddenItemData
+ ld bc, wHiddenItemDataEnd - wHiddenItemData
+ call FarCopyBytes
+ jr .dontread
+
+.ifset
+ call CheckBGEventFlag
+ jr z, .dontread
+ jr .thenread
+
+.ifnotset
+ call CheckBGEventFlag
+ jr nz, .dontread
+
+.thenread
+ push hl
+ call PlayTalkObject
+ pop hl
+ inc hl
+ inc hl
+ call GetMapScriptsBank
+ call GetFarHalfword
+ call GetMapScriptsBank
+ call CallScript
+ scf
+ ret
+
+.dontread
+ xor a
+ ret
+
+CheckBGEventFlag:
+ ld hl, wCurBGEventScriptAddr
+ ld a, [hli]
+ ld h, [hl]
+ ld l, a
+ push hl
+ call GetMapScriptsBank
+ call GetFarHalfword
+ ld e, l
+ ld d, h
+ ld b, CHECK_FLAG
+ call EventFlagAction
+ ld a, c
+ and a
+ pop hl
+ ret
+
+PlayerMovement:
+ farcall DoPlayerMovement
+ ld a, c
+ ld hl, .pointers
+ rst JumpTable
+ ld a, c
+ ret
+
+.pointers
+; entries correspond to PLAYERMOVEMENT_* constants
+ dw .normal
+ dw .warp
+ dw .turn
+ dw .force_turn
+ dw .finish
+ dw .continue
+ dw .exit_water
+ dw .jump
+
+.normal:
+.finish:
+ xor a
+ ld c, a
+ ret
+
+.jump:
+ call ret_96804
+ xor a
+ ld c, a
+ ret
+
+.warp:
+ ld a, PLAYEREVENT_WARP
+ ld c, a
+ scf
+ ret
+
+.turn:
+ ld a, PLAYEREVENT_JOYCHANGEFACING
+ ld c, a
+ scf
+ ret
+
+.force_turn:
+; force the player to move in some direction
+ ld a, BANK(Script_ForcedMovement)
+ ld hl, Script_ForcedMovement
+ call CallScript
+; ld a, -1
+ ld c, a
+ scf
+ ret
+
+.continue:
+.exit_water:
+ ld a, -1
+ ld c, a
+ and a
+ ret
+
+CheckMenuOW:
+ xor a
+ ldh [hMenuReturn], a
+ ldh [hUnusedFFA3], a
+ ldh a, [hJoyPressed]
+
+ bit SELECT_F, a
+ jr nz, .Select
+
+ bit START_F, a
+ jr z, .NoMenu
+
+ ld a, BANK(StartMenuScript)
+ ld hl, StartMenuScript
+ call CallScript
+ scf
+ ret
+
+.NoMenu:
+ xor a
+ ret
+
+.Select:
+ call PlayTalkObject
+ ld a, BANK(SelectMenuScript)
+ ld hl, SelectMenuScript
+ call CallScript
+ scf
+ ret
+
+StartMenuScript:
+ callasm StartMenu
+ sjump StartMenuCallback
+
+SelectMenuScript:
+ callasm SelectMenu
+ sjump SelectMenuCallback
+
+StartMenuCallback:
+SelectMenuCallback:
+ readmem hMenuReturn
+ ifequal HMENURETURN_SCRIPT, .Script
+ ifequal HMENURETURN_ASM, .Asm
+ end
+
+.Script:
+ memjump wQueuedScriptBank
+
+.Asm:
+ memcallasm wQueuedScriptBank
+ end
+
+CountStep:
+ ; Don't count steps in link communication rooms.
+ ld a, [wLinkMode]
+ and a
+ jr nz, .done
+
+ ; If there is a special phone call, don't count the step.
+ farcall CheckSpecialPhoneCall
+ jr c, .doscript
+
+ ; If Repel wore off, don't count the step.
+ call DoRepelStep
+ jr c, .doscript
+
+ ; Count the step for poison and total steps
+ ld hl, wPoisonStepCount
+ inc [hl]
+ ld hl, wStepCount
+ inc [hl]
+ ; Every 256 steps, increase the happiness of all your Pokemon.
+ jr nz, .skip_happiness
+
+ farcall StepHappiness
+
+.skip_happiness
+ ; Every 256 steps, offset from the happiness incrementor by 128 steps,
+ ; decrease the hatch counter of all your eggs until you reach the first
+ ; one that is ready to hatch.
+ ld a, [wStepCount]
+ cp $80
+ jr nz, .skip_egg
+
+ farcall DoEggStep
+ jr nz, .hatch
+
+.skip_egg
+ ; Increase the EXP of (both) DayCare Pokemon by 1.
+ farcall DayCareStep
+
+ ; Every four steps, deal damage to all Poisoned Pokemon
+ ld hl, wPoisonStepCount
+ ld a, [hl]
+ cp 4
+ jr c, .skip_poison
+ ld [hl], 0
+
+ farcall DoPoisonStep
+ jr c, .doscript
+
+.skip_poison
+ farcall DoBikeStep
+
+.done
+ xor a
+ ret
+
+.doscript
+ ld a, -1
+ scf
+ ret
+
+.hatch
+ ld a, PLAYEREVENT_HATCH
+ scf
+ ret
+
+; unused
+.unreferenced
+ ld a, PLAYEREVENT_WHITEOUT
+ scf
+ ret
+
+DoRepelStep:
+ ld a, [wRepelEffect]
+ and a
+ ret z
+
+ dec a
+ ld [wRepelEffect], a
+ ret nz
+
+ ld a, BANK(RepelWoreOffScript)
+ ld hl, RepelWoreOffScript
+ call CallScript
+ scf
+ ret
+
+DoPlayerEvent:
+ ld a, [wScriptRunning]
+ and a
+ ret z
+
+ cp PLAYEREVENT_MAPSCRIPT ; run script
+ ret z
+
+ cp NUM_PLAYER_EVENTS
+ ret nc
+
+ ld c, a
+ ld b, 0
+ ld hl, PlayerEventScriptPointers
+ add hl, bc
+ add hl, bc
+ add hl, bc
+ ld a, [hli]
+ ld [wScriptBank], a
+ ld a, [hli]
+ ld [wScriptPos], a
+ ld a, [hl]
+ ld [wScriptPos + 1], a
+ ret
+
+PlayerEventScriptPointers:
+; entries correspond to PLAYEREVENT_* constants
+ dba Invalid_0x96b60 ; PLAYEREVENT_NONE
+ dba SeenByTrainerScript ; PLAYEREVENT_SEENBYTRAINER
+ dba TalkToTrainerScript ; PLAYEREVENT_TALKTOTRAINER
+ dba FindItemInBallScript ; PLAYEREVENT_ITEMBALL
+ dba EdgeWarpScript ; PLAYEREVENT_CONNECTION
+ dba WarpToNewMapScript ; PLAYEREVENT_WARP
+ dba FallIntoMapScript ; PLAYEREVENT_FALL
+ dba Script_OverworldWhiteout ; PLAYEREVENT_WHITEOUT
+ dba HatchEggScript ; PLAYEREVENT_HATCH
+ dba ChangeDirectionScript ; PLAYEREVENT_JOYCHANGEFACING
+ dba Invalid_0x96b60 ; (NUM_PLAYER_EVENTS)
+
+Invalid_0x96b60:
+ end
+
+; unused
+ end
+
+HatchEggScript:
+ callasm OverworldHatchEgg
+ end
+
+WarpToNewMapScript:
+ warpsound
+ newloadmap MAPSETUP_DOOR
+ end
+
+FallIntoMapScript:
+ newloadmap MAPSETUP_FALL
+ playsound SFX_KINESIS
+ applymovement PLAYER, MovementData_0x96c48
+ playsound SFX_STRENGTH
+ scall LandAfterPitfallScript
+ end
+
+MovementData_0x96c48:
+ skyfall
+ step_end
+
+LandAfterPitfallScript:
+ earthquake 16
+ end
+
+EdgeWarpScript: ; 4
+ reloadandreturn MAPSETUP_CONNECTION
+
+ChangeDirectionScript: ; 9
+ deactivatefacing 3
+ callasm EnableWildEncounters
+ end
+
+INCLUDE "engine/overworld/scripting.asm"
+
+WarpToSpawnPoint::
+ ld hl, wStatusFlags2
+ res STATUSFLAGS2_SAFARI_GAME_F, [hl]
+ res STATUSFLAGS2_BUG_CONTEST_TIMER_F, [hl]
+ ret
+
+RunMemScript::
+; If there is no script here, we don't need to be here.
+ ld a, [wMapReentryScriptQueueFlag]
+ and a
+ ret z
+; Execute the script at (wMapReentryScriptBank):(wMapReentryScriptAddress).
+ ld hl, wMapReentryScriptAddress
+ ld a, [hli]
+ ld h, [hl]
+ ld l, a
+ ld a, [wMapReentryScriptBank]
+ call CallScript
+ scf
+; Clear the buffer for the next script.
+ push af
+ xor a
+ ld hl, wMapReentryScriptQueueFlag
+ ld bc, 8
+ call ByteFill
+ pop af
+ ret
+
+LoadScriptBDE::
+; If there's already a script here, don't overwrite.
+ ld hl, wMapReentryScriptQueueFlag
+ ld a, [hl]
+ and a
+ ret nz
+; Set the flag
+ ld [hl], 1
+ inc hl
+; Load the script pointer b:de into (wMapReentryScriptBank):(wMapReentryScriptAddress)
+ ld [hl], b
+ inc hl
+ ld [hl], e
+ inc hl
+ ld [hl], d
+ scf
+ ret
+
+TryTileCollisionEvent::
+ call GetFacingTileCoord
+ ld [wFacingTileID], a
+ ld c, a
+ farcall CheckFacingTileForStdScript
+ jr c, .done
+
+ call CheckCutTreeTile
+ jr nz, .whirlpool
+ farcall TryCutOW
+ jr .done
+
+.whirlpool
+ ld a, [wFacingTileID]
+ call CheckWhirlpoolTile
+ jr nz, .waterfall
+ farcall TryWhirlpoolOW
+ jr .done
+
+.waterfall
+ ld a, [wFacingTileID]
+ call CheckWaterfallTile
+ jr nz, .headbutt
+ farcall TryWaterfallOW
+ jr .done
+
+.headbutt
+ ld a, [wFacingTileID]
+ call CheckHeadbuttTreeTile
+ jr nz, .surf
+ farcall TryHeadbuttOW
+ jr c, .done
+ jr .noevent
+
+.surf
+ farcall TrySurfOW
+ jr nc, .noevent
+ jr .done
+
+.noevent
+ xor a
+ ret
+
+.done
+ call PlayClickSFX
+ ld a, $ff
+ scf
+ ret
+
+RandomEncounter::
+; Random encounter
+
+ call CheckWildEncounterCooldown
+ jr c, .nope
+ call CanUseSweetScent
+ jr nc, .nope
+ ld hl, wStatusFlags2
+ bit STATUSFLAGS2_BUG_CONTEST_TIMER_F, [hl]
+ jr nz, .bug_contest
+ farcall TryWildEncounter
+ jr nz, .nope
+ jr .ok
+
+.bug_contest
+ call _TryWildEncounter_BugContest
+ jr nc, .nope
+ jr .ok_bug_contest
+
+.nope
+ ld a, 1
+ and a
+ ret
+
+.ok
+ ld a, BANK(WildBattleScript)
+ ld hl, WildBattleScript
+ jr .done
+
+.ok_bug_contest
+ ld a, BANK(BugCatchingContestBattleScript)
+ ld hl, BugCatchingContestBattleScript
+ jr .done
+
+.done
+ call CallScript
+ scf
+ ret
+
+WildBattleScript:
+ randomwildmon
+ startbattle
+ reloadmapafterbattle
+ end
+
+CanUseSweetScent::
+ ld hl, wStatusFlags
+ bit STATUSFLAGS_NO_WILD_ENCOUNTERS_F, [hl]
+ jr nz, .no
+ ld a, [wEnvironment]
+ cp CAVE
+ jr z, .ice_check
+ cp DUNGEON
+ jr z, .ice_check
+ farcall CheckGrassCollision
+ jr nc, .no
+
+.ice_check
+ ld a, [wPlayerStandingTile]
+ call CheckIceTile
+ jr z, .no
+ scf
+ ret
+
+.no
+ and a
+ ret
+
+_TryWildEncounter_BugContest:
+ call TryWildEncounter_BugContest
+ ret nc
+ call ChooseWildEncounter_BugContest
+ farcall CheckRepelEffect
+ ret
+
+ChooseWildEncounter_BugContest::
+; Pick a random mon out of ContestMons.
+
+.loop
+ call Random
+ cp 100 << 1
+ jr nc, .loop
+ srl a
+
+ ld hl, ContestMons
+ ld de, 4
+.CheckMon:
+ sub [hl]
+ jr c, .GotMon
+ add hl, de
+ jr .CheckMon
+
+.GotMon:
+ inc hl
+
+; Species
+ ld a, [hli]
+ ld [wTempWildMonSpecies], a
+
+; Min level
+ ld a, [hli]
+ ld d, a
+
+; Max level
+ ld a, [hl]
+
+ sub d
+ jr nz, .RandomLevel
+
+; If min and max are the same.
+ ld a, d
+ jr .GotLevel
+
+.RandomLevel:
+; Get a random level between the min and max.
+ ld c, a
+ inc c
+ call Random
+ ldh a, [hRandomAdd]
+ call SimpleDivide
+ add d
+
+.GotLevel:
+ ld [wCurPartyLevel], a
+
+ xor a
+ ret
+
+TryWildEncounter_BugContest:
+ ld a, [wPlayerStandingTile]
+ call CheckSuperTallGrassTile
+ ld b, 40 percent
+ jr z, .ok
+ ld b, 20 percent
+
+.ok
+ farcall ApplyMusicEffectOnEncounterRate
+ farcall ApplyCleanseTagEffectOnEncounterRate
+ call Random
+ ldh a, [hRandomAdd]
+ cp b
+ ret c
+ ld a, 1
+ and a
+ ret
+
+INCLUDE "data/wild/bug_contest_mons.asm"
+
+DoBikeStep::
+ nop
+ nop
+ ; If the bike shop owner doesn't have our number, or
+ ; if we've already gotten the call, we don't have to
+ ; be here.
+ ld hl, wStatusFlags2
+ bit STATUSFLAGS2_BIKE_SHOP_CALL_F, [hl]
+ jr z, .NoCall
+
+ ; If we're not on the bike, we don't have to be here.
+ ld a, [wPlayerState]
+ cp PLAYER_BIKE
+ jr nz, .NoCall
+
+ ; If we're not in an area of phone service, we don't
+ ; have to be here.
+ call GetMapPhoneService
+ and a
+ jr nz, .NoCall
+
+ ; Check the bike step count and check whether we've
+ ; taken 65536 of them yet.
+ ld hl, wBikeStep
+ ld a, [hli]
+ ld d, a
+ ld e, [hl]
+ cp 255
+ jr nz, .increment
+ ld a, e
+ cp 255
+ jr z, .dont_increment
+
+.increment
+ inc de
+ ld [hl], e
+ dec hl
+ ld [hl], d
+
+.dont_increment
+ ; If we've taken at least 1024 steps, have the bike
+ ; shop owner try to call us.
+ ld a, d
+ cp HIGH(1024)
+ jr c, .NoCall
+
+ ; If a call has already been queued, don't overwrite
+ ; that call.
+ ld a, [wSpecialPhoneCallID]
+ and a
+ jr nz, .NoCall
+
+ ; Queue the call.
+ ld a, SPECIALCALL_BIKESHOP
+ ld [wSpecialPhoneCallID], a
+ xor a
+ ld [wSpecialPhoneCallID + 1], a
+ ld hl, wStatusFlags2
+ res STATUSFLAGS2_BIKE_SHOP_CALL_F, [hl]
+ scf
+ ret
+
+.NoCall:
+ xor a
+ ret
+
+ClearCmdQueue::
+ ld hl, wCmdQueue
+ ld de, CMDQUEUE_ENTRY_SIZE
+ ld c, CMDQUEUE_CAPACITY
+ xor a
+.loop
+ ld [hl], a
+ add hl, de
+ dec c
+ jr nz, .loop
+ ret
+
+HandleCmdQueue::
+ ld hl, wCmdQueue
+ xor a
+.loop
+ ldh [hMapObjectIndexBuffer], a
+ ld a, [hl]
+ and a
+ jr z, .skip
+ push hl
+ ld b, h
+ ld c, l
+ call HandleQueuedCommand
+ pop hl
+
+.skip
+ ld de, CMDQUEUE_ENTRY_SIZE
+ add hl, de
+ ldh a, [hMapObjectIndexBuffer]
+ inc a
+ cp CMDQUEUE_CAPACITY
+ jr nz, .loop
+ ret
+
+Unreferenced_GetNthCmdQueueEntry:
+ ld hl, wCmdQueue
+ ld bc, CMDQUEUE_ENTRY_SIZE
+ call AddNTimes
+ ld b, h
+ ld c, l
+ ret
+
+WriteCmdQueue::
+ push bc
+ push de
+ call .GetNextEmptyEntry
+ ld d, h
+ ld e, l
+ pop hl
+ pop bc
+ ret c
+ ld a, b
+ ld bc, CMDQUEUE_ENTRY_SIZE - 1
+ call FarCopyBytes
+ xor a
+ ld [hl], a
+ ret
+
+.GetNextEmptyEntry:
+ ld hl, wCmdQueue
+ ld de, CMDQUEUE_ENTRY_SIZE
+ ld c, CMDQUEUE_CAPACITY
+.loop
+ ld a, [hl]
+ and a
+ jr z, .done
+ add hl, de
+ dec c
+ jr nz, .loop
+ scf
+ ret
+
+.done
+ ld a, CMDQUEUE_CAPACITY
+ sub c
+ and a
+ ret
+
+DelCmdQueue::
+ ld hl, wCmdQueue
+ ld de, CMDQUEUE_ENTRY_SIZE
+ ld c, CMDQUEUE_CAPACITY
+.loop
+ ld a, [hl]
+ cp b
+ jr z, .done
+ add hl, de
+ dec c
+ jr nz, .loop
+ and a
+ ret
+
+.done
+ xor a
+ ld [hl], a
+ scf
+ ret
+
+_DelCmdQueue:
+ ld hl, CMDQUEUE_TYPE
+ add hl, bc
+ ld [hl], 0
+ ret
+
+HandleQueuedCommand:
+ ld hl, CMDQUEUE_TYPE
+ add hl, bc
+ ld a, [hl]
+ cp NUM_CMDQUEUE_TYPES
+ jr c, .okay
+ xor a
+
+.okay
+ ld e, a
+ ld d, 0
+ ld hl, .Jumptable
+ add hl, de
+ add hl, de
+ add hl, de
+ ld a, [hli]
+ push af
+ ld a, [hli]
+ ld h, [hl]
+ ld l, a
+ pop af
+ rst FarCall
+ ret
+
+.Jumptable:
+ dba CmdQueue_Null
+ dba CmdQueue_Type2
+ dba CmdQueue_StoneTable
+ dba CmdQueue_Null2
+ dba CmdQueue_Type4
+
+CmdQueueAnonymousJumptable:
+ ld hl, CMDQUEUE_05
+ add hl, bc
+ ld a, [hl]
+ pop hl
+ rst JumpTable
+ ret
+
+CmdQueueAnonJT_Increment:
+ ld hl, CMDQUEUE_05
+ add hl, bc
+ inc [hl]
+ ret
+
+CmdQueueAnonJT_Decrement:
+ ld hl, CMDQUEUE_05
+ add hl, bc
+ dec [hl]
+ ret
+
+CmdQueue_Null:
+ ret
+
+CmdQueue_Type2:
+ call Function2ffe
+ ret
+
+CmdQueue_Type4:
+ call CmdQueueAnonymousJumptable
+ ; anonymous dw
+ dw .zero
+ dw .one
+
+.zero
+ ldh a, [hSCY]
+ ld hl, CMDQUEUE_04
+ add hl, bc
+ ld [hl], a
+ call CmdQueueAnonJT_Increment
+.one
+ ld hl, CMDQUEUE_ADDR
+ add hl, bc
+ ld a, [hl]
+ dec a
+ ld [hl], a
+ jr z, .finish
+ and 1
+ jr z, .add
+ ld hl, CMDQUEUE_02
+ add hl, bc
+ ldh a, [hSCY]
+ sub [hl]
+ ldh [hSCY], a
+ ret
+
+.add
+ ld hl, CMDQUEUE_02
+ add hl, bc
+ ldh a, [hSCY]
+ add [hl]
+ ldh [hSCY], a
+ ret
+
+.finish
+ ld hl, CMDQUEUE_04
+ add hl, bc
+ ld a, [hl]
+ ldh [hSCY], a
+ call _DelCmdQueue
+ ret
+
+CmdQueue_Null2:
+ ret
+
+CmdQueue_StoneTable:
+ ld de, wPlayerStruct
+ ld a, NUM_OBJECT_STRUCTS
+.loop
+ push af
+
+ ld hl, OBJECT_SPRITE
+ add hl, de
+ ld a, [hl]
+ and a
+ jr z, .next
+
+ ld hl, OBJECT_MOVEMENTTYPE
+ add hl, de
+ ld a, [hl]
+ cp SPRITEMOVEDATA_STRENGTH_BOULDER
+ jr nz, .next
+
+ ld hl, OBJECT_NEXT_TILE
+ add hl, de
+ ld a, [hl]
+ call CheckPitTile
+ jr nz, .next
+
+ ld hl, OBJECT_DIRECTION_WALKING
+ add hl, de
+ ld a, [hl]
+ cp STANDING
+ jr nz, .next
+ call HandleStoneQueue
+ jr c, .fall_down_hole
+
+.next
+ ld hl, OBJECT_LENGTH
+ add hl, de
+ ld d, h
+ ld e, l
+
+ pop af
+ dec a
+ jr nz, .loop
+ ret
+
+.fall_down_hole
+ pop af
+ ret
+
+INCLUDE "engine/events/trainer_scripts.asm"
diff --git a/engine/overworld/init_map.asm b/engine/overworld/init_map.asm
new file mode 100644
index 00000000..72950ac7
--- /dev/null
+++ b/engine/overworld/init_map.asm
@@ -0,0 +1,96 @@
+ReanchorBGMap_NoOAMUpdate::
+ call DelayFrame
+ ldh a, [hOAMUpdate]
+ push af
+
+ ld a, $1
+ ldh [hOAMUpdate], a
+ ldh a, [hBGMapMode]
+ push af
+ xor a
+ ldh [hBGMapMode], a
+
+ call .ReanchorBGMap
+
+ pop af
+ ldh [hBGMapMode], a
+ pop af
+ ldh [hOAMUpdate], a
+ ret
+
+.ReanchorBGMap:
+ xor a
+ ldh [hLCDCPointer], a
+ ldh [hBGMapMode], a
+ ld hl, wEnteredMapFromContinue
+ set 7, [hl]
+ res 2, [hl]
+ ld a, $90
+ ldh [hWY], a
+ call OverworldTextModeSwitch
+ ld a, HIGH(vBGMap1)
+ call .LoadBGMapAddrIntoHRAM
+ call _OpenAndCloseMenu_HDMATransferTilemapAndAttrmap
+ xor a
+ ldh [hBGMapMode], a
+ ldh [hWY], a
+ ld a, HIGH(vBGMap0)
+ call .LoadBGMapAddrIntoHRAM
+ call .WaitTransfer
+ xor a ; LOW(vBGMap0)
+ ld [wBGMapAnchor], a
+ ld a, HIGH(vBGMap0)
+ ld [wBGMapAnchor + 1], a
+ xor a
+ ldh [hSCX], a
+ ldh [hSCY], a
+ call ApplyBGMapAnchorToObjects
+ ret
+
+.LoadBGMapAddrIntoHRAM:
+ ldh [hBGMapAddress + 1], a
+ xor a
+ ldh [hBGMapAddress], a
+ ret
+
+.WaitTransfer:
+ ldh a, [hBGMapMode]
+ push af
+ xor a
+ ldh [hBGMapMode], a
+ ldh a, [hOAMUpdate]
+ push af
+ ld a, 1
+ ldh [hOAMUpdate], a
+ ld a, 3
+ ldh [hFF9E], a
+.asm_65bc
+ call DelayFrame
+ ldh a, [hFF9E]
+ and a
+ jr nz, .asm_65bc
+ pop af
+ ldh [hOAMUpdate], a
+ pop af
+ ldh [hBGMapMode], a
+ ret
+
+LoadFonts_NoOAMUpdate::
+ ldh a, [hOAMUpdate]
+ push af
+ ld a, $1
+ ldh [hOAMUpdate], a
+
+ call .LoadGFX
+
+ pop af
+ ldh [hOAMUpdate], a
+ ret
+
+.LoadGFX:
+ call LoadFontsExtra
+ ld a, $90
+ ldh [hWY], a
+ call SafeUpdateSprites
+ call LoadStandardFont
+ ret
diff --git a/engine/overworld/landmarks.asm b/engine/overworld/landmarks.asm
new file mode 100644
index 00000000..bee64c75
--- /dev/null
+++ b/engine/overworld/landmarks.asm
@@ -0,0 +1,82 @@
+GetLandmarkCoords:
+; Return coordinates (d, e) of landmark e.
+ push hl
+ ld l, e
+ ld h, 0
+ add hl, hl
+ add hl, hl
+ ld de, Landmarks
+ add hl, de
+ ld a, [hli]
+ ld e, a
+ ld d, [hl]
+ pop hl
+ ret
+
+GetLandmarkName::
+; Copy the name of landmark e to wStringBuffer1.
+ push hl
+ push de
+ push bc
+
+ ld l, e
+ ld h, 0
+ add hl, hl
+ add hl, hl
+ ld de, Landmarks + 2
+ add hl, de
+ ld a, [hli]
+ ld h, [hl]
+ ld l, a
+
+ ld de, wStringBuffer1
+ ld c, 18
+.copy
+ ld a, [hli]
+ ld [de], a
+ inc de
+ dec c
+ jr nz, .copy
+
+ pop bc
+ pop de
+ pop hl
+ ret
+
+INCLUDE "data/maps/landmarks.asm"
+
+RegionCheck:
+; Checks if the player is in Kanto or Johto.
+; If in Johto, returns 0 in e.
+; If in Kanto, returns 1 in e.
+ ld a, [wMapGroup]
+ ld b, a
+ ld a, [wMapNumber]
+ ld c, a
+ call GetWorldMapLocation
+ cp LANDMARK_FAST_SHIP ; S.S. Aqua
+ jr z, .johto
+ cp LANDMARK_SPECIAL
+ jr nz, .checkagain
+
+; In a special map, get the backup map group / map id
+ ld a, [wBackupMapGroup]
+ ld b, a
+ ld a, [wBackupMapNumber]
+ ld c, a
+ call GetWorldMapLocation
+
+.checkagain
+ cp KANTO_LANDMARK
+ jr c, .johto
+
+; Victory Road area is considered to be Johto.
+ cp LANDMARK_VICTORY_ROAD
+ jr c, .kanto
+
+.johto
+ ld e, JOHTO_REGION
+ ret
+.kanto
+ ld e, KANTO_REGION
+ ret
diff --git a/engine/overworld/load_map_part.asm b/engine/overworld/load_map_part.asm
new file mode 100644
index 00000000..23758f28
--- /dev/null
+++ b/engine/overworld/load_map_part.asm
@@ -0,0 +1,155 @@
+_LoadMapPart::
+ ld hl, wSurroundingTiles
+ ld a, [wMetatileStandingY]
+ and a
+ jr z, .top_row
+ ld bc, SURROUNDING_WIDTH * 2
+ add hl, bc
+
+.top_row
+ ld a, [wMetatileStandingX]
+ and a
+ jr z, .left_column
+ inc hl
+ inc hl
+
+.left_column
+ decoord 0, 0
+ ld b, SCREEN_HEIGHT
+.loop
+ ld c, SCREEN_WIDTH
+.loop2
+ ld a, [hli]
+ ld [de], a
+ inc de
+ dec c
+ jr nz, .loop2
+ ld a, l
+ add METATILE_WIDTH
+ ld l, a
+ jr nc, .carry
+ inc h
+
+.carry
+ dec b
+ jr nz, .loop
+ ret
+
+UnusedFunction153ba:
+ decoord 2, 2
+ ld bc, (SURROUNDING_WIDTH + 1) * 2
+ add hl, bc
+ ld c, SCREEN_HEIGHT - 4 * 1
+.loop:
+ ld b, SCREEN_WIDTH - SCREEN_META_WIDTH
+.loop2:
+ ld a, [hli]
+ ld [de], a
+ inc de
+ dec b
+ jr nz, .loop2
+ ld a, l
+ add SCREEN_META_WIDTH + METATILE_WIDTH
+ ld l, a
+ jr nc, .carry1
+ inc h
+
+.carry1:
+ ld a, e
+ add SCREEN_META_WIDTH
+ ld e, a
+ jr nc, .carry2
+ inc d
+
+.carry2:
+ dec c
+ jr nz, .loop
+ ret
+
+UnusedFunction153dd:
+ decoord 4, 4
+ ld bc, (SURROUNDING_WIDTH + 1) * 4
+ add hl, bc
+ ld c, SCREEN_HEIGHT - 4 * 2
+.loop:
+ ld b, SCREEN_WIDTH - SCREEN_META_WIDTH - METATILE_WIDTH
+.loop2:
+ ld a, [hli]
+ ld [de], a
+ inc de
+ dec b
+ jr nz, .loop2
+ ld a, l
+ add SCREEN_META_WIDTH + METATILE_WIDTH * 2
+ ld l, a
+ jr nc, .carry1
+ inc h
+
+.carry1:
+ ld a, e
+ add SCREEN_META_WIDTH + METATILE_WIDTH
+ ld e, a
+ jr nc, .carry2
+ inc d
+
+.carry2:
+ dec c
+ jr nz, .loop
+ ret
+
+UnusedFunction15400:
+ decoord 6, 6
+ ld bc, (SURROUNDING_WIDTH + 1) * 6
+ add hl, bc
+ ld c, SCREEN_HEIGHT - 4 * 3
+.loop:
+ ld b, SCREEN_WIDTH - SCREEN_META_WIDTH - METATILE_WIDTH * 2
+.loop2:
+ ld a, [hli]
+ ld [de], a
+ inc de
+ dec b
+ jr nz, .loop2
+ ld a, l
+ add SCREEN_META_WIDTH + METATILE_WIDTH * 3
+ ld l, a
+ jr nc, .carry1
+ inc h
+
+.carry1:
+ ld a, e
+ add SCREEN_META_WIDTH + METATILE_WIDTH * 2
+ ld e, a
+ jr nc, .carry2
+ inc d
+
+.carry2:
+ dec c
+ jr nz, .loop
+ ret
+
+UnusedFunction15423:
+ decoord 8, 8
+ ld bc, (SURROUNDING_WIDTH + 1) * 8
+ add hl, bc
+.loop
+ ld a, [hli]
+ ld [de], a
+ inc de
+ ld a, [hli]
+ ld [de], a
+ ld bc, SCREEN_WIDTH + 2
+ add hl, bc
+ ld a, e
+ add SCREEN_META_WIDTH + METATILE_WIDTH * 3 + 1
+ ld e, a
+ jr nc, .carry
+ inc d
+
+.carry:
+ ld a, [hli]
+ ld [de], a
+ inc de
+ ld a, [hli]
+ ld [de], a
+ ret
diff --git a/engine/overworld/map_object_action.asm b/engine/overworld/map_object_action.asm
index 553243c4..8f749f84 100755
--- a/engine/overworld/map_object_action.asm
+++ b/engine/overworld/map_object_action.asm
@@ -1,260 +1,264 @@
- ld hl, $b
- add hl, bc
- ld a, [hl]
- ld l, a
- ld h, $0
- add hl, hl
- add hl, hl
- add hl, de
- ld a, [hli]
- ld h, [hl]
- ld l, a
- call _hl_
- ret
+ObjectActionPairPointers:
+; entries correspond to OBJECT_ACTION_* constants
+ dw SetFacingStanding, SetFacingStanding
+ dw SetFacingStandAction, SetFacingCurrent
+ dw SetFacingStepAction, SetFacingCurrent
+ dw SetFacingBumpAction, SetFacingCurrent
+ dw SetFacingCounterclockwiseSpin, SetFacingCurrent
+ dw SetFacingCounterclockwiseSpin2, SetFacingStanding
+ dw SetFacingFish, SetFacingFish
+ dw SetFacingShadow, SetFacingStanding
+ dw SetFacingEmote, SetFacingEmote
+ dw SetFacingBigDollSym, SetFacingBigDollSym
+ dw SetFacingBounce, SetFacingFreezeBounce
+ dw SetFacingWeirdTree, SetFacingCurrent
+ dw SetFacingBigDollAsym, SetFacingBigDollAsym
+ dw SetFacingBigDoll, SetFacingBigDoll
+ dw SetFacingBoulderDust, SetFacingStanding
+ dw SetFacingGrassShake, SetFacingStanding
-Pointers4460:
- dw Function44a0, Function44a0
- dw Function44b2, Function44a7
- dw Function44be, Function44a7
- dw Function44e1, Function44a7
- dw Function4502, Function44a7
- dw Function4512, Function44a0
- dw Function4547, Function4547
- dw Function4554, Function44a0
- dw Function455b, Function455b
- dw Function4562, Function4562
- dw Function4569, Function457d
- dw Function4584, Function44a7
- dw Function4597, Function4597
- dw Function459e, Function459e
- dw Function45b3, Function44a0
- dw Function45c6, Function44a0
-
-Function44a0
- ld hl, $d
+SetFacingStanding:
+ ld hl, OBJECT_FACING_STEP
add hl, bc
- ld [hl], $ff
+ ld [hl], STANDING
ret
-Function44a7: ; 44a7 (1:44a7)
+SetFacingCurrent:
call GetSpriteDirection
- or $0
- ld hl, $d
+ or FACING_STEP_DOWN_0 ; useless
+ ld hl, OBJECT_FACING_STEP
add hl, bc
ld [hl], a
ret
-Function44b2:
- ld hl, $d
+SetFacingStandAction:
+ ld hl, OBJECT_FACING_STEP
add hl, bc
ld a, [hl]
- and $1
- jr nz, Function44be
- jp Function44a7
+ and 1
+ jr nz, SetFacingStepAction
+ jp SetFacingCurrent
-Function44be:
- ld hl, $4
+SetFacingStepAction:
+ ld hl, OBJECT_FLAGS1
add hl, bc
- bit 3, [hl]
- jp nz, Function44a7
- ld hl, $c
+ bit SLIDING_F, [hl]
+ jp nz, SetFacingCurrent
+
+ ld hl, OBJECT_STEP_FRAME
add hl, bc
ld a, [hl]
inc a
- and $f
+ and %00001111
ld [hl], a
+
rrca
rrca
- and $3
+ maskbits NUM_DIRECTIONS
ld d, a
+
call GetSpriteDirection
- or $0
+ or FACING_STEP_DOWN_0 ; useless
or d
- ld hl, $d
+ ld hl, OBJECT_FACING_STEP
add hl, bc
ld [hl], a
ret
-Function44e1:
- ld hl, $4
+SetFacingBumpAction:
+ ld hl, OBJECT_FLAGS1
add hl, bc
- bit 3, [hl]
- jp nz, Function44a7
- ld hl, $c
+ bit SLIDING_F, [hl]
+ jp nz, SetFacingCurrent
+
+ ld hl, OBJECT_STEP_FRAME
add hl, bc
inc [hl]
+
ld a, [hl]
rrca
rrca
rrca
- and $3
+ maskbits NUM_DIRECTIONS
ld d, a
+
call GetSpriteDirection
- or $0
+ or FACING_STEP_DOWN_0 ; useless
or d
- ld hl, $d
+ ld hl, OBJECT_FACING_STEP
add hl, bc
ld [hl], a
ret
-Function4502:
- call Function4518
- ld hl, $8
+SetFacingCounterclockwiseSpin:
+ call CounterclockwiseSpinAction
+ ld hl, OBJECT_FACING
add hl, bc
ld a, [hl]
- or $0
- ld hl, $d
+ or FACING_STEP_DOWN_0 ; useless
+ ld hl, OBJECT_FACING_STEP
add hl, bc
ld [hl], a
ret
-Function4512:
- call Function4518
- jp Function44a0
+SetFacingCounterclockwiseSpin2:
+ call CounterclockwiseSpinAction
+ jp SetFacingStanding
-Function4518: ; 4518 (1:4518)
- ld hl, $c
+CounterclockwiseSpinAction:
+; Here, OBJECT_STEP_FRAME consists of two 2-bit components,
+; using only bits 0,1 and 4,5.
+; bits 0,1 is a timer (4 overworld frames)
+; bits 4,5 determines the facing - the direction is counterclockwise.
+ ld hl, OBJECT_STEP_FRAME
add hl, bc
ld a, [hl]
- and $f0
+ and %11110000
ld e, a
+
ld a, [hl]
inc a
- and $f
+ and %00001111
ld d, a
- cp $4
- jr c, .asm_4531
- ld d, $0
+ cp 4
+ jr c, .ok
+
+ ld d, 0
ld a, e
add $10
- and $30
+ and %00110000
ld e, a
-.asm_4531
+
+.ok
ld a, d
or e
ld [hl], a
+
swap e
- ld d, $0
- ld hl, .directions
+ ld d, 0
+ ld hl, .Directions
add hl, de
ld a, [hl]
- ld hl, $8
+ ld hl, OBJECT_FACING
add hl, bc
ld [hl], a
ret
-.directions
+.Directions:
db OW_DOWN, OW_RIGHT, OW_UP, OW_LEFT
-Function4547:
+SetFacingFish:
call GetSpriteDirection
rrca
rrca
- add $10
- ld hl, $d
+ add FACING_FISH_DOWN
+ ld hl, OBJECT_FACING_STEP
add hl, bc
ld [hl], a
ret
-Function4554:
- ld hl, $d
+SetFacingShadow:
+ ld hl, OBJECT_FACING_STEP
add hl, bc
- ld [hl], $15
+ ld [hl], FACING_SHADOW
ret
-Function455b:
- ld hl, $d
+SetFacingEmote:
+ ld hl, OBJECT_FACING_STEP
add hl, bc
- ld [hl], $14
+ ld [hl], FACING_EMOTE
ret
-Function4562:
- ld hl, $d
+SetFacingBigDollSym:
+ ld hl, OBJECT_FACING_STEP
add hl, bc
- ld [hl], $17
+ ld [hl], FACING_BIG_DOLL_SYM
ret
-Function4569:
- ld hl, $c
+SetFacingBounce:
+ ld hl, OBJECT_STEP_FRAME
add hl, bc
ld a, [hl]
inc a
- and $f
+ and %00001111
ld [hl], a
- and $8
- jr z, Function457d
- ld hl, $d
+ and %00001000
+ jr z, SetFacingFreezeBounce
+ ld hl, OBJECT_FACING_STEP
add hl, bc
- ld [hl], $4
+ ld [hl], FACING_STEP_UP_0
ret
-Function457d:
- ld hl, $d
+SetFacingFreezeBounce:
+ ld hl, OBJECT_FACING_STEP
add hl, bc
- ld [hl], $0
+ ld [hl], FACING_STEP_DOWN_0
ret
-Function4584:
- ld hl, $c
+SetFacingWeirdTree:
+ ld hl, OBJECT_STEP_FRAME
add hl, bc
ld a, [hl]
inc a
ld [hl], a
- and $c
+ maskbits NUM_DIRECTIONS, 2
rrca
rrca
- add $18
- ld hl, $d
+ add FACING_WEIRD_TREE_0
+ ld hl, OBJECT_FACING_STEP
add hl, bc
ld [hl], a
ret
-Function4597:
- ld hl, $d
+SetFacingBigDollAsym:
+ ld hl, OBJECT_FACING_STEP
add hl, bc
- ld [hl], $16
+ ld [hl], FACING_BIG_DOLL_ASYM
ret
-Function459e:
- ld a, [wd558]
- ld d, $17
- cp $33
- jr z, .asm_45ad
- cp $47
- jr z, .asm_45ad
- ld d, $16
-.asm_45ad
- ld hl, $d
+SetFacingBigDoll:
+ ld a, [wVariableSprites + SPRITE_BIG_DOLL - SPRITE_VARS]
+ ld d, FACING_BIG_DOLL_SYM ; symmetric
+ cp SPRITE_BIG_SNORLAX
+ jr z, .ok
+ cp SPRITE_BIG_LAPRAS
+ jr z, .ok
+ ld d, FACING_BIG_DOLL_ASYM ; asymmetric
+
+.ok
+ ld hl, OBJECT_FACING_STEP
add hl, bc
ld [hl], d
ret
-Function45b3:
- ld hl, $c
+SetFacingBoulderDust:
+ ld hl, OBJECT_STEP_FRAME
add hl, bc
inc [hl]
ld a, [hl]
- ld hl, $d
+
+ ld hl, OBJECT_FACING_STEP
add hl, bc
- and $2
- ld a, $1c
- jr z, .asm_45c4
- inc a
-.asm_45c4
+ and 2
+ ld a, FACING_BOULDER_DUST_1
+ jr z, .ok
+ inc a ; FACING_BOULDER_DUST_2
+.ok
ld [hl], a
ret
-Function45c6:
- ld hl, $c
+SetFacingGrassShake:
+ ld hl, OBJECT_STEP_FRAME
add hl, bc
inc [hl]
ld a, [hl]
- ld hl, $d
+ ld hl, OBJECT_FACING_STEP
add hl, bc
- and $4
- ld a, $1e
- jr z, .asm_45d7
- inc a
-.asm_45d7
+ and 4
+ ld a, FACING_GRASS_1
+ jr z, .ok
+ inc a ; FACING_GRASS_2
+
+.ok
ld [hl], a
ret
diff --git a/engine/overworld/map_objects.asm b/engine/overworld/map_objects.asm
index 887fb753..62b1df41 100755
--- a/engine/overworld/map_objects.asm
+++ b/engine/overworld/map_objects.asm
@@ -1,27 +1,28 @@
-INCLUDE "engine/facings.asm"
-SpriteMovementData:: INCLUDE "data/map_objects.asm"
+INCLUDE "data/sprites/facings.asm"
-DeleteMapObject:: ; 4358 (1:4358)
+INCLUDE "data/sprites/map_objects.asm"
+
+DeleteMapObject::
push bc
- ld hl, $1
+ ld hl, OBJECT_MAP_OBJECT_INDEX
add hl, bc
ld a, [hl]
push af
ld h, b
ld l, c
- ld bc, $28
+ ld bc, OBJECT_LENGTH
xor a
call ByteFill
pop af
- cp $ff
- jr z, .asm_437a
+ cp -1
+ jr z, .ok
bit 7, a
- jr nz, .asm_437a
+ jr nz, .ok
call GetMapObject
- ld hl, $0
+ ld hl, OBJECT_SPRITE
add hl, bc
- ld [hl], $ff
-.asm_437a
+ ld [hl], -1
+.ok
pop bc
ret
@@ -32,306 +33,322 @@ Function437c:
call .HandleObjectAction
ret
-.CheckObjectStillVisible: ; 4387 (1:4387)
- ld hl, $5
+.CheckObjectStillVisible:
+ ld hl, OBJECT_FLAGS2
add hl, bc
- res 6, [hl]
+ res OBJ_FLAGS2_6, [hl]
ld a, [wXCoord]
ld e, a
- ld hl, $10
+ ld hl, OBJECT_NEXT_MAP_X
add hl, bc
ld a, [hl]
- add $1
+ add 1
sub e
- jr c, .asm_43b3
- cp $c
- jr nc, .asm_43b3
+ jr c, .ok
+ cp MAPOBJECT_SCREEN_WIDTH
+ jr nc, .ok
ld a, [wYCoord]
ld e, a
- ld hl, $11
+ ld hl, OBJECT_NEXT_MAP_Y
add hl, bc
ld a, [hl]
- add $1
+ add 1
sub e
- jr c, .asm_43b3
- cp $b
- jr nc, .asm_43b3
- jr .asm_43dd
+ jr c, .ok
+ cp MAPOBJECT_SCREEN_HEIGHT
+ jr nc, .ok
+ jr .yes
-.asm_43b3
- ld hl, $5
+.ok
+ ld hl, OBJECT_FLAGS2
add hl, bc
- set 6, [hl]
+ set OBJ_FLAGS2_6, [hl]
ld a, [wXCoord]
ld e, a
- ld hl, $14
+ ld hl, OBJECT_INIT_X
add hl, bc
ld a, [hl]
- add $1
+ add 1
sub e
- jr c, .asm_43df
- cp $c
- jr nc, .asm_43df
+ jr c, .ok2
+ cp MAPOBJECT_SCREEN_WIDTH
+ jr nc, .ok2
ld a, [wYCoord]
ld e, a
- ld hl, $15
+ ld hl, OBJECT_INIT_Y
add hl, bc
ld a, [hl]
- add $1
+ add 1
sub e
- jr c, .asm_43df
- cp $b
- jr nc, .asm_43df
-.asm_43dd
+ jr c, .ok2
+ cp MAPOBJECT_SCREEN_HEIGHT
+ jr nc, .ok2
+.yes
and a
ret
-.asm_43df
- ld hl, $4
+.ok2
+ ld hl, OBJECT_FLAGS1
add hl, bc
- bit 1, [hl]
- jr nz, .asm_43ec
+ bit WONT_DELETE_F, [hl]
+ jr nz, .yes2
call DeleteMapObject
scf
ret
-.asm_43ec
- ld hl, $5
+.yes2
+ ld hl, OBJECT_FLAGS2
add hl, bc
- set 6, [hl]
+ set OBJ_FLAGS2_6, [hl]
and a
ret
-.HandleStepType: ; 43f4 (1:43f4)
- ld hl, $9
+.HandleStepType:
+ ld hl, OBJECT_STEP_TYPE
add hl, bc
ld a, [hl]
and a
- jr z, .asm_440a
- ld hl, $5
+ jr z, .zero
+ ld hl, OBJECT_FLAGS2
add hl, bc
- bit 5, [hl]
- jr nz, .asm_4427
- cp $1
- jr z, .asm_4415
- jr .asm_4422
+ bit OBJ_FLAGS2_5, [hl]
+ jr nz, .bit5
+ cp STEP_TYPE_SLEEP
+ jr z, .one
+ jr .ok3
-.asm_440a
+.zero
call ObjectMovementReset
- ld hl, $5
+ ld hl, OBJECT_FLAGS2
add hl, bc
- bit 5, [hl]
- jr nz, .asm_4427
-.asm_4415
+ bit OBJ_FLAGS2_5, [hl]
+ jr nz, .bit5
+.one
call MapObjectMovementPattern
- ld hl, $9
+ ld hl, OBJECT_STEP_TYPE
add hl, bc
ld a, [hl]
and a
ret z
- cp $1
+ cp STEP_TYPE_SLEEP
ret z
-.asm_4422
+.ok3
ld hl, StepTypesJumptable
rst JumpTable
ret
-.asm_4427
+.bit5
ret
-.HandleObjectAction: ; 4428 (1:4428)
- ld hl, $4
+.HandleObjectAction:
+ ld hl, OBJECT_FLAGS1
add hl, bc
- bit 0, [hl]
- jr nz, Function44a0
- ld hl, $5
+ bit INVISIBLE_F, [hl]
+ jr nz, SetFacingStanding
+ ld hl, OBJECT_FLAGS2
add hl, bc
- bit 6, [hl]
- jr nz, Function44a0
- bit 5, [hl]
+ bit OBJ_FLAGS2_6, [hl]
+ jr nz, SetFacingStanding
+ bit OBJ_FLAGS2_5, [hl]
jr nz, asm_4449
- ld de, Pointers4460
- jr asm_444e
+ ld de, ObjectActionPairPointers ; use first column
+ jr _HandleObjectAction
Function4441:
- ld hl, $4
+ ld hl, OBJECT_FLAGS1
add hl, bc
- bit 0, [hl]
- jr nz, Function44a0
-asm_4449
- ld de, Pointers4460 + 2
- jr asm_444e
+ bit INVISIBLE_F, [hl]
+ jr nz, SetFacingStanding
+asm_4449:
+ ld de, ObjectActionPairPointers + 2 ; use second column
+ jr _HandleObjectAction
+
+_HandleObjectAction:
+; call [4 * wObjectStructs[ObjInd, OBJECT_ACTION] + de]
+ ld hl, OBJECT_ACTION
+ add hl, bc
+ ld a, [hl]
+ ld l, a
+ ld h, 0
+ add hl, hl
+ add hl, hl
+ add hl, de
+ ld a, [hli]
+ ld h, [hl]
+ ld l, a
+ call _hl_
+ ret
-asm_444e
INCLUDE "engine/overworld/map_object_action.asm"
-CopyNextCoordsTileToStandingCoordsTile: ; 45d9 (1:45d9)
- ld hl, $10
+CopyNextCoordsTileToStandingCoordsTile:
+ ld hl, OBJECT_NEXT_MAP_X
add hl, bc
ld a, [hl]
- ld hl, $12
+ ld hl, OBJECT_MAP_X
add hl, bc
ld [hl], a
- ld hl, $11
+ ld hl, OBJECT_NEXT_MAP_Y
add hl, bc
ld a, [hl]
- ld hl, $13
+ ld hl, OBJECT_MAP_Y
add hl, bc
ld [hl], a
- ld hl, $e
+ ld hl, OBJECT_NEXT_TILE
add hl, bc
ld a, [hl]
- ld hl, $f
+ ld hl, OBJECT_STANDING_TILE
add hl, bc
ld [hl], a
- call SetGrassPriority
- ld hl, $e
+ call SetTallGrassFlags
+ ld hl, OBJECT_NEXT_TILE
add hl, bc
ld a, [hl]
call UselessAndA
ret
Function4603:
- ld hl, $12
+ ld hl, OBJECT_MAP_X
add hl, bc
ld a, [hl]
- ld hl, $10
+ ld hl, OBJECT_NEXT_MAP_X
add hl, bc
ld [hl], a
- ld hl, $13
+ ld hl, OBJECT_MAP_Y
add hl, bc
ld a, [hl]
- ld hl, $11
+ ld hl, OBJECT_NEXT_MAP_Y
add hl, bc
ld [hl], a
ret
-UpdateGrassPriority:
- ld hl, $5
+UpdateTallGrassFlags:
+ ld hl, OBJECT_FLAGS2
add hl, bc
- bit 3, [hl]
- jr z, .asm_4628
- ld hl, $e
+ bit OVERHEAD_F, [hl]
+ jr z, .ok
+ ld hl, OBJECT_NEXT_TILE
add hl, bc
ld a, [hl]
- call SetGrassPriority
-.asm_4628
- ld hl, $e
+ call SetTallGrassFlags
+.ok
+ ld hl, OBJECT_NEXT_TILE
add hl, bc
ld a, [hl]
call UselessAndA
- ret c
- ld hl, $f
+ ret c ; never happens
+ ld hl, OBJECT_STANDING_TILE
add hl, bc
ld a, [hl]
call UselessAndA
ret
-SetGrassPriority: ; 463a (1:463a)
+SetTallGrassFlags:
call CheckSuperTallGrassTile
- jr z, .asm_4644
+ jr z, .set
call CheckGrassTile
- jr c, .asm_464b
-.asm_4644
- ld hl, $5
+ jr c, .reset
+.set
+ ld hl, OBJECT_FLAGS2
add hl, bc
- set 3, [hl]
+ set OVERHEAD_F, [hl]
ret
-.asm_464b
- ld hl, $5
+.reset
+ ld hl, OBJECT_FLAGS2
add hl, bc
- res 3, [hl]
+ res OVERHEAD_F, [hl]
ret
-UselessAndA: ; 4652 (1:4652)
+UselessAndA:
and a
ret
EndSpriteMovement:
xor a
- ld hl, $c
+ ld hl, OBJECT_STEP_FRAME
add hl, bc
ld [hl], a
- ld hl, $1b
+ ld hl, OBJECT_MOVEMENT_BYTE_INDEX
add hl, bc
ld [hli], a
ld [hli], a
ld [hli], a
- ld [hl], a
- ld hl, $7
+ ld [hl], a ; OBJECT_1E
+ ld hl, OBJECT_DIRECTION_WALKING
add hl, bc
- ld [hl], $ff
+ ld [hl], STANDING
ret
InitStep:
- ld hl, $7
+ ld hl, OBJECT_DIRECTION_WALKING
add hl, bc
ld [hl], a
- ld hl, $4
+ ld hl, OBJECT_FLAGS1
add hl, bc
- bit 2, [hl]
+ bit FIXED_FACING_F, [hl]
jr nz, GetNextTile
add a
add a
- and $c
- ld hl, $8
+ and %00001100
+ ld hl, OBJECT_FACING
add hl, bc
ld [hl], a
GetNextTile:
call GetStepVector
- ld hl, $a
+ ld hl, OBJECT_STEP_DURATION
add hl, bc
ld [hl], a
ld a, d
call GetStepVectorSign
- ld hl, $12
+ ld hl, OBJECT_MAP_X
add hl, bc
add [hl]
- ld hl, $10
+ ld hl, OBJECT_NEXT_MAP_X
add hl, bc
ld [hl], a
ld d, a
ld a, e
call GetStepVectorSign
- ld hl, $13
+ ld hl, OBJECT_MAP_Y
add hl, bc
add [hl]
- ld hl, $11
+ ld hl, OBJECT_NEXT_MAP_Y
add hl, bc
ld [hl], a
ld e, a
push bc
call GetCoordTile
pop bc
- ld hl, $e
+ ld hl, OBJECT_NEXT_TILE
add hl, bc
ld [hl], a
ret
-AddStepVector: ; 46b0 (1:46b0)
+AddStepVector:
call GetStepVector
- ld hl, $17
+ ld hl, OBJECT_SPRITE_X
add hl, bc
ld a, [hl]
add d
ld [hl], a
- ld hl, $18
+ ld hl, OBJECT_SPRITE_Y
add hl, bc
ld a, [hl]
add e
ld [hl], a
ret
-GetStepVector: ; 46c2 (1:46c2)
- ld hl, $7
+GetStepVector:
+; Return (x, y, duration, speed) in (d, e, a, h).
+ ld hl, OBJECT_DIRECTION_WALKING
add hl, bc
ld a, [hl]
- and $f
+ and %00001111
add a
add a
ld l, a
- ld h, $0
+ ld h, 0
ld de, StepVectors
add hl, de
ld d, [hl]
@@ -342,7 +359,7 @@ GetStepVector: ; 46c2 (1:46c2)
ld h, [hl]
ret
-StepVectors: ; 46d9
+StepVectors:
; x, y, duration, speed
; slow
db 0, 1, 16, 1
@@ -360,19 +377,19 @@ StepVectors: ; 46d9
db -4, 0, 4, 4
db 4, 0, 4, 4
-GetStepVectorSign: ; 4709 (1:4709)
+GetStepVectorSign:
add a
- ret z
- ld a, $1
- ret nc
- ld a, $ff
- ret
+ ret z ; 0 or 128
+ ld a, 1
+ ret nc ; 1 - 127
+ ld a, -1
+ ret ; 129 - 255
UpdatePlayerStep:
- ld hl, $7
+ ld hl, OBJECT_DIRECTION_WALKING
add hl, bc
ld a, [hl]
- and $3
+ and %00000011
ld [wPlayerStepDirection], a
call AddStepVector
ld a, [wPlayerStepVectorX]
@@ -382,14 +399,14 @@ UpdatePlayerStep:
add e
ld [wPlayerStepVectorY], a
ld hl, wPlayerStepFlags
- set 5, [hl]
+ set PLAYERSTEP_CONTINUE_F, [hl]
ret
-Function4732:
+Unreferenced_Function4732:
push bc
ld e, a
- ld d, $0
- ld hl, $1
+ ld d, 0
+ ld hl, OBJECT_MAP_OBJECT_INDEX
add hl, bc
ld a, [hl]
call GetMapObject
@@ -398,40 +415,1480 @@ Function4732:
pop bc
ret
-INCLUDE "engine/movement_pattern.asm"
-INCLUDE "engine/step_types.asm"
-INCLUDE "engine/overworld/movement.asm"
+RestoreDefaultMovement:
+ ld hl, OBJECT_MAP_OBJECT_INDEX
+ add hl, bc
+ ld a, [hl]
+ cp -1
+ jr z, .ok
+ push bc
+ call GetMapObject
+ ld hl, MAPOBJECT_MOVEMENT
+ add hl, bc
+ ld a, [hl]
+ pop bc
+ ret
+
+.ok
+ ld a, SPRITEMOVEDATA_STANDING_DOWN
+ ret
-Function5429: ; 5429 (1:5429)
+ClearObjectMovementByteIndex:
+ ld hl, OBJECT_MOVEMENT_BYTE_INDEX
+ add hl, bc
+ ld [hl], 0
+ ret
+
+IncrementObjectMovementByteIndex:
+ ld hl, OBJECT_MOVEMENT_BYTE_INDEX
+ add hl, bc
+ inc [hl]
+ ret
+
+DecrementObjectMovementByteIndex:
+ ld hl, OBJECT_MOVEMENT_BYTE_INDEX
+ add hl, bc
+ dec [hl]
+ ret
+
+MovementAnonymousJumptable:
+ ld hl, OBJECT_MOVEMENT_BYTE_INDEX
+ add hl, bc
+ ld a, [hl]
+ pop hl
+ rst JumpTable
+ ret
+
+ClearObjectStructField1c:
+ ld hl, OBJECT_1C
+ add hl, bc
+ ld [hl], 0
+ ret
+
+IncrementObjectStructField1c:
+ ld hl, OBJECT_1C
+ add hl, bc
+ inc [hl]
+ ret
+
+Field1cAnonymousJumptable:
+ ld hl, OBJECT_1C
+ add hl, bc
+ ld a, [hl]
+ pop hl
+ rst JumpTable
+ ret
+
+GetValueObjectStructField1c:
+ ld hl, OBJECT_1C
+ add hl, bc
+ ld a, [hl]
+ ret
+
+SetValueObjectStructField1c:
+ ld hl, OBJECT_1C
+ add hl, bc
+ ld [hl], a
+ ret
+
+ObjectMovementReset:
+ ld hl, OBJECT_NEXT_MAP_X
+ add hl, bc
+ ld d, [hl]
+ ld hl, OBJECT_NEXT_MAP_Y
+ add hl, bc
+ ld e, [hl]
+ push bc
+ call GetCoordTile
+ pop bc
+ ld hl, OBJECT_NEXT_TILE
+ add hl, bc
+ ld [hl], a
+ call CopyNextCoordsTileToStandingCoordsTile
+ call EndSpriteMovement
+ ld hl, OBJECT_STEP_TYPE
+ add hl, bc
+ ld [hl], STEP_TYPE_SLEEP
+ ret
+
+MapObjectMovementPattern:
+ call ClearObjectStructField1c
+ call GetSpriteMovementFunction
+ ld a, [hl]
+ ld hl, .Pointers
+ rst JumpTable
+ ret
+
+.Pointers:
+; entries correspond to SPRITEMOVEFN_* constants
+ dw .Null_00 ; 00
+ dw .RandomWalkY ; 01
+ dw .RandomWalkX ; 02
+ dw .RandomWalkXY ; 03
+ dw .RandomSpin1 ; 04
+ dw .RandomSpin2 ; 05
+ dw .Standing ; 06
+ dw .ObeyDPad ; 07
+ dw .Movement08 ; 08
+ dw .Movement09 ; 09
+ dw .Movement0a ; 0a
+ dw .Movement0b ; 0b
+ dw .Movement0c ; 0c
+ dw .Movement0d ; 0d
+ dw .Movement0e ; 0e
+ dw .Follow ; 0f
+ dw .Script ; 10
+ dw .Strength ; 11
+ dw .FollowNotExact ; 12
+ dw .MovementShadow ; 13
+ dw .MovementEmote ; 14
+ dw .MovementBigStanding ; 15
+ dw .MovementBouncing ; 16
+ dw .MovementScreenShake ; 17
+ dw .MovementSpinClockwise ; 18
+ dw .MovementSpinCounterclockwise ; 19
+ dw .MovementBoulderDust ; 1a
+ dw .MovementShakingGrass ; 1b
+
+.Null_00:
+ ret
+
+.RandomWalkY:
+ call Random
+ ldh a, [hRandomAdd]
+ and %00000001
+ jp .RandomWalkContinue
+
+.RandomWalkX:
+ call Random
+ ldh a, [hRandomAdd]
+ and %00000001
+ or %00000010
+ jp .RandomWalkContinue
+
+.RandomWalkXY:
+ call Random
+ ldh a, [hRandomAdd]
+ and %00000011
+ jp .RandomWalkContinue
+
+.RandomSpin1:
+ call Random
+ ldh a, [hRandomAdd]
+ and %00001100
+ ld hl, OBJECT_FACING
+ add hl, bc
+ ld [hl], a
+ jp RandomStepDuration_Slow
+
+.RandomSpin2:
+ ld hl, OBJECT_FACING
+ add hl, bc
+ ld a, [hl]
+ and %00001100
+ ld d, a
+ call Random
+ ldh a, [hRandomAdd]
+ and %00001100
+ cp d
+ jr nz, .keep
+ xor %00001100
+.keep
+ ld [hl], a
+ jp RandomStepDuration_Fast
+
+.Standing:
+ call Function4603
+ call EndSpriteMovement
+ ld hl, OBJECT_ACTION
+ add hl, bc
+ ld [hl], OBJECT_ACTION_STAND
+ ld hl, OBJECT_STEP_TYPE
+ add hl, bc
+ ld [hl], STEP_TYPE_05
+ ret
+
+.ObeyDPad:
+ ld hl, Function4fa8
+ jp HandleMovementData
+
+.Movement08:
+ ld hl, Function4fbd
+ jp HandleMovementData
+
+.Movement09:
+ ld hl, Function4fce
+ jp HandleMovementData
+
+.Movement0a:
+ jp _GetMovementObject
+
+.Movement0b:
+ jp _GetMovementObject
+
+.Movement0c:
+ jp _GetMovementObject
+
+.Movement0d:
+ ld hl, Function4fa8
+ jp HandleMovementData
+
+.Movement0e:
+ jp _GetMovementObject
+
+.Follow:
+ ld hl, GetFollowerNextMovementByte
+ jp HandleMovementData
+
+.Script:
+ ld hl, GetMovementByte
+ jp HandleMovementData
+
+.Strength:
+ call MovementAnonymousJumptable
+ dw .Strength_Start
+ dw .Strength_Stop
+
+.Strength_Start:
+ ld hl, OBJECT_NEXT_TILE
+ add hl, bc
+ ld a, [hl]
+ call CheckPitTile
+ jr z, .on_pit
+ ld hl, OBJECT_FLAGS2
+ add hl, bc
+ bit OBJ_FLAGS2_2, [hl]
+ res OBJ_FLAGS2_2, [hl]
+ jr z, .ok
+ ld hl, OBJECT_RANGE
+ add hl, bc
+ ld a, [hl]
+ and %00000011
+ or 0
call InitStep
- ld hl, $1f
+ call CanObjectMoveInDirection
+ jr c, .ok2
+ ld de, SFX_STRENGTH
+ call PlaySFX
+ call SpawnStrengthBoulderDust
+ call UpdateTallGrassFlags
+ ld hl, OBJECT_STEP_TYPE
+ add hl, bc
+ ld [hl], STEP_TYPE_0F
+ ret
+
+.ok2
+ call Function4603
+.ok
+ ld hl, OBJECT_DIRECTION_WALKING
+ add hl, bc
+ ld [hl], STANDING
+ ret
+
+.on_pit
+ call IncrementObjectMovementByteIndex
+.Strength_Stop:
+ ld hl, OBJECT_DIRECTION_WALKING
+ add hl, bc
+ ld [hl], STANDING
+ ret
+
+.FollowNotExact:
+ ld hl, OBJECT_NEXT_MAP_X
+ add hl, bc
+ ld d, [hl]
+ ld hl, OBJECT_NEXT_MAP_Y
add hl, bc
- ld [hl], $0
- ld hl, $5
+ ld e, [hl]
+ ld hl, OBJECT_RANGE
+ add hl, bc
+ ld a, [hl]
+ push bc
+ call GetObjectStruct
+ ld hl, OBJECT_DIRECTION_WALKING
add hl, bc
- res 3, [hl]
- ld hl, $b
+ ld a, [hl]
+ cp STANDING
+ jr z, .standing
+ ld hl, OBJECT_MAP_X
+ add hl, bc
+ ld a, [hl]
+ cp d
+ jr z, .equal
+ jr c, .less
+ ld a, 3
+ jr .done
+
+.less
+ ld a, 2
+ jr .done
+
+.equal
+ ld hl, OBJECT_MAP_Y
+ add hl, bc
+ ld a, [hl]
+ cp e
+ jr z, .standing
+ jr c, .less2
+ ld a, 0
+ jr .done
+
+.less2
+ ld a, 1
+.done
+ ld d, a
+ ld hl, OBJECT_DIRECTION_WALKING
+ add hl, bc
+ ld a, [hl]
+ and %00001100
+ or d
+ pop bc
+ jp NormalStep
+
+.standing
+ pop bc
+ ld hl, OBJECT_DIRECTION_WALKING
add hl, bc
- ld [hl], $2
- call Function54c8
+ ld [hl], STANDING
+ ld hl, OBJECT_ACTION
+ add hl, bc
+ ld [hl], OBJECT_ACTION_STAND
+ ret
+
+.MovementBigStanding:
+ call EndSpriteMovement
+ ld hl, OBJECT_DIRECTION_WALKING
+ add hl, bc
+ ld [hl], STANDING
+ ld hl, OBJECT_ACTION
+ add hl, bc
+ ld [hl], OBJECT_ACTION_BIG_DOLL_SYM
+ ld hl, OBJECT_STEP_TYPE
+ add hl, bc
+ ld [hl], STEP_TYPE_04
+ ret
+
+.MovementBouncing:
+ call EndSpriteMovement
+ ld hl, OBJECT_DIRECTION_WALKING
+ add hl, bc
+ ld [hl], STANDING
+ ld hl, OBJECT_ACTION
+ add hl, bc
+ ld [hl], OBJECT_ACTION_BOUNCE
+ ld hl, OBJECT_STEP_TYPE
+ add hl, bc
+ ld [hl], STEP_TYPE_04
+ ret
+
+.MovementSpinCounterclockwise:
+ call MovementAnonymousJumptable
+ dw .MovementSpinInit
+ dw .MovementSpinRepeat
+ dw .MovementSpinTurnLeft
+
+.MovementSpinClockwise:
+ call MovementAnonymousJumptable
+ dw .MovementSpinInit
+ dw .MovementSpinRepeat
+ dw .MovementSpinTurnRight
+
+.MovementSpinInit:
+ call EndSpriteMovement
+ call IncrementObjectMovementByteIndex
+.MovementSpinRepeat:
+ ld hl, OBJECT_ACTION
+ add hl, bc
+ ld [hl], OBJECT_ACTION_STAND
+ ld hl, OBJECT_RANGE
+ add hl, bc
+ ld a, [hl]
+ ld a, $10
+ ld hl, OBJECT_STEP_DURATION
+ add hl, bc
+ ld [hl], a
+ ld hl, OBJECT_STEP_TYPE
+ add hl, bc
+ ld [hl], STEP_TYPE_03
+ call IncrementObjectMovementByteIndex
+ ret
+
+.MovementSpinTurnLeft:
+ ld de, .DirectionData_Counterclockwise
+ call .MovementSpinNextFacing
+ jr .MovementSpinCounterclockwise
+
+.DirectionData_Counterclockwise:
+ db OW_RIGHT, OW_LEFT, OW_DOWN, OW_UP
+
+.MovementSpinTurnRight:
+ ld de, .DirectionData_Clockwise
+ call .MovementSpinNextFacing
+ jr .MovementSpinClockwise
+
+.DirectionData_Clockwise:
+ db OW_LEFT, OW_RIGHT, OW_UP, OW_DOWN
+
+.MovementSpinNextFacing:
+ ld hl, OBJECT_FACING
+ add hl, bc
+ ld a, [hl]
+ and %00001100
+ rrca
+ rrca
+ push hl
+ ld l, a
+ ld h, 0
+ add hl, de
+ ld a, [hl]
+ pop hl
+ ld [hl], a
+ call DecrementObjectMovementByteIndex
+ ret
+
+.MovementShadow:
+ call ._MovementShadow_Grass_Emote_BoulderDust
+ ld hl, OBJECT_ACTION
+ add hl, bc
+ ld [hl], OBJECT_ACTION_SHADOW
+ ld hl, OBJECT_STEP_DURATION
+ add hl, de
+ ld a, [hl]
+ inc a
+ add a
+ add 0
+ ld hl, OBJECT_STEP_DURATION
+ add hl, bc
+ ld [hl], a
+ ld hl, OBJECT_DIRECTION_WALKING
+ add hl, de
+ ld a, [hl]
+ maskbits NUM_DIRECTIONS
+ ld d, 1 * 8 + 6
+ cp DOWN
+ jr z, .ok_13
+ cp UP
+ jr z, .ok_13
+ ld d, 1 * 8 + 4
+.ok_13
+ ld hl, OBJECT_SPRITE_Y_OFFSET
+ add hl, bc
+ ld [hl], d
+ ld hl, OBJECT_SPRITE_X_OFFSET
+ add hl, bc
+ ld [hl], 0
+ ld hl, OBJECT_STEP_TYPE
+ add hl, bc
+ ld [hl], STEP_TYPE_TRACKING_OBJECT
+ ret
+
+.MovementEmote:
+ call EndSpriteMovement
+ call ._MovementShadow_Grass_Emote_BoulderDust
+ ld hl, OBJECT_ACTION
+ add hl, bc
+ ld [hl], OBJECT_ACTION_EMOTE
+ ld hl, OBJECT_STEP_DURATION
+ add hl, bc
+ ld [hl], 0
+ ld hl, OBJECT_SPRITE_Y_OFFSET
+ add hl, bc
+ ld [hl], -2 * 8
+ ld hl, OBJECT_SPRITE_X_OFFSET
+ add hl, bc
+ ld [hl], 0
+ ld hl, OBJECT_STEP_TYPE
+ add hl, bc
+ ld [hl], STEP_TYPE_TRACKING_OBJECT
+ ret
+
+.MovementBoulderDust:
+ call EndSpriteMovement
+ call ._MovementShadow_Grass_Emote_BoulderDust
+ ld hl, OBJECT_ACTION
+ add hl, bc
+ ld [hl], OBJECT_ACTION_BOULDER_DUST
+ ld hl, OBJECT_STEP_DURATION
+ add hl, de
+ ld a, [hl]
+ inc a
+ add a
+ ld hl, OBJECT_STEP_DURATION
+ add hl, bc
+ ld [hl], a
+ ld hl, OBJECT_DIRECTION_WALKING
+ add hl, de
+ ld a, [hl]
+ and %00000011
+ ld e, a
+ ld d, 0
+ ld hl, .data_4a81
+ add hl, de
+ add hl, de
+ ld d, [hl]
+ inc hl
+ ld e, [hl]
+ ld hl, OBJECT_SPRITE_X_OFFSET
+ add hl, bc
+ ld [hl], d
+ ld hl, OBJECT_SPRITE_Y_OFFSET
+ add hl, bc
+ ld [hl], e
+ ld hl, OBJECT_STEP_TYPE
+ add hl, bc
+ ld [hl], STEP_TYPE_TRACKING_OBJECT
+ ret
+
+.data_4a81
+ ; x, y
+ db 0, -4
+ db 0, 8
+ db 6, 2
+ db -6, 2
+
+.MovementShakingGrass:
+ call EndSpriteMovement
+ call ._MovementShadow_Grass_Emote_BoulderDust
+ ld hl, OBJECT_ACTION
+ add hl, bc
+ ld [hl], OBJECT_ACTION_GRASS_SHAKE
+ ld hl, OBJECT_STEP_DURATION
+ add hl, de
+ ld a, [hl]
+ add -1
+ ld hl, OBJECT_STEP_DURATION
+ add hl, bc
+ ld [hl], a
+ ld hl, OBJECT_STEP_TYPE
+ add hl, bc
+ ld [hl], STEP_TYPE_TRACKING_OBJECT
+ ret
+
+._MovementShadow_Grass_Emote_BoulderDust:
+ ld hl, OBJECT_RANGE
+ add hl, bc
+ ld a, [hl]
+ push bc
+ call GetObjectStruct
+ ld d, b
+ ld e, c
+ pop bc
+ ld hl, OBJECT_1D
+ add hl, bc
+ ld [hl], e
+ inc hl
+ ld [hl], d
+ ret
+
+.MovementScreenShake:
+ call EndSpriteMovement
+ ld hl, OBJECT_ACTION
+ add hl, bc
+ ld [hl], OBJECT_ACTION_00
+ ld hl, OBJECT_RANGE
+ add hl, bc
+ ld a, [hl]
+ call ._MovementScreenShake
+ ld hl, OBJECT_STEP_DURATION
+ add hl, bc
+ ld [hl], e
+ ld hl, OBJECT_1E
+ add hl, bc
+ ld [hl], a
+ ld hl, OBJECT_STEP_TYPE
+ add hl, bc
+ ld [hl], STEP_TYPE_15
+ ret
+
+._MovementScreenShake:
+ ld d, a
+ and %00111111
+ ld e, a
+ ld a, d
+ rlca
+ rlca
+ and %00000011
+ ld d, a
+ inc d
+ ld a, 1
+.loop
+ dec d
+ ret z
+ add a
+ jr .loop
+
+.RandomWalkContinue:
+ call InitStep
+ call CanObjectMoveInDirection ; check whether the object can move in that direction
+ jr c, .NewDuration
+ call UpdateTallGrassFlags
+ ld hl, OBJECT_ACTION
+ add hl, bc
+ ld [hl], OBJECT_ACTION_STEP
ld hl, wCenteredObject
ldh a, [hMapObjectIndexBuffer]
cp [hl]
- jr z, .asm_5450
- ld hl, $9
+ jr z, .load_6
+ ld hl, OBJECT_STEP_TYPE
+ add hl, bc
+ ld [hl], STEP_TYPE_07
+ ret
+
+.load_6
+ ld hl, OBJECT_STEP_TYPE
+ add hl, bc
+ ld [hl], STEP_TYPE_PLAYER_WALK
+ ret
+
+.NewDuration:
+ call EndSpriteMovement
+ call Function4603
+RandomStepDuration_Slow:
+ call Random
+ ldh a, [hRandomAdd]
+ and %01111111
+ jr SetRandomStepDuration
+
+RandomStepDuration_Fast:
+ call Random
+ ldh a, [hRandomAdd]
+ and %00011111
+SetRandomStepDuration:
+ ld hl, OBJECT_STEP_DURATION
+ add hl, bc
+ ld [hl], a
+ ld hl, OBJECT_DIRECTION_WALKING
+ add hl, bc
+ ld [hl], STANDING
+ ld hl, OBJECT_ACTION
+ add hl, bc
+ ld [hl], OBJECT_ACTION_STAND
+ ld hl, OBJECT_STEP_TYPE
+ add hl, bc
+ ld [hl], STEP_TYPE_03
+ ret
+
+StepTypesJumptable:
+; entries correspond to STEP_TYPE_* constants
+ dw ObjectMovementReset ; 00
+ dw MapObjectMovementPattern ; 01
+ dw NPCStep ; 02
+ dw StepType03 ; 03
+ dw StepType04 ; 04
+ dw StepType05 ; 05
+ dw PlayerStep ; 06
+ dw StepType07 ; 07
+ dw NPCJump ; 08
+ dw PlayerJump ; 09
+ dw PlayerOrNPCTurnStep ; 0a
+ dw StepTypeBump ; 0b
+ dw TeleportFrom ; 0c
+ dw TeleportTo ; 0d
+ dw Skyfall ; 0e
+ dw StepType0f ; 0f
+ dw GotBiteStep ; 10
+ dw RockSmashStep ; 11
+ dw ReturnDigStep ; 12
+ dw StepTypeTrackingObject ; 13
+ dw StepType14 ; 14
+ dw StepType15 ; 15
+ dw StepType16 ; 16
+ dw StepType17 ; 17
+ dw StepType18 ; 18
+
+WaitStep_InPlace:
+ ld hl, OBJECT_STEP_DURATION
+ add hl, bc
+ dec [hl]
+ ret nz
+ ld hl, OBJECT_STEP_TYPE
+ add hl, bc
+ ld [hl], STEP_TYPE_SLEEP
+ ret
+
+NPCJump:
+ call Field1cAnonymousJumptable
+; anonymous dw
+ dw .Jump
+ dw .Land
+
+.Jump:
+ call AddStepVector
+ call UpdateJumpPosition
+ ld hl, OBJECT_STEP_DURATION
+ add hl, bc
+ dec [hl]
+ ret nz
+ call CopyNextCoordsTileToStandingCoordsTile
+ call GetNextTile
+ ld hl, OBJECT_FLAGS2
add hl, bc
- ld [hl], $8
+ res OVERHEAD_F, [hl]
+ call IncrementObjectStructField1c
ret
-.asm_5450
- ld hl, $9
+.Land:
+ call AddStepVector
+ call UpdateJumpPosition
+ ld hl, OBJECT_STEP_DURATION
+ add hl, bc
+ dec [hl]
+ ret nz
+ call CopyNextCoordsTileToStandingCoordsTile
+ ld hl, OBJECT_STEP_TYPE
add hl, bc
- ld [hl], $9
+ ld [hl], STEP_TYPE_SLEEP
ret
-Function5457: ; 5457 (1:5457)
+
+PlayerJump:
+ call Field1cAnonymousJumptable
+; anonymous dw
+ dw .initjump
+ dw .stepjump
+ dw .initland
+ dw .stepland
+
+.initjump
+ ld hl, wPlayerStepFlags
+ set PLAYERSTEP_START_F, [hl]
+ call IncrementObjectStructField1c
+.stepjump
+ call UpdateJumpPosition
+ call UpdatePlayerStep
+ ld hl, OBJECT_STEP_DURATION
+ add hl, bc
+ dec [hl]
+ ret nz
+ call CopyNextCoordsTileToStandingCoordsTile
+ ld hl, OBJECT_FLAGS2
+ add hl, bc
+ res OVERHEAD_F, [hl]
+ ld hl, wPlayerStepFlags
+ set PLAYERSTEP_STOP_F, [hl]
+ set PLAYERSTEP_MIDAIR_F, [hl]
+ call IncrementObjectStructField1c
+ ret
+
+.initland
+ call GetNextTile
+ ld hl, wPlayerStepFlags
+ set PLAYERSTEP_START_F, [hl]
+ call IncrementObjectStructField1c
+.stepland
+ call UpdateJumpPosition
+ call UpdatePlayerStep
+ ld hl, OBJECT_STEP_DURATION
+ add hl, bc
+ dec [hl]
+ ret nz
+ ld hl, wPlayerStepFlags
+ set PLAYERSTEP_STOP_F, [hl]
+ call CopyNextCoordsTileToStandingCoordsTile
+ ld hl, OBJECT_STEP_TYPE
+ add hl, bc
+ ld [hl], STEP_TYPE_SLEEP
+ ret
+
+TeleportFrom:
+ call Field1cAnonymousJumptable
+; anonymous dw
+ dw .InitSpin
+ dw .DoSpin
+ dw .InitSpinRise
+ dw .DoSpinRise
+
+.InitSpin:
+ ld hl, OBJECT_STEP_FRAME
+ add hl, bc
+ ld [hl], 0
+ ld hl, OBJECT_STEP_DURATION
+ add hl, bc
+ ld [hl], 16
+ call IncrementObjectStructField1c
+.DoSpin:
+ ld hl, OBJECT_ACTION
+ add hl, bc
+ ld [hl], OBJECT_ACTION_SPIN
+ ld hl, OBJECT_STEP_DURATION
+ add hl, bc
+ dec [hl]
+ ret nz
+ call IncrementObjectStructField1c
+ ret
+
+.InitSpinRise:
+ ld hl, OBJECT_STEP_FRAME
+ add hl, bc
+ ld [hl], 0
+ ld hl, OBJECT_1F
+ add hl, bc
+ ld [hl], $10
+ ld hl, OBJECT_STEP_DURATION
+ add hl, bc
+ ld [hl], 16
+ ld hl, OBJECT_FLAGS2
+ add hl, bc
+ res OVERHEAD_F, [hl]
+ call IncrementObjectStructField1c
+.DoSpinRise:
+ ld hl, OBJECT_ACTION
+ add hl, bc
+ ld [hl], OBJECT_ACTION_SPIN
+ ld hl, OBJECT_1F
+ add hl, bc
+ inc [hl]
+ ld a, [hl]
+ ld d, $60
+ call Sine
+ ld a, h
+ sub $60
+ ld hl, OBJECT_SPRITE_Y_OFFSET
+ add hl, bc
+ ld [hl], a
+ ld hl, OBJECT_STEP_DURATION
+ add hl, bc
+ dec [hl]
+ ret nz
+ ld hl, OBJECT_STEP_FRAME
+ add hl, bc
+ ld [hl], 0
+ ld hl, OBJECT_STEP_TYPE
+ add hl, bc
+ ld [hl], STEP_TYPE_SLEEP
+ ret
+
+TeleportTo:
+ call Field1cAnonymousJumptable
+; anonymous dw
+ dw .InitWait
+ dw .DoWait
+ dw .InitDescent
+ dw .DoDescent
+ dw .InitFinalSpin
+ dw .DoFinalSpin
+ dw .FinishStep
+
+.InitWait:
+ ld hl, OBJECT_ACTION
+ add hl, bc
+ ld [hl], OBJECT_ACTION_00
+ ld hl, OBJECT_STEP_DURATION
+ add hl, bc
+ ld [hl], 16
+ call IncrementObjectStructField1c
+ ret
+
+.DoWait:
+ ld hl, OBJECT_STEP_DURATION
+ add hl, bc
+ dec [hl]
+ ret nz
+ call IncrementObjectStructField1c
+.InitDescent:
+ ld hl, OBJECT_STEP_FRAME
+ add hl, bc
+ ld [hl], 0
+ ld hl, OBJECT_1F
+ add hl, bc
+ ld [hl], 0
+ ld hl, OBJECT_STEP_DURATION
+ add hl, bc
+ ld [hl], 16
+ call IncrementObjectStructField1c
+ ret
+
+.DoDescent:
+ ld hl, OBJECT_ACTION
+ add hl, bc
+ ld [hl], OBJECT_ACTION_SPIN
+ ld hl, OBJECT_1F
+ add hl, bc
+ inc [hl]
+ ld a, [hl]
+ ld d, $60
+ call Sine
+ ld a, h
+ sub $60
+ ld hl, OBJECT_SPRITE_Y_OFFSET
+ add hl, bc
+ ld [hl], a
+ ld hl, OBJECT_STEP_DURATION
+ add hl, bc
+ dec [hl]
+ ret nz
+ call IncrementObjectStructField1c
+.InitFinalSpin:
+ ld hl, OBJECT_STEP_DURATION
+ add hl, bc
+ ld [hl], 16
+ call IncrementObjectStructField1c
+ ret
+
+.DoFinalSpin:
+ ld hl, OBJECT_ACTION
+ add hl, bc
+ ld [hl], OBJECT_ACTION_SPIN
+ ld hl, OBJECT_STEP_DURATION
+ add hl, bc
+ dec [hl]
+ ret nz
+.FinishStep:
+ ld hl, OBJECT_STEP_FRAME
+ add hl, bc
+ ld [hl], 0
+ ld hl, OBJECT_SPRITE_Y_OFFSET
+ add hl, bc
+ ld [hl], 0
+ ld hl, OBJECT_STEP_TYPE
+ add hl, bc
+ ld [hl], STEP_TYPE_SLEEP
+ ret
+
+Skyfall:
+ call Field1cAnonymousJumptable
+; anonymous dw
+ dw .Init
+ dw .Step
+ dw .Fall
+ dw .Finish
+
+.Init:
+ ld hl, OBJECT_ACTION
+ add hl, bc
+ ld [hl], OBJECT_ACTION_00
+ ld hl, OBJECT_STEP_DURATION
+ add hl, bc
+ ld [hl], 16
+ call IncrementObjectStructField1c
+.Step:
+ ld hl, OBJECT_STEP_DURATION
+ add hl, bc
+ dec [hl]
+ ret nz
+ ld hl, OBJECT_ACTION
+ add hl, bc
+ ld [hl], OBJECT_ACTION_STEP
+ ld hl, OBJECT_STEP_FRAME
+ add hl, bc
+ ld [hl], 0
+ ld hl, OBJECT_1F
+ add hl, bc
+ ld [hl], 0
+ ld hl, OBJECT_STEP_DURATION
+ add hl, bc
+ ld [hl], 16
+ call IncrementObjectStructField1c
+.Fall:
+ ld hl, OBJECT_1F
+ add hl, bc
+ inc [hl]
+ ld a, [hl]
+ ld d, $60
+ call Sine
+ ld a, h
+ sub $60
+ ld hl, OBJECT_SPRITE_Y_OFFSET
+ add hl, bc
+ ld [hl], a
+ ld hl, OBJECT_STEP_DURATION
+ add hl, bc
+ dec [hl]
+ ret nz
+ call IncrementObjectStructField1c
+.Finish:
+ ld hl, OBJECT_STEP_FRAME
+ add hl, bc
+ ld [hl], 0
+ ld hl, OBJECT_SPRITE_Y_OFFSET
+ add hl, bc
+ ld [hl], 0
+ ld hl, OBJECT_STEP_TYPE
+ add hl, bc
+ ld [hl], STEP_TYPE_SLEEP
+ ret
+
+GotBiteStep:
+ call Field1cAnonymousJumptable
+; anonymous dw
+ dw .Init
+ dw .Run
+
+.Init:
+ ld hl, OBJECT_STEP_DURATION
+ add hl, bc
+ ld [hl], 8
+ ld hl, OBJECT_SPRITE_Y_OFFSET
+ add hl, bc
+ ld [hl], 0
+ call IncrementObjectStructField1c
+.Run:
+ ld hl, OBJECT_SPRITE_Y_OFFSET
+ add hl, bc
+ ld a, [hl]
+ xor 1
+ ld [hl], a
+ ld hl, OBJECT_STEP_DURATION
+ add hl, bc
+ dec [hl]
+ ret nz
+ ld hl, OBJECT_SPRITE_Y_OFFSET
+ add hl, bc
+ ld [hl], 0
+ ld hl, OBJECT_STEP_TYPE
+ add hl, bc
+ ld [hl], STEP_TYPE_SLEEP
+ ret
+
+RockSmashStep:
+ call .Step
+ jp WaitStep_InPlace
+
+.Step:
+ ld hl, OBJECT_STEP_DURATION
+ add hl, bc
+ ld a, [hl]
+ and %00000001
+ ld a, OBJECT_ACTION_STAND
+ jr z, .yes
+ ld a, OBJECT_ACTION_00
+.yes
+ ld hl, OBJECT_ACTION
+ add hl, bc
+ ld [hl], a
+ ret
+
+ReturnDigStep:
+ ld hl, OBJECT_STEP_DURATION
+ add hl, bc
+ ld a, [hl]
+ and %00000001
+ ld a, OBJECT_ACTION_SPIN
+ jr z, .yes
+ ld a, OBJECT_ACTION_SPIN_FLICKER
+.yes
+ ld hl, OBJECT_ACTION
+ add hl, bc
+ ld [hl], a
+ jp WaitStep_InPlace
+
+StepType03:
+ ld hl, OBJECT_DIRECTION_WALKING
+ add hl, bc
+ ld [hl], STANDING
+ ld hl, OBJECT_STEP_DURATION
+ add hl, bc
+ dec [hl]
+ ret nz
+ ld hl, OBJECT_STEP_TYPE
+ add hl, bc
+ ld [hl], STEP_TYPE_SLEEP
+ ret
+
+StepType18:
+ ld hl, OBJECT_DIRECTION_WALKING
+ add hl, bc
+ ld [hl], STANDING
+ ld hl, OBJECT_STEP_DURATION
+ add hl, bc
+ dec [hl]
+ ret nz
+ jp DeleteMapObject
+
+StepTypeBump:
+ ld hl, OBJECT_STEP_DURATION
+ add hl, bc
+ dec [hl]
+ ret nz
+ ld hl, OBJECT_STEP_TYPE
+ add hl, bc
+ ld [hl], STEP_TYPE_SLEEP
+ ret
+
+StepType05:
+ call Field1cAnonymousJumptable
+; anonymous dw
+ dw .Reset
+ dw StepType04
+
+.Reset:
+ call RestoreDefaultMovement
+ call GetInitialFacing
+ ld hl, OBJECT_FACING
+ add hl, bc
+ ld [hl], a
+ call IncrementObjectStructField1c
+StepType04:
+ call Stubbed_Function4f5a
+ ld hl, OBJECT_DIRECTION_WALKING
+ add hl, bc
+ ld [hl], STANDING
+ ret
+
+NPCStep:
+ call Stubbed_Function4f5a
+ call AddStepVector
+ ld hl, OBJECT_STEP_DURATION
+ add hl, bc
+ dec [hl]
+ ret nz
+ call CopyNextCoordsTileToStandingCoordsTile
+ ld hl, OBJECT_DIRECTION_WALKING
+ add hl, bc
+ ld [hl], STANDING
+ ld hl, OBJECT_STEP_TYPE
+ add hl, bc
+ ld [hl], STEP_TYPE_SLEEP
+ ret
+
+StepType07:
+ call AddStepVector
+ ld hl, OBJECT_STEP_DURATION
+ add hl, bc
+ dec [hl]
+ ret nz
+ call CopyNextCoordsTileToStandingCoordsTile
+ jp RandomStepDuration_Slow
+
+PlayerStep:
+; AnimateStep?
+ call Field1cAnonymousJumptable
+; anonymous dw
+ dw .init
+ dw .step
+
+.init
+ ld hl, wPlayerStepFlags
+ set PLAYERSTEP_START_F, [hl]
+ call IncrementObjectStructField1c
+.step
+ call UpdatePlayerStep
+ ld hl, OBJECT_STEP_DURATION
+ add hl, bc
+ dec [hl]
+ ret nz
+ ld hl, wPlayerStepFlags
+ set PLAYERSTEP_STOP_F, [hl]
+ call CopyNextCoordsTileToStandingCoordsTile
+ ld hl, OBJECT_DIRECTION_WALKING
+ add hl, bc
+ ld [hl], STANDING
+ ld hl, OBJECT_STEP_TYPE
+ add hl, bc
+ ld [hl], STEP_TYPE_SLEEP
+ ret
+
+PlayerOrNPCTurnStep:
+ call Field1cAnonymousJumptable
+; anonymous dw
+ dw .init1
+ dw .step1
+ dw .init2
+ dw .step2
+
+.init1
+ ld hl, OBJECT_DIRECTION_WALKING
+ add hl, bc
+ ld [hl], STANDING
+ ld hl, OBJECT_STEP_FRAME
+ add hl, bc
+ ld a, [hl]
+ ld [hl], 2
+ ld hl, OBJECT_STEP_DURATION
+ add hl, bc
+ ld [hl], 2
+ call IncrementObjectStructField1c
+.step1
+ ld hl, OBJECT_STEP_DURATION
+ add hl, bc
+ dec [hl]
+ ret nz
+ call IncrementObjectStructField1c
+.init2
+ ld hl, OBJECT_1D ; new facing
+ add hl, bc
+ ld a, [hl]
+ ld hl, OBJECT_FACING
+ add hl, bc
+ ld [hl], a
+ ld hl, OBJECT_STEP_DURATION
+ add hl, bc
+ ld [hl], 2
+ call IncrementObjectStructField1c
+.step2
+ ld hl, OBJECT_STEP_DURATION
+ add hl, bc
+ dec [hl]
+ ret nz
+ ld hl, OBJECT_STEP_TYPE
+ add hl, bc
+ ld [hl], STEP_TYPE_SLEEP
+ ret
+
+StepType0f:
+ call AddStepVector
+ ld hl, OBJECT_STEP_DURATION
+ add hl, bc
+ dec [hl]
+ ret nz
+ push bc
+ ld hl, OBJECT_NEXT_MAP_X
+ add hl, bc
+ ld d, [hl]
+ ld hl, OBJECT_NEXT_MAP_Y
+ add hl, bc
+ ld e, [hl]
+ ld hl, OBJECT_MAP_OBJECT_INDEX
+ add hl, bc
+ ld a, [hl]
+ ld b, a
+ farcall CopyDECoordsToMapObject
+ pop bc
+ ld hl, OBJECT_FLAGS2
+ add hl, bc
+ res OBJ_FLAGS2_2, [hl]
+ call CopyNextCoordsTileToStandingCoordsTile
+ ld hl, OBJECT_DIRECTION_WALKING
+ add hl, bc
+ ld [hl], STANDING
+ ld hl, OBJECT_STEP_TYPE
+ add hl, bc
+ ld [hl], STEP_TYPE_SLEEP
+ ret
+
+StepTypeTrackingObject:
+ ld hl, OBJECT_1D
+ add hl, bc
+ ld e, [hl]
+ inc hl
+ ld d, [hl]
+ ld hl, OBJECT_SPRITE
+ add hl, de
+ ld a, [hl]
+ and a
+ jr z, .nope
+ ld hl, OBJECT_SPRITE_X
+ add hl, de
+ ld a, [hl]
+ ld hl, OBJECT_SPRITE_X
+ add hl, bc
+ ld [hl], a
+ ld hl, OBJECT_SPRITE_Y
+ add hl, de
+ ld a, [hl]
+ ld hl, OBJECT_SPRITE_Y
+ add hl, bc
+ ld [hl], a
+ ld hl, OBJECT_STEP_DURATION
+ add hl, bc
+ ld a, [hl]
+ and a
+ ret z
+ dec [hl]
+ ret nz
+.nope
+ jp DeleteMapObject
+
+StepType14:
+StepType15:
+ call Field1cAnonymousJumptable
+; anonymous dw
+ dw .Init
+ dw .Run
+
+.Init:
+ xor a
+ ld hl, OBJECT_1D
+ add hl, bc
+ ld [hl], a
+ call IncrementObjectStructField1c
+.Run:
+ ld hl, OBJECT_1D
+ add hl, bc
+ ld d, [hl]
+ ld a, [wPlayerStepVectorY]
+ sub d
+ ld [wPlayerStepVectorY], a
+ ld hl, OBJECT_STEP_DURATION
+ add hl, bc
+ dec [hl]
+ jr z, .ok
+ ld a, [hl]
+ call .GetSign
+ ld hl, OBJECT_1D
+ add hl, bc
+ ld [hl], a
+ ld d, a
+ ld a, [wPlayerStepVectorY]
+ add d
+ ld [wPlayerStepVectorY], a
+ ret
+
+.ok
+ call DeleteMapObject
+ ret
+
+.GetSign:
+ ld hl, OBJECT_1E
+ add hl, bc
+ and 1
+ ld a, [hl]
+ ret z
+ cpl
+ inc a
+ ret
+
+StepType16:
+ call Field1cAnonymousJumptable ; ????
+StepType17:
+ call Field1cAnonymousJumptable
+; anonymous dw
+ dw .null
+ dw .null
+ dw .null
+.null
+
+Stubbed_Function4f5a:
+ ret
+ ld hl, OBJECT_1D
+ add hl, bc
+ inc [hl]
+ ld a, [hl]
+ srl a
+ srl a
+ and %00000111
+ ld l, a
+ ld h, 0
+ ld de, .y
+ add hl, de
+ ld a, [hl]
+ ld hl, OBJECT_SPRITE_Y_OFFSET
+ add hl, bc
+ ld [hl], a
+ ret
+
+.y
+ db 0, -1, -2, -3, -4, -3, -2, -1
+UpdateJumpPosition:
+ call GetStepVector
+ ld a, h
+ ld hl, OBJECT_1F
+ add hl, bc
+ ld e, [hl]
+ add e
+ ld [hl], a
+ nop
+ srl e
+ ld d, 0
+ ld hl, .y
+ add hl, de
+ ld a, [hl]
+ ld hl, OBJECT_SPRITE_Y_OFFSET
+ add hl, bc
+ ld [hl], a
+ ret
+
+.y
+ db -4, -6, -8, -10, -11, -12, -12, -12
+ db -11, -10, -9, -8, -6, -4, 0, 0
+
+Function4fa8: ; unscripted?
+; copy [wPlayerNextMovement] to [wPlayerMovement]
+ ld a, [wPlayerNextMovement]
+ ld hl, wPlayerMovement
+ ld [hl], a
+; load [wPlayerNextMovement] with movement_step_sleep
+ ld a, movement_step_sleep
+ ld [wPlayerNextMovement], a
+; recover the previous value of [wPlayerNextMovement]
+ ld a, [hl]
+ ret
+
+GetMovementByte:
+ ld hl, wMovementDataBank
+ call _GetMovementByte
+ ret
+
+Function4fbd:
+ ld hl, OBJECT_MOVEMENT_BYTE_INDEX
+ add hl, bc
+ ld e, [hl]
+ inc [hl]
+ ld d, 0
+ ld hl, wMovementObject
+ ld a, [hli]
+ ld h, [hl]
+ ld l, a
+ add hl, de
+ ld a, [hl]
+ ret
+
+Function4fce:
+ ld hl, OBJECT_MOVEMENT_BYTE_INDEX
+ add hl, bc
+ ld e, [hl]
+ inc [hl]
+ ld d, 0
+ ld hl, wce8f
+ ld a, [hli]
+ ld h, [hl]
+ ld l, a
+ add hl, de
+ ld a, [hl]
+ ret
+
+_GetMovementObject:
+ ld hl, GetMovementObject
+ jp HandleMovementData
+
+GetMovementObject:
+ ld a, [wMovementObject]
+ ret
+
+HandleMovementData:
+ call .StorePointer
+.loop
+ xor a
+ ld [wMovementByteWasControlSwitch], a
+ call JumpMovementPointer
+ call DoMovementFunction
+ ld a, [wMovementByteWasControlSwitch]
+ and a
+ jr nz, .loop
+ ret
+
+.StorePointer:
+ ld a, l
+ ld [wMovementPointer], a
+ ld a, h
+ ld [wMovementPointer + 1], a
+ ret
+
+JumpMovementPointer:
+ ld hl, wMovementPointer
+ ld a, [hli]
+ ld h, [hl]
+ ld l, a
+ jp hl
+
+ContinueReadingMovement:
+ ld a, 1
+ ld [wMovementByteWasControlSwitch], a
+ ret
+
+DoMovementFunction:
+ push af
+ call ApplyMovementToFollower
+ pop af
+ ld hl, MovementPointers
+ rst JumpTable
+ ret
+
+INCLUDE "engine/overworld/movement.asm"
+
+ApplyMovementToFollower:
ld e, a
ld a, [wObjectFollow_Follower]
- cp $ff
+ cp -1
ret z
ld a, [wObjectFollow_Leader]
ld d, a
@@ -439,21 +1896,21 @@ Function5457: ; 5457 (1:5457)
cp d
ret nz
ld a, e
- cp $3e
+ cp movement_step_sleep
ret z
- cp $47
+ cp movement_step_end
ret z
- cp $4b
+ cp movement_step_4b
ret z
- cp $50
+ cp movement_step_bump
ret z
- cp $8
+ cp movement_slow_step
ret c
push af
ld hl, wFollowerMovementQueueLength
inc [hl]
ld e, [hl]
- ld d, $0
+ ld d, 0
ld hl, wFollowMovementQueue
add hl, de
pop af
@@ -464,143 +1921,149 @@ GetFollowerNextMovementByte:
ld hl, wFollowerMovementQueueLength
ld a, [hl]
and a
- jr z, .asm_54a2
- cp $ff
- jr z, .asm_54a2
+ jr z, .done
+ cp -1
+ jr z, .done
dec [hl]
ld e, a
- ld d, $0
+ ld d, 0
ld hl, wFollowMovementQueue
add hl, de
inc e
- ld a, $ff
-.asm_549b
+ ld a, -1
+.loop
ld d, [hl]
ld [hld], a
ld a, d
dec e
- jr nz, .asm_549b
+ jr nz, .loop
ret
-.asm_54a2
- call Function54a9
+.done
+ call .CancelFollowIfLeaderMissing
ret c
- ld a, $3e
+ ld a, movement_step_sleep
ret
-Function54a9: ; 54a9 (1:54a9)
+.CancelFollowIfLeaderMissing:
ld a, [wObjectFollow_Leader]
- cp $ff
- jr z, .asm_54bf
+ cp -1
+ jr z, .nope
push bc
call GetObjectStruct
- ld hl, $0
+ ld hl, OBJECT_SPRITE
add hl, bc
ld a, [hl]
pop bc
and a
- jr z, .asm_54bf
+ jr z, .nope
and a
ret
-.asm_54bf
- ld a, $ff
+.nope
+ ld a, -1
ld [wObjectFollow_Follower], a
- ld a, $47
+ ld a, movement_step_end
scf
ret
-Function54c8: ; 54c8 (1:54c8)
+SpawnShadow:
push bc
- ld de, .data
- call Function5558
- call Function554b
+ ld de, .ShadowObject
+ call CopyTempObjectData
+ call InitTempObject
pop bc
ret
-.data db $fc, PAL_OW_SILVER, SPRITEMOVEDATA_SHADOW
+.ShadowObject:
+ ; vtile, palette, movement
+ db $fc, PAL_OW_SILVER, SPRITEMOVEDATA_SHADOW
-Function54d7: ; 54d7 (1:54d7)
+SpawnStrengthBoulderDust:
push bc
- ld de, .data
- call Function5558
- call Function554b
+ ld de, .BoulderDustObject
+ call CopyTempObjectData
+ call InitTempObject
pop bc
ret
-.data db $fe, PAL_OW_SILVER, SPRITEMOVEDATA_BOULDERDUST
+.BoulderDustObject:
+ db $fe, PAL_OW_SILVER, SPRITEMOVEDATA_BOULDERDUST
-Function54e6: ; 54e6 (1:54e6)
+SpawnEmote:
push bc
- ld de, .data
- call Function5558
- call Function554b
+ ld de, .EmoteObject
+ call CopyTempObjectData
+ call InitTempObject
pop bc
ret
-.data db $f8, PAL_OW_SILVER, SPRITEMOVEDATA_EMOTE
+.EmoteObject:
+ db $f8, PAL_OW_SILVER, SPRITEMOVEDATA_EMOTE
-Function54f5: ; 54f5 (1:54f5)
+ShakeGrass:
push bc
- ld de, .data
- call Function5558
- call Function554b
+ ld de, .GrassObject
+ call CopyTempObjectData
+ call InitTempObject
pop bc
ret
-.data db $fe, PAL_OW_TREE, SPRITEMOVEDATA_GRASS
+.GrassObject
+ db $fe, PAL_OW_TREE, SPRITEMOVEDATA_GRASS
-Function5504: ; 5504 (1:5504)
+ShakeScreen:
push bc
push af
- ld de, .data
- call Function5558
+ ld de, .ScreenShakeObject
+ call CopyTempObjectData
pop af
- ld [wce9e], a
- call Function554b
+ ld [wTempObjectCopyRange], a
+ call InitTempObject
pop bc
ret
-.data db $00, PAL_OW_SILVER, SPRITEMOVEDATA_SCREENSHAKE
+.ScreenShakeObject:
+ db $00, PAL_OW_SILVER, SPRITEMOVEDATA_SCREENSHAKE
-Function5518: ; 5518 (1:5518)
+DespawnEmote:
push bc
ldh a, [hMapObjectIndexBuffer]
ld c, a
- call Function5521
+ call .DeleteEmote
pop bc
ret
-Function5521: ; 5521 (1:5521)
- ld de, wPlayerStruct
- ld a, $d
-.asm_5526
+.DeleteEmote:
+ ld de, wObjectStructs
+ ld a, NUM_OBJECT_STRUCTS
+.loop
push af
- ld hl, $4
+ ld hl, OBJECT_FLAGS1
add hl, de
- bit 7, [hl]
- jr z, .asm_5540
- ld hl, $0
+ bit EMOTE_OBJECT_F, [hl]
+ jr z, .next
+ ld hl, OBJECT_SPRITE
add hl, de
ld a, [hl]
and a
- jr z, .asm_5540
+ jr z, .next
push bc
xor a
- ld bc, $28
+ ld bc, OBJECT_LENGTH
call ByteFill
pop bc
-.asm_5540
- ld hl, $28
+.next
+ ld hl, OBJECT_LENGTH
add hl, de
ld d, h
ld e, l
pop af
dec a
- jr nz, .asm_5526
+ jr nz, .loop
ret
-Function554b: ; 554b (1:554b)
+InitTempObject:
call FindFirstEmptyObjectStruct
ret nc
ld d, h
@@ -608,11 +2071,14 @@ Function554b: ; 554b (1:554b)
farcall CopyTempObjectToObjectStruct
ret
-Function5558: ; 5558 (1:5558)
- ld hl, wce99
- ld [hl], $ff
+CopyTempObjectData:
+; load into wTempObjectCopy:
+; -1, -1, [de], [de + 1], [de + 2], [hMapObjectIndexBuffer], [NextMapX], [NextMapY], -1
+; This spawns the object at the same place as whichever object is loaded into bc.
+ ld hl, wTempObjectCopyMapObjectIndex
+ ld [hl], -1
inc hl
- ld [hl], $ff
+ ld [hl], -1
inc hl
ld a, [de]
inc de
@@ -625,10 +2091,10 @@ Function5558: ; 5558 (1:5558)
ldh a, [hMapObjectIndexBuffer]
ld [hli], a
push hl
- ld hl, $10
+ ld hl, OBJECT_NEXT_MAP_X
add hl, bc
ld d, [hl]
- ld hl, $11
+ ld hl, OBJECT_NEXT_MAP_Y
add hl, bc
ld e, [hl]
pop hl
@@ -636,56 +2102,57 @@ Function5558: ; 5558 (1:5558)
inc hl
ld [hl], e
inc hl
- ld [hl], $ff
+ ld [hl], -1
ret
-Function557f:: ; 557f (1:557f)
+Function557f::
ld a, [wVramState]
bit 0, a
ret z
- ld bc, wPlayerStruct
+ ld bc, wObjectStructs
xor a
-.asm_5589
- ldh [hConnectionStripLength], a
+.loop
+ ldh [hMapObjectIndexBuffer], a
call DoesObjectHaveASprite
- jr z, .asm_5593
+ jr z, .ok
call Function55ef
-.asm_5593
- ld hl, $28
+.ok
+ ld hl, OBJECT_LENGTH
add hl, bc
ld b, h
ld c, l
ldh a, [hMapObjectIndexBuffer]
inc a
- cp $d
- jr nz, .asm_5589
+ cp NUM_OBJECT_STRUCTS
+ jr nz, .loop
ret
-Function55a1
- call Function55d8
- ld a, $0
- call Function55bc
- ld a, [wd180]
+Function55a1:
+; called at battle start
+ call Function55d8 ; clear sprites
+ ld a, PLAYER
+ call Function55bc ; respawn player
+ ld a, [wBattleScriptFlags]
bit 7, a
- jr z, .asm_55b8
+ jr z, .ok
ldh a, [hLastTalked]
and a
- jr z, .asm_55b8
- call Function55bc
-.asm_55b8
+ jr z, .ok
+ call Function55bc ; respawn opponent
+.ok
call _UpdateSprites
ret
-Function55bc: ; 55bc (1:55bc)
- cp $10
+Function55bc:
+ cp NUM_OBJECTS
ret nc
call GetMapObject
- ld hl, $0
+ ld hl, MAPOBJECT_OBJECT_STRUCT_ID
add hl, bc
ld a, [hl]
- cp $ff
+ cp -1
ret z
- cp $d
+ cp NUM_OBJECT_STRUCTS
ret nc
call GetObjectStruct
call DoesObjectHaveASprite
@@ -693,209 +2160,211 @@ Function55bc: ; 55bc (1:55bc)
call Function5606
ret
-Function55d8: ; 55d8 (1:55d8)
+Function55d8:
xor a
- ld bc, wPlayerStruct
-.asm_55dc
+ ld bc, wObjectStructs
+.loop
ldh [hMapObjectIndexBuffer], a
- call Function5613
- ld hl, $28
+ call SetFacing_Standing
+ ld hl, OBJECT_LENGTH
add hl, bc
ld b, h
ld c, l
- ldh a, [hConnectionStripLength]
+ ldh a, [hMapObjectIndexBuffer]
inc a
- cp $d
- jr nz, .asm_55dc
+ cp NUM_OBJECT_STRUCTS
+ jr nz, .loop
ret
-Function55ef: ; 55ef (1:55ef)
+Function55ef:
push bc
call Function5660
pop bc
- jr c, Function5613
+ jr c, SetFacing_Standing
call Function5636
- jr c, Function5613
+ jr c, SetFacing_Standing
call Function561b
- farcall Function4441 ; same bank
+ farcall Function4441
xor a
ret
-Function5606: ; 5606 (1:5606)
+Function5606:
call Function5636
- jr c, Function5613
- farcall Function4441 ; same bank
+ jr c, SetFacing_Standing
+ farcall Function4441
xor a
ret
-Function5613: ; 5613 (1:5613)
- ld hl, $d
+SetFacing_Standing:
+ ld hl, OBJECT_FACING_STEP
add hl, bc
- ld [hl], $ff
+ ld [hl], STANDING
scf
ret
-Function561b: ; 561b (1:561b)
+Function561b:
push bc
- ld hl, $10
+ ld hl, OBJECT_NEXT_MAP_X
add hl, bc
ld d, [hl]
- ld hl, $11
+ ld hl, OBJECT_NEXT_MAP_Y
add hl, bc
ld e, [hl]
call GetCoordTile
pop bc
- ld hl, $e
+ ld hl, OBJECT_NEXT_TILE
add hl, bc
ld [hl], a
- farcall UpdateGrassPriority ; same bank
+ farcall UpdateTallGrassFlags ; no need to farcall
ret
-Function5636: ; 5636 (1:5636)
- ld hl, $10
+Function5636:
+ ld hl, OBJECT_NEXT_MAP_X
add hl, bc
ld d, [hl]
- ld hl, $11
+ ld hl, OBJECT_NEXT_MAP_Y
add hl, bc
ld e, [hl]
inc d
inc e
ld a, [wXCoord]
cp d
- jr z, .asm_564f
- jr nc, .asm_565e
- add $b
+ jr z, .equal_x
+ jr nc, .nope
+ add MAPOBJECT_SCREEN_WIDTH - 1
cp d
- jr c, .asm_565e
-.asm_564f
+ jr c, .nope
+.equal_x
ld a, [wYCoord]
cp e
- jr z, .asm_565c
- jr nc, .asm_565e
- add $a
+ jr z, .equal_y
+ jr nc, .nope
+ add MAPOBJECT_SCREEN_HEIGHT - 1
cp e
- jr c, .asm_565e
-.asm_565c
+ jr c, .nope
+.equal_y
xor a
ret
-.asm_565e
+.nope
scf
ret
-Function5660: ; 5660 (1:5660)
- ld a, [wce81]
+Function5660:
+ ld a, [wPlayerBGMapOffsetX]
ld d, a
- ld hl, $19
+ ld hl, OBJECT_SPRITE_X_OFFSET
add hl, bc
ld a, [hl]
- ld hl, $17
+ ld hl, OBJECT_SPRITE_X
add hl, bc
add [hl]
add d
cp $f0
- jr nc, .asm_5678
+ jr nc, .ok1
cp $a0
- jp nc, Function56fb
-.asm_5678
- and $7
- ld d, $2
- cp $4
- jr c, .asm_5682
- ld d, $3
-.asm_5682
+ jp nc, .nope
+.ok1
+ and %00000111
+ ld d, 2
+ cp 4
+ jr c, .ok2
+ ld d, 3
+.ok2
ld a, [hl]
srl a
srl a
srl a
- cp $14
- jr c, .asm_568f
- sub $20
-.asm_568f
- ldh [hUsedSpriteIndex], a
- ld a, [wce82]
+ cp SCREEN_WIDTH
+ jr c, .ok3
+ sub BG_MAP_WIDTH
+.ok3
+ ldh [hCurSpriteXCoord], a
+ ld a, [wPlayerBGMapOffsetY]
ld e, a
- ld hl, $1a
+ ld hl, OBJECT_SPRITE_Y_OFFSET
add hl, bc
ld a, [hl]
- ld hl, $18
+ ld hl, OBJECT_SPRITE_Y
add hl, bc
add [hl]
add e
cp $f0
- jr nc, .asm_56a8
+ jr nc, .ok4
cp $90
- jr nc, Function56fb
-.asm_56a8
- and $7
- ld e, $2
- cp $4
- jr c, .asm_56b2
- ld e, $3
-.asm_56b2
+ jr nc, .nope
+.ok4
+ and %00000111
+ ld e, 2
+ cp 4
+ jr c, .ok5
+ ld e, 3
+.ok5
ld a, [hl]
srl a
srl a
srl a
- cp $12
- jr c, .asm_56bf
- sub $20
-.asm_56bf
- ldh [hUsedSpriteTile], a
- ld hl, $6
- add hl, bc
- bit 7, [hl]
- jr z, .asm_56d1
+ cp SCREEN_HEIGHT
+ jr c, .ok6
+ sub BG_MAP_HEIGHT
+.ok6
+ ldh [hCurSpriteYCoord], a
+ ld hl, OBJECT_PALETTE
+ add hl, bc
+ bit BIG_OBJECT_F, [hl]
+ jr z, .ok7
ld a, d
- add $2
+ add 2
ld d, a
ld a, e
- add $2
+ add 2
ld e, a
-.asm_56d1
+.ok7
ld a, d
- ldh [hFFC1], a
-.asm_56d4
- ldh a, [hFFC1]
+ ldh [hCurSpriteXPixel], a
+.loop
+ ldh a, [hCurSpriteXPixel]
ld d, a
- ldh a, [hUsedSpriteTile]
+ ldh a, [hCurSpriteYCoord]
add e
dec a
- cp $12
- jr nc, .asm_56f6
+ cp SCREEN_HEIGHT
+ jr nc, .ok9
ld b, a
-.asm_56e0
- ldh a, [hUsedSpriteIndex]
+.next
+ ldh a, [hCurSpriteXCoord]
add d
dec a
- cp $14
- jr nc, .asm_56f3
+ cp SCREEN_WIDTH
+ jr nc, .ok8
ld c, a
push bc
call Coord2Tile
pop bc
+; NPCs disappear if standing on tile $60-$7f (or $e0-$ff),
+; since those IDs are for text characters and textbox frames.
ld a, [hl]
- cp $60
- jr nc, Function56fb
-.asm_56f3
+ cp FIRST_REGULAR_TEXT_CHAR
+ jr nc, .nope
+.ok8
dec d
- jr nz, .asm_56e0
-.asm_56f6
+ jr nz, .next
+.ok9
dec e
- jr nz, .asm_56d4
+ jr nz, .loop
and a
ret
-Function56fb: ; 56fb (1:56fb)
+.nope
scf
ret
HandleNPCStep::
- call Function5704
- call Function5714
+ call .ResetStepVector
+ call .DoStepsForAllObjects
ret
-Function5704: ; 5704 (1:5704)
+.ResetStepVector:
xor a
ld [wPlayerStepVectorX], a
ld [wPlayerStepVectorY], a
@@ -904,257 +2373,261 @@ Function5704: ; 5704 (1:5704)
ld [wPlayerStepDirection], a
ret
-Function5714: ; 5714 (1:5714)
- ld bc, wPlayerSprite
+.DoStepsForAllObjects:
+ ld bc, wObjectStructs
xor a
-.asm_5718
+.loop
ldh [hMapObjectIndexBuffer], a
call DoesObjectHaveASprite
- jr z, .asm_5722
+ jr z, .next
call Function437c
-.asm_5722
- ld hl, $28
+.next
+ ld hl, OBJECT_LENGTH
add hl, bc
ld b, h
ld c, l
- ldh a, [hConnectionStripLength]
+ ldh a, [hMapObjectIndexBuffer]
inc a
- cp $d
- jr nz, .asm_5718
+ cp NUM_OBJECT_STRUCTS
+ jr nz, .loop
ret
-Function5730:: ; 5730 (1:5730)
- ld a, $3e
- ld [wce87], a
- ld [wce88], a
+RefreshPlayerSprite::
+ ld a, movement_step_sleep
+ ld [wPlayerNextMovement], a
+ ld [wPlayerMovement], a
xor a
- ld [wcf39], a
+ ld [wPlayerTurningDirection], a
ld [wPlayerObjectStepFrame], a
- call Function574f
- farcall Function14a44
- call c, Function5770
- call Function5761
+ call .TryResetPlayerAction
+ farcall CheckWarpFacingDown
+ call c, SpawnInFacingDown
+ call .SpawnInCustomFacing
ret
-Function574f: ; 574f (1:574f)
- ld hl, wd182
- bit 7, [hl]
- jr nz, .asm_575b
- bit 6, [hl]
- jr nz, .asm_575b
+.TryResetPlayerAction:
+ ld hl, wPlayerSpriteSetupFlags
+ bit PLAYERSPRITESETUP_RESET_ACTION_F, [hl]
+ jr nz, .ok
+ bit PLAYERSPRITESETUP_SKIP_RELOAD_GFX_F, [hl]
+ jr nz, .ok
ret
-.asm_575b
- ld a, $0
+.ok
+ ld a, OBJECT_ACTION_00
ld [wPlayerAction], a
ret
-Function5761: ; 5761 (1:5761)
- ld hl, wd182
- bit 5, [hl]
+.SpawnInCustomFacing:
+ ld hl, wPlayerSpriteSetupFlags
+ bit PLAYERSPRITESETUP_CUSTOM_FACING_F, [hl]
ret z
- ld a, [wd182]
- and $3
+ ld a, [wPlayerSpriteSetupFlags]
+ and PLAYERSPRITESETUP_FACING_MASK
add a
add a
- jr asm_5772
+ jr ContinueSpawnFacing
-Function5770: ; 5770 (1:5770)
- ld a, $0
-asm_5772
- ld bc, wObjectStructs
+SpawnInFacingDown:
+ ld a, DOWN
+ContinueSpawnFacing:
+ ld bc, wPlayerStruct
call SetSpriteDirection
ret
StartFollow::
push bc
ld a, b
- call Function578b
+ call SetLeaderIfVisible
pop bc
ret c
ld a, c
- call Function57a2
+ call SetFollowerIfVisible
farcall QueueFollowerFirstStep
ret
-Function578b: ; 578b (1:578b)
+SetLeaderIfVisible:
call CheckObjectVisibility
ret c
ldh a, [hObjectStructIndexBuffer]
ld [wObjectFollow_Leader], a
ret
-StopFollow:: ; 5795 (1:5795)
- call Function579c
- call Function57bd
+StopFollow::
+ call ResetLeader
+ call ResetFollower
ret
-Function579c: ; 579c (1:579c)
- ld a, $ff
+ResetLeader:
+ ld a, -1
ld [wObjectFollow_Leader], a
ret
-Function57a2: ; 57a2 (1:57a2)
+SetFollowerIfVisible:
push af
- call Function57bd
+ call ResetFollower
pop af
call CheckObjectVisibility
ret c
- ld hl, $3
+ ld hl, OBJECT_MOVEMENTTYPE
add hl, bc
- ld [hl], $13
- ld hl, $9
+ ld [hl], SPRITEMOVEDATA_FOLLOWING
+ ld hl, OBJECT_STEP_TYPE
add hl, bc
- ld [hl], $0
- ldh a, [hConnectedMapWidth]
+ ld [hl], STEP_TYPE_00
+ ldh a, [hObjectStructIndexBuffer]
ld [wObjectFollow_Follower], a
ret
-Function57bd: ; 57bd (1:57bd)
+ResetFollower:
ld a, [wObjectFollow_Follower]
- cp $ff
+ cp -1
ret z
call GetObjectStruct
- farcall Function5859 ; same bank
- ld a, $ff
+ farcall Function5859 ; no need to bankswitch
+ ld a, -1
ld [wObjectFollow_Follower], a
ret
-Function57d2:
+SetFlagsForMovement_1::
ld a, c
call CheckObjectVisibility
ret c
push bc
call Function57f0
pop bc
- ld hl, $5
+ ld hl, OBJECT_FLAGS2
add hl, bc
- res 5, [hl]
+ res OBJ_FLAGS2_5, [hl]
xor a
ret
Function57e4:
call CheckObjectVisibility
ret c
- ld hl, $5
+ ld hl, OBJECT_FLAGS2
add hl, bc
- set 5, [hl]
+ set OBJ_FLAGS2_5, [hl]
xor a
ret
-Function57f0: ; 57f0 (1:57f0)
- ld bc, wPlayerStruct
+Function57f0:
+ ld bc, wObjectStructs
xor a
-.asm_57f4
+.loop
push af
call DoesObjectHaveASprite
- jr z, .asm_5800
- ld hl, $5
+ jr z, .next
+ ld hl, OBJECT_FLAGS2
add hl, bc
- set 5, [hl]
-.asm_5800
- ld hl, $28
+ set OBJ_FLAGS2_5, [hl]
+.next
+ ld hl, OBJECT_LENGTH
add hl, bc
ld b, h
ld c, l
pop af
inc a
- cp $d
- jr nz, .asm_57f4
+ cp NUM_OBJECT_STRUCTS
+ jr nz, .loop
ret
-Function580d:
+_SetFlagsForMovement_2::
ld a, [wObjectFollow_Leader]
- cp $ff
+ cp -1
ret z
push bc
call GetObjectStruct
- ld hl, $1
+ ld hl, OBJECT_MAP_OBJECT_INDEX
add hl, bc
ld a, [hl]
pop bc
cp c
ret nz
ld a, [wObjectFollow_Follower]
- cp $ff
+ cp -1
ret z
call GetObjectStruct
- ld hl, $5
+ ld hl, OBJECT_FLAGS2
add hl, bc
- res 5, [hl]
+ res OBJ_FLAGS2_5, [hl]
ret
-Function582f:
+Function582f::
push bc
- ld bc, wPlayerSprite
+ ld bc, wObjectStructs
xor a
-.asm_5834
+.loop
push af
call DoesObjectHaveASprite
- jr z, .asm_5840
- ld hl, $5
+ jr z, .next
+ ld hl, OBJECT_FLAGS2
add hl, bc
- res 5, [hl]
-.asm_5840
- ld hl, $28
+ res OBJ_FLAGS2_5, [hl]
+.next
+ ld hl, OBJECT_LENGTH
add hl, bc
ld b, h
ld c, l
pop af
inc a
- cp $d
- jr nz, .asm_5834
+ cp NUM_OBJECT_STRUCTS
+ jr nz, .loop
pop bc
ret
Function584e:
call CheckObjectVisibility
ret c
- ld hl, $5
+ ld hl, OBJECT_FLAGS2
add hl, bc
- res 5, [hl]
+ res OBJ_FLAGS2_5, [hl]
ret
-Function5859:
- ld hl, $1
+Function5859::
+ ld hl, OBJECT_MAP_OBJECT_INDEX
add hl, bc
ld a, [hl]
- cp $ff
- jp z, Function5879
+ cp -1
+ jp z, Function5879 ; a jr would have been appropriate here
push bc
call GetMapObject
- ld hl, $4
+ ld hl, MAPOBJECT_MOVEMENT
add hl, bc
ld a, [hl]
pop bc
- ld hl, $3
+ ld hl, OBJECT_MOVEMENTTYPE
add hl, bc
ld [hl], a
- ld hl, $9
+ ld hl, OBJECT_STEP_TYPE
add hl, bc
- ld [hl], $0
+ ld [hl], STEP_TYPE_00
ret
-Function5879: ; 5879 (1:5879)
+Function5879:
call GetSpriteDirection
rrca
rrca
ld e, a
- ld d, $0
- ld hl, .data
+ ld d, 0
+ ld hl, .standing_movefns
add hl, de
ld a, [hl]
- ld hl, $3
+ ld hl, OBJECT_MOVEMENTTYPE
add hl, bc
ld [hl], a
- ld hl, $9
+ ld hl, OBJECT_STEP_TYPE
add hl, bc
- ld [hl], $0
+ ld [hl], STEP_TYPE_00
ret
-.data db 6,7,8,9
+.standing_movefns
+ db SPRITEMOVEDATA_STANDING_DOWN
+ db SPRITEMOVEDATA_STANDING_UP
+ db SPRITEMOVEDATA_STANDING_LEFT
+ db SPRITEMOVEDATA_STANDING_RIGHT
-_UpdateSprites:: ; 5896 (1:5896)
+_UpdateSprites::
ld a, [wVramState]
bit 0, a
ret z
@@ -1162,119 +2635,124 @@ _UpdateSprites:: ; 5896 (1:5896)
ldh [hUsedSpriteIndex], a
ldh a, [hOAMUpdate]
push af
- ld a, $1
+ ld a, 1
ldh [hOAMUpdate], a
- call Function58fe
- call Function58b0
+ call InitSprites
+ call .fill
pop af
ldh [hOAMUpdate], a
ret
-Function58b0: ; 58b0 (1:58b0)
- ld b, $a0
+.fill
+ ld b, OBJECT_LENGTH * SPRITEOAMSTRUCT_LENGTH
ldh a, [hUsedSpriteIndex]
cp b
ret nc
ld l, a
- ld h, wVirtualOAM / $100
- ld de, $4
+ ld h, HIGH(wVirtualOAM)
+ ld de, SPRITEOAMSTRUCT_LENGTH
ld a, b
- ld c, $a0
-.asm_58bf
- ld [hl], c
+ ld c, SCREEN_HEIGHT_PX + 2 * TILE_WIDTH
+.loop
+ ld [hl], c ; y
add hl, de
cp l
- jr nz, .asm_58bf
+ jr nz, .loop
ret
-ApplyBGMapAnchorToObjects:: ; 58c5 (1:58c5)
+ApplyBGMapAnchorToObjects::
push hl
push de
push bc
- ld a, [wce81]
+ ld a, [wPlayerBGMapOffsetX]
ld d, a
- ld a, [wce82]
+ ld a, [wPlayerBGMapOffsetY]
ld e, a
- ld bc, wPlayerStruct
- ld a, $d
-.asm_58d5
+ ld bc, wObjectStructs
+ ld a, NUM_OBJECT_STRUCTS
+.loop
push af
call DoesObjectHaveASprite
- jr z, .asm_58e9
- ld hl, $17
+ jr z, .skip
+ ld hl, OBJECT_SPRITE_X
add hl, bc
ld a, [hl]
add d
ld [hl], a
- ld hl, $18
+ ld hl, OBJECT_SPRITE_Y
add hl, bc
ld a, [hl]
add e
ld [hl], a
-.asm_58e9
- ld hl, $28
+.skip
+ ld hl, OBJECT_LENGTH
add hl, bc
ld b, h
ld c, l
pop af
dec a
- jr nz, .asm_58d5
+ jr nz, .loop
xor a
- ld [wce81], a
- ld [wce82], a
+ ld [wPlayerBGMapOffsetX], a
+ ld [wPlayerBGMapOffsetY], a
pop bc
pop de
pop hl
ret
-Function58fe: ; 58fe (1:58fe)
- call Function5911
- ld c, $30
- call Function5960
- ld c, $20
- call Function5960
- ld c, $10
- call Function5960
+PRIORITY_LOW EQU $10
+PRIORITY_NORM EQU $20
+PRIORITY_HIGH EQU $30
+
+InitSprites:
+ call .DeterminePriorities
+ ld c, PRIORITY_HIGH
+ call .InitSpritesByPriority
+ ld c, PRIORITY_NORM
+ call .InitSpritesByPriority
+ ld c, PRIORITY_LOW
+ call .InitSpritesByPriority
ret
-Function5911: ; 5911 (1:5911)
+.DeterminePriorities:
xor a
- ld hl, wce94
- ld bc, $d
+ ld hl, wMovementPointer
+ ld bc, NUM_OBJECT_STRUCTS
call ByteFill
- ld d, $0
+ ld d, 0
ld bc, wObjectStructs
- ld hl, wce94
-.asm_5923
+ ld hl, wMovementPointer
+.loop
push hl
call DoesObjectHaveASprite
- jr z, .asm_5946
- ld hl, $d
+ jr z, .skip
+ ld hl, OBJECT_FACING_STEP
add hl, bc
ld a, [hl]
- cp $ff
- jr z, .asm_5946
- ld e, $10
- ld hl, $5
- add hl, bc
- bit 0, [hl]
- jr nz, .asm_594f
- ld e, $20
- bit 1, [hl]
- jr z, .asm_594f
- ld e, $30
- jr .asm_594f
-
-.asm_5946
- ld hl, $28
+ cp STANDING
+ jr z, .skip
+; Define the sprite priority.
+ ld e, PRIORITY_LOW
+ ld hl, OBJECT_FLAGS2
+ add hl, bc
+ bit LOW_PRIORITY_F, [hl]
+ jr nz, .add
+ ld e, PRIORITY_NORM
+ bit HIGH_PRIORITY_F, [hl]
+ jr z, .add
+ ld e, PRIORITY_HIGH
+ jr .add
+
+.skip
+ ld hl, OBJECT_LENGTH
add hl, bc
ld b, h
ld c, l
pop hl
- jr .asm_5959
+ jr .next
-.asm_594f
- ld hl, $28
+.add
+ ld hl, OBJECT_LENGTH
add hl, bc
ld b, h
ld c, l
@@ -1282,157 +2760,158 @@ Function5911: ; 5911 (1:5911)
ld a, d
or e
ld [hli], a
-.asm_5959
+.next
inc d
ld a, d
- cp $d
- jr nz, .asm_5923
+ cp NUM_OBJECT_STRUCTS
+ jr nz, .loop
ret
-Function5960: ; 5960 (1:5960)
- ld hl, wce94
-.asm_5963
+.InitSpritesByPriority:
+ ld hl, wMovementPointer
+.next_sprite
ld a, [hli]
ld d, a
and $f0
ret z
cp c
- jr nz, .asm_5963
+ jr nz, .next_sprite
push bc
push hl
ld a, d
and $f
- call Function5a27
- call Function597a
+ call .GetObjectStructPointer
+ call .InitSprite
pop hl
pop bc
- jr .asm_5963
+ jr .next_sprite
-Function597a: ; 597a (1:597a)
+.InitSprite:
xor a
- ld hl, $5
+.skip1
+ ld hl, OBJECT_FLAGS2
add hl, bc
ld e, [hl]
- bit 7, e
- jr z, .asm_5986
- or $80
-.asm_5986
- bit 4, e
- jr z, .asm_598c
- or $10
-.asm_598c
- ld hl, $6
+ bit OBJ_FLAGS2_7, e
+ jr z, .skip2
+ or PRIORITY
+.skip2
+ bit USE_OBP1_F, e
+ jr z, .skip3
+ or OBP_NUM
+.skip3
+ ld hl, OBJECT_PALETTE
add hl, bc
ld d, a
ld a, [hl]
- and $7
+ and PALETTE_MASK
or d
ld d, a
xor a
- bit 3, e
- jr z, .asm_599d
- or $80
-.asm_599d
- ldh [hFFC4], a
- ld hl, $2
+ bit OVERHEAD_F, e
+ jr z, .skip4
+ or PRIORITY
+.skip4
+ ldh [hCurSpriteOAMFlags], a
+ ld hl, OBJECT_SPRITE_TILE
add hl, bc
ld a, [hl]
- ldh [hFFC3], a
- ld hl, $17
+ ldh [hCurSpriteTile], a
+ ld hl, OBJECT_SPRITE_X
add hl, bc
ld a, [hl]
- ld hl, $19
+ ld hl, OBJECT_SPRITE_X_OFFSET
add hl, bc
add [hl]
- add $8
+ add 8
ld e, a
- ld a, [wce81]
+ ld a, [wPlayerBGMapOffsetX]
add e
- ldh [hFFC1], a
- ld hl, $18
+ ldh [hCurSpriteXPixel], a
+ ld hl, OBJECT_SPRITE_Y
add hl, bc
ld a, [hl]
- ld hl, $1a
+ ld hl, OBJECT_SPRITE_Y_OFFSET
add hl, bc
add [hl]
- add $c
+ add 12
ld e, a
- ld a, [wce82]
+ ld a, [wPlayerBGMapOffsetY]
add e
- ldh [hFFC2], a
- ld hl, $d
+ ldh [hCurSpriteYPixel], a
+ ld hl, OBJECT_FACING_STEP
add hl, bc
ld a, [hl]
- cp $ff
- jp z, .asm_5a23
- cp $20
- jp nc, .asm_5a23
+ cp STANDING
+ jp z, .done
+ cp NUM_FACINGS
+ jp nc, .done
ld l, a
- ld h, $0
+ ld h, 0
add hl, hl
- ld bc, PushOAMEnd
+ ld bc, Facings
add hl, bc
ld a, [hli]
ld h, [hl]
ld l, a
ldh a, [hUsedSpriteIndex]
ld c, a
- ld b, $c3
+ ld b, HIGH(wVirtualOAM)
ld a, [hli]
ldh [hUsedSpriteTile], a
add c
- cp $a0
- jr nc, .asm_5a25
-.asm_59f3
- ldh a, [hFFC2]
+ cp LOW(wVirtualOAMEnd)
+ jr nc, .full
+.addsprite
+ ldh a, [hCurSpriteYPixel]
add [hl]
inc hl
- ld [bc], a
+ ld [bc], a ; y
inc c
- ldh a, [hFFC1]
+ ldh a, [hCurSpriteXPixel]
add [hl]
inc hl
- ld [bc], a
+ ld [bc], a ; x
inc c
ld e, [hl]
inc hl
- ldh a, [hFFC3]
- bit 2, e
- jr z, .asm_5a08
+ ldh a, [hCurSpriteTile]
+ bit ABSOLUTE_TILE_ID_F, e
+ jr z, .nope1
xor a
-.asm_5a08
+.nope1
add [hl]
inc hl
- ld [bc], a
+ ld [bc], a ; tile id
inc c
ld a, e
- bit 1, a
- jr z, .asm_5a14
- ldh a, [hFFC4]
+ bit RELATIVE_ATTRIBUTES_F, a
+ jr z, .nope2
+ ldh a, [hCurSpriteOAMFlags]
or e
-.asm_5a14
- and $f0
+.nope2
+ and OBP_NUM | X_FLIP | Y_FLIP | PRIORITY
or d
- ld [bc], a
+ ld [bc], a ; attributes
inc c
ldh a, [hUsedSpriteTile]
dec a
ldh [hUsedSpriteTile], a
- jr nz, .asm_59f3
+ jr nz, .addsprite
ld a, c
ldh [hUsedSpriteIndex], a
-.asm_5a23
+.done
xor a
ret
-.asm_5a25
+.full
scf
ret
-Function5a27: ; 5a27 (1:5a27)
+.GetObjectStructPointer:
ld c, a
- ld b, $0
- ld hl, ObjectStructPointers
+ ld b, 0
+ ld hl, .Addresses
add hl, bc
add hl, bc
ld c, [hl]
@@ -1440,7 +2919,7 @@ Function5a27: ; 5a27 (1:5a27)
ld b, [hl]
ret
-ObjectStructPointers:
+.Addresses:
dw wPlayerStruct
dw wObject1Struct
dw wObject2Struct
diff --git a/engine/overworld/map_objects_2.asm b/engine/overworld/map_objects_2.asm
new file mode 100644
index 00000000..d89d95fc
--- /dev/null
+++ b/engine/overworld/map_objects_2.asm
@@ -0,0 +1,70 @@
+LoadObjectMasks:
+ ld hl, wObjectMasks
+ xor a
+ ld bc, NUM_OBJECTS
+ call ByteFill
+ nop
+ ld bc, wMapObjects
+ ld de, wObjectMasks
+ xor a
+.loop
+ push af
+ push bc
+ push de
+ call GetObjectTimeMask
+ jr c, .next
+ call CheckObjectFlag
+.next
+ pop de
+ ld [de], a
+ inc de
+ pop bc
+ ld hl, MAPOBJECT_LENGTH
+ add hl, bc
+ ld b, h
+ ld c, l
+ pop af
+ inc a
+ cp NUM_OBJECTS
+ jr nz, .loop
+ ret
+
+CheckObjectFlag:
+ ld hl, MAPOBJECT_SPRITE
+ add hl, bc
+ ld a, [hl]
+ and a
+ jr z, .masked
+ ld hl, MAPOBJECT_EVENT_FLAG
+ add hl, bc
+ ld a, [hli]
+ ld e, a
+ ld a, [hl]
+ ld d, a
+ cp -1
+ jr nz, .check
+ ld a, e
+ cp -1
+ jr z, .unmasked
+ jr .masked
+.check
+ ld b, CHECK_FLAG
+ call EventFlagAction
+ ld a, c
+ and a
+ jr nz, .masked
+.unmasked
+ xor a
+ ret
+
+.masked
+ ld a, -1
+ scf
+ ret
+
+GetObjectTimeMask:
+ call CheckObjectTime
+ ld a, -1
+ ret c
+ xor a
+ ret
diff --git a/engine/overworld/map_setup.asm b/engine/overworld/map_setup.asm
new file mode 100644
index 00000000..aec3c949
--- /dev/null
+++ b/engine/overworld/map_setup.asm
@@ -0,0 +1,256 @@
+RunMapSetupScript::
+ ldh a, [hMapEntryMethod]
+ and $f
+ dec a
+ ld c, a
+ ld b, 0
+ ld hl, MapSetupScripts
+ add hl, bc
+ add hl, bc
+ ld a, [hli]
+ ld h, [hl]
+ ld l, a
+ call ReadMapSetupScript
+ ret
+
+INCLUDE "data/maps/setup_scripts.asm"
+
+ReadMapSetupScript:
+.loop
+ ld a, [hli]
+ cp map_end
+ ret z
+
+ push hl
+
+ ld c, a
+ ld b, 0
+ ld hl, MapSetupCommands
+ add hl, bc
+ add hl, bc
+ add hl, bc
+
+ ; bank
+ ld b, [hl]
+ inc hl
+
+ ; address
+ ld a, [hli]
+ ld h, [hl]
+ ld l, a
+
+ ; Bit 7 of the bank indicates a parameter.
+ ; This is left unused.
+ bit 7, b
+ jr z, .go
+
+ pop de
+ ld a, [de]
+ ld c, a
+ inc de
+ push de
+
+.go
+ ld a, b
+ and $7f
+ rst FarCall
+
+ pop hl
+ jr .loop
+
+MapSetupCommands:
+; entries correspond to command indexes in constants/map_setup_constants.asm
+ dba EnableLCD ; 00
+ dba DisableLCD ; 01
+ dba InitSound ; 02
+ dba PlayMapMusic ; 03
+ dba RestartMapMusic ; 04
+ dba FadeToMapMusic ; 05
+ dba FadeMapMusicAndPalettes ; 06
+ dba PlayMapMusicBike ; 07
+ dba ForceMapMusic ; 08
+ dba FadeInMusic ; 09
+ dba LoadBlockData ; 0a (callback 1)
+ dba LoadConnectionBlockData ; 0b
+ dba SaveScreen ; 0c
+ dba BufferScreen ; 0d
+ dba LoadMapGraphics ; 0e
+ dba LoadMapTileset ; 0f
+ dba LoadMapTimeOfDay ; 10
+ dba LoadMapPalettes ; 11
+ dba LoadWildMonData ; 12
+ dba RefreshMapSprites ; 13
+ dba HandleNewMap ; 14
+ dba HandleContinueMap ; 15
+ dba LoadMapObjects ; 16
+ dba EnterMapSpawnPoint ; 17
+ dba EnterMapConnection ; 18
+ dba EnterMapWarp ; 19
+ dba LoadMapAttributes ; 1a
+ dba LoadMapAttributes_SkipObjects ; 1b
+ dba ClearBGPalettes ; 1c
+ dba FadeOutPalettes ; 1d
+ dba FadeInPalettes ; 1e
+ dba GetMapScreenCoords ; 1f
+ dba GetWarpDestCoords ; 20
+ dba SpawnInFacingDown ; 21
+ dba SpawnPlayer ; 22
+ dba RefreshPlayerCoords ; 23
+ dba ResetPlayerObjectAction ; 24
+ dba SkipUpdateMapSprites ; 25
+ dba UpdateRoamMons ; 26
+ dba JumpRoamMons ; 27
+ dba FadeOutMapMusic ; 28
+ dba ActivateMapAnims ; 29
+ dba SuspendMapAnims ; 2a
+ dba ApplyMapPalettes ; 2b
+ dba EnableTextAcceleration ; 2c
+
+EnableTextAcceleration:
+ xor a
+ ld [wDisableTextAcceleration], a
+ ret
+
+UnusedActivateMapAnims:
+ ld a, $1
+ ldh [hMapAnims], a
+ ret
+
+UnusedSuspendMapAnims:
+ xor a
+ ldh [hMapAnims], a
+ ret
+
+LoadMapObjects:
+ ld a, MAPCALLBACK_OBJECTS
+ call RunMapCallback
+ farcall LoadObjectMasks
+ farcall InitializeVisibleSprites
+ ret
+
+; unused
+ ret
+
+ResetPlayerObjectAction:
+ ld hl, wPlayerSpriteSetupFlags
+ set PLAYERSPRITESETUP_RESET_ACTION_F, [hl]
+ ret
+
+SkipUpdateMapSprites:
+ ld hl, wPlayerSpriteSetupFlags
+ set PLAYERSPRITESETUP_SKIP_RELOAD_GFX_F, [hl]
+ ret
+
+CheckReplaceChrisSprite::
+ nop
+ call .CheckBiking
+ jr c, .ok
+ call .CheckSurfing
+ jr c, .ok
+ call .CheckSurfing2
+ jr c, .ok
+ ret
+
+.ok
+ call ReplaceChrisSprite
+ ret
+
+.CheckBiking:
+ and a
+ ld hl, wBikeFlags
+ bit BIKEFLAGS_ALWAYS_ON_BIKE_F, [hl]
+ ret z
+ ld a, PLAYER_BIKE
+ ld [wPlayerState], a
+ scf
+ ret
+
+.CheckSurfing2:
+ ld a, [wPlayerState]
+ cp PLAYER_NORMAL
+ jr z, .nope
+ cp PLAYER_SKATE
+ jr z, .nope
+ cp PLAYER_SURF
+ jr z, .surfing
+ cp PLAYER_SURF_PIKA
+ jr z, .surfing
+ call GetMapEnvironment
+ cp INDOOR
+ jr z, .no_biking
+ cp ENVIRONMENT_5
+ jr z, .no_biking
+ cp DUNGEON
+ jr z, .no_biking
+ jr .nope
+.no_biking
+ ld a, [wPlayerState]
+ cp PLAYER_BIKE
+ jr nz, .nope
+.surfing
+ ld a, PLAYER_NORMAL
+ ld [wPlayerState], a
+ scf
+ ret
+
+.nope
+ and a
+ ret
+
+.CheckSurfing:
+ call CheckOnWater
+ jr nz, .nope2
+ ld a, [wPlayerState]
+ cp PLAYER_SURF
+ jr z, .is_surfing
+ cp PLAYER_SURF_PIKA
+ jr z, .is_surfing
+ ld a, PLAYER_SURF
+ ld [wPlayerState], a
+.is_surfing
+ scf
+ ret
+
+.nope2
+ and a
+ ret
+
+FadeOutMapMusic:
+ ld a, 6
+ call SkipMusic
+ ret
+
+ActivateMapAnims:
+ ld a, $1
+ ldh [hMapAnims], a
+ ret
+
+SuspendMapAnims:
+ xor a
+ ldh [hMapAnims], a
+ ret
+
+ApplyMapPalettes:
+ farcall _UpdateTimePals
+ ret
+
+FadeMapMusicAndPalettes:
+ ld e, LOW(MUSIC_NONE)
+ ld a, [wMusicFadeID]
+ ld d, HIGH(MUSIC_NONE)
+ ld a, [wMusicFadeID + 1]
+ ld a, $4
+ ld [wMusicFade], a
+ call RotateThreePalettesRight
+ ret
+
+ForceMapMusic:
+ ld a, [wPlayerState]
+ cp PLAYER_BIKE
+ jr nz, .notbiking
+ call MinVolume
+ ld a, $88
+ ld [wMusicFade], a
+.notbiking
+ call TryRestartMapMusic
+ ret
diff --git a/engine/overworld/movement.asm b/engine/overworld/movement.asm
index d98b47ee..1a819acb 100755
--- a/engine/overworld/movement.asm
+++ b/engine/overworld/movement.asm
@@ -1,776 +1,767 @@
-GetMovementByte:
- ld hl, wMovementDataBank
- call _GetMovementByte
+MovementPointers:
+; entries correspond to macros/scripts/movement.asm enumeration
+ dw Movement_turn_head_down ; 00
+ dw Movement_turn_head_up ; 01
+ dw Movement_turn_head_left ; 02
+ dw Movement_turn_head_right ; 03
+ dw Movement_turn_step_down ; 04
+ dw Movement_turn_step_up ; 05
+ dw Movement_turn_step_left ; 06
+ dw Movement_turn_step_right ; 07
+ dw Movement_slow_step_down ; 08
+ dw Movement_slow_step_up ; 09
+ dw Movement_slow_step_left ; 0a
+ dw Movement_slow_step_right ; 0b
+ dw Movement_step_down ; 0c
+ dw Movement_step_up ; 0d
+ dw Movement_step_left ; 0e
+ dw Movement_step_right ; 0f
+ dw Movement_big_step_down ; 10
+ dw Movement_big_step_up ; 11
+ dw Movement_big_step_left ; 12
+ dw Movement_big_step_right ; 13
+ dw Movement_slow_slide_step_down ; 14
+ dw Movement_slow_slide_step_up ; 15
+ dw Movement_slow_slide_step_left ; 16
+ dw Movement_slow_slide_step_right ; 17
+ dw Movement_slide_step_down ; 18
+ dw Movement_slide_step_up ; 19
+ dw Movement_slide_step_left ; 1a
+ dw Movement_slide_step_right ; 1b
+ dw Movement_fast_slide_step_down ; 1c
+ dw Movement_fast_slide_step_up ; 1d
+ dw Movement_fast_slide_step_left ; 1e
+ dw Movement_fast_slide_step_right ; 1f
+ dw Movement_turn_away_down ; 20
+ dw Movement_turn_away_up ; 21
+ dw Movement_turn_away_left ; 22
+ dw Movement_turn_away_right ; 23
+ dw Movement_turn_in_down ; 24
+ dw Movement_turn_in_up ; 25
+ dw Movement_turn_in_left ; 26
+ dw Movement_turn_in_right ; 27
+ dw Movement_turn_waterfall_down ; 28
+ dw Movement_turn_waterfall_up ; 29
+ dw Movement_turn_waterfall_left ; 2a
+ dw Movement_turn_waterfall_right ; 2b
+ dw Movement_slow_jump_step_down ; 2c
+ dw Movement_slow_jump_step_up ; 2d
+ dw Movement_slow_jump_step_left ; 2e
+ dw Movement_slow_jump_step_right ; 2f
+ dw Movement_jump_step_down ; 30
+ dw Movement_jump_step_up ; 31
+ dw Movement_jump_step_left ; 32
+ dw Movement_jump_step_right ; 33
+ dw Movement_fast_jump_step_down ; 34
+ dw Movement_fast_jump_step_up ; 35
+ dw Movement_fast_jump_step_left ; 36
+ dw Movement_fast_jump_step_right ; 37
+ dw Movement_remove_sliding ; 38
+ dw Movement_set_sliding ; 39
+ dw Movement_remove_fixed_facing ; 3a
+ dw Movement_fix_facing ; 3b
+ dw Movement_show_object ; 3c
+ dw Movement_hide_object ; 3d
+ dw Movement_step_sleep_1 ; 3e
+ dw Movement_step_sleep_2 ; 3f
+ dw Movement_step_sleep_3 ; 40
+ dw Movement_step_sleep_4 ; 41
+ dw Movement_step_sleep_5 ; 42
+ dw Movement_step_sleep_6 ; 43
+ dw Movement_step_sleep_7 ; 44
+ dw Movement_step_sleep_8 ; 45
+ dw Movement_step_sleep ; 46
+ dw Movement_step_end ; 47
+ dw Movement_48 ; 48
+ dw Movement_remove_object ; 49
+ dw Movement_step_loop ; 4a
+ dw Movement_4b ; 4b
+ dw Movement_teleport_from ; 4c
+ dw Movement_teleport_to ; 4d
+ dw Movement_skyfall ; 4e
+ dw Movement_step_dig ; 4f
+ dw Movement_step_bump ; 50
+ dw Movement_fish_got_bite ; 51
+ dw Movement_fish_cast_rod ; 52
+ dw Movement_hide_emote ; 53
+ dw Movement_show_emote ; 54
+ dw Movement_step_shake ; 55
+ dw Movement_tree_shake ; 56
+ dw Movement_rock_smash ; 57
+ dw Movement_return_dig ; 58
+
+Movement_teleport_from:
+ ld hl, OBJECT_STEP_TYPE
+ add hl, bc
+ ld [hl], STEP_TYPE_TELEPORT_FROM
ret
-Function4fbd:
- ld hl, $1b
- add hl, bc
- ld e, [hl]
- inc [hl]
- ld d, $0
- ld hl, wMovementObject
- ld a, [hli]
- ld h, [hl]
- ld l, a
- add hl, de
- ld a, [hl]
- ret
-
-Function4fce:
- ld hl, $1b
- add hl, bc
- ld e, [hl]
- inc [hl]
- ld d, $0
- ld hl, wce8f
- ld a, [hli]
- ld h, [hl]
- ld l, a
- add hl, de
- ld a, [hl]
- ret
-
-Function4fdf: ; 4fdf (1:4fdf)
- ld hl, GetMovementPerson
- jp Function4fe9
-
-GetMovementPerson
- ld a, [wMovementObject]
- ret
-
-Function4fe9: ; 4fe9 (1:4fe9)
- call Function4ffd
-.asm_4fec
- xor a
- ld [wce93], a
- call Function5006
- call Function5013
- ld a, [wce93]
- and a
- jr nz, .asm_4fec
- ret
-
-Function4ffd: ; 4ffd (1:4ffd)
- ld a, l
- ld [wce94], a
- ld a, h
- ld [wce95], a
- ret
-
-Function5006: ; 5006 (1:5006)
- ld hl, wce94
- ld a, [hli]
- ld h, [hl]
- ld l, a
- jp hl
-
-Function500d: ; 500d (1:500d)
- ld a, $1
- ld [wce93], a
- ret
-
-Function5013: ; 5013 (1:5013)
- push af
- call Function5457
- pop af
- ld hl, MovementPointers
- rst JumpTable
- ret
-
-MovementPointers: ; 501d
- dw Function527d
- dw Function5281
- dw Function5285
- dw Function5289
- dw Function538f
- dw Function5393
- dw Function5397
- dw Function539b
- dw Function529f
- dw Function52a4
- dw Function52a9
- dw Function52ae
- dw Function52b3
- dw Function52b8
- dw Function52bd
- dw Function52c2
- dw Function52c7
- dw Function52cc
- dw Function52d1
- dw Function52d6
- dw Function5317
- dw Function531c
- dw Function5321
- dw Function5326
- dw Function532b
- dw Function5330
- dw Function5335
- dw Function533a
- dw Function533f
- dw Function5344
- dw Function5349
- dw Function534e
- dw Function52db
- dw Function52e0
- dw Function52e5
- dw Function52ea
- dw Function52ef
- dw Function52f4
- dw Function52f9
- dw Function52fe
- dw Function5303
- dw Function5308
- dw Function530d
- dw Function5312
- dw Function5353
- dw Function5358
- dw Function535d
- dw Function5362
- dw Function5367
- dw Function536c
- dw Function5371
- dw Function5376
- dw Function537b
- dw Function5380
- dw Function5385
- dw Function538a
- dw Function5232
- dw Function523b
- dw Function5244
- dw Function524d
- dw Function5256
- dw Function525f
- dw Function51c1
- dw Function51c5
- dw Function51c9
- dw Function51cd
- dw Function51d1
- dw Function51d5
- dw Function51d9
- dw Function51dd
- dw Function51e1
- dw Function5160
- dw Function517a
- dw Function519c
- dw Function5157
- dw Function51af
- dw Function50cf
- dw Function50d6
- dw Function50dd
- dw Function50e4
- dw Function51fe
- dw Function5128
- dw Function514a
- dw Function5268
- dw Function526e
- dw Function5274
- dw Function5218
- dw Function5135
- dw Function5109
-
-Function50cf: ; 50cf (1:50cf)
- ld hl, $9
- add hl, bc
- ld [hl], $c
- ret
-
-Function50d6: ; 50d6 (1:50d6)
- ld hl, $9
+Movement_teleport_to:
+ ld hl, OBJECT_STEP_TYPE
add hl, bc
- ld [hl], $d
+ ld [hl], STEP_TYPE_TELEPORT_TO
ret
-Function50dd: ; 50dd (1:50dd)
- ld hl, $9
+Movement_skyfall:
+ ld hl, OBJECT_STEP_TYPE
add hl, bc
- ld [hl], $e
+ ld [hl], STEP_TYPE_SKYFALL
ret
-Function50e4: ; 50e4 (1:50e4)
+Movement_step_dig:
call GetSpriteDirection
rlca
rlca
- ld hl, $c
+ ld hl, OBJECT_STEP_FRAME
add hl, bc
ld [hl], a
- ld hl, $b
+ ld hl, OBJECT_ACTION
add hl, bc
- ld [hl], $4
- call Function5006
- ld hl, $a
+ ld [hl], OBJECT_ACTION_SPIN
+ call JumpMovementPointer
+ ld hl, OBJECT_STEP_DURATION
add hl, bc
ld [hl], a
- ld hl, $9
+ ld hl, OBJECT_STEP_TYPE
add hl, bc
- ld [hl], $3
- ld hl, $7
+ ld [hl], STEP_TYPE_03
+ ld hl, OBJECT_DIRECTION_WALKING
add hl, bc
- ld [hl], $ff
+ ld [hl], STANDING
ret
-Function5109: ; 5109 (1:5109)
+Movement_return_dig:
call GetSpriteDirection
rlca
rlca
- ld hl, $c
+ ld hl, OBJECT_STEP_FRAME
add hl, bc
ld [hl], a
- call Function5006
- ld hl, $a
+ call JumpMovementPointer
+ ld hl, OBJECT_STEP_DURATION
add hl, bc
ld [hl], a
- ld hl, $7
+ ld hl, OBJECT_DIRECTION_WALKING
add hl, bc
- ld [hl], $ff
- ld hl, $9
+ ld [hl], STANDING
+ ld hl, OBJECT_STEP_TYPE
add hl, bc
- ld [hl], $12
+ ld [hl], STEP_TYPE_RETURN_DIG
ret
-Function5128: ; 5128 (1:5128)
- ld hl, $b
+Movement_fish_got_bite:
+ ld hl, OBJECT_ACTION
add hl, bc
- ld [hl], $6
- ld hl, $9
+ ld [hl], OBJECT_ACTION_FISHING
+ ld hl, OBJECT_STEP_TYPE
add hl, bc
- ld [hl], $10
+ ld [hl], STEP_TYPE_GOT_BITE
ret
-Function5135: ; 5135 (1:5135)
- call Function5006
- ld hl, $a
+Movement_rock_smash:
+ call JumpMovementPointer
+ ld hl, OBJECT_STEP_DURATION
add hl, bc
ld [hl], a
- ld hl, $b
+ ld hl, OBJECT_ACTION
add hl, bc
- ld [hl], $1
- ld hl, $9
+ ld [hl], OBJECT_ACTION_STAND
+ ld hl, OBJECT_STEP_TYPE
add hl, bc
- ld [hl], $11
+ ld [hl], STEP_TYPE_ROCK_SMASH
ret
-Function514a: ; 514a (1:514a)
- ld hl, $b
+Movement_fish_cast_rod:
+ ld hl, OBJECT_ACTION
add hl, bc
- ld [hl], $6
- ld hl, $9
+ ld [hl], OBJECT_ACTION_FISHING
+ ld hl, OBJECT_STEP_TYPE
add hl, bc
- ld [hl], $1
+ ld [hl], STEP_TYPE_SLEEP
ret
-Function5157: ; 5157 (1:5157)
- ld hl, $1b
+Movement_step_loop:
+ ld hl, OBJECT_MOVEMENT_BYTE_INDEX
add hl, bc
ld [hl], $0
- jp Function500d
+ jp ContinueReadingMovement
-Function5160: ; 5160 (1:5160)
+Movement_step_end:
call RestoreDefaultMovement
- ld hl, $3
+ ld hl, OBJECT_MOVEMENTTYPE
add hl, bc
ld [hl], a
- ld hl, $1b
+
+ ld hl, OBJECT_MOVEMENT_BYTE_INDEX
add hl, bc
ld [hl], $0
+
ld hl, wVramState
res 7, [hl]
- ld hl, $9
+
+ ld hl, OBJECT_STEP_TYPE
add hl, bc
- ld [hl], $1
+ ld [hl], STEP_TYPE_SLEEP
ret
-Function517a: ; 517a (1:517a)
+Movement_48:
call RestoreDefaultMovement
- ld hl, $3
+ ld hl, OBJECT_MOVEMENTTYPE
add hl, bc
ld [hl], a
- ld hl, $1b
+
+ ld hl, OBJECT_MOVEMENT_BYTE_INDEX
add hl, bc
ld [hl], $0
- call Function5006
- ld hl, $a
+
+ call JumpMovementPointer
+ ld hl, OBJECT_STEP_DURATION
add hl, bc
ld [hl], a
- ld hl, $9
+
+ ld hl, OBJECT_STEP_TYPE
add hl, bc
- ld [hl], $3
+ ld [hl], STEP_TYPE_03
+
ld hl, wVramState
res 7, [hl]
ret
-Function519c: ; 519c (1:519c)
+Movement_remove_object:
call DeleteMapObject
ld hl, wObjectFollow_Leader
ldh a, [hMapObjectIndexBuffer]
cp [hl]
- jr nz, .asm_51a9
- ld [hl], $ff
-.asm_51a9
+ jr nz, .not_leading
+ ld [hl], -1
+
+.not_leading
ld hl, wVramState
res 7, [hl]
ret
-Function51af: ; 51af (1:51af)
- ld hl, $b
+Movement_4b:
+ ld hl, OBJECT_ACTION
add hl, bc
- ld [hl], $1
- ld hl, $9
+ ld [hl], OBJECT_ACTION_STAND
+
+ ld hl, OBJECT_STEP_TYPE
add hl, bc
- ld [hl], $4
+ ld [hl], STEP_TYPE_04
+
ld hl, wVramState
res 7, [hl]
ret
-Function51c1: ; 51c1 (1:51c1)
- ld a, $1
- jr asm_51e6
+Movement_step_sleep_1:
+ ld a, 1
+ jr Movement_step_sleep_common
+
+Movement_step_sleep_2:
+ ld a, 2
+ jr Movement_step_sleep_common
-Function51c5: ; 51c5 (1:51c5)
- ld a, $2
- jr asm_51e6
+Movement_step_sleep_3:
+ ld a, 3
+ jr Movement_step_sleep_common
-Function51c9: ; 51c9 (1:51c9)
- ld a, $3
- jr asm_51e6
+Movement_step_sleep_4:
+ ld a, 4
+ jr Movement_step_sleep_common
-Function51cd: ; 51cd (1:51cd)
- ld a, $4
- jr asm_51e6
+Movement_step_sleep_5:
+ ld a, 5
+ jr Movement_step_sleep_common
-Function51d1: ; 51d1 (1:51d1)
- ld a, $5
- jr asm_51e6
+Movement_step_sleep_6:
+ ld a, 6
+ jr Movement_step_sleep_common
-Function51d5: ; 51d5 (1:51d5)
- ld a, $6
- jr asm_51e6
+Movement_step_sleep_7:
+ ld a, 7
+ jr Movement_step_sleep_common
-Function51d9: ; 51d9 (1:51d9)
- ld a, $7
- jr asm_51e6
+Movement_step_sleep_8:
+ ld a, 8
+ jr Movement_step_sleep_common
-Function51dd: ; 51dd (1:51dd)
- ld a, $8
- jr asm_51e6
+Movement_step_sleep:
+; parameters:
+; duration (DecimalParam)
-Function51e1: ; 51e1 (1:51e1)
- call Function5006
- jr asm_51e6
+ call JumpMovementPointer
+ jr Movement_step_sleep_common
-asm_51e6
- ld hl, $a
+Movement_step_sleep_common:
+ ld hl, OBJECT_STEP_DURATION
add hl, bc
ld [hl], a
- ld hl, $9
+
+ ld hl, OBJECT_STEP_TYPE
add hl, bc
- ld [hl], $3
- ld hl, $b
+ ld [hl], STEP_TYPE_03
+
+ ld hl, OBJECT_ACTION
add hl, bc
- ld [hl], $1
- ld hl, $7
+ ld [hl], OBJECT_ACTION_STAND
+
+ ld hl, OBJECT_DIRECTION_WALKING
add hl, bc
- ld [hl], $ff
+ ld [hl], STANDING
ret
-Function51fe: ; 51fe (1:51fe)
- ld a, $1
- ld hl, $a
+Movement_step_bump:
+ ld a, 1
+ ld hl, OBJECT_STEP_DURATION
add hl, bc
ld [hl], a
- ld hl, $9
+
+ ld hl, OBJECT_STEP_TYPE
add hl, bc
- ld [hl], $b
- ld hl, $b
+ ld [hl], STEP_TYPE_BUMP
+
+ ld hl, OBJECT_ACTION
add hl, bc
- ld [hl], $3
- ld hl, $7
+ ld [hl], OBJECT_ACTION_BUMP
+
+ ld hl, OBJECT_DIRECTION_WALKING
add hl, bc
- ld [hl], $ff
+ ld [hl], STANDING
ret
-Function5218: ; 5218 (1:5218)
- ld a, $18
- ld hl, $a
+Movement_tree_shake:
+ ld a, 24
+ ld hl, OBJECT_STEP_DURATION
add hl, bc
ld [hl], a
- ld hl, $9
+
+ ld hl, OBJECT_STEP_TYPE
add hl, bc
- ld [hl], $3
- ld hl, $b
+ ld [hl], STEP_TYPE_03
+
+ ld hl, OBJECT_ACTION
add hl, bc
- ld [hl], $b
- ld hl, $7
+ ld [hl], OBJECT_ACTION_WEIRD_TREE
+
+ ld hl, OBJECT_DIRECTION_WALKING
add hl, bc
- ld [hl], $ff
+ ld [hl], STANDING
ret
-Function5232: ; 5232 (1:5232)
- ld hl, $4
+Movement_remove_sliding:
+ ld hl, OBJECT_FLAGS1
add hl, bc
- res 3, [hl]
- jp Function500d
+ res SLIDING_F, [hl]
+ jp ContinueReadingMovement
-Function523b: ; 523b (1:523b)
- ld hl, $4
+Movement_set_sliding:
+ ld hl, OBJECT_FLAGS1
add hl, bc
- set 3, [hl]
- jp Function500d
+ set SLIDING_F, [hl]
+ jp ContinueReadingMovement
-Function5244: ; 5244 (1:5244)
- ld hl, $4
+Movement_remove_fixed_facing:
+ ld hl, OBJECT_FLAGS1
add hl, bc
- res 2, [hl]
- jp Function500d
+ res FIXED_FACING_F, [hl]
+ jp ContinueReadingMovement
-Function524d: ; 524d (1:524d)
- ld hl, $4
+Movement_fix_facing:
+ ld hl, OBJECT_FLAGS1
add hl, bc
- set 2, [hl]
- jp Function500d
+ set FIXED_FACING_F, [hl]
+ jp ContinueReadingMovement
-Function5256: ; 5256 (1:5256)
- ld hl, $4
+Movement_show_object:
+ ld hl, OBJECT_FLAGS1
add hl, bc
- res 0, [hl]
- jp Function500d
+ res INVISIBLE_F, [hl]
+ jp ContinueReadingMovement
-Function525f: ; 525f (1:525f)
- ld hl, $4
+Movement_hide_object:
+ ld hl, OBJECT_FLAGS1
add hl, bc
- set 0, [hl]
- jp Function500d
+ set INVISIBLE_F, [hl]
+ jp ContinueReadingMovement
+
+Movement_hide_emote:
+ call DespawnEmote
+ jp ContinueReadingMovement
-Function5268: ; 5268 (1:5268)
- call Function5518
- jp Function500d
+Movement_show_emote:
+ call SpawnEmote
+ jp ContinueReadingMovement
-Function526e: ; 526e (1:526e)
- call Function54e6
- jp Function500d
+Movement_step_shake:
+; parameters:
+; displacement (DecimalParam)
-Function5274: ; 5274 (1:5274)
- call Function5006
- call Function5504
- jp Function500d
+ call JumpMovementPointer
+ call ShakeScreen
+ jp ContinueReadingMovement
-Function527d: ; 527d (1:527d)
- ld a, $0
- jr asm_528d
+Movement_turn_head_down:
+ ld a, OW_DOWN
+ jr TurnHead
-Function5281: ; 5281 (1:5281)
- ld a, $4
- jr asm_528d
+Movement_turn_head_up:
+ ld a, OW_UP
+ jr TurnHead
-Function5285: ; 5285 (1:5285)
- ld a, $8
- jr asm_528d
+Movement_turn_head_left:
+ ld a, OW_LEFT
+ jr TurnHead
-Function5289: ; 5289 (1:5289)
- ld a, $c
- jr asm_528d
+Movement_turn_head_right:
+ ld a, OW_RIGHT
+ jr TurnHead
-asm_528d
- ld hl, $8
+TurnHead:
+ ld hl, OBJECT_FACING
add hl, bc
ld [hl], a
- ld hl, $b
+
+ ld hl, OBJECT_ACTION
add hl, bc
- ld [hl], $1
- ld hl, $7
+ ld [hl], OBJECT_ACTION_STAND
+
+ ld hl, OBJECT_DIRECTION_WALKING
add hl, bc
- ld [hl], $ff
+ ld [hl], STANDING
ret
-Function529f: ; 529f (1:529f)
- ld a, $0
- jp Function53b1
+Movement_slow_step_down:
+ ld a, STEP_SLOW << 2 | DOWN
+ jp NormalStep
-Function52a4: ; 52a4 (1:52a4)
- ld a, $1
- jp Function53b1
+Movement_slow_step_up:
+ ld a, STEP_SLOW << 2 | UP
+ jp NormalStep
-Function52a9: ; 52a9 (1:52a9)
- ld a, $2
- jp Function53b1
+Movement_slow_step_left:
+ ld a, STEP_SLOW << 2 | LEFT
+ jp NormalStep
-Function52ae: ; 52ae (1:52ae)
- ld a, $3
- jp Function53b1
+Movement_slow_step_right:
+ ld a, STEP_SLOW << 2 | RIGHT
+ jp NormalStep
-Function52b3: ; 52b3 (1:52b3)
- ld a, $4
- jp Function53b1
+Movement_step_down:
+ ld a, STEP_WALK << 2 | DOWN
+ jp NormalStep
-Function52b8: ; 52b8 (1:52b8)
- ld a, $5
- jp Function53b1
+Movement_step_up:
+ ld a, STEP_WALK << 2 | UP
+ jp NormalStep
-Function52bd: ; 52bd (1:52bd)
- ld a, $6
- jp Function53b1
+Movement_step_left:
+ ld a, STEP_WALK << 2 | LEFT
+ jp NormalStep
-Function52c2: ; 52c2 (1:52c2)
- ld a, $7
- jp Function53b1
+Movement_step_right:
+ ld a, STEP_WALK << 2 | RIGHT
+ jp NormalStep
-Function52c7: ; 52c7 (1:52c7)
- ld a, $8
- jp Function53b1
+Movement_big_step_down:
+ ld a, STEP_BIKE << 2 | DOWN
+ jp NormalStep
-Function52cc: ; 52cc (1:52cc)
- ld a, $9
- jp Function53b1
+Movement_big_step_up:
+ ld a, STEP_BIKE << 2 | UP
+ jp NormalStep
-Function52d1: ; 52d1 (1:52d1)
- ld a, $a
- jp Function53b1
+Movement_big_step_left:
+ ld a, STEP_BIKE << 2 | LEFT
+ jp NormalStep
-Function52d6: ; 52d6 (1:52d6)
- ld a, $b
- jp Function53b1
+Movement_big_step_right:
+ ld a, STEP_BIKE << 2 | RIGHT
+ jp NormalStep
-Function52db: ; 52db (1:52db)
- ld a, $0
- jp Function53e5
+Movement_turn_away_down:
+ ld a, STEP_SLOW << 2 | DOWN
+ jp TurningStep
-Function52e0: ; 52e0 (1:52e0)
- ld a, $1
- jp Function53e5
+Movement_turn_away_up:
+ ld a, STEP_SLOW << 2 | UP
+ jp TurningStep
-Function52e5: ; 52e5 (1:52e5)
- ld a, $2
- jp Function53e5
+Movement_turn_away_left:
+ ld a, STEP_SLOW << 2 | LEFT
+ jp TurningStep
-Function52ea: ; 52ea (1:52ea)
- ld a, $3
- jp Function53e5
+Movement_turn_away_right:
+ ld a, STEP_SLOW << 2 | RIGHT
+ jp TurningStep
-Function52ef: ; 52ef (1:52ef)
- ld a, $4
- jp Function53e5
+Movement_turn_in_down:
+ ld a, STEP_WALK << 2 | DOWN
+ jp TurningStep
-Function52f4: ; 52f4 (1:52f4)
- ld a, $5
- jp Function53e5
+Movement_turn_in_up:
+ ld a, STEP_WALK << 2 | UP
+ jp TurningStep
-Function52f9: ; 52f9 (1:52f9)
- ld a, $6
- jp Function53e5
+Movement_turn_in_left:
+ ld a, STEP_WALK << 2 | LEFT
+ jp TurningStep
-Function52fe: ; 52fe (1:52fe)
- ld a, $7
- jp Function53e5
+Movement_turn_in_right:
+ ld a, STEP_WALK << 2 | RIGHT
+ jp TurningStep
-Function5303: ; 5303 (1:5303)
- ld a, $8
- jp Function53e5
+Movement_turn_waterfall_down:
+ ld a, STEP_BIKE << 2 | DOWN
+ jp TurningStep
-Function5308: ; 5308 (1:5308)
- ld a, $9
- jp Function53e5
+Movement_turn_waterfall_up:
+ ld a, STEP_BIKE << 2 | UP
+ jp TurningStep
-Function530d: ; 530d (1:530d)
- ld a, $a
- jp Function53e5
+Movement_turn_waterfall_left:
+ ld a, STEP_BIKE << 2 | LEFT
+ jp TurningStep
-Function5312: ; 5312 (1:5312)
- ld a, $b
- jp Function53e5
+Movement_turn_waterfall_right:
+ ld a, STEP_BIKE << 2 | RIGHT
+ jp TurningStep
-Function5317: ; 5317 (1:5317)
- ld a, $0
- jp Function5407
+Movement_slow_slide_step_down:
+ ld a, STEP_SLOW << 2 | DOWN
+ jp SlideStep
-Function531c: ; 531c (1:531c)
- ld a, $1
- jp Function5407
+Movement_slow_slide_step_up:
+ ld a, STEP_SLOW << 2 | UP
+ jp SlideStep
-Function5321: ; 5321 (1:5321)
- ld a, $2
- jp Function5407
+Movement_slow_slide_step_left:
+ ld a, STEP_SLOW << 2 | LEFT
+ jp SlideStep
-Function5326: ; 5326 (1:5326)
- ld a, $3
- jp Function5407
+Movement_slow_slide_step_right:
+ ld a, STEP_SLOW << 2 | RIGHT
+ jp SlideStep
-Function532b: ; 532b (1:532b)
- ld a, $4
- jp Function5407
+Movement_slide_step_down:
+ ld a, STEP_WALK << 2 | DOWN
+ jp SlideStep
-Function5330: ; 5330 (1:5330)
- ld a, $5
- jp Function5407
+Movement_slide_step_up:
+ ld a, STEP_WALK << 2 | UP
+ jp SlideStep
-Function5335: ; 5335 (1:5335)
- ld a, $6
- jp Function5407
+Movement_slide_step_left:
+ ld a, STEP_WALK << 2 | LEFT
+ jp SlideStep
-Function533a: ; 533a (1:533a)
- ld a, $7
- jp Function5407
+Movement_slide_step_right:
+ ld a, STEP_WALK << 2 | RIGHT
+ jp SlideStep
-Function533f: ; 533f (1:533f)
- ld a, $8
- jp Function5407
+Movement_fast_slide_step_down:
+ ld a, STEP_BIKE << 2 | DOWN
+ jp SlideStep
-Function5344: ; 5344 (1:5344)
- ld a, $9
- jp Function5407
+Movement_fast_slide_step_up:
+ ld a, STEP_BIKE << 2 | UP
+ jp SlideStep
-Function5349: ; 5349 (1:5349)
- ld a, $a
- jp Function5407
+Movement_fast_slide_step_left:
+ ld a, STEP_BIKE << 2 | LEFT
+ jp SlideStep
-Function534e: ; 534e (1:534e)
- ld a, $b
- jp Function5407
+Movement_fast_slide_step_right:
+ ld a, STEP_BIKE << 2 | RIGHT
+ jp SlideStep
-Function5353: ; 5353 (1:5353)
- ld a, $0
- jp Function5429
+Movement_slow_jump_step_down:
+ ld a, STEP_SLOW << 2 | DOWN
+ jp JumpStep
-Function5358: ; 5358 (1:5358)
- ld a, $1
- jp Function5429
+Movement_slow_jump_step_up:
+ ld a, STEP_SLOW << 2 | UP
+ jp JumpStep
-Function535d: ; 535d (1:535d)
- ld a, $2
- jp Function5429
+Movement_slow_jump_step_left:
+ ld a, STEP_SLOW << 2 | LEFT
+ jp JumpStep
-Function5362: ; 5362 (1:5362)
- ld a, $3
- jp Function5429
+Movement_slow_jump_step_right:
+ ld a, STEP_SLOW << 2 | RIGHT
+ jp JumpStep
-Function5367: ; 5367 (1:5367)
- ld a, $4
- jp Function5429
+Movement_jump_step_down:
+ ld a, STEP_WALK << 2 | DOWN
+ jp JumpStep
-Function536c: ; 536c (1:536c)
- ld a, $5
- jp Function5429
+Movement_jump_step_up:
+ ld a, STEP_WALK << 2 | UP
+ jp JumpStep
-Function5371: ; 5371 (1:5371)
- ld a, $6
- jp Function5429
+Movement_jump_step_left:
+ ld a, STEP_WALK << 2 | LEFT
+ jp JumpStep
-Function5376: ; 5376 (1:5376)
- ld a, $7
- jp Function5429
+Movement_jump_step_right:
+ ld a, STEP_WALK << 2 | RIGHT
+ jp JumpStep
-Function537b: ; 537b (1:537b)
- ld a, $8
- jp Function5429
+Movement_fast_jump_step_down:
+ ld a, STEP_BIKE << 2 | DOWN
+ jp JumpStep
-Function5380: ; 5380 (1:5380)
- ld a, $9
- jp Function5429
+Movement_fast_jump_step_up:
+ ld a, STEP_BIKE << 2 | UP
+ jp JumpStep
-Function5385: ; 5385 (1:5385)
- ld a, $a
- jp Function5429
+Movement_fast_jump_step_left:
+ ld a, STEP_BIKE << 2 | LEFT
+ jp JumpStep
-Function538a: ; 538a (1:538a)
- ld a, $b
- jp Function5429
+Movement_fast_jump_step_right:
+ ld a, STEP_BIKE << 2 | RIGHT
+ jp JumpStep
-Function538f: ; 538f (1:538f)
- ld a, $0
- jr asm_539f
+Movement_turn_step_down:
+ ld a, OW_DOWN
+ jr TurnStep
-Function5393: ; 5393 (1:5393)
- ld a, $4
- jr asm_539f
+Movement_turn_step_up:
+ ld a, OW_UP
+ jr TurnStep
-Function5397: ; 5397 (1:5397)
- ld a, $8
- jr asm_539f
+Movement_turn_step_left:
+ ld a, OW_LEFT
+ jr TurnStep
-Function539b: ; 539b (1:539b)
- ld a, $c
- jr asm_539f
+Movement_turn_step_right:
+ ld a, OW_RIGHT
+ jr TurnStep
-asm_539f
- ld hl, $1d
+TurnStep:
+ ld hl, OBJECT_1D ; new facing
add hl, bc
ld [hl], a
- ld hl, $b
+
+ ld hl, OBJECT_ACTION
add hl, bc
- ld [hl], $2
- ld hl, $9
+ ld [hl], OBJECT_ACTION_STEP
+
+ ld hl, OBJECT_STEP_TYPE
add hl, bc
- ld [hl], $a
+ ld [hl], STEP_TYPE_HALF_STEP
ret
-Function53b1: ; 53b1 (1:53b1)
+NormalStep:
call InitStep
- call UpdateGrassPriority
- ld hl, $b
+ call UpdateTallGrassFlags
+ ld hl, OBJECT_ACTION
add hl, bc
- ld [hl], $2
- ld hl, $e
+ ld [hl], OBJECT_ACTION_STEP
+
+ ld hl, OBJECT_NEXT_TILE
add hl, bc
ld a, [hl]
call CheckSuperTallGrassTile
- jr z, .asm_53cc
+ jr z, .shake_grass
+
call CheckGrassTile
- jr c, .asm_53cf
-.asm_53cc
- call Function54f5
-.asm_53cf
+ jr c, .skip_grass
+
+.shake_grass
+ call ShakeGrass
+
+.skip_grass
ld hl, wCenteredObject
- ldh a, [hConnectionStripLength]
+ ldh a, [hMapObjectIndexBuffer]
cp [hl]
- jr z, .asm_53de
- ld hl, $9
+ jr z, .player
+
+ ld hl, OBJECT_STEP_TYPE
add hl, bc
- ld [hl], $2
+ ld [hl], STEP_TYPE_NPC_WALK
ret
-.asm_53de
- ld hl, $9
+.player
+ ld hl, OBJECT_STEP_TYPE
add hl, bc
- ld [hl], $6
+ ld [hl], STEP_TYPE_PLAYER_WALK
ret
-Function53e5: ; 53e5 (1:53e5)
+TurningStep:
call InitStep
- call UpdateGrassPriority
- ld hl, $b
+ call UpdateTallGrassFlags
+
+ ld hl, OBJECT_ACTION
add hl, bc
- ld [hl], $4
+ ld [hl], OBJECT_ACTION_SPIN
+
ld hl, wCenteredObject
ldh a, [hMapObjectIndexBuffer]
cp [hl]
- jr z, .asm_5400
- ld hl, $9
+ jr z, .player
+
+ ld hl, OBJECT_STEP_TYPE
add hl, bc
- ld [hl], $2
+ ld [hl], STEP_TYPE_NPC_WALK
ret
-.asm_5400
- ld hl, $9
+.player
+ ld hl, OBJECT_STEP_TYPE
add hl, bc
- ld [hl], $6
+ ld [hl], STEP_TYPE_PLAYER_WALK
ret
-Function5407: ; 5407 (1:5407)
+SlideStep:
call InitStep
- call UpdateGrassPriority
- ld hl, $b
+ call UpdateTallGrassFlags
+
+ ld hl, OBJECT_ACTION
add hl, bc
- ld [hl], $1
+ ld [hl], OBJECT_ACTION_STAND
+
ld hl, wCenteredObject
- ldh a, [hConnectionStripLength]
+ ldh a, [hMapObjectIndexBuffer]
cp [hl]
- jr z, .asm_5422
- ld hl, $9
+ jr z, .player
+
+ ld hl, OBJECT_STEP_TYPE
+ add hl, bc
+ ld [hl], STEP_TYPE_NPC_WALK
+ ret
+
+.player
+ ld hl, OBJECT_STEP_TYPE
+ add hl, bc
+ ld [hl], STEP_TYPE_PLAYER_WALK
+ ret
+
+JumpStep:
+ call InitStep
+ ld hl, OBJECT_1F
+ add hl, bc
+ ld [hl], $0
+
+ ld hl, OBJECT_FLAGS2
+ add hl, bc
+ res OVERHEAD_F, [hl]
+
+ ld hl, OBJECT_ACTION
+ add hl, bc
+ ld [hl], OBJECT_ACTION_STEP
+ call SpawnShadow
+ ld hl, wCenteredObject
+ ldh a, [hMapObjectIndexBuffer]
+ cp [hl]
+ jr z, .player
+
+ ld hl, OBJECT_STEP_TYPE
add hl, bc
- ld [hl], $2
+ ld [hl], STEP_TYPE_NPC_JUMP
ret
-.asm_5422
- ld hl, $9
+.player
+ ld hl, OBJECT_STEP_TYPE
add hl, bc
- ld [hl], $6
+ ld [hl], STEP_TYPE_PLAYER_JUMP
ret
diff --git a/engine/overworld/npc_movement.asm b/engine/overworld/npc_movement.asm
index 84235570..01d49d21 100755
--- a/engine/overworld/npc_movement.asm
+++ b/engine/overworld/npc_movement.asm
@@ -1,102 +1,110 @@
-CheckNPCMovementPermissions: ; 6fa0 (1:6fa0)
- ld hl, $6
+CanObjectMoveInDirection:
+ ld hl, OBJECT_PALETTE
add hl, bc
- bit 5, [hl]
- jr z, .asm_6fb8
- ld hl, $4
+ bit SWIMMING_F, [hl]
+ jr z, .not_swimming
+
+ ld hl, OBJECT_FLAGS1
add hl, bc
- bit 4, [hl]
+ bit NOCLIP_TILES_F, [hl] ; lost, uncomment next line to fix
+ ; jr nz, .noclip_tiles
push hl
push bc
- call Function700b
+ call WillObjectBumpIntoLand
pop bc
pop hl
ret c
- jr .asm_6fc8
+ jr .continue
-.asm_6fb8
- ld hl, $4
+.not_swimming
+ ld hl, OBJECT_FLAGS1
add hl, bc
- bit 4, [hl]
- jr nz, .asm_6fc8
+ bit NOCLIP_TILES_F, [hl]
+ jr nz, .noclip_tiles
push hl
push bc
- call Function6fe6
+ call WillObjectBumpIntoWater
pop bc
pop hl
ret c
-.asm_6fc8
- bit 6, [hl]
- jr nz, .asm_6fd4
+
+.noclip_tiles
+.continue
+ bit NOCLIP_OBJS_F, [hl]
+ jr nz, .noclip_objs
+
push hl
push bc
- call WillPersonBumpIntoSomeoneElse
+ call WillObjectBumpIntoSomeoneElse
pop bc
pop hl
ret c
-.asm_6fd4
- bit 5, [hl]
- jr nz, .asm_6fe4
+
+.noclip_objs
+ bit MOVE_ANYWHERE_F, [hl]
+ jr nz, .move_anywhere
push hl
- call HasPersonReachedMovementLimit
+ call HasObjectReachedMovementLimit
pop hl
ret c
+
push hl
- call IsPersonMovingOffEdgeOfScreen
+ call IsObjectMovingOffEdgeOfScreen
pop hl
ret c
-.asm_6fe4
+
+.move_anywhere
and a
ret
-Function6fe6: ; 6fe6 (1:6fe6)
+WillObjectBumpIntoWater:
call Function703e
ret c
- ld hl, $10
+ ld hl, OBJECT_NEXT_MAP_X
add hl, bc
ld d, [hl]
- ld hl, $11
+ ld hl, OBJECT_NEXT_MAP_Y
add hl, bc
ld e, [hl]
- ld hl, $6
+ ld hl, OBJECT_PALETTE
add hl, bc
- bit 7, [hl]
+ bit OAM_PRIORITY, [hl]
jp nz, Function7080
- ld hl, $e
+ ld hl, OBJECT_NEXT_TILE
add hl, bc
ld a, [hl]
ld d, a
call GetTileCollision
- and a
- jr z, Function701d
+ and a ; LAND_TILE
+ jr z, WillObjectBumpIntoTile
scf
ret
-Function700b: ; 700b (1:700b)
+WillObjectBumpIntoLand:
call Function703e
ret c
- ld hl, $e
+ ld hl, OBJECT_NEXT_TILE
add hl, bc
ld a, [hl]
call GetTileCollision
- cp $1
- jr z, Function701d
+ cp WATER_TILE
+ jr z, WillObjectBumpIntoTile
scf
ret
-Function701d
- ld hl, $e
+WillObjectBumpIntoTile:
+ ld hl, OBJECT_NEXT_TILE
add hl, bc
ld a, [hl]
call Function705e
ret nc
push af
- ld hl, $7
+ ld hl, OBJECT_DIRECTION_WALKING
add hl, bc
ld a, [hl]
- and $3
+ maskbits NUM_DIRECTIONS
ld e, a
- ld d, $0
+ ld d, 0
ld hl, .data_703a
add hl, de
pop af
@@ -106,20 +114,23 @@ Function701d
ret
.data_703a
- db 1 << DOWN, 1 << UP, 1 << RIGHT, 1 << LEFT
+ db DOWN_MASK ; DOWN
+ db UP_MASK ; UP
+ db RIGHT_MASK ; LEFT
+ db LEFT_MASK ; RIGHT
-Function703e: ; 703e (1:703e)
- ld hl, $f
+Function703e:
+ ld hl, OBJECT_STANDING_TILE
add hl, bc
ld a, [hl]
call Function705e
ret nc
push af
- ld hl, $7
+ ld hl, OBJECT_DIRECTION_WALKING
add hl, bc
- and $3
+ maskbits NUM_DIRECTIONS
ld e, a
- ld d, $0
+ ld d, 0
ld hl, .data_705a
add hl, de
pop af
@@ -129,23 +140,26 @@ Function703e: ; 703e (1:703e)
ret
.data_705a
- db 1 << UP, 1 << DOWN, 1 << LEFT, 1 << RIGHT
+ db UP_MASK ; DOWN
+ db DOWN_MASK ; UP
+ db LEFT_MASK ; LEFT
+ db RIGHT_MASK ; RIGHT
-Function705e: ; 705e (1:705e)
+Function705e:
ld d, a
and $f0
- cp $b0
- jr z, .asm_706b
- cp $c0
- jr z, .asm_706b
+ cp HI_NYBBLE_SIDE_WALLS
+ jr z, .continue
+ cp HI_NYBBLE_SIDE_BUOYS
+ jr z, .continue
xor a
ret
-.asm_706b
+.continue
ld a, d
- and $7
+ and 7
ld e, a
- ld d, $0
+ ld d, 0
ld hl, .data_7078
add hl, de
ld a, [hl]
@@ -153,216 +167,234 @@ Function705e: ; 705e (1:705e)
ret
.data_7078
- db 8, 4, 1, 2
- db 10, 6, 9, 5
-
-Function7080: ; 7080 (1:7080)
- ld hl, $7
+ db RIGHT_MASK ; COLL_RIGHT_WALL/BUOY
+ db LEFT_MASK ; COLL_LEFT_WALL/BUOY
+ db DOWN_MASK ; COLL_UP_WALL/BUOY
+ db UP_MASK ; COLL_DOWN_WALL/BUOY
+ db UP_MASK | RIGHT_MASK ; COLL_DOWN_RIGHT_WALL/BUOY
+ db UP_MASK | LEFT_MASK ; COLL_DOWN_LEFT_WALL/BUOY
+ db DOWN_MASK | RIGHT_MASK ; COLL_UP_RIGHT_WALL/BUOY
+ db DOWN_MASK | LEFT_MASK ; COLL_UP_LEFT_WALL/BUOY
+
+Function7080:
+ ld hl, OBJECT_DIRECTION_WALKING
add hl, bc
ld a, [hl]
- and $3
- jr z, .asm_7091
+ maskbits NUM_DIRECTIONS
+ jr z, .down
dec a
- jr z, .asm_7096
+ jr z, .up
dec a
- jr z, .asm_709a
- jr .asm_709e
+ jr z, .left
+ jr .right
-.asm_7091
+.down
inc e
push de
inc d
- jr .asm_70a1
+ jr .continue
-.asm_7096
+.up
push de
inc d
- jr .asm_70a1
+ jr .continue
-.asm_709a
+.left
push de
inc e
- jr .asm_70a1
+ jr .continue
-.asm_709e
+.right
inc d
push de
inc e
-.asm_70a1
+
+.continue
call GetCoordTile
call GetTileCollision
pop de
- and a
- jr nz, .asm_70b6
+ and a ; LAND_TILE
+ jr nz, .not_land
call GetCoordTile
call GetTileCollision
- and a
- jr nz, .asm_70b6
+ and a ; LAND_TILE
+ jr nz, .not_land
xor a
ret
-.asm_70b6
+.not_land
scf
ret
-CheckFacingObject:
+CheckFacingObject::
call GetFacingTileCoord
+
+; Double the distance for counter tiles.
call CheckCounterTile
jr nz, .asm_70d0
+
ld a, [wPlayerStandingMapX]
sub d
cpl
inc a
add d
ld d, a
+
ld a, [wPlayerStandingMapY]
sub e
cpl
inc a
add e
ld e, a
+
.asm_70d0
- ld bc, wObjectStructs
- ld a, $0
+ ld bc, wObjectStructs ; redundant
+ ld a, 0
ldh [hMapObjectIndexBuffer], a
- call Function7120
+ call IsNPCAtCoord
ret nc
- ld hl, $7
+ ld hl, OBJECT_DIRECTION_WALKING
add hl, bc
ld a, [hl]
- cp $ff
- jr z, .asm_70e6
+ cp STANDING
+ jr z, .standing
xor a
ret
-.asm_70e6
+.standing
scf
ret
-WillPersonBumpIntoSomeoneElse: ; 70e8 (1:70e8)
- ld hl, $10
+WillObjectBumpIntoSomeoneElse:
+ ld hl, OBJECT_NEXT_MAP_X
add hl, bc
ld d, [hl]
- ld hl, $11
+ ld hl, OBJECT_NEXT_MAP_Y
add hl, bc
ld e, [hl]
- jr Function7120
+ jr IsNPCAtCoord
-Function70f4:
+Unreferenced_Function70f4:
ldh a, [hMapObjectIndexBuffer]
call GetObjectStruct
- call Function7100
- call Function7120
+ call .CheckWillBeFacingNPC
+ call IsNPCAtCoord
ret
-Function7100: ; 7100 (1:7100)
- ld hl, $10
+.CheckWillBeFacingNPC:
+ ld hl, OBJECT_NEXT_MAP_X
add hl, bc
ld d, [hl]
- ld hl, $11
+ ld hl, OBJECT_NEXT_MAP_Y
add hl, bc
ld e, [hl]
call GetSpriteDirection
and a
- jr z, .asm_711a
- cp $4
- jr z, .asm_711c
- cp $8
- jr z, .asm_711e
+ jr z, .down
+ cp OW_UP
+ jr z, .up
+ cp OW_LEFT
+ jr z, .left
inc d
ret
-.asm_711a
+.down
inc e
ret
-.asm_711c
+.up
dec e
ret
-.asm_711e
+.left
dec d
ret
-Function7120: ; 7120 (1:7120)
- ld bc, wPlayerStruct
+IsNPCAtCoord:
+ ld bc, wObjectStructs
xor a
-.asm_7124
+.loop
ldh [hObjectStructIndexBuffer], a
call DoesObjectHaveASprite
- jr z, .asm_7172
- ld hl, $4
+ jr z, .next
+
+ ld hl, OBJECT_FLAGS1
add hl, bc
bit 7, [hl]
- jr nz, .asm_7172
- ld hl, $6
+ jr nz, .next
+
+ ld hl, OBJECT_PALETTE
add hl, bc
- bit 7, [hl]
- jr z, .asm_7142
+ bit BIG_OBJECT_F, [hl]
+ jr z, .got
+
call Function7250
- jr nc, .asm_715a
- jr .asm_7152
+ jr nc, .ok
+ jr .ok2
-.asm_7142
- ld hl, $10
+.got
+ ld hl, OBJECT_NEXT_MAP_X
add hl, bc
ld a, [hl]
cp d
- jr nz, .asm_715a
- ld hl, $11
+ jr nz, .ok
+ ld hl, OBJECT_NEXT_MAP_Y
add hl, bc
ld a, [hl]
cp e
- jr nz, .asm_715a
-.asm_7152
+ jr nz, .ok
+
+.ok2
ldh a, [hMapObjectIndexBuffer]
ld l, a
- ldh a, [hConnectedMapWidth]
+ ldh a, [hObjectStructIndexBuffer]
cp l
- jr nz, .asm_7181
-.asm_715a
- ld hl, $12
+ jr nz, .setcarry
+
+.ok
+ ld hl, OBJECT_MAP_X
add hl, bc
ld a, [hl]
cp d
- jr nz, .asm_7172
- ld hl, $13
+ jr nz, .next
+ ld hl, OBJECT_MAP_Y
add hl, bc
ld a, [hl]
cp e
- jr nz, .asm_7172
- ldh a, [hConnectionStripLength]
+ jr nz, .next
+ ldh a, [hMapObjectIndexBuffer]
ld l, a
ldh a, [hObjectStructIndexBuffer]
cp l
- jr nz, .asm_7181
-.asm_7172
- ld hl, $28
+ jr nz, .setcarry
+
+.next
+ ld hl, OBJECT_LENGTH
add hl, bc
ld b, h
ld c, l
- ldh a, [hConnectedMapWidth]
+ ldh a, [hObjectStructIndexBuffer]
inc a
- cp $d
- jr nz, .asm_7124
+ cp NUM_OBJECT_STRUCTS
+ jr nz, .loop
and a
ret
-.asm_7181
+.setcarry
scf
ret
-HasPersonReachedMovementLimit: ; 7183 (1:7183)
- ld hl, $16
+HasObjectReachedMovementLimit:
+ ld hl, OBJECT_RADIUS
add hl, bc
ld a, [hl]
and a
- jr z, .asm_71c8
+ jr z, .nope
and $f
- jr z, .asm_71a6
+ jr z, .check_y
ld e, a
ld d, a
- ld hl, $14
+ ld hl, OBJECT_INIT_X
add hl, bc
ld a, [hl]
sub d
@@ -370,23 +402,24 @@ HasPersonReachedMovementLimit: ; 7183 (1:7183)
ld a, [hl]
add e
ld e, a
- ld hl, $10
+ ld hl, OBJECT_NEXT_MAP_X
add hl, bc
ld a, [hl]
cp d
- jr z, .asm_71ca
+ jr z, .yes
cp e
- jr z, .asm_71ca
-.asm_71a6
- ld hl, $16
+ jr z, .yes
+
+.check_y
+ ld hl, OBJECT_RADIUS
add hl, bc
ld a, [hl]
swap a
and $f
- jr z, .asm_71c8
+ jr z, .nope
ld e, a
ld d, a
- ld hl, $15
+ ld hl, OBJECT_INIT_Y
add hl, bc
ld a, [hl]
sub d
@@ -394,132 +427,135 @@ HasPersonReachedMovementLimit: ; 7183 (1:7183)
ld a, [hl]
add e
ld e, a
- ld hl, $11
+ ld hl, OBJECT_NEXT_MAP_Y
add hl, bc
ld a, [hl]
cp d
- jr z, .asm_71ca
+ jr z, .yes
cp e
- jr z, .asm_71ca
-.asm_71c8
+ jr z, .yes
+
+.nope
xor a
ret
-.asm_71ca
+.yes
scf
ret
-IsPersonMovingOffEdgeOfScreen: ; 71cc (1:71cc)
- ld hl, $10
+IsObjectMovingOffEdgeOfScreen:
+ ld hl, OBJECT_NEXT_MAP_X
add hl, bc
ld a, [wXCoord]
cp [hl]
- jr z, .asm_71dd
- jr nc, .asm_71f0
+ jr z, .check_y
+ jr nc, .yes
add $9
cp [hl]
- jr c, .asm_71f0
-.asm_71dd
- ld hl, $11
+ jr c, .yes
+
+.check_y
+ ld hl, OBJECT_NEXT_MAP_Y
add hl, bc
ld a, [wYCoord]
cp [hl]
- jr z, .asm_71ee
- jr nc, .asm_71f0
+ jr z, .nope
+ jr nc, .yes
add $8
cp [hl]
- jr c, .asm_71f0
-.asm_71ee
+ jr c, .yes
+
+.nope
and a
ret
-.asm_71f0
+.yes
scf
ret
-Function71f2
+Unreferenced_Function71f2:
ld a, [wPlayerStandingMapX]
ld d, a
ld a, [wPlayerStandingMapY]
ld e, a
ld bc, wObjectStructs
xor a
-.asm_71fe
- ldh [hConnectedMapWidth], a
+.loop
+ ldh [hObjectStructIndexBuffer], a
call DoesObjectHaveASprite
- jr z, .asm_723f
- ld hl, $3
+ jr z, .next
+ ld hl, OBJECT_MOVEMENTTYPE
add hl, bc
ld a, [hl]
- cp $15
- jr nz, .asm_7215
+ cp SPRITEMOVEDATA_BIGDOLLSYM
+ jr nz, .not_snorlax
call Function7250
- jr c, .asm_724e
- jr .asm_723f
+ jr c, .yes
+ jr .next
-.asm_7215
- ld hl, $11
+.not_snorlax
+ ld hl, OBJECT_NEXT_MAP_Y
add hl, bc
ld a, [hl]
cp e
- jr nz, .asm_722d
- ld hl, $10
+ jr nz, .check_current_coords
+ ld hl, OBJECT_NEXT_MAP_X
add hl, bc
ld a, [hl]
cp d
- jr nz, .asm_722d
+ jr nz, .check_current_coords
ldh a, [hObjectStructIndexBuffer]
- cp $0
- jr z, .asm_723f
- jr .asm_724e
+ cp PLAYER_OBJECT
+ jr z, .next
+ jr .yes
-.asm_722d
- ld hl, $13
+.check_current_coords
+ ld hl, OBJECT_MAP_Y
add hl, bc
ld a, [hl]
cp e
- jr nz, .asm_723f
- ld hl, $12
+ jr nz, .next
+ ld hl, OBJECT_MAP_X
add hl, bc
ld a, [hl]
cp d
- jr nz, .asm_723f
- jr .asm_724e
+ jr nz, .next
+ jr .yes
-.asm_723f
- ld hl, $28
+.next
+ ld hl, OBJECT_LENGTH
add hl, bc
ld b, h
ld c, l
- ldh a, [hConnectedMapWidth]
+ ldh a, [hObjectStructIndexBuffer]
inc a
- cp $d
- jr nz, .asm_71fe
+ cp NUM_OBJECT_STRUCTS
+ jr nz, .loop
xor a
ret
-.asm_724e
+.yes
scf
ret
-Function7250: ; 7250 (1:7250)
- ld hl, $10
+Function7250:
+ ld hl, OBJECT_NEXT_MAP_X
add hl, bc
ld a, d
sub [hl]
- jr c, .asm_726a
+ jr c, .nope
cp $2
- jr nc, .asm_726a
- ld hl, $11
+ jr nc, .nope
+ ld hl, OBJECT_NEXT_MAP_Y
add hl, bc
ld a, e
sub [hl]
- jr c, .asm_726a
+ jr c, .nope
cp $2
- jr nc, .asm_726a
+ jr nc, .nope
scf
ret
-.asm_726a
+.nope
and a
ret
diff --git a/engine/overworld/overworld.asm b/engine/overworld/overworld.asm
new file mode 100644
index 00000000..05b15ea9
--- /dev/null
+++ b/engine/overworld/overworld.asm
@@ -0,0 +1,494 @@
+_ReplaceChrisSprite::
+ call GetChrisSprite
+ ld a, [wUsedSprites]
+ ld c, a
+ ld a, [wUsedSprites + 1]
+ ld b, a
+ call GetUsedSprite
+ ret
+
+_RefreshSprites::
+ ld hl, wSpriteFlags
+ ld a, [hl]
+ push af
+ res 7, [hl]
+ set 6, [hl]
+ call LoadUsedSpritesGFX
+ pop af
+ ld [wSpriteFlags], a
+ ret
+
+_ClearSprites::
+ ld hl, wSpriteFlags
+ ld a, [hl]
+ push af
+ set 7, [hl]
+ res 6, [hl]
+ call LoadUsedSpritesGFX
+ pop af
+ ld [wSpriteFlags], a
+ ret
+
+RefreshSprites::
+ call .Refresh
+ call LoadUsedSpritesGFX
+ ret
+
+.Refresh:
+ xor a
+ ld bc, SPRITE_GFX_LIST_CAPACITY * 2
+ ld hl, wUsedSprites
+ call ByteFill
+ call GetChrisSprite
+ call AddMapSprites
+ ret
+
+GetChrisSprite:
+ ld a, [wPlayerState]
+ ld c, a
+; Get Chris's sprite.
+ ld hl, ChrisStateSprites
+.loop
+ ld a, [hli]
+ cp c
+ jr z, .good
+ inc hl
+ cp -1
+ jr nz, .loop
+
+; Any player state not in the array defaults to Chris's sprite.
+ xor a ; ld a, PLAYER_NORMAL
+ ld [wPlayerState], a
+ ld a, SPRITE_CHRIS
+ jr .finish
+
+.good
+ ld a, [hl]
+
+.finish
+ ld [wUsedSprites + 0], a
+ ld [wPlayerSprite], a
+ ld [wPlayerObjectSprite], a
+ ret
+
+INCLUDE "data/sprites/player_sprites.asm"
+
+AddMapSprites:
+ call GetMapEnvironment
+ call CheckOutdoorMap
+ jr z, .outdoor
+ call AddIndoorSprites
+ ret
+
+.outdoor
+ call AddOutdoorSprites
+ ret
+
+AddIndoorSprites:
+ ld hl, wMap2ObjectSprite
+ ld a, 2
+.loop
+ push af
+ ld a, [hl]
+ call AddSpriteGFX
+ ld de, MAPOBJECT_LENGTH
+ add hl, de
+ pop af
+ inc a
+ cp NUM_OBJECTS
+ jr nz, .loop
+ ret
+
+AddOutdoorSprites:
+ ld a, [wMapGroup]
+ dec a
+ ld c, a
+ ld b, 0
+ ld hl, OutdoorSprites
+ add hl, bc
+ add hl, bc
+ ld a, [hli]
+ ld h, [hl]
+ ld l, a
+ ld c, MAX_OUTDOOR_SPRITES
+.loop
+ push bc
+ ld a, [hli]
+ call AddSpriteGFX
+ pop bc
+ dec c
+ jr nz, .loop
+
+ ld a, [wUnusedD05A]
+ ld c, a
+ ret
+
+AddSpriteGFX:
+ and a
+ ret z
+ ld c, a
+ call _DoesSpriteHaveFacings
+ jr nc, .nope
+ ld de, wUsedSprites + (SPRITE_GFX_LIST_CAPACITY - 2) * 2
+ ld b, 2
+ call .Loop
+ jr nc, .ok
+.nope
+ ld de, wUsedSprites + 2
+ ld b, SPRITE_GFX_LIST_CAPACITY - 3
+ call .Loop
+ jr .ok
+.ok:
+ ret
+
+.Loop:
+ ld a, [de]
+ and a
+ jr z, .new
+ cp c
+ jr z, .exists
+ inc de
+ inc de
+ dec b
+ jr nz, .Loop
+ scf
+ ret
+.new:
+ ld a, c
+ ld [de], a
+ xor a
+ ret
+.exists:
+ xor a
+ ret
+
+LoadUsedSpritesGFX:
+ ld a, MAPCALLBACK_SPRITES
+ call RunMapCallback
+ call GetUsedSprites
+ ret c
+
+ call _LoadMiscTiles
+ call LoadMiscTiles
+ ret
+
+GetUsedSprites:
+ xor a
+ ldh [hUsedSpriteTile], a
+ ld hl, wUsedSprites
+ ld a, SPRITE_GFX_LIST_CAPACITY - 2
+
+.loop
+ push af
+ ld a, [hli]
+ ldh [hUsedSpriteIndex], a
+ and a
+ jr z, .dont_set
+
+ call GetSprite
+ push hl
+ push bc
+ ldh a, [hUsedSpriteTile]
+ call CopyToVram
+ pop bc
+ pop hl
+ ldh a, [hUsedSpriteTile]
+ ld [hl], a
+ add c
+ ldh [hUsedSpriteTile], a
+ cp $80
+ jr nc, .done
+
+.dont_set
+ inc hl
+ pop af
+ dec a
+ jr nz, .loop
+
+ xor a
+ ret
+
+.done
+ pop af
+ scf
+ ret
+
+_LoadMiscTiles:
+ ld a, [wUsedSprites + (SPRITE_GFX_LIST_CAPACITY - 2) * 2]
+ and a
+ jr z, .asm_14274
+
+ call GetSprite
+ ld hl, vTiles0 tile $78
+ call Get2bpp
+
+.asm_14274
+ ld a, $78
+ ld [wUsedSprites + (SPRITE_GFX_LIST_CAPACITY - 2) * 2 + 1], a
+ ld a, [wUsedSprites + (SPRITE_GFX_LIST_CAPACITY - 1) * 2]
+ and a
+ jr z, .asm_14288
+
+ call GetSprite
+ ld hl, vTiles0 tile $7c
+ call Get2bpp
+
+.asm_14288
+ ld a, $7c
+ ld [wUsedSprites + (SPRITE_GFX_LIST_CAPACITY - 1) * 2 + 1], a
+ ret
+
+LoadMiscTiles:
+ ld a, [wSpriteFlags]
+ bit 6, a
+ ret nz
+
+ ld c, EMOTE_SHADOW
+ farcall LoadEmote
+ call GetMapEnvironment
+ call CheckOutdoorMap
+ ld c, EMOTE_GRASS_RUSTLE
+ jr z, .outdoor
+ ld c, EMOTE_BOULDER_DUST
+.outdoor
+ farcall LoadEmote
+ ret
+
+GetSprite:
+ call GetMonSprite
+ ret c
+
+ push hl
+ ld hl, OverworldSprites + SPRITEDATA_ADDR
+ dec a
+ ld c, a
+ ld b, 0
+ ld a, NUM_SPRITEDATA_FIELDS
+ call AddNTimes
+ ld a, [hli]
+ ld e, a
+ ld a, [hli]
+ ld d, a
+ ld a, [hli]
+ swap a
+ ld c, a
+ ld b, [hl]
+ pop hl
+ ret
+
+GetMonSprite:
+; Return carry if a monster sprite was loaded.
+
+ cp SPRITE_POKEMON
+ jr c, .Normal
+ cp SPRITE_DAY_CARE_MON_1
+ jr z, .BreedMon1
+ cp SPRITE_DAY_CARE_MON_2
+ jr z, .BreedMon2
+ cp SPRITE_VARS
+ jr nc, .Variable
+ jr .Icon
+
+.Normal:
+ and a
+ ret
+
+.Icon:
+ push hl
+ sub SPRITE_POKEMON
+ ld e, a
+ ld d, 0
+ ld hl, SpriteMons
+ add hl, de
+ ld a, [hl]
+ pop hl
+ jr .Mon
+
+.BreedMon1
+ ld a, [wBreedMon1Species]
+ jr .Mon
+
+.BreedMon2
+ ld a, [wBreedMon2Species]
+
+.Mon:
+ ld e, a
+ and a
+ jr z, .NoBreedmon
+
+ push hl
+ farcall LoadOverworldMonIcon
+ pop hl
+
+ scf
+ ret
+
+.Variable:
+ push hl
+ sub SPRITE_VARS
+ ld e, a
+ ld d, 0
+ ld hl, wVariableSprites
+ add hl, de
+ ld a, [hl]
+ pop hl
+ and a
+ jp nz, GetMonSprite
+
+.NoBreedmon:
+ ld a, 1
+ and a
+ ret
+
+_DoesSpriteHaveFacings::
+; Checks to see whether we can apply a facing to a sprite.
+; Returns carry unless the sprite is a Pokemon or a Still Sprite.
+ cp SPRITE_POKEMON
+ jr nc, .only_down
+
+ push hl
+ push bc
+ ld hl, OverworldSprites + SPRITEDATA_TYPE
+ dec a
+ ld c, a
+ ld b, 0
+ ld a, NUM_SPRITEDATA_FIELDS
+ call AddNTimes
+ ld a, [hl]
+ pop bc
+ pop hl
+ cp STILL_SPRITE
+ jr nz, .only_down
+ scf
+ ret
+
+.only_down
+ and a
+ ret
+
+_GetSpritePalette::
+ ld a, c
+ call GetMonSprite
+ jr c, .is_pokemon
+
+ ld hl, OverworldSprites + SPRITEDATA_PALETTE
+ dec a
+ ld c, a
+ ld b, 0
+ ld a, NUM_SPRITEDATA_FIELDS
+ call AddNTimes
+ ld c, [hl]
+ ret
+
+.is_pokemon
+ xor a
+ ld c, a
+ ret
+
+CopyToVram:
+ ld l, a
+ ld h, 0
+rept 4
+ add hl, hl
+endr
+ ld a, l
+ add LOW(vTiles0)
+ ld l, a
+ ld a, h
+ adc HIGH(vTiles0)
+ ld h, a
+ push hl
+ push de
+ push bc
+ ld a, [wSpriteFlags]
+ bit 7, a
+ jr nz, .skip
+ call Get2bpp
+
+.skip:
+ pop bc
+ ld l, c
+ ld h, 0
+rept 4
+ add hl, hl
+endr
+ pop de
+ add hl, de
+ ld e, l
+ ld d, h
+ pop hl
+ ld a, h
+ add HIGH(vTiles1 - vTiles0)
+ ld h, a
+ ldh a, [hUsedSpriteIndex]
+ call _DoesSpriteHaveFacings
+ jr c, .done
+
+ ld a, [wSpriteFlags]
+ bit 6, a
+ jr nz, .done
+
+ call Get2bpp
+
+.done:
+ ret
+
+Unreferenced_Function1438a:
+ ld a, c
+ jr GetUsedSprite
+
+ ld a, c
+ ld b, 0
+ jr GetUsedSprite
+
+ ld a, c
+ ld b, SPRITE_GFX_LIST_CAPACITY
+ jr GetUsedSprite
+
+GetUsedSprite:
+ push bc
+ ld a, c
+ ldh [hUsedSpriteIndex], a
+ call GetSprite
+ pop af
+ call CopyToVram
+ ret
+
+LoadEmote::
+; Get the address of the pointer to emote c.
+ ld a, c
+ ld bc, 6 ; sizeof(emote)
+ ld hl, Emotes
+ call AddNTimes
+; Load the emote address into de
+ ld e, [hl]
+ inc hl
+ ld d, [hl]
+; load the length of the emote (in tiles) into c
+ inc hl
+ ld c, [hl]
+ swap c
+; load the emote pointer bank into b
+ inc hl
+ ld b, [hl]
+; load the VRAM destination into hl
+ inc hl
+ ld a, [hli]
+ ld h, [hl]
+ ld l, a
+; if the emote has a length of 0, do not proceed (error handling)
+ ld a, c
+ and a
+ ret z
+ call Get2bpp
+ ret
+
+INCLUDE "data/sprites/emotes.asm"
+
+INCLUDE "gfx/emotes.asm"
+
+INCLUDE "data/sprites/sprite_mons.asm"
+
+INCLUDE "data/maps/outdoor_sprites.asm"
+
+INCLUDE "data/sprites/sprites.asm"
diff --git a/engine/overworld/player_movement.asm b/engine/overworld/player_movement.asm
index 3fa38cc0..bdf23ec4 100755
--- a/engine/overworld/player_movement.asm
+++ b/engine/overworld/player_movement.asm
@@ -1,421 +1,475 @@
-DoPlayerMovement:: ; 10000 (4:4000)
- call Function10017
+DoPlayerMovement::
+
+ call .GetDPad
ld a, movement_step_sleep
- ld [wcf2d], a
+ ld [wMovementAnimation], a
xor a
- ld [wcf2c], a
- call Function1002d
+ ld [wWalkingIntoEdgeWarp], a
+ call .TranslateIntoMovement
ld c, a
- ld a, [wcf2d]
- ld [wce87], a
+ ld a, [wMovementAnimation]
+ ld [wPlayerNextMovement], a
ret
-Function10017: ; 10017 (4:4017)
+.GetDPad:
+
ldh a, [hJoyDown]
- ld [wcf29], a
- CheckFlagHL ENGINE_DOWNHILL
+ ld [wCurInput], a
+
+; Standing downhill instead moves down.
+
+ ld hl, wBikeFlags
+ bit BIKEFLAGS_DOWNHILL_F, [hl]
ret z
+
ld c, a
- and $f0
+ and D_PAD
ret nz
+
ld a, c
- or $80
- ld [wcf29], a
+ or D_DOWN
+ ld [wCurInput], a
ret
-Function1002d: ; 1002d (4:402d)
+.TranslateIntoMovement:
ld a, [wPlayerState]
cp PLAYER_NORMAL
- jr z, .asm_10044
+ jr z, .Normal
cp PLAYER_SURF
- jr z, .asm_10060
+ jr z, .Surf
cp PLAYER_SURF_PIKA
- jr z, .asm_10060
+ jr z, .Surf
cp PLAYER_BIKE
- jr z, .asm_10044
- cp PLAYER_SLIP
- jr z, .asm_10074
-.asm_10044
- call Function102cb
- call Function102ec
- call Function100b7
+ jr z, .Normal
+ cp PLAYER_SKATE
+ jr z, .Ice
+
+.Normal:
+ call .CheckForced
+ call .GetAction
+ call .CheckTile
ret c
- call Function10147
+ call .CheckTurning
ret c
- call Function1016b
+ call .TryStep
ret c
- call Function101f3
+ call .TryJump
ret c
- call Function10226
+ call .CheckWarp
ret c
- jr .asm_1009d
+ jr .NotMoving
-.asm_10060
- call Function102cb
- call Function102ec
- call Function100b7
+.Surf:
+ call .CheckForced
+ call .GetAction
+ call .CheckTile
ret c
- call Function10147
+ call .CheckTurning
ret c
- call Function101c0
+ call .TrySurf
ret c
- jr .asm_1009d
+ jr .NotMoving
-.asm_10074
- call Function102cb
- call Function102ec
- call Function100b7
+.Ice:
+ call .CheckForced
+ call .GetAction
+ call .CheckTile
ret c
- call Function10147
+ call .CheckTurning
ret c
- call Function1016b
+ call .TryStep
ret c
- call Function101f3
+ call .TryJump
ret c
- call Function10226
+ call .CheckWarp
ret c
- ld a, [wcf2e]
- cp $ff
- jr z, .asm_10098
- call Function103ee
-.asm_10098
- call Function102b3
+ ld a, [wWalkingDirection]
+ cp STANDING
+ jr z, .HitWall
+ call .BumpSound
+.HitWall:
+ call .StandInPlace
xor a
ret
-.asm_1009d
- ld a, [wcf2e]
- cp $ff
- jr z, .asm_100b2
- ld a, [wTempTrainer]
+.NotMoving:
+ ld a, [wWalkingDirection]
+ cp STANDING
+ jr z, .Standing
+
+; Walking into an edge warp won't bump.
+ ld a, [wWalkingIntoEdgeWarp]
and a
- jr nz, .asm_100ad
- call Function103ee
-.asm_100ad
- call Function102bf
+ jr nz, .CantMove
+ call .BumpSound
+.CantMove:
+ call ._WalkInPlace
xor a
ret
-.asm_100b2
- call Function102b3
+.Standing:
+ call .StandInPlace
xor a
ret
-Function100b7: ; 100b7 (4:40b7)
+.CheckTile:
+; Tiles such as waterfalls and warps move the player
+; in a given direction, overriding input.
+
ld a, [wPlayerStandingTile]
ld c, a
call CheckWhirlpoolTile
- jr c, .asm_100c4
- ld a, $3
+ jr c, .not_whirlpool
+ ld a, PLAYERMOVEMENT_FORCE_TURN
scf
ret
-.asm_100c4
+.not_whirlpool
and $f0
- cp $30
- jr z, .asm_100d8
- cp $40
- jr z, .asm_100ec
- cp $50
- jr z, .asm_10108
- cp $70
- jr z, .asm_10124
- jr .asm_1013c
-
-.asm_100d8
+ cp HI_NYBBLE_CURRENT
+ jr z, .water
+ cp HI_NYBBLE_WALK
+ jr z, .land1
+ cp HI_NYBBLE_WALK_ALT
+ jr z, .land2
+ cp HI_NYBBLE_WARPS
+ jr z, .warps
+ jr .no_walk
+
+.water
ld a, c
- and $3
+ maskbits NUM_DIRECTIONS
ld c, a
- ld b, $0
+ ld b, 0
ld hl, .water_table
add hl, bc
ld a, [hl]
- ld [wcf2e], a
- jr .asm_1013e
+ ld [wWalkingDirection], a
+ jr .continue_walk
.water_table
- db RIGHT
- db LEFT
- db UP
- db DOWN
+ db RIGHT ; COLL_WATERFALL_RIGHT
+ db LEFT ; COLL_WATERFALL_LEFT
+ db UP ; COLL_WATERFALL_UP
+ db DOWN ; COLL_WATERFALL
-.asm_100ec
+.land1
ld a, c
- and $7
+ and 7
ld c, a
- ld b, $0
+ ld b, 0
ld hl, .land1_table
add hl, bc
ld a, [hl]
- cp $ff
- jr z, .asm_1013c
- ld [wcf2e], a
- jr .asm_1013e
+ cp STANDING
+ jr z, .no_walk
+ ld [wWalkingDirection], a
+ jr .continue_walk
.land1_table
- db STANDING
- db RIGHT
- db LEFT
- db UP
- db DOWN
- db STANDING
- db STANDING
- db STANDING
-
-.asm_10108
+ db STANDING ; COLL_BRAKE
+ db RIGHT ; COLL_WALK_RIGHT
+ db LEFT ; COLL_WALK_LEFT
+ db UP ; COLL_WALK_UP
+ db DOWN ; COLL_WALK_DOWN
+ db STANDING ; COLL_BRAKE_45
+ db STANDING ; COLL_BRAKE_46
+ db STANDING ; COLL_BRAKE_47
+
+.land2
ld a, c
- and $7
+ and 7
ld c, a
- ld b, $0
+ ld b, 0
ld hl, .land2_table
add hl, bc
ld a, [hl]
- cp $ff
- jr z, .asm_1013c
- ld [wcf2e], a
- jr .asm_1013e
+ cp STANDING
+ jr z, .no_walk
+ ld [wWalkingDirection], a
+ jr .continue_walk
.land2_table
- db RIGHT
- db LEFT
- db UP
- db DOWN
- db STANDING
- db STANDING
- db STANDING
- db STANDING
-
-.asm_10124
+ db RIGHT ; COLL_WALK_RIGHT_ALT
+ db LEFT ; COLL_WALK_LEFT_ALT
+ db UP ; COLL_WALK_UP_ALT
+ db DOWN ; COLL_WALK_DOWN_ALT
+ db STANDING ; COLL_BRAKE_ALT
+ db STANDING ; COLL_BRAKE_55
+ db STANDING ; COLL_BRAKE_56
+ db STANDING ; COLL_BRAKE_57
+
+.warps
ld a, c
- cp $71
- jr z, .asm_10135
- cp $79
- jr z, .asm_10135
- cp $7a
- jr z, .asm_10135
- cp $7b
- jr nz, .asm_1013c
-.asm_10135
- ld a, $0
- ld [wcf2e], a
- jr .asm_1013e
-
-.asm_1013c
+ cp COLL_DOOR
+ jr z, .down
+ cp COLL_DOOR_79
+ jr z, .down
+ cp COLL_STAIRCASE
+ jr z, .down
+ cp COLL_CAVE
+ jr nz, .no_walk
+
+.down
+ ld a, DOWN
+ ld [wWalkingDirection], a
+ jr .continue_walk
+
+.no_walk
xor a
ret
-.asm_1013e
- ld a, $1
- call Function1025f
- ld a, $5
+.continue_walk
+ ld a, STEP_WALK
+ call .DoStep
+ ld a, PLAYERMOVEMENT_CONTINUE
scf
ret
-Function10147: ; 10147 (4:4147)
- ld a, [wcf39]
- cp $0
- jr nz, .asm_10169
- ld a, [wcf2e]
- cp $ff
- jr z, .asm_10169
+.CheckTurning:
+; If the player is turning, change direction first. This also lets
+; the player change facing without moving by tapping a direction.
+
+ ld a, [wPlayerTurningDirection]
+ cp 0
+ jr nz, .not_turning
+ ld a, [wWalkingDirection]
+ cp STANDING
+ jr z, .not_turning
+
ld e, a
ld a, [wPlayerDirection]
rrca
rrca
- and $3
+ maskbits NUM_DIRECTIONS
cp e
- jr z, .asm_10169
- ld a, $5
- call Function1025f
- ld a, $2
+ jr z, .not_turning
+
+ ld a, STEP_TURN
+ call .DoStep
+ ld a, PLAYERMOVEMENT_TURN
scf
ret
-.asm_10169
+.not_turning
xor a
ret
-Function1016b: ; 1016b (4:416b)
+.TryStep:
+; Surfing actually calls .TrySurf directly instead of passing through here.
ld a, [wPlayerState]
- cp $4
- jr z, Function101c0
- cp $8
- jr z, Function101c0
- call Function1039e
- jr c, .asm_101be
- call Function10341
+ cp PLAYER_SURF
+ jr z, .TrySurf
+ cp PLAYER_SURF_PIKA
+ jr z, .TrySurf
+
+ call .CheckLandPerms
+ jr c, .bump
+
+ call .CheckNPC
and a
- jr z, .asm_101be
- cp $2
- jr z, .asm_101be
+ jr z, .bump
+ cp 2
+ jr z, .bump
+
ld a, [wPlayerStandingTile]
call CheckIceTile
- jr nc, .asm_101b5
- call Function103ca
- jr nz, .asm_101ae
+ jr nc, .ice
+
+; Downhill riding is slower when not moving down.
+ call .BikeCheck
+ jr nz, .walk
+
ld hl, wBikeFlags
- bit 2, [hl]
- jr z, .asm_101a7
- ld a, [wcf2e]
- cp $0
- jr z, .asm_101a7
- ld a, $1
- call Function1025f
+ bit BIKEFLAGS_DOWNHILL_F, [hl]
+ jr z, .fast
+
+ ld a, [wWalkingDirection]
+ cp DOWN
+ jr z, .fast
+
+ ld a, STEP_WALK
+ call .DoStep
scf
ret
-.asm_101a7
- ld a, $2
- call Function1025f
+.fast
+ ld a, STEP_BIKE
+ call .DoStep
scf
ret
-.asm_101ae
- ld a, $1
- call Function1025f
+.walk
+ ld a, STEP_WALK
+ call .DoStep
scf
ret
-.asm_101b5
- ld a, $4
- call Function1025f
+.ice
+ ld a, STEP_ICE
+ call .DoStep
scf
ret
+; unused
xor a
ret
-.asm_101be
+.bump
xor a
ret
-Function101c0: ; 101c0 (4:41c0)
- call Function103b4
- ld [wcf2b], a
- jr c, .asm_101f1
- call Function10341
- ld [wcf2a], a
+.TrySurf:
+ call .CheckSurfPerms
+ ld [wWalkingIntoLand], a
+ jr c, .surf_bump
+
+ call .CheckNPC
+ ld [wWalkingIntoNPC], a
and a
- jr z, .asm_101f1
- cp $2
- jr z, .asm_101f1
- ld a, [wcf2b]
+ jr z, .surf_bump
+ cp 2
+ jr z, .surf_bump
+
+ ld a, [wWalkingIntoLand]
and a
- jr nz, .asm_101e2
- ld a, $1
- call Function1025f
+ jr nz, .ExitWater
+
+ ld a, STEP_WALK
+ call .DoStep
scf
ret
-.asm_101e2
- call Function103f9
+.ExitWater:
+ call .GetOutOfWater
call PlayMapMusic
- ld a, $1
- call Function1025f
- ld a, $6
+ ld a, STEP_WALK
+ call .DoStep
+ ld a, PLAYERMOVEMENT_EXIT_WATER
scf
ret
-.asm_101f1
+.surf_bump
xor a
ret
-Function101f3: ; 101f3 (4:41f3)
+.TryJump:
ld a, [wPlayerStandingTile]
ld e, a
and $f0
- cp $a0
- jr nz, .asm_1021c
+ cp HI_NYBBLE_LEDGES
+ jr nz, .DontJump
+
ld a, e
- and $7
+ and 7
ld e, a
- ld d, $0
+ ld d, 0
ld hl, .data_1021e
add hl, de
- ld a, [wcf2f]
+ ld a, [wFacingDirection]
and [hl]
- jr z, .asm_1021c
- ld de, $16
+ jr z, .DontJump
+
+ ld de, SFX_JUMP_OVER_LEDGE
call PlaySFX
- ld a, $3
- call Function1025f
- ld a, $7
+ ld a, STEP_LEDGE
+ call .DoStep
+ ld a, PLAYERMOVEMENT_JUMP
scf
ret
-.asm_1021c
+.DontJump:
xor a
ret
.data_1021e
- db FACE_RIGHT
- db FACE_LEFT
- db FACE_UP
- db FACE_DOWN
- db FACE_RIGHT | FACE_DOWN
- db FACE_DOWN | FACE_LEFT
- db FACE_UP | FACE_RIGHT
- db FACE_UP | FACE_LEFT
-
-Function10226: ; 10226 (4:4226)
- ld a, [wcf2e]
+ db FACE_RIGHT ; COLL_HOP_RIGHT
+ db FACE_LEFT ; COLL_HOP_LEFT
+ db FACE_UP ; COLL_HOP_UP
+ db FACE_DOWN ; COLL_HOP_DOWN
+ db FACE_RIGHT | FACE_DOWN ; COLL_HOP_DOWN_RIGHT
+ db FACE_DOWN | FACE_LEFT ; COLL_HOP_DOWN_LEFT
+ db FACE_UP | FACE_RIGHT ; COLL_HOP_UP_RIGHT
+ db FACE_UP | FACE_LEFT ; COLL_HOP_UP_LEFT
+
+.CheckWarp:
+; Bug: Since no case is made for STANDING here, it will check
+; [.edgewarps + $ff]. This resolves to $3e at $8035a.
+; This causes wWalkingIntoEdgeWarp to be nonzero when standing on tile $3e,
+; making bumps silent.
+
+ ld a, [wWalkingDirection]
+ ; cp STANDING
+ ; jr z, .not_warp
ld e, a
- ld d, $0
- ld hl, .edge_warps
+ ld d, 0
+ ld hl, .EdgeWarps
add hl, de
ld a, [wPlayerStandingTile]
cp [hl]
- jr nz, .asm_10259
- ld a, $1
- ld [wTempTrainer], a
- ld a, [wcf2e]
- cp $ff
- jr z, .asm_10259
+ jr nz, .not_warp
+
+ ld a, TRUE
+ ld [wWalkingIntoEdgeWarp], a
+ ld a, [wWalkingDirection]
+ ; This is in the wrong place.
+ cp STANDING
+ jr z, .not_warp
+
ld e, a
ld a, [wPlayerDirection]
rrca
rrca
- and $3
+ maskbits NUM_DIRECTIONS
cp e
- jr nz, .asm_10259
- call Function22a5
- jr nc, .asm_10259
- call Function102b3
+ jr nz, .not_warp
+ call WarpCheck
+ jr nc, .not_warp
+
+ call .StandInPlace
scf
- ld a, $1
+ ld a, PLAYERMOVEMENT_WARP
ret
-.asm_10259
- xor a
+.not_warp
+ xor a ; PLAYERMOVEMENT_NORMAL
ret
-.edge_warps
- db $70, $78, $76, $7e
+.EdgeWarps:
+ db COLL_WARP_CARPET_DOWN
+ db COLL_WARP_CARPET_UP
+ db COLL_WARP_CARPET_LEFT
+ db COLL_WARP_CARPET_RIGHT
-Function1025f: ; 1025f (4:425f)
+.DoStep:
ld e, a
- ld d, $0
+ ld d, 0
ld hl, .Steps
add hl, de
add hl, de
ld a, [hli]
ld h, [hl]
ld l, a
- ld a, [wcf2e]
+
+ ld a, [wWalkingDirection]
ld e, a
- cp $ff
- jp z, Function102b3
+ cp STANDING
+ jp z, .StandInPlace
+
add hl, de
ld a, [hl]
- ld [wcf2d], a
- ld hl, $42af
+ ld [wMovementAnimation], a
+
+ ld hl, .FinishFacing
add hl, de
ld a, [hl]
- ld [wcf39], a
- ld a, $4
+ ld [wPlayerTurningDirection], a
+
+ ld a, PLAYERMOVEMENT_FINISH
ret
.Steps:
+; entries correspond to STEP_* constants
dw .SlowStep
dw .NormalStep
dw .FastStep
@@ -461,275 +515,307 @@ Function1025f: ; 1025f (4:425f)
turn_step LEFT
turn_step RIGHT
.FinishFacing:
- db $80 + DOWN
- db $80 + UP
- db $80 + LEFT
- db $80 + RIGHT
-
-Function102b3: ; 102b3 (4:42b3)
- ld a, $0
- ld [wcf39], a
- ld a, $3e
- ld [wcf2d], a
+ db $80 | DOWN
+ db $80 | UP
+ db $80 | LEFT
+ db $80 | RIGHT
+
+.StandInPlace:
+ ld a, 0
+ ld [wPlayerTurningDirection], a
+ ld a, movement_step_sleep
+ ld [wMovementAnimation], a
xor a
ret
-Function102bf: ; 102bf (4:42bf)
- ld a, $0
- ld [wTempTrainerEnd], a
- ld a, $50
- ld [wcf2d], a
+._WalkInPlace:
+ ld a, 0
+ ld [wPlayerTurningDirection], a
+ ld a, movement_step_bump
+ ld [wMovementAnimation], a
xor a
ret
-Function102cb: ; 102cb (4:42cb)
- call Function10404
+.CheckForced:
+; When sliding on ice, input is forced to remain in the same direction.
+
+ call CheckStandingOnIce
ret nc
- ld a, [wTempTrainerEnd]
-.asm_102d2
- cp $0
+
+ ld a, [wPlayerTurningDirection]
+ cp 0
ret z
- and $3
+
+ maskbits NUM_DIRECTIONS
ld e, a
- ld d, $0
+ ld d, 0
ld hl, .forced_dpad
add hl, de
- ld a, [wcf29]
- and $f
+ ld a, [wCurInput]
+ and BUTTONS
or [hl]
- ld [wcf29], a
+ ld [wCurInput], a
ret
.forced_dpad
db D_DOWN, D_UP, D_LEFT, D_RIGHT
-Function102ec: ; 102ec (4:42ec)
- ld hl, .table
- ld de, .table2 - .table1
- ld a, [wcf29]
- bit 7, a
- jr nz, .asm_10307
- bit 6, a
- jr nz, .asm_10308
-.asm_102fc
- bit 5, a
- jr nz, .asm_10309
- bit 4, a
- jr nz, .asm_1030a
- jr .asm_1030b
-
-.asm_10307
+.GetAction:
+; Poll player input and update movement info.
+
+ ld hl, .action_table
+ ld de, .action_table_1_end - .action_table_1
+ ld a, [wCurInput]
+ bit D_DOWN_F, a
+ jr nz, .d_down
+ bit D_UP_F, a
+ jr nz, .d_up
+ bit D_LEFT_F, a
+ jr nz, .d_left
+ bit D_RIGHT_F, a
+ jr nz, .d_right
+; Standing
+ jr .update
+
+.d_down
add hl, de
-.asm_10308
+.d_up
add hl, de
-.asm_10309
+.d_left
add hl, de
-.asm_1030a
+.d_right
add hl, de
-.asm_1030b
+.update
ld a, [hli]
- ld [wcf2e], a
+ ld [wWalkingDirection], a
ld a, [hli]
- ld [wcf2f], a
+ ld [wFacingDirection], a
ld a, [hli]
- ld [wcf30], a
+ ld [wWalkingX], a
ld a, [hli]
- ld [wcf31], a
+ ld [wWalkingY], a
ld a, [hli]
ld h, [hl]
ld l, a
ld a, [hl]
- ld [wWinTextPointer], a
- ret
-
-.table
-; struct:
-; walk direction
-; facing
-; x movement
-; y movement
-; tile collision pointer
-.table1
- db STANDING, FACE_CURRENT, 0, 0
- dw wPlayerStandingTile
-.table2
- db RIGHT, FACE_RIGHT, 1, 0
- dw wTileRight
- db LEFT, FACE_LEFT, -1, 0
- dw wTileLeft
- db UP, FACE_UP, 0, -1
- dw wTileUp
- db DOWN, FACE_DOWN, 0, 1
- dw wTileDown
-
-Function10341: ; 10341 (4:4341)
+ ld [wWalkingTile], a
+ ret
+
+player_action: MACRO
+; walk direction, facing, x movement, y movement, tile collision pointer
+ db \1, \2, \3, \4
+ dw \5
+ENDM
+
+.action_table:
+.action_table_1
+ player_action STANDING, FACE_CURRENT, 0, 0, wPlayerStandingTile
+.action_table_1_end
+ player_action RIGHT, FACE_RIGHT, 1, 0, wTileRight
+ player_action LEFT, FACE_LEFT, -1, 0, wTileLeft
+ player_action UP, FACE_UP, 0, -1, wTileUp
+ player_action DOWN, FACE_DOWN, 0, 1, wTileDown
+
+.CheckNPC:
+; Returns 0 if there is an NPC in front that you can't move
+; Returns 1 if there is no NPC in front
+; Returns 2 if there is a movable NPC in front
ld a, 0
ldh [hMapObjectIndexBuffer], a
+; Load the next X coordinate into d
ld a, [wPlayerStandingMapX]
ld d, a
- ld a, [wcf30]
+ ld a, [wWalkingX]
add d
ld d, a
+; Load the next Y coordinate into e
ld a, [wPlayerStandingMapY]
ld e, a
- ld a, [wcf31]
+ ld a, [wWalkingY]
add e
ld e, a
- ld bc, wPlayerSprite
- farcall Function7120
- jr nc, .asm_10369
- call Function1036f
- jr c, .asm_1036c
+; Find an object struct with coordinates equal to d,e
+ ld bc, wObjectStructs ; redundant
+ farcall IsNPCAtCoord
+ jr nc, .is_npc
+ call .CheckStrengthBoulder
+ jr c, .no_bump
+
xor a
ret
-.asm_10369
- ld a, $1
+.is_npc
+ ld a, 1
ret
-.asm_1036c
- ld a, $2
+.no_bump
+ ld a, 2
ret
-Function1036f: ; 1036f (4:436f)
+.CheckStrengthBoulder:
ld hl, wBikeFlags
- bit 0, [hl]
- jr z, .asm_1039c
- ld hl, $7
+ bit BIKEFLAGS_STRENGTH_ACTIVE_F, [hl]
+ jr z, .not_boulder
+
+ ld hl, OBJECT_DIRECTION_WALKING
add hl, bc
ld a, [hl]
- cp $ff
- jr nz, .asm_1039c
- ld hl, $6
+ cp STANDING
+ jr nz, .not_boulder
+
+ ld hl, OBJECT_PALETTE
add hl, bc
- bit 6, [hl]
- jr z, .asm_1039c
- ld hl, $5
+ bit STRENGTH_BOULDER_F, [hl]
+ jr z, .not_boulder
+
+ ld hl, OBJECT_FLAGS2
add hl, bc
set 2, [hl]
- ld a, [wcf2e]
+
+ ld a, [wWalkingDirection]
ld d, a
- ld hl, $20
+ ld hl, OBJECT_RANGE
add hl, bc
ld a, [hl]
- and $fc
+ and %11111100
or d
ld [hl], a
+
scf
ret
-.asm_1039c
+.not_boulder
xor a
ret
-Function1039e: ; 1039e (4:439e)
+.CheckLandPerms:
+; Return 0 if walking onto land and tile permissions allow it.
+; Otherwise, return carry.
+
ld a, [wTilePermissions]
ld d, a
- ld a, [wcf2f]
+ ld a, [wFacingDirection]
and d
- jr nz, .asm_103b2
- ld a, [wWinTextPointer]
- call Function103d3
- jr c, .asm_103b2
+ jr nz, .NotWalkable
+
+ ld a, [wWalkingTile]
+ call .CheckWalkable
+ jr c, .NotWalkable
+
xor a
ret
-.asm_103b2
+.NotWalkable:
scf
ret
-Function103b4: ; 103b4 (4:43b4)
+.CheckSurfPerms:
+; Return 0 if moving in water, or 1 if moving onto land.
+; Otherwise, return carry.
+
ld a, [wTilePermissions]
ld d, a
- ld a, [wcf2f]
+ ld a, [wFacingDirection]
and d
- jr nz, .asm_103c8
- ld a, [wWinTextPointer]
- call Function103da
- jr c, .asm_103c8
+ jr nz, .NotSurfable
+
+ ld a, [wWalkingTile]
+ call .CheckSurfable
+ jr c, .NotSurfable
+
and a
ret
-.asm_103c8
+.NotSurfable:
scf
ret
-Function103ca: ; 103ca (4:43ca)
+.BikeCheck:
ld a, [wPlayerState]
- cp $1
+ cp PLAYER_BIKE
ret z
- cp $2
+ cp PLAYER_SKATE
ret
-Function103d3: ; 103d3 (4:43d3)
+.CheckWalkable:
+; Return 0 if tile a is land. Otherwise, return carry.
+
call GetTileCollision
- and a
+ and a ; LAND_TILE
ret z
scf
ret
-Function103da: ; 103da (4:43da)
+.CheckSurfable:
+; Return 0 if tile a is water, or 1 if land.
+; Otherwise, return carry.
+
call GetTileCollision
- cp $1
- jr z, .asm_103e6
- and a
- jr z, .asm_103e8
- jr .asm_103ec
+ cp WATER_TILE
+ jr z, .Water
+
+; Can walk back onto land from water.
+ and a ; LAND_TILE
+ jr z, .Land
+
+ jr .Neither
-.asm_103e6
+.Water:
xor a
ret
-.asm_103e8
- ld a, $1
+.Land:
+ ld a, 1
and a
ret
-.asm_103ec
+.Neither:
scf
ret
-Function103ee: ; 103ee (4:43ee)
+.BumpSound:
call CheckSFX
ret c
- ld de, $24
+ ld de, SFX_BUMP
call PlaySFX
ret
-Function103f9: ; 103f9 (4:43f9)
+.GetOutOfWater:
push bc
- ld a, $0
+ ld a, PLAYER_NORMAL
ld [wPlayerState], a
- call ReplacePlayerSprite
+ call ReplaceChrisSprite ; UpdateSprites
pop bc
ret
-Function10404: ; 10404 (4:4404)
- ld a, [wTempTrainerEnd]
- cp $0
- jr z, .asm_10420
+CheckStandingOnIce::
+ ld a, [wPlayerTurningDirection]
+ cp 0
+ jr z, .not_ice
cp $f0
- jr z, .asm_10420
+ jr z, .not_ice
ld a, [wPlayerStandingTile]
call CheckIceTile
- jr nc, .asm_1041e
+ jr nc, .yep
ld a, [wPlayerState]
- cp $2
- jr nz, .asm_10420
-.asm_1041e
+ cp PLAYER_SKATE
+ jr nz, .not_ice
+
+.yep
scf
ret
-.asm_10420
+.not_ice
and a
ret
StopPlayerForEvent::
- ld hl, wce87
- ld a, $3e
+ ld hl, wPlayerNextMovement
+ ld a, movement_step_sleep
cp [hl]
ret z
+
ld [hl], a
- ld a, $0
- ld [wcf39], a
+ ld a, 0
+ ld [wPlayerTurningDirection], a
ret
diff --git a/engine/overworld/player_object.asm b/engine/overworld/player_object.asm
index 0865dbf8..cd886bc3 100755
--- a/engine/overworld/player_object.asm
+++ b/engine/overworld/player_object.asm
@@ -4,80 +4,81 @@ BlankScreen:
ldh [hBGMapMode], a
call ClearBGPalettes
call ClearSprites
- ld hl, wTilemap
- ld bc, SCREEN_HEIGHT * SCREEN_WIDTH
+ hlcoord 0, 0
+ ld bc, wTilemapEnd - wTilemap
ld a, " "
call ByteFill
- ld hl, wAttrmap
- ld bc, SCREEN_HEIGHT * SCREEN_WIDTH
+ hlcoord 0, 0, wAttrmap
+ ld bc, wAttrmapEnd - wAttrmap
ld a, $7
call ByteFill
call WaitBGMap2
call SetPalettes
ret
-SpawnPlayer: ; 861a (2:461a)
- ld a, $ff
+SpawnPlayer:
+ ld a, -1
ld [wObjectFollow_Leader], a
ld [wObjectFollow_Follower], a
- ld a, $0
- ld hl, .PlayerObjectTemplate
+ ld a, PLAYER
+ ld hl, PlayerObjectTemplate
call CopyPlayerObjectTemplate
- ld b, $0
+ ld b, PLAYER
call PlayerSpawn_ConvertCoords
- ld a, $0
+ ld a, PLAYER_OBJECT
ldh [hObjectStructIndexBuffer], a
ld de, wObjectStructs
- ld a, $0
+ ld a, PLAYER_OBJECT
ldh [hMapObjectIndexBuffer], a
ld bc, wMapObjects
call CopyMapObjectToObjectStruct
- ld a, $0
+ ld a, PLAYER
ld [wCenteredObject], a
ret
-.PlayerObjectTemplate
+PlayerObjectTemplate:
; A dummy map object used to initialize the player object.
; Shorter than the actual amount copied by two bytes.
; Said bytes seem to be unused.
object_event -4, -4, SPRITE_CHRIS, SPRITEMOVEDATA_PLAYER, 15, 15, -1, -1, 0, OBJECTTYPE_SCRIPT, 0, 0, -1
-CopyDECoordsToMapObject: ; 8653 (2:4653)
+CopyDECoordsToMapObject::
push de
ld a, b
call GetMapObject
pop de
- ld hl, $3
+ ld hl, MAPOBJECT_X_COORD
add hl, bc
ld [hl], d
- ld hl, $2
+ ld hl, MAPOBJECT_Y_COORD
add hl, bc
ld [hl], e
ret
-PlayerSpawn_ConvertCoords: ; 8664 (2:4664)
+PlayerSpawn_ConvertCoords:
push bc
ld a, [wXCoord]
- add $4
+ add 4
ld d, a
ld a, [wYCoord]
- add $4
+ add 4
ld e, a
pop bc
call CopyDECoordsToMapObject
ret
-WritePersonXY:
+WriteObjectXY::
ld a, b
call CheckObjectVisibility
ret c
- ld hl, $10
+
+ ld hl, OBJECT_NEXT_MAP_X
add hl, bc
ld d, [hl]
- ld hl, $11
+ ld hl, OBJECT_NEXT_MAP_Y
add hl, bc
ld e, [hl]
- ldh a, [hConnectionStripLength]
+ ldh a, [hMapObjectIndexBuffer]
ld b, a
call CopyDECoordsToMapObject
and a
@@ -85,381 +86,417 @@ WritePersonXY:
RefreshPlayerCoords:
ld a, [wXCoord]
- add $4
+ add 4
ld d, a
ld hl, wPlayerStandingMapX
sub [hl]
ld [hl], d
- ld hl, wPlayerObjectXCoord
+ ld hl, wMapObjects + MAPOBJECT_X_COORD
ld [hl], d
ld hl, wPlayerLastMapX
ld [hl], d
ld d, a
ld a, [wYCoord]
- add $4
+ add 4
ld e, a
ld hl, wPlayerStandingMapY
sub [hl]
ld [hl], e
- ld hl, wPlayerObjectYCoord
+ ld hl, wMapObjects + MAPOBJECT_Y_COORD
ld [hl], e
ld hl, wPlayerLastMapY
ld [hl], e
ld e, a
+; the next three lines are useless
ld a, [wObjectFollow_Leader]
- cp $0
+ cp PLAYER
ret nz
ret
SpawnPlayer2:
- ld a, $1
+ ld a, 1
ld hl, .PlayerObjectTemplate
call CopyPlayerObjectTemplate
- ld b, $1
+ ld b, 1
call PlayerSpawn_ConvertCoords
ret
.PlayerObjectTemplate:
object_event -4, -4, SPRITE_CHRIS, SPRITEMOVEDATA_12, 15, 15, -1, -1, 0, OBJECTTYPE_SCRIPT, 0, 0, -1
-CopyObjectStruct:: ; 86d7 (2:46d7)
+CopyObjectStruct::
call CheckObjectMask
and a
- ret nz
- ld hl, wPlayerStructEnd
- ld a, $1
- ld de, $28
-.asm_86e4
+ ret nz ; masked
+
+ ld hl, wObjectStructs + OBJECT_LENGTH * 1
+ ld a, 1
+ ld de, OBJECT_LENGTH
+.loop
ldh [hObjectStructIndexBuffer], a
ld a, [hl]
and a
- jr z, .asm_86f4
+ jr z, .done
add hl, de
- ldh a, [hConnectedMapWidth]
+ ldh a, [hObjectStructIndexBuffer]
inc a
- cp $d
- jr nz, .asm_86e4
+ cp NUM_OBJECT_STRUCTS
+ jr nz, .loop
scf
- ret
+ ret ; overflow
-.asm_86f4
+.done
ld d, h
ld e, l
call CopyMapObjectToObjectStruct
ld a, [wVramState]
bit 7, a
ret z
- ld hl, $5
+
+ ld hl, OBJECT_FLAGS2
add hl, de
set 5, [hl]
ret
-CopyMapObjectToObjectStruct: ; 8706 (2:4706)
- call CopyMapObjectToTempObject
+CopyMapObjectToObjectStruct:
+ call .CopyMapObjectToTempObject
call CopyTempObjectToObjectStruct
ret
-CopyMapObjectToTempObject: ; 870d (2:470d)
- ldh a, [hConnectedMapWidth]
- ld hl, $0
+.CopyMapObjectToTempObject:
+ ldh a, [hObjectStructIndexBuffer]
+ ld hl, MAPOBJECT_OBJECT_STRUCT_ID
add hl, bc
ld [hl], a
+
ldh a, [hMapObjectIndexBuffer]
- ld [wce99], a
- ld hl, $1
+ ld [wTempObjectCopyMapObjectIndex], a
+
+ ld hl, MAPOBJECT_SPRITE
add hl, bc
ld a, [hl]
- ld [wce9a], a
+ ld [wTempObjectCopySprite], a
+
call GetSpriteVTile
- ld [wce9b], a
+ ld [wTempObjectCopySpriteVTile], a
+
ld a, [hl]
call GetSpritePalette
- ld [wce9c], a
- ld hl, $8
+ ld [wTempObjectCopyPalette], a
+
+ ld hl, MAPOBJECT_COLOR
add hl, bc
ld a, [hl]
and $f0
- jr z, .asm_873e
+ jr z, .skip_color_override
swap a
- and $7
- ld [wce9c], a
-.asm_873e
- ld hl, $4
+ and PALETTE_MASK
+ ld [wTempObjectCopyPalette], a
+
+.skip_color_override
+ ld hl, MAPOBJECT_MOVEMENT
add hl, bc
ld a, [hl]
- ld [wce9d], a
- ld hl, $9
+ ld [wTempObjectCopyMovement], a
+
+ ld hl, MAPOBJECT_RANGE
add hl, bc
ld a, [hl]
- ld [wce9e], a
- ld hl, $3
+ ld [wTempObjectCopyRange], a
+
+ ld hl, MAPOBJECT_X_COORD
add hl, bc
ld a, [hl]
- ld [wce9f], a
- ld hl, $2
+ ld [wTempObjectCopyX], a
+
+ ld hl, MAPOBJECT_Y_COORD
add hl, bc
ld a, [hl]
- ld [wcea0], a
- ld hl, $5
+ ld [wTempObjectCopyY], a
+
+ ld hl, MAPOBJECT_RADIUS
add hl, bc
ld a, [hl]
- ld [wcea1], a
+ ld [wTempObjectCopyRadius], a
ret
-InitializeVariableSprites:
+InitializeVisibleSprites:
ld bc, wMap2Object
- ld a, $2
-.asm_876c
- ldh [hConnectionStripLength], a
- ld hl, $1
+ ld a, 2
+.loop
+ ldh [hMapObjectIndexBuffer], a
+ ld hl, MAPOBJECT_SPRITE
add hl, bc
ld a, [hl]
and a
- jr z, .asm_87ab
- ld hl, $0
+ jr z, .next
+
+ ld hl, MAPOBJECT_OBJECT_STRUCT_ID
add hl, bc
ld a, [hl]
- cp $ff
- jr nz, .asm_87ab
+ cp -1
+ jr nz, .next
+
ld a, [wXCoord]
ld d, a
ld a, [wYCoord]
ld e, a
- ld hl, $3
+
+ ld hl, MAPOBJECT_X_COORD
add hl, bc
ld a, [hl]
- add $1
+ add 1
sub d
- jr c, .asm_87ab
- cp $c
- jr nc, .asm_87ab
- ld hl, $2
+ jr c, .next
+
+ cp MAPOBJECT_SCREEN_WIDTH
+ jr nc, .next
+
+ ld hl, MAPOBJECT_Y_COORD
add hl, bc
ld a, [hl]
- add $1
+ add 1
sub e
- jr c, .asm_87ab
- cp $b
- jr nc, .asm_87ab
+ jr c, .next
+
+ cp MAPOBJECT_SCREEN_HEIGHT
+ jr nc, .next
+
push bc
call CopyObjectStruct
pop bc
- jp c, Function87b9
-.asm_87ab
- ld hl, $10
+ jp c, .ret
+
+.next
+ ld hl, MAPOBJECT_LENGTH
add hl, bc
ld b, h
ld c, l
ldh a, [hMapObjectIndexBuffer]
inc a
- cp $10
- jr nz, .asm_876c
+ cp NUM_OBJECTS
+ jr nz, .loop
ret
-Function87b9: ; 87b9 (2:47b9)
+.ret
ret
-CheckObjectEnteringVisibleRange:
+CheckObjectEnteringVisibleRange::
nop
ld a, [wPlayerStepDirection]
- cp $ff
+ cp STANDING
ret z
- ld hl, .Jumptable
+ ld hl, .dw
rst JumpTable
ret
-.Jumptable:
- dw Function87d5
- dw Function87ce
- dw Function8822
- dw Function8829
+.dw
+ dw .Down
+ dw .Up
+ dw .Left
+ dw .Right
-Function87ce:
+.Up:
ld a, [wYCoord]
- sub $1
- jr asm_87da
+ sub 1
+ jr .Vertical
-Function87d5:
+.Down:
ld a, [wYCoord]
- add $9
-asm_87da
+ add 9
+.Vertical:
ld d, a
ld a, [wXCoord]
ld e, a
ld bc, wMap2Object
- ld a, $2
-.asm_87e4
- ldh [hConnectionStripLength], a
- ld hl, $1
+ ld a, 2
+.loop_v
+ ldh [hMapObjectIndexBuffer], a
+ ld hl, MAPOBJECT_SPRITE
add hl, bc
ld a, [hl]
and a
- jr z, .asm_8814
- ld hl, $2
+ jr z, .next_v
+ ld hl, MAPOBJECT_Y_COORD
add hl, bc
ld a, d
cp [hl]
- jr nz, .asm_8814
- ld hl, $0
+ jr nz, .next_v
+ ld hl, MAPOBJECT_OBJECT_STRUCT_ID
add hl, bc
ld a, [hl]
- cp $ff
- jr nz, .asm_8814
- ld hl, $3
+ cp -1
+ jr nz, .next_v
+ ld hl, MAPOBJECT_X_COORD
add hl, bc
ld a, [hl]
- add $1
+ add 1
sub e
- jr c, .asm_8814
- cp $c
- jr nc, .asm_8814
+ jr c, .next_v
+ cp MAPOBJECT_SCREEN_WIDTH
+ jr nc, .next_v
push de
push bc
call CopyObjectStruct
pop bc
pop de
-.asm_8814
- ld hl, $10
+
+.next_v
+ ld hl, MAPOBJECT_LENGTH
add hl, bc
ld b, h
ld c, l
ldh a, [hMapObjectIndexBuffer]
inc a
- cp $10
- jr nz, .asm_87e4
+ cp NUM_OBJECTS
+ jr nz, .loop_v
ret
-Function8822:
+.Left:
ld a, [wXCoord]
- sub $1
- jr asm_882e
+ sub 1
+ jr .Horizontal
-Function8829:
+.Right:
ld a, [wXCoord]
- add $a
-asm_882e
+ add 10
+.Horizontal:
ld e, a
ld a, [wYCoord]
ld d, a
ld bc, wMap2Object
- ld a, $2
-.asm_8838
- ldh [hConnectionStripLength], a
- ld hl, $1
+ ld a, 2
+.loop_h
+ ldh [hMapObjectIndexBuffer], a
+ ld hl, MAPOBJECT_SPRITE
add hl, bc
ld a, [hl]
and a
- jr z, .asm_8868
- ld hl, $3
+ jr z, .next_h
+ ld hl, MAPOBJECT_X_COORD
add hl, bc
ld a, e
cp [hl]
- jr nz, .asm_8868
- ld hl, $0
+ jr nz, .next_h
+ ld hl, MAPOBJECT_OBJECT_STRUCT_ID
add hl, bc
ld a, [hl]
- cp $ff
- jr nz, .asm_8868
- ld hl, $2
+ cp -1
+ jr nz, .next_h
+ ld hl, MAPOBJECT_Y_COORD
add hl, bc
ld a, [hl]
- add $1
+ add 1
sub d
- jr c, .asm_8868
- cp $b
- jr nc, .asm_8868
+ jr c, .next_h
+ cp MAPOBJECT_SCREEN_HEIGHT
+ jr nc, .next_h
push de
push bc
call CopyObjectStruct
pop bc
pop de
-.asm_8868
- ld hl, $10
+
+.next_h
+ ld hl, MAPOBJECT_LENGTH
add hl, bc
ld b, h
ld c, l
- ldh a, [hConnectionStripLength]
+ ldh a, [hMapObjectIndexBuffer]
inc a
- cp $10
- jr nz, .asm_8838
+ cp NUM_OBJECTS
+ jr nz, .loop_h
ret
-CopyTempObjectToObjectStruct: ; 8876 (2:4876)
- ld a, [wce99]
- ld hl, $1
+CopyTempObjectToObjectStruct:
+ ld a, [wTempObjectCopyMapObjectIndex]
+ ld hl, OBJECT_MAP_OBJECT_INDEX
add hl, de
ld [hl], a
- ld a, [wce9d]
+
+ ld a, [wTempObjectCopyMovement]
call CopySpriteMovementData
- ld a, [wce9c]
- ld hl, $6
+
+ ld a, [wTempObjectCopyPalette]
+ ld hl, OBJECT_PALETTE
add hl, de
or [hl]
ld [hl], a
- ld a, [wcea0]
- call InitTempObjectYCoord
- ld a, [wce9f]
- call InitTempObjectXCoord
- ld a, [wce9a]
- ld hl, $0
+
+ ld a, [wTempObjectCopyY]
+ call .InitYCoord
+
+ ld a, [wTempObjectCopyX]
+ call .InitXCoord
+
+ ld a, [wTempObjectCopySprite]
+ ld hl, OBJECT_SPRITE
add hl, de
ld [hl], a
- ld a, [wce9b]
- ld hl, $2
+
+ ld a, [wTempObjectCopySpriteVTile]
+ ld hl, OBJECT_SPRITE_TILE
add hl, de
ld [hl], a
- ld hl, $9
+
+ ld hl, OBJECT_STEP_TYPE
add hl, de
- ld [hl], $0
- ld hl, $d
+ ld [hl], STEP_TYPE_00
+
+ ld hl, OBJECT_FACING_STEP
add hl, de
- ld [hl], $ff
- ld a, [wcea1]
- call InitTempObjectRadius
- ld a, [wce9e]
- ld hl, $20
+ ld [hl], STANDING
+
+ ld a, [wTempObjectCopyRadius]
+ call .InitRadius
+
+ ld a, [wTempObjectCopyRange]
+ ld hl, OBJECT_RANGE
add hl, de
ld [hl], a
+
and a
ret
-InitTempObjectYCoord: ; 88c5 (2:48c5)
- ld hl, $15
+.InitYCoord:
+ ld hl, OBJECT_INIT_Y
add hl, de
ld [hl], a
- ld hl, $11
+
+ ld hl, OBJECT_NEXT_MAP_Y
add hl, de
ld [hl], a
+
ld hl, wYCoord
sub [hl]
and $f
swap a
- ld hl, wce82
+ ld hl, wPlayerBGMapOffsetY
sub [hl]
- ld hl, $18
+ ld hl, OBJECT_SPRITE_Y
add hl, de
ld [hl], a
ret
-InitTempObjectXCoord: ; 88e1 (2:48e1)
- ld hl, $14
+.InitXCoord:
+ ld hl, OBJECT_INIT_X
add hl, de
ld [hl], a
- ld hl, $10
+ ld hl, OBJECT_NEXT_MAP_X
add hl, de
ld [hl], a
ld hl, wXCoord
sub [hl]
and $f
swap a
- ld hl, wce81
+ ld hl, wPlayerBGMapOffsetX
sub [hl]
- ld hl, $17
+ ld hl, OBJECT_SPRITE_X
add hl, de
ld [hl], a
ret
-InitTempObjectRadius: ; 88fd (2:48fd)
+.InitRadius:
ld h, a
inc a
and $f
@@ -468,93 +505,102 @@ InitTempObjectRadius: ; 88fd (2:48fd)
add $10
and $f0
or l
- ld hl, $16
+ ld hl, OBJECT_RADIUS
add hl, de
ld [hl], a
ret
-TrainerWalkToPlayer:
+TrainerWalkToPlayer::
ldh a, [hLastTalked]
call InitMovementBuffer
ld a, movement_step_sleep
call AppendToMovementBuffer
- ld a, [wcf2a]
+ ld a, [wWalkingIntoNPC]
dec a
- jr z, .asm_892b
+ jr z, .TerminateStep
ldh a, [hLastTalked]
ld b, a
ld c, PLAYER
- ld d, $1
- call GetTrainerPathToPlayer
+ ld d, 1
+ call .GetPathToPlayer
call DecrementMovementBufferCount
-.asm_892b
+
+.TerminateStep:
ld a, movement_step_end
call AppendToMovementBuffer
ret
-GetTrainerPathToPlayer: ; 8931 (2:4931)
+.GetPathToPlayer:
push de
push bc
+; get player object struct, load to de
ld a, c
call GetMapObject
- ld hl, $0
+ ld hl, MAPOBJECT_OBJECT_STRUCT_ID
add hl, bc
ld a, [hl]
call GetObjectStruct
ld d, b
ld e, c
+
+; get last talked object struct, load to bc
pop bc
ld a, b
call GetMapObject
- ld hl, $0
+ ld hl, MAPOBJECT_OBJECT_STRUCT_ID
add hl, bc
ld a, [hl]
call GetObjectStruct
- ld hl, $10
+
+; get last talked coords, load to bc
+ ld hl, OBJECT_NEXT_MAP_X
add hl, bc
ld a, [hl]
- ld hl, $11
+ ld hl, OBJECT_NEXT_MAP_Y
add hl, bc
ld c, [hl]
ld b, a
- ld hl, $10
+
+; get player coords, load to de
+ ld hl, OBJECT_NEXT_MAP_X
add hl, de
ld a, [hl]
- ld hl, $11
+ ld hl, OBJECT_NEXT_MAP_Y
add hl, de
ld e, [hl]
ld d, a
+
pop af
call ComputePathToWalkToPlayer
ret
-SurfStartStep: ; 8969 (2:4969)
+SurfStartStep:
call InitMovementBuffer
- call GetInitialSurfStep
+ call .GetMovementData
call AppendToMovementBuffer
ld a, movement_step_end
call AppendToMovementBuffer
ret
-GetInitialSurfStep: ; 8978 (2:4978)
+.GetMovementData:
ld a, [wPlayerDirection]
srl a
srl a
- and $3
+ maskbits NUM_DIRECTIONS
ld e, a
- ld d, $0
- ld hl, .Data ; $498a
+ ld d, 0
+ ld hl, .movement_data
add hl, de
ld a, [hl]
ret
-.Data
+.movement_data
slow_step DOWN
slow_step UP
slow_step LEFT
slow_step RIGHT
-FollowNotExact:
+FollowNotExact::
push bc
ld a, c
call CheckObjectVisibility
@@ -562,43 +608,48 @@ FollowNotExact:
ld e, c
pop bc
ret c
+
ld a, b
call CheckObjectVisibility
ret c
- ld hl, $10
+
+; object 2 is now in bc, object 1 is now in de
+ ld hl, OBJECT_NEXT_MAP_X
add hl, bc
ld a, [hl]
- ld hl, $11
+ ld hl, OBJECT_NEXT_MAP_Y
add hl, bc
ld c, [hl]
ld b, a
- ld hl, $10
+
+ ld hl, OBJECT_NEXT_MAP_X
add hl, de
ld a, [hl]
cp b
- jr z, .asm_89b7
- jr c, .asm_89b4
+ jr z, .same_x
+ jr c, .to_the_left
inc b
- jr .asm_89c5
+ jr .continue
-.asm_89b4
+.to_the_left
dec b
- jr .asm_89c5
+ jr .continue
-.asm_89b7
- ld hl, $11
+.same_x
+ ld hl, OBJECT_NEXT_MAP_Y
add hl, de
ld a, [hl]
cp c
- jr z, .asm_89c5
- jr c, .asm_89c4
+ jr z, .continue
+ jr c, .below
inc c
- jr .asm_89c5
+ jr .continue
-.asm_89c4
+.below
dec c
-.asm_89c5
- ld hl, $10
+
+.continue
+ ld hl, OBJECT_NEXT_MAP_X
add hl, de
ld [hl], b
ld a, b
@@ -606,12 +657,12 @@ FollowNotExact:
sub [hl]
and $f
swap a
- ld hl, wce81
+ ld hl, wPlayerBGMapOffsetX
sub [hl]
- ld hl, $17
+ ld hl, OBJECT_SPRITE_X
add hl, de
ld [hl], a
- ld hl, $11
+ ld hl, OBJECT_NEXT_MAP_Y
add hl, de
ld [hl], c
ld a, c
@@ -619,171 +670,184 @@ FollowNotExact:
sub [hl]
and $f
swap a
- ld hl, wce82
+ ld hl, wPlayerBGMapOffsetY
sub [hl]
- ld hl, $18
+ ld hl, OBJECT_SPRITE_Y
add hl, de
ld [hl], a
ldh a, [hObjectStructIndexBuffer]
- ld hl, $20
+ ld hl, OBJECT_RANGE
add hl, de
ld [hl], a
- ld hl, $3
+ ld hl, OBJECT_MOVEMENTTYPE
add hl, de
- ld [hl], $1a
- ld hl, $9
+ ld [hl], SPRITEMOVEDATA_FOLLOWNOTEXACT
+ ld hl, OBJECT_STEP_TYPE
add hl, de
- ld [hl], $0
+ ld [hl], STEP_TYPE_00
ret
-GetRelativeFacing:
+GetRelativeFacing::
+; Determines which way map object e would have to turn to face map object d. Returns carry if it's impossible for whatever reason.
ld a, d
call GetMapObject
- ld hl, $0
+ ld hl, MAPOBJECT_OBJECT_STRUCT_ID
add hl, bc
ld a, [hl]
- cp $d
- jr nc, .asm_8a27
+ cp NUM_OBJECT_STRUCTS
+ jr nc, .carry
ld d, a
ld a, e
call GetMapObject
- ld hl, $0
+ ld hl, MAPOBJECT_OBJECT_STRUCT_ID
add hl, bc
ld a, [hl]
- cp $d
- jr nc, .asm_8a27
+ cp NUM_OBJECT_STRUCTS
+ jr nc, .carry
ld e, a
- call GetFacing_e_relativeto_d
+ call .GetFacing_e_relativeto_d
ret
-.asm_8a27
+.carry
scf
ret
-GetFacing_e_relativeto_d: ; 8a29 (2:4a29)
+.GetFacing_e_relativeto_d:
+; Determines which way object e would have to turn to face object d. Returns carry if it's impossible.
+; load the coordinates of object d into bc
ld a, d
call GetObjectStruct
- ld hl, $10
+ ld hl, OBJECT_NEXT_MAP_X
add hl, bc
ld a, [hl]
- ld hl, $11
+ ld hl, OBJECT_NEXT_MAP_Y
add hl, bc
ld c, [hl]
ld b, a
push bc
+; load the coordinates of object e into de
ld a, e
call GetObjectStruct
- ld hl, $10
+ ld hl, OBJECT_NEXT_MAP_X
add hl, bc
ld d, [hl]
- ld hl, $11
+ ld hl, OBJECT_NEXT_MAP_Y
add hl, bc
ld e, [hl]
pop bc
+; |x1 - x2|
ld a, b
sub d
- jr z, .asm_8a5c
- jr nc, .asm_8a50
+ jr z, .same_x_1
+ jr nc, .b_right_of_d_1
cpl
inc a
-.asm_8a50
+
+.b_right_of_d_1
+; |y1 - y2|
ld h, a
ld a, c
sub e
- jr z, .asm_8a6a
- jr nc, .asm_8a59
+ jr z, .same_y_1
+ jr nc, .c_below_e_1
cpl
inc a
-.asm_8a59
+
+.c_below_e_1
+; |y1 - y2| - |x1 - x2|
sub h
- jr c, .asm_8a6a
-.asm_8a5c
+ jr c, .same_y_1
+
+.same_x_1
+; compare the y coordinates
ld a, c
cp e
- jr z, .asm_8a78
- jr c, .asm_8a66
- ld d, $0
+ jr z, .same_x_and_y
+ jr c, .c_directly_below_e
+; c directly above e
+ ld d, DOWN
and a
ret
-.asm_8a66
- ld d, $1
+.c_directly_below_e
+ ld d, UP
and a
ret
-.asm_8a6a
+.same_y_1
ld a, b
cp d
- jr z, .asm_8a78
- jr c, .asm_8a74
- ld d, $3
+ jr z, .same_x_and_y
+ jr c, .b_directly_right_of_d
+; b directly left of d
+ ld d, RIGHT
and a
ret
-.asm_8a74
- ld d, $2
+.b_directly_right_of_d
+ ld d, LEFT
and a
ret
-.asm_8a78
+.same_x_and_y
scf
ret
-QueueFollowerFirstStep: ; 8a7a (2:4a7a)
- call Function8a8d
- jr c, .asm_8a87
+QueueFollowerFirstStep:
+ call .QueueFirstStep
+ jr c, .same
ld [wFollowMovementQueue], a
xor a
ld [wFollowerMovementQueueLength], a
ret
-.asm_8a87
- ld a, $ff
+.same
+ ld a, -1
ld [wFollowerMovementQueueLength], a
ret
-Function8a8d: ; 8a8d (2:4a8d)
+.QueueFirstStep:
ld a, [wObjectFollow_Leader]
call GetObjectStruct
- ld hl, $10
+ ld hl, OBJECT_NEXT_MAP_X
add hl, bc
ld d, [hl]
- ld hl, $11
+ ld hl, OBJECT_NEXT_MAP_Y
add hl, bc
ld e, [hl]
ld a, [wObjectFollow_Follower]
call GetObjectStruct
- ld hl, $10
+ ld hl, OBJECT_NEXT_MAP_X
add hl, bc
ld a, d
cp [hl]
- jr z, .asm_8ab5
- jr c, .asm_8ab1
+ jr z, .check_y
+ jr c, .left
and a
- ld a, $f
+ ld a, movement_step + RIGHT
ret
-.asm_8ab1
+.left
and a
- ld a, $e
+ ld a, movement_step + LEFT
ret
-.asm_8ab5
- ld hl, $11
+.check_y
+ ld hl, OBJECT_NEXT_MAP_Y
add hl, bc
ld a, e
cp [hl]
- jr z, .asm_8ac7
- jr c, .asm_8ac3
+ jr z, .same_xy
+ jr c, .up
and a
- ld a, $c
+ ld a, movement_step + DOWN
ret
-.asm_8ac3
+.up
and a
- ld a, $d
+ ld a, movement_step + UP
ret
-.asm_8ac7
+.same_xy
scf
ret
diff --git a/engine/overworld/player_step.asm b/engine/overworld/player_step.asm
index 36698ed8..a290730c 100755
--- a/engine/overworld/player_step.asm
+++ b/engine/overworld/player_step.asm
@@ -1,37 +1,37 @@
-HandlePlayerStep_::
+_HandlePlayerStep::
ld a, [wPlayerStepFlags]
and a
ret z
- bit 7, a
- jr nz, .asm_d4b6
- bit 6, a
- jr nz, .asm_d4c0
- bit 5, a
- jr nz, .asm_d4c5
+ bit PLAYERSTEP_START_F, a
+ jr nz, .update_overworld_map
+ bit PLAYERSTEP_STOP_F, a
+ jr nz, .update_player_coords
+ bit PLAYERSTEP_CONTINUE_F, a
+ jr nz, .finish
ret
-.asm_d4b6
- ld a, $4
+.update_overworld_map
+ ld a, 4
ld [wHandlePlayerStep], a
- call Functiond53c
- jr .asm_d4c5
+ call UpdateOverworldMap
+ jr .finish
-.asm_d4c0
- call Functiond517
- jr .asm_d4c5
+.update_player_coords
+ call UpdatePlayerCoords
+ jr .finish
-.asm_d4c5
- call Functiond4f2
+.finish
+ call HandlePlayerStep
ld a, [wPlayerStepVectorX]
ld d, a
ld a, [wPlayerStepVectorY]
ld e, a
- ld a, [wce81]
+ ld a, [wPlayerBGMapOffsetX]
sub d
- ld [wce81], a
- ld a, [wce82]
+ ld [wPlayerBGMapOffsetX], a
+ ld a, [wPlayerBGMapOffsetY]
sub e
- ld [wce82], a
+ ld [wPlayerBGMapOffsetY], a
ret
ScrollScreen::
@@ -47,7 +47,7 @@ ScrollScreen::
ldh [hSCY], a
ret
-Functiond4f2: ; d4f2 (3:54f2)
+HandlePlayerStep:
ld hl, wHandlePlayerStep
ld a, [hl]
and a
@@ -58,146 +58,147 @@ Functiond4f2: ; d4f2 (3:54f2)
rst JumpTable
ret
-.Jumptable
+.Jumptable:
dw GetMovementPermissions
dw BufferScreen
- dw Functiond515
- dw Functiond516
- dw Functiond515
- dw Functiond515
- dw Functiond515
- dw Functiond515
- dw Functiond515
- dw Functiond515
- dw Functiond515
+ dw .fail1
+ dw .fail2
+; The rest are never used. Ever.
+ dw .fail1
+ dw .fail1
+ dw .fail1
+ dw .fail1
+ dw .fail1
+ dw .fail1
+ dw .fail1
-Functiond515:
+.fail1
ret
-Functiond516:
+.fail2
ret
-Functiond517: ; d517 (3:5517)
+UpdatePlayerCoords:
ld a, [wPlayerStepDirection]
and a
- jr nz, .asm_d522
+ jr nz, .check_step_down
ld hl, wYCoord
inc [hl]
ret
-.asm_d522
- cp $1
- jr nz, .asm_d52b
+.check_step_down
+ cp UP
+ jr nz, .check_step_left
ld hl, wYCoord
dec [hl]
ret
-.asm_d52b
- cp $2
- jr nz, .asm_d534
+.check_step_left
+ cp LEFT
+ jr nz, .check_step_right
ld hl, wXCoord
dec [hl]
ret
-.asm_d534
- cp $3
+.check_step_right
+ cp RIGHT
ret nz
ld hl, wXCoord
inc [hl]
ret
-Functiond53c: ; d53c (3:553c)
+UpdateOverworldMap:
ld a, [wPlayerStepDirection]
and a
- jr z, .asm_d54f
- cp $1
- jr z, .asm_d559
- cp $2
- jr z, .asm_d563
- cp $3
- jr z, .asm_d56d
+ jr z, .step_down
+ cp UP
+ jr z, .step_up
+ cp LEFT
+ jr z, .step_left
+ cp RIGHT
+ jr z, .step_right
ret
-.asm_d54f
- call Functiond577
+.step_down
+ call .ScrollOverworldMapDown
call LoadMapPart
- call ScrollMapUp
+ call ScrollMapDown
ret
-.asm_d559
- call Functiond5a8
+.step_up
+ call .ScrollOverworldMapUp
call LoadMapPart
- call ScrollMapDown
+ call ScrollMapUp
ret
-.asm_d563
- call Functiond5db
+.step_left
+ call .ScrollOverworldMapLeft
call LoadMapPart
- call ScrollMapRight
+ call ScrollMapLeft
ret
-.asm_d56d
- call Functiond604
+.step_right
+ call .ScrollOverworldMapRight
call LoadMapPart
- call ScrollMapLeft
+ call ScrollMapRight
ret
-Functiond577: ; d577 (3:5577)
- ld a, [wd05b]
- add $40
- ld [wd05b], a
- jr nc, .asm_d58c
- ld a, [wd05c]
+.ScrollOverworldMapDown:
+ ld a, [wBGMapAnchor]
+ add 2 * BG_MAP_WIDTH
+ ld [wBGMapAnchor], a
+ jr nc, .not_overflowed
+ ld a, [wBGMapAnchor + 1]
inc a
- and $3
- or $98
- ld [wd05c], a
-.asm_d58c
- ld hl, wd07f
+ and %11
+ or HIGH(vBGMap0)
+ ld [wBGMapAnchor + 1], a
+.not_overflowed
+ ld hl, wMetatileStandingY
inc [hl]
ld a, [hl]
- cp $2
- jr nz, .asm_d59a
- ld [hl], $0
- call Functiond59b
-.asm_d59a
+ cp 2 ; was 1
+ jr nz, .done_down
+ ld [hl], 0
+ call .ScrollMapDataDown
+.done_down
ret
-Functiond59b: ; d59b (3:559b)
+.ScrollMapDataDown:
ld hl, wOverworldMapAnchor
ld a, [wMapWidth]
- add $6
+ add 3 * 2 ; surrounding tiles
add [hl]
ld [hli], a
ret nc
inc [hl]
ret
-Functiond5a8: ; d5a8 (3:55a8)
- ld a, [wd05b]
- sub $40
- ld [wd05b], a
- jr nc, .asm_d5bd
- ld a, [wd05c]
+.ScrollOverworldMapUp:
+ ld a, [wBGMapAnchor]
+ sub 2 * BG_MAP_WIDTH
+ ld [wBGMapAnchor], a
+ jr nc, .not_underflowed
+ ld a, [wBGMapAnchor + 1]
dec a
- and $3
- or $98
- ld [wd05c], a
-.asm_d5bd
- ld hl, wd07f
+ and %11
+ or HIGH(vBGMap0)
+ ld [wBGMapAnchor + 1], a
+.not_underflowed
+ ld hl, wMetatileStandingY
dec [hl]
ld a, [hl]
- cp $ff
- jr nz, .asm_d5cb
+ cp -1 ; was 0
+ jr nz, .done_up
ld [hl], $1
- call Functiond5cc
-.asm_d5cb
+ call .ScrollMapDataUp
+.done_up
ret
-Functiond5cc: ; d5cc (3:55cc)
+.ScrollMapDataUp:
ld hl, wOverworldMapAnchor
ld a, [wMapWidth]
- add $6
+ add 3 * 2 ; surrounding tiles
ld b, a
ld a, [hl]
sub b
@@ -206,8 +207,8 @@ Functiond5cc: ; d5cc (3:55cc)
dec [hl]
ret
-Functiond5db: ; d5db (3:55db)
- ld a, [wd05b]
+.ScrollOverworldMapLeft:
+ ld a, [wBGMapAnchor]
ld e, a
and $e0
ld d, a
@@ -215,28 +216,28 @@ Functiond5db: ; d5db (3:55db)
sub $2
and $1f
or d
- ld [wd05b], a
- ld hl, wd080
+ ld [wBGMapAnchor], a
+ ld hl, wMetatileStandingX
dec [hl]
ld a, [hl]
- cp $ff
- jr nz, .asm_d5f9
- ld [hl], $1
- call Functiond5fa
-.asm_d5f9
+ cp -1
+ jr nz, .done_left
+ ld [hl], 1
+ call .ScrollMapDataLeft
+.done_left
ret
-Functiond5fa: ; d5fa (3:55fa)
+.ScrollMapDataLeft:
ld hl, wOverworldMapAnchor
ld a, [hl]
- sub $1
+ sub 1
ld [hli], a
ret nc
dec [hl]
ret
-Functiond604: ; d604 (3:5604)
- ld a, [wd05b]
+.ScrollOverworldMapRight:
+ ld a, [wBGMapAnchor]
ld e, a
and $e0
ld d, a
@@ -244,21 +245,21 @@ Functiond604: ; d604 (3:5604)
add $2
and $1f
or d
- ld [wd05b], a
- ld hl, wd080
+ ld [wBGMapAnchor], a
+ ld hl, wMetatileStandingX
inc [hl]
ld a, [hl]
- cp $2
- jr nz, .asm_d622
- ld [hl], $0
- call Functiond623
-.asm_d622
+ cp 2
+ jr nz, .done_right
+ ld [hl], 0
+ call .ScrollMapDataRight
+.done_right
ret
-Functiond623: ; d623 (3:5623)
+.ScrollMapDataRight:
ld hl, wOverworldMapAnchor
ld a, [hl]
- add $1
+ add 1
ld [hli], a
ret nc
inc [hl]
diff --git a/engine/overworld/scripting.asm b/engine/overworld/scripting.asm
new file mode 100644
index 00000000..7659c42d
--- /dev/null
+++ b/engine/overworld/scripting.asm
@@ -0,0 +1,2673 @@
+; Event scripting commands.
+
+EnableScriptMode::
+ push af
+ ld a, SCRIPT_READ
+ ld [wScriptMode], a
+ pop af
+ ret
+
+ScriptEvents::
+ call StartScript
+.loop
+ ld a, [wScriptMode]
+ ld hl, .modes
+ rst JumpTable
+ call CheckScript
+ jr nz, .loop
+ ret
+
+.modes
+ dw EndScript
+ dw RunScriptCommand
+ dw WaitScriptMovement
+ dw WaitScript
+
+EndScript:
+ call StopScript
+ ret
+
+WaitScript:
+ call StopScript
+
+ ld hl, wScriptDelay
+ dec [hl]
+ ret nz
+
+ farcall Function582f
+
+ ld a, SCRIPT_READ
+ ld [wScriptMode], a
+ call StartScript
+ ret
+
+WaitScriptMovement:
+ call StopScript
+
+ ld hl, wVramState
+ bit 7, [hl]
+ ret nz
+
+ farcall Function582f
+
+ ld a, SCRIPT_READ
+ ld [wScriptMode], a
+ call StartScript
+ ret
+
+RunScriptCommand:
+ call GetScriptByte
+ ld hl, ScriptCommandTable
+ rst JumpTable
+ ret
+
+ScriptCommandTable:
+; entries correspond to macros/scripts/events.asm enumeration
+ dw Script_scall ; 00
+ dw Script_farscall ; 01
+ dw Script_memcall ; 02
+ dw Script_sjump ; 03
+ dw Script_farsjump ; 04
+ dw Script_memjump ; 05
+ dw Script_ifequal ; 06
+ dw Script_ifnotequal ; 07
+ dw Script_iffalse ; 08
+ dw Script_iftrue ; 09
+ dw Script_ifgreater ; 0a
+ dw Script_ifless ; 0b
+ dw Script_jumpstd ; 0c
+ dw Script_callstd ; 0d
+ dw Script_callasm ; 0e
+ dw Script_special ; 0f
+ dw Script_memcallasm ; 10
+ dw Script_checkmapscene ; 11
+ dw Script_setmapscene ; 12
+ dw Script_checkscene ; 13
+ dw Script_setscene ; 14
+ dw Script_setval ; 15
+ dw Script_addval ; 16
+ dw Script_random ; 17
+ dw Script_checkver ; 18
+ dw Script_readmem ; 19
+ dw Script_writemem ; 1a
+ dw Script_loadmem ; 1b
+ dw Script_readvar ; 1c
+ dw Script_writevar ; 1d
+ dw Script_loadvar ; 1e
+ dw Script_giveitem ; 1f
+ dw Script_takeitem ; 20
+ dw Script_checkitem ; 21
+ dw Script_givemoney ; 22
+ dw Script_takemoney ; 23
+ dw Script_checkmoney ; 24
+ dw Script_givecoins ; 25
+ dw Script_takecoins ; 26
+ dw Script_checkcoins ; 27
+ dw Script_addcellnum ; 28
+ dw Script_delcellnum ; 29
+ dw Script_checkcellnum ; 2a
+ dw Script_checktime ; 2b
+ dw Script_checkpoke ; 2c
+ dw Script_givepoke ; 2d
+ dw Script_giveegg ; 2e
+ dw Script_givepokemail ; 2f
+ dw Script_checkpokemail ; 30
+ dw Script_checkevent ; 31
+ dw Script_clearevent ; 32
+ dw Script_setevent ; 33
+ dw Script_checkflag ; 34
+ dw Script_clearflag ; 35
+ dw Script_setflag ; 36
+ dw Script_wildon ; 37
+ dw Script_wildoff ; 38
+ dw Script_xycompare ; 39
+ dw Script_warpmod ; 3a
+ dw Script_blackoutmod ; 3b
+ dw Script_warp ; 3c
+ dw Script_getmoney ; 3d
+ dw Script_getcoins ; 3e
+ dw Script_getnum ; 3f
+ dw Script_getmonname ; 40
+ dw Script_getitemname ; 41
+ dw Script_getcurlandmarkname ; 42
+ dw Script_gettrainername ; 43
+ dw Script_getstring ; 44
+ dw Script_itemnotify ; 45
+ dw Script_pocketisfull ; 46
+ dw Script_opentext ; 47
+ dw Script_refreshscreen ; 48
+ dw Script_closetext ; 49
+ dw Script_writeunusedbytebuffer ; 4a
+ dw Script_farwritetext ; 4b
+ dw Script_writetext ; 4c
+ dw Script_repeattext ; 4d
+ dw Script_yesorno ; 4e
+ dw Script_loadmenu ; 4f
+ dw Script_closewindow ; 50
+ dw Script_jumptextfaceplayer ; 51
+ dw Script_jumptext ; 52
+ dw Script_waitbutton ; 53
+ dw Script_promptbutton ; 54
+ dw Script_pokepic ; 55
+ dw Script_closepokepic ; 56
+ dw Script__2dmenu ; 57
+ dw Script_verticalmenu ; 58
+ dw Script_loadpikachudata ; 59
+ dw Script_randomwildmon ; 5a
+ dw Script_loadtemptrainer ; 5b
+ dw Script_loadwildmon ; 5c
+ dw Script_loadtrainer ; 5d
+ dw Script_startbattle ; 5e
+ dw Script_reloadmapafterbattle ; 5f
+ dw Script_catchtutorial ; 60
+ dw Script_trainertext ; 61
+ dw Script_trainerflagaction ; 62
+ dw Script_winlosstext ; 63
+ dw Script_scripttalkafter ; 64
+ dw Script_endifjustbattled ; 65
+ dw Script_checkjustbattled ; 66
+ dw Script_setlasttalked ; 67
+ dw Script_applymovement ; 68
+ dw Script_applymovementlasttalked ; 69
+ dw Script_faceplayer ; 6a
+ dw Script_faceobject ; 6b
+ dw Script_variablesprite ; 6c
+ dw Script_disappear ; 6d
+ dw Script_appear ; 6e
+ dw Script_follow ; 6f
+ dw Script_stopfollow ; 70
+ dw Script_moveobject ; 71
+ dw Script_writeobjectxy ; 72
+ dw Script_loademote ; 73
+ dw Script_showemote ; 74
+ dw Script_turnobject ; 75
+ dw Script_follownotexact ; 76
+ dw Script_earthquake ; 77
+ dw Script_changemapblocks ; 78
+ dw Script_changeblock ; 79
+ dw Script_reloadmap ; 7a
+ dw Script_reloadmappart ; 7b
+ dw Script_writecmdqueue ; 7c
+ dw Script_delcmdqueue ; 7d
+ dw Script_playmusic ; 7e
+ dw Script_encountermusic ; 7f
+ dw Script_musicfadeout ; 80
+ dw Script_playmapmusic ; 81
+ dw Script_dontrestartmapmusic ; 82
+ dw Script_cry ; 83
+ dw Script_playsound ; 84
+ dw Script_waitsfx ; 85
+ dw Script_warpsound ; 86
+ dw Script_specialsound ; 87
+ dw Script_autoinput ; 88
+ dw Script_newloadmap ; 89
+ dw Script_pause ; 8a
+ dw Script_deactivatefacing ; 8b
+ dw Script_prioritysjump ; 8c
+ dw Script_warpcheck ; 8d
+ dw Script_stopandsjump ; 8e
+ dw Script_return ; 8f
+ dw Script_end ; 90
+ dw Script_reloadandreturn ; 91
+ dw Script_endall ; 92
+ dw Script_pokemart ; 93
+ dw Script_elevator ; 94
+ dw Script_trade ; 95
+ dw Script_askforphonenumber ; 96
+ dw Script_phonecall ; 97
+ dw Script_hangup ; 98
+ dw Script_describedecoration ; 99
+ dw Script_fruittree ; 9a
+ dw Script_specialphonecall ; 9b
+ dw Script_checkphonecall ; 9c
+ dw Script_verbosegiveitem ; 9d
+ dw Script_swarm ; 9e
+ dw Script_halloffame ; 9f
+ dw Script_credits ; a0
+ dw Script_warpfacing ; a1
+
+StartScript:
+ ld hl, wScriptFlags
+ set SCRIPT_RUNNING, [hl]
+ ret
+
+CheckScript:
+ ld hl, wScriptFlags
+ bit SCRIPT_RUNNING, [hl]
+ ret
+
+StopScript:
+ ld hl, wScriptFlags
+ res SCRIPT_RUNNING, [hl]
+ ret
+
+Script_callasm:
+; script command 0xe
+; parameters: asm
+
+ call GetScriptByte
+ ld b, a
+ call GetScriptByte
+ ld l, a
+ call GetScriptByte
+ ld h, a
+ ld a, b
+ rst FarCall
+ ret
+
+Script_special:
+; script command 0xf
+; parameters: predefined_script
+
+ call GetScriptByte
+ ld e, a
+ call GetScriptByte
+ ld d, a
+ farcall Special
+ ret
+
+Script_memcallasm:
+; script command 0x10
+; parameters: asm
+
+ call GetScriptByte
+ ld l, a
+ call GetScriptByte
+ ld h, a
+ ld b, [hl]
+ inc hl
+ ld a, [hli]
+ ld h, [hl]
+ ld l, a
+ ld a, b
+ rst FarCall
+ ret
+
+Script_jumptextfaceplayer:
+; script command 0x51
+; parameters: text_pointer
+
+ ld a, [wScriptBank]
+ ld [wScriptTextBank], a
+ call GetScriptByte
+ ld [wScriptTextAddr], a
+ call GetScriptByte
+ ld [wScriptTextAddr + 1], a
+ ld b, BANK(JumpTextFacePlayerScript)
+ ld hl, JumpTextFacePlayerScript
+ jp ScriptJump
+
+Script_jumptext:
+; script command 0x52
+; parameters: text_pointer
+
+ ld a, [wScriptBank]
+ ld [wScriptTextBank], a
+ call GetScriptByte
+ ld [wScriptTextAddr], a
+ call GetScriptByte
+ ld [wScriptTextAddr + 1], a
+ ld b, BANK(JumpTextScript)
+ ld hl, JumpTextScript
+ jp ScriptJump
+
+JumpTextFacePlayerScript:
+ faceplayer
+JumpTextScript:
+ opentext
+ repeattext -1, -1
+ waitbutton
+ closetext
+ end
+
+Script_writetext:
+; script command 0x4c
+; parameters: text_pointer
+
+ call GetScriptByte
+ ld l, a
+ call GetScriptByte
+ ld h, a
+ ld a, [wScriptBank]
+ ld b, a
+ call MapTextbox
+ ret
+
+Script_farwritetext:
+; script command 0x4b
+; parameters: text_pointer
+
+ call GetScriptByte
+ ld b, a
+ call GetScriptByte
+ ld l, a
+ call GetScriptByte
+ ld h, a
+ call MapTextbox
+ ret
+
+Script_repeattext:
+; script command 0x4d
+; parameters: byte, byte
+
+ call GetScriptByte
+ ld l, a
+ call GetScriptByte
+ ld h, a
+ cp -1
+ jr nz, .done
+ ld a, l
+ cp -1
+ jr nz, .done
+ ld hl, wScriptTextBank
+ ld a, [hli]
+ ld b, a
+ ld a, [hli]
+ ld h, [hl]
+ ld l, a
+ call MapTextbox
+ ret
+
+.done
+ ret
+
+Script_waitbutton:
+; script command 0x53
+
+ jp WaitButton
+
+Script_promptbutton:
+; script command 0x54
+
+ ldh a, [hOAMUpdate]
+ push af
+ ld a, $1
+ ldh [hOAMUpdate], a
+ call WaitBGMap
+ call PromptButton
+ pop af
+ ldh [hOAMUpdate], a
+ ret
+
+Script_yesorno:
+; script command 0x4e
+
+ call YesNoBox
+ ld a, FALSE
+ jr c, .no
+ ld a, TRUE
+.no
+ ld [wScriptVar], a
+ ret
+
+Script_loadmenu:
+; script command 0x4f
+; parameters: menu_header
+
+ call GetScriptByte
+ ld l, a
+ call GetScriptByte
+ ld h, a
+ ld de, LoadMenuHeader
+ ld a, [wScriptBank]
+ call Call_a_de
+ call UpdateSprites
+ ret
+
+Script_closewindow:
+; script command 0x50
+
+ call CloseWindow
+ call UpdateSprites
+ ret
+
+Script_pokepic:
+; script command 0x55
+; parameters: pokemon
+
+ call GetScriptByte
+ and a
+ jr nz, .ok
+ ld a, [wScriptVar]
+.ok
+ ld [wCurPartySpecies], a
+ farcall Pokepic
+ ret
+
+Script_closepokepic:
+; script command 0x56
+
+ farcall ClosePokepic
+ ret
+
+Script_verticalmenu:
+; script command 0x58
+
+ ld a, [wScriptBank]
+ ld hl, VerticalMenu
+ rst FarCall
+ ld a, [wMenuCursorY]
+ jr nc, .ok
+ xor a
+.ok
+ ld [wScriptVar], a
+ ret
+
+Script__2dmenu:
+; script command 0x57
+
+ ld a, [wScriptBank]
+ ld hl, _2DMenu
+ rst FarCall
+ ld a, [wMenuCursorBuffer]
+ jr nc, .ok
+ xor a
+.ok
+ ld [wScriptVar], a
+ ret
+
+Script_verbosegiveitem:
+; script command 0x9d
+; parameters: item, quantity
+
+ call Script_giveitem
+ call CurItemName
+ ld de, wStringBuffer1
+ ld a, STRING_BUFFER_4
+ call CopyConvertedText
+ ld b, BANK(GiveItemScript)
+ ld de, GiveItemScript
+ jp ScriptCall
+
+ret_96e71:
+ ret
+
+GiveItemScript:
+ callasm ret_96e71
+ writetext ReceivedItemText
+ iffalse .Full
+ waitsfx
+ specialsound
+ waitbutton
+ itemnotify
+ end
+
+.Full:
+ promptbutton
+ pocketisfull
+ end
+
+ReceivedItemText:
+ text_far _ReceivedItemText
+ text_end
+
+Script_itemnotify:
+; script command 0x45
+
+ call GetPocketName
+ call CurItemName
+ ld b, BANK(PutItemInPocketText)
+ ld hl, PutItemInPocketText
+ call MapTextbox
+ ret
+
+Script_pocketisfull:
+; script command 0x46
+
+ call GetPocketName
+ call CurItemName
+ ld b, BANK(PocketIsFullText)
+ ld hl, PocketIsFullText
+ call MapTextbox
+ ret
+
+Script_specialsound:
+; script command 0x87
+
+ farcall CheckItemPocket
+ ld a, [wItemAttributeParamBuffer]
+ cp TM_HM
+ ld de, SFX_GET_TM
+ jr z, .play
+ ld de, SFX_ITEM
+.play
+ call PlaySFX
+ call WaitSFX
+ ret
+
+GetPocketName:
+ farcall CheckItemPocket
+ ld a, [wItemAttributeParamBuffer]
+ dec a
+ ld hl, ItemPocketNames
+ maskbits NUM_POCKETS
+ add a
+ ld e, a
+ ld d, 0
+ add hl, de
+ ld a, [hli]
+ ld d, [hl]
+ ld e, a
+ ld hl, wStringBuffer3
+ call CopyName2
+ ret
+
+INCLUDE "data/items/pocket_names.asm"
+
+CurItemName:
+ ld a, [wCurItem]
+ ld [wNamedObjectIndexBuffer], a
+ call GetItemName
+ ret
+
+PutItemInPocketText:
+ text_far _PutItemInPocketText
+ text_end
+
+PocketIsFullText:
+ text_far _PocketIsFullText
+ text_end
+
+Script_pokemart:
+; script command 0x93
+; parameters: mart_type, mart_id
+
+ call GetScriptByte
+ ld c, a
+ call GetScriptByte
+ ld e, a
+ call GetScriptByte
+ ld d, a
+ ld a, [wScriptBank]
+ ld b, a
+ farcall OpenMartDialog
+ ret
+
+Script_elevator:
+; script command 0x94
+; parameters: floor_list_pointer
+
+ xor a
+ ld [wScriptVar], a
+ call GetScriptByte
+ ld e, a
+ call GetScriptByte
+ ld d, a
+ ld a, [wScriptBank]
+ ld b, a
+ farcall Elevator
+ ret c
+ ld a, TRUE
+ ld [wScriptVar], a
+ ret
+
+Script_trade:
+; script command 0x95
+; parameters: trade_id
+
+ call GetScriptByte
+ ld e, a
+ farcall NPCTrade
+ ret
+
+Script_phonecall:
+; script command 0x97
+; parameters: caller_name
+
+ call GetScriptByte
+ ld e, a
+ call GetScriptByte
+ ld d, a
+ ld a, [wScriptBank]
+ ld b, a
+ farcall PhoneCall
+ ret
+
+Script_hangup:
+; script command 0x98
+
+ farcall HangUp
+ ret
+
+Script_askforphonenumber:
+; script command 0x96
+; parameters: number
+
+ call YesNoBox
+ jr c, .refused
+ call GetScriptByte
+ ld c, a
+ farcall AddPhoneNumber
+ jr c, .phonefull
+ xor a ; PHONE_CONTACT_GOT
+ jr .done
+.phonefull
+ ld a, PHONE_CONTACTS_FULL
+ jr .done
+.refused
+ call GetScriptByte
+ ld a, PHONE_CONTACT_REFUSED
+.done
+ ld [wScriptVar], a
+ ret
+
+Script_describedecoration:
+; script command 0x99
+; parameters: byte
+
+ call GetScriptByte
+ ld b, a
+ farcall DescribeDecoration
+ ld h, d
+ ld l, e
+ jp ScriptJump
+
+Script_fruittree:
+; script command 0x9a
+; parameters: tree_id
+
+ call GetScriptByte
+ ld [wCurFruitTree], a
+ ld b, BANK(FruitTreeScript)
+ ld hl, FruitTreeScript
+ jp ScriptJump
+
+Script_swarm:
+; script command 0x9e
+; parameters: map_group, map_id
+
+ call GetScriptByte
+ ld d, a
+ call GetScriptByte
+ ld e, a
+ farcall StoreSwarmMapIndices
+ ret
+
+Script_trainertext:
+; script command 0x61
+; parameters: text_id
+
+ call GetScriptByte
+ ld c, a
+ ld b, 0
+ ld hl, wSeenTextPointer
+ add hl, bc
+ add hl, bc
+ ld a, [hli]
+ ld h, [hl]
+ ld l, a
+ ld a, [wSeenTrainerBank]
+ ld b, a
+ call MapTextbox
+ ret
+
+Script_scripttalkafter:
+; script command 0x64
+
+ ld hl, wScriptAfterPointer
+ ld a, [hli]
+ ld h, [hl]
+ ld l, a
+ ld a, [wSeenTrainerBank]
+ ld b, a
+ jp ScriptJump
+
+Script_trainerflagaction:
+; script command 0x62
+; parameters: action
+
+ xor a
+ ld [wScriptVar], a
+ ld hl, wTempTrainerEventFlag
+ ld e, [hl]
+ inc hl
+ ld d, [hl]
+ call GetScriptByte
+ ld b, a
+ call EventFlagAction
+ ld a, c
+ and a
+ ret z
+ ld a, TRUE
+ ld [wScriptVar], a
+ ret
+
+Script_winlosstext:
+; script command 0x63
+; parameters: win_text_pointer, loss_text_pointer
+
+ ld hl, wWinTextPointer
+ call GetScriptByte
+ ld [hli], a
+ call GetScriptByte
+ ld [hli], a
+ ld hl, wLossTextPointer
+ call GetScriptByte
+ ld [hli], a
+ call GetScriptByte
+ ld [hli], a
+ ret
+
+Script_endifjustbattled:
+; script command 0x65
+
+ ld a, [wRunningTrainerBattleScript]
+ and a
+ ret z
+ jp Script_end
+
+Script_checkjustbattled:
+; script command 0x66
+
+ ld a, TRUE
+ ld [wScriptVar], a
+ ld a, [wRunningTrainerBattleScript]
+ and a
+ ret nz
+ xor a
+ ld [wScriptVar], a
+ ret
+
+Script_encountermusic:
+; script command 0x7f
+
+ ld a, [wOtherTrainerClass]
+ ld e, a
+ farcall PlayTrainerEncounterMusic
+ ret
+
+Script_playmapmusic:
+; script command 0x81
+
+ call PlayMapMusic
+ ret
+
+Script_playmusic:
+; script command 0x7e
+; parameters: music_pointer
+
+ ld de, MUSIC_NONE
+ call PlayMusic
+ xor a
+ ld [wMusicFade], a
+ call MaxVolume
+ call GetScriptByte
+ ld e, a
+ call GetScriptByte
+ ld d, a
+ call PlayMusic
+ ret
+
+Script_musicfadeout:
+; script command 0x80
+; parameters: music, fadetime
+
+ call GetScriptByte
+ ld [wMusicFadeID], a
+ call GetScriptByte
+ ld [wMusicFadeID + 1], a
+ call GetScriptByte
+ and $ff ^ (1 << MUSIC_FADE_IN_F)
+ ld [wMusicFade], a
+ ret
+
+Script_playsound:
+; script command 0x84
+; parameters: sound_pointer
+
+ call GetScriptByte
+ ld e, a
+ call GetScriptByte
+ ld d, a
+ call PlaySFX
+ ret
+
+Script_waitsfx:
+; script command 0x85
+
+ call WaitSFX
+ ret
+
+Script_warpsound:
+; script command 0x86
+
+ farcall GetWarpSFX
+ call PlaySFX
+ ret
+
+Script_cry:
+; script command 0x83
+; parameters: cry_id
+
+ call GetScriptByte
+ push af
+ call GetScriptByte
+ pop af
+ and a
+ jr nz, .ok
+ ld a, [wScriptVar]
+.ok
+ call PlayMonCry
+ ret
+
+Script_setlasttalked:
+; script command 0x67
+; parameters: object_id
+
+ call GetScriptByte
+ ldh [hLastTalked], a
+ ret
+
+Script_applymovement:
+; script command 0x68
+; parameters: object_id, data
+
+ call GetScriptByte
+ ld c, a
+
+ApplyMovement:
+ push bc
+ ld a, c
+ farcall SetFlagsForMovement_1
+ pop bc
+
+ push bc
+ call SetFlagsForMovement_2
+ pop bc
+
+ call GetScriptByte
+ ld l, a
+ call GetScriptByte
+ ld h, a
+ ld a, [wScriptBank]
+ ld b, a
+ call GetMovementData
+ ret c
+
+ ld a, SCRIPT_WAIT_MOVEMENT
+ ld [wScriptMode], a
+ call StopScript
+ ret
+
+SetFlagsForMovement_2:
+ farcall _SetFlagsForMovement_2
+ ret
+
+Script_applymovementlasttalked:
+; script command 0x69
+; parameters: data
+; apply movement to last talked
+
+ ldh a, [hLastTalked]
+ ld c, a
+ jp ApplyMovement
+
+Script_faceplayer:
+; script command 0x6a
+
+ ldh a, [hLastTalked]
+ and a
+ ret z
+ ld d, $0
+ ldh a, [hLastTalked]
+ ld e, a
+ farcall GetRelativeFacing
+ ld a, d
+ add a
+ add a
+ ld e, a
+ ldh a, [hLastTalked]
+ ld d, a
+ call ApplyObjectFacing
+ ret
+
+Script_faceobject:
+; script command 0x6b
+; parameters: object1, object2
+
+ call GetScriptByte
+ cp LAST_TALKED
+ jr c, .ok
+ ldh a, [hLastTalked]
+.ok
+ ld e, a
+ call GetScriptByte
+ cp LAST_TALKED
+ jr nz, .ok2
+ ldh a, [hLastTalked]
+.ok2
+ ld d, a
+ push de
+ farcall GetRelativeFacing
+ pop bc
+ ret c
+ ld a, d
+ add a
+ add a
+ ld e, a
+ ld d, c
+ call ApplyObjectFacing
+ ret
+
+Script_turnobject:
+; script command 0x75
+; parameters: object_id, facing
+
+ call GetScriptByte
+ cp LAST_TALKED
+ jr nz, .ok
+ ldh a, [hLastTalked]
+.ok
+ ld d, a
+ call GetScriptByte
+ add a
+ add a
+ ld e, a
+ call ApplyObjectFacing
+ ret
+
+ApplyObjectFacing:
+ ld a, d
+ push de
+ call CheckObjectVisibility
+ jr c, .not_visible
+ ld hl, OBJECT_SPRITE
+ add hl, bc
+ ld a, [hl]
+ push bc
+ call DoesSpriteHaveFacings
+ pop bc
+ jr c, .not_visible ; STILL_SPRITE
+ ld hl, OBJECT_FLAGS1
+ add hl, bc
+ bit FIXED_FACING_F, [hl]
+ jr nz, .not_visible
+ pop de
+ ld a, e
+ call SetSpriteDirection
+ call UpdateSprites
+ ret
+
+.not_visible
+ pop de
+ scf
+ ret
+
+Script_variablesprite:
+; script command 0x6c
+; parameters: byte, sprite
+
+ call GetScriptByte
+ ld e, a
+ ld d, $0
+ ld hl, wVariableSprites
+ add hl, de
+ call GetScriptByte
+ ld [hl], a
+ ret
+
+Script_appear:
+; script command 0x6e
+; parameters: object_id
+
+ call GetScriptByte
+ call _CopyObjectStruct
+ ldh a, [hMapObjectIndexBuffer]
+ ld b, 0 ; clear
+ call ApplyEventActionAppearDisappear
+ ret
+
+Script_disappear:
+; script command 0x6d
+; parameters: object_id
+
+ call GetScriptByte
+ cp LAST_TALKED
+ jr nz, .ok
+ ldh a, [hLastTalked]
+.ok
+ call DeleteObjectStruct
+ ldh a, [hMapObjectIndexBuffer]
+ ld b, 1 ; set
+ call ApplyEventActionAppearDisappear
+ farcall _UpdateSprites
+ ret
+
+ApplyEventActionAppearDisappear:
+ push bc
+ call GetMapObject
+ ld hl, MAPOBJECT_EVENT_FLAG
+ add hl, bc
+ pop bc
+ ld e, [hl]
+ inc hl
+ ld d, [hl]
+ ld a, -1
+ cp e
+ jr nz, .okay
+ cp d
+ jr nz, .okay
+ xor a
+ ret
+.okay
+ call EventFlagAction
+ ret
+
+Script_follow:
+; script command 0x6f
+; parameters: object2, object1
+
+ call GetScriptByte
+ ld b, a
+ call GetScriptByte
+ ld c, a
+ farcall StartFollow
+ ret
+
+Script_stopfollow:
+; script command 0x70
+
+ farcall StopFollow
+ ret
+
+Script_moveobject:
+; script command 0x71
+; parameters: object id, x, y
+
+ call GetScriptByte
+ ld b, a
+ call GetScriptByte
+ add 4
+ ld d, a
+ call GetScriptByte
+ add 4
+ ld e, a
+ farcall CopyDECoordsToMapObject
+ ret
+
+Script_writeobjectxy:
+; script command 0x72
+; parameters: object_id
+
+ call GetScriptByte
+ cp LAST_TALKED
+ jr nz, .ok
+ ldh a, [hLastTalked]
+.ok
+ ld b, a
+ farcall WriteObjectXY
+ ret
+
+Script_follownotexact:
+; script command 0x76
+; parameters: object2, object1
+
+ call GetScriptByte
+ ld b, a
+ call GetScriptByte
+ ld c, a
+ farcall FollowNotExact
+ ret
+
+Script_loademote:
+; script command 0x73
+; parameters: bubble
+
+ call GetScriptByte
+ cp EMOTE_FROM_MEM
+ jr nz, .not_var_emote
+ ld a, [wScriptVar]
+.not_var_emote
+ ld c, a
+ farcall LoadEmote
+ ret
+
+Script_showemote:
+; script command 0x74
+; parameters: bubble, object_id, time
+
+ call GetScriptByte
+ ld [wScriptVar], a
+ call GetScriptByte
+ cp LAST_TALKED
+ jr z, .ok
+ ldh [hLastTalked], a
+.ok
+ call GetScriptByte
+ ld [wScriptDelay], a
+ ld b, BANK(ShowEmoteScript)
+ ld de, ShowEmoteScript
+ jp ScriptCall
+
+ShowEmoteScript:
+ loademote EMOTE_FROM_MEM
+ applymovementlasttalked .Show
+ pause 0
+ applymovementlasttalked .Hide
+ end
+
+.Show:
+ show_emote
+ step_sleep 1
+ step_end
+
+.Hide:
+ hide_emote
+ step_sleep 1
+ step_end
+
+Script_earthquake:
+; script command 0x77
+; parameters: param
+
+ ld hl, EarthquakeMovement
+ ld de, wEarthquakeMovementDataBuffer
+ ld bc, EarthquakeMovement.End - EarthquakeMovement
+ call CopyBytes
+ call GetScriptByte
+ ld [wEarthquakeMovementDataBuffer + 1], a
+ and %00111111
+ ld [wEarthquakeMovementDataBuffer + 3], a
+ ld b, BANK(.script)
+ ld de, .script
+ jp ScriptCall
+
+.script
+ applymovement PLAYER, wEarthquakeMovementDataBuffer
+ end
+
+EarthquakeMovement:
+ step_shake 16 ; the 16 gets overwritten with the script byte
+ step_sleep 16 ; the 16 gets overwritten with the lower 6 bits of the script byte
+ step_end
+.End
+
+Script_loadpikachudata:
+; script command 0x59
+
+ ld a, PIKACHU
+ ld [wTempWildMonSpecies], a
+ ld a, 5
+ ld [wCurPartyLevel], a
+ ret
+
+Script_randomwildmon:
+; script command 0x5a
+
+ xor a
+ ld [wBattleScriptFlags], a
+ ret
+
+Script_loadtemptrainer:
+; script command 0x5b
+
+ ld a, (1 << 7) | 1
+ ld [wBattleScriptFlags], a
+ ld a, [wTempTrainerClass]
+ ld [wOtherTrainerClass], a
+ ld a, [wTempTrainerID]
+ ld [wOtherTrainerID], a
+ ret
+
+Script_loadwildmon:
+; script command 0x5c
+; parameters: pokemon, level
+
+ ld a, (1 << 7)
+ ld [wBattleScriptFlags], a
+ call GetScriptByte
+ ld [wTempWildMonSpecies], a
+ call GetScriptByte
+ ld [wCurPartyLevel], a
+ ret
+
+Script_loadtrainer:
+; script command 0x5d
+; parameters: trainer_group, trainer_id
+
+ ld a, (1 << 7) | 1
+ ld [wBattleScriptFlags], a
+ call GetScriptByte
+ ld [wOtherTrainerClass], a
+ call GetScriptByte
+ ld [wOtherTrainerID], a
+ ret
+
+Script_startbattle:
+; script command 0x5e
+
+ call BufferScreen
+ predef StartBattle
+ ld a, [wBattleResult]
+ and $ff ^ BATTLERESULT_BITMASK
+ ld [wScriptVar], a
+ ret
+
+Script_catchtutorial:
+; script command 0x60
+; parameters: byte
+
+ call GetScriptByte
+ ld [wBattleType], a
+ call BufferScreen
+ farcall CatchTutorial
+ jp Script_reloadmap
+
+Script_reloadmapafterbattle:
+; script command 0x5f
+
+ ld hl, wBattleScriptFlags
+ ld d, [hl]
+ ld [hl], 0
+ ld a, [wBattleResult]
+ and $ff ^ BATTLERESULT_BITMASK
+ cp LOSE
+ jr nz, .notblackedout
+ ld b, BANK(Script_BattleWhiteout)
+ ld hl, Script_BattleWhiteout
+ jp ScriptJump
+
+.notblackedout
+ bit 0, d
+ jr z, .was_wild
+ farcall MomTriesToBuySomething
+ jr .done
+
+.was_wild
+ ld a, [wBattleResult]
+ bit BATTLERESULT_BOX_FULL, a
+ jr z, .done
+ ld b, BANK(Script_SpecialBillCall)
+ ld de, Script_SpecialBillCall
+ farcall LoadScriptBDE
+.done
+ jp Script_reloadmap
+
+Script_reloadmap:
+; script command 0x7a
+
+ xor a
+ ld [wBattleScriptFlags], a
+ ld a, MAPSETUP_RELOADMAP
+ ldh [hMapEntryMethod], a
+ ld a, MAPSTATUS_ENTER
+ call LoadMapStatus
+ call StopScript
+ ret
+
+Script_scall:
+; script command 0x0
+; parameters: pointer
+
+ ld a, [wScriptBank]
+ ld b, a
+ call GetScriptByte
+ ld e, a
+ call GetScriptByte
+ ld d, a
+ jr ScriptCall
+
+Script_farscall:
+; script command 0x1
+; parameters: pointer
+
+ call GetScriptByte
+ ld b, a
+ call GetScriptByte
+ ld e, a
+ call GetScriptByte
+ ld d, a
+ jr ScriptCall
+
+Script_memcall:
+; script command 0x2
+; parameters: pointer
+
+ call GetScriptByte
+ ld l, a
+ call GetScriptByte
+ ld h, a
+ ld b, [hl]
+ inc hl
+ ld e, [hl]
+ inc hl
+ ld d, [hl]
+ ; fallthrough
+
+ScriptCall:
+; Bug: The script stack has a capacity of 5 scripts, yet there is
+; nothing to stop you from pushing a sixth script. The high part
+; of the script address can then be overwritten by modifications
+; to wScriptDelay, causing the script to return to the rst/interrupt
+; space.
+
+ push de
+ ld hl, wScriptStackSize
+ ld e, [hl]
+ inc [hl]
+ ld d, 0
+ ld hl, wScriptStack
+ add hl, de
+ add hl, de
+ add hl, de
+ pop de
+ ld a, [wScriptBank]
+ ld [hli], a
+ ld a, [wScriptPos]
+ ld [hli], a
+ ld a, [wScriptPos + 1]
+ ld [hl], a
+ ld a, b
+ ld [wScriptBank], a
+ ld a, e
+ ld [wScriptPos], a
+ ld a, d
+ ld [wScriptPos + 1], a
+ ret
+
+CallCallback::
+ ld a, [wScriptBank]
+ or $80
+ ld [wScriptBank], a
+ jp ScriptCall
+
+Script_sjump:
+; script command 0x3
+; parameters: pointer
+
+ call GetScriptByte
+ ld l, a
+ call GetScriptByte
+ ld h, a
+ ld a, [wScriptBank]
+ ld b, a
+ jp ScriptJump
+
+Script_farsjump:
+; script command 0x4
+; parameters: pointer
+
+ call GetScriptByte
+ ld b, a
+ call GetScriptByte
+ ld l, a
+ call GetScriptByte
+ ld h, a
+ jp ScriptJump
+
+Script_memjump:
+; script command 0x5
+; parameters: pointer
+
+ call GetScriptByte
+ ld l, a
+ call GetScriptByte
+ ld h, a
+ ld b, [hl]
+ inc hl
+ ld a, [hli]
+ ld h, [hl]
+ ld l, a
+ jp ScriptJump
+
+Script_iffalse:
+; script command 0x8
+; parameters: pointer
+
+ ld a, [wScriptVar]
+ and a
+ jp nz, SkipTwoScriptBytes
+ jp Script_sjump
+
+Script_iftrue:
+; script command 0x9
+; parameters: pointer
+
+ ld a, [wScriptVar]
+ and a
+ jp nz, Script_sjump
+ jp SkipTwoScriptBytes
+
+Script_ifequal:
+; script command 0x6
+; parameters: byte, pointer
+
+ call GetScriptByte
+ ld hl, wScriptVar
+ cp [hl]
+ jr z, Script_sjump
+ jr SkipTwoScriptBytes
+
+Script_ifnotequal:
+; script command 0x7
+; parameters: byte, pointer
+
+ call GetScriptByte
+ ld hl, wScriptVar
+ cp [hl]
+ jr nz, Script_sjump
+ jr SkipTwoScriptBytes
+
+Script_ifgreater:
+; script command 0xa
+; parameters: byte, pointer
+
+ ld a, [wScriptVar]
+ ld b, a
+ call GetScriptByte
+ cp b
+ jr c, Script_sjump
+ jr SkipTwoScriptBytes
+
+Script_ifless:
+; script command 0xb
+; parameters: byte, pointer
+
+ call GetScriptByte
+ ld b, a
+ ld a, [wScriptVar]
+ cp b
+ jr c, Script_sjump
+ jr SkipTwoScriptBytes
+
+Script_jumpstd:
+; script command 0xc
+; parameters: predefined_script
+
+ call StdScript
+ jr ScriptJump
+
+Script_callstd:
+; script command 0xd
+; parameters: predefined_script
+
+ call StdScript
+ ld d, h
+ ld e, l
+ jp ScriptCall
+
+StdScript:
+ call GetScriptByte
+ ld e, a
+ call GetScriptByte
+ ld d, a
+ ld hl, StdScripts
+ add hl, de
+ add hl, de
+ add hl, de
+ ld a, BANK(StdScripts)
+ call GetFarByte
+ ld b, a
+ inc hl
+ ld a, BANK(StdScripts)
+ call GetFarHalfword
+ ret
+
+SkipTwoScriptBytes:
+ call GetScriptByte
+ call GetScriptByte
+ ret
+
+ScriptJump:
+ ld a, b
+ ld [wScriptBank], a
+ ld a, l
+ ld [wScriptPos], a
+ ld a, h
+ ld [wScriptPos + 1], a
+ ret
+
+Script_prioritysjump:
+; script command 0x8c
+; parameters: pointer
+
+ ld a, [wScriptBank]
+ ld [wPriorityScriptBank], a
+ call GetScriptByte
+ ld [wPriorityScriptAddr], a
+ call GetScriptByte
+ ld [wPriorityScriptAddr + 1], a
+ ld hl, wScriptFlags
+ set 3, [hl]
+ ret
+
+Script_checkscene:
+; script command 0x13
+
+ call CheckScenes
+ jr z, .no_scene
+ ld [wScriptVar], a
+ ret
+
+.no_scene
+ ld a, $ff
+ ld [wScriptVar], a
+ ret
+
+Script_checkmapscene:
+; script command 0x11
+; parameters: map_group, map_id
+
+ call GetScriptByte
+ ld b, a
+ call GetScriptByte
+ ld c, a
+ call GetMapSceneID
+ ld a, d
+ or e
+ jr z, .no_scene
+ ld a, [de]
+ ld [wScriptVar], a
+ ret
+
+.no_scene
+ ld a, $ff
+ ld [wScriptVar], a
+ ret
+
+Script_setscene:
+; script command 0x14
+; parameters: scene_id
+
+ ld a, [wMapGroup]
+ ld b, a
+ ld a, [wMapNumber]
+ ld c, a
+ jr DoScene
+
+Script_setmapscene:
+; script command 0x12
+; parameters: map_group, map_id, scene_id
+
+ call GetScriptByte
+ ld b, a
+ call GetScriptByte
+ ld c, a
+DoScene:
+ call GetMapSceneID
+ ld a, d
+ or e
+ jr z, .no_scene
+ call GetScriptByte
+ ld [de], a
+.no_scene
+ ret
+
+Script_readmem:
+; script command 0x19
+; parameters: address
+
+ call GetScriptByte
+ ld l, a
+ call GetScriptByte
+ ld h, a
+ ld a, [hl]
+ ld [wScriptVar], a
+ ret
+
+Script_writemem:
+; script command 0x1a
+; parameters: address
+
+ call GetScriptByte
+ ld l, a
+ call GetScriptByte
+ ld h, a
+ ld a, [wScriptVar]
+ ld [hl], a
+ ret
+
+Script_loadmem:
+; script command 0x1b
+; parameters: address, value
+
+ call GetScriptByte
+ ld l, a
+ call GetScriptByte
+ ld h, a
+ call GetScriptByte
+ ld [hl], a
+ ret
+
+Script_setval:
+; script command 0x15
+; parameters: value
+
+ call GetScriptByte
+ ld [wScriptVar], a
+ ret
+
+Script_addval:
+; script command 0x16
+; parameters: value
+
+ call GetScriptByte
+ ld hl, wScriptVar
+ add [hl]
+ ld [hl], a
+ ret
+
+Script_random:
+; script command 0x17
+; parameters: input
+
+ call GetScriptByte
+ ld [wScriptVar], a
+ and a
+ ret z
+
+ ld c, a
+ call .Divide256byC
+ and a
+ jr z, .no_restriction ; 256 % b == 0
+ ld b, a
+ xor a
+ sub b
+ ld b, a
+.loop
+ push bc
+ call Random
+ pop bc
+ ldh a, [hRandomAdd]
+ cp b
+ jr nc, .loop
+ jr .finish
+
+.no_restriction
+ push bc
+ call Random
+ pop bc
+ ldh a, [hRandomAdd]
+
+.finish
+ push af
+ ld a, [wScriptVar]
+ ld c, a
+ pop af
+ call SimpleDivide
+ ld [wScriptVar], a
+ ret
+
+.Divide256byC:
+ xor a
+ ld b, a
+ sub c
+.mod_loop
+ inc b
+ sub c
+ jr nc, .mod_loop
+ dec b
+ add c
+ ret
+
+Script_readvar:
+; script command 0x1c
+; parameters: variable_id
+
+ call GetScriptByte
+ call GetVarAction
+ ld a, [de]
+ ld [wScriptVar], a
+ ret
+
+Script_writevar:
+; script command 0x1d
+; parameters: variable_id
+
+ call GetScriptByte
+ call GetVarAction
+ ld a, [wScriptVar]
+ ld [de], a
+ ret
+
+Script_loadvar:
+; script command 0x1e
+; parameters: variable_id, value
+
+ call GetScriptByte
+ call GetVarAction
+ call GetScriptByte
+ ld [de], a
+ ret
+
+GetVarAction:
+ ld c, a
+ farcall _GetVarAction
+ ret
+
+Script_checkver:
+; script command 0x18
+
+ ld a, [.gs_version]
+ ld [wScriptVar], a
+ ret
+
+.gs_version:
+ db GS_VERSION
+
+Script_getmonname:
+; script command 0x40
+; parameters: string_buffer, mon_id (0 aka USE_SCRIPT_VAR to use wScriptVar)
+
+ call GetScriptByte
+ and a
+ jr nz, .gotit
+ ld a, [wScriptVar]
+.gotit
+ ld [wNamedObjectIndexBuffer], a
+ call GetPokemonName
+ ld de, wStringBuffer1
+
+GetStringBuffer:
+ call GetScriptByte
+ cp NUM_STRING_BUFFERS
+ jr c, .ok
+ xor a
+.ok
+
+CopyConvertedText:
+ ld hl, wStringBuffer3
+ ld bc, wStringBuffer4 - wStringBuffer3
+ call AddNTimes
+ call CopyName2
+ ret
+
+Script_getitemname:
+; script command 0x41
+; parameters: string_buffer, item_id (0 aka USE_SCRIPT_VAR to use wScriptVar)
+
+ call GetScriptByte
+ and a ; USE_SCRIPT_VAR
+ jr nz, .ok
+ ld a, [wScriptVar]
+.ok
+ ld [wNamedObjectIndexBuffer], a
+ call GetItemName
+ ld de, wStringBuffer1
+ jr GetStringBuffer
+
+Script_getcurlandmarkname:
+; script command 0x42
+; parameters: string_buffer
+
+ ld a, [wMapGroup]
+ ld b, a
+ ld a, [wMapNumber]
+ ld c, a
+ call GetWorldMapLocation
+
+ConvertLandmarkToText:
+ ld e, a
+ farcall GetLandmarkName
+ ld de, wStringBuffer1
+ jp GetStringBuffer
+
+Script_gettrainername:
+; script command 0x43
+; parameters: string_buffer, trainer_group, trainer_id
+
+ call GetScriptByte
+ ld c, a
+ call GetScriptByte
+ ld b, a
+ farcall GetTrainerName
+ jr GetStringBuffer
+
+Script_getmoney:
+; script command 0x3d
+; parameters: string_buffer, account
+
+ call ResetStringBuffer1
+ call GetMoneyAccount
+ ld hl, wStringBuffer1
+ lb bc, PRINTNUM_LEFTALIGN | 3, 6
+ call PrintNum
+ ld de, wStringBuffer1
+ jp GetStringBuffer
+
+Script_getcoins:
+; script command 0x3e
+; parameters: string_buffer
+
+ call ResetStringBuffer1
+ ld hl, wStringBuffer1
+ ld de, wCoins
+ lb bc, PRINTNUM_LEFTALIGN | 2, 6
+ call PrintNum
+ ld de, wStringBuffer1
+ jp GetStringBuffer
+
+Script_getnum:
+; script command 0x3f
+; parameters: string_buffer
+
+ call ResetStringBuffer1
+ ld de, wScriptVar
+ ld hl, wStringBuffer1
+ lb bc, PRINTNUM_LEFTALIGN | 1, 3
+ call PrintNum
+ ld de, wStringBuffer1
+ jp GetStringBuffer
+
+ResetStringBuffer1:
+ ld hl, wStringBuffer1
+ ld bc, NAME_LENGTH + 2
+ ld a, "@"
+ call ByteFill
+ ret
+
+Script_getstring:
+; script command 0x44
+; parameters: string_buffer, text_pointer
+
+ call GetScriptByte
+ ld e, a
+ call GetScriptByte
+ ld d, a
+ ld a, [wScriptBank]
+ ld hl, CopyName1
+ rst FarCall
+ ld de, wStringBuffer2
+ jp GetStringBuffer
+
+Script_givepokemail:
+; script command 0x2f
+; parameters: pointer
+
+ call GetScriptByte
+ ld l, a
+ call GetScriptByte
+ ld h, a
+ ld a, [wScriptBank]
+ call GetFarByte
+ ld b, a
+ push bc
+ inc hl
+ ld bc, MAIL_MSG_LENGTH
+ ld de, wceed
+ ld a, [wScriptBank]
+ call FarCopyBytes
+ pop bc
+ farcall GivePokeMail
+ ret
+
+Script_checkpokemail:
+; script command 0x30
+; parameters: pointer
+
+ call GetScriptByte
+ ld e, a
+ call GetScriptByte
+ ld d, a
+ ld a, [wScriptBank]
+ ld b, a
+ farcall CheckPokeMail
+ ret
+
+Script_giveitem:
+; script command 0x1f
+; parameters: item, quantity
+
+ call GetScriptByte
+ cp ITEM_FROM_MEM
+ jr nz, .ok
+ ld a, [wScriptVar]
+.ok
+ ld [wCurItem], a
+ call GetScriptByte
+ ld [wItemQuantityChangeBuffer], a
+ ld hl, wNumItems
+ call ReceiveItem
+ jr nc, .full
+ ld a, TRUE
+ ld [wScriptVar], a
+ ret
+.full
+ xor a
+ ld [wScriptVar], a
+ ret
+
+Script_takeitem:
+; script command 0x20
+; parameters: item, quantity
+
+ xor a
+ ld [wScriptVar], a
+ call GetScriptByte
+ ld [wCurItem], a
+ call GetScriptByte
+ ld [wItemQuantityChangeBuffer], a
+ ld a, -1
+ ld [wCurItemQuantity], a
+ ld hl, wNumItems
+ call TossItem
+ ret nc
+ ld a, TRUE
+ ld [wScriptVar], a
+ ret
+
+Script_checkitem:
+; script command 0x21
+; parameters: item
+
+ xor a
+ ld [wScriptVar], a
+ call GetScriptByte
+ ld [wCurItem], a
+ ld hl, wNumItems
+ call CheckItem
+ ret nc
+ ld a, TRUE
+ ld [wScriptVar], a
+ ret
+
+Script_givemoney:
+; script command 0x22
+; parameters: account, money
+
+ call GetMoneyAccount
+ call LoadMoneyAmountToMem
+ farcall GiveMoney
+ ret
+
+Script_takemoney:
+; script command 0x23
+; parameters: account, money
+
+ call GetMoneyAccount
+ call LoadMoneyAmountToMem
+ farcall TakeMoney
+ ret
+
+Script_checkmoney:
+; script command 0x24
+; parameters: account, money
+
+ call GetMoneyAccount
+ call LoadMoneyAmountToMem
+ farcall CompareMoney
+
+CompareMoneyAction:
+ jr c, .less
+ jr z, .exact
+ ld a, HAVE_MORE
+ jr .done
+.exact
+ ld a, HAVE_AMOUNT
+ jr .done
+.less
+ ld a, HAVE_LESS
+.done
+ ld [wScriptVar], a
+ ret
+
+GetMoneyAccount:
+ call GetScriptByte
+ and a
+ ld de, wMoney ; YOUR_MONEY
+ ret z
+ ld de, wMomsMoney ; MOMS_MONEY
+ ret
+
+LoadMoneyAmountToMem:
+ ld bc, hMoneyTemp
+ push bc
+ call GetScriptByte
+ ld [bc], a
+ inc bc
+ call GetScriptByte
+ ld [bc], a
+ inc bc
+ call GetScriptByte
+ ld [bc], a
+ pop bc
+ ret
+
+Script_givecoins:
+; script command 0x25
+; parameters: coins
+
+ call LoadCoinAmountToMem
+ farcall GiveCoins
+ ret
+
+Script_takecoins:
+; script command 0x26
+; parameters: coins
+
+ call LoadCoinAmountToMem
+ farcall TakeCoins
+ ret
+
+Script_checkcoins:
+; script command 0x27
+; parameters: coins
+
+ call LoadCoinAmountToMem
+ farcall CheckCoins
+ jr CompareMoneyAction
+
+LoadCoinAmountToMem:
+ call GetScriptByte
+ ldh [hMoneyTemp + 1], a
+ call GetScriptByte
+ ldh [hMoneyTemp], a
+ ld bc, hMoneyTemp
+ ret
+
+Script_checktime:
+; script command 0x2b
+; parameters: time
+
+ xor a
+ ld [wScriptVar], a
+ farcall CheckTime
+ call GetScriptByte
+ and c
+ ret z
+ ld a, TRUE
+ ld [wScriptVar], a
+ ret
+
+Script_checkpoke:
+; script command 0x2c
+; parameters: pokemon
+
+ xor a
+ ld [wScriptVar], a
+ call GetScriptByte
+ ld hl, wPartySpecies
+ ld de, 1
+ call IsInArray
+ ret nc
+ ld a, TRUE
+ ld [wScriptVar], a
+ ret
+
+Script_addcellnum:
+; script command 0x28
+; parameters: person
+
+ xor a
+ ld [wScriptVar], a
+ call GetScriptByte
+ ld c, a
+ farcall AddPhoneNumber
+ ret nc
+ ld a, TRUE
+ ld [wScriptVar], a
+ ret
+
+Script_delcellnum:
+; script command 0x29
+; parameters: person
+
+ xor a
+ ld [wScriptVar], a
+ call GetScriptByte
+ ld c, a
+ farcall DelCellNum
+ ret nc
+ ld a, TRUE
+ ld [wScriptVar], a
+ ret
+
+Script_checkcellnum:
+; script command 0x2a
+; parameters: person
+; returns false if the cell number is not in your phone
+
+ xor a
+ ld [wScriptVar], a
+ call GetScriptByte
+ ld c, a
+ farcall CheckCellNum
+ ret nc
+ ld a, TRUE
+ ld [wScriptVar], a
+ ret
+
+Script_specialphonecall:
+; script command 0x9b
+; parameters: call_id
+
+ call GetScriptByte
+ ld [wSpecialPhoneCallID], a
+ call GetScriptByte
+ ld [wSpecialPhoneCallID + 1], a
+ ret
+
+Script_checkphonecall:
+; script command 0x9c
+; returns false if no special phone call is stored
+
+ ld a, [wSpecialPhoneCallID]
+ and a
+ jr z, .ok
+ ld a, TRUE
+.ok
+ ld [wScriptVar], a
+ ret
+
+Script_givepoke:
+; script command 0x2d
+; parameters: pokemon, level, item, trainer, trainer_name_pointer, pkmn_nickname
+
+ call GetScriptByte
+ ld [wCurPartySpecies], a
+ call GetScriptByte
+ ld [wCurPartyLevel], a
+ call GetScriptByte
+ ld [wCurItem], a
+ call GetScriptByte
+ and a
+ ld b, a
+ jr z, .ok
+ ld hl, wScriptPos
+ ld e, [hl]
+ inc hl
+ ld d, [hl]
+ call GetScriptByte
+ call GetScriptByte
+ call GetScriptByte
+ call GetScriptByte
+.ok
+ farcall GivePoke
+ ld a, b
+ ld [wScriptVar], a
+ ret
+
+Script_giveegg:
+; script command 0x2e
+; parameters: pokemon, level
+; if no room in the party, return 0 in wScriptVar; else, return 2
+
+ xor a ; PARTYMON
+ ld [wScriptVar], a
+ ld [wMonType], a
+ call GetScriptByte
+ ld [wCurPartySpecies], a
+ call GetScriptByte
+ ld [wCurPartyLevel], a
+ farcall GiveEgg
+ ret nc
+ ld a, 2
+ ld [wScriptVar], a
+ ret
+
+Script_setevent:
+; script command 0x33
+; parameters: bit_number
+
+ call GetScriptByte
+ ld e, a
+ call GetScriptByte
+ ld d, a
+ ld b, SET_FLAG
+ call EventFlagAction
+ ret
+
+Script_clearevent:
+; script command 0x32
+; parameters: bit_number
+
+ call GetScriptByte
+ ld e, a
+ call GetScriptByte
+ ld d, a
+ ld b, RESET_FLAG
+ call EventFlagAction
+ ret
+
+Script_checkevent:
+; script command 0x31
+; parameters: bit_number
+
+ call GetScriptByte
+ ld e, a
+ call GetScriptByte
+ ld d, a
+ ld b, CHECK_FLAG
+ call EventFlagAction
+ ld a, c
+ and a
+ jr z, .false
+ ld a, TRUE
+.false
+ ld [wScriptVar], a
+ ret
+
+Script_setflag:
+; script command 0x36
+; parameters: bit_number
+
+ call GetScriptByte
+ ld e, a
+ call GetScriptByte
+ ld d, a
+ ld b, SET_FLAG
+ call _EngineFlagAction
+ ret
+
+Script_clearflag:
+; script command 0x35
+; parameters: bit_number
+
+ call GetScriptByte
+ ld e, a
+ call GetScriptByte
+ ld d, a
+ ld b, RESET_FLAG
+ call _EngineFlagAction
+ ret
+
+Script_checkflag:
+; script command 0x34
+; parameters: bit_number
+
+ call GetScriptByte
+ ld e, a
+ call GetScriptByte
+ ld d, a
+ ld b, CHECK_FLAG
+ call _EngineFlagAction
+ ld a, c
+ and a
+ jr z, .false
+ ld a, TRUE
+.false
+ ld [wScriptVar], a
+ ret
+
+_EngineFlagAction:
+ farcall EngineFlagAction
+ ret
+
+Script_wildoff:
+; script command 0x38
+
+ ld hl, wStatusFlags
+ set STATUSFLAGS_NO_WILD_ENCOUNTERS_F, [hl]
+ ret
+
+Script_wildon:
+; script command 0x37
+
+ ld hl, wStatusFlags
+ res STATUSFLAGS_NO_WILD_ENCOUNTERS_F, [hl]
+ ret
+
+Script_xycompare:
+; script command 0x39
+; parameters: pointer
+
+ call GetScriptByte
+ ld [wXYComparePointer], a
+ call GetScriptByte
+ ld [wXYComparePointer + 1], a
+ ret
+
+Script_warpfacing:
+; script command 0xa1
+; parameters: facing, map_group, map_id, x, y
+
+ call GetScriptByte
+ maskbits NUM_DIRECTIONS
+ ld c, a
+ ld a, [wPlayerSpriteSetupFlags]
+ set PLAYERSPRITESETUP_CUSTOM_FACING_F, a
+ or c
+ ld [wPlayerSpriteSetupFlags], a
+; fall through
+
+Script_warp:
+; script command 0x3c
+; parameters: map_group, map_id, x, y
+
+; This seems to be some sort of error handling case.
+ call GetScriptByte
+ and a
+ jr z, .not_ok
+ ld [wMapGroup], a
+ call GetScriptByte
+ ld [wMapNumber], a
+ call GetScriptByte
+ ld [wXCoord], a
+ call GetScriptByte
+ ld [wYCoord], a
+ ld a, SPAWN_N_A
+ ld [wDefaultSpawnpoint], a
+ ld a, MAPSETUP_WARP
+ ldh [hMapEntryMethod], a
+ ld a, MAPSTATUS_ENTER
+ call LoadMapStatus
+ call StopScript
+ ret
+
+.not_ok
+ call GetScriptByte
+ call GetScriptByte
+ call GetScriptByte
+ ld a, SPAWN_N_A
+ ld [wDefaultSpawnpoint], a
+ ld a, MAPSETUP_BADWARP
+ ldh [hMapEntryMethod], a
+ ld a, MAPSTATUS_ENTER
+ call LoadMapStatus
+ call StopScript
+ ret
+
+Script_warpmod:
+; script command 0x3a
+; parameters: warp_id, map_group, map_id
+
+ call GetScriptByte
+ ld [wBackupWarpNumber], a
+ call GetScriptByte
+ ld [wBackupMapGroup], a
+ call GetScriptByte
+ ld [wBackupMapNumber], a
+ ret
+
+Script_blackoutmod:
+; script command 0x3b
+; parameters: map_group, map_id
+
+ call GetScriptByte
+ ld [wLastSpawnMapGroup], a
+ call GetScriptByte
+ ld [wLastSpawnMapNumber], a
+ ret
+
+Script_dontrestartmapmusic:
+; script command 0x82
+
+ ld a, TRUE
+ ld [wDontPlayMapMusicOnReload], a
+ ret
+
+Script_writecmdqueue:
+; script command 0x7c
+; parameters: queue_pointer
+
+ call GetScriptByte
+ ld e, a
+ call GetScriptByte
+ ld d, a
+ ld a, [wScriptBank]
+ ld b, a
+ farcall WriteCmdQueue ; no need to farcall
+ ret
+
+Script_delcmdqueue:
+; script command 0x7d
+; parameters: byte
+
+ xor a
+ ld [wScriptVar], a
+ call GetScriptByte
+ ld b, a
+ farcall DelCmdQueue ; no need to farcall
+ ret c
+ ld a, TRUE
+ ld [wScriptVar], a
+ ret
+
+Script_changemapblocks:
+; script command 0x78
+; parameters: map_data_pointer
+
+ call GetScriptByte
+ ld [wMapBlocksBank], a
+ call GetScriptByte
+ ld [wMapBlocksPointer], a
+ call GetScriptByte
+ ld [wMapBlocksPointer + 1], a
+ call ChangeMap
+ call BufferScreen
+ ret
+
+Script_changeblock:
+; script command 0x79
+; parameters: x, y, block
+
+ call GetScriptByte
+ add 4
+ ld d, a
+ call GetScriptByte
+ add 4
+ ld e, a
+ call GetBlockLocation
+ call GetScriptByte
+ ld [hl], a
+ call BufferScreen
+ ret
+
+Script_reloadmappart::
+; script command 0x7b
+
+ xor a
+ ldh [hBGMapMode], a
+ call OverworldTextModeSwitch
+ call GetMovementPermissions
+ call ApplyTilemap
+ call UpdateSprites
+ ret
+
+Script_warpcheck:
+; script command 0x8d
+
+ call WarpCheck
+ ret nc
+ farcall EnableEvents
+ ret
+
+Script_enableevents:
+; unused
+ farcall EnableEvents
+ ret
+
+Script_newloadmap:
+; script command 0x89
+; parameters: which_method
+
+ call GetScriptByte
+ ldh [hMapEntryMethod], a
+ ld a, MAPSTATUS_ENTER
+ call LoadMapStatus
+ call StopScript
+ ret
+
+Script_reloadandreturn:
+; script command 0x91
+
+ call Script_newloadmap
+ jp Script_end
+
+Script_opentext:
+; script command 0x47
+
+ call OpenText
+ ret
+
+Script_refreshscreen:
+; script command 0x48
+; parameters: dummy
+
+ call RefreshScreen
+ call GetScriptByte
+ ret
+
+Script_writeunusedbytebuffer:
+; script command 0x4a
+; parameters: byte
+
+ call GetScriptByte
+ ld [wUnusedScriptByteBuffer], a
+ ret
+
+ db closetext_command ; unused
+
+Script_closetext:
+; script command 0x49
+
+ ldh a, [hOAMUpdate]
+ push af
+ ld a, $01
+ ldh [hOAMUpdate], a
+ call WaitBGMap
+ pop af
+ ldh [hOAMUpdate], a
+ call CloseText
+ ret
+
+Script_autoinput:
+; script command 0x88
+; parameters: input_pointer
+
+ call GetScriptByte
+ push af
+ call GetScriptByte
+ ld l, a
+ call GetScriptByte
+ ld h, a
+ pop af
+ call StartAutoInput
+ ret
+
+Script_pause:
+; script command 0x8a
+; parameters: length
+
+ call GetScriptByte
+ and a
+ jr z, .loop
+ ld [wScriptDelay], a
+.loop
+ ld c, 2
+ call DelayFrames
+ ld hl, wScriptDelay
+ dec [hl]
+ jr nz, .loop
+ ret
+
+Script_deactivatefacing:
+; script command 0x8b
+; parameters: time
+
+ call GetScriptByte
+ and a
+ jr z, .no_time
+ ld [wScriptDelay], a
+.no_time
+ ld a, SCRIPT_WAIT
+ ld [wScriptMode], a
+ call StopScript
+ ret
+
+Script_stopandsjump:
+; script command 0x8e
+; parameters: pointer
+
+ call StopScript
+ jp Script_sjump
+
+Script_end:
+; script command 0x90
+
+ call ExitScriptSubroutine
+ jr c, .resume
+ ret
+
+.resume
+ xor a
+ ld [wScriptRunning], a
+ ld a, SCRIPT_OFF
+ ld [wScriptMode], a
+ ld hl, wScriptFlags
+ res 0, [hl]
+ call StopScript
+ ret
+
+Script_return:
+; script command 0x8f
+
+ call ExitScriptSubroutine
+ jr c, .dummy
+.dummy
+ ld hl, wScriptFlags
+ res 0, [hl]
+ call StopScript
+ ret
+
+ExitScriptSubroutine:
+; Return carry if there's no parent to return to.
+
+ ld hl, wScriptStackSize
+ ld a, [hl]
+ and a
+ jr z, .done
+ dec [hl]
+ ld e, [hl]
+ ld d, $0
+ ld hl, wScriptStack
+ add hl, de
+ add hl, de
+ add hl, de
+ ld a, [hli]
+ ld b, a
+ and " "
+ ld [wScriptBank], a
+ ld a, [hli]
+ ld e, a
+ ld [wScriptPos], a
+ ld a, [hl]
+ ld d, a
+ ld [wScriptPos + 1], a
+ and a
+ ret
+.done
+ scf
+ ret
+
+Script_endall:
+; script command 0x92
+
+ xor a
+ ld [wScriptStackSize], a
+ ld [wScriptRunning], a
+ ld a, SCRIPT_OFF
+ ld [wScriptMode], a
+ ld hl, wScriptFlags
+ res 0, [hl]
+ call StopScript
+ ret
+
+Script_halloffame:
+; script command 0x9f
+
+ ld hl, wGameTimerPause
+ res GAMETIMERPAUSE_TIMER_PAUSED_F, [hl]
+ farcall HallOfFame
+ ld hl, wGameTimerPause
+ set GAMETIMERPAUSE_TIMER_PAUSED_F, [hl]
+ jr ReturnFromCredits
+
+Script_credits:
+; script command 0xa0
+
+ farcall RedCredits
+ReturnFromCredits:
+ call Script_endall
+ ld a, MAPSTATUS_DONE
+ call LoadMapStatus
+ call StopScript
+ ret
+
+; unused
+ ld a, [.gs_version]
+ ld [wScriptVar], a
+ ret
+
+.gs_version:
+ db GS_VERSION
diff --git a/engine/overworld/select_menu.asm b/engine/overworld/select_menu.asm
new file mode 100644
index 00000000..18532eda
--- /dev/null
+++ b/engine/overworld/select_menu.asm
@@ -0,0 +1,172 @@
+SelectMenu::
+ call CheckRegisteredItem
+ jr c, .NotRegistered
+ jp UseRegisteredItem
+
+.NotRegistered:
+ call OpenText
+ ld b, BANK(MayRegisterItemText)
+ ld hl, MayRegisterItemText
+ call MapTextbox
+ call WaitButton
+ jp CloseText
+
+MayRegisterItemText:
+ text_far _MayRegisterItemText
+ text_end
+
+CheckRegisteredItem:
+ ld a, [wWhichRegisteredItem]
+ and a
+ jr z, .NoRegisteredItem
+ and REGISTERED_POCKET
+ rlca
+ rlca
+ ld hl, .Pockets
+ rst JumpTable
+ ret
+
+.Pockets:
+; entries correspond to *_POCKET constants
+ dw .CheckItem
+ dw .CheckBall
+ dw .CheckKeyItem
+ dw .CheckTMHM
+
+.CheckItem:
+ ld hl, wNumItems
+ call .CheckRegisteredNo
+ jr c, .NoRegisteredItem
+ inc hl
+ ld e, a
+ ld d, 0
+ add hl, de
+ add hl, de
+ call .IsSameItem
+ jr c, .NoRegisteredItem
+ and a
+ ret
+
+.CheckKeyItem:
+ ld a, [wRegisteredItem]
+ ld hl, wKeyItems
+ ld de, 1
+ call IsInArray
+ jr nc, .NoRegisteredItem
+ ld a, [wRegisteredItem]
+ ld [wCurItem], a
+ and a
+ ret
+
+.CheckBall:
+ ld hl, wNumBalls
+ call .CheckRegisteredNo
+ jr nc, .NoRegisteredItem
+ inc hl
+ ld e, a
+ ld d, 0
+ add hl, de
+ add hl, de
+ call .IsSameItem
+ jr c, .NoRegisteredItem
+ ret
+
+.CheckTMHM:
+ jr .NoRegisteredItem
+
+.NoRegisteredItem:
+ xor a
+ ld [wWhichRegisteredItem], a
+ ld [wRegisteredItem], a
+ scf
+ ret
+
+.CheckRegisteredNo:
+ ld a, [wWhichRegisteredItem]
+ and REGISTERED_NUMBER
+ dec a
+ cp [hl]
+ jr nc, .NotEnoughItems
+ ld [wCurItemQuantity], a
+ and a
+ ret
+
+.NotEnoughItems:
+ scf
+ ret
+
+.IsSameItem:
+ ld a, [wRegisteredItem]
+ cp [hl]
+ jr nz, .NotSameItem
+ ld [wCurItem], a
+ and a
+ ret
+
+.NotSameItem:
+ scf
+ ret
+
+UseRegisteredItem:
+ farcall CheckItemMenu
+ ld a, [wItemAttributeParamBuffer]
+ ld hl, .SwitchTo
+ rst JumpTable
+ ret
+
+.SwitchTo:
+; entries correspond to ITEMMENU_* constants
+ dw .CantUse
+ dw .NoFunction
+ dw .NoFunction
+ dw .NoFunction
+ dw .Current
+ dw .Party
+ dw .Overworld
+
+.NoFunction:
+ call OpenText
+ call CantUseItem
+ call CloseText
+ and a
+ ret
+
+.Current:
+ call OpenText
+ call DoItemEffect
+ call CloseText
+ and a
+ ret
+
+.Party:
+ call RefreshScreen
+ call FadeToMenu
+ call DoItemEffect
+ call CloseSubmenu
+ call CloseText
+ and a
+ ret
+
+.Overworld:
+ call RefreshScreen
+ ld a, 1
+ ld [wUsingItemWithSelect], a
+ call DoItemEffect
+ xor a
+ ld [wUsingItemWithSelect], a
+ ld a, [wItemEffectSucceeded]
+ cp 1
+ jr nz, ._cantuse
+ scf
+ ld a, HMENURETURN_SCRIPT
+ ldh [hMenuReturn], a
+ ret
+
+.CantUse:
+ call RefreshScreen
+
+._cantuse
+ call CantUseItem
+ call CloseText
+ and a
+ ret
diff --git a/engine/overworld/spawn_points.asm b/engine/overworld/spawn_points.asm
new file mode 100644
index 00000000..1b92b1e0
--- /dev/null
+++ b/engine/overworld/spawn_points.asm
@@ -0,0 +1,56 @@
+EnterMapSpawnPoint:
+ ; loads the spawn point in wDefaultSpawnpoint
+ push hl
+ push de
+ ld a, [wDefaultSpawnpoint]
+ cp SPAWN_N_A
+ jr z, .spawn_n_a
+ ld l, a
+ ld h, 0
+ add hl, hl
+ add hl, hl
+ ld de, SpawnPoints
+ add hl, de
+ ld a, [hli]
+ ld [wMapGroup], a
+ ld a, [hli]
+ ld [wMapNumber], a
+ ld a, [hli]
+ ld [wXCoord], a
+ ld a, [hli]
+ ld [wYCoord], a
+.spawn_n_a
+ pop de
+ pop hl
+ ret
+
+IsSpawnPoint:
+; Checks if the map loaded in de is a spawn point. Returns carry if it's a spawn point.
+ ld hl, SpawnPoints
+ ld c, 0
+.loop
+ ld a, [hl]
+ cp SPAWN_N_A
+ jr z, .nope
+ cp d
+ jr nz, .next
+ inc hl
+ ld a, [hld]
+ cp e
+ jr z, .yes
+
+.next
+ push bc
+ ld bc, 4 ; length of a spawn table entry
+ add hl, bc
+ pop bc
+ inc c
+ jr .loop
+
+.nope
+ and a
+ ret
+
+.yes
+ scf
+ ret
diff --git a/engine/overworld/tile_events.asm b/engine/overworld/tile_events.asm
new file mode 100644
index 00000000..bb566c99
--- /dev/null
+++ b/engine/overworld/tile_events.asm
@@ -0,0 +1,101 @@
+CheckWarpCollision::
+; Is this tile a warp?
+ ld a, [wPlayerStandingTile]
+ cp COLL_PIT
+ jr z, .warp
+ cp COLL_PIT_68
+ jr z, .warp
+ and $f0
+ cp HI_NYBBLE_WARPS
+ jr z, .warp
+ and a
+ ret
+
+.warp
+ scf
+ ret
+
+CheckDirectionalWarp::
+; If this is a directional warp, clear carry (press the designated button to warp).
+; Else, set carry (immediate warp).
+ ld a, [wPlayerStandingTile]
+ cp COLL_WARP_CARPET_DOWN
+ jr z, .directional
+ cp COLL_WARP_CARPET_LEFT
+ jr z, .directional
+ cp COLL_WARP_CARPET_UP
+ jr z, .directional
+ cp COLL_WARP_CARPET_RIGHT
+ jr z, .directional
+ scf
+ ret
+
+.directional
+ xor a
+ ret
+
+CheckWarpFacingDown:
+ ld de, 1
+ ld hl, .blocks
+ ld a, [wPlayerStandingTile]
+ call IsInArray
+ ret
+
+.blocks
+ db COLL_DOOR
+ db COLL_DOOR_79
+ db COLL_STAIRCASE
+ db COLL_STAIRCASE_73
+ db COLL_CAVE
+ db COLL_CAVE_74
+ db COLL_WARP_PANEL
+ db COLL_DOOR_75
+ db COLL_DOOR_7D
+ db -1
+
+CheckGrassCollision::
+ ld a, [wPlayerStandingTile]
+ ld hl, .blocks
+ ld de, 1
+ call IsInArray
+ ret
+
+.blocks
+ db COLL_CUT_08
+ db COLL_TALL_GRASS
+ db COLL_LONG_GRASS
+ db COLL_CUT_28
+ db COLL_WATER
+ db COLL_GRASS_48
+ db COLL_GRASS_49
+ db COLL_GRASS_4A
+ db COLL_GRASS_4B
+ db COLL_GRASS_4C
+ db -1
+
+CheckCutCollision:
+ ld a, c
+ ld hl, .blocks
+ ld de, 1
+ call IsInArray
+ ret
+
+.blocks
+ db COLL_CUT_TREE
+ db COLL_CUT_TREE_1A
+ db COLL_TALL_GRASS_10
+ db COLL_TALL_GRASS
+ db COLL_LONG_GRASS
+ db COLL_LONG_GRASS_1C
+ db -1
+
+GetWarpSFX::
+ ld a, [wPlayerStandingTile]
+ ld de, SFX_ENTER_DOOR
+ cp COLL_DOOR
+ ret z
+ ld de, SFX_WARP_TO
+ cp COLL_WARP_PANEL
+ ret z
+ ld de, SFX_EXIT_BUILDING
+ ret
diff --git a/engine/overworld/time.asm b/engine/overworld/time.asm
index 01273a75..a829cd4f 100755
--- a/engine/overworld/time.asm
+++ b/engine/overworld/time.asm
@@ -1,5 +1,5 @@
-InitializeStartDay_: ; 117f1 (4:57f1)
- call Function118c9
+_InitializeStartDay:
+ call InitializeStartDay
ret
ClearDailyTimers:
@@ -9,41 +9,45 @@ ClearDailyTimers:
ld [wDailyResetTimer], a
ret
-InitCallReceiveDelay:
+InitCallReceiveDelay::
xor a
ld [wTimeCyclesSinceLastCall], a
-Function11804: ; 11804 (4:5804)
+
+NextCallReceiveDelay:
ld a, [wTimeCyclesSinceLastCall]
- cp $3
- jr c, .asm_1180d
- ld a, $3
-.asm_1180d
+ cp 3
+ jr c, .okay
+ ld a, 3
+
+.okay
ld e, a
- ld d, $0
+ ld d, 0
ld hl, .ReceiveCallDelays
add hl, de
ld a, [hl]
- jp Function11849
+ jp RestartReceiveCallDelay
.ReceiveCallDelays:
db 20, 10, 5, 3
CheckReceiveCallTimer:
- call Function11857
+ call CheckReceiveCallDelay ; check timer
ret nc
ld hl, wTimeCyclesSinceLastCall
ld a, [hl]
- cp $3
- jr nc, .asm_11829
+ cp 3
+ jr nc, .ok
inc [hl]
-.asm_11829
- call Function11804
+
+.ok
+ call NextCallReceiveDelay ; restart timer
scf
ret
-Function1182e: ; 1182e (4:582e)
- ld a, $1
-Function11830:
+InitOneDayCountdown:
+ ld a, 1
+
+InitNDaysCountdown:
ld [hl], a
push hl
call UpdateTime
@@ -52,17 +56,17 @@ Function11830:
call CopyDayToHL
ret
-Function1183b: ; 1183b (4:583b)
+CheckDayDependentEventHL:
inc hl
push hl
call CalcDaysSince
- call Function119b4
+ call GetDaysSince
pop hl
dec hl
- call Function11972
+ call UpdateTimeRemaining
ret
-Function11849: ; 11849 (4:5849)
+RestartReceiveCallDelay:
ld hl, wReceiveCallDelay_MinsRemaining
ld [hl], a
call UpdateTime
@@ -70,91 +74,92 @@ Function11849: ; 11849 (4:5849)
call CopyDayHourMinToHL
ret
-Function11857: ; 11857 (4:5857)
+CheckReceiveCallDelay:
ld hl, wReceiveCallDelay_StartTime
call CalcMinsHoursDaysSince
- call Function1199a
+ call GetMinutesSinceIfLessThan60
ld hl, wReceiveCallDelay_MinsRemaining
- call Function11972
+ call UpdateTimeRemaining
ret
-asm_11867
+RestartDailyResetTimer:
ld hl, wDailyResetTimer
- jp Function1182e
+ jp InitOneDayCountdown
-CheckDailyResetTimer:
+CheckDailyResetTimer::
ld hl, wDailyResetTimer
- call Function1183b
+ call CheckDayDependentEventHL
ret nc
xor a
- ld hl, wDailyFlags
- ld [hli], a
- ld [hl], a
- jr asm_11867
+ ld hl, wDailyFlags1
+ ld [hli], a ; wDailyFlags1
+ ld [hl], a ; wDailyFlags2
+ jr RestartDailyResetTimer
StartBugContestTimer:
- ld a, 20
+ ld a, BUG_CONTEST_MINUTES
ld [wBugContestMinsRemaining], a
- ld a, 0
+ ld a, BUG_CONTEST_SECONDS
ld [wBugContestSecsRemaining], a
call UpdateTime
ld hl, wBugContestStartTime
call CopyDayHourMinSecToHL
ret
-CheckBugContestTimer:
+CheckBugContestTimer::
ld hl, wBugContestStartTime
call CalcSecsMinsHoursDaysSince
ld a, [wDaysSince]
and a
- jr nz, .asm_118c0
+ jr nz, .timed_out
ld a, [wHoursSince]
and a
- jr nz, .asm_118c0
- ld a, [wSecsSince]
+ jr nz, .timed_out
+ ld a, [wSecondsSince]
ld b, a
ld a, [wBugContestSecsRemaining]
sub b
- jr nc, .asm_118ae
+ jr nc, .okay
add 60
-.asm_118ae
+
+.okay
ld [wBugContestSecsRemaining], a
- ld a, [wMinsSince]
+ ld a, [wMinutesSince]
ld b, a
ld a, [wBugContestMinsRemaining]
sbc b
ld [wBugContestMinsRemaining], a
- jr c, .asm_118c0
+ jr c, .timed_out
and a
ret
-.asm_118c0
+.timed_out
xor a
ld [wBugContestMinsRemaining], a
ld [wBugContestSecsRemaining], a
scf
ret
-Function118c9: ; 118c9 (4:58c9)
+InitializeStartDay:
call UpdateTime
- ld hl, wStartDay
+ ld hl, wTimerEventStartDay
call CopyDayToHL
ret
-CheckPokerusTick:
- ld hl, wStartDay
+CheckPokerusTick::
+ ld hl, wTimerEventStartDay
call CalcDaysSince
- call Function119b4
+ call GetDaysSince
and a
- jr z, .asm_118e6
+ jr z, .done ; not even a day has passed since game start
ld b, a
- farcall ApplyPokerusTick ; same bank
-.asm_118e6
+ farcall ApplyPokerusTick
+.done
xor a
ret
SetUnusedTwoDayTimer:
- ld a, $2
+ ld a, 2
ld hl, wUnusedTwoDayTimer
ld [hl], a
call UpdateTime
@@ -162,63 +167,69 @@ SetUnusedTwoDayTimer:
call CopyDayToHL
ret
-Function118f8: ; 118f8 (4:58f8)
+CheckUnusedTwoDayTimer:
ld hl, wUnusedTwoDayTimerStartDate
call CalcDaysSince
- call Function119b4
+ call GetDaysSince
ld hl, wUnusedTwoDayTimer
- call Function11972
+ call UpdateTimeRemaining
ret
- ld hl, wDailyFlags
- set 2, [hl]
+; unused
+ ld hl, wDailyFlags1
+ set DAILYFLAGS1_SWARM_F, [hl]
ret
+; unused
and a
- ld hl, wDailyFlags
- bit 2, [hl]
+ ld hl, wDailyFlags1
+ bit DAILYFLAGS1_SWARM_F, [hl]
ret nz
scf
ret
-Function11917: ; 11917 (4:5917)
- call Function11920
+RestartLuckyNumberCountdown:
+ call .GetDaysUntilNextFriday
ld hl, wLuckyNumberDayBuffer
- jp Function11830
+ jp InitNDaysCountdown
-Function11920: ; 11920 (4:5920)
+.GetDaysUntilNextFriday:
call GetWeekday
ld c, a
- ld a, $5
+ ld a, FRIDAY
sub c
- jr z, .asm_1192b
- jr nc, .asm_1192d
-.asm_1192b
- add $7
-.asm_1192d
+ jr z, .friday_saturday
+ jr nc, .earlier ; could have done "ret nc"
+
+.friday_saturday
+ add 7
+
+.earlier
ret
-Function1192e: ; 1192e (4:592e)
+_CheckLuckyNumberShowFlag:
ld hl, wLuckyNumberDayBuffer
- jp Function1183b
+ jp CheckDayDependentEventHL
-Function11934: ; 11934 (4:5934)
+DoMysteryGiftIfDayHasPassed:
ld a, BANK(sMysteryGiftTimer)
call OpenSRAM
ld hl, sMysteryGiftTimer
ld a, [hli]
- ld [wCurHPAnimMaxHP], a
+ ld [wBuffer1], a
ld a, [hl]
ld [wBuffer2], a
call CloseSRAM
- ld hl, wCurHPAnimMaxHP
- call Function1183b
- jr nc, .asm_1195e
- ld hl, wCurHPAnimMaxHP
- call Function1182e
+
+ ld hl, wBuffer1
+ call CheckDayDependentEventHL
+ jr nc, .not_timed_out
+ ld hl, wBuffer1
+ call InitOneDayCountdown
call CloseSRAM
farcall Function2a4f6
-.asm_1195e
+
+.not_timed_out
ld a, BANK(sMysteryGiftTimer)
call OpenSRAM
ld hl, wBuffer1
@@ -229,21 +240,24 @@ Function11934: ; 11934 (4:5934)
call CloseSRAM
ret
-Function11972: ; 11972 (4:5972)
- cp $ff
- jr z, .asm_11981
+UpdateTimeRemaining:
+; If the amount of time elapsed exceeds the capacity of its
+; unit, skip this part.
+ cp -1
+ jr z, .set_carry
ld c, a
- ld a, [hl]
+ ld a, [hl] ; time remaining
sub c
- jr nc, .asm_1197c
+ jr nc, .ok
xor a
-.asm_1197c
+
+.ok
ld [hl], a
- jr z, .asm_11981
+ jr z, .set_carry
xor a
ret
-.asm_11981
+.set_carry
xor a
ld [hl], a
scf
@@ -252,100 +266,103 @@ Function11972: ; 11972 (4:5972)
GetSecondsSinceIfLessThan60:
ld a, [wDaysSince]
and a
- jr nz, asm_119b8
+ jr nz, GetTimeElapsed_ExceedsUnitLimit
ld a, [wHoursSince]
and a
- jr nz, asm_119b8
- ld a, [wMinsSince]
- jr nz, asm_119b8
- ld a, [wSecsSince]
+ jr nz, GetTimeElapsed_ExceedsUnitLimit
+ ld a, [wMinutesSince]
+ jr nz, GetTimeElapsed_ExceedsUnitLimit
+ ld a, [wSecondsSince]
ret
-Function1199a: ; 1199a (4:599a)
+GetMinutesSinceIfLessThan60:
ld a, [wDaysSince]
and a
- jr nz, asm_119b8
+ jr nz, GetTimeElapsed_ExceedsUnitLimit
ld a, [wHoursSince]
and a
- jr nz, asm_119b8
- ld a, [wMinsSince]
+ jr nz, GetTimeElapsed_ExceedsUnitLimit
+ ld a, [wMinutesSince]
ret
GetHoursSinceIfLessThan24:
ld a, [wDaysSince]
and a
- jr nz, asm_119b8
+ jr nz, GetTimeElapsed_ExceedsUnitLimit
ld a, [wHoursSince]
ret
-Function119b4: ; 119b4 (4:59b4)
+GetDaysSince:
ld a, [wDaysSince]
ret
-asm_119b8
- ld a, $ff
+GetTimeElapsed_ExceedsUnitLimit:
+ ld a, -1
ret
-CalcDaysSince: ; 119bb (4:59bb)
+CalcDaysSince:
xor a
- jr CalcDaysSince_
+ jr _CalcDaysSince
CalcHoursDaysSince:
inc hl
xor a
- jr CalcHoursDaysSince_
+ jr _CalcHoursDaysSince
-CalcMinsHoursDaysSince: ; 119c2 (4:59c2)
+CalcMinsHoursDaysSince:
inc hl
inc hl
xor a
- jr CalcMinsHoursDaysSince_
+ jr _CalcMinsHoursDaysSince
-CalcSecsMinsHoursDaysSince: ; 119c7 (4:59c7)
+CalcSecsMinsHoursDaysSince:
inc hl
inc hl
inc hl
ldh a, [hSeconds]
ld c, a
sub [hl]
- jr nc, .asm_119d2
+ jr nc, .skip
add 60
-.asm_119d2
- ld [hl], c
+.skip
+ ld [hl], c ; current seconds
dec hl
- ld [wSecsSince], a
-CalcMinsHoursDaysSince_
+ ld [wSecondsSince], a ; seconds since
+
+_CalcMinsHoursDaysSince:
ldh a, [hMinutes]
ld c, a
sbc [hl]
- jr nc, .asm_119df
+ jr nc, .skip
add 60
-.asm_119df
- ld [hl], c
+.skip
+ ld [hl], c ; current minutes
dec hl
- ld [wMinsSince], a
-CalcHoursDaysSince_
+ ld [wMinutesSince], a ; minutes since
+
+_CalcHoursDaysSince:
ldh a, [hHours]
ld c, a
sbc [hl]
- jr nc, .asm_119ec
+ jr nc, .skip
add 24
-.asm_119ec
- ld [hl], c
+.skip
+ ld [hl], c ; current hours
dec hl
- ld [wHoursSince], a
-CalcDaysSince_:
+ ld [wHoursSince], a ; hours since
+
+_CalcDaysSince:
ld a, [wCurDay]
ld c, a
sbc [hl]
- jr nc, .asm_119fa
+ jr nc, .skip
add 20 * 7
-.asm_119fa
- ld [hl], c
- ld [wDaysSince], a
+.skip
+ ld [hl], c ; current days
+ ld [wDaysSince], a ; days since
ret
-CopyDayHourMinSecToHL: ; 119ff (4:59ff)
+CopyDayHourMinSecToHL:
ld a, [wCurDay]
ld [hli], a
ldh a, [hHours]
@@ -356,7 +373,7 @@ CopyDayHourMinSecToHL: ; 119ff (4:59ff)
ld [hli], a
ret
-CopyDayToHL: ; 11a0d (4:5a0d)
+CopyDayToHL:
ld a, [wCurDay]
ld [hl], a
ret
@@ -368,7 +385,7 @@ CopyDayHourToHL:
ld [hli], a
ret
-CopyDayHourMinToHL: ; 11a1a (4:5a1a)
+CopyDayHourMinToHL:
ld a, [wCurDay]
ld [hli], a
ldh a, [hHours]
diff --git a/engine/overworld/variables.asm b/engine/overworld/variables.asm
new file mode 100755
index 00000000..406cf715
--- /dev/null
+++ b/engine/overworld/variables.asm
@@ -0,0 +1,122 @@
+_GetVarAction::
+ ld a, c
+ cp NUM_VARS
+ jr c, .valid
+ xor a
+.valid
+ ld c, a
+ ld b, 0
+ ld hl, .VarActionTable
+ add hl, bc
+ add hl, bc
+ add hl, bc
+ ld e, [hl]
+ inc hl
+ ld d, [hl]
+ inc hl
+ ld b, [hl]
+ ld a, b
+ and RETVAR_EXECUTE
+ jr nz, .call
+ ld a, b
+ and RETVAR_ADDR_DE
+ ret nz
+ ld a, [de]
+ jr .loadstringbuffer2
+
+.call
+ call _de_
+ ret
+
+.loadstringbuffer2
+ ld de, wStringBuffer2
+ ld [de], a
+ ret
+
+.VarActionTable:
+; entries correspond to VAR_* constants
+ ; RETVAR_STRBUF2: copy [de] to wStringBuffer2
+ ; RETVAR_ADDR_DE: return address in de
+ ; RETVAR_EXECUTE: call function
+ dwb wStringBuffer2, RETVAR_STRBUF2
+ dwb wPartyCount, RETVAR_STRBUF2
+ dwb .BattleResult, RETVAR_EXECUTE
+ dwb wBattleType, RETVAR_ADDR_DE
+ dwb wTimeOfDay, RETVAR_STRBUF2
+ dwb .CountCaughtMons, RETVAR_EXECUTE
+ dwb .CountSeenMons, RETVAR_EXECUTE
+ dwb .CountBadges, RETVAR_EXECUTE
+ dwb wPlayerState, RETVAR_ADDR_DE
+ dwb .PlayerFacing, RETVAR_EXECUTE
+ dwb hHours, RETVAR_STRBUF2
+ dwb .DayOfWeek, RETVAR_EXECUTE
+ dwb wMapGroup, RETVAR_STRBUF2
+ dwb wMapNumber, RETVAR_STRBUF2
+ dwb .UnownCaught, RETVAR_EXECUTE
+ dwb wEnvironment, RETVAR_STRBUF2
+ dwb .BoxFreeSpace, RETVAR_EXECUTE
+ dwb wBugContestMinsRemaining, RETVAR_STRBUF2
+ dwb wXCoord, RETVAR_STRBUF2
+ dwb wYCoord, RETVAR_STRBUF2
+ dwb wSpecialPhoneCallID, RETVAR_STRBUF2
+ dwb NULL, RETVAR_STRBUF2
+
+.CountCaughtMons:
+; Caught mons.
+ ld hl, wPokedexCaught
+ ld b, wEndPokedexCaught - wPokedexCaught
+ call CountSetBits
+ ld a, [wNumSetBits]
+ jp .loadstringbuffer2
+
+.CountSeenMons:
+; Seen mons.
+ ld hl, wPokedexSeen
+ ld b, wEndPokedexSeen - wPokedexSeen
+ call CountSetBits
+ ld a, [wNumSetBits]
+ jp .loadstringbuffer2
+
+.CountBadges:
+; Number of owned badges.
+ ld hl, wBadges
+ ld b, 2
+ call CountSetBits
+ ld a, [wNumSetBits]
+ jp .loadstringbuffer2
+
+.PlayerFacing:
+; The direction the player is facing.
+ ld a, [wPlayerDirection]
+ and $c
+ rrca
+ rrca
+ jp .loadstringbuffer2
+
+.DayOfWeek:
+; The day of the week.
+ call GetWeekday
+ jp .loadstringbuffer2
+
+.UnownCaught:
+; Number of unique Unown caught.
+ call CountUnown
+ ld a, b
+ jp .loadstringbuffer2
+
+.BoxFreeSpace:
+; Remaining slots in the current box.
+ ld a, BANK(sBoxCount)
+ call OpenSRAM
+ ld hl, sBoxCount
+ ld a, MONS_PER_BOX
+ sub [hl]
+ ld b, a
+ call CloseSRAM
+ ld a, b
+ jp .loadstringbuffer2
+
+.BattleResult:
+ ld a, [wBattleResult]
+ and $ff ^ BATTLERESULT_BITMASK
+ jp .loadstringbuffer2
diff --git a/engine/overworld/wildmons.asm b/engine/overworld/wildmons.asm
new file mode 100644
index 00000000..c06020e1
--- /dev/null
+++ b/engine/overworld/wildmons.asm
@@ -0,0 +1,971 @@
+LoadWildMonData:
+ call _GrassWildmonLookup
+ jr c, .copy
+ ld hl, wMornEncounterRate
+ xor a
+ ld [hli], a
+ ld [hli], a
+ ld [hl], a
+ jr .done_copy
+
+.copy
+ inc hl
+ inc hl
+ ld de, wMornEncounterRate
+ ld bc, 3
+ call CopyBytes
+.done_copy
+ call _WaterWildmonLookup
+ ld a, 0
+ jr nc, .no_copy
+ inc hl
+ inc hl
+ ld a, [hl]
+.no_copy
+ ld [wWaterEncounterRate], a
+ ret
+
+FindNest:
+; Parameters:
+; e: 0 = Johto, 1 = Kanto
+; wNamedObjectIndexBuffer: species
+ hlcoord 0, 0
+ ld bc, SCREEN_WIDTH * SCREEN_HEIGHT
+ xor a
+ call ByteFill
+ ld a, e
+ and a
+ jr nz, .kanto
+ decoord 0, 0
+ ld hl, JohtoGrassWildMons
+ call .FindGrass
+ ld hl, JohtoWaterWildMons
+ call .FindWater
+ call .RoamMon1
+ call .RoamMon2
+ call .RoamMon3
+ ret
+
+.kanto
+ decoord 0, 0
+ ld hl, KantoGrassWildMons
+ call .FindGrass
+ ld hl, KantoWaterWildMons
+ jp .FindWater
+
+.FindGrass:
+ ld a, [hl]
+ cp -1
+ ret z
+ push hl
+ ld a, [hli]
+ ld b, a
+ ld a, [hli]
+ ld c, a
+ inc hl
+ inc hl
+ inc hl
+ ld a, NUM_GRASSMON * 3
+ call .SearchMapForMon
+ jr nc, .next_grass
+ ld [de], a
+ inc de
+
+.next_grass
+ pop hl
+ ld bc, GRASS_WILDDATA_LENGTH
+ add hl, bc
+ jr .FindGrass
+
+.FindWater:
+ ld a, [hl]
+ cp -1
+ ret z
+ push hl
+ ld a, [hli]
+ ld b, a
+ ld a, [hli]
+ ld c, a
+ inc hl
+ ld a, NUM_WATERMON
+ call .SearchMapForMon
+ jr nc, .next_water
+ ld [de], a
+ inc de
+
+.next_water
+ pop hl
+ ld bc, WATER_WILDDATA_LENGTH
+ add hl, bc
+ jr .FindWater
+
+.SearchMapForMon:
+ inc hl
+.ScanMapLoop:
+ push af
+ ld a, [wNamedObjectIndexBuffer]
+ cp [hl]
+ jr z, .found
+ inc hl
+ inc hl
+ pop af
+ dec a
+ jr nz, .ScanMapLoop
+ and a
+ ret
+
+.found
+ pop af
+ jp .AppendNest
+
+.AppendNest:
+ push de
+ call GetWorldMapLocation
+ ld c, a
+ hlcoord 0, 0
+ ld de, SCREEN_WIDTH * SCREEN_HEIGHT
+.AppendNestLoop:
+ ld a, [hli]
+ cp c
+ jr z, .found_nest
+ dec de
+ ld a, e
+ or d
+ jr nz, .AppendNestLoop
+ ld a, c
+ pop de
+ scf
+ ret
+
+.found_nest
+ pop de
+ and a
+ ret
+
+.RoamMon1:
+ ld a, [wRoamMon1Species]
+ ld b, a
+ ld a, [wNamedObjectIndexBuffer]
+ cp b
+ ret nz
+ ld a, [wRoamMon1MapGroup]
+ ld b, a
+ ld a, [wRoamMon1MapNumber]
+ ld c, a
+ call .AppendNest
+ ret nc
+ ld [de], a
+ inc de
+ ret
+
+.RoamMon2:
+ ld a, [wRoamMon2Species]
+ ld b, a
+ ld a, [wNamedObjectIndexBuffer]
+ cp b
+ ret nz
+ ld a, [wRoamMon2MapGroup]
+ ld b, a
+ ld a, [wRoamMon2MapNumber]
+ ld c, a
+ call .AppendNest
+ ret nc
+ ld [de], a
+ inc de
+ ret
+
+.RoamMon3:
+ ld a, [wRoamMon3Species]
+ ld b, a
+ ld a, [wNamedObjectIndexBuffer]
+ cp b
+ ret nz
+ ld a, [wRoamMon3MapGroup]
+ ld b, a
+ ld a, [wRoamMon3MapNumber]
+ ld c, a
+ call .AppendNest
+ ret nc
+ ld [de], a
+ inc de
+ ret
+
+TryWildEncounter::
+; Try to trigger a wild encounter.
+ call .EncounterRate
+ jr nc, .no_battle
+ call ChooseWildEncounter
+ jr nz, .no_battle
+ call CheckRepelEffect
+ jr nc, .no_battle
+ xor a
+ ret
+
+.no_battle
+ xor a ; BATTLETYPE_NORMAL
+ ld [wTempWildMonSpecies], a
+ ld [wBattleType], a
+ ld a, 1
+ and a
+ ret
+
+.EncounterRate:
+ call GetMapEncounterRate
+ call ApplyMusicEffectOnEncounterRate
+ call ApplyCleanseTagEffectOnEncounterRate
+ call Random
+ cp b
+ ret
+
+GetMapEncounterRate:
+ ld hl, wMornEncounterRate
+ call CheckOnWater
+ ld a, wWaterEncounterRate - wMornEncounterRate
+ jr z, .ok
+ ld a, [wTimeOfDay]
+.ok
+ ld c, a
+ ld b, 0
+ add hl, bc
+ ld b, [hl]
+ ret
+
+ApplyMusicEffectOnEncounterRate::
+; Pokemon March and Ruins of Alph signal double encounter rate.
+; Pokemon Lullaby halves encounter rate.
+ ld a, [wMapMusic]
+ cp MUSIC_POKEMON_MARCH
+ jr z, .double
+ cp MUSIC_RUINS_OF_ALPH_RADIO
+ jr z, .double
+ cp MUSIC_POKEMON_LULLABY
+ ret nz
+ srl b
+ ret
+
+.double
+ sla b
+ ret
+
+ApplyCleanseTagEffectOnEncounterRate::
+; Cleanse Tag halves encounter rate.
+ ld hl, wPartyMon1Item
+ ld de, PARTYMON_STRUCT_LENGTH
+ ld a, [wPartyCount]
+ ld c, a
+.loop
+ ld a, [hl]
+ cp CLEANSE_TAG
+ jr z, .cleansetag
+ add hl, de
+ dec c
+ jr nz, .loop
+ ret
+
+.cleansetag
+ srl b
+ ret
+
+ChooseWildEncounter:
+ call LoadWildMonDataPointer
+ jp nc, .nowildbattle
+ call CheckEncounterRoamMon
+ jp c, .startwildbattle
+
+ inc hl
+ inc hl
+ inc hl
+ call CheckOnWater
+ ld de, WaterMonProbTable
+ jr z, .watermon
+ inc hl
+ inc hl
+ ld a, [wTimeOfDay]
+ ld bc, NUM_GRASSMON * 2
+ call AddNTimes
+ ld de, GrassMonProbTable
+
+.watermon
+; hl contains the pointer to the wild mon data, let's save that to the stack
+ push hl
+.randomloop
+ call Random
+ cp 100
+ jr nc, .randomloop
+ inc a ; 1 <= a <= 100
+ ld b, a
+ ld h, d
+ ld l, e
+; This next loop chooses which mon to load up.
+.prob_bracket_loop
+ ld a, [hli]
+ cp b
+ jr nc, .got_it
+ inc hl
+ jr .prob_bracket_loop
+
+.got_it
+ ld c, [hl]
+ ld b, 0
+ pop hl
+ add hl, bc ; this selects our mon
+ ld a, [hli]
+ ld b, a
+; If the Pokemon is encountered by surfing, we need to give the levels some variety.
+ call CheckOnWater
+ jr nz, .ok
+; Check if we buff the wild mon, and by how much.
+ call Random
+ cp 35 percent
+ jr c, .ok
+ inc b
+ cp 65 percent
+ jr c, .ok
+ inc b
+ cp 85 percent
+ jr c, .ok
+ inc b
+ cp 95 percent
+ jr c, .ok
+ inc b
+; Store the level
+.ok
+ ld a, b
+ ld [wCurPartyLevel], a
+ ld b, [hl]
+ ; ld a, b
+ call ValidateTempWildMonSpecies
+ jr c, .nowildbattle
+
+ ld a, b ; This is in the wrong place.
+ cp UNOWN
+ jr nz, .done
+
+ ld a, [wUnlockedUnowns]
+ and a
+ jr z, .nowildbattle
+
+.done
+ jr .loadwildmon
+
+.nowildbattle
+ ld a, 1
+ and a
+ ret
+
+.loadwildmon
+ ld a, b
+ ld [wTempWildMonSpecies], a
+
+.startwildbattle
+ xor a
+ ret
+
+INCLUDE "data/wild/probabilities.asm"
+
+CheckRepelEffect::
+; If there is no active Repel, there's no need to be here.
+ ld a, [wRepelEffect]
+ and a
+ jr z, .encounter
+; Get the first Pokemon in your party that isn't fainted.
+ ld hl, wPartyMon1HP
+ ld bc, PARTYMON_STRUCT_LENGTH - 1
+.loop
+ ld a, [hli]
+ or [hl]
+ jr nz, .ok
+ add hl, bc
+ jr .loop
+
+.ok
+; to PartyMonLevel
+rept 4
+ dec hl
+endr
+
+ ld a, [wCurPartyLevel]
+ cp [hl]
+ jr nc, .encounter
+ and a
+ ret
+
+.encounter
+ scf
+ ret
+
+LoadWildMonDataPointer:
+ call CheckOnWater
+ jr z, _WaterWildmonLookup
+
+_GrassWildmonLookup:
+ ld hl, SwarmGrassWildMons
+ ld bc, GRASS_WILDDATA_LENGTH
+ call _SwarmWildmonCheck
+ ret c
+ ld hl, JohtoGrassWildMons
+ ld de, KantoGrassWildMons
+ call _JohtoWildmonCheck
+ ld bc, GRASS_WILDDATA_LENGTH
+ jr _NormalWildmonOK
+
+_WaterWildmonLookup:
+ ld hl, SwarmWaterWildMons
+ ld bc, WATER_WILDDATA_LENGTH
+ call _SwarmWildmonCheck
+ ret c
+ ld hl, JohtoWaterWildMons
+ ld de, KantoWaterWildMons
+ call _JohtoWildmonCheck
+ ld bc, WATER_WILDDATA_LENGTH
+ jr _NormalWildmonOK
+
+_JohtoWildmonCheck:
+ call IsInJohto
+ and a
+ ret z
+ ld h, d
+ ld l, e
+ ret
+
+_SwarmWildmonCheck:
+ call CopyCurrMapDE
+ ld a, [wSwarmMapGroup]
+ cp d
+ jr nz, _NoSwarmWildmon
+ ld a, [wSwarmMapNumber]
+ cp e
+ jr nz, _NoSwarmWildmon
+ call LookUpWildmonsForMapDE
+ jr nc, _NoSwarmWildmon
+ scf
+ ret
+
+_NoSwarmWildmon:
+ and a
+ ret
+
+_NormalWildmonOK:
+ call CopyCurrMapDE
+ jr LookUpWildmonsForMapDE
+
+CopyCurrMapDE:
+ ld a, [wMapGroup]
+ ld d, a
+ ld a, [wMapNumber]
+ ld e, a
+ ret
+
+LookUpWildmonsForMapDE:
+.loop
+ push hl
+ ld a, [hl]
+ inc a
+ jr z, .nope
+ ld a, d
+ cp [hl]
+ jr nz, .next
+ inc hl
+ ld a, e
+ cp [hl]
+ jr z, .yup
+
+.next
+ pop hl
+ add hl, bc
+ jr .loop
+
+.nope
+ pop hl
+ and a
+ ret
+
+.yup
+ pop hl
+ scf
+ ret
+
+InitRoamMons:
+; initialize wRoamMon structs
+
+; species
+ ld a, RAIKOU
+ ld [wRoamMon1Species], a
+ ld a, ENTEI
+ ld [wRoamMon2Species], a
+ ld a, SUICUNE
+ ld [wRoamMon3Species], a
+
+; level
+ ld a, 40
+ ld [wRoamMon1Level], a
+ ld [wRoamMon2Level], a
+ ld [wRoamMon3Level], a
+
+; raikou starting map
+ ld a, GROUP_ROUTE_42
+ ld [wRoamMon1MapGroup], a
+ ld a, MAP_ROUTE_42
+ ld [wRoamMon1MapNumber], a
+
+; entei starting map
+ ld a, GROUP_ROUTE_37
+ ld [wRoamMon2MapGroup], a
+ ld a, MAP_ROUTE_37
+ ld [wRoamMon2MapNumber], a
+
+; suicune starting map
+ ld a, GROUP_ROUTE_38
+ ld [wRoamMon3MapGroup], a
+ ld a, MAP_ROUTE_38
+ ld [wRoamMon3MapNumber], a
+
+; hp
+ xor a ; generate new stats
+ ld [wRoamMon1HP], a
+ ld [wRoamMon2HP], a
+ ld [wRoamMon3HP], a
+
+ ret
+
+CheckEncounterRoamMon:
+ push hl
+; Don't trigger an encounter if we're on water.
+ call CheckOnWater
+ jr z, .DontEncounterRoamMon
+; Load the current map group and number to de
+ call CopyCurrMapDE
+; Randomly select a beast.
+ call Random
+ cp 100 ; 25/64 chance
+ jr nc, .DontEncounterRoamMon
+ and %00000011 ; Of that, a 3/4 chance. Running total: 75/256, or around 29.3%.
+ jr z, .DontEncounterRoamMon
+ dec a ; 1/3 chance that it's Entei, 1/3 chance that it's Raikou, 1/3 chance that it's Suicune
+; Compare its current location with yours
+ ld hl, wRoamMon1MapGroup
+ ld c, a
+ ld b, 0
+ ld a, 7 ; length of the roam_struct
+ call AddNTimes
+ ld a, d
+ cp [hl]
+ jr nz, .DontEncounterRoamMon
+ inc hl
+ ld a, e
+ cp [hl]
+ jr nz, .DontEncounterRoamMon
+; We've decided to take on a beast, so stage its information for battle.
+ dec hl
+ dec hl
+ dec hl
+ ld a, [hli]
+ ld [wTempWildMonSpecies], a
+ ld a, [hl]
+ ld [wCurPartyLevel], a
+ ld a, BATTLETYPE_ROAMING
+ ld [wBattleType], a
+
+ pop hl
+ scf
+ ret
+
+.DontEncounterRoamMon:
+ pop hl
+ and a
+ ret
+
+UpdateRoamMons:
+ ld a, [wRoamMon1MapGroup]
+ cp GROUP_N_A
+ jr z, .SkipRaikou
+ ld b, a
+ ld a, [wRoamMon1MapNumber]
+ ld c, a
+ call .Update
+ ld a, b
+ ld [wRoamMon1MapGroup], a
+ ld a, c
+ ld [wRoamMon1MapNumber], a
+
+.SkipRaikou:
+ ld a, [wRoamMon2MapGroup]
+ cp GROUP_N_A
+ jr z, .SkipEntei
+ ld b, a
+ ld a, [wRoamMon2MapNumber]
+ ld c, a
+ call .Update
+ ld a, b
+ ld [wRoamMon2MapGroup], a
+ ld a, c
+ ld [wRoamMon2MapNumber], a
+
+.SkipEntei:
+ ld a, [wRoamMon3MapGroup]
+ cp GROUP_N_A
+ jr z, .Finished
+ ld b, a
+ ld a, [wRoamMon3MapNumber]
+ ld c, a
+ call .Update
+ ld a, b
+ ld [wRoamMon3MapGroup], a
+ ld a, c
+ ld [wRoamMon3MapNumber], a
+
+.Finished:
+ jp _BackUpMapIndices
+
+.Update:
+ ld hl, RoamMaps
+.loop
+; Are we at the end of the table?
+ ld a, [hl]
+ cp -1
+ ret z
+; Is this the correct entry?
+ ld a, b
+ cp [hl]
+ jr nz, .next
+ inc hl
+ ld a, c
+ cp [hl]
+ jr z, .yes
+; We don't have the correct entry yet, so let's continue. A 0 terminates each entry.
+.next
+ ld a, [hli]
+ and a
+ jr nz, .next
+ jr .loop
+
+; We have the correct entry now, so let's choose a random map from it.
+.yes
+ inc hl
+ ld d, h
+ ld e, l
+.update_loop
+ ld h, d
+ ld l, e
+; Choose which map to warp to.
+ call Random
+ and %00011111 ; 1/8n chance it moves to a completely random map, where n is the number of roaming connections from the current map.
+ jr z, JumpRoamMon
+ and %11
+ cp [hl]
+ jr nc, .update_loop ; invalid index, try again
+ inc hl
+ ld c, a
+ ld b, 0
+ add hl, bc
+ add hl, bc
+ ld a, [wRoamMons_LastMapGroup]
+ cp [hl]
+ jr nz, .done
+ inc hl
+ ld a, [wRoamMons_LastMapNumber]
+ cp [hl]
+ jr z, .update_loop
+ dec hl
+
+.done
+ ld a, [hli]
+ ld b, a
+ ld c, [hl]
+ ret
+
+JumpRoamMons:
+ ld a, [wRoamMon1MapGroup]
+ cp GROUP_N_A
+ jr z, .SkipRaikou
+ call JumpRoamMon
+ ld a, b
+ ld [wRoamMon1MapGroup], a
+ ld a, c
+ ld [wRoamMon1MapNumber], a
+
+.SkipRaikou:
+ ld a, [wRoamMon2MapGroup]
+ cp GROUP_N_A
+ jr z, .SkipEntei
+ call JumpRoamMon
+ ld a, b
+ ld [wRoamMon2MapGroup], a
+ ld a, c
+ ld [wRoamMon2MapNumber], a
+
+.SkipEntei:
+ ld a, [wRoamMon3MapGroup]
+ cp GROUP_N_A
+ jr z, .Finished
+ call JumpRoamMon
+ ld a, b
+ ld [wRoamMon3MapGroup], a
+ ld a, c
+ ld [wRoamMon3MapNumber], a
+
+.Finished:
+ jp _BackUpMapIndices
+
+JumpRoamMon:
+.loop
+ ld hl, RoamMaps
+.innerloop1 ; This loop happens to be unnecessary.
+ call Random ; Choose a random number.
+ maskbits NUM_ROAMMON_MAPS ; Mask the number to limit it between 0 and 15.
+ cp NUM_ROAMMON_MAPS ; If the number is not less than 16, try again.
+ jr nc, .innerloop1 ; I'm sure you can guess why this check is bogus.
+ inc a
+ ld b, a
+.innerloop2 ; Loop to get hl to the address of the chosen roam map.
+ dec b
+ jr z, .ok
+.innerloop3 ; Loop to skip the current roam map, which is terminated by a 0.
+ ld a, [hli]
+ and a
+ jr nz, .innerloop3
+ jr .innerloop2
+; Check to see if the selected map is the one the player is currently in. If so, try again.
+.ok
+ ld a, [wMapGroup]
+ cp [hl]
+ jr nz, .done
+ inc hl
+ ld a, [wMapNumber]
+ cp [hl]
+ jr z, .loop
+ dec hl
+; Return the map group and number in bc.
+.done
+ ld a, [hli]
+ ld b, a
+ ld c, [hl]
+ ret
+
+_BackUpMapIndices:
+ ld a, [wRoamMons_CurMapNumber]
+ ld [wRoamMons_LastMapNumber], a
+ ld a, [wRoamMons_CurMapGroup]
+ ld [wRoamMons_LastMapGroup], a
+ ld a, [wMapNumber]
+ ld [wRoamMons_CurMapNumber], a
+ ld a, [wMapGroup]
+ ld [wRoamMons_CurMapGroup], a
+ ret
+
+INCLUDE "data/wild/roammon_maps.asm"
+
+ValidateTempWildMonSpecies:
+; Due to a development oversight, this function is called with the wild Pokemon's level, not its species, in a.
+ and a
+ jr z, .nowildmon ; = 0
+ cp NUM_POKEMON + 1 ; 252
+ jr nc, .nowildmon ; >= 252
+ and a ; 1 <= Species <= 251
+ ret
+
+.nowildmon
+ scf
+ ret
+
+; Finds a rare wild Pokemon in the route of the trainer calling, then checks if it's been Seen already.
+; The trainer will then tell you about the Pokemon if you haven't seen it.
+RandomUnseenWildMon:
+ farcall GetCallerLocation
+ ld d, b
+ ld e, c
+ ld hl, JohtoGrassWildMons
+ ld bc, GRASS_WILDDATA_LENGTH
+ call LookUpWildmonsForMapDE
+ jr c, .GetGrassmon
+ ld hl, KantoGrassWildMons
+ call LookUpWildmonsForMapDE
+ jr nc, .done
+
+.GetGrassmon:
+ push hl
+ ld bc, 5 + 4 * 2 ; Location of the level of the 5th wild Pokemon in that map
+ add hl, bc
+ ld a, [wTimeOfDay]
+ ld bc, NUM_GRASSMON * 2
+ call AddNTimes
+.randloop1
+ call Random
+ and %11
+ jr z, .randloop1
+ dec a
+ ld c, a
+ ld b, 0
+ add hl, bc
+ add hl, bc
+; We now have the pointer to one of the last (rarest) three wild Pokemon found in that area.
+ inc hl
+ ld c, [hl] ; Contains the species index of this rare Pokemon
+ pop hl
+ ld de, 5 + 0 * 2
+ add hl, de
+ inc hl ; Species index of the most common Pokemon on that route
+ ld b, 4
+.loop2
+ ld a, [hli]
+ cp c ; Compare this most common Pokemon with the rare one stored in c.
+ jr z, .done
+ inc hl
+ dec b
+ jr nz, .loop2
+; This Pokemon truly is rare.
+ push bc
+ dec c
+ ld a, c
+ call CheckSeenMon
+ pop bc
+ jr nz, .done
+; Since we haven't seen it, have the caller tell us about it.
+ ld de, wStringBuffer1
+ call CopyName1
+ ld a, c
+ ld [wNamedObjectIndexBuffer], a
+ call GetPokemonName
+ ld hl, .JustSawSomeRareMonText
+ call PrintText
+ xor a
+ ld [wScriptVar], a
+ ret
+
+.done
+ ld a, $1
+ ld [wScriptVar], a
+ ret
+
+.JustSawSomeRareMonText:
+ text_far _JustSawSomeRareMonText
+ text_end
+
+RandomPhoneWildMon:
+ farcall GetCallerLocation
+ ld d, b
+ ld e, c
+ ld hl, JohtoGrassWildMons
+ ld bc, GRASS_WILDDATA_LENGTH
+ call LookUpWildmonsForMapDE
+ jr c, .ok
+ ld hl, KantoGrassWildMons
+ call LookUpWildmonsForMapDE
+
+.ok
+ ld bc, 5 + 0 * 2
+ add hl, bc
+ ld a, [wTimeOfDay]
+ inc a
+ ld bc, NUM_GRASSMON * 2
+.loop
+ dec a
+ jr z, .done
+ add hl, bc
+ jr .loop
+
+.done
+ call Random
+ and %11
+ ld c, a
+ ld b, 0
+ add hl, bc
+ add hl, bc
+ inc hl
+ ld a, [hl]
+ ld [wNamedObjectIndexBuffer], a
+ call GetPokemonName
+ ld hl, wStringBuffer1
+ ld de, wStringBuffer4
+ ld bc, MON_NAME_LENGTH
+ jp CopyBytes
+
+RandomPhoneMon:
+; Get a random monster owned by the trainer who's calling.
+ farcall GetCallerLocation
+ ld hl, TrainerGroups
+ ld a, d
+ dec a
+ ld c, a
+ ld b, 0
+ add hl, bc
+ add hl, bc
+ ld a, BANK(TrainerGroups)
+ call GetFarHalfword
+
+.skip_trainer
+ dec e
+ jr z, .skipped
+.skip
+ ld a, BANK(Trainers)
+ call GetFarByte
+ inc hl
+ cp -1
+ jr nz, .skip
+ jr .skip_trainer
+.skipped
+
+.skip_name
+ ld a, BANK(Trainers)
+ call GetFarByte
+ inc hl
+ cp "@"
+ jr nz, .skip_name
+
+ ld a, BANK(Trainers)
+ call GetFarByte
+ inc hl
+ ld bc, 2 ; level, species
+ cp TRAINERTYPE_NORMAL
+ jr z, .got_mon_length
+ ld bc, 2 + NUM_MOVES ; level, species, moves
+ cp TRAINERTYPE_MOVES
+ jr z, .got_mon_length
+ ld bc, 2 + 1 ; level, species, item
+ cp TRAINERTYPE_ITEM
+ jr z, .got_mon_length
+ ; TRAINERTYPE_ITEM_MOVES
+ ld bc, 2 + 1 + NUM_MOVES ; level, species, item, moves
+.got_mon_length
+
+ ld e, 0
+ push hl
+.count_mon
+ inc e
+ add hl, bc
+ ld a, BANK(Trainers)
+ call GetFarByte
+ cp -1
+ jr nz, .count_mon
+ pop hl
+
+.rand
+ call Random
+ maskbits PARTY_LENGTH
+ cp e
+ jr nc, .rand
+
+ inc a
+.get_mon
+ dec a
+ jr z, .got_mon
+ add hl, bc
+ jr .get_mon
+.got_mon
+
+ inc hl ; species
+ ld a, BANK(Trainers)
+ call GetFarByte
+ ld [wNamedObjectIndexBuffer], a
+ call GetPokemonName
+ ld hl, wStringBuffer1
+ ld de, wStringBuffer4
+ ld bc, MON_NAME_LENGTH
+ jp CopyBytes
+
+INCLUDE "data/wild/johto_grass.asm"
+INCLUDE "data/wild/johto_water.asm"
+INCLUDE "data/wild/kanto_grass.asm"
+INCLUDE "data/wild/kanto_water.asm"
+INCLUDE "data/wild/swarm_grass.asm"
+INCLUDE "data/wild/swarm_water.asm"
diff --git a/engine/pack.asm b/engine/pack.asm
deleted file mode 100755
index 620976a9..00000000
--- a/engine/pack.asm
+++ /dev/null
@@ -1,1572 +0,0 @@
-Function10430:
- ld hl, wOptions
- set NO_TEXT_SCROLL, [hl]
- call Function10aba
-.asm_10438
- call JoyTextDelay
- ld a, [wce63]
- bit 7, a
- jr nz, .asm_1044a
- call Function10456
- call DelayFrame
- jr .asm_10438
-
-.asm_1044a
- ld a, [wce65]
- ld [wcfc8], a
- ld hl, wOptions
- res NO_TEXT_SCROLL, [hl]
- ret
-
-Function10456: ; 10456 (4:4456)
- ld a, [wce63]
- ld hl, .Jumptable ; $4460
- call Function10c9b
- jp hl
-
-.Jumptable
- dw Pack_InitGFX
- dw Pack_InitItemsPocket
- dw Pack_ItemsPocketMenu
- dw Pack_InitBallsPocket
- dw Pack_BallsPocketMenu
- dw Pack_InitKeyItemsPocket
- dw Pack_KeyItemsPocketMenu
- dw Pack_InitTMHMPocket
- dw Pack_TMHMPocketMenu
- dw Pack_ExitNoScript
- dw Pack_ExitRunScript
-
-Pack_InitGFX:
- xor a
- ldh [hBGMapMode], a
- call Function10d70
- ld a, [wce64]
- ld [wce63], a
- call Function10e5b
- ret
-
-Pack_InitItemsPocket:
- xor a
- ld [wce65], a
- call Function10e51
- call Function10dd6
- call Function10cca
- call Function10c96
- ret
-
-Pack_ItemsPocketMenu:
- ld hl, ItemsPocketMenuDataHeader
- call CopyMenuHeader
- ld a, [wcfca]
- ld [wMenuCursorBuffer], a
- ld a, [wcfcf]
- ld [wcfd4], a
- call ScrollingMenu
- ld a, [wcfd4]
- ld [wcfcf], a
- ld a, [wMenuCursorY]
- ld [wcfca], a
-.asm_104b7
- ld b, $7
- ld c, $3
- call Function10cef
- ret c
- call Function105f5
- ret
-
-Pack_InitKeyItemsPocket:
- ld a, $2
- ld [wce65], a
- call Function10e51
- call Function10dd6
- call Function10cca
- call Function10c96
- ret
-
-Pack_KeyItemsPocketMenu:
- ld hl, KeyItemsPocketMenuDataHeader ; $4e9a
- call CopyMenuHeader
- ld a, [wcfcb]
- ld [wMenuCursorBuffer], a
- ld a, [wcfd0]
- ld [wcfd4], a
- call ScrollingMenu
- ld a, [wcfd4]
- ld [wcfd0], a
- ld a, [wMenuCursorY]
- ld [wcfcb], a
- ld b, $3
- ld c, $7
- call Function10cef
- ret c
- call Function105f5
- ret
-
-Pack_InitTMHMPocket:
- ld a, $3
- ld [wce65], a
- call Function10e51
- call Function10dd6
- xor a
- ldh [hBGMapMode], a
- call Function10cca
- call Function10c96
- ret
-
-Pack_TMHMPocketMenu:
- farcall Pack_TMHMPocketMenu_
- ld b, $5
- ld c, $1
- call Function10cef
- ret c
- farcall _CheckTossableItem
- ld a, [wItemAttributeParamBuffer]
- and a
- jr nz, .asm_1053a
- ld hl, TMHMPocketSubmenuDataHeader_Give ; $456b
- ld de, TMHMPocketSubmenuJumptable_Give ; $4583
- jr .asm_10540
-
-.asm_1053a
- ld hl, TMHMPocketSubmenuDataHeader_NoGive ; $4554
- ld de, TMHMPocketSubmenuJumptable_NoGive ; $4567
-.asm_10540
- push de
- call LoadMenuHeader
- call VerticalMenu
- call ExitMenu
- pop hl
- ret c
- ld a, [wMenuCursorY]
- dec a
- call Function10c9b
- jp hl
-
-TMHMPocketSubmenuDataHeader_NoGive:
- db $40
- db 07, 00
- db 11, 06
- dw .MenuData2
- db 1
-
-.MenuData2:
- db $c0
- db 2
- db "USE@"
- db "QUIT@"
-
-TMHMPocketSubmenuJumptable_NoGive:
- dw UseTMorHM
- dw QuitItemSubmenu
-
-TMHMPocketSubmenuDataHeader_Give:
- db $40
- db 05, 00
- db 11, 06
- dw .MenuData2
- db 1
-
-.MenuData2:
- db $c0
- db 3
- db "USE@"
- db "GIVE@"
- db "QUIT@"
-
-TMHMPocketSubmenuJumptable_Give:
- dw UseTMorHM
- dw GiveItem
- dw QuitItemSubmenu
-
-UseTMorHM:
- farcall AskTeachTMHM
- ret c
- farcall ChooseMonToLearnTMHM
- jr c, .asm_105a9
- ld hl, wOptions
- ld a, [hl]
- push af
- res 4, [hl]
- farcall TeachTMHM
- pop af
- ld [wOptions], a
-.asm_105a9
- xor a
- ldh [hBGMapMode], a
- call Function10d70
- call Function10cca
- call Function10e5b
- ret
-
-Pack_InitBallsPocket:
- ld a, $1
- ld [wce65], a
- call Function10e51
- call Function10dd6
- call Function10cca
- call Function10c96
- ret
-
-Pack_BallsPocketMenu:
- ld hl, BallsPocketMenuDataHeader ; $4eca
- call CopyMenuHeader
- ld a, [wcfcc]
- ld [wMenuCursorBuffer], a
- ld a, [wcfd1]
- ld [wcfd4], a
- call ScrollingMenu
- ld a, [wcfd4]
- ld [wcfd1], a
- ld a, [wMenuCursorY]
- ld [wcfcc], a
- ld b, $1
- ld c, $5
- call Function10cef
- ret c
- call Function105f5
- ret
-
-Function105f5: ; 105f5 (4:45f5)
- farcall _CheckTossableItem
- ld a, [wItemAttributeParamBuffer]
- and a
- jr nz, .asm_10629
- farcall CheckSelectableItem
- ld a, [wItemAttributeParamBuffer]
- and a
- jr nz, .asm_1061b
- farcall CheckItemMenu
- ld a, [wItemAttributeParamBuffer]
- and a
- jr nz, .asm_10637
- jr .asm_10657
-
-.asm_1061b
- farcall CheckItemMenu
- ld a, [wItemAttributeParamBuffer]
- and a
- jr nz, .asm_1063f
- jr .asm_1065f
-
-.asm_10629
- farcall CheckSelectableItem
- ld a, [wItemAttributeParamBuffer]
- and a
- jr nz, .asm_10647
- jr .asm_1064f
-
-.asm_10637
- ld hl, ItemSubmenuDataHeader_UseGiveTossSelQuit ; $4679
- ld de, ItemSubmenuJumptable_UseGiveTossSelQuit ; $469a
- jr .asm_10665
-
-.asm_1063f
- ld hl, ItemSubmenuDataHeader_UseGiveTossQuit ; $46a4
- ld de, ItemSubmenuJumptable_UseGiveTossQuit ; $46c1
- jr .asm_10665
-
-.asm_10647
- ld hl, ItemSubmenuDataHeader_UseQuit ; $46c9
- ld de, ItemSubmenuJumptable_UseQuit ; $46dc
- jr .asm_10665
-
-.asm_1064f
- ld hl, ItemSubmenuDataHeader_UseSelQuit ; $46e0
- ld de, ItemSubmenuJumptable_UseSelQuit ; $46f7
- jr .asm_10665
-
-.asm_10657
- ld hl, ItemSubmenuDataHeader_GiveTossSelQuit ; $46fd
- ld de, ItemSubmenuJumptable_GiveTossSelQuit ; $471a
- jr .asm_10665
-
-.asm_1065f
- ld hl, ItemSubmenuDataHeader_GiveTossQuit ; $4722
- ld de, ItemSubmenuJumptable_GiveTossQuit ; $473b
-.asm_10665
- push de
- call LoadMenuHeader
- call VerticalMenu
- call ExitMenu
- pop hl
- ret c
- ld a, [wMenuCursorY]
- dec a
- call Function10c9b
- jp hl
-
-ItemSubmenuDataHeader_UseGiveTossSelQuit:
- db $40 ; flags
- db 02, 00 ; start coords
- db 12, 06 ; end coords
- dw .MenuData2
- db 1 ; default option
-
-.MenuData2:
- db $c0 ; flags
- db 5 ; items
- db "USE@"
- db "GIVE@"
- db "TOSS@"
- db "SEL@"
- db "QUIT@"
-
-ItemSubmenuJumptable_UseGiveTossSelQuit:
- dw UseItem
- dw GiveItem
- dw TossMenu
- dw RegisterItem
- dw QuitItemSubmenu
-
-ItemSubmenuDataHeader_UseGiveTossQuit:
- db $40 ; flags
- db 03, 00 ; start coords
- db 11, 06 ; end coords
- dw .MenuData2
- db 1 ; default option
-
-.MenuData2:
- db $c0 ; flags
- db 4 ; items
- db "USE@"
- db "GIVE@"
- db "TOSS@"
- db "QUIT@"
-
-ItemSubmenuJumptable_UseGiveTossQuit:
- dw UseItem
- dw GiveItem
- dw TossMenu
- dw QuitItemSubmenu
-
-ItemSubmenuDataHeader_UseQuit:
- db %01000000 ; flags
- db 07, 00 ; start coords
- db 11, 06 ; end coords
- dw .MenuData2
- db 1 ; default option
-
-.MenuData2:
- db $c0 ; flags
- db 2 ; items
- db "USE@"
- db "QUIT@"
-
-ItemSubmenuJumptable_UseQuit:
- dw UseItem
- dw QuitItemSubmenu
-
-ItemSubmenuDataHeader_UseSelQuit:
- db %01000000 ; flags
- db 05, 00 ; start coords
- db 11, 06 ; end coords
- dw .MenuData2
- db 1 ; default option
-
-.MenuData2:
- db $c0 ; flags
- db 3 ; items
- db "USE@"
- db "SEL@"
- db "QUIT@"
-
-ItemSubmenuJumptable_UseSelQuit:
- dw UseItem
- dw RegisterItem
- dw QuitItemSubmenu
-
-ItemSubmenuDataHeader_GiveTossSelQuit:
- db $40 ; flags
- db 03, 00 ; start coords
- db 11, 06 ; end coords
- dw .MenuData2
- db 1 ; default option
-
-.MenuData2:
- db $c0 ; flags
- db 4 ; items
- db "GIVE@"
- db "TOSS@"
- db "SEL@"
- db "QUIT@"
-
-ItemSubmenuJumptable_GiveTossSelQuit:
- dw GiveItem
- dw TossMenu
- dw RegisterItem
- dw QuitItemSubmenu
-
-ItemSubmenuDataHeader_GiveTossQuit:
- db $40 ; flags
- db 05, 00 ; start coords
- db 11, 06 ; end coords
- dw .MenuData2
- db 1 ; default option
-
-.MenuData2:
- db $c0 ; flags
- db 3 ; items
- db "GIVE@"
- db "TOSS@"
- db "QUIT@"
-
-ItemSubmenuJumptable_GiveTossQuit:
- dw GiveItem
- dw TossMenu
- dw QuitItemSubmenu
-
-UseItem:
- farcall CheckItemMenu
- ld a, [wItemAttributeParamBuffer]
- ld hl, .Jumptable
- rst JumpTable
- ret
-
-.Jumptable
- dw .NotTheTime
- dw .NotTheTime
- dw .NotTheTime
- dw .NotTheTime
- dw .Current
- dw .Party
- dw .Field
-
-.NotTheTime
- ld hl, Text_ThisIsntTheTime
- call Function10cb9
- ret
-
-.Current
- call DoItemEffect
- ret
-
-.Party
- ld a, [wPartyCount]
- and a
- jr z, .no_pokemon
- call DoItemEffect
- xor a
- ldh [hBGMapMode], a
- call Function10d70
- call Function10cca
- call Function10e5b
- ret
-
-.no_pokemon
- ld hl, Text_YouDontHaveAPokemon
- call Function10cb9
- ret
-
-.Field
- call DoItemEffect
- ld a, [wFieldMoveSucceeded]
- and a
- jr z, .NotTheTime
- ld a, $a
- ld [wce63], a
- ret
-
-TossMenu:
- ld hl, Text_ThrowAwayHowMany
- call Function10cb9
- farcall SelectQuantityToToss ; 9:4f20
- push af
- call ExitMenu
- pop af
- jr c, .asm_107cc
- call Function10e38
- ld hl, Text_ConfirmThrowAway
- call MenuTextbox
- call YesNoBox
- push af
- call ExitMenu
- pop af
- jr c, .asm_107cc
- ld hl, wTMsHMsEnd
- ld a, [wd003]
- call TossItem
- call Function10e38
- ld hl, Text_ThrewAway
- call Function10cb9
-.asm_107cc
- ret
-
-Function107cd:
- ld a, [wce65]
- and a
- jr z, .asm_107e2
- dec a
- jr z, .asm_107da
- dec a
- jr z, .asm_107ea
- ret
-
-.asm_107da
- xor a
- ld [wcfcc], a
- ld [wcfd1], a
- ret
-
-.asm_107e2
- xor a
- ld [wcfca], a
- ld [wcfcf], a
- ret
-
-.asm_107ea
- xor a
- ld [wcfcb], a
- ld [wcfd0], a
- ret
-
-RegisterItem:
- farcall CheckSelectableItem
- ld a, [wItemAttributeParamBuffer]
- and a
- jr nz, .asm_10826
- ld a, [wce65]
- rrca
- rrca
- and $c0
- ld b, a
- ld a, [wd003]
- inc a
- and $3f
- or b
- ld [wWhichRegisteredItem], a
- ld a, [wd002]
- ld [wRegisteredItem], a
- call Function10e38
- ld de, SFX_FULL_HEAL
- call WaitPlaySFX
- ld hl, Text_RegisteredTheItem
- call Function10cb9
- ret
-
-.asm_10826
- ld hl, Text_CantRegisterThatItem
- call Function10cb9
- ret
-
-GiveItem:
- ld a, [wPartyCount]
- and a
- jp z, Function108b6
- ld a, [wOptions]
- push af
- res 4, a
- ld [wOptions], a
- ld a, $8
- ld [wPartyMenuActionText], a
- call ClearBGPalettes
- farcall LoadPartyMenuGFX
- farcall InitPartyMenuWithCancel
- farcall InitPartyMenuGFX
-.asm_10857
- farcall WritePartyMenuTilemap
- farcall PrintPartyMenuText
- call WaitBGMap
- call SetPalettes
- call DelayFrame
- farcall PartyMenuSelect
- jr c, .asm_108a5
- ld a, [wCurPartySpecies]
- cp EGG
- jr nz, .asm_10883
- ld hl, Text_AnEggCantHoldAnItem
- call PrintText
- jr .asm_10857
-
-.asm_10883
- ld a, [wce63]
- push af
- ld a, [wce64]
- push af
- call GetCurNick
- ld hl, wStringBuffer1
- ld de, wMonOrItemNameBuffer
- ld bc, $b
- call CopyBytes
- call Function12fa0
- pop af
- ld [wce64], a
- pop af
- ld [wce63], a
-.asm_108a5
- pop af
- ld [wOptions], a
- xor a
- ldh [hBGMapMode], a
- call Function10d70
- call Function10cca
- call Function10e5b
- ret
-
-Function108b6: ; 108b6 (4:48b6)
- ld hl, Text_YouDontHaveAPokemon ; $4f13
- call Function10cb9
- ret
-
-Text_AnEggCantHoldAnItem:
- text_far Text_AnEGGCantHoldAnItem
- db "@"
-
-QuitItemSubmenu:
- ret
-
-BattlePack:
- ld hl, wOptions
- set 4, [hl]
- call Function10aba
-.asm_108cb
- call JoyTextDelay
- ld a, [wce63]
- bit 7, a
- jr nz, .asm_108dd
- call Function108e9
- call DelayFrame
- jr .asm_108cb
-
-.asm_108dd
- ld a, [wce65]
- ld [wcfc8], a
- ld hl, wOptions
- res 4, [hl]
- ret
-
-Function108e9: ; 108e9 (4:48e9)
- ld a, [wce63]
- ld hl, .Jumptable
- call Function10c9b
- jp hl
-
-.Jumptable
- dw BattlePack_InitGFX
- dw BattlePack_InitItemsPocket
- dw BattlePack_ItemsPocketMenu
- dw BattlePack_InitBallsPocket
- dw BattlePack_BallsPocketMenu
- dw BattlePack_InitKeyItemsPocket
- dw BattlePack_KeyItemsPocketMenu
- dw BattlePack_InitTMHMPocket
- dw BattlePack_TMHMPocketMenu
- dw Pack_ExitNoScript
- dw Pack_ExitRunScript
-
-BattlePack_InitGFX:
- xor a
- ldh [hBGMapMode], a
- call Function10d70
- ld a, [wce64]
- ld [wce63], a
- call Function10e5b
- ret
-
-BattlePack_InitItemsPocket:
- xor a
- ld [wce65], a
- call Function10e51
- call Function10dd6
- call Function10cca
- call Function10c96
- ret
-
-BattlePack_ItemsPocketMenu:
- ld hl, $4e6a
- call CopyMenuHeader
- ld a, [wcfca]
- ld [wMenuCursorBuffer], a
- ld a, [wcfcf]
- ld [wcfd4], a
- call ScrollingMenu
- ld a, [wcfd4]
- ld [wcfcf], a
- ld a, [wMenuCursorY]
- ld [wcfca], a
- ld b, $7
- ld c, $3
- call Function10cef
- ret c
- call Function10a03
- ret
-
-BattlePack_InitKeyItemsPocket:
- ld a, $2
- ld [wce65], a
- call Function10e51
- call Function10dd6
- call Function10cca
- call Function10c96
- ret
-
-BattlePack_KeyItemsPocketMenu:
- ld hl, $4e9a
- call CopyMenuHeader
- ld a, [wcfcb]
- ld [wMenuCursorBuffer], a
- ld a, [wcfd0]
- ld [wcfd4], a
- call ScrollingMenu
- ld a, [wcfd4]
- ld [wcfd0], a
- ld a, [wMenuCursorY]
- ld [wcfcb], a
- ld b, $3
- ld c, $7
- call Function10cef
- ret c
- call Function10a03
- ret
-
-BattlePack_InitTMHMPocket:
- ld a, $3
- ld [wce65], a
- call Function10e51
- call Function10dd6
- xor a
- ldh [hBGMapMode], a
- call Function10cca
- ld hl, Text_PackEmptyString
- call Function10cb9
- call Function10c96
- ret
-
-BattlePack_TMHMPocketMenu:
- farcall Pack_TMHMPocketMenu_ ; b:457a
- ld b, $5
- ld c, $1
- call Function10cef
- ret c
- xor a
- call Function10a0c
- ret
-
-BattlePack_InitBallsPocket:
- ld a, $1
- ld [wce65], a
- call Function10e51
- call Function10dd6
- call Function10cca
- call Function10c96
- ret
-
-BattlePack_BallsPocketMenu:
- ld hl, $4eca
- call CopyMenuHeader
- ld a, [wcfcc]
- ld [wMenuCursorBuffer], a
- ld a, [wcfd1]
- ld [wcfd4], a
- call ScrollingMenu
- ld a, [wcfd4]
- ld [wcfd1], a
- ld a, [wMenuCursorY]
- ld [wcfcc], a
- ld b, $1
- ld c, $5
- call Function10cef
- ret c
- call Function10a03
- ret
-
-Function10a03: ; 10a03 (4:4a03)
- farcall CheckItemContext
- ld a, [wItemAttributeParamBuffer]
-Function10a0c: ; 10a0c (4:4a0c)
- and a
- jr z, .asm_10a17
- ld hl, BattlePackUseQuitMenuDataHeader
- ld de, BattlePackUseQuitJumptable
- jr .asm_10a1d
-
-.asm_10a17
- ld hl, BattlePackQuitMenuDataHeader
- ld de, BattlePackQuitJumptable
-.asm_10a1d
- push de
- call LoadMenuHeader
- call VerticalMenu
- call ExitMenu
- pop hl
- ret c
- ld a, [wMenuCursorY]
- dec a
- call Function10c9b
- jp hl
-
-BattlePackUseQuitMenuDataHeader:
- db $40 ; flags
- db 07, 00 ; start coords
- db 11, 06 ; end coords
- dw .MenuData2
- db 1 ; default option
-
-.MenuData2:
- db $c0 ; flags
- db 2 ; items
- db "USE@"
- db "QUIT@"
-
-BattlePackUseQuitJumptable:
- dw BattlePack_UseItem
- dw BattlePack_QuitSubmenu
-
-BattlePackQuitMenuDataHeader:
- db $40 ; flags
- db 09, 00 ; start coords
- db 11, 06 ; end coords
- dw .MenuData2
- db 1 ; default option
-
-.MenuData2:
- db $c0 ; flags
- db 1 ; items
- db "QUIT@"
-
-BattlePackQuitJumptable:
- dw BattlePack_QuitSubmenu
-
-BattlePack_UseItem:
- farcall CheckItemContext
- ld a, [wItemAttributeParamBuffer]
- ld hl, $4a67
- rst JumpTable
- ret
-
- dw Function10a75
- dw Function10a75
- dw Function10a75
- dw Function10a75
- dw Function10a7c
- dw Function10a86
- dw Function10aa1
-
-Function10a75:
- ld hl, Text_ThisIsntTheTime
- call Function10cb9
- ret
-
-Function10a7c:
- call DoItemEffect
- ld a, [wFieldMoveSucceeded]
- and a
- jr nz, asm_10a9c
- ret
-
-Function10a86:
- call DoItemEffect
- ld a, [wFieldMoveSucceeded]
- and a
- jr nz, asm_10aae
- xor a
- ldh [hBGMapMode], a
- call Function10d70
- call Function10cca
- call Function10e5b
- ret
-
-asm_10a9c
- call ClearBGPalettes
- jr asm_10aae
-
-Function10aa1
- call DoItemEffect
- ld a, [wFieldMoveSucceeded]
- and a
- jr z, Function10a75
- cp $2
- jr z, asm_10ab4
-asm_10aae
- ld a, $a
- ld [wce63], a
- ret
-
-asm_10ab4
- xor a
- ld [wFieldMoveSucceeded], a
- ret
-
-BattlePack_QuitSubmenu:
- ret
-
-Function10aba: ; 10aba (4:4aba)
- xor a
- ld [wce63], a
- ld a, [wcfc8]
- and $3
- ld [wce65], a
- inc a
- add a
- dec a
- ld [wce64], a
- xor a
- ld [wce66], a
- xor a
- ld [wcfd3], a
- ret
-
-Function10ad5: ; 10ad5 (4:4ad5)
- xor a
- ldh [hBGMapMode], a
- ld [wce63], a
- ld [wce64], a
- ld [wce65], a
- ld [wce66], a
- ld [wcfd3], a
- call Function10d70
- call Function10e5b
- ret
-
-.asm_10aee
- call Function10af7
- call Function10b9f
- jr c, .asm_10aee
- ret
-
-Function10af7: ; 10af7 (4:4af7)
- ld a, [wce63]
- ld hl, .Jumptable
- call Function10c9b
- jp hl
-
-.Jumptable
- dw DepositOrSell_ItemPocket
- dw DepositOrSell_BallsPocket
- dw DepositOrSell_KeyItemsPocket
- dw DepositOrSell_TMHMPocket
-
-DepositOrSell_ItemPocket:
- xor a
- call Function10b92
- ld hl, PC_Mart_ItemsPocketMenuDataHeader ; $4e82
- call CopyMenuHeader
- ld a, [wcfca]
- ld [wMenuCursorBuffer], a
- ld a, [wcfcf]
- ld [wcfd4], a
- call ScrollingMenu
- ld a, [wcfd4]
- ld [wcfcf], a
- ld a, [wMenuCursorY]
- ld [wcfca], a
- ret
-
-DepositOrSell_KeyItemsPocket:
- ld a, $2
- call Function10b92
- ld hl, PC_Mart_KeyItemsPocketMenuDataHeader ; $4eb2
- call CopyMenuHeader
- ld a, [wcfcb]
- ld [wMenuCursorBuffer], a
- ld a, [wcfd0]
- ld [wcfd4], a
- call ScrollingMenu
- ld a, [wcfd4]
- ld [wcfd0], a
- ld a, [wMenuCursorY]
- ld [wcfcb], a
- ret
-
-DepositOrSell_TMHMPocket:
- ld a, $3
- call Function10b92
- call Function10cca
- farcall Pack_TMHMPocketMenu_ ; b:457a
- ld a, [wd002]
- ld [wd002], a
- ret
-
-DepositOrSell_BallsPocket:
- ld a, $1
- call Function10b92
- ld hl, PC_Mart_BallsPocketMenuDataHeader ; $4ee2
- call CopyMenuHeader
- ld a, [wcfcc]
- ld [wMenuCursorBuffer], a
- ld a, [wcfd1]
- ld [wcfd4], a
- call ScrollingMenu
- ld a, [wcfd4]
- ld [wcfd1], a
- ld a, [wMenuCursorY]
- ld [wcfcc], a
- ret
-
-Function10b92: ; 10b92 (4:4b92)
- ld [wce65], a
- call Function10e51
- call Function10dd6
- call Function10cca
- ret
-
-Function10b9f: ; 10b9f (4:4b9f)
- ld hl, wMenuJoypad
- ld a, [hl]
- and $1
- jr nz, .asm_10bb8
- ld a, [hl]
- and $2
- jr nz, .asm_10bbf
- ld a, [hl]
- and $20
- jr nz, .asm_10bc5
- ld a, [hl]
- and $10
- jr nz, .asm_10bd8
- scf
- ret
-
-.asm_10bb8
- ld a, $1
- ld [wce66], a
- and a
- ret
-
-.asm_10bbf
- xor a
- ld [wce66], a
- and a
- ret
-
-.asm_10bc5
- ld a, [wce63]
- dec a
- and $3
- ld [wce63], a
- push de
- ld de, $62
- call PlaySFX
- pop de
- scf
- ret
-
-.asm_10bd8
- ld a, [wce63]
- inc a
- and $3
- ld [wce63], a
- push de
- ld de, $62
- call PlaySFX
- pop de
- scf
- ret
-
-TutorialPack:
- call Function10ad5
- ld a, [wInputType]
- or a
- jr z, .asm_10bfa
- farcall DudeAutoInput_RightA ; 70:4dee
-.asm_10bfa
- call Function10c07
- call Function10b9f
- jr c, .asm_10bfa
- xor a
- ld [wce66], a
- ret
-
-Function10c07: ; 10c07 (4:4c07)
- ld a, [wce63]
- ld hl, $4c11
- call Function10c9b
- jp hl
-
-.Jumptable
- dw TutorialItems
- dw TutorialBalls
- dw TutorialKeyItems
- dw TutorialTMHM
-
-TutorialItems:
- xor a
- ld hl, TutorialItemsMenuDataHeader
- jr asm_10c8a
-
-TutorialItemsMenuDataHeader:
- db $40 ; flags
- db 01, 07 ; start coords
- db 11, 19 ; end coords
- dw .MenuData2
- db 1 ; default option
-
-.MenuData2:
- db $ae ; flags
- db 5, 8 ; rows, columns
- db 2 ; horizontal spacing
- dbw 0, wDudeNumItems
- dba PlaceMenuItemName
- dba PlaceMenuItemQuantity
- dba UpdateItemDescription
-
-TutorialKeyItems:
- ld a, $2
- ld hl, TutorialKeyItemsMenuDataHeader
- jr asm_10c8a
-
-TutorialKeyItemsMenuDataHeader:
- db $40 ; flags
- db 01, 07 ; start coords
- db 11, 19 ; end coords
- dw .MenuData2
- db 1 ; default option
-
-.MenuData2:
- db $ae ; flags
- db 5, 8 ; rows, columns
- db 1 ; horizontal spacing
- dbw 0, wDudeNumKeyItems
- dba PlaceMenuItemName
- dba PlaceMenuItemQuantity
- dba UpdateItemDescription
-
-TutorialTMHM:
- ld a, $3
- call Function10b92
- call Function10cca
- farcall Pack_TMHMPocketMenu_
- ld a, [wd002]
- ld [wd002], a
- ret
-
-TutorialBalls:
- ld a, $1
- ld hl, TutorialBallsMenuDataHeader
- jr asm_10c8a
-
-TutorialBallsMenuDataHeader:
- db $40 ; flags
- db 01, 07 ; start coords
- db 11, 19 ; end coords
- dw .MenuData2
- db 1 ; default option
-
-.MenuData2:
- db $ae ; flags
- db 5, 8 ; rows, columns
- db 2 ; horizontal spacing
- dbw 0, wDudeNumBalls
- dba PlaceMenuItemName
- dba PlaceMenuItemQuantity
- dba UpdateItemDescription
-
-asm_10c8a
- push hl
- call Function10b92
- pop hl
- call CopyMenuHeader
- call ScrollingMenu
- ret
-
-Function10c96: ; 10c96 (4:4c96)
- ld hl, wce63
- inc [hl]
- ret
-
-Function10c9b: ; 10c9b (4:4c9b)
- ld e, a
- ld d, $0
- add hl, de
- add hl, de
- ld a, [hli]
- ld h, [hl]
- ld l, a
- ret
-
-Pack_ExitNoScript:
- ld hl, wce63
- set 7, [hl]
- xor a
- ld [wce66], a
- ret
-
-Pack_ExitRunScript:
- ld hl, wce63
- set 7, [hl]
- ld a, $1
- ld [wce66], a
- ret
-
-Function10cb9: ; 10cb9 (4:4cb9)
- ld a, [wOptions]
- push af
- set 4, a
- ld [wOptions], a
- call PrintText
- pop af
- ld [wOptions], a
- ret
-
-Function10cca: ; 10cca (4:4cca)
- call WaitBGMap
-Function10ccd: ; 10ccd (4:4ccd)
- ld a, [wce65]
- and $3
- ld e, a
- ld d, $0
- ld hl, PackGFXPointers
- add hl, de
- add hl, de
- ld a, [hli]
- ld e, a
- ld d, [hl]
- ld hl, $9500
- lb bc, BANK(PackGFX), 15
- call Request2bpp
- ret
-
-PackGFXPointers:
- dw PackGFX + $f0 * 1
- dw PackGFX + $f0 * 3
- dw PackGFX + $f0 * 0
- dw PackGFX + $f0 * 2
-
-Function10cef: ; 10cef (4:4cef)
- ld hl, wMenuJoypad
- ld a, [wcfd3]
- and a
- jr nz, .asm_10d4c
- ld a, [hl]
- and $1
- jr nz, .asm_10d13
- ld a, [hl]
- and $2
- jr nz, .asm_10d15
- ld a, [hl]
- and $20
- jr nz, .asm_10d1c
- ld a, [hl]
- and $10
- jr nz, .asm_10d2d
- ld a, [hl]
- and $4
- jr nz, .asm_10d3e
- scf
- ret
-
-.asm_10d13
- and a
- ret
-
-.asm_10d15
- ld a, $9
- ld [wce63], a
- scf
- ret
-
-.asm_10d1c
- ld a, b
- ld [wce63], a
- ld [wce64], a
- push de
- ld de, SFX_SWITCH_POCKETS
- call PlaySFX
- pop de
- scf
- ret
-
-.asm_10d2d
- ld a, c
- ld [wce63], a
- ld [wce64], a
- push de
- ld de, SFX_SWITCH_POCKETS
- call PlaySFX
- pop de
- scf
- ret
-
-.asm_10d3e
- farcall SwitchItemsInBag ; 9:4834
- ld hl, Text_MoveItemWhere
- call Function10cb9
- scf
- ret
-
-.asm_10d4c
- ld a, [hl]
- and $5
- jr nz, .asm_10d58
- ld a, [hl]
- and $2
- jr nz, .asm_10d6a
- scf
- ret
-
-.asm_10d58
- farcall SwitchItemsInBag ; 9:4834
- ld de, SFX_SWITCH_POKEMON
- call WaitPlaySFX
- ld de, SFX_SWITCH_POKEMON
- call WaitPlaySFX
-.asm_10d6a
- xor a
- ld [wcfd3], a
- scf
- ret
-
-Function10d70: ; 10d70 (4:4d70)
- call ClearBGPalettes
- call ClearTilemap
- call ClearSprites
- call DisableLCD
- ld hl, PackMenuGFX
- ld de, $9000
- ld bc, $600
- ld a, BANK(PackMenuGFX)
- call FarCopyBytes ; same bank
- hlcoord 0, 1
- ld bc, 11 * SCREEN_WIDTH
- ld a, $24
- call ByteFill
- hlcoord 5, 1
- lb bc, 11, 15
- call ClearBox
- hlcoord 0, 0
- ld a, $28
- ld c, $14
-.asm_10da5
- ld [hli], a
- inc a
- dec c
- jr nz, .asm_10da5
- call Function10dd6
- call Function10dc0
- hlcoord 0, 12
- ld bc, IncGradGBPalTable_13
- call Textbox
- call EnableLCD
- call Function10ccd
- ret
-
-Function10dc0: ; 10dc0 (4:4dc0)
- hlcoord 0, 3
- ld a, $50
- ld de, $f
- ld b, $3
-.asm_10dca
- ld c, $5
-.asm_10dcc
- ld [hli], a
- inc a
- dec c
- jr nz, .asm_10dcc
- add hl, de
- dec b
- jr nz, .asm_10dca
- ret
-
-Function10dd6: ; 10dd6 (4:4dd6)
- ld a, [wce65]
- 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
-.asm_10deb
- ld b, $5
-.asm_10ded
- ld a, [de]
- inc de
- ld [hli], a
- dec b
- jr nz, .asm_10ded
- ld a, c
- ld c, $f
- add hl, bc
- ld c, a
- dec c
- jr nz, .asm_10deb
- ret
-
-.tilemap
- db $00, $04, $04, $04, $01 ; top border
- db $06, $07, $08, $09, $0a ; Items
- db $02, $05, $05, $05, $03 ; bottom border
- db $00, $04, $04, $04, $01 ; top border
- db $15, $16, $17, $18, $19 ; Balls
- db $02, $05, $05, $05, $03 ; bottom border
- db $00, $04, $04, $04, $01 ; top border
- db $0b, $0c, $0d, $0e, $0f ; Key Items
- db $02, $05, $05, $05, $03 ; bottom border
- db $00, $04, $04, $04, $01 ; top border
- db $10, $11, $12, $13, $14 ; TM/HM
- db $02, $05, $05, $05, $03 ; bottom border
-
-Function10e38: ; 10e38 (4:4e38)
- ld a, [wd002]
- ld [wd151], a
- call GetItemName
- call CopyName1
- ret
-
-Pack_ClearTilemap:
- hlcoord 0, 0
- ld bc, SCREEN_WIDTH * SCREEN_HEIGHT
- ld a, " "
- call ByteFill
- ret
-
-Function10e51: ; 10e51 (4:4e51)
- hlcoord 5, 2
- lb bc, 10, 15
- call ClearBox
- ret
-
-Function10e5b: ; 10e5b (4:4e5b)
- call WaitBGMap
- ld b, $14
- call GetSGBLayout
- call SetPalettes
- call DelayFrame
- ret
-
-ItemsPocketMenuDataHeader:
- db $40
- db 01, 07
- db 11, 19
- dw .MenuData2
- db 1
-
-.MenuData2:
- db $ae
- db 5, 8
- db 2
- dbw 0, wNumItems
- dba PlaceMenuItemName ; 9:49dc
- dba PlaceMenuItemQuantity ; 9:49eb
- dba UpdateItemDescription ; 9:43eb
-
-PC_Mart_ItemsPocketMenuDataHeader:
- db $40
- db 01, 07
- db 11, 19
- dw .MenuData2
- db 1
-
-.MenuData2:
- db $2e
- db 5, 8
- db 2
- dbw 0, wNumItems
- dba PlaceMenuItemName ; 9:49dc
- dba PlaceMenuItemQuantity ; 9:49eb
- dba UpdateItemDescription ; 9:43eb
-
-KeyItemsPocketMenuDataHeader:
- db $40
- db 01, 07
- db 11, 19
- dw .MenuData2
- db 1
-
-.MenuData2:
- db $ae
- db 5, 8
- db 1
- dbw 0, wNumKeyItems
- dba PlaceMenuItemName ; 9:49dc
- dba PlaceMenuItemQuantity ; 9:49eb
- dba UpdateItemDescription ; 9:43eb
-
-PC_Mart_KeyItemsPocketMenuDataHeader:
- db $40
- db 01, 07
- db 11, 19
- dw .MenuData2
- db 1
-
-.MenuData2:
- db $2e
- db 5, 8
- db 1
- dbw 0, wNumKeyItems
- dba PlaceMenuItemName ; 9:49dc
- dba PlaceMenuItemQuantity ; 9:49eb
- dba UpdateItemDescription ; 9:43eb
-
-BallsPocketMenuDataHeader:
- db $40
- db 01, 07
- db 11, 19
- dw .MenuData2
- db 1
-
-.MenuData2:
- db $ae
- db 5, 8
- db 2
- dbw 0, wNumBalls
- dba PlaceMenuItemName ; 9:49dc
- dba PlaceMenuItemQuantity ; 9:49eb
- dba UpdateItemDescription ; 9:43eb
-
-PC_Mart_BallsPocketMenuDataHeader:
- db $40
- db 01, 07
- db 11, 19
- dw .MenuData2
- db 1
-
-.MenuData2:
- db $2e
- db 5, 8
- db 2
- dbw 0, wNumBalls
- dba PlaceMenuItemName ; 9:49dc
- dba PlaceMenuItemQuantity ; 9:49eb
- dba UpdateItemDescription ; 9:43eb
-
-Text_PackNoItems:
- text_far Text_PackNoItems_
- db "@"
-
-Text_ThrowAwayHowMany:
- text_far Text_ThrowAwayHowMany_
- db "@"
-
-Text_ConfirmThrowAway:
- text_far Text_ConfirmThrowAway_
- db "@"
-
-Text_ThrewAway:
- text_far Text_ThrewAway_
- db "@"
-
-Text_ThisIsntTheTime:
- text_far Text_ThisIsntTheTime_
- db "@"
-
-Text_YouDontHaveAPokemon:
- text_far Text_YouDontHaveAMon
- db "@"
-
-Text_RegisteredTheItem:
- text_far Text_RegisteredTheItem_
- db "@"
-
-Text_CantRegisterThatItem:
- text_far Text_CantRegisterThatItem_
- db "@"
-
-Text_MoveItemWhere:
- text_far Text_MoveItemWhere_
- db "@"
-
-Text_PackEmptyString:
- text_far Text_PackEmptyString_
- db "@"
-
-Text_CantUseItInABattle:
- text_far Text_YouCantUseItInABattle
- db "@"
-
-PackMenuGFX: INCBIN "gfx/misc/pack_menu.2bpp"
-PackGFX: INCBIN "gfx/misc/pack.2bpp"
diff --git a/engine/phone/phone.asm b/engine/phone/phone.asm
new file mode 100644
index 00000000..7ee9d0f0
--- /dev/null
+++ b/engine/phone/phone.asm
@@ -0,0 +1,732 @@
+AddPhoneNumber::
+ call _CheckCellNum
+ jr c, .cant_add
+ call Phone_FindOpenSlot
+ jr nc, .cant_add
+ ld [hl], c
+ xor a
+ ret
+
+.cant_add
+ scf
+ ret
+
+DelCellNum::
+ call _CheckCellNum
+ jr nc, .not_in_list
+ xor a
+ ld [hl], a
+ ret
+
+.not_in_list
+ scf
+ ret
+
+CheckCellNum::
+ jp _CheckCellNum ; useless
+
+_CheckCellNum:
+ ld hl, wPhoneList
+ ld b, CONTACT_LIST_SIZE
+.loop
+ ld a, [hli]
+ cp c
+ jr z, .got_it
+ dec b
+ jr nz, .loop
+ xor a
+ ret
+
+.got_it
+ dec hl
+ scf
+ ret
+
+Phone_FindOpenSlot:
+ call GetRemainingSpaceInPhoneList
+ ld b, a
+ ld hl, wPhoneList
+.loop
+ ld a, [hli]
+ and a
+ jr z, .FoundOpenSpace
+ dec b
+ jr nz, .loop
+ xor a
+ ret
+
+.FoundOpenSpace:
+ dec hl
+ scf
+ ret
+
+GetRemainingSpaceInPhoneList:
+ xor a
+ ld [wBuffer1], a
+ ld hl, PermanentNumbers
+.loop
+ ld a, [hli]
+ cp -1
+ jr z, .done
+ cp c
+ jr z, .continue
+
+ push bc
+ push hl
+ ld c, a
+ call _CheckCellNum
+ jr c, .permanent
+ ld hl, wBuffer1
+ inc [hl]
+.permanent
+ pop hl
+ pop bc
+
+.continue
+ jr .loop
+
+.done
+ ld a, CONTACT_LIST_SIZE
+ ld hl, wBuffer1
+ sub [hl]
+ ret
+
+INCLUDE "data/phone/permanent_numbers.asm"
+
+FarPlaceString:
+ ldh a, [hROMBank]
+ push af
+ ld a, b
+ rst Bankswitch
+
+ call PlaceString
+
+ pop af
+ rst Bankswitch
+ ret
+
+CheckPhoneCall::
+; Check if the phone is ringing in the overworld.
+
+ call CheckStandingOnEntrance
+ jr z, .no_call
+
+ call .timecheck
+ nop
+ jr nc, .no_call
+
+ call Random
+ ld b, a
+ and 50 percent
+ cp b
+ jr nz, .no_call
+
+ call GetMapPhoneService
+ and a
+ jr nz, .no_call
+
+ call GetAvailableCallers
+ call ChooseRandomCaller
+ jr nc, .no_call
+
+ ld e, a
+ call LoadCallerScript
+ ld a, BANK(Script_ReceivePhoneCall)
+ ld hl, Script_ReceivePhoneCall
+ call CallScript
+ scf
+ ret
+
+.no_call
+ xor a
+ ret
+
+.timecheck
+ farcall CheckReceiveCallTimer
+ ret
+
+; unused
+ ret
+
+UnusedInitCallReceiveDelay:
+ farcall InitCallReceiveDelay
+ ret
+
+CheckPhoneContactTimeOfDay:
+ push hl
+ push bc
+ push de
+ push af
+
+ farcall CheckTime
+ pop af
+ and ANYTIME
+ and c
+
+ pop de
+ pop bc
+ pop hl
+ ret
+
+ChooseRandomCaller:
+; If no one is available to call, don't return anything.
+ ld a, [wNumAvailableCallers]
+ and a
+ jr z, .NothingToSample
+
+; Store the number of available callers in c.
+ ld c, a
+; Sample a random number between 0 and 31.
+ call Random
+ ldh a, [hRandomAdd]
+ swap a
+ and $1f
+; Compute that number modulo the number of available callers.
+ call SimpleDivide
+; Return the caller ID you just sampled.
+ ld c, a
+ ld b, 0
+ ld hl, wAvailableCallers
+ add hl, bc
+ ld a, [hl]
+ scf
+ ret
+
+.NothingToSample:
+ xor a
+ ret
+
+GetAvailableCallers:
+ farcall CheckTime
+ ld a, c
+ ld [wCheckedTime], a
+ ld hl, wNumAvailableCallers
+ ld bc, CONTACT_LIST_SIZE + 1
+ xor a
+ call ByteFill
+ ld de, wPhoneList
+ ld a, CONTACT_LIST_SIZE
+
+.loop
+ ld [wPhoneListIndex], a
+ ld a, [de]
+ and a
+ jr z, .not_good_for_call
+ ld hl, PhoneContacts + PHONE_CONTACT_SCRIPT2_TIME
+ ld bc, PHONE_CONTACT_SIZE
+ call AddNTimes
+ ld a, [wCheckedTime]
+ and [hl]
+ jr z, .not_good_for_call
+ ld bc, PHONE_CONTACT_MAP_GROUP - PHONE_CONTACT_SCRIPT2_TIME
+ add hl, bc
+ ld a, [wMapGroup]
+ cp [hl]
+ jr nz, .different_map
+ inc hl
+ ld a, [wMapNumber]
+ cp [hl]
+ jr z, .not_good_for_call
+.different_map
+ ld a, [wNumAvailableCallers]
+ ld c, a
+ ld b, $0
+ inc a
+ ld [wNumAvailableCallers], a
+ ld hl, wAvailableCallers
+ add hl, bc
+ ld a, [de]
+ ld [hl], a
+.not_good_for_call
+ inc de
+ ld a, [wPhoneListIndex]
+ dec a
+ jr nz, .loop
+ ret
+
+CheckSpecialPhoneCall::
+ ld a, [wSpecialPhoneCallID]
+ and a
+ jr z, .NoPhoneCall
+
+ dec a
+ ld c, a
+ ld b, 0
+ ld hl, SpecialPhoneCallList
+ ld a, 6
+ call AddNTimes
+ ld a, [hli]
+ ld h, [hl]
+ ld l, a
+ call _hl_
+ jr nc, .NoPhoneCall
+
+ call .DoSpecialPhoneCall
+ inc hl
+ inc hl
+ ld a, [hli]
+ ld e, a
+ push hl
+ call LoadCallerScript
+ pop hl
+ ld de, wCallerContact + PHONE_CONTACT_SCRIPT2_BANK
+ ld a, [hli]
+ ld [de], a
+ inc de
+ ld a, [hli]
+ ld [de], a
+ inc de
+ ld a, [hli]
+ ld [de], a
+ ld a, BANK(.script)
+ ld hl, .script
+ call CallScript
+ scf
+ ret
+.NoPhoneCall:
+ xor a
+ ret
+
+.script
+ pause 30
+ sjump Script_ReceivePhoneCall
+
+.DoSpecialPhoneCall:
+ ld a, [wSpecialPhoneCallID]
+ dec a
+ ld c, a
+ ld b, 0
+ ld hl, SpecialPhoneCallList
+ ld a, 6
+ call AddNTimes
+ ret
+
+SpecialCallOnlyWhenOutside:
+ ld a, [wEnvironment]
+ cp TOWN
+ jr z, .outside
+ cp ROUTE
+ jr z, .outside
+ xor a
+ ret
+
+.outside
+ scf
+ ret
+
+SpecialCallWhereverYouAre:
+ scf
+ ret
+
+Function901a1:
+ ; Don't do the call if you're in a link communication
+ ld a, [wLinkMode]
+ and a
+ jr nz, .OutOfArea
+ ; If you're in an area without phone service, don't do the call
+ call GetMapPhoneService
+ and a
+ jr nz, .OutOfArea
+ ; If the person can't take a call at that time, don't do the call
+ ld a, b
+ ld [wCurCaller], a
+ ld hl, PhoneContacts
+ ld bc, PHONE_CONTACT_SIZE
+ call AddNTimes
+ ld d, h
+ ld e, l
+ ld hl, PHONE_CONTACT_SCRIPT1_TIME
+ add hl, de
+ ld a, [hl]
+ call CheckPhoneContactTimeOfDay
+ jr z, .OutOfArea
+ ; If we're in the same map as the person we're calling,
+ ; use the "Just talk to that person" script.
+ ld hl, PHONE_CONTACT_MAP_GROUP
+ add hl, de
+ ld a, [wMapGroup]
+ cp [hl]
+ jr nz, .GetPhoneScript
+ ld hl, PHONE_CONTACT_MAP_NUMBER
+ add hl, de
+ ld a, [wMapNumber]
+ cp [hl]
+ jr nz, .GetPhoneScript
+ ld b, BANK(PhoneScript_JustTalkToThem)
+ ld hl, PhoneScript_JustTalkToThem
+ jr .DoPhoneCall
+
+.GetPhoneScript:
+ ld hl, PHONE_CONTACT_SCRIPT1_BANK
+ add hl, de
+ ld b, [hl]
+ ld hl, PHONE_CONTACT_SCRIPT1_ADDR_LO
+ add hl, de
+ ld a, [hli]
+ ld h, [hl]
+ ld l, a
+ jr .DoPhoneCall
+
+.OutOfArea:
+ ld b, BANK(LoadOutOfAreaScript)
+ ld de, LoadOutOfAreaScript
+ call ExecuteCallbackScript
+ ret
+
+.DoPhoneCall:
+ ld a, b
+ ld [wPhoneScriptBank], a
+ ld a, l
+ ld [wPhoneCaller], a
+ ld a, h
+ ld [wPhoneCaller + 1], a
+ ld b, BANK(LoadPhoneScriptBank)
+ ld de, LoadPhoneScriptBank
+ call ExecuteCallbackScript
+ ret
+
+LoadPhoneScriptBank:
+ memcall wPhoneScriptBank
+ return
+
+LoadOutOfAreaScript:
+ scall PhoneOutOfAreaScript
+ return
+
+LoadCallerScript:
+ nop
+ nop
+ ld a, e
+ ld [wCurCaller], a
+ and a
+ jr nz, .actualcaller
+ ld hl, WrongNumber
+ ld a, BANK(WrongNumber)
+ jr .proceed
+
+.actualcaller
+ ld hl, PhoneContacts
+ ld bc, PHONE_CONTACT_SIZE
+ ld a, e
+ call AddNTimes
+ ld a, BANK(PhoneContacts)
+.proceed
+ ld de, wCallerContact
+ ld bc, PHONE_CONTACT_SIZE
+ call FarCopyBytes
+ ret
+
+WrongNumber:
+ db TRAINER_NONE, PHONE_00
+ dba .script
+.script
+ writetext .PhoneWrongNumberText
+ end
+.PhoneWrongNumberText:
+ text_far _PhoneWrongNumberText
+ text_end
+
+Script_ReceivePhoneCall:
+ refreshscreen
+ callasm RingTwice_StartCall
+ memcall wCallerContact + PHONE_CONTACT_SCRIPT2_BANK
+ waitbutton
+ callasm HangUp
+ closetext
+ callasm InitCallReceiveDelay
+ end
+
+Script_SpecialBillCall::
+ callasm .LoadBillScript
+ sjump Script_ReceivePhoneCall
+
+.LoadBillScript:
+ ld e, PHONE_BILL
+ jp LoadCallerScript
+
+LoadElmCallScript:
+ callasm .LoadElmScript
+ pause 30
+ sjump Script_ReceivePhoneCall
+
+.LoadElmScript:
+ ld e, PHONE_ELM
+ jp LoadCallerScript
+
+RingTwice_StartCall:
+ call .Ring
+; fall through (rings a second time)
+.Ring:
+ call Phone_StartRinging
+ call Phone_Wait20Frames
+ call Phone_CallerTextboxWithName
+ call Phone_Wait20Frames
+ call Phone_CallerTextbox
+ call Phone_Wait20Frames
+ call Phone_CallerTextboxWithName
+ ret
+
+Phone_CallerTextboxWithName:
+ ld a, [wCurCaller]
+ ld b, a
+ call Function90357
+ ret
+
+PhoneCall::
+ ld a, b
+ ld [wPhoneScriptBank], a
+ ld a, e
+ ld [wPhoneCaller], a
+ ld a, d
+ ld [wPhoneCaller + 1], a
+ call Phone_Ring
+; fall through (rings a second time)
+Phone_Ring:
+ call Phone_StartRinging
+ call Phone_Wait20Frames
+ call Phone_CallerTextboxWithName2
+ call Phone_Wait20Frames
+ call Phone_CallerTextbox
+ call Phone_Wait20Frames
+ call Phone_CallerTextboxWithName2
+ ret
+
+Phone_CallerTextboxWithName2:
+ call Phone_CallerTextbox
+ hlcoord 1, 2
+ ld [hl], "☎"
+ inc hl
+ inc hl
+ ld a, [wPhoneScriptBank]
+ ld b, a
+ ld a, [wPhoneCaller]
+ ld e, a
+ ld a, [wPhoneCaller + 1]
+ ld d, a
+ call FarPlaceString
+ ret
+
+Phone_NoSignal:
+ ld de, SFX_NO_SIGNAL
+ call PlaySFX
+ jr Phone_CallEnd
+
+HangUp::
+ call HangUp_Beep
+ call HangUp_Wait20Frames
+Phone_CallEnd:
+ call HangUp_BoopOn
+ call HangUp_Wait20Frames
+ call HangUp_BoopOff
+ call HangUp_Wait20Frames
+ call HangUp_BoopOn
+ call HangUp_Wait20Frames
+ call HangUp_BoopOff
+ call HangUp_Wait20Frames
+ call HangUp_BoopOn
+ call HangUp_Wait20Frames
+ call HangUp_BoopOff
+ call HangUp_Wait20Frames
+ ret
+
+Function9030a:
+ ld de, SFX_SHUT_DOWN_PC
+ call PlaySFX
+ ret
+
+HangUp_Beep:
+ ld hl, PhoneClickText
+ call PrintText
+ ld de, SFX_HANG_UP
+ call PlaySFX
+ ret
+
+PhoneClickText:
+ text_far _PhoneClickText
+ text_end
+
+HangUp_BoopOn:
+ ld hl, PhoneEllipseText
+ call PrintText
+ ret
+
+PhoneEllipseText:
+ text_far _PhoneEllipseText
+ text_end
+
+HangUp_BoopOff:
+ call SpeechTextbox
+ ret
+
+Phone_StartRinging:
+ call WaitSFX
+ ld de, SFX_CALL
+ call PlaySFX
+ call Phone_CallerTextbox
+ call UpdateSprites
+ farcall PhoneRing_CopyTilemapAtOnce
+ ret
+
+HangUp_Wait20Frames:
+ jr Phone_Wait20Frames
+
+Phone_Wait20Frames:
+ ld c, 20
+ call DelayFrames
+ farcall PhoneRing_CopyTilemapAtOnce
+ ret
+
+Function90357:
+ push bc
+ call Phone_CallerTextbox
+ hlcoord 1, 1
+ ld [hl], "☎"
+ inc hl
+ inc hl
+ ld d, h
+ ld e, l
+ pop bc
+ call Function90374
+ ret
+
+Phone_CallerTextbox:
+ hlcoord 0, 0
+ ld b, 2
+ ld c, SCREEN_WIDTH - 2
+ call Textbox
+ ret
+
+Function90374:
+ ld h, d
+ ld l, e
+ ld a, b
+ call GetCallerTrainerClass
+ call GetCallerName
+ ret
+
+CheckCanDeletePhoneNumber:
+ ld a, c
+ call GetCallerTrainerClass
+ ld a, c
+ ; and a
+ ret nz
+ ld a, b
+ cp PHONECONTACT_MOM
+ ret z
+ cp PHONECONTACT_ELM
+ ret z
+ ld c, $1
+ ret
+
+GetCallerTrainerClass:
+ push hl
+ ld hl, PhoneContacts + PHONE_CONTACT_TRAINER_CLASS
+ ld bc, PHONE_CONTACT_SIZE
+ call AddNTimes
+ ld a, [hli]
+ ld b, [hl]
+ ld c, a
+ pop hl
+ ret
+
+GetCallerName:
+ ld a, c
+ and a
+ jr z, .NotTrainer
+
+ call Phone_GetTrainerName
+ push hl
+ push bc
+ call PlaceString
+ ld a, ":"
+ ld [bc], a
+ pop bc
+ pop hl
+ ld de, SCREEN_WIDTH + 3
+ add hl, de
+ call Phone_GetTrainerClassName
+ call PlaceString
+ ret
+
+.NotTrainer:
+ push hl
+ ld c, b
+ ld b, 0
+ ld hl, NonTrainerCallerNames
+ add hl, bc
+ add hl, bc
+ ld a, [hli]
+ ld e, a
+ ld d, [hl]
+ pop hl
+ call PlaceString
+ ld a, ":"
+ ld [bc], a
+ ret
+
+INCLUDE "data/phone/non_trainer_names.asm"
+
+Phone_GetTrainerName:
+ push hl
+ push bc
+ farcall GetTrainerName
+ pop bc
+ pop hl
+ ret
+
+Phone_GetTrainerClassName:
+ push hl
+ push bc
+ farcall GetTrainerClassName
+ pop bc
+ pop hl
+ ret
+
+GetCallerLocation:
+ ld a, [wCurCaller]
+ call GetCallerTrainerClass
+ ld d, c
+ ld e, b
+ push de
+ ld a, [wCurCaller]
+ ld hl, PhoneContacts + PHONE_CONTACT_MAP_GROUP
+ ld bc, PHONE_CONTACT_SIZE
+ call AddNTimes
+ ld b, [hl]
+ inc hl
+ ld c, [hl]
+ push bc
+ call GetWorldMapLocation
+ ld e, a
+ farcall GetLandmarkName
+ pop bc
+ pop de
+ ret
+
+INCLUDE "data/phone/phone_contacts.asm"
+
+INCLUDE "data/phone/special_calls.asm"
+
+PhoneOutOfAreaScript:
+ writetext PhoneOutOfAreaText
+ end
+
+PhoneOutOfAreaText:
+ text_far _PhoneOutOfAreaText
+ text_end
+
+PhoneScript_JustTalkToThem:
+ writetext PhoneJustTalkToThemText
+ end
+
+PhoneJustTalkToThemText:
+ text_far _PhoneJustTalkToThemText
+ text_end
+
+PhoneThankYouTextScript:
+ writetext PhoneThankYouText
+ end
+
+PhoneThankYouText:
+ text_far _PhoneThankYouText
+ text_end
diff --git a/engine/pokedex/pokedex_2.asm b/engine/pokedex/pokedex_2.asm
new file mode 100644
index 00000000..3d5f51b7
--- /dev/null
+++ b/engine/pokedex/pokedex_2.asm
@@ -0,0 +1,275 @@
+AnimateDexSearchSlowpoke:
+ ld hl, .FrameIDs
+ ld b, 25
+.loop
+ ld a, [hli]
+
+ ; Wrap around
+ cp $fe
+ jr nz, .ok
+ ld hl, .FrameIDs
+ ld a, [hli]
+.ok
+
+ ld [wDexSearchSlowpokeFrame], a
+ ld a, [hli]
+ ld c, a
+ push bc
+ push hl
+ call DoDexSearchSlowpokeFrame
+ pop hl
+ pop bc
+ call DelayFrames
+ dec b
+ jr nz, .loop
+ xor a
+ ld [wDexSearchSlowpokeFrame], a
+ call DoDexSearchSlowpokeFrame
+ ld c, 32
+ call DelayFrames
+ ret
+
+.FrameIDs:
+ ; frame ID, duration
+ db 0, 7
+ db 1, 7
+ db 2, 7
+ db 3, 7
+ db 4, 7
+ db -2
+
+DoDexSearchSlowpokeFrame:
+ ld a, [wDexSearchSlowpokeFrame]
+ ld hl, .SlowpokeSpriteData
+ ld de, wVirtualOAMSprite00
+.loop
+ ld a, [hli]
+ cp -1
+ ret z
+ ld [de], a ; y
+ inc de
+ ld a, [hli]
+ ld [de], a ; x
+ inc de
+ ld a, [wDexSearchSlowpokeFrame]
+ ld b, a
+ add a
+ add b
+ add [hl]
+ inc hl
+ ld [de], a ; tile id
+ inc de
+ ld a, [hli]
+ ld [de], a ; attributes
+ inc de
+ jr .loop
+
+.SlowpokeSpriteData:
+ dbsprite 9, 11, 0, 0, $00, 0
+ dbsprite 10, 11, 0, 0, $01, 0
+ dbsprite 11, 11, 0, 0, $02, 0
+ dbsprite 9, 12, 0, 0, $10, 0
+ dbsprite 10, 12, 0, 0, $11, 0
+ dbsprite 11, 12, 0, 0, $12, 0
+ dbsprite 9, 13, 0, 0, $20, 0
+ dbsprite 10, 13, 0, 0, $21, 0
+ dbsprite 11, 13, 0, 0, $22, 0
+ db -1
+
+DisplayDexEntry:
+ call GetPokemonName
+ hlcoord 9, 3
+ call PlaceString ; mon species
+ ld a, [wTempSpecies]
+ ld b, a
+ call GetDexEntryPointer
+ ld a, b
+ push af
+ hlcoord 9, 5
+ call FarString ; dex species
+ ld h, b
+ ld l, c
+ push de
+; Print dex number
+ hlcoord 2, 8
+ ld a, $5c ; No
+ ld [hli], a
+ ld a, $5d ; .
+ ld [hli], a
+ ld de, wTempSpecies
+ lb bc, PRINTNUM_LEADINGZEROS | 1, 3
+ call PrintNum
+; Check to see if we caught it. Get out of here if we haven't.
+ ld a, [wTempSpecies]
+ dec a
+ call CheckCaughtMon
+ pop hl
+ pop bc
+ ret z
+; Get the height of the Pokemon.
+ ld a, [wCurPartySpecies]
+ ld [wCurSpecies], a
+ inc hl
+ ld a, b
+ push af
+ push hl
+ call GetFarHalfword
+ ld d, l
+ ld e, h
+ pop hl
+ inc hl
+ inc hl
+ ld a, d
+ or e
+ jr z, .skip_height
+ push hl
+ push de
+; Print the height, with two of the four digits in front of the decimal point
+ ld hl, sp+$0
+ ld d, h
+ ld e, l
+ hlcoord 12, 7
+ lb bc, 2, (2 << 4) | 4
+ call PrintNum
+; Replace the decimal point with a ft symbol
+ hlcoord 14, 7
+ ld [hl], $5e
+ pop af
+ pop hl
+
+.skip_height
+ pop af
+ push af
+ inc hl
+ push hl
+ dec hl
+ call GetFarHalfword
+ ld d, l
+ ld e, h
+ ld a, e
+ or d
+ jr z, .skip_weight
+ push de
+; Print the weight, with four of the five digits in front of the decimal point
+ ld hl, sp+$0
+ ld d, h
+ ld e, l
+ hlcoord 11, 9
+ lb bc, 2, (4 << 4) | 5
+ call PrintNum
+ pop de
+
+.skip_weight
+; Page 1
+ lb bc, 5, SCREEN_WIDTH - 2
+ hlcoord 2, 11
+ call ClearBox
+ hlcoord 1, 10
+ ld bc, SCREEN_WIDTH - 1
+ ld a, $61 ; horizontal divider
+ call ByteFill
+ ; page number
+ hlcoord 1, 9
+ ld [hl], $55
+ inc hl
+ ld [hl], $55
+ hlcoord 1, 10
+ ld [hl], $56 ; P.
+ inc hl
+ ld [hl], $57 ; 1
+ pop de
+ inc de
+ pop af
+ hlcoord 2, 11
+ push af
+ call FarString
+ pop bc
+ ld a, [wPokedexStatus]
+ or a ; check for page 2
+ ret z
+
+; Page 2
+ push bc
+ push de
+ lb bc, 5, SCREEN_WIDTH - 2
+ hlcoord 2, 11
+ call ClearBox
+ hlcoord 1, 10
+ ld bc, SCREEN_WIDTH - 1
+ ld a, $61
+ call ByteFill
+ ; page number
+ hlcoord 1, 9
+ ld [hl], $55
+ inc hl
+ ld [hl], $55
+ hlcoord 1, 10
+ ld [hl], $56 ; P.
+ inc hl
+ ld [hl], $58 ; 2
+ pop de
+ inc de
+ pop af
+ hlcoord 2, 11
+ call FarString
+ ret
+
+UnreferencedPOKeString:
+; unused
+ db "#@"
+
+GetDexEntryPointer:
+; return dex entry pointer b:de
+ push hl
+ ld hl, PokedexDataPointerTable
+ ld a, b
+ dec a
+ ld d, 0
+ ld e, a
+ add hl, de
+ add hl, de
+ ld e, [hl]
+ inc hl
+ ld d, [hl]
+ rlca
+ rlca
+ and %11
+ add BANK("Pokedex Entries 001-064")
+ ld b, a
+ pop hl
+ ret
+
+GetDexEntryPagePointer:
+ call GetDexEntryPointer ; b:de
+ push hl
+ ld h, d
+ ld l, e
+; skip species name
+.loop1
+ ld a, b
+ call GetFarByte
+ inc hl
+ cp "@"
+ jr nz, .loop1
+; skip height and weight
+rept 4
+ inc hl
+endr
+; if c != 1: skip entry
+ dec c
+ jr z, .done
+; skip entry
+.loop2
+ ld a, b
+ call GetFarByte
+ inc hl
+ cp "@"
+ jr nz, .loop2
+
+.done
+ ld d, h
+ ld e, l
+ pop hl
+ ret
+
+INCLUDE "data/pokemon/dex_entry_pointers.asm"
diff --git a/engine/pokegear/pokegear.asm b/engine/pokegear/pokegear.asm
new file mode 100644
index 00000000..5443889a
--- /dev/null
+++ b/engine/pokegear/pokegear.asm
@@ -0,0 +1,2878 @@
+; Pokégear cards
+ const_def
+ const POKEGEARCARD_CLOCK ; 0
+ const POKEGEARCARD_MAP ; 1
+ const POKEGEARCARD_PHONE ; 2
+ const POKEGEARCARD_RADIO ; 3
+NUM_POKEGEAR_CARDS EQU const_value
+
+PHONE_DISPLAY_HEIGHT EQU 4
+
+; PokegearJumptable.Jumptable indexes
+ const_def
+ const POKEGEARSTATE_CLOCKINIT ; 0
+ const POKEGEARSTATE_CLOCKJOYPAD ; 1
+ const POKEGEARSTATE_MAPCHECKREGION ; 2
+ const POKEGEARSTATE_JOHTOMAPINIT ; 3
+ const POKEGEARSTATE_JOHTOMAPJOYPAD ; 4
+ const POKEGEARSTATE_KANTOMAPINIT ; 5
+ const POKEGEARSTATE_KANTOMAPJOYPAD ; 6
+ const POKEGEARSTATE_PHONEINIT ; 7
+ const POKEGEARSTATE_PHONEJOYPAD ; 8
+ const POKEGEARSTATE_MAKEPHONECALL ; 9
+ const POKEGEARSTATE_FINISHPHONECALL ; a
+ const POKEGEARSTATE_RADIOINIT ; b
+ const POKEGEARSTATE_RADIOJOYPAD ; c
+
+PokeGear:
+ ld hl, wOptions
+ ld a, [hl]
+ push af
+ set NO_TEXT_SCROLL, [hl]
+ ldh a, [hInMenu]
+ push af
+ ld a, $1
+ ldh [hInMenu], a
+ ld a, [wVramState]
+ push af
+ xor a
+ ld [wVramState], a
+ call .InitTilemap
+ call DelayFrame
+.loop
+ call UpdateTime
+ call JoyTextDelay
+ ld a, [wJumptableIndex]
+ bit 7, a
+ jr nz, .done
+ call PokegearJumptable
+ farcall PlaySpriteAnimations
+ call DelayFrame
+ jr .loop
+
+.done
+ ld de, SFX_READ_TEXT_2
+ call PlaySFX
+ call WaitSFX
+ pop af
+ ld [wVramState], a
+ pop af
+ ldh [hInMenu], a
+ pop af
+ ld [wOptions], a
+ call ClearBGPalettes
+ xor a ; LOW(vBGMap0)
+ ldh [hBGMapAddress], a
+ ld a, HIGH(vBGMap0)
+ ldh [hBGMapAddress + 1], a
+ ld a, $90
+ ldh [hWY], a
+ call ExitPokegearRadio_HandleMusic
+ ret
+
+.InitTilemap:
+ call ClearBGPalettes
+ call ClearTilemap
+ call ClearSprites
+ call DisableLCD
+ xor a
+ ldh [hSCY], a
+ ldh [hSCX], a
+ ld a, $7
+ ldh [hWX], a
+ call Pokegear_LoadGFX
+ farcall ClearSpriteAnims
+ call InitPokegearModeIndicatorArrow
+ ld a, 8
+ call SkipMusic
+ ld a, LCDC_DEFAULT
+ ldh [rLCDC], a
+ call TownMap_InitCursorAndPlayerIconPositions
+ xor a
+ ld [wJumptableIndex], a ; POKEGEARSTATE_CLOCKINIT
+ ld [wPokegearCard], a ; POKEGEARCARD_CLOCK
+ ld [wPokegearMapRegion], a ; JOHTO_REGION
+ ld [wPokegearCE66], a
+ ld [wPokegearPhoneScrollPosition], a
+ ld [wPokegearPhoneCursorPosition], a
+ ld [wPokegearPhoneSelectedPerson], a
+ ld [wPokegearRadioChannelBank], a
+ ld [wPokegearRadioChannelAddr], a
+ ld [wPokegearRadioChannelAddr + 1], a
+ call Pokegear_InitJumptableIndices
+ call InitPokegearTilemap
+ ld b, SCGB_POKEGEAR_PALS
+ call GetSGBLayout
+ call SetPalettes
+ ldh a, [hCGB]
+ and a
+ ret z
+ ld a, %11100100
+ call DmgToCgbObjPal0
+ ret
+
+Pokegear_LoadGFX:
+ call ClearVBank1
+ ld hl, TownMapGFX
+ ld de, vTiles2
+ ld a, BANK(TownMapGFX)
+ call FarDecompress
+ ld hl, PokegearGFX
+ ld de, vTiles2 tile $30
+ ld a, BANK(PokegearGFX)
+ call FarDecompress
+ ld hl, PokegearSpritesGFX
+ ld de, vTiles0
+ ld a, BANK(PokegearSpritesGFX)
+ call Decompress
+ ld a, [wMapGroup]
+ ld b, a
+ ld a, [wMapNumber]
+ ld c, a
+ call GetWorldMapLocation
+ cp LANDMARK_FAST_SHIP
+ jr z, .ssaqua
+ ld hl, ChrisSpriteGFX
+ ld de, vTiles0 tile $10
+ ld bc, 4 tiles
+ ld a, BANK(ChrisSpriteGFX)
+ call FarCopyBytes
+ ld hl, ChrisSpriteGFX + 12 tiles
+ ld de, vTiles0 tile $14
+ ld bc, 4 tiles
+ ld a, BANK(ChrisSpriteGFX)
+ call FarCopyBytes
+ ret
+
+.ssaqua
+ ld hl, FastShipGFX
+ ld de, vTiles0 tile $10
+ ld bc, 8 tiles
+ call CopyBytes
+ ret
+
+FastShipGFX:
+INCBIN "gfx/pokegear/fast_ship.2bpp"
+
+InitPokegearModeIndicatorArrow:
+ depixel 4, 2, 4, 0
+ ld a, SPRITE_ANIM_INDEX_POKEGEAR_ARROW
+ call InitSpriteAnimStruct
+ ld hl, SPRITEANIMSTRUCT_TILE_ID
+ add hl, bc
+ ld [hl], $0
+ ret
+
+AnimatePokegearModeIndicatorArrow:
+ ld hl, wPokegearCard
+ ld e, [hl]
+ ld d, 0
+ ld hl, .XCoords
+ add hl, de
+ ld a, [hl]
+ ld hl, SPRITEANIMSTRUCT_XOFFSET
+ add hl, bc
+ ld [hl], a
+ ret
+
+.XCoords:
+ db $00 ; POKEGEARCARD_CLOCK
+ db $10 ; POKEGEARCARD_MAP
+ db $20 ; POKEGEARCARD_PHONE
+ db $30 ; POKEGEARCARD_RADIO
+
+TownMap_GetCurrentLandmark:
+ ld a, [wMapGroup]
+ ld b, a
+ ld a, [wMapNumber]
+ ld c, a
+ call GetWorldMapLocation
+ cp LANDMARK_SPECIAL
+ ret nz
+ ld a, [wBackupMapGroup]
+ ld b, a
+ ld a, [wBackupMapNumber]
+ ld c, a
+ call GetWorldMapLocation
+ ret
+
+TownMap_InitCursorAndPlayerIconPositions:
+ ld a, [wMapGroup]
+ ld b, a
+ ld a, [wMapNumber]
+ ld c, a
+ call GetWorldMapLocation
+ cp LANDMARK_FAST_SHIP
+ jr z, .FastShip
+ cp LANDMARK_SPECIAL
+ jr nz, .LoadLandmark
+ ld a, [wBackupMapGroup]
+ ld b, a
+ ld a, [wBackupMapNumber]
+ ld c, a
+ call GetWorldMapLocation
+.LoadLandmark:
+ ld [wPokegearMapPlayerIconLandmark], a
+ ld [wPokegearMapCursorLandmark], a
+ ret
+
+.FastShip:
+ ld [wPokegearMapPlayerIconLandmark], a
+ ld a, LANDMARK_NEW_BARK_TOWN
+ ld [wPokegearMapCursorLandmark], a
+ ret
+
+Pokegear_InitJumptableIndices:
+ ld a, POKEGEARSTATE_CLOCKINIT
+ ld [wJumptableIndex], a
+ xor a ; POKEGEARCARD_CLOCK
+ ld [wPokegearCard], a
+ ret
+
+InitPokegearTilemap:
+ xor a
+ ldh [hBGMapMode], a
+ hlcoord 0, 0
+ ld bc, SCREEN_WIDTH * SCREEN_HEIGHT
+ ld a, $4f
+ call ByteFill
+ ld a, [wPokegearCard]
+ maskbits NUM_POKEGEAR_CARDS
+ add a
+ ld e, a
+ ld d, 0
+ ld hl, .Jumptable
+ add hl, de
+ ld a, [hli]
+ ld h, [hl]
+ ld l, a
+ ld de, .return_from_jumptable
+ push de
+ jp hl
+
+.return_from_jumptable
+ call Pokegear_FinishTilemap
+ farcall TownMapPals
+ ld a, [wPokegearMapRegion]
+ and a
+ jr nz, .kanto_0
+ xor a ; LOW(vBGMap0)
+ ldh [hBGMapAddress], a
+ ld a, HIGH(vBGMap0)
+ ldh [hBGMapAddress + 1], a
+ call .UpdateBGMap
+ ld a, $90
+ jr .finish
+
+.kanto_0
+ xor a ; LOW(vBGMap1)
+ ldh [hBGMapAddress], a
+ ld a, HIGH(vBGMap1)
+ ldh [hBGMapAddress + 1], a
+ call .UpdateBGMap
+ xor a
+.finish
+ ldh [hWY], a
+ ; swap region maps
+ ld a, [wPokegearMapRegion]
+ maskbits NUM_REGIONS
+ xor 1
+ ld [wPokegearMapRegion], a
+ ret
+
+.UpdateBGMap:
+ ldh a, [hCGB]
+ and a
+ jr z, .dmg
+ ld a, $2
+ ldh [hBGMapMode], a
+ ld c, 3
+ call DelayFrames
+.dmg
+ call WaitBGMap
+ ret
+
+.Jumptable:
+; entries correspond to POKEGEARCARD_* constants
+ dw .Clock
+ dw .Map
+ dw .Phone
+ dw .Radio
+
+.Clock:
+ ld de, ClockTilemapRLE
+ call Pokegear_LoadTilemapRLE
+ hlcoord 13, 1
+ ld de, .switch
+ call PlaceString
+ hlcoord 0, 12
+ lb bc, 4, 18
+ call Textbox
+ call Pokegear_UpdateClock
+ ret
+
+.switch
+ db "SWITCH▶@"
+
+.Map:
+ ld a, [wPokegearMapPlayerIconLandmark]
+ cp LANDMARK_FAST_SHIP
+ jr z, .johto
+ cp KANTO_LANDMARK
+ jr nc, .kanto
+.johto
+ ld e, 0
+ jr .ok
+
+.kanto
+ ld e, 1
+.ok
+ farcall PokegearMap
+ ld a, $07
+ ld bc, SCREEN_WIDTH - 2
+ hlcoord 1, 2
+ call ByteFill
+ hlcoord 0, 2
+ ld [hl], $06
+ hlcoord 19, 2
+ ld [hl], $17
+ ld a, [wPokegearMapCursorLandmark]
+ call PokegearMap_UpdateLandmarkName
+ ret
+
+.Radio:
+ ld de, RadioTilemapRLE
+ call Pokegear_LoadTilemapRLE
+ hlcoord 0, 12
+ lb bc, 4, 18
+ call Textbox
+ ret
+
+.Phone:
+ ld de, PhoneTilemapRLE
+ call Pokegear_LoadTilemapRLE
+ hlcoord 0, 12
+ lb bc, 4, 18
+ call Textbox
+ call .PlacePhoneBars
+ call PokegearPhone_UpdateDisplayList
+ ret
+
+.PlacePhoneBars:
+ hlcoord 17, 1
+ ld a, $3c
+ ld [hli], a
+ inc a
+ ld [hl], a
+ hlcoord 17, 2
+ inc a
+ ld [hli], a
+ call GetMapPhoneService
+ and a
+ ret nz
+ hlcoord 18, 2
+ ld [hl], $3f
+ ret
+
+Pokegear_FinishTilemap:
+ hlcoord 0, 0
+ ld bc, $8
+ ld a, $4f
+ call ByteFill
+ hlcoord 0, 1
+ ld bc, $8
+ ld a, $4f
+ call ByteFill
+ ld de, wPokegearFlags
+ ld a, [de]
+ bit POKEGEAR_MAP_CARD_F, a
+ call nz, .PlaceMapIcon
+ ld a, [de]
+ bit POKEGEAR_PHONE_CARD_F, a
+ call nz, .PlacePhoneIcon
+ ld a, [de]
+ bit POKEGEAR_RADIO_CARD_F, a
+ call nz, .PlaceRadioIcon
+ hlcoord 0, 0
+ ld a, $46
+ call .PlacePokegearCardIcon
+ ret
+
+.PlaceMapIcon:
+ hlcoord 2, 0
+ ld a, $40
+ jr .PlacePokegearCardIcon
+
+.PlacePhoneIcon:
+ hlcoord 4, 0
+ ld a, $44
+ jr .PlacePokegearCardIcon
+
+.PlaceRadioIcon:
+ hlcoord 6, 0
+ ld a, $42
+.PlacePokegearCardIcon:
+ ld [hli], a
+ inc a
+ ld [hld], a
+ ld bc, $14
+ add hl, bc
+ add $f
+ ld [hli], a
+ inc a
+ ld [hld], a
+ ret
+
+PokegearJumptable:
+ ld a, [wJumptableIndex]
+ ld e, a
+ ld d, 0
+ ld hl, .Jumptable
+ add hl, de
+ add hl, de
+ ld a, [hli]
+ ld h, [hl]
+ ld l, a
+ jp hl
+
+.Jumptable:
+; entries correspond to POKEGEARSTATE_* constants
+ dw PokegearClock_Init
+ dw PokegearClock_Joypad
+ dw PokegearMap_CheckRegion
+ dw PokegearMap_Init
+ dw PokegearMap_JohtoMap
+ dw PokegearMap_Init
+ dw PokegearMap_KantoMap
+ dw PokegearPhone_Init
+ dw PokegearPhone_Joypad
+ dw PokegearPhone_MakePhoneCall
+ dw PokegearPhone_FinishPhoneCall
+ dw PokegearRadio_Init
+ dw PokegearRadio_Joypad
+
+PokegearClock_Init:
+ call InitPokegearTilemap
+ ld hl, PokegearPressButtonText
+ call PrintText
+ ld hl, wJumptableIndex
+ inc [hl]
+ call ExitPokegearRadio_HandleMusic
+ ret
+
+PokegearClock_Joypad:
+ call .UpdateClock
+ ld hl, hJoyLast
+ ld a, [hl]
+ and A_BUTTON | B_BUTTON | START | SELECT
+ jr nz, .quit
+ ld a, [hl]
+ and D_RIGHT
+ ret z
+ ld a, [wPokegearFlags]
+ bit POKEGEAR_MAP_CARD_F, a
+ jr z, .no_map_card
+ ld c, POKEGEARSTATE_MAPCHECKREGION
+ ld b, POKEGEARCARD_MAP
+ jr .done
+
+.no_map_card
+ ld a, [wPokegearFlags]
+ bit POKEGEAR_PHONE_CARD_F, a
+ jr z, .no_phone_card
+ ld c, POKEGEARSTATE_PHONEINIT
+ ld b, POKEGEARCARD_PHONE
+ jr .done
+
+.no_phone_card
+ ld a, [wPokegearFlags]
+ bit POKEGEAR_RADIO_CARD_F, a
+ ret z
+ ld c, POKEGEARSTATE_RADIOINIT
+ ld b, POKEGEARCARD_RADIO
+.done
+ call Pokegear_SwitchPage
+ ret
+
+.quit
+ ld hl, wJumptableIndex
+ set 7, [hl]
+ ret
+
+.UpdateClock:
+ xor a
+ ldh [hBGMapMode], a
+ call Pokegear_UpdateClock
+ ld a, $1
+ ldh [hBGMapMode], a
+ ret
+
+Pokegear_UpdateClock:
+ hlcoord 3, 5
+ lb bc, 5, 14
+ call ClearBox
+ ldh a, [hHours]
+ ld b, a
+ ldh a, [hMinutes]
+ ld c, a
+ decoord 6, 8
+ farcall PrintHoursMins
+ ld hl, .GearTodayText
+ bccoord 6, 6
+ call PlaceHLTextAtBC
+ ret
+
+ db "ごぜん@"
+ db "ごご@"
+
+.GearTodayText:
+ text_far _GearTodayText
+ text_end
+
+PokegearMap_CheckRegion:
+ ld a, [wPokegearMapPlayerIconLandmark]
+ cp LANDMARK_FAST_SHIP
+ jr z, .johto
+ cp KANTO_LANDMARK
+ jr nc, .kanto
+.johto
+ ld a, POKEGEARSTATE_JOHTOMAPINIT
+ jr .done
+ ret
+
+.kanto
+ ld a, POKEGEARSTATE_KANTOMAPINIT
+.done
+ ld [wJumptableIndex], a
+ call ExitPokegearRadio_HandleMusic
+ ret
+
+PokegearMap_Init:
+ call InitPokegearTilemap
+ ld a, [wPokegearMapPlayerIconLandmark]
+ call PokegearMap_InitPlayerIcon
+ ld a, [wPokegearMapCursorLandmark]
+ call PokegearMap_InitCursor
+ ld a, c
+ ld [wPokegearMapCursorObjectPointer], a
+ ld a, b
+ ld [wPokegearMapCursorObjectPointer + 1], a
+ ld hl, wJumptableIndex
+ inc [hl]
+ ret
+
+PokegearMap_KantoMap:
+ call TownMap_GetKantoLandmarkLimits
+ jr PokegearMap_ContinueMap
+
+PokegearMap_JohtoMap:
+ ld d, LANDMARK_SILVER_CAVE
+ ld e, LANDMARK_NEW_BARK_TOWN
+PokegearMap_ContinueMap:
+ ld hl, hJoyLast
+ ld a, [hl]
+ and B_BUTTON
+ jr nz, .cancel
+ ld a, [hl]
+ and D_RIGHT
+ jr nz, .right
+ ld a, [hl]
+ and D_LEFT
+ jr nz, .left
+ call .DPad
+ ret
+
+.right
+ ld a, [wPokegearFlags]
+ bit POKEGEAR_PHONE_CARD_F, a
+ jr z, .no_phone
+ ld c, POKEGEARSTATE_PHONEINIT
+ ld b, POKEGEARCARD_PHONE
+ jr .done
+
+.no_phone
+ ld a, [wPokegearFlags]
+ bit POKEGEAR_RADIO_CARD_F, a
+ ret z
+ ld c, POKEGEARSTATE_RADIOINIT
+ ld b, POKEGEARCARD_RADIO
+ jr .done
+
+.left
+ ld c, POKEGEARSTATE_CLOCKINIT
+ ld b, POKEGEARCARD_CLOCK
+.done
+ call Pokegear_SwitchPage
+ ret
+
+.cancel
+ ld hl, wJumptableIndex
+ set 7, [hl]
+ ret
+
+.DPad:
+ ld hl, hJoyLast
+ ld a, [hl]
+ and D_UP
+ jr nz, .up
+ ld a, [hl]
+ and D_DOWN
+ jr nz, .down
+ ret
+
+.up
+ ld hl, wPokegearMapCursorLandmark
+ ld a, [hl]
+ cp d
+ jr c, .wrap_around_up
+ ld a, e
+ dec a
+ ld [hl], a
+.wrap_around_up
+ inc [hl]
+ jr .done_dpad
+
+.down
+ ld hl, wPokegearMapCursorLandmark
+ ld a, [hl]
+ cp e
+ jr nz, .wrap_around_down
+ ld a, d
+ inc a
+ ld [hl], a
+.wrap_around_down
+ dec [hl]
+.done_dpad
+ ld a, [wPokegearMapCursorLandmark]
+ call PokegearMap_UpdateLandmarkName
+ ld a, [wPokegearMapCursorObjectPointer]
+ ld c, a
+ ld a, [wPokegearMapCursorObjectPointer + 1]
+ ld b, a
+ ld a, [wPokegearMapCursorLandmark]
+ call PokegearMap_UpdateCursorPosition
+ ret
+
+PokegearMap_InitPlayerIcon:
+ push af
+ depixel 0, 0
+ ld a, SPRITE_ANIM_INDEX_RED_WALK
+ call InitSpriteAnimStruct
+ ld hl, SPRITEANIMSTRUCT_TILE_ID
+ add hl, bc
+ ld [hl], $10
+ pop af
+ ld e, a
+ push bc
+ farcall GetLandmarkCoords
+ pop bc
+ ld hl, SPRITEANIMSTRUCT_XCOORD
+ add hl, bc
+ ld [hl], e
+ ld hl, SPRITEANIMSTRUCT_YCOORD
+ add hl, bc
+ ld [hl], d
+ ret
+
+PokegearMap_InitCursor:
+ push af
+ depixel 0, 0
+ ld a, SPRITE_ANIM_INDEX_POKEGEAR_ARROW
+ call InitSpriteAnimStruct
+ ld hl, SPRITEANIMSTRUCT_TILE_ID
+ add hl, bc
+ ld [hl], $04
+ ld hl, SPRITEANIMSTRUCT_ANIM_SEQ_ID
+ add hl, bc
+ ld [hl], SPRITE_ANIM_SEQ_NULL
+ pop af
+ push bc
+ call PokegearMap_UpdateCursorPosition
+ pop bc
+ ret
+
+PokegearMap_UpdateLandmarkName:
+ push af
+ hlcoord 8, 0
+ lb bc, 2, 12
+ call ClearBox
+ pop af
+ ld e, a
+ push de
+ farcall GetLandmarkName
+ pop de
+ farcall TownMap_ConvertLineBreakCharacters
+ hlcoord 8, 0
+ ld [hl], $34
+ ret
+
+PokegearMap_UpdateCursorPosition:
+ push bc
+ ld e, a
+ farcall GetLandmarkCoords
+ pop bc
+ ld hl, SPRITEANIMSTRUCT_XCOORD
+ add hl, bc
+ ld [hl], e
+ ld hl, SPRITEANIMSTRUCT_YCOORD
+ add hl, bc
+ ld [hl], d
+ ret
+
+TownMap_GetKantoLandmarkLimits:
+ ld a, [wStatusFlags]
+ bit STATUSFLAGS_HALL_OF_FAME_F, a
+ jr z, .not_hof
+ ld d, LANDMARK_ROUTE_28
+ ld e, LANDMARK_PALLET_TOWN
+ ret
+
+.not_hof
+ ld d, LANDMARK_ROUTE_28
+ ld e, LANDMARK_VICTORY_ROAD
+ ret
+
+PokegearRadio_Init:
+ call InitPokegearTilemap
+ depixel 4, 10, 4, 4
+ ld a, SPRITE_ANIM_INDEX_RADIO_TUNING_KNOB
+ call InitSpriteAnimStruct
+ ld hl, SPRITEANIMSTRUCT_TILE_ID
+ add hl, bc
+ ld [hl], $08
+ call _UpdateRadioStation
+ ld hl, wJumptableIndex
+ inc [hl]
+ ret
+
+PokegearRadio_Joypad:
+ ld hl, hJoyLast
+ ld a, [hl]
+ and B_BUTTON
+ jr nz, .cancel
+ ld a, [hl]
+ and D_LEFT
+ jr nz, .left
+ ld a, [wPokegearRadioChannelAddr]
+ ld l, a
+ ld a, [wPokegearRadioChannelAddr + 1]
+ ld h, a
+ ld a, [wPokegearRadioChannelBank]
+ and a
+ ret z
+ rst FarCall
+ ret
+
+.left
+ ld a, [wPokegearFlags]
+ bit POKEGEAR_PHONE_CARD_F, a
+ jr z, .no_phone
+ ld c, POKEGEARSTATE_PHONEINIT
+ ld b, POKEGEARCARD_PHONE
+ jr .switch_page
+
+.no_phone
+ ld a, [wPokegearFlags]
+ bit POKEGEAR_MAP_CARD_F, a
+ jr z, .no_map
+ ld c, POKEGEARSTATE_MAPCHECKREGION
+ ld b, POKEGEARCARD_MAP
+ jr .switch_page
+
+.no_map
+ ld c, POKEGEARSTATE_CLOCKINIT
+ ld b, POKEGEARCARD_CLOCK
+.switch_page
+ call Pokegear_SwitchPage
+ ret
+
+.cancel
+ ld hl, wJumptableIndex
+ set 7, [hl]
+ ret
+
+PokegearPhone_Init:
+ ld hl, wJumptableIndex
+ inc [hl]
+ xor a
+ ld [wPokegearPhoneScrollPosition], a
+ ld [wPokegearPhoneCursorPosition], a
+ ld [wPokegearPhoneSelectedPerson], a
+ call InitPokegearTilemap
+ call ExitPokegearRadio_HandleMusic
+ ld hl, PokegearAskWhoCallText
+ call PrintText
+ ret
+
+PokegearPhone_Joypad:
+ ld hl, hJoyPressed
+ ld a, [hl]
+ and B_BUTTON
+ jr nz, .b
+ ld a, [hl]
+ and A_BUTTON
+ jr nz, .a
+ ld hl, hJoyLast
+ ld a, [hl]
+ and D_LEFT
+ jr nz, .left
+ ld a, [hl]
+ and D_RIGHT
+ jr nz, .right
+ call PokegearPhone_GetDPad
+ ret
+
+.left
+ ld a, [wPokegearFlags]
+ bit POKEGEAR_MAP_CARD_F, a
+ jr z, .no_map
+ ld c, POKEGEARSTATE_MAPCHECKREGION
+ ld b, POKEGEARCARD_MAP
+ jr .switch_page
+
+.no_map
+ ld c, POKEGEARSTATE_CLOCKINIT
+ ld b, POKEGEARCARD_CLOCK
+ jr .switch_page
+
+.right
+ ld a, [wPokegearFlags]
+ bit POKEGEAR_RADIO_CARD_F, a
+ ret z
+ ld c, POKEGEARSTATE_RADIOINIT
+ ld b, POKEGEARCARD_RADIO
+.switch_page
+ call Pokegear_SwitchPage
+ ret
+
+.b
+ ld hl, wJumptableIndex
+ set 7, [hl]
+ ret
+
+.a
+ ld hl, wPhoneList
+ ld a, [wPokegearPhoneScrollPosition]
+ ld e, a
+ ld d, 0
+ add hl, de
+ ld a, [wPokegearPhoneCursorPosition]
+ ld e, a
+ ld d, 0
+ add hl, de
+ ld a, [hl]
+ and a
+ ret z
+ ld [wPokegearPhoneSelectedPerson], a
+ hlcoord 1, 4
+ ld a, [wPokegearPhoneCursorPosition]
+ ld bc, SCREEN_WIDTH * 2
+ call AddNTimes
+ ld [hl], "▷"
+ call PokegearPhoneContactSubmenu
+ jr c, .quit_submenu
+ ld hl, wJumptableIndex
+ inc [hl]
+ ret
+
+.quit_submenu
+ ld a, POKEGEARSTATE_PHONEJOYPAD
+ ld [wJumptableIndex], a
+ ret
+
+PokegearPhone_MakePhoneCall:
+ call GetMapPhoneService
+ and a
+ jr nz, .no_service
+ ld hl, wOptions
+ res NO_TEXT_SCROLL, [hl]
+ xor a
+ ldh [hInMenu], a
+ ld de, SFX_CALL
+ call PlaySFX
+ ld hl, .GearEllipseText
+ call PrintText
+ call WaitSFX
+ ld de, SFX_CALL
+ call PlaySFX
+ ld hl, .GearEllipseText
+ call PrintText
+ call WaitSFX
+ ld a, [wPokegearPhoneSelectedPerson]
+ ld b, a
+ call Function901a1
+ ld c, 10
+ call DelayFrames
+ ld hl, wOptions
+ set NO_TEXT_SCROLL, [hl]
+ ld a, $1
+ ldh [hInMenu], a
+ call PokegearPhone_UpdateCursor
+ ld hl, wJumptableIndex
+ inc [hl]
+ ret
+
+.no_service
+ farcall Phone_NoSignal
+ ld hl, .GearOutOfServiceText
+ call PrintText
+ ld a, POKEGEARSTATE_PHONEJOYPAD
+ ld [wJumptableIndex], a
+ ld hl, PokegearAskWhoCallText
+ call PrintText
+ ret
+
+.GearEllipseText:
+ text_far _GearEllipseText
+ text_end
+
+.GearOutOfServiceText:
+ text_far _GearOutOfServiceText
+ text_end
+
+PokegearPhone_FinishPhoneCall:
+ ldh a, [hJoyPressed]
+ and A_BUTTON | B_BUTTON
+ ret z
+ farcall HangUp
+ ld a, POKEGEARSTATE_PHONEJOYPAD
+ ld [wJumptableIndex], a
+ ld hl, PokegearAskWhoCallText
+ call PrintText
+ ret
+
+PokegearPhone_GetDPad:
+ ld hl, hJoyLast
+ ld a, [hl]
+ and D_UP
+ jr nz, .up
+ ld a, [hl]
+ and D_DOWN
+ jr nz, .down
+ ret
+
+.up
+ ld hl, wPokegearPhoneCursorPosition
+ ld a, [hl]
+ and a
+ jr z, .scroll_page_up
+ dec [hl]
+ jr .done_joypad_same_page
+
+.scroll_page_up
+ ld hl, wPokegearPhoneScrollPosition
+ ld a, [hl]
+ and a
+ ret z
+ dec [hl]
+ jr .done_joypad_update_page
+
+.down
+ ld hl, wPokegearPhoneCursorPosition
+ ld a, [hl]
+ cp PHONE_DISPLAY_HEIGHT - 1
+ jr nc, .scroll_page_down
+ inc [hl]
+ jr .done_joypad_same_page
+
+.scroll_page_down
+ ld hl, wPokegearPhoneScrollPosition
+ ld a, [hl]
+ cp CONTACT_LIST_SIZE - PHONE_DISPLAY_HEIGHT
+ ret nc
+ inc [hl]
+ jr .done_joypad_update_page
+
+.done_joypad_same_page
+ xor a
+ ldh [hBGMapMode], a
+ call PokegearPhone_UpdateCursor
+ call WaitBGMap
+ ret
+
+.done_joypad_update_page
+ xor a
+ ldh [hBGMapMode], a
+ call PokegearPhone_UpdateDisplayList
+ call WaitBGMap
+ ret
+
+PokegearPhone_UpdateCursor:
+ ld a, " "
+x = 4
+rept PHONE_DISPLAY_HEIGHT
+ hlcoord 1, x
+ ld [hl], a
+x = x + 2
+endr
+ hlcoord 1, 4
+ ld a, [wPokegearPhoneCursorPosition]
+ ld bc, 2 * SCREEN_WIDTH
+ call AddNTimes
+ ld [hl], "▶"
+ ret
+
+PokegearPhone_UpdateDisplayList:
+ hlcoord 1, 3
+ ld b, PHONE_DISPLAY_HEIGHT * 2 + 1
+ ld a, " "
+.row
+ ld c, SCREEN_WIDTH - 2
+.col
+ ld [hli], a
+ dec c
+ jr nz, .col
+ inc hl
+ inc hl
+ dec b
+ jr nz, .row
+ ld a, [wPokegearPhoneScrollPosition]
+ ld e, a
+ ld d, 0
+ ld hl, wPhoneList
+ add hl, de
+ xor a
+ ld [wPokegearPhoneLoadNameBuffer], a
+.loop
+ ld a, [hli]
+ push hl
+ push af
+ hlcoord 2, 4
+ ld a, [wPokegearPhoneLoadNameBuffer]
+ ld bc, 2 * SCREEN_WIDTH
+ call AddNTimes
+ ld d, h
+ ld e, l
+ pop af
+ ld b, a
+ call Function90374
+ pop hl
+ ld a, [wPokegearPhoneLoadNameBuffer]
+ inc a
+ ld [wPokegearPhoneLoadNameBuffer], a
+ cp PHONE_DISPLAY_HEIGHT
+ jr c, .loop
+ call PokegearPhone_UpdateCursor
+ ret
+
+PokegearPhone_DeletePhoneNumber:
+ ld hl, wPhoneList
+ ld a, [wPokegearPhoneScrollPosition]
+ ld e, a
+ ld d, 0
+ add hl, de
+ ld a, [wPokegearPhoneCursorPosition]
+ ld e, a
+ ld d, 0
+ add hl, de
+ ld [hl], 0
+ ld hl, wPhoneList
+ ld c, CONTACT_LIST_SIZE
+.loop
+ ld a, [hli]
+ and a
+ jr nz, .skip
+ ld a, [hld]
+ ld [hli], a
+ ld [hl], 0
+.skip
+ dec c
+ jr nz, .loop
+ ret
+
+PokegearPhoneContactSubmenu:
+ ld hl, wPhoneList
+ ld a, [wPokegearPhoneScrollPosition]
+ ld e, a
+ ld d, 0
+ add hl, de
+ ld a, [wPokegearPhoneCursorPosition]
+ ld e, a
+ ld d, 0
+ add hl, de
+ ld c, [hl]
+ farcall CheckCanDeletePhoneNumber
+ ld a, c
+ and a
+ jr z, .cant_delete
+ ld hl, .CallDeleteCancelJumptable
+ ld de, .CallDeleteCancelStrings
+ jr .got_menu_data
+
+.cant_delete
+ ld hl, .CallCancelJumptable
+ ld de, .CallCancelStrings
+.got_menu_data
+ xor a
+ ldh [hBGMapMode], a
+ push hl
+ push de
+ ld a, [de]
+ ld l, a
+ inc de
+ ld a, [de]
+ ld h, a
+ inc de
+ push hl
+ bccoord -1, -2, 0
+ add hl, bc
+ ld a, [de]
+ inc de
+ sla a
+ ld b, a
+ ld c, 8
+ push de
+ call Textbox
+ pop de
+ pop hl
+ inc hl
+ call PlaceString
+ pop de
+ xor a
+ ld [wPokegearPhoneSubmenuCursor], a
+ call .UpdateCursor
+ call WaitBGMap
+.loop
+ push de
+ call JoyTextDelay
+ pop de
+ ld hl, hJoyPressed
+ ld a, [hl]
+ and D_UP
+ jr nz, .d_up
+ ld a, [hl]
+ and D_DOWN
+ jr nz, .d_down
+ ld a, [hl]
+ and A_BUTTON | B_BUTTON
+ jr nz, .a_b
+ call DelayFrame
+ jr .loop
+
+.d_up
+ ld hl, wPokegearPhoneSubmenuCursor
+ ld a, [hl]
+ and a
+ jr z, .loop
+ dec [hl]
+ call .UpdateCursor
+ jr .loop
+
+.d_down
+ ld hl, 2
+ add hl, de
+ ld a, [wPokegearPhoneSubmenuCursor]
+ inc a
+ cp [hl]
+ jr nc, .loop
+ ld [wPokegearPhoneSubmenuCursor], a
+ call .UpdateCursor
+ jr .loop
+
+.a_b
+ xor a
+ ldh [hBGMapMode], a
+ call PokegearPhone_UpdateDisplayList
+ ld a, $1
+ ldh [hBGMapMode], a
+ pop hl
+ ldh a, [hJoyPressed]
+ and B_BUTTON
+ jr nz, .Cancel
+ ld a, [wPokegearPhoneSubmenuCursor]
+ ld e, a
+ ld d, 0
+ add hl, de
+ add hl, de
+ ld a, [hli]
+ ld h, [hl]
+ ld l, a
+ jp hl
+
+.Cancel:
+ ld hl, PokegearAskWhoCallText
+ call PrintText
+ scf
+ ret
+
+.Delete:
+ ld hl, PokegearAskDeleteText
+ call MenuTextbox
+ call YesNoBox
+ call ExitMenu
+ jr c, .CancelDelete
+ call PokegearPhone_DeletePhoneNumber
+ xor a
+ ldh [hBGMapMode], a
+ call PokegearPhone_UpdateDisplayList
+ ld hl, PokegearAskWhoCallText
+ call PrintText
+ call WaitBGMap
+.CancelDelete:
+ scf
+ ret
+
+.Call:
+ and a
+ ret
+
+.UpdateCursor:
+ push de
+ ld a, [de]
+ inc de
+ ld l, a
+ ld a, [de]
+ inc de
+ ld h, a
+ ld a, [de]
+ ld c, a
+ push hl
+ ld a, " "
+ ld de, SCREEN_WIDTH * 2
+.clear_column
+ ld [hl], a
+ add hl, de
+ dec c
+ jr nz, .clear_column
+ pop hl
+ ld a, [wPokegearPhoneSubmenuCursor]
+ ld bc, SCREEN_WIDTH * 2
+ call AddNTimes
+ ld [hl], "▶"
+ pop de
+ ret
+
+.CallDeleteCancelStrings:
+ dwcoord 10, 6
+ db 3
+ db "CALL"
+ next "DELETE"
+ next "CANCEL"
+ db "@"
+
+.CallDeleteCancelJumptable:
+ dw .Call
+ dw .Delete
+ dw .Cancel
+
+.CallCancelStrings:
+ dwcoord 10, 8
+ db 2
+ db "CALL"
+ next "CANCEL"
+ db "@"
+
+.CallCancelJumptable:
+ dw .Call
+ dw .Cancel
+
+; unused
+ ldh a, [hHours]
+ cp 12
+ jr c, .am
+ sub 12
+ ld [wTempByteValue], a
+ scf
+ ret
+
+.am
+ ld [wTempByteValue], a
+ and a
+ ret
+
+Pokegear_SwitchPage:
+ ld de, SFX_READ_TEXT_2
+ call PlaySFX
+ ld a, c
+ ld [wJumptableIndex], a
+ ld a, b
+ ld [wPokegearCard], a
+ call DeleteSpriteAnimStruct2ToEnd
+ ret
+
+ExitPokegearRadio_HandleMusic:
+ ld a, [wPokegearRadioMusicPlaying]
+ cp RESTART_MAP_MUSIC
+ jr z, .restart_map_music
+ cp ENTER_MAP_MUSIC
+ call z, PlayMapMusicBike
+ xor a
+ ld [wPokegearRadioMusicPlaying], a
+ ret
+
+.restart_map_music
+ call RestartMapMusic
+ xor a
+ ld [wPokegearRadioMusicPlaying], a
+ ret
+
+DeleteSpriteAnimStruct2ToEnd:
+ ld hl, wSpriteAnim2
+ ld bc, wSpriteAnimationStructsEnd - wSpriteAnim2
+ xor a
+ call ByteFill
+ ld a, 2
+ ld [wSpriteAnimCount], a
+ ret
+
+Pokegear_LoadTilemapRLE:
+ ; Format: repeat count, tile ID
+ ; Terminated with -1
+ hlcoord 0, 0
+.loop
+ ld a, [de]
+ cp -1
+ ret z
+ ld b, a
+ inc de
+ ld a, [de]
+ ld c, a
+ inc de
+ ld a, b
+.load
+ ld [hli], a
+ dec c
+ jr nz, .load
+ jr .loop
+
+PokegearAskWhoCallText:
+ text_far _PokegearAskWhoCallText
+ text_end
+
+PokegearPressButtonText:
+ text_far _PokegearPressButtonText
+ text_end
+
+PokegearAskDeleteText:
+ text_far _PokegearAskDeleteText
+ text_end
+
+PokegearSpritesGFX:
+INCBIN "gfx/pokegear/pokegear_sprites.2bpp.lz"
+
+RadioTilemapRLE:
+INCBIN "gfx/pokegear/radio.tilemap.rle"
+PhoneTilemapRLE:
+INCBIN "gfx/pokegear/phone.tilemap.rle"
+ClockTilemapRLE:
+INCBIN "gfx/pokegear/clock.tilemap.rle"
+
+_UpdateRadioStation:
+ jr UpdateRadioStation
+
+; called from engine/sprite_anims.asm
+
+AnimateTuningKnob:
+ push bc
+ call .TuningKnob
+ pop bc
+ ld a, [wRadioTuningKnob]
+ ld hl, SPRITEANIMSTRUCT_XOFFSET
+ add hl, bc
+ ld [hl], a
+ ret
+
+.TuningKnob:
+ ld hl, hJoyLast
+ ld a, [hl]
+ and D_DOWN
+ jr nz, .down
+ ld a, [hl]
+ and D_UP
+ jr nz, .up
+ ret
+
+.down
+ ld hl, wRadioTuningKnob
+ ld a, [hl]
+ and a
+ ret z
+ dec [hl]
+ dec [hl]
+ jr .update
+
+.up
+ ld hl, wRadioTuningKnob
+ ld a, [hl]
+ cp 80
+ ret nc
+ inc [hl]
+ inc [hl]
+.update
+UpdateRadioStation:
+ ld hl, wRadioTuningKnob
+ ld d, [hl]
+ ld hl, RadioChannels
+.loop
+ ld a, [hli]
+ cp -1
+ jr z, .nostation
+ cp d
+ jr z, .foundstation
+ inc hl
+ inc hl
+ jr .loop
+
+.nostation
+ call NoRadioStation
+ ret
+
+.foundstation
+ ld a, [hli]
+ ld h, [hl]
+ ld l, a
+ ld de, .returnafterstation
+ push de
+ jp hl
+
+.returnafterstation
+ ld a, [wPokegearRadioChannelBank]
+ and a
+ ret z
+ xor a
+ ldh [hBGMapMode], a
+ hlcoord 2, 9
+ call PlaceString
+ ld a, $1
+ ldh [hBGMapMode], a
+ ret
+
+; unused
+ ld [wPokegearRadioChannelBank], a
+ ld a, [hli]
+ ld [wPokegearRadioChannelAddr], a
+ ld a, [hli]
+ ld [wPokegearRadioChannelAddr + 1], a
+ ret
+
+RadioChannels:
+; entries correspond to constants/radio_constants.asm
+
+; frequency value given here = 4 × ingame_frequency − 2
+ dbw 16, .PKMNTalkAndPokedexShow ; 04.5
+ dbw 28, .PokemonMusic ; 07.5
+ dbw 32, .LuckyChannel ; 08.5
+ dbw 52, .RuinsOfAlphRadio ; 13.5
+ dbw 64, .PlacesAndPeople ; 16.5
+ dbw 72, .LetsAllSing ; 18.5
+ dbw 78, .PokeFluteRadio ; 20.0
+ dbw 80, .EvolutionRadio ; 20.5
+ db -1
+
+.PKMNTalkAndPokedexShow:
+; Pokédex Show in the morning
+
+; Oak's Pokémon Talk in the afternoon and evening
+ call .InJohto
+ jr nc, .NoSignal
+ ld a, [wTimeOfDay]
+ and a
+ jp z, LoadStation_PokedexShow
+ jp LoadStation_OaksPokemonTalk
+
+.PokemonMusic:
+ call .InJohto
+ jr nc, .NoSignal
+ jp LoadStation_PokemonMusic
+
+.LuckyChannel:
+ call .InJohto
+ jr nc, .NoSignal
+ jp LoadStation_LuckyChannel
+
+.RuinsOfAlphRadio:
+ ld a, [wPokegearMapPlayerIconLandmark]
+ cp LANDMARK_RUINS_OF_ALPH
+ jr nz, .NoSignal
+ jp LoadStation_UnownRadio
+
+.PlacesAndPeople:
+ call .InJohto
+ jr c, .NoSignal
+ jp LoadStation_PlacesAndPeople
+
+.LetsAllSing:
+ call .InJohto
+ jr c, .NoSignal
+ jp LoadStation_LetsAllSing
+
+.PokeFluteRadio:
+ call .InJohto
+ jr c, .NoSignal
+ ld a, [wPokegearFlags]
+ bit POKEGEAR_EXPN_CARD_F, a
+ jr z, .NoSignal
+ jp LoadStation_PokeFluteRadio
+
+.EvolutionRadio:
+; This station airs in the Lake of Rage area when Team Rocket is still in Mahogany.
+ ld a, [wStatusFlags]
+ bit STATUSFLAGS_ROCKET_SIGNAL_F, a
+ jr z, .NoSignal
+ ld a, [wPokegearMapPlayerIconLandmark]
+ cp LANDMARK_MAHOGANY_TOWN
+ jr z, .ok
+ cp LANDMARK_ROUTE_43
+ jr z, .ok
+ cp LANDMARK_LAKE_OF_RAGE
+ jr nz, .NoSignal
+.ok
+ jp LoadStation_EvolutionRadio
+
+.NoSignal:
+ call NoRadioStation
+ ret
+
+.InJohto:
+; if in Johto or on the S.S. Aqua, set carry
+
+; otherwise clear carry
+ ld a, [wPokegearMapPlayerIconLandmark]
+ cp LANDMARK_FAST_SHIP
+ jr z, .johto
+ cp KANTO_LANDMARK
+ jr c, .johto
+.kanto
+ and a
+ ret
+
+.johto
+ scf
+ ret
+
+LoadStation_OaksPokemonTalk:
+ xor a ; OAKS_POKEMON_TALK
+ ld [wCurRadioLine], a
+ ld [wNumRadioLinesPrinted], a
+ ld a, BANK(PlayRadioShow)
+ ld hl, PlayRadioShow
+ call Radio_BackUpFarCallParams
+ ld de, OaksPKMNTalkName
+ ret
+
+LoadStation_PokedexShow:
+ ld a, POKEDEX_SHOW
+ ld [wCurRadioLine], a
+ xor a
+ ld [wNumRadioLinesPrinted], a
+ ld a, BANK(PlayRadioShow)
+ ld hl, PlayRadioShow
+ call Radio_BackUpFarCallParams
+ ld de, PokedexShowName
+ ret
+
+LoadStation_PokemonMusic:
+ ld a, POKEMON_MUSIC
+ ld [wCurRadioLine], a
+ xor a
+ ld [wNumRadioLinesPrinted], a
+ ld a, BANK(PlayRadioShow)
+ ld hl, PlayRadioShow
+ call Radio_BackUpFarCallParams
+ ld de, PokemonMusicName
+ ret
+
+LoadStation_LuckyChannel:
+ ld a, LUCKY_CHANNEL
+ ld [wCurRadioLine], a
+ xor a
+ ld [wNumRadioLinesPrinted], a
+ ld a, BANK(PlayRadioShow)
+ ld hl, PlayRadioShow
+ call Radio_BackUpFarCallParams
+ ld de, LuckyChannelName
+ ret
+
+LoadStation_UnownRadio:
+ ld a, UNOWN_RADIO
+ ld [wCurRadioLine], a
+ xor a
+ ld [wNumRadioLinesPrinted], a
+ ld a, BANK(PlayRadioShow)
+ ld hl, PlayRadioShow
+ call Radio_BackUpFarCallParams
+ ld de, UnownStationName
+ ret
+
+LoadStation_PlacesAndPeople:
+ ld a, PLACES_AND_PEOPLE
+ ld [wCurRadioLine], a
+ xor a
+ ld [wNumRadioLinesPrinted], a
+ ld a, BANK(PlayRadioShow)
+ ld hl, PlayRadioShow
+ call Radio_BackUpFarCallParams
+ ld de, PlacesAndPeopleName
+ ret
+
+LoadStation_LetsAllSing:
+ ld a, LETS_ALL_SING
+ ld [wCurRadioLine], a
+ xor a
+ ld [wNumRadioLinesPrinted], a
+ ld a, BANK(PlayRadioShow)
+ ld hl, PlayRadioShow
+ call Radio_BackUpFarCallParams
+ ld de, LetsAllSingName
+ ret
+
+LoadStation_RocketRadio:
+ ld a, ROCKET_RADIO
+ ld [wCurRadioLine], a
+ xor a
+ ld [wNumRadioLinesPrinted], a
+ ld a, BANK(PlayRadioShow)
+ ld hl, PlayRadioShow
+ call Radio_BackUpFarCallParams
+ ld de, LetsAllSingName
+ ret
+
+LoadStation_PokeFluteRadio:
+ ld a, POKE_FLUTE_RADIO
+ ld [wCurRadioLine], a
+ xor a
+ ld [wNumRadioLinesPrinted], a
+ ld a, BANK(PlayRadioShow)
+ ld hl, PlayRadioShow
+ call Radio_BackUpFarCallParams
+ ld de, PokeFluteStationName
+ ret
+
+LoadStation_EvolutionRadio:
+ ld a, EVOLUTION_RADIO
+ ld [wCurRadioLine], a
+ xor a
+ ld [wNumRadioLinesPrinted], a
+ ld a, BANK(PlayRadioShow)
+ ld hl, PlayRadioShow
+ call Radio_BackUpFarCallParams
+ ld de, UnownStationName
+ ret
+
+Unreferenced_LoadStation:
+ ret
+
+RadioMusicRestartDE:
+ push de
+ ld a, e
+ ld [wPokegearRadioMusicPlaying], a
+ ld de, MUSIC_NONE
+ call PlayMusic
+ pop de
+ ld a, e
+ ld [wMapMusic], a
+ call PlayMusic
+ ret
+
+RadioMusicRestartPokemonChannel:
+ push de
+ ld a, RESTART_MAP_MUSIC
+ ld [wPokegearRadioMusicPlaying], a
+ ld de, MUSIC_NONE
+ call PlayMusic
+ pop de
+ ld de, MUSIC_POKEMON_CHANNEL
+ call PlayMusic
+ ret
+
+Radio_BackUpFarCallParams:
+ ld [wPokegearRadioChannelBank], a
+ ld a, l
+ ld [wPokegearRadioChannelAddr], a
+ ld a, h
+ ld [wPokegearRadioChannelAddr + 1], a
+ ret
+
+NoRadioStation:
+; no radio music
+ ld de, MUSIC_NONE
+ call PlayMusic
+ ld a, ENTER_MAP_MUSIC
+ ld [wPokegearRadioMusicPlaying], a
+; no radio name
+ xor a
+ ldh [hBGMapMode], a
+ hlcoord 1, 8
+ lb bc, 3, 18
+ call ClearBox
+ hlcoord 0, 12
+ lb bc, 4, 18
+ call Textbox
+; no radio channel
+ xor a
+ ld [wPokegearRadioChannelBank], a
+ ld [wPokegearRadioChannelAddr], a
+ ld [wPokegearRadioChannelAddr + 1], a
+ ld a, $1
+ ldh [hBGMapMode], a
+ ret
+
+OaksPKMNTalkName: db "OAK's <PK><MN> Talk@"
+PokedexShowName: db "#DEX Show@"
+PokemonMusicName: db "#MON Music@"
+LuckyChannelName: db "Lucky Channel@"
+UnownStationName: db "?????@"
+
+PlacesAndPeopleName: db "Places & People@"
+LetsAllSingName: db "Let's All Sing!@"
+PokeFluteStationName: db "# FLUTE@"
+
+_TownMap:
+ ld hl, wOptions
+ ld a, [hl]
+ push af
+ set NO_TEXT_SCROLL, [hl]
+
+ ldh a, [hInMenu]
+ push af
+ ld a, $1
+ ldh [hInMenu], a
+
+ ld a, [wVramState]
+ push af
+ xor a
+ ld [wVramState], a
+
+ call ClearBGPalettes
+ call ClearTilemap
+ call ClearSprites
+ call DisableLCD
+ call Pokegear_LoadGFX
+ farcall ClearSpriteAnims
+ ld a, 8
+ call SkipMusic
+ ld a, LCDC_DEFAULT
+ ldh [rLCDC], a
+ call TownMap_GetCurrentLandmark
+ ld [wTownMapPlayerIconLandmark], a
+ ld [wTownMapCursorLandmark], a
+ xor a
+ ldh [hBGMapMode], a
+ call .InitTilemap
+ call WaitBGMap2
+ ld a, [wTownMapPlayerIconLandmark]
+ call PokegearMap_InitPlayerIcon
+ ld a, [wTownMapCursorLandmark]
+ call PokegearMap_InitCursor
+ ld a, c
+ ld [wTownMapCursorObjectPointer], a
+ ld a, b
+ ld [wTownMapCursorObjectPointer + 1], a
+ ld b, SCGB_POKEGEAR_PALS
+ call GetSGBLayout
+ call SetPalettes
+ ldh a, [hCGB]
+ and a
+ jr z, .dmg
+ ld a, %11100100
+ call DmgToCgbObjPal0
+ call DelayFrame
+
+.dmg
+ ld a, [wTownMapPlayerIconLandmark]
+ cp KANTO_LANDMARK
+ jr nc, .kanto
+ ld d, KANTO_LANDMARK - 1
+ ld e, 1
+ call .loop
+ jr .resume
+
+.kanto
+ call TownMap_GetKantoLandmarkLimits
+ call .loop
+
+.resume
+ pop af
+ ld [wVramState], a
+ pop af
+ ldh [hInMenu], a
+ pop af
+ ld [wOptions], a
+ call ClearBGPalettes
+ ret
+
+.loop
+ call JoyTextDelay
+ ld hl, hJoyPressed
+ ld a, [hl]
+ and B_BUTTON
+ ret nz
+
+ ld hl, hJoyLast
+ ld a, [hl]
+ and D_UP
+ jr nz, .pressed_up
+
+ ld a, [hl]
+ and D_DOWN
+ jr nz, .pressed_down
+.loop2
+ push de
+ farcall PlaySpriteAnimations
+ pop de
+ call DelayFrame
+ jr .loop
+
+.pressed_up
+ ld hl, wTownMapCursorLandmark
+ ld a, [hl]
+ cp d
+ jr c, .okay
+ ld a, e
+ dec a
+ ld [hl], a
+
+.okay
+ inc [hl]
+ jr .next
+
+.pressed_down
+ ld hl, wTownMapCursorLandmark
+ ld a, [hl]
+ cp e
+ jr nz, .okay2
+ ld a, d
+ inc a
+ ld [hl], a
+
+.okay2
+ dec [hl]
+
+.next
+ push de
+ ld a, [wTownMapCursorLandmark]
+ call PokegearMap_UpdateLandmarkName
+ ld a, [wTownMapCursorObjectPointer]
+ ld c, a
+ ld a, [wTownMapCursorObjectPointer + 1]
+ ld b, a
+ ld a, [wTownMapCursorLandmark]
+ call PokegearMap_UpdateCursorPosition
+ pop de
+ jr .loop2
+
+.InitTilemap:
+ ld a, [wTownMapPlayerIconLandmark]
+ cp KANTO_LANDMARK
+ jr nc, .kanto2
+ ld e, JOHTO_REGION
+ jr .okay_tilemap
+
+.kanto2
+ ld e, KANTO_REGION
+.okay_tilemap
+ farcall PokegearMap
+ ld a, $07
+ ld bc, 6
+ hlcoord 1, 0
+ call ByteFill
+ hlcoord 0, 0
+ ld [hl], $06
+ hlcoord 7, 0
+ ld [hl], $17
+ hlcoord 7, 1
+ ld [hl], $16
+ hlcoord 7, 2
+ ld [hl], $26
+ ld a, $07
+ ld bc, NAME_LENGTH
+ hlcoord 8, 2
+ call ByteFill
+ hlcoord 19, 2
+ ld [hl], $17
+ ld a, [wTownMapCursorLandmark]
+ call PokegearMap_UpdateLandmarkName
+ farcall TownMapPals
+ ret
+
+PlayRadio:
+ ld hl, wOptions
+ ld a, [hl]
+ push af
+ set NO_TEXT_SCROLL, [hl]
+ call .PlayStation
+ ld c, 100
+ call DelayFrames
+.loop
+ call JoyTextDelay
+ ldh a, [hJoyPressed]
+ and A_BUTTON | B_BUTTON
+ jr nz, .stop
+ ld a, [wPokegearRadioChannelAddr]
+ ld l, a
+ ld a, [wPokegearRadioChannelAddr + 1]
+ ld h, a
+ ld a, [wPokegearRadioChannelBank]
+ and a
+ jr z, .zero
+ rst FarCall
+.zero
+ call DelayFrame
+ jr .loop
+
+.stop
+ pop af
+ ld [wOptions], a
+ call ExitPokegearRadio_HandleMusic
+ ret
+
+.PlayStation:
+ ld a, ENTER_MAP_MUSIC
+ ld [wPokegearRadioMusicPlaying], a
+ ld hl, .StationPointers
+ ld d, 0
+ add hl, de
+ add hl, de
+ ld a, [hli]
+ ld h, [hl]
+ ld l, a
+ ld de, .jump_return
+ push de
+ jp hl
+
+.jump_return
+ push de
+ hlcoord 0, 12
+ lb bc, 4, 18
+ call Textbox
+ hlcoord 1, 14
+ ld [hl], "“"
+ pop de
+ hlcoord 2, 14
+ call PlaceString
+ ld h, b
+ ld l, c
+ ld [hl], "”"
+ call WaitBGMap
+ ret
+
+.StationPointers:
+; entries correspond to MAPRADIO_* constants
+ dw .OakOrPnP
+ dw LoadStation_OaksPokemonTalk
+ dw LoadStation_PokedexShow
+ dw LoadStation_PokemonMusic
+ dw LoadStation_LuckyChannel
+ dw LoadStation_UnownRadio
+ dw LoadStation_PlacesAndPeople
+ dw LoadStation_LetsAllSing
+ dw LoadStation_RocketRadio
+
+.OakOrPnP:
+ call IsInJohto
+ and a
+ jr nz, .kanto
+ call UpdateTime
+ ld a, [wTimeOfDay]
+ and a
+ jp z, LoadStation_PokedexShow
+ jp LoadStation_OaksPokemonTalk
+
+.kanto
+ jp LoadStation_PlacesAndPeople
+
+PokegearMap:
+ ld a, e
+ and a
+ jr nz, .kanto
+ call LoadTownMapGFX
+ call FillJohtoMap
+ ret
+
+.kanto
+ call LoadTownMapGFX
+ call FillKantoMap
+ ret
+
+_FlyMap:
+ call ClearBGPalettes
+ call ClearTilemap
+ call ClearSprites
+ ld hl, hInMenu
+ ld a, [hl]
+ push af
+ ld [hl], $1
+ xor a
+ ldh [hBGMapMode], a
+ farcall ClearSpriteAnims
+ call LoadTownMapGFX
+ ld de, FlyMapLabelBorderGFX
+ ld hl, vTiles2 tile $30
+ lb bc, BANK(FlyMapLabelBorderGFX), 6
+ call Request1bpp
+ call FlyMap
+ call ret_91bfd
+ ld b, SCGB_POKEGEAR_PALS
+ call GetSGBLayout
+ call SetPalettes
+.loop
+ call JoyTextDelay
+ ld hl, hJoyPressed
+ ld a, [hl]
+ and B_BUTTON
+ jr nz, .pressedB
+ ld a, [hl]
+ and A_BUTTON
+ jr nz, .pressedA
+ call FlyMapScroll
+ call GetMapCursorCoordinates
+ farcall PlaySpriteAnimations
+ call DelayFrame
+ jr .loop
+
+.pressedB
+ ld a, -1
+ jr .exit
+
+.pressedA
+ ld a, [wTownMapPlayerIconLandmark]
+ ld l, a
+ ld h, 0
+ add hl, hl
+ ld de, Flypoints + 1
+ add hl, de
+ ld a, [hl]
+.exit
+ ld [wTownMapPlayerIconLandmark], a
+ pop af
+ ldh [hInMenu], a
+ call ClearBGPalettes
+ ld a, $90
+ ldh [hWY], a
+ xor a ; LOW(vBGMap0)
+ ldh [hBGMapAddress], a
+ ld a, HIGH(vBGMap0)
+ ldh [hBGMapAddress + 1], a
+ ld a, [wTownMapPlayerIconLandmark]
+ ld e, a
+ ret
+
+FlyMapScroll:
+ ld a, [wStartFlypoint]
+ ld e, a
+ ld a, [wEndFlypoint]
+ ld d, a
+ ld hl, hJoyLast
+ ld a, [hl]
+ and D_UP
+ jr nz, .ScrollNext
+ ld a, [hl]
+ and D_DOWN
+ jr nz, .ScrollPrev
+ ret
+
+.ScrollNext:
+ ld hl, wTownMapPlayerIconLandmark
+ ld a, [hl]
+ cp d
+ jr nz, .NotAtEndYet
+ ld a, e
+ dec a
+ ld [hl], a
+.NotAtEndYet:
+ inc [hl]
+ call CheckIfVisitedFlypoint
+ jr z, .ScrollNext
+ jr .Finally
+
+.ScrollPrev:
+ ld hl, wTownMapPlayerIconLandmark
+ ld a, [hl]
+ cp e
+ jr nz, .NotAtStartYet
+ ld a, d
+ inc a
+ ld [hl], a
+.NotAtStartYet:
+ dec [hl]
+ call CheckIfVisitedFlypoint
+ jr z, .ScrollPrev
+.Finally:
+ call TownMapBubble
+ call WaitBGMap
+ xor a
+ ldh [hBGMapMode], a
+ ret
+
+TownMapBubble:
+; Draw the bubble containing the location text in the town map HUD
+
+; Top-left corner
+ hlcoord 1, 0
+ ld a, $30
+ ld [hli], a
+; Top row
+ ld bc, 16
+ ld a, " "
+ call ByteFill
+; Top-right corner
+ ld a, $31
+ ld [hl], a
+ hlcoord 1, 1
+
+; Middle row
+ ld bc, SCREEN_WIDTH - 2
+ ld a, " "
+ call ByteFill
+
+; Bottom-left corner
+ hlcoord 1, 2
+ ld a, $32
+ ld [hli], a
+; Bottom row
+ ld bc, 16
+ ld a, " "
+ call ByteFill
+; Bottom-right corner
+ ld a, $33
+ ld [hl], a
+
+; Print "Where?"
+ hlcoord 2, 0
+ ld de, .Where
+ call PlaceString
+; Print the name of the default flypoint
+ call .Name
+; Up/down arrows
+ hlcoord 18, 1
+ ld [hl], $34
+ ret
+
+.Where:
+ db "Where?@"
+
+.Name:
+; We need the map location of the default flypoint
+ ld a, [wTownMapPlayerIconLandmark]
+ ld l, a
+ ld h, 0
+ add hl, hl ; two bytes per flypoint
+ ld de, Flypoints
+ add hl, de
+ ld e, [hl]
+ farcall GetLandmarkName
+ hlcoord 2, 1
+ ld de, wStringBuffer1
+ call PlaceString
+ ret
+
+GetMapCursorCoordinates:
+ ld a, [wTownMapPlayerIconLandmark]
+ ld l, a
+ ld h, 0
+ add hl, hl
+ ld de, Flypoints
+ add hl, de
+ ld e, [hl]
+ farcall GetLandmarkCoords
+ ld a, [wTownMapCursorCoordinates]
+ ld c, a
+ ld a, [wTownMapCursorCoordinates + 1]
+ ld b, a
+ ld hl, 4
+ add hl, bc
+ ld [hl], e
+ ld hl, 5
+ add hl, bc
+ ld [hl], d
+ ret
+
+CheckIfVisitedFlypoint:
+; Check if the flypoint loaded in [hl] has been visited yet.
+ push bc
+ push de
+ push hl
+ ld l, [hl]
+ ld h, 0
+ add hl, hl
+ ld de, Flypoints + 1
+ add hl, de
+ ld c, [hl]
+ call HasVisitedSpawn
+ pop hl
+ pop de
+ pop bc
+ and a
+ ret
+
+HasVisitedSpawn:
+; Check if spawn point c has been visited.
+ ld hl, wVisitedSpawns
+ ld b, CHECK_FLAG
+ ld d, 0
+ predef SmallFarFlagAction
+ ld a, c
+ ret
+
+INCLUDE "data/maps/flypoints.asm"
+
+ret_91bfd:
+ ret
+
+FlyMap:
+ ld a, [wMapGroup]
+ ld b, a
+ ld a, [wMapNumber]
+ ld c, a
+ call GetWorldMapLocation
+; If we're not in a valid location, i.e. Pokecenter floor 2F,
+; the backup map information is used.
+ cp LANDMARK_SPECIAL
+ jr nz, .CheckRegion
+ ld a, [wBackupMapGroup]
+ ld b, a
+ ld a, [wBackupMapNumber]
+ ld c, a
+ call GetWorldMapLocation
+.CheckRegion:
+; The first 46 locations are part of Johto. The rest are in Kanto.
+ cp KANTO_LANDMARK
+ jr nc, .KantoFlyMap
+.JohtoFlyMap:
+; Note that .NoKanto should be modified in tandem with this branch
+ push af
+; Start from New Bark Town
+ ld a, FLY_NEW_BARK
+ ld [wTownMapPlayerIconLandmark], a
+; Flypoints begin at New Bark Town...
+ ld [wStartFlypoint], a
+; ..and end at Silver Cave.
+ ld a, FLY_MT_SILVER
+ ld [wEndFlypoint], a
+; Fill out the map
+ call FillJohtoMap
+ call .MapHud
+ pop af
+ call TownMapPlayerIcon
+ ret
+
+.KantoFlyMap:
+; The event that there are no flypoints enabled in a map is not
+; accounted for. As a result, if you attempt to select a flypoint
+; when there are none enabled, the game will crash. Additionally,
+; the flypoint selection has a default starting point that
+; can be flown to even if none are enabled.
+; To prevent both of these things from happening when the player
+; enters Kanto, fly access is restricted until Indigo Plateau is
+; visited and its flypoint enabled.
+ push af
+ ld c, SPAWN_INDIGO
+ call HasVisitedSpawn
+ and a
+ jr z, .NoKanto
+; Kanto's map is only loaded if we've visited Indigo Plateau
+
+; Flypoints begin at Pallet Town...
+ ld a, FLY_PALLET
+ ld [wStartFlypoint], a
+; ...and end at Indigo Plateau
+ ld a, FLY_INDIGO
+ ld [wEndFlypoint], a
+; Because Indigo Plateau is the first flypoint the player
+; visits, it's made the default flypoint.
+ ld [wTownMapPlayerIconLandmark], a
+; Fill out the map
+ call FillKantoMap
+ call .MapHud
+ pop af
+ call TownMapPlayerIcon
+ ret
+
+.NoKanto:
+; If Indigo Plateau hasn't been visited, we use Johto's map instead
+
+; Start from New Bark Town
+ ld a, FLY_NEW_BARK
+ ld [wTownMapPlayerIconLandmark], a
+; Flypoints begin at New Bark Town...
+ ld [wStartFlypoint], a
+; ..and end at Silver Cave
+ ld a, FLY_MT_SILVER
+ ld [wEndFlypoint], a
+ call FillJohtoMap
+ pop af
+.MapHud:
+ call TownMapBubble
+ call TownMapPals
+ hlbgcoord 0, 0 ; BG Map 0
+ call TownMapBGUpdate
+ call TownMapMon
+ ld a, c
+ ld [wTownMapCursorCoordinates], a
+ ld a, b
+ ld [wTownMapCursorCoordinates + 1], a
+ ret
+
+Pokedex_GetArea:
+; e: Current landmark
+ ld a, [wTownMapPlayerIconLandmark]
+ push af
+ ld a, [wTownMapCursorLandmark]
+ push af
+ ld a, e
+ ld [wTownMapPlayerIconLandmark], a
+ call ClearSprites
+ xor a
+ ldh [hBGMapMode], a
+ ld a, $1
+ ldh [hInMenu], a
+ ld de, PokedexNestIconGFX
+ ld hl, vTiles0 tile $7f
+ lb bc, BANK(PokedexNestIconGFX), 1
+ call Request2bpp
+ call .GetPlayerOrFastShipIcon
+ ld hl, vTiles0 tile $78
+ ld c, 4
+ call Request2bpp
+ call LoadTownMapGFX
+ call FillKantoMap
+ call .PlaceString_MonsNest
+ call TownMapPals
+ hlbgcoord 0, 0, vBGMap1
+ call TownMapBGUpdate
+ call FillJohtoMap
+ call .PlaceString_MonsNest
+ call TownMapPals
+ hlbgcoord 0, 0
+ call TownMapBGUpdate
+ ld b, SCGB_POKEGEAR_PALS
+ call GetSGBLayout
+ call SetPalettes
+ xor a
+ ldh [hBGMapMode], a
+ xor a ; JOHTO_REGION
+ call .GetAndPlaceNest
+.loop
+ call JoyTextDelay
+ ld hl, hJoyPressed
+ ld a, [hl]
+ and A_BUTTON | B_BUTTON
+ jr nz, .a_b
+ ldh a, [hJoypadDown]
+ and SELECT
+ jr nz, .select
+ call .LeftRightInput
+ call .BlinkNestIcons
+ jr .next
+
+.select
+ call .HideNestsShowPlayer
+.next
+ call DelayFrame
+ jr .loop
+
+.a_b
+ call ClearSprites
+ pop af
+ ld [wTownMapCursorLandmark], a
+ pop af
+ ld [wTownMapPlayerIconLandmark], a
+ ret
+
+.LeftRightInput:
+ ld a, [hl]
+ and D_LEFT
+ jr nz, .left
+ ld a, [hl]
+ and D_RIGHT
+ jr nz, .right
+ ret
+
+.left
+ ldh a, [hWY]
+ cp $90
+ ret z
+ call ClearSprites
+ ld a, $90
+ ldh [hWY], a
+ xor a ; JOHTO_REGION
+ call .GetAndPlaceNest
+ ret
+
+.right
+ ld a, [wStatusFlags]
+ bit STATUSFLAGS_HALL_OF_FAME_F, a
+ ret z
+ ldh a, [hWY]
+ and a
+ ret z
+ call ClearSprites
+ xor a
+ ldh [hWY], a
+ ld a, KANTO_REGION
+ call .GetAndPlaceNest
+ ret
+
+.BlinkNestIcons:
+ ldh a, [hVBlankCounter]
+ ld e, a
+ and $f
+ ret nz
+ ld a, e
+ and $10
+ jr nz, .copy_sprites
+ call ClearSprites
+ ret
+
+.copy_sprites
+ hlcoord 0, 0
+ ld de, wVirtualOAM
+ ld bc, wVirtualOAMEnd - wVirtualOAM
+ call CopyBytes
+ ret
+
+.PlaceString_MonsNest:
+ hlcoord 0, 0
+ ld bc, SCREEN_WIDTH
+ ld a, " "
+ call ByteFill
+ hlcoord 0, 1
+ ld a, $06
+ ld [hli], a
+ ld bc, SCREEN_WIDTH - 2
+ ld a, $07
+ call ByteFill
+ ld [hl], $17
+ call GetPokemonName
+ hlcoord 2, 0
+ call PlaceString
+ ld h, b
+ ld l, c
+ ld de, .String_SNest
+ call PlaceString
+ ret
+
+.String_SNest:
+ db "'S NEST@"
+
+.GetAndPlaceNest:
+ ld [wTownMapCursorLandmark], a
+ ld e, a
+ farcall FindNest ; load nest landmarks into wTilemap[0,0]
+ decoord 0, 0
+ ld hl, wVirtualOAMSprite00
+.nestloop
+ ld a, [de]
+ and a
+ jr z, .done_nest
+ push de
+ ld e, a
+ push hl
+ farcall GetLandmarkCoords
+ pop hl
+ ; load into OAM
+ ld a, d
+ sub 4
+ ld [hli], a ; y
+ ld a, e
+ sub 4
+ ld [hli], a ; x
+ ld a, $7f ; nest icon
+ ld [hli], a ; tile id
+ xor a
+ ld [hli], a ; attributes
+ ; next
+ pop de
+ inc de
+ jr .nestloop
+
+.done_nest
+ ld hl, wVirtualOAM
+ decoord 0, 0
+ ld bc, wVirtualOAMEnd - wVirtualOAM
+ call CopyBytes
+ ret
+
+.HideNestsShowPlayer:
+ call .CheckPlayerLocation
+ ret c
+ ld a, [wTownMapPlayerIconLandmark]
+ ld e, a
+ farcall GetLandmarkCoords
+ ld c, e
+ ld b, d
+ ld de, .PlayerOAM
+ ld hl, wVirtualOAMSprite00
+.ShowPlayerLoop:
+ ld a, [de]
+ cp $80
+ jr z, .clear_oam
+ add b
+ ld [hli], a ; y
+ inc de
+ ld a, [de]
+ add c
+ ld [hli], a ; x
+ inc de
+ ld a, [de]
+ add $78 ; where the player's sprite is loaded
+ ld [hli], a ; tile id
+ inc de
+ xor a ; PAL_OW_RED
+ ld [hli], a ; attributes
+ jr .ShowPlayerLoop
+
+.clear_oam
+ ld hl, wVirtualOAMSprite04
+ ld bc, wVirtualOAMEnd - wVirtualOAMSprite04
+ xor a
+ call ByteFill
+ ret
+
+.PlayerOAM:
+ ; y pxl, x pxl, tile offset
+ db -1 * 8, -1 * 8, 0 ; top left
+ db -1 * 8, 0 * 8, 1 ; top right
+ db 0 * 8, -1 * 8, 2 ; bottom left
+ db 0 * 8, 0 * 8, 3 ; bottom right
+ db $80 ; terminator
+
+.CheckPlayerLocation:
+; Don't show the player's sprite if you're
+; not in the same region as what's currently
+; on the screen.
+ ld a, [wTownMapPlayerIconLandmark]
+ cp LANDMARK_FAST_SHIP
+ jr z, .johto
+ cp KANTO_LANDMARK
+ jr c, .johto
+.kanto
+ ld a, [wTownMapCursorLandmark]
+ and a
+ jr z, .clear
+ jr .ok
+
+.johto
+ ld a, [wTownMapCursorLandmark]
+ and a
+ jr nz, .clear
+.ok
+ and a
+ ret
+
+.clear
+ ld hl, wVirtualOAM
+ ld bc, wVirtualOAMEnd - wVirtualOAM
+ xor a
+ call ByteFill
+ scf
+ ret
+
+.GetPlayerOrFastShipIcon:
+ ld a, [wTownMapPlayerIconLandmark]
+ cp LANDMARK_FAST_SHIP
+ jr z, .FastShip
+ ld de, ChrisSpriteGFX
+ ld b, BANK(ChrisSpriteGFX)
+ ret
+
+.FastShip:
+ ld de, FastShipGFX
+ ld b, BANK(FastShipGFX)
+ ret
+
+TownMapBGUpdate:
+; Update BG Map tiles and attributes
+
+; BG Map address
+ ld a, l
+ ldh [hBGMapAddress], a
+ ld a, h
+ ldh [hBGMapAddress + 1], a
+; Only update palettes on CGB
+ ldh a, [hCGB]
+ and a
+ jr z, .tiles
+; BG Map mode 2 (palettes)
+ ld a, 2
+ ldh [hBGMapMode], a
+; The BG Map is updated in thirds, so we wait
+
+; 3 frames to update the whole screen's palettes.
+ ld c, 3
+ call DelayFrames
+.tiles
+; Update BG Map tiles
+ call WaitBGMap
+; Turn off BG Map update
+ xor a
+ ldh [hBGMapMode], a
+ ret
+
+FillJohtoMap:
+ ld de, JohtoMap
+ jr FillTownMap
+
+FillKantoMap:
+ ld de, KantoMap
+FillTownMap:
+ hlcoord 0, 0
+.loop
+ ld a, [de]
+ cp -1
+ ret z
+ ld a, [de]
+ ld [hli], a
+ inc de
+ jr .loop
+
+TownMapPals:
+; Assign palettes based on tile ids
+ hlcoord 0, 0
+ decoord 0, 0, wAttrmap
+ ld bc, SCREEN_WIDTH * SCREEN_HEIGHT
+.loop
+; Current tile
+ ld a, [hli]
+ push hl
+; The palette map covers tiles $00 to $5f; $60 and above use palette 0
+ cp $60
+ jr nc, .pal0
+
+; The palette data is condensed to nybbles, least-significant first.
+ ld hl, .PalMap
+ srl a
+ jr c, .odd
+; Even-numbered tile ids take the bottom nybble...
+ add l
+ ld l, a
+ ld a, h
+ adc 0
+ ld h, a
+ ld a, [hl]
+ and PALETTE_MASK
+ jr .update
+
+.odd
+; ...and odd ids take the top.
+ add l
+ ld l, a
+ ld a, h
+ adc 0
+ ld h, a
+ ld a, [hl]
+ swap a
+ and PALETTE_MASK
+ jr .update
+
+.pal0
+ xor a
+.update
+ pop hl
+ ld [de], a
+ inc de
+ dec bc
+ ld a, b
+ or c
+ jr nz, .loop
+ ret
+
+.PalMap:
+INCLUDE "gfx/pokegear/town_map_palette_map.asm"
+
+TownMapMon:
+; Draw the FlyMon icon at town map location
+
+; Get FlyMon species
+ ld a, [wCurPartyMon]
+ ld hl, wPartySpecies
+ ld e, a
+ ld d, $0
+ add hl, de
+ ld a, [hl]
+ ld [wTempIconSpecies], a
+; Get FlyMon icon
+ ld e, $08 ; starting tile in VRAM
+ farcall GetSpeciesIcon
+; Animation/palette
+ depixel 0, 0
+ ld a, SPRITE_ANIM_INDEX_PARTY_MON
+ call InitSpriteAnimStruct
+ ld hl, SPRITEANIMSTRUCT_TILE_ID
+ add hl, bc
+ ld [hl], $08
+ ld hl, SPRITEANIMSTRUCT_ANIM_SEQ_ID
+ add hl, bc
+ ld [hl], SPRITE_ANIM_SEQ_NULL
+ ret
+
+TownMapPlayerIcon:
+; Draw the player icon at town map location in a
+ push af
+ ld de, ChrisSpriteGFX
+; Standing icon
+ ld hl, vTiles0 tile $10
+ lb bc, BANK(ChrisSpriteGFX), 4
+ call Request2bpp
+; Walking icon
+ ld de, ChrisSpriteGFX + 12 tiles
+ ld hl, vTiles0 tile $14
+ lb bc, BANK(ChrisSpriteGFX), 4
+ ld a, BANK(ChrisSpriteGFX) ; does nothing
+ call Request2bpp
+; Animation/palette
+ depixel 0, 0
+ ld a, SPRITE_ANIM_INDEX_RED_WALK
+ call InitSpriteAnimStruct
+ ld hl, SPRITEANIMSTRUCT_TILE_ID
+ add hl, bc
+ ld [hl], $10
+ pop af
+ ld e, a
+ push bc
+ farcall GetLandmarkCoords
+ pop bc
+ ld hl, SPRITEANIMSTRUCT_XCOORD
+ add hl, bc
+ ld [hl], e
+ ld hl, SPRITEANIMSTRUCT_YCOORD
+ add hl, bc
+ ld [hl], d
+ ret
+
+LoadTownMapGFX:
+ ld hl, TownMapGFX
+ ld de, vTiles2
+ lb bc, BANK(TownMapGFX), 48
+ call DecompressRequest2bpp
+ ret
+
+JohtoMap:
+INCBIN "gfx/pokegear/johto.bin"
+
+KantoMap:
+INCBIN "gfx/pokegear/kanto.bin"
+
+PokedexNestIconGFX:
+INCBIN "gfx/pokegear/dexmap_nest_icon.2bpp"
+FlyMapLabelBorderGFX:
+INCBIN "gfx/pokegear/flymap_label_border.1bpp"
+
+Unreferenced_Function92264:
+ xor a
+ ld [wTownMapPlayerIconLandmark], a
+ call ClearBGPalettes
+ call ClearTilemap
+ call ClearSprites
+ ld hl, hInMenu
+ ld a, [hl]
+ push af
+ ld [hl], $1
+ xor a
+ ldh [hBGMapMode], a
+ farcall ClearSpriteAnims
+ call LoadTownMapGFX
+ ld de, FlyMapLabelBorderGFX
+ ld hl, vTiles2 tile $30
+ lb bc, BANK(FlyMapLabelBorderGFX), 6
+ call Request1bpp
+ call FillKantoMap
+ call TownMapBubble
+ call TownMapPals
+ hlbgcoord 0, 0, vBGMap1
+ call TownMapBGUpdate
+ call FillJohtoMap
+ call TownMapBubble
+ call TownMapPals
+ hlbgcoord 0, 0
+ call TownMapBGUpdate
+ call TownMapMon
+ ld a, c
+ ld [wTownMapCursorCoordinates], a
+ ld a, b
+ ld [wTownMapCursorCoordinates + 1], a
+ ld b, SCGB_POKEGEAR_PALS
+ call GetSGBLayout
+ call SetPalettes
+.loop
+ call JoyTextDelay
+ ld hl, hJoyPressed
+ ld a, [hl]
+ and B_BUTTON
+ jr nz, .pressedB
+ ld a, [hl]
+ and A_BUTTON
+ jr nz, .pressedA
+ call .HandleDPad
+ call GetMapCursorCoordinates
+ farcall PlaySpriteAnimations
+ call DelayFrame
+ jr .loop
+
+.pressedB
+ ld a, -1
+ jr .finished_a_b
+
+.pressedA
+ ld a, [wTownMapPlayerIconLandmark]
+ ld l, a
+ ld h, 0
+ add hl, hl
+ ld de, Flypoints + 1
+ add hl, de
+ ld a, [hl]
+.finished_a_b
+ ld [wTownMapPlayerIconLandmark], a
+ pop af
+ ldh [hInMenu], a
+ call ClearBGPalettes
+ ld a, $90
+ ldh [hWY], a
+ xor a ; LOW(vBGMap0)
+ ldh [hBGMapAddress], a
+ ld a, HIGH(vBGMap0)
+ ldh [hBGMapAddress + 1], a
+ ld a, [wTownMapPlayerIconLandmark]
+ ld e, a
+ ret
+
+.HandleDPad:
+ ld hl, hJoyLast
+ ld a, [hl]
+ and D_DOWN | D_RIGHT
+ jr nz, .down_right
+ ld a, [hl]
+ and D_UP | D_LEFT
+ jr nz, .up_left
+ ret
+
+.down_right
+ ld hl, wTownMapPlayerIconLandmark
+ ld a, [hl]
+ cp FLY_INDIGO
+ jr c, .okay_dr
+ ld [hl], -1
+.okay_dr
+ inc [hl]
+ jr .continue
+
+.up_left
+ ld hl, wTownMapPlayerIconLandmark
+ ld a, [hl]
+ and a
+ jr nz, .okay_ul
+ ld [hl], FLY_INDIGO + 1
+.okay_ul
+ dec [hl]
+.continue
+ ld a, [wTownMapPlayerIconLandmark]
+ cp KANTO_FLYPOINT
+ jr c, .johto
+ call FillKantoMap
+ xor a
+ ld b, $9c
+ jr .finish
+
+.johto
+ call FillJohtoMap
+ ld a, $90
+ ld b, $98
+.finish
+ ldh [hWY], a
+ ld a, b
+ ldh [hBGMapAddress + 1], a
+ call TownMapBubble
+ call WaitBGMap
+ xor a
+ ldh [hBGMapMode], a
+ ret
diff --git a/engine/pokegear/radio.asm b/engine/pokegear/radio.asm
new file mode 100644
index 00000000..77ba764e
--- /dev/null
+++ b/engine/pokegear/radio.asm
@@ -0,0 +1,1417 @@
+PlayRadioShow:
+; If we're already in the radio program proper, we don't need to be here.
+ ld a, [wCurRadioLine]
+ cp POKE_FLUTE_RADIO
+ jr nc, .ok
+; If Team Rocket is not occupying the radio tower, we don't need to be here.
+ ld a, [wStatusFlags2]
+ bit STATUSFLAGS2_ROCKETS_IN_RADIO_TOWER_F, a
+ jr z, .ok
+; If we're in Kanto, we don't need to be here.
+ call IsInJohto
+ and a
+ jr nz, .ok
+; Team Rocket broadcasts on all stations.
+ ld a, ROCKET_RADIO
+ ld [wCurRadioLine], a
+.ok
+; Jump to the currently loaded station. The index to which we need to jump is in wCurRadioLine.
+ ld a, [wCurRadioLine]
+ ld e, a
+ ld d, 0
+ ld hl, RadioJumptable
+ add hl, de
+ add hl, de
+ ld a, [hli]
+ ld h, [hl]
+ ld l, a
+ jp hl
+
+RadioJumptable:
+; entries correspond to constants/radio_constants.asm
+ dw OaksPKMNTalk1 ; $00
+ dw PokedexShow1 ; $01
+ dw BenMonMusic1 ; $02
+ dw LuckyNumberShow1 ; $03
+ dw PeoplePlaces1 ; $04
+ dw FernMonMusic1 ; $05
+ dw RocketRadio1 ; $06
+ dw PokeFluteRadio ; $07
+ dw UnownRadio ; $08
+ dw EvolutionRadio ; $09
+; OaksPKMNTalk
+ dw OaksPKMNTalk2 ; $0a
+ dw OaksPKMNTalk3 ; $0b
+ dw OaksPKMNTalk4 ; $0c
+ dw OaksPKMNTalk5 ; $0d
+ dw OaksPKMNTalk6 ; $0e
+ dw OaksPKMNTalk7 ; $0f
+ dw OaksPKMNTalk8 ; $10
+ dw OaksPKMNTalk9 ; $11
+ dw PokedexShow2 ; $12
+ dw PokedexShow3 ; $13
+ dw PokedexShow4 ; $14
+ dw PokedexShow5 ; $15
+; Ben Music
+ dw BenMonMusic2 ; $16
+ dw BenMonMusic3 ; $17
+ dw BenFernMusic4 ; $18
+ dw BenFernMusic5 ; $19
+ dw BenFernMusic6 ; $1a
+ dw BenFernMusic7 ; $1b
+ dw FernMonMusic2 ; $1c
+; Lucky Number Show
+ dw LuckyNumberShow2 ; $1d
+ dw LuckyNumberShow3 ; $1e
+ dw LuckyNumberShow4 ; $1f
+ dw LuckyNumberShow5 ; $20
+ dw LuckyNumberShow6 ; $21
+ dw LuckyNumberShow7 ; $22
+ dw LuckyNumberShow8 ; $23
+ dw LuckyNumberShow9 ; $24
+ dw LuckyNumberShow10 ; $25
+ dw LuckyNumberShow11 ; $26
+ dw LuckyNumberShow12 ; $27
+ dw LuckyNumberShow13 ; $28
+ dw LuckyNumberShow14 ; $29
+ dw LuckyNumberShow15 ; $2a
+; People & Places
+ dw PeoplePlaces2 ; $2b
+ dw PeoplePlaces3 ; $2c
+ dw PeoplePlaces4 ; $2d
+ dw PeoplePlaces5 ; $2e
+ dw PeoplePlaces6 ; $2f
+ dw PeoplePlaces7 ; $30
+; Rocket Radio
+ dw RocketRadio2 ; $31
+ dw RocketRadio3 ; $32
+ dw RocketRadio4 ; $33
+ dw RocketRadio5 ; $34
+ dw RocketRadio6 ; $35
+ dw RocketRadio7 ; $36
+ dw RocketRadio8 ; $37
+ dw RocketRadio9 ; $38
+ dw RocketRadio10 ; $39
+; More Pokemon Channel stuff
+ dw OaksPKMNTalk10 ; $3a
+ dw OaksPKMNTalk11 ; $3b
+ dw OaksPKMNTalk12 ; $3c
+ dw OaksPKMNTalk13 ; $3d
+ dw OaksPKMNTalk14 ; $3e
+ dw RadioScroll ; $3f
+; More Pokemon Channel stuff
+ dw PokedexShow6 ; $40
+ dw PokedexShow7 ; $41
+ dw PokedexShow8 ; $42
+
+PrintRadioLine:
+ ld [wNextRadioLine], a
+ ld hl, wRadioText
+ ld a, [wNumRadioLinesPrinted]
+ cp 2
+ jr nc, .print
+ inc hl
+ ld [hl], TX_START
+ inc a
+ ld [wNumRadioLinesPrinted], a
+ cp 2
+ jr nz, .print
+ bccoord 1, 16
+ call PlaceHLTextAtBC
+ jr .skip
+.print
+ call PrintTextboxText
+.skip
+ ld a, RADIO_SCROLL
+ ld [wCurRadioLine], a
+ ld a, 100
+ ld [wRadioTextDelay], a
+ ret
+
+ReplacePeriodsWithSpaces:
+ push hl
+ ld b, SCREEN_WIDTH * 2
+.loop
+ ld a, [hl]
+ cp "."
+ jr nz, .next
+ ld [hl], " "
+
+.next
+ inc hl
+ dec b
+ jr nz, .loop
+ pop hl
+ ret
+
+RadioScroll:
+ ld hl, wRadioTextDelay
+ ld a, [hl]
+ and a
+ jr z, .proceed
+ dec [hl]
+ ret
+.proceed
+ ld a, [wNextRadioLine]
+ ld [wCurRadioLine], a
+ ld a, [wNumRadioLinesPrinted]
+ cp 1
+ call nz, CopyBottomLineToTopLine
+ jp ClearBottomLine
+
+OaksPKMNTalk1:
+ ld a, 5
+ ld [wOaksPKMNTalkSegmentCounter], a
+ call StartRadioStation
+ ld hl, OPT_IntroText1
+ ld a, OAKS_POKEMON_TALK_2
+ jp NextRadioLine
+
+OaksPKMNTalk2:
+ ld hl, OPT_IntroText2
+ ld a, OAKS_POKEMON_TALK_3
+ jp NextRadioLine
+
+OaksPKMNTalk3:
+ ld hl, OPT_IntroText3
+ ld a, OAKS_POKEMON_TALK_4
+ jp NextRadioLine
+
+OaksPKMNTalk4:
+; Choose a random route, and a random Pokemon from that route.
+.sample
+ call Random
+ and %11111
+ cp (OaksPKMNTalkRoutes.End - OaksPKMNTalkRoutes) / 2
+ jr nc, .sample
+ ; We now have a number between 0 and 14.
+ ld hl, OaksPKMNTalkRoutes
+ ld c, a
+ ld b, 0
+ add hl, bc
+ add hl, bc
+ ld b, [hl]
+ inc hl
+ ld c, [hl]
+ ; bc now contains the chosen map's group and number indices.
+ push bc
+
+ ; Search the JohtoGrassWildMons array for the chosen map.
+ ld hl, JohtoGrassWildMons
+.loop
+ ld a, BANK(JohtoGrassWildMons)
+ call GetFarByte
+ cp -1
+ jr z, .overflow
+ inc hl
+ cp b
+ jr nz, .next
+ ld a, BANK(JohtoGrassWildMons)
+ call GetFarByte
+ cp c
+ jr z, .done
+.next
+ dec hl
+ ld de, GRASS_WILDDATA_LENGTH
+ add hl, de
+ jr .loop
+
+.done
+ ; Point hl to the list of morning Pokémon., skipping percentages
+rept 4
+ inc hl
+endr
+ ; Generate a number, either 0, 1, or 2, to choose a time of day.
+.loop2
+ call Random
+ maskbits NUM_DAYTIMES
+ cp DARKNESS_F
+ jr z, .loop2
+
+ ld bc, 2 * NUM_GRASSMON
+ call AddNTimes
+.loop3
+ ; Choose one of the middle three Pokemon.
+ call Random
+ and NUM_GRASSMON
+ cp 2
+ jr c, .loop3
+ cp 5
+ jr nc, .loop3
+ ld e, a
+ ld d, 0
+ add hl, de
+ add hl, de
+ inc hl ; skip level
+ ld a, BANK(JohtoGrassWildMons)
+ call GetFarByte
+ ld [wNamedObjectIndexBuffer], a
+ ld [wCurPartySpecies], a
+ call GetPokemonName
+ ld hl, wStringBuffer1
+ ld de, wMonOrItemNameBuffer
+ ld bc, MON_NAME_LENGTH
+ call CopyBytes
+
+ ; Now that we've chosen our wild Pokemon,
+ ; let's recover the map index info and get its name.
+ pop bc
+ call GetWorldMapLocation
+ ld e, a
+ callfar GetLandmarkName
+ ld hl, OPT_OakText1
+ call CopyRadioTextToRAM
+ ld a, OAKS_POKEMON_TALK_5
+ jp PrintRadioLine
+
+.overflow
+ pop bc
+ ld a, OAKS_POKEMON_TALK
+ jp PrintRadioLine
+
+INCLUDE "data/radio/oaks_pkmn_talk_routes.asm"
+
+OaksPKMNTalk5:
+ ld hl, OPT_OakText2
+ ld a, OAKS_POKEMON_TALK_6
+ jp NextRadioLine
+
+OaksPKMNTalk6:
+ ld hl, OPT_OakText3
+ ld a, OAKS_POKEMON_TALK_7
+ jp NextRadioLine
+
+OPT_IntroText1:
+ text_far _OPT_IntroText1
+ text_end
+
+OPT_IntroText2:
+ text_far _OPT_IntroText2
+ text_end
+
+OPT_IntroText3:
+ text_far _OPT_IntroText3
+ text_end
+
+OPT_OakText1:
+ text_far _OPT_OakText1
+ text_end
+
+OPT_OakText2:
+ text_far _OPT_OakText2
+ text_end
+
+OPT_OakText3:
+ text_far _OPT_OakText3
+ text_end
+
+OaksPKMNTalk7:
+ ld a, [wCurPartySpecies]
+ ld [wNamedObjectIndexBuffer], a
+ call GetPokemonName
+ ld hl, OPT_MaryText1
+ ld a, OAKS_POKEMON_TALK_8
+ jp NextRadioLine
+
+OPT_MaryText1:
+ text_far _OPT_MaryText1
+ text_end
+
+OaksPKMNTalk8:
+ ; 0-15 are all valid indexes into .Adverbs,
+ ; so no need for a retry loop
+ call Random
+ maskbits NUM_OAKS_POKEMON_TALK_ADVERBS
+ ld e, a
+ ld d, 0
+ ld hl, .Adverbs
+ add hl, de
+ add hl, de
+ ld a, [hli]
+ ld h, [hl]
+ ld l, a
+ ld a, OAKS_POKEMON_TALK_9
+ jp NextRadioLine
+
+.Adverbs:
+; there are NUM_OAKS_POKEMON_TALK_ADVERBS entries
+ dw .OPT_SweetAdorablyText
+ dw .OPT_WigglySlicklyText
+ dw .OPT_AptlyNamedText
+ dw .OPT_UndeniablyKindOfText
+ dw .OPT_UnbearablyText
+ dw .OPT_WowImpressivelyText
+ dw .OPT_AlmostPoisonouslyText
+ dw .OPT_SensuallyText
+ dw .OPT_MischievouslyText
+ dw .OPT_TopicallyText
+ dw .OPT_AddictivelyText
+ dw .OPT_LooksInWaterText
+ dw .OPT_EvolutionMustBeText
+ dw .OPT_ProvocativelyText
+ dw .OPT_FlippedOutText
+ dw .OPT_HeartMeltinglyText
+
+.OPT_SweetAdorablyText:
+ text_far _OPT_SweetAdorablyText
+ text_end
+
+.OPT_WigglySlicklyText:
+ text_far _OPT_WigglySlicklyText
+ text_end
+
+.OPT_AptlyNamedText:
+ text_far _OPT_AptlyNamedText
+ text_end
+
+.OPT_UndeniablyKindOfText:
+ text_far _OPT_UndeniablyKindOfText
+ text_end
+
+.OPT_UnbearablyText:
+ text_far _OPT_UnbearablyText
+ text_end
+
+.OPT_WowImpressivelyText:
+ text_far _OPT_WowImpressivelyText
+ text_end
+
+.OPT_AlmostPoisonouslyText:
+ text_far _OPT_AlmostPoisonouslyText
+ text_end
+
+.OPT_SensuallyText:
+ text_far _OPT_SensuallyText
+ text_end
+
+.OPT_MischievouslyText:
+ text_far _OPT_MischievouslyText
+ text_end
+
+.OPT_TopicallyText:
+ text_far _OPT_TopicallyText
+ text_end
+
+.OPT_AddictivelyText:
+ text_far _OPT_AddictivelyText
+ text_end
+
+.OPT_LooksInWaterText:
+ text_far _OPT_LooksInWaterText
+ text_end
+
+.OPT_EvolutionMustBeText:
+ text_far _OPT_EvolutionMustBeText
+ text_end
+
+.OPT_ProvocativelyText:
+ text_far _OPT_ProvocativelyText
+ text_end
+
+.OPT_FlippedOutText:
+ text_far _OPT_FlippedOutText
+ text_end
+
+.OPT_HeartMeltinglyText:
+ text_far _OPT_HeartMeltinglyText
+ text_end
+
+OaksPKMNTalk9:
+ ; 0-15 are all valid indexes into .Adjectives,
+ ; so no need for a retry loop
+ call Random
+ maskbits NUM_OAKS_POKEMON_TALK_ADJECTIVES
+ ld e, a
+ ld d, 0
+ ld hl, .Adjectives
+ add hl, de
+ add hl, de
+ ld a, [hli]
+ ld h, [hl]
+ ld l, a
+ ld a, [wOaksPKMNTalkSegmentCounter]
+ dec a
+ ld [wOaksPKMNTalkSegmentCounter], a
+ ld a, OAKS_POKEMON_TALK_4
+ jr nz, .ok
+ ld a, 5
+ ld [wOaksPKMNTalkSegmentCounter], a
+ ld a, OAKS_POKEMON_TALK_10
+.ok
+ jp NextRadioLine
+
+.Adjectives:
+; there are NUM_OAKS_POKEMON_TALK_ADJECTIVES entries
+ dw .OPT_CuteText
+ dw .OPT_WeirdText
+ dw .OPT_PleasantText
+ dw .OPT_BoldSortOfText
+ dw .OPT_FrighteningText
+ dw .OPT_SuaveDebonairText
+ dw .OPT_PowerfulText
+ dw .OPT_ExcitingText
+ dw .OPT_NowText
+ dw .OPT_InspiringText
+ dw .OPT_FriendlyText
+ dw .OPT_HotHotHotText
+ dw .OPT_StimulatingText
+ dw .OPT_GuardedText
+ dw .OPT_LovelyText
+ dw .OPT_SpeedyText
+
+.OPT_CuteText:
+ text_far _OPT_CuteText
+ text_end
+
+.OPT_WeirdText:
+ text_far _OPT_WeirdText
+ text_end
+
+.OPT_PleasantText:
+ text_far _OPT_PleasantText
+ text_end
+
+.OPT_BoldSortOfText:
+ text_far _OPT_BoldSortOfText
+ text_end
+
+.OPT_FrighteningText:
+ text_far _OPT_FrighteningText
+ text_end
+
+.OPT_SuaveDebonairText:
+ text_far _OPT_SuaveDebonairText
+ text_end
+
+.OPT_PowerfulText:
+ text_far _OPT_PowerfulText
+ text_end
+
+.OPT_ExcitingText:
+ text_far _OPT_ExcitingText
+ text_end
+
+.OPT_NowText:
+ text_far _OPT_NowText
+ text_end
+
+.OPT_InspiringText:
+ text_far _OPT_InspiringText
+ text_end
+
+.OPT_FriendlyText:
+ text_far _OPT_FriendlyText
+ text_end
+
+.OPT_HotHotHotText:
+ text_far _OPT_HotHotHotText
+ text_end
+
+.OPT_StimulatingText:
+ text_far _OPT_StimulatingText
+ text_end
+
+.OPT_GuardedText:
+ text_far _OPT_GuardedText
+ text_end
+
+.OPT_LovelyText:
+ text_far _OPT_LovelyText
+ text_end
+
+.OPT_SpeedyText:
+ text_far _OPT_SpeedyText
+ text_end
+
+OaksPKMNTalk10:
+ farcall RadioMusicRestartPokemonChannel
+ ld hl, OPT_RestartText
+ call PrintText
+ call WaitBGMap
+ ld hl, OPT_PokemonChannelText
+ call PrintText
+ ld a, OAKS_POKEMON_TALK_11
+ ld [wCurRadioLine], a
+ ld a, 100
+ ld [wRadioTextDelay], a
+ ret
+
+OPT_PokemonChannelText:
+ text_far _OPT_PokemonChannelText
+ text_end
+
+OPT_RestartText:
+ text_end
+
+OaksPKMNTalk11:
+ ld hl, wRadioTextDelay
+ dec [hl]
+ ret nz
+ hlcoord 9, 14
+ ld de, .pokemon_string
+ ld a, OAKS_POKEMON_TALK_12
+ jp PlaceRadioString
+
+.pokemon_string
+ db "#MON@"
+
+OaksPKMNTalk12:
+ ld hl, wRadioTextDelay
+ dec [hl]
+ ret nz
+ hlcoord 1, 16
+ ld de, .pokemon_channel_string
+ ld a, OAKS_POKEMON_TALK_13
+ jp PlaceRadioString
+
+.pokemon_channel_string
+ db "#MON Channel@"
+
+OaksPKMNTalk13:
+ ld hl, wRadioTextDelay
+ dec [hl]
+ ret nz
+ hlcoord 12, 16
+ ld de, .terminator
+ ld a, OAKS_POKEMON_TALK_14
+ jp PlaceRadioString
+
+.terminator
+ db "@"
+
+OaksPKMNTalk14:
+ ld hl, wRadioTextDelay
+ dec [hl]
+ ret nz
+ ld de, MUSIC_POKEMON_TALK
+ callfar RadioMusicRestartDE
+ ld hl, .terminator
+ call PrintText
+ ld a, OAKS_POKEMON_TALK_4
+ ld [wNextRadioLine], a
+ xor a
+ ld [wNumRadioLinesPrinted], a
+ ld a, RADIO_SCROLL
+ ld [wCurRadioLine], a
+ ld a, 10
+ ld [wRadioTextDelay], a
+ ret
+
+.terminator
+ db "@"
+
+PlaceRadioString:
+ ld [wCurRadioLine], a
+ ld a, 100
+ ld [wRadioTextDelay], a
+ jp PlaceString
+
+CopyBottomLineToTopLine:
+ hlcoord 0, 15
+ decoord 0, 13
+ ld bc, SCREEN_WIDTH * 2
+ jp CopyBytes
+
+ClearBottomLine:
+ hlcoord 1, 15
+ ld bc, SCREEN_WIDTH - 2
+ ld a, " "
+ call ByteFill
+ hlcoord 1, 16
+ ld bc, SCREEN_WIDTH - 2
+ ld a, " "
+ jp ByteFill
+
+PokedexShow1:
+ call StartRadioStation
+.loop
+ call Random
+ cp NUM_POKEMON
+ jr nc, .loop
+ ld c, a
+ push bc
+ ld a, c
+ call CheckCaughtMon
+ pop bc
+ jr z, .loop
+ inc c
+ ld a, c
+ ld [wCurPartySpecies], a
+ ld [wNamedObjectIndexBuffer], a
+ call GetPokemonName
+ ld hl, PokedexShowText
+ ld a, POKEDEX_SHOW_2
+ jp NextRadioLine
+
+PokedexShow2:
+ ld a, [wCurPartySpecies]
+ dec a
+ ld hl, PokedexDataPointerTable
+ ld c, a
+ ld b, 0
+ add hl, bc
+ add hl, bc
+ rlca
+ rlca
+ and %11
+ add BANK("Pokedex Entries 001-064")
+ push af
+ ld a, BANK(PokedexDataPointerTable)
+ call GetFarHalfword
+ pop af
+ push af
+ push hl
+ call CopyDexEntryPart1
+ dec hl
+ ld [hl], "<DONE>"
+ ld hl, wPokedexShowPointerAddr
+ call CopyRadioTextToRAM
+ pop hl
+ pop af
+ call CopyDexEntryPart2
+rept 4
+ inc hl
+endr
+ ld a, l
+ ld [wPokedexShowPointerAddr], a
+ ld a, h
+ ld [wPokedexShowPointerAddr + 1], a
+ ld a, POKEDEX_SHOW_3
+ jp PrintRadioLine
+
+PokedexShow3:
+ call CopyDexEntry
+ ld a, POKEDEX_SHOW_4
+ jp PrintRadioLine
+
+PokedexShow4:
+ call CopyDexEntry
+ ld a, POKEDEX_SHOW_5
+ jp PrintRadioLine
+
+PokedexShow5:
+ call CopyDexEntry
+ ld a, POKEDEX_SHOW_6
+ jp PrintRadioLine
+
+PokedexShow6:
+ call CopyDexEntry
+ ld a, POKEDEX_SHOW_7
+ jp PrintRadioLine
+
+PokedexShow7:
+ call CopyDexEntry
+ ld a, POKEDEX_SHOW_8
+ jp PrintRadioLine
+
+PokedexShow8:
+ call CopyDexEntry
+ ld a, POKEDEX_SHOW
+ jp PrintRadioLine
+
+CopyDexEntry:
+ ld a, [wPokedexShowPointerAddr]
+ ld l, a
+ ld a, [wPokedexShowPointerAddr + 1]
+ ld h, a
+ ld a, [wPokedexShowPointerBank]
+ push af
+ push hl
+ call CopyDexEntryPart1
+ dec hl
+ ld [hl], "<DONE>"
+ ld hl, wPokedexShowPointerAddr
+ call CopyRadioTextToRAM
+ pop hl
+ pop af
+ call CopyDexEntryPart2
+ ret
+
+CopyDexEntryPart1:
+ ld de, wPokedexShowPointerBank
+ ld bc, SCREEN_WIDTH - 1
+ call FarCopyBytes
+ ld hl, wPokedexShowPointerAddr
+ ld [hl], TX_START
+ inc hl
+ ld [hl], "<LINE>"
+ inc hl
+.loop
+ ld a, [hli]
+ cp "@"
+ ret z
+ cp "<NEXT>"
+ ret z
+ cp "<DEXEND>"
+ ret z
+ jr .loop
+
+CopyDexEntryPart2:
+ ld d, a
+.loop
+ ld a, d
+ call GetFarByte
+ inc hl
+ cp "@"
+ jr z, .okay
+ cp "<NEXT>"
+ jr z, .okay
+ cp "<DEXEND>"
+ jr nz, .loop
+.okay
+ ld a, l
+ ld [wPokedexShowPointerAddr], a
+ ld a, h
+ ld [wPokedexShowPointerAddr + 1], a
+ ld a, d
+ ld [wPokedexShowPointerBank], a
+ ret
+
+PokedexShowText:
+ text_far _PokedexShowText
+ text_end
+
+BenMonMusic1:
+ call StartPokemonMusicChannel
+ ld hl, BenIntroText1
+ ld a, POKEMON_MUSIC_2
+ jp NextRadioLine
+
+BenMonMusic2:
+ ld hl, BenIntroText2
+ ld a, POKEMON_MUSIC_3
+ jp NextRadioLine
+
+BenMonMusic3:
+ ld hl, BenIntroText3
+ ld a, POKEMON_MUSIC_4
+ jp NextRadioLine
+
+FernMonMusic1:
+ call StartPokemonMusicChannel
+ ld hl, FernIntroText1
+ ld a, LETS_ALL_SING_2
+ jp NextRadioLine
+
+FernMonMusic2:
+ ld hl, FernIntroText2
+ ld a, POKEMON_MUSIC_4
+ jp NextRadioLine
+
+BenFernMusic4:
+ ld hl, BenFernText1
+ ld a, POKEMON_MUSIC_5
+ jp NextRadioLine
+
+BenFernMusic5:
+ call GetWeekday
+ and 1
+ ld hl, BenFernText2A
+ jr z, .SunTueThurSun
+ ld hl, BenFernText2B
+.SunTueThurSun:
+ ld a, POKEMON_MUSIC_6
+ jp NextRadioLine
+
+BenFernMusic6:
+ call GetWeekday
+ and 1
+ ld hl, BenFernText3A
+ jr z, .SunTueThurSun
+ ld hl, BenFernText3B
+.SunTueThurSun:
+ ld a, POKEMON_MUSIC_7
+ jp NextRadioLine
+
+BenFernMusic7:
+ ret
+
+StartPokemonMusicChannel:
+ call RadioTerminator
+ call PrintText
+ ld de, MUSIC_POKEMON_MARCH
+ call GetWeekday
+ and 1
+ jr z, .SunTueThurSun
+ ld de, MUSIC_POKEMON_LULLABY
+.SunTueThurSun:
+ callfar RadioMusicRestartDE
+ ret
+
+BenIntroText1:
+ text_far _BenIntroText1
+ text_end
+
+BenIntroText2:
+ text_far _BenIntroText2
+ text_end
+
+BenIntroText3:
+ text_far _BenIntroText3
+ text_end
+
+FernIntroText1:
+ text_far _FernIntroText1
+ text_end
+
+FernIntroText2:
+ text_far _FernIntroText2
+ text_end
+
+BenFernText1:
+ text_far _BenFernText1
+ text_end
+
+BenFernText2A:
+ text_far _BenFernText2A
+ text_end
+
+BenFernText2B:
+ text_far _BenFernText2B
+ text_end
+
+BenFernText3A:
+ text_far _BenFernText3A
+ text_end
+
+BenFernText3B:
+ text_far _BenFernText3B
+ text_end
+
+LuckyNumberShow1:
+ call StartRadioStation
+ callfar CheckLuckyNumberShowFlag
+ jr nc, .dontreset
+ callfar ResetLuckyNumberShowFlag
+.dontreset
+ ld hl, LC_Text1
+ ld a, LUCKY_NUMBER_SHOW_2
+ jp NextRadioLine
+
+LuckyNumberShow2:
+ ld hl, LC_Text2
+ ld a, LUCKY_NUMBER_SHOW_3
+ jp NextRadioLine
+
+LuckyNumberShow3:
+ ld hl, LC_Text3
+ ld a, LUCKY_NUMBER_SHOW_4
+ jp NextRadioLine
+
+LuckyNumberShow4:
+ ld hl, LC_Text4
+ ld a, LUCKY_NUMBER_SHOW_5
+ jp NextRadioLine
+
+LuckyNumberShow5:
+ ld hl, LC_Text5
+ ld a, LUCKY_NUMBER_SHOW_6
+ jp NextRadioLine
+
+LuckyNumberShow6:
+ ld hl, LC_Text6
+ ld a, LUCKY_NUMBER_SHOW_7
+ jp NextRadioLine
+
+LuckyNumberShow7:
+ ld hl, LC_Text7
+ ld a, LUCKY_NUMBER_SHOW_8
+ jp NextRadioLine
+
+LuckyNumberShow8:
+ ld hl, wStringBuffer1
+ ld de, wLuckyIDNumber
+ lb bc, PRINTNUM_LEADINGZEROS | 2, 5
+ call PrintNum
+ ld a, "@"
+ ld [wStringBuffer1 + 5], a
+ ld hl, LC_Text8
+ ld a, LUCKY_NUMBER_SHOW_9
+ jp NextRadioLine
+
+LuckyNumberShow9:
+ ld hl, LC_Text9
+ ld a, LUCKY_NUMBER_SHOW_10
+ jp NextRadioLine
+
+LuckyNumberShow10:
+ ld hl, LC_Text7
+ ld a, LUCKY_NUMBER_SHOW_11
+ jp NextRadioLine
+
+LuckyNumberShow11:
+ ld hl, LC_Text8
+ ld a, LUCKY_NUMBER_SHOW_12
+ jp NextRadioLine
+
+LuckyNumberShow12:
+ ld hl, LC_Text10
+ ld a, LUCKY_NUMBER_SHOW_13
+ jp NextRadioLine
+
+LuckyNumberShow13:
+ ld hl, LC_Text11
+ call Random
+ and a
+ ld a, LUCKY_CHANNEL
+ jr nz, .okay
+ ld a, LUCKY_NUMBER_SHOW_14
+.okay
+ jp NextRadioLine
+
+LuckyNumberShow14:
+ ld hl, LC_DragText1
+ ld a, LUCKY_NUMBER_SHOW_15
+ jp NextRadioLine
+
+LuckyNumberShow15:
+ ld hl, LC_DragText2
+ ld a, LUCKY_CHANNEL
+ jp NextRadioLine
+
+LC_Text1:
+ text_far _LC_Text1
+ text_end
+
+LC_Text2:
+ text_far _LC_Text2
+ text_end
+
+LC_Text3:
+ text_far _LC_Text3
+ text_end
+
+LC_Text4:
+ text_far _LC_Text4
+ text_end
+
+LC_Text5:
+ text_far _LC_Text5
+ text_end
+
+LC_Text6:
+ text_far _LC_Text6
+ text_end
+
+LC_Text7:
+ text_far _LC_Text7
+ text_end
+
+LC_Text8:
+ text_far _LC_Text8
+ text_end
+
+LC_Text9:
+ text_far _LC_Text9
+ text_end
+
+LC_Text10:
+ text_far _LC_Text10
+ text_end
+
+LC_Text11:
+ text_far _LC_Text11
+ text_end
+
+LC_DragText1:
+ text_far _LC_DragText1
+ text_end
+
+LC_DragText2:
+ text_far _LC_DragText2
+ text_end
+
+PeoplePlaces1:
+ call StartRadioStation
+ ld hl, PnP_Text1
+ ld a, PLACES_AND_PEOPLE_2
+ jp NextRadioLine
+
+PeoplePlaces2:
+ ld hl, PnP_Text2
+ ld a, PLACES_AND_PEOPLE_3
+ jp NextRadioLine
+
+PeoplePlaces3:
+ ld hl, PnP_Text3
+ call Random
+ cp 49 percent - 1
+ ld a, PLACES_AND_PEOPLE_4 ; People
+ jr c, .ok
+ ld a, PLACES_AND_PEOPLE_6 ; Places
+.ok
+ jp NextRadioLine
+
+PnP_Text1:
+ text_far _PnP_Text1
+ text_end
+
+PnP_Text2:
+ text_far _PnP_Text2
+ text_end
+
+PnP_Text3:
+ text_far _PnP_Text3
+ text_end
+
+PeoplePlaces4: ; People
+ call Random
+ maskbits NUM_TRAINER_CLASSES
+ inc a
+ cp NUM_TRAINER_CLASSES
+ jr nc, PeoplePlaces4
+ push af
+ ld hl, PnP_HiddenPeople
+ ld a, [wStatusFlags]
+ bit STATUSFLAGS_HALL_OF_FAME_F, a
+ jr z, .ok
+ ld hl, PnP_HiddenPeople_BeatE4
+ ld a, [wKantoBadges]
+ cp %11111111 ; all badges
+ jr nz, .ok
+ ld hl, PnP_HiddenPeople_BeatKanto
+.ok
+ pop af
+ ld c, a
+ ld de, 1
+ push bc
+ call IsInArray
+ pop bc
+ jr c, PeoplePlaces4
+ push bc
+ callfar GetTrainerClassName
+ ld de, wStringBuffer1
+ call CopyName1
+ pop bc
+ ld b, 1
+ callfar GetTrainerName
+ ld hl, PnP_Text4
+ ld a, PLACES_AND_PEOPLE_5
+ jp NextRadioLine
+
+INCLUDE "data/radio/pnp_hidden_people.asm"
+
+PnP_Text4:
+ text_far _PnP_Text4
+ text_end
+
+PeoplePlaces5:
+ ; 0-15 are all valid indexes into .Adjectives,
+ ; so no need for a retry loop
+ call Random
+ maskbits NUM_PNP_PEOPLE_ADJECTIVES
+ ld e, a
+ ld d, 0
+ ld hl, .Adjectives
+ add hl, de
+ add hl, de
+ ld a, [hli]
+ ld h, [hl]
+ ld l, a
+ call Random
+ cp 4 percent
+ ld a, PLACES_AND_PEOPLE
+ jr c, .ok
+ call Random
+ cp 49 percent - 1
+ ld a, PLACES_AND_PEOPLE_4 ; People
+ jr c, .ok
+ ld a, PLACES_AND_PEOPLE_6 ; Places
+.ok
+ jp NextRadioLine
+
+.Adjectives:
+; there are NUM_PNP_PEOPLE_ADJECTIVES entries
+ dw PnP_CuteText
+ dw PnP_LazyText
+ dw PnP_HappyText
+ dw PnP_NoisyText
+ dw PnP_PrecociousText
+ dw PnP_BoldText
+ dw PnP_PickyText
+ dw PnP_SortOfOKText
+ dw PnP_SoSoText
+ dw PnP_GreatText
+ dw PnP_MyTypeText
+ dw PnP_CoolText
+ dw PnP_InspiringText
+ dw PnP_WeirdText
+ dw PnP_RightForMeText
+ dw PnP_OddText
+
+PnP_CuteText:
+ text_far _PnP_CuteText
+ text_end
+
+PnP_LazyText:
+ text_far _PnP_LazyText
+ text_end
+
+PnP_HappyText:
+ text_far _PnP_HappyText
+ text_end
+
+PnP_NoisyText:
+ text_far _PnP_NoisyText
+ text_end
+
+PnP_PrecociousText:
+ text_far _PnP_PrecociousText
+ text_end
+
+PnP_BoldText:
+ text_far _PnP_BoldText
+ text_end
+
+PnP_PickyText:
+ text_far _PnP_PickyText
+ text_end
+
+PnP_SortOfOKText:
+ text_far _PnP_SortOfOKText
+ text_end
+
+PnP_SoSoText:
+ text_far _PnP_SoSoText
+ text_end
+
+PnP_GreatText:
+ text_far _PnP_GreatText
+ text_end
+
+PnP_MyTypeText:
+ text_far _PnP_MyTypeText
+ text_end
+
+PnP_CoolText:
+ text_far _PnP_CoolText
+ text_end
+
+PnP_InspiringText:
+ text_far _PnP_InspiringText
+ text_end
+
+PnP_WeirdText:
+ text_far _PnP_WeirdText
+ text_end
+
+PnP_RightForMeText:
+ text_far _PnP_RightForMeText
+ text_end
+
+PnP_OddText:
+ text_far _PnP_OddText
+ text_end
+
+PeoplePlaces6: ; Places
+ call Random
+ cp (PnP_Places.End - PnP_Places) / 2
+ jr nc, PeoplePlaces6
+ ld hl, PnP_Places
+ ld c, a
+ ld b, 0
+ add hl, bc
+ add hl, bc
+ ld b, [hl]
+ inc hl
+ ld c, [hl]
+ call GetWorldMapLocation
+ ld e, a
+ callfar GetLandmarkName
+ ld hl, PnP_Text5
+ ld a, PLACES_AND_PEOPLE_7
+ jp NextRadioLine
+
+INCLUDE "data/radio/pnp_places.asm"
+
+PnP_Text5:
+ text_far _PnP_Text5
+ text_end
+
+PeoplePlaces7:
+ ; 0-15 are all valid indexes into .Adjectives,
+ ; so no need for a retry loop
+ call Random
+ maskbits NUM_PNP_PLACES_ADJECTIVES
+ ld e, a
+ ld d, 0
+ ld hl, .Adjectives
+ add hl, de
+ add hl, de
+ ld a, [hli]
+ ld h, [hl]
+ ld l, a
+ call CopyRadioTextToRAM
+ call Random
+ cp 4 percent
+ ld a, PLACES_AND_PEOPLE
+ jr c, .ok
+ call Random
+ cp 49 percent - 1
+ ld a, PLACES_AND_PEOPLE_4 ; People
+ jr c, .ok
+ ld a, PLACES_AND_PEOPLE_6 ; Places
+.ok
+ jp PrintRadioLine
+
+.Adjectives:
+; there are NUM_PNP_PLACES_ADJECTIVES entries
+ dw PnP_CuteText
+ dw PnP_LazyText
+ dw PnP_HappyText
+ dw PnP_NoisyText
+ dw PnP_PrecociousText
+ dw PnP_BoldText
+ dw PnP_PickyText
+ dw PnP_SortOfOKText
+ dw PnP_SoSoText
+ dw PnP_GreatText
+ dw PnP_MyTypeText
+ dw PnP_CoolText
+ dw PnP_InspiringText
+ dw PnP_WeirdText
+ dw PnP_RightForMeText
+ dw PnP_OddText
+
+RocketRadio1:
+ call StartRadioStation
+ ld hl, RocketRadioText1
+ ld a, ROCKET_RADIO_2
+ jp NextRadioLine
+
+RocketRadio2:
+ ld hl, RocketRadioText2
+ ld a, ROCKET_RADIO_3
+ jp NextRadioLine
+
+RocketRadio3:
+ ld hl, RocketRadioText3
+ ld a, ROCKET_RADIO_4
+ jp NextRadioLine
+
+RocketRadio4:
+ ld hl, RocketRadioText4
+ ld a, ROCKET_RADIO_5
+ jp NextRadioLine
+
+RocketRadio5:
+ ld hl, RocketRadioText5
+ ld a, ROCKET_RADIO_6
+ jp NextRadioLine
+
+RocketRadio6:
+ ld hl, RocketRadioText6
+ ld a, ROCKET_RADIO_7
+ jp NextRadioLine
+
+RocketRadio7:
+ ld hl, RocketRadioText7
+ ld a, ROCKET_RADIO_8
+ jp NextRadioLine
+
+RocketRadio8:
+ ld hl, RocketRadioText8
+ ld a, ROCKET_RADIO_9
+ jp NextRadioLine
+
+RocketRadio9:
+ ld hl, RocketRadioText9
+ ld a, ROCKET_RADIO_10
+ jp NextRadioLine
+
+RocketRadio10:
+ ld hl, RocketRadioText10
+ ld a, ROCKET_RADIO
+ jp NextRadioLine
+
+RocketRadioText1:
+ text_far _RocketRadioText1
+ text_end
+
+RocketRadioText2:
+ text_far _RocketRadioText2
+ text_end
+
+RocketRadioText3:
+ text_far _RocketRadioText3
+ text_end
+
+RocketRadioText4:
+ text_far _RocketRadioText4
+ text_end
+
+RocketRadioText5:
+ text_far _RocketRadioText5
+ text_end
+
+RocketRadioText6:
+ text_far _RocketRadioText6
+ text_end
+
+RocketRadioText7:
+ text_far _RocketRadioText7
+ text_end
+
+RocketRadioText8:
+ text_far _RocketRadioText8
+ text_end
+
+RocketRadioText9:
+ text_far _RocketRadioText9
+ text_end
+
+RocketRadioText10:
+ text_far _RocketRadioText10
+ text_end
+
+PokeFluteRadio:
+ call StartRadioStation
+ ld a, 1
+ ld [wNumRadioLinesPrinted], a
+ ret
+
+UnownRadio:
+ call StartRadioStation
+ ld a, 1
+ ld [wNumRadioLinesPrinted], a
+ ret
+
+EvolutionRadio:
+ call StartRadioStation
+ ld a, 1
+ ld [wNumRadioLinesPrinted], a
+ ret
+
+CopyRadioTextToRAM:
+ ld a, [hl]
+ cp TX_FAR
+ jp z, FarCopyRadioText
+ ld de, wRadioText
+ ld bc, SCREEN_WIDTH * 2
+ jp CopyBytes
+
+StartRadioStation:
+ ld a, [wNumRadioLinesPrinted]
+ and a
+ ret nz
+ call RadioTerminator
+ call PrintText
+ ld hl, RadioChannelSongs
+ ld a, [wCurRadioLine]
+ ld c, a
+ ld b, 0
+ add hl, bc
+ add hl, bc
+ ld e, [hl]
+ inc hl
+ ld d, [hl]
+ callfar RadioMusicRestartDE
+ ret
+
+INCLUDE "data/radio/channel_music.asm"
+
+NextRadioLine:
+ push af
+ call CopyRadioTextToRAM
+ pop af
+ jp PrintRadioLine
diff --git a/engine/billspctop.asm b/engine/pokemon/bills_pc_top.asm
index b0ec59a5..0975c750 100644
--- a/engine/billspctop.asm
+++ b/engine/pokemon/bills_pc_top.asm
@@ -1,82 +1,81 @@
-BillsPC_:
- call BillsPC_CheckHavePokemon
+_BillsPC:
+ call .CheckCanUsePC
ret c
- call BillsPC_LogIn
- call BillsPC_UsePC
- jp BillsPC_LogOut
+ call .LogIn
+ call .UseBillsPC
+ jp .LogOut
-BillsPC_CheckHavePokemon: ; e3e5 (3:63e5)
- ld a, [wPokemonData]
+.CheckCanUsePC:
+ ld a, [wPartyCount]
and a
ret nz
- ld hl, Text_GottaHavePokemon
+ ld hl, .PCGottaHavePokemonText
call MenuTextboxBackup
scf
ret
-Text_GottaHavePokemon:
- text_far Text_GottaHavePokemon_
- db "@"
+.PCGottaHavePokemonText:
+ text_far _PCGottaHavePokemonText
+ text_end
-BillsPC_LogIn: ; e3f7 (3:63f7)
+.LogIn:
xor a
ldh [hBGMapMode], a
call LoadStandardMenuHeader
- call Functione566
+ call ClearPCItemScreen
ld hl, wOptions
ld a, [hl]
push af
- set 4, [hl]
- ld hl, Text_BillsPCWhat
+ set NO_TEXT_SCROLL, [hl]
+ ld hl, .PCWhatText
call PrintText
pop af
ld [wOptions], a
- call Functionda5
+ call LoadFontsBattleExtra
ret
-Text_BillsPCWhat:
- text_far Text_BillsPCWhat_
- db "@"
+.PCWhatText:
+ text_far _PCWhatText
+ text_end
-BillsPC_LogOut: ; e41a (3:641a)
+.LogOut:
call CloseSubmenu
ret
-BillsPC_UsePC: ; e41e (3:641e)
- ld hl, BillsPC_TopMenuDataHeader
+.UseBillsPC:
+ ld hl, .MenuHeader
call LoadMenuHeader
ld a, $1
-.asm_e426
+.loop
ld [wMenuCursorBuffer], a
call SetPalettes
xor a
ld [wWhichIndexSet], a
ldh [hBGMapMode], a
call DoNthMenu
- jr c, .asm_e446
+ jr c, .cancel
ld a, [wMenuCursorBuffer]
push af
ld a, [wMenuSelection]
- ld hl, BillsPC_TopMenuJumptable
+ ld hl, .Jumptable
rst JumpTable
pop bc
ld a, b
- jr nc, .asm_e426
-.asm_e446
+ jr nc, .loop
+.cancel
call CloseWindow
ret
-BillsPC_TopMenuDataHeader:
- db $40
- db 00, 00
- db 17, 19
- dw .MenuData2
- db 1
-
-.MenuData2:
- db $80
- db 0
- dw BillsPC_TopMenuItems
+.MenuHeader:
+ db MENU_BACKUP_TILES ; flags
+ menu_coords 0, 0, SCREEN_WIDTH - 1, SCREEN_HEIGHT - 1
+ dw .MenuData
+ db 1 ; default option
+
+.MenuData:
+ db STATICMENU_CURSOR ; flags
+ db 0 ; items
+ dw .items
dw PlaceMenuStrings
dw .strings
@@ -87,16 +86,20 @@ BillsPC_TopMenuDataHeader:
db "MOVE <PK><MN> W/O MAIL@"
db "SEE YA!@"
-BillsPC_TopMenuJumptable:
+.Jumptable:
dw BillsPC_WithdrawMenu
dw BillsPC_DepositMenu
dw BillsPC_ChangeBoxMenu
dw BillsPC_MovePKMNMenu
dw BillsPC_SeeYa
-BillsPC_TopMenuItems:
- db 5
- db 0, 1, 2, 3, 4
+.items
+ db 5 ; # items
+ db 0 ; WITHDRAW
+ db 1 ; DEPOSIT
+ db 2 ; CHANGE BOX
+ db 3 ; MOVE PKMN
+ db 4 ; SEE YA!
db -1
BillsPC_SeeYa:
@@ -105,125 +108,127 @@ BillsPC_SeeYa:
BillsPC_MovePKMNMenu:
call LoadStandardMenuHeader
- farcall IsAnyPokemonHoldingMail ; 11:488c
- jr nc, .asm_e4bb
- ld hl, Text_PleaseRemoveMailBeforeMovePkmnWOMail
+ farcall IsAnyMonHoldingMail
+ jr nc, .no_mail
+ ld hl, .PCMonHoldingMailText
call PrintText
- jr .asm_e4cf
+ jr .quit
-.asm_e4bb
- farcall StartMovePkmnWOMail_SaveGame ; 5:4bd2
- jr c, .asm_e4cf
- farcall MovePKMNWithoutMail_ ; 38:6f47
+.no_mail
+ farcall StartMoveMonWOMail_SaveGame
+ jr c, .quit
+ farcall _MovePKMNWithoutMail
call ReturnToMapFromSubmenu
- call Functione566
-.asm_e4cf
+ call ClearPCItemScreen
+
+.quit
call CloseWindow
and a
ret
-Text_PleaseRemoveMailBeforeMovePkmnWOMail:
- text_far Text_PleaseRemoveMailBeforeMovePkmnWOMail_
- db "@"
+.PCMonHoldingMailText:
+ text_far _PCMonHoldingMailText
+ text_end
BillsPC_DepositMenu:
call LoadStandardMenuHeader
- farcall DepositPokemon_ ; 38:6b9e
+ farcall _DepositPKMN
call ReturnToMapFromSubmenu
- call Functione566
+ call ClearPCItemScreen
call CloseWindow
and a
ret
-Functione4ed:
+Unreferenced_Functione4ed:
ld a, [wPartyCount]
and a
- jr z, .asm_e4f9
- cp $2
- jr c, .asm_e501
+ jr z, .no_mon
+ cp 2
+ jr c, .only_one_mon
and a
ret
-.asm_e4f9
- ld hl, Text_YouDontHaveASinglePokemon
+.no_mon
+ ld hl, .PCNoSingleMonText
call MenuTextboxBackup
scf
ret
-.asm_e501
- ld hl, Text_ItsYourLastPokemon
+.only_one_mon
+ ld hl, .PCCantDepositLastMonText
call MenuTextboxBackup
scf
ret
-Text_YouDontHaveASinglePokemon:
- text_far Text_YouDontHaveASinglePokemon_
- db "@"
+.PCNoSingleMonText:
+ text_far _PCNoSingleMonText
+ text_end
-Text_ItsYourLastPokemon:
- text_far Text_ItsYourLastPokemon_
- db "@"
+.PCCantDepositLastMonText:
+ text_far _PCCantDepositLastMonText
+ text_end
-CheckCurPartyMonFainted: ; e513 (3:6513)
+CheckCurPartyMonFainted:
ld hl, wPartyMon1HP
- ld de, $30
+ ld de, PARTYMON_STRUCT_LENGTH
ld b, $0
-.asm_e51b
+.loop
ld a, [wCurPartyMon]
cp b
- jr z, .asm_e526
+ jr z, .skip
ld a, [hli]
or [hl]
- jr nz, .asm_e532
+ jr nz, .notfainted
dec hl
-.asm_e526
+
+.skip
inc b
ld a, [wPartyCount]
cp b
- jr z, .asm_e530
+ jr z, .done
add hl, de
- jr .asm_e51b
+ jr .loop
-.asm_e530
+.done
scf
ret
-.asm_e532
+.notfainted
and a
ret
BillsPC_WithdrawMenu:
call LoadStandardMenuHeader
- farcall WithdrawPokemon_ ; 38:6d71
+ farcall _WithdrawPKMN
call ReturnToMapFromSubmenu
- call Functione566
+ call ClearPCItemScreen
call CloseWindow
and a
ret
-Functione548:
+Unreferenced_Functione548:
ld a, [wPartyCount]
- cp $6
+ cp PARTY_LENGTH
jr nc, .asm_e551
and a
ret
.asm_e551
- ld hl, Text_CantTakeAnyMorePokemon
+ ld hl, PCCantTakeText
call MenuTextboxBackup
scf
ret
-Text_CantTakeAnyMorePokemon:
- text_far Text_CantTakeAnyMorePokemon_
- db "@"
+PCCantTakeText:
+ text_far _PCCantTakeText
+ text_end
BillsPC_ChangeBoxMenu:
- farcall ChangeBox_ ; 38:7d25
+ farcall _ChangeBox
and a
ret
-Functione566: ; e566 (3:6566)
+ClearPCItemScreen:
call DisableSpriteUpdates
xor a
ldh [hBGMapMode], a
@@ -237,32 +242,32 @@ Functione566: ; e566 (3:6566)
lb bc, 10, 18
call Textbox
hlcoord 0, 12
- ld bc, IncGradGBPalTable_13
+ lb bc, 4, 18
call Textbox
call WaitBGMap2
- call SetPalettes
+ call SetPalettes ; load regular palettes?
ret
-CopyBoxmonToTempMon
+CopyBoxmonToTempMon:
ld a, [wCurPartyMon]
ld hl, sBoxMon1Species
- ld bc, $20
+ ld bc, BOXMON_STRUCT_LENGTH
call AddNTimes
ld de, wTempMonSpecies
- ld bc, $20
+ ld bc, BOXMON_STRUCT_LENGTH
ld a, BANK(sBoxMon1Species)
call OpenSRAM
call CopyBytes
call CloseSRAM
ret
-Function65b4:
+Unreferenced_LoadBoxMonListing:
ld a, [wCurBox]
cp b
- jr z, .asm_e5cc
+ jr z, .same_box
ld a, b
- ld hl, Bank3BoxAddrs
- ld bc, $3
+ ld hl, .BoxAddrs
+ ld bc, 3
call AddNTimes
ld a, [hli]
push af
@@ -270,29 +275,30 @@ Function65b4:
ld h, [hl]
ld l, a
pop af
- jr .asm_e5d1
+ jr .okay
-.asm_e5cc
+.same_box
ld a, BANK(sBoxCount)
ld hl, sBoxCount
-.asm_e5d1
+
+.okay
call OpenSRAM
ld a, [hl]
- ld bc, sBoxMon1 - sBox
+ ld bc, sBoxMons - sBox
add hl, bc
ld b, a
ld c, $0
- ld de, wMisc
+ ld de, wBoxPartialData
ld a, b
and a
- jr z, .asm_e645
-.asm_e5e3
+ jr z, .empty_box
+.loop
push hl
push bc
ld a, c
- ld bc, $0
+ ld bc, sBoxMon1Species - sBoxMons
add hl, bc
- ld bc, $20
+ ld bc, BOXMON_STRUCT_LENGTH
call AddNTimes
ld a, [hl]
ld [de], a
@@ -301,6 +307,7 @@ Function65b4:
call GetBaseData
pop bc
pop hl
+
push hl
push bc
ld a, c
@@ -310,24 +317,26 @@ Function65b4:
call CopyBytes
pop bc
pop hl
+
push hl
push bc
ld a, c
- ld bc, $1f
+ ld bc, MON_LEVEL
add hl, bc
- ld bc, $20
+ ld bc, BOXMON_STRUCT_LENGTH
call AddNTimes
ld a, [hl]
ld [de], a
inc de
pop bc
pop hl
+
push hl
push bc
ld a, c
- ld bc, $15
+ ld bc, MON_DVS
add hl, bc
- ld bc, $20
+ ld bc, BOXMON_STRUCT_LENGTH
call AddNTimes
ld a, [hli]
and $f0
@@ -337,24 +346,25 @@ Function65b4:
swap a
or b
ld b, a
- ld a, [wd12d]
+ ld a, [wBaseGender]
cp b
ld a, $1
- jr c, .asm_e63d
+ jr c, .okay2
xor a
-.asm_e63d
+.okay2
ld [de], a
inc de
pop bc
pop hl
+
inc c
dec b
- jr nz, .asm_e5e3
-.asm_e645
+ jr nz, .loop
+.empty_box
call CloseSRAM
ret
-Bank3BoxAddrs:
+.BoxAddrs:
dba sBox1
dba sBox2
dba sBox3
diff --git a/engine/pokemon/breeding.asm b/engine/pokemon/breeding.asm
new file mode 100644
index 00000000..ee1afd25
--- /dev/null
+++ b/engine/pokemon/breeding.asm
@@ -0,0 +1,935 @@
+CheckBreedmonCompatibility:
+ call .CheckBreedingGroupCompatibility
+ ld c, $0
+ jp nc, .done
+ ld a, [wBreedMon1Species]
+ ld [wCurPartySpecies], a
+ ld a, [wBreedMon1DVs]
+ ld [wTempMonDVs], a
+ ld a, [wBreedMon1DVs + 1]
+ ld [wTempMonDVs + 1], a
+ ld a, TEMPMON
+ ld [wMonType], a
+ predef GetGender
+ jr c, .genderless
+ ld b, $1
+ jr nz, .breedmon2
+ inc b
+
+.breedmon2
+ push bc
+ ld a, [wBreedMon2Species]
+ ld [wCurPartySpecies], a
+ ld a, [wBreedMon2DVs]
+ ld [wTempMonDVs], a
+ ld a, [wBreedMon2DVs + 1]
+ ld [wTempMonDVs + 1], a
+ ld a, TEMPMON
+ ld [wMonType], a
+ predef GetGender
+ pop bc
+ jr c, .genderless
+ ld a, $1
+ jr nz, .compare_gender
+ inc a
+
+.compare_gender
+ cp b
+ jr nz, .compute
+
+.genderless
+ ld c, $0
+ ld a, [wBreedMon1Species]
+ cp DITTO
+ jr z, .ditto1
+ ld a, [wBreedMon2Species]
+ cp DITTO
+ jr nz, .done
+ jr .compute
+
+.ditto1
+ ld a, [wBreedMon2Species]
+ cp DITTO
+ jr z, .done
+
+.compute
+ call .CheckDVs
+ ld c, 255
+ jp z, .done
+ ld a, [wBreedMon2Species]
+ ld b, a
+ ld a, [wBreedMon1Species]
+ cp b
+ ld c, 254
+ jr z, .compare_ids
+ ld c, 128
+.compare_ids
+ ; Speed up
+ ld a, [wBreedMon1ID]
+ ld b, a
+ ld a, [wBreedMon2ID]
+ cp b
+ jr nz, .done
+ ld a, [wBreedMon1ID + 1]
+ ld b, a
+ ld a, [wBreedMon2ID + 1]
+ cp b
+ jr nz, .done
+ ld a, c
+ sub 77
+ ld c, a
+
+.done
+ ld a, c
+ ld [wBreedingCompatibility], a
+ ret
+
+.CheckDVs:
+; If Defense DVs match and the lower 3 bits of the Special DVs match,
+; avoid breeding
+ ld a, [wBreedMon1DVs]
+ and %1111
+ ld b, a
+ ld a, [wBreedMon2DVs]
+ and %1111
+ cp b
+ ret nz
+ ld a, [wBreedMon1DVs + 1]
+ and %111
+ ld b, a
+ ld a, [wBreedMon2DVs + 1]
+ and %111
+ cp b
+ ret
+
+.CheckBreedingGroupCompatibility:
+; If either mon is in the No Eggs group,
+; they are not compatible.
+ ld a, [wBreedMon2Species]
+ ld [wCurSpecies], a
+ call GetBaseData
+ ld a, [wBaseEggGroups]
+ cp EGG_NONE * $11
+ jr z, .Incompatible
+
+ ld a, [wBreedMon1Species]
+ ld [wCurSpecies], a
+ call GetBaseData
+ ld a, [wBaseEggGroups]
+ cp EGG_NONE * $11
+ jr z, .Incompatible
+
+; Ditto is automatically compatible with everything.
+; If not Ditto, load the breeding groups into b/c and d/e.
+ ld a, [wBreedMon2Species]
+ cp DITTO
+ jr z, .Compatible
+ ld [wCurSpecies], a
+ call GetBaseData
+ ld a, [wBaseEggGroups]
+ push af
+ and $f
+ ld b, a
+ pop af
+ and $f0
+ swap a
+ ld c, a
+
+ ld a, [wBreedMon1Species]
+ cp DITTO
+ jr z, .Compatible
+ ld [wCurSpecies], a
+ push bc
+ call GetBaseData
+ pop bc
+ ld a, [wBaseEggGroups]
+ push af
+ and $f
+ ld d, a
+ pop af
+ and $f0
+ swap a
+ ld e, a
+
+ ld a, d
+ cp b
+ jr z, .Compatible
+ cp c
+ jr z, .Compatible
+
+ ld a, e
+ cp b
+ jr z, .Compatible
+ cp c
+ jr z, .Compatible
+
+.Incompatible:
+ and a
+ ret
+
+.Compatible:
+ scf
+ ret
+
+DoEggStep::
+ ld de, wPartySpecies
+ ld hl, wPartyMon1Happiness
+ ld c, 0
+.loop
+ ld a, [de]
+ inc de
+ cp -1
+ ret z
+ cp EGG
+ jr nz, .next
+ dec [hl]
+ jr nz, .next
+ ld a, 1
+ and a
+ ret
+
+.next
+ push de
+ ld de, PARTYMON_STRUCT_LENGTH
+ add hl, de
+ pop de
+ jr .loop
+
+OverworldHatchEgg::
+ call RefreshScreen
+ call LoadStandardMenuHeader
+ call HatchEggs
+ call ExitAllMenus
+ call RestartMapMusic
+ jp CloseText
+
+HatchEggs:
+ ld de, wPartySpecies
+ ld hl, wPartyMon1Happiness
+ xor a
+ ld [wCurPartyMon], a
+
+.loop
+ ld a, [de]
+ inc de
+ cp -1
+ jp z, .done
+ push de
+ push hl
+ cp EGG
+ jp nz, .next
+ ld a, [hl]
+ and a
+ jp nz, .next
+ ld [hl], $78
+
+ push de
+
+ ld a, [wCurPartyMon]
+ ld hl, wPartyMon1Species
+ ld bc, PARTYMON_STRUCT_LENGTH
+ call AddNTimes
+ ld a, [hl]
+ ld [wCurPartySpecies], a
+ dec a
+ call SetSeenAndCaughtMon
+
+ ld a, [wCurPartySpecies]
+ cp TOGEPI
+ jr nz, .nottogepi
+ ; set the event flag for hatching togepi
+ ld de, EVENT_TOGEPI_HATCHED
+ ld b, SET_FLAG
+ call EventFlagAction
+.nottogepi
+
+ pop de
+
+ ld a, [wCurPartySpecies]
+ dec de
+ ld [de], a
+ ld [wNamedObjectIndexBuffer], a
+ ld [wCurSpecies], a
+ call GetPokemonName
+ xor a
+ ld [wUnusedEggHatchFlag], a
+ call GetBaseData
+ ld a, [wCurPartyMon]
+ ld hl, wPartyMon1
+ ld bc, PARTYMON_STRUCT_LENGTH
+ call AddNTimes
+ push hl
+ ld bc, MON_MAXHP
+ add hl, bc
+ ld d, h
+ ld e, l
+ pop hl
+ push hl
+ ld bc, MON_LEVEL
+ add hl, bc
+ ld a, [hl]
+ ld [wCurPartyLevel], a
+ pop hl
+ push hl
+ ld bc, MON_STATUS
+ add hl, bc
+ xor a
+ ld [hli], a
+ ld [hl], a
+ pop hl
+ push hl
+ ld bc, MON_STAT_EXP - 1
+ add hl, bc
+ ld b, FALSE
+ predef CalcMonStats
+ pop bc
+ ld hl, MON_MAXHP
+ add hl, bc
+ ld d, h
+ ld e, l
+ ld hl, MON_HP
+ add hl, bc
+ ld a, [de]
+ inc de
+ ld [hli], a
+ ld a, [de]
+ ld [hl], a
+ ld hl, MON_ID
+ add hl, bc
+ ld a, [wPlayerID]
+ ld [hli], a
+ ld a, [wPlayerID + 1]
+ ld [hl], a
+ ld a, [wCurPartyMon]
+ ld hl, wPartyMonOT
+ ld bc, NAME_LENGTH
+ call AddNTimes
+ ld d, h
+ ld e, l
+ ld hl, wPlayerName
+ call CopyBytes
+ ld hl, .Text_HatchEgg
+ call PrintText
+ ld a, [wCurPartyMon]
+ ld hl, wPartyMonNicknames
+ ld bc, MON_NAME_LENGTH
+ call AddNTimes
+ ld d, h
+ ld e, l
+ push de
+ ld hl, .BreedAskNicknameText
+ call PrintText
+ call YesNoBox
+ pop de
+ jr c, .nonickname
+
+ ld a, TRUE
+ ld [wUnusedEggHatchFlag], a
+ xor a
+ ld [wMonType], a
+ push de
+ ld b, NAME_MON
+ farcall NamingScreen
+ pop hl
+ ld de, wStringBuffer1
+ call InitName
+ jr .next
+
+.nonickname
+ ld hl, wStringBuffer1
+ ld bc, MON_NAME_LENGTH
+ call CopyBytes
+
+.next
+ ld hl, wCurPartyMon
+ inc [hl]
+ pop hl
+ ld de, PARTYMON_STRUCT_LENGTH
+ add hl, de
+ pop de
+ jp .loop
+
+.done
+ ret
+
+.Text_HatchEgg:
+ ; Huh? @ @
+ text_far Text_BreedHuh
+ text_asm
+ ld hl, wVramState
+ res 0, [hl]
+ push hl
+ push de
+ push bc
+ ld a, [wCurPartySpecies]
+ push af
+ call EggHatch_AnimationSequence
+ ld hl, .BreedClearboxText
+ call PrintText
+ pop af
+ ld [wCurPartySpecies], a
+ pop bc
+ pop de
+ pop hl
+ ld hl, .BreedEggHatchText
+ ret
+
+.BreedClearboxText:
+ text_far _BreedClearboxText
+ text_end
+
+.BreedEggHatchText:
+ text_far _BreedEggHatchText
+ text_end
+
+.BreedAskNicknameText:
+ text_far _BreedAskNicknameText
+ text_end
+
+InitEggMoves:
+ call GetHeritableMoves
+ ld d, h
+ ld e, l
+ ld b, NUM_MOVES
+.loop
+ ld a, [de]
+ and a
+ jr z, .done
+ ld hl, wEggMonMoves
+ ld c, NUM_MOVES
+.next
+ ld a, [de]
+ cp [hl]
+ jr z, .skip
+ inc hl
+ dec c
+ jr nz, .next
+ call GetEggMove
+ jr nc, .skip
+ call LoadEggMove
+
+.skip
+ inc de
+ dec b
+ jr nz, .loop
+
+.done
+ ret
+
+GetEggMove:
+ push bc
+ ld a, [wEggMonSpecies]
+ dec a
+ ld c, a
+ ld b, 0
+ ld hl, EggMovePointers
+ add hl, bc
+ add hl, bc
+ ld a, BANK(EggMovePointers)
+ call GetFarHalfword
+.loop
+ ld a, BANK("Egg Moves")
+ call GetFarByte
+ cp -1
+ jr z, .reached_end
+ ld b, a
+ ld a, [de]
+ cp b
+ jr z, .done_carry
+ inc hl
+ jr .loop
+
+.reached_end
+ call GetBreedmonMovePointer
+ ld b, NUM_MOVES
+.loop2
+ ld a, [de]
+ cp [hl]
+ jr z, .found_eggmove
+ inc hl
+ dec b
+ jr z, .inherit_tmhm
+ jr .loop2
+
+.found_eggmove
+ ld a, [wEggMonSpecies]
+ dec a
+ ld c, a
+ ld b, 0
+ ld hl, EvosAttacksPointers
+ add hl, bc
+ add hl, bc
+ ld a, BANK(EvosAttacksPointers)
+ call GetFarHalfword
+.loop3
+ ld a, BANK("Evolutions and Attacks")
+ call GetFarByte
+ inc hl
+ and a
+ jr nz, .loop3
+.loop4
+ ld a, BANK("Evolutions and Attacks")
+ call GetFarByte
+ and a
+ jr z, .inherit_tmhm
+ inc hl
+ ld a, BANK("Evolutions and Attacks")
+ call GetFarByte
+ ld b, a
+ ld a, [de]
+ cp b
+ jr z, .done_carry
+ inc hl
+ jr .loop4
+
+.inherit_tmhm
+ ld hl, TMHMMoves
+.loop5
+ ld a, BANK(TMHMMoves)
+ call GetFarByte
+ inc hl
+ and a
+ jr z, .done
+ ld b, a
+ ld a, [de]
+ cp b
+ jr nz, .loop5
+ ld [wPutativeTMHMMove], a
+ predef CanLearnTMHMMove
+ ld a, c
+ and a
+ jr z, .done
+
+.done_carry
+ pop bc
+ scf
+ ret
+
+.done
+ pop bc
+ and a
+ ret
+
+LoadEggMove:
+ push de
+ push bc
+ ld a, [de]
+ ld b, a
+ ld hl, wEggMonMoves
+ ld c, NUM_MOVES
+.loop
+ ld a, [hli]
+ and a
+ jr z, .done
+ dec c
+ jr nz, .loop
+ ld de, wEggMonMoves
+ ld hl, wEggMonMoves + 1
+ ld a, [hli]
+ ld [de], a
+ inc de
+ ld a, [hli]
+ ld [de], a
+ inc de
+ ld a, [hli]
+ ld [de], a
+
+.done
+ dec hl
+ ld [hl], b
+ ld hl, wEggMonMoves
+ ld de, wEggMonPP
+ predef FillPP
+ pop bc
+ pop de
+ ret
+
+GetHeritableMoves:
+ ld hl, wBreedMon2Moves
+ ld a, [wBreedMon1Species]
+ cp DITTO
+ jr z, .ditto1
+ ld a, [wBreedMon2Species]
+ cp DITTO
+ jr z, .ditto2
+ ld a, [wBreedMotherOrNonDitto]
+ and a
+ ret z
+ ld hl, wBreedMon1Moves
+ ret
+
+.ditto1
+ ld a, [wCurPartySpecies]
+ push af
+ ld a, [wBreedMon2Species]
+ ld [wCurPartySpecies], a
+ ld a, [wBreedMon2DVs]
+ ld [wTempMonDVs], a
+ ld a, [wBreedMon2DVs + 1]
+ ld [wTempMonDVs + 1], a
+ ld a, TEMPMON
+ ld [wMonType], a
+ predef GetGender
+ jr c, .inherit_mon2_moves
+ jr nz, .inherit_mon2_moves
+ jr .inherit_mon1_moves
+
+.ditto2
+ ld a, [wCurPartySpecies]
+ push af
+ ld a, [wBreedMon1Species]
+ ld [wCurPartySpecies], a
+ ld a, [wBreedMon1DVs]
+ ld [wTempMonDVs], a
+ ld a, [wBreedMon1DVs + 1]
+ ld [wTempMonDVs + 1], a
+ ld a, TEMPMON
+ ld [wMonType], a
+ predef GetGender
+ jr c, .inherit_mon1_moves
+ jr nz, .inherit_mon1_moves
+
+.inherit_mon2_moves
+ ld hl, wBreedMon2Moves
+ pop af
+ ld [wCurPartySpecies], a
+ ret
+
+.inherit_mon1_moves
+ ld hl, wBreedMon1Moves
+ pop af
+ ld [wCurPartySpecies], a
+ ret
+
+GetBreedmonMovePointer:
+ ld hl, wBreedMon1Moves
+ ld a, [wBreedMon1Species]
+ cp DITTO
+ ret z
+ ld a, [wBreedMon2Species]
+ cp DITTO
+ jr z, .ditto
+ ld a, [wBreedMotherOrNonDitto]
+ and a
+ ret z
+
+.ditto
+ ld hl, wBreedMon2Moves
+ ret
+
+GetEggFrontpic:
+ push de
+ ld [wCurPartySpecies], a
+ ld [wCurSpecies], a
+ call GetBaseData
+ ld hl, wBattleMonDVs
+ predef GetUnownLetter
+ pop de
+ predef_jump GetMonFrontpic
+
+Hatch_UpdateFrontpicBGMapCenter:
+ push af
+ call WaitTop
+ push hl
+ push bc
+ hlcoord 0, 0
+ ld bc, SCREEN_HEIGHT * SCREEN_WIDTH
+ ld a, " "
+ call ByteFill
+ pop bc
+ pop hl
+ ld a, b
+ ldh [hBGMapAddress + 1], a
+ ld a, c
+ ldh [hGraphicStartTile], a
+ lb bc, 7, 7
+ predef PlaceGraphic
+ pop af
+ call Hatch_LoadFrontpicPal
+ call SetPalettes
+ jp WaitBGMap
+
+EggHatch_DoAnimFrame:
+ push hl
+ push de
+ push bc
+ callfar PlaySpriteAnimations
+ call DelayFrame
+ pop bc
+ pop de
+ pop hl
+ ret
+
+EggHatch_AnimationSequence:
+ ld a, [wNamedObjectIndexBuffer]
+ ld [wJumptableIndex], a
+ ld a, [wCurSpecies]
+ push af
+ ld de, MUSIC_NONE
+ call PlayMusic
+ farcall BlankScreen
+ call DisableLCD
+ ld hl, EggHatchGFX
+ ld de, vTiles0 tile $00
+ ld bc, 2 tiles
+ ld a, BANK(EggHatchGFX)
+ call FarCopyBytes
+ farcall ClearSpriteAnims
+ ld de, vTiles2 tile $00
+ ld a, [wJumptableIndex]
+ call GetEggFrontpic
+ ld de, vTiles2 tile $31
+ ld a, EGG
+ call GetEggFrontpic
+ ld de, MUSIC_EVOLUTION
+ call PlayMusic
+ call EnableLCD
+ hlcoord 7, 4
+ ld b, HIGH(vBGMap0)
+ ld c, $31 ; Egg tiles start here
+ ld a, EGG
+ call Hatch_UpdateFrontpicBGMapCenter
+ ld c, 80
+ call DelayFrames
+ xor a
+ ld [wFrameCounter], a
+ ldh a, [hSCX]
+ ld b, a
+.outerloop
+ ld hl, wFrameCounter
+ ld a, [hl]
+ inc [hl]
+ cp 8
+ jr nc, .done
+ ld e, [hl]
+.loop
+; wobble e times
+ ld a, 2
+ ldh [hSCX], a
+ ld a, -2
+ ld [wGlobalAnimXOffset], a
+ call EggHatch_DoAnimFrame
+ ld c, 2
+ call DelayFrames
+ ld a, -2
+ ldh [hSCX], a
+ ld a, 2
+ ld [wGlobalAnimXOffset], a
+ call EggHatch_DoAnimFrame
+ ld c, 2
+ call DelayFrames
+ dec e
+ jr nz, .loop
+ ld c, 16
+ call DelayFrames
+ call EggHatch_CrackShell
+ jr .outerloop
+
+.done
+ ld de, SFX_EGG_HATCH
+ call PlaySFX
+ xor a
+ ldh [hSCX], a
+ ld [wGlobalAnimXOffset], a
+ call ClearSprites
+ call Hatch_InitShellFragments
+ hlcoord 6, 3
+ ld b, HIGH(vBGMap0)
+ ld c, $00 ; Hatchling tiles start here
+ ld a, [wJumptableIndex]
+ call Hatch_UpdateFrontpicBGMapCenter
+ call Hatch_ShellFragmentLoop
+ call WaitSFX
+ ld a, [wJumptableIndex]
+ call PlayMonCry
+ pop af
+ ld [wCurSpecies], a
+ ret
+
+Hatch_LoadFrontpicPal:
+ ld [wPlayerHPPal], a
+ ld b, SCGB_EVOLUTION
+ ld c, $0
+ jp GetSGBLayout
+
+EggHatch_CrackShell:
+ ld a, [wFrameCounter]
+ dec a
+ and $7
+ cp $7
+ ret z
+ srl a
+ ret nc
+ swap a
+ srl a
+ add 9 * 8
+ ld d, a
+ ld e, 11 * 8
+ ld a, SPRITE_ANIM_INDEX_EGG_CRACK
+ call InitSpriteAnimStruct
+ ld hl, SPRITEANIMSTRUCT_TILE_ID
+ add hl, bc
+ ld [hl], $0
+ ld de, SFX_EGG_CRACK
+ jp PlaySFX
+
+EggHatchGFX:
+INCBIN "gfx/evo/egg_hatch.2bpp"
+
+Hatch_InitShellFragments:
+ farcall ClearSpriteAnims
+ ld hl, .SpriteData
+.loop
+ ld a, [hli]
+ cp -1
+ jr z, .done
+ ld e, a
+ ld a, [hli]
+ ld d, a
+ ld a, [hli]
+ ld c, a
+ ld a, [hli]
+ ld b, a
+ push hl
+ push bc
+
+ ld a, SPRITE_ANIM_INDEX_EGG_HATCH
+ call InitSpriteAnimStruct
+
+ ld hl, SPRITEANIMSTRUCT_TILE_ID
+ add hl, bc
+ ld [hl], $0
+
+ pop de
+ ld a, e
+ ld hl, SPRITEANIMSTRUCT_FRAMESET_ID
+ add hl, bc
+ add [hl]
+ ld [hl], a
+
+ ld hl, SPRITEANIMSTRUCT_JUMPTABLE_INDEX
+ add hl, bc
+ ld [hl], d
+
+ pop hl
+ jr .loop
+.done
+ ld de, SFX_EGG_HATCH
+ call PlaySFX
+ call EggHatch_DoAnimFrame
+ ret
+
+shell_fragment: MACRO
+; y tile, y pxl, x tile, x pxl, frameset offset, ???
+ db (\1 * 8) % $100 + \2, (\3 * 8) % $100 + \4, \5 - SPRITE_ANIM_FRAMESET_EGG_HATCH_1, \6
+ENDM
+
+.SpriteData:
+ shell_fragment 10, 4, 9, 0, SPRITE_ANIM_FRAMESET_EGG_HATCH_1, $3c
+ shell_fragment 11, 4, 9, 0, SPRITE_ANIM_FRAMESET_EGG_HATCH_2, $04
+ shell_fragment 10, 4, 10, 0, SPRITE_ANIM_FRAMESET_EGG_HATCH_1, $30
+ shell_fragment 11, 4, 10, 0, SPRITE_ANIM_FRAMESET_EGG_HATCH_2, $10
+ shell_fragment 10, 4, 11, 0, SPRITE_ANIM_FRAMESET_EGG_HATCH_3, $24
+ shell_fragment 11, 4, 11, 0, SPRITE_ANIM_FRAMESET_EGG_HATCH_4, $1c
+ shell_fragment 10, 0, 9, 4, SPRITE_ANIM_FRAMESET_EGG_HATCH_1, $36
+ shell_fragment 12, 0, 9, 4, SPRITE_ANIM_FRAMESET_EGG_HATCH_2, $0a
+ shell_fragment 10, 0, 10, 4, SPRITE_ANIM_FRAMESET_EGG_HATCH_3, $2a
+ shell_fragment 12, 0, 10, 4, SPRITE_ANIM_FRAMESET_EGG_HATCH_4, $16
+ db -1
+
+Hatch_ShellFragmentLoop:
+ ld c, 129
+.loop
+ call EggHatch_DoAnimFrame
+ dec c
+ jr nz, .loop
+ ret
+
+DayCareMon1:
+ ld hl, LeftWithDayCareManText
+ call PrintText
+ ld a, [wBreedMon1Species]
+ call PlayMonCry
+ ld a, [wDayCareLady]
+ bit DAYCARELADY_HAS_MON_F, a
+ jr z, DayCareMonCursor
+ call PromptButton
+ ld hl, wBreedMon2Nick
+ call DayCareMonCompatibilityText
+ jp PrintText
+
+DayCareMon2:
+ ld hl, LeftWithDayCareLadyText
+ call PrintText
+ ld a, [wBreedMon2Species]
+ call PlayMonCry
+ ld a, [wDayCareMan]
+ bit DAYCAREMAN_HAS_MON_F, a
+ jr z, DayCareMonCursor
+ call PromptButton
+ ld hl, wBreedMon1Nick
+ call DayCareMonCompatibilityText
+ jp PrintText
+
+DayCareMonCursor:
+ jp WaitPressAorB_BlinkCursor
+
+LeftWithDayCareLadyText:
+ text_far _LeftWithDayCareLadyText
+ text_end
+
+LeftWithDayCareManText:
+ text_far _LeftWithDayCareManText
+ text_end
+
+DayCareMonCompatibilityText:
+ push bc
+ ld de, wStringBuffer1
+ ld bc, NAME_LENGTH
+ call CopyBytes
+ call CheckBreedmonCompatibility
+ pop bc
+ ld a, [wBreedingCompatibility]
+ ld hl, .BreedBrimmingWithEnergyText
+ cp -1
+ jr z, .done
+ ld hl, .BreedNoInterestText
+ and a
+ jr z, .done
+ ld hl, .BreedAppearsToCareForText
+ cp 230
+ jr nc, .done
+ cp 70
+ ld hl, .BreedFriendlyText
+ jr nc, .done
+ ld hl, .BreedShowsInterestText
+
+.done
+ ret
+
+.BreedBrimmingWithEnergyText:
+ text_far _BreedBrimmingWithEnergyText
+ text_end
+
+.BreedNoInterestText:
+ text_far _BreedNoInterestText
+ text_end
+
+.BreedAppearsToCareForText:
+ text_far _BreedAppearsToCareForText
+ text_end
+
+.BreedFriendlyText:
+ text_far _BreedFriendlyText
+ text_end
+
+.BreedShowsInterestText:
+ text_far _BreedShowsInterestText
+ text_end
+
+Unreferenced_DayCareMonPrintEmptyString:
+ ld hl, .string
+ ret
+
+.string
+ db "@"
diff --git a/engine/pokemon/breedmon_level_growth.asm b/engine/pokemon/breedmon_level_growth.asm
new file mode 100644
index 00000000..c6356dd6
--- /dev/null
+++ b/engine/pokemon/breedmon_level_growth.asm
@@ -0,0 +1,27 @@
+GetBreedMon1LevelGrowth:
+ ld hl, wBreedMon1Stats
+ ld de, wTempMon
+ ld bc, BOXMON_STRUCT_LENGTH
+ call CopyBytes
+ callfar CalcLevel
+ ld a, [wBreedMon1Level]
+ ld b, a
+ ld a, d
+ ld e, a
+ sub b
+ ld d, a
+ ret
+
+GetBreedMon2LevelGrowth:
+ ld hl, wBreedMon2Stats
+ ld de, wTempMon
+ ld bc, BOXMON_STRUCT_LENGTH
+ call CopyBytes
+ callfar CalcLevel
+ ld a, [wBreedMon2Level]
+ ld b, a
+ ld a, d
+ ld e, a
+ sub b
+ ld d, a
+ ret
diff --git a/engine/pokemon/correct_nick_errors.asm b/engine/pokemon/correct_nick_errors.asm
new file mode 100644
index 00000000..421bf92d
--- /dev/null
+++ b/engine/pokemon/correct_nick_errors.asm
@@ -0,0 +1,74 @@
+CorrectNickErrors::
+; error-check monster nick before use
+; must be a peace offering to gamesharkers
+
+; input: de = nick location
+
+ push bc
+ push de
+ ld b, MON_NAME_LENGTH
+
+.checkchar
+; end of nick?
+ ld a, [de]
+ cp "@" ; terminator
+ jr z, .end
+
+; check if this char is a text command
+ ld hl, .textcommands
+ dec hl
+.loop
+; next entry
+ inc hl
+; reached end of commands table?
+ ld a, [hl]
+ cp -1
+ jr z, .done
+
+; is the current char between this value (inclusive)...
+ ld a, [de]
+ cp [hl]
+ inc hl
+ jr c, .loop
+; ...and this one?
+ cp [hl]
+ jr nc, .loop
+
+; replace it with a "?"
+ ld a, "?"
+ ld [de], a
+ jr .loop
+
+.done
+; next char
+ inc de
+; reached end of nick without finding a terminator?
+ dec b
+ jr nz, .checkchar
+
+; change nick to "?@"
+ pop de
+ push de
+ ld a, "?"
+ ld [de], a
+ inc de
+ ld a, "@"
+ ld [de], a
+.end
+; if the nick has any errors at this point it's out of our hands
+ pop de
+ pop bc
+ ret
+
+.textcommands
+; table defining which characters are actually text commands
+; format:
+ ; ≥ <
+ db "<NULL>", "ガ"
+ db "<PLAY_G>", "<JP_18>" + 1
+ db "<NI>", "<NO>" + 1
+ db "<ROUTE>", "<GREEN>" + 1
+ db "<ENEMY>", "<ENEMY>" + 1
+ db "<MOM>", "<TM>" + 1
+ db "<ROCKET>", "┘" + 1
+ db -1 ; end
diff --git a/engine/health.asm b/engine/pokemon/health.asm
index a94a3ec3..d11a073b 100755
--- a/engine/health.asm
+++ b/engine/pokemon/health.asm
@@ -1,54 +1,62 @@
-HealParty: ; c69d (3:469d)
+HealParty:
xor a
ld [wCurPartyMon], a
ld hl, wPartySpecies
-.asm_c6a4
+.loop
ld a, [hli]
- cp $ff
- jr z, .asm_c6bb
- cp $fd
- jr z, .asm_c6b2
+ cp -1
+ jr z, .done
+ cp EGG
+ jr z, .next
+
push hl
- call Functionc6bc
+ call HealPartyMon
pop hl
-.asm_c6b2
+
+.next
ld a, [wCurPartyMon]
inc a
ld [wCurPartyMon], a
- jr .asm_c6a4
+ jr .loop
-.asm_c6bb
+.done
ret
-Functionc6bc: ; c6bc (3:46bc)
- ld a, $0
+HealPartyMon:
+ ld a, MON_SPECIES
call GetPartyParamLocation
ld d, h
ld e, l
- ld hl, $20
+
+ ld hl, MON_STATUS
add hl, de
xor a
ld [hli], a
ld [hl], a
- ld hl, $24
+
+ ld hl, MON_MAXHP
add hl, de
+
+ ; bc = MON_HP
ld b, h
ld c, l
dec bc
dec bc
+
ld a, [hli]
ld [bc], a
inc bc
ld a, [hl]
ld [bc], a
- farcall Functionf900
+
+ farcall RestoreAllPP
ret
ComputeHPBarPixels:
; e = bc * (6 * 8) / de
ld a, b
or c
- jr z, .asm_c722
+ jr z, .zero
push hl
xor a
ldh [hMultiplicand + 0], a
@@ -62,7 +70,7 @@ ComputeHPBarPixels:
; We need de to be under 256 because hDivisor is only 1 byte.
ld a, d
and a
- jr z, .asm_c711
+ jr z, .divide
; divide de and hProduct by 4
srl d
rr e
@@ -78,25 +86,25 @@ ComputeHPBarPixels:
ldh [hDividend + 3], a
ld a, b
ldh [hDividend + 2], a
-.asm_c711
+.divide
ld a, e
- ldh [hPrintNum5], a
- ld b, $4
+ ldh [hDivisor], a
+ ld b, 4
call Divide
- ldh a, [hPrintNum4]
+ ldh a, [hQuotient + 3]
ld e, a
pop hl
and a
ret nz
- ld e, $1
+ ld e, 1
ret
-.asm_c722
- ld e, $0
+.zero
+ ld e, 0
ret
-AnimateHPBar: ; c725 (3:4725)
+AnimateHPBar:
call WaitBGMap
- call AnimateHPBar_
+ call _AnimateHPBar
call WaitBGMap
ret
diff --git a/engine/pokemon/knows_move.asm b/engine/pokemon/knows_move.asm
new file mode 100644
index 00000000..9fe0f6ac
--- /dev/null
+++ b/engine/pokemon/knows_move.asm
@@ -0,0 +1,24 @@
+KnowsMove:
+ ld a, MON_MOVES
+ call GetPartyParamLocation
+ ld a, [wPutativeTMHMMove]
+ ld b, a
+ ld c, NUM_MOVES
+.loop
+ ld a, [hli]
+ cp b
+ jr z, .knows_move
+ dec c
+ jr nz, .loop
+ and a
+ ret
+
+.knows_move
+ ld hl, .KnowsMoveText
+ call PrintText
+ scf
+ ret
+
+.KnowsMoveText:
+ text_far _KnowsMoveText
+ text_end
diff --git a/engine/pokemon/learn.asm b/engine/pokemon/learn.asm
new file mode 100644
index 00000000..2c66dcd5
--- /dev/null
+++ b/engine/pokemon/learn.asm
@@ -0,0 +1,239 @@
+LearnMove:
+ call LoadTilemapToTempTilemap
+ ld a, [wCurPartyMon]
+ ld hl, wPartyMonNicknames
+ call GetNick
+ ld hl, wStringBuffer1
+ ld de, wMonOrItemNameBuffer
+ ld bc, MON_NAME_LENGTH
+ call CopyBytes
+
+.loop
+ ld hl, wPartyMon1Moves
+ ld bc, PARTYMON_STRUCT_LENGTH
+ ld a, [wCurPartyMon]
+ call AddNTimes
+ ld d, h
+ ld e, l
+ ld b, NUM_MOVES
+; Get the first empty move slot. This routine also serves to
+; determine whether the Pokemon learning the moves already has
+; all four slots occupied, in which case one would need to be
+; deleted.
+.next
+ ld a, [hl]
+ and a
+ jr z, .learn
+ inc hl
+ dec b
+ jr nz, .next
+; If we're here, we enter the routine for forgetting a move
+; to make room for the new move we're trying to learn.
+ push de
+ call ForgetMove
+ pop de
+ jp c, .cancel
+
+ push hl
+ push de
+ ld [wNamedObjectIndexBuffer], a
+
+ ld b, a
+ ld a, [wBattleMode]
+ and a
+ jr z, .not_disabled
+ ld a, [wDisabledMove]
+ cp b
+ jr nz, .not_disabled
+ xor a
+ ld [wDisabledMove], a
+ ld [wPlayerDisableCount], a
+.not_disabled
+
+ call GetMoveName
+ ld hl, Text_1_2_and_Poof ; 1, 2 and…
+ call PrintText
+ pop de
+ pop hl
+
+.learn
+ ld a, [wPutativeTMHMMove]
+ ld [hl], a
+ ld bc, MON_PP - MON_MOVES
+ add hl, bc
+
+ push hl
+ push de
+ dec a
+ ld hl, Moves + MOVE_PP
+ ld bc, MOVE_LENGTH
+ call AddNTimes
+ ld a, BANK(Moves)
+ call GetFarByte
+ pop de
+ pop hl
+
+ ld [hl], a
+
+ ld a, [wBattleMode]
+ and a
+ jp z, .learned
+
+ ld a, [wCurPartyMon]
+ ld b, a
+ ld a, [wCurBattleMon]
+ cp b
+ jp nz, .learned
+
+ ld a, [wPlayerSubStatus5]
+ bit SUBSTATUS_TRANSFORMED, a
+ jp nz, .learned
+
+ ld h, d
+ ld l, e
+ ld de, wBattleMonMoves
+ ld bc, NUM_MOVES
+ call CopyBytes
+ ld bc, wPartyMon1PP - (wPartyMon1Moves + NUM_MOVES)
+ add hl, bc
+ ld de, wBattleMonPP
+ ld bc, NUM_MOVES
+ call CopyBytes
+ jp .learned
+
+.cancel
+ ld hl, StopLearningMoveText
+ call PrintText
+ call YesNoBox
+ jp c, .loop
+
+ ld hl, DidNotLearnMoveText
+ call PrintText
+ ld b, 0
+ ret
+
+.learned
+ ld hl, LearnedMoveText
+ call PrintText
+ ld b, 1
+ ret
+
+ForgetMove:
+ push hl
+ ld hl, AskForgetMoveText
+ call PrintText
+ call YesNoBox
+ pop hl
+ ret c
+ ld bc, -NUM_MOVES
+ add hl, bc
+ push hl
+ ld de, wListMoves_MoveIndicesBuffer
+ ld bc, NUM_MOVES
+ call CopyBytes
+ pop hl
+.loop
+ push hl
+ ld hl, MoveAskForgetText
+ call PrintText
+ hlcoord 5, 2
+ ld b, NUM_MOVES * 2
+ ld c, MOVE_NAME_LENGTH
+ call Textbox
+ hlcoord 5 + 2, 2 + 2
+ ld a, SCREEN_WIDTH * 2
+ ld [wBuffer1], a
+ predef ListMoves
+ ; w2DMenuData
+ ld a, $4
+ ld [w2DMenuCursorInitY], a
+ ld a, $6
+ ld [w2DMenuCursorInitX], a
+ ld a, [wNumMoves]
+ inc a
+ ld [w2DMenuNumRows], a
+ ld a, $1
+ ld [w2DMenuNumCols], a
+ ld [wMenuCursorY], a
+ ld [wMenuCursorX], a
+ ld a, $3
+ ld [wMenuJoypadFilter], a
+ ld a, $20
+ ld [w2DMenuFlags1], a
+ xor a
+ ld [w2DMenuFlags2], a
+ ld a, $20
+ ld [w2DMenuCursorOffsets], a
+ call StaticMenuJoypad
+ push af
+ call SafeLoadTempTilemapToTilemap
+ pop af
+ pop hl
+ bit 1, a
+ jr nz, .cancel
+ push hl
+ ld a, [wMenuCursorY]
+ dec a
+ ld c, a
+ ld b, 0
+ add hl, bc
+ ld a, [hl]
+ push af
+ push bc
+ call IsHMMove
+ pop bc
+ pop de
+ ld a, d
+ jr c, .hmmove
+ pop hl
+ add hl, bc
+ and a
+ ret
+
+.hmmove
+ ld hl, MoveCantForgetHMText
+ call PrintText
+ pop hl
+ jr .loop
+
+.cancel
+ scf
+ ret
+
+LearnedMoveText:
+ text_far _LearnedMoveText
+ text_end
+
+MoveAskForgetText:
+ text_far _MoveAskForgetText
+ text_end
+
+StopLearningMoveText:
+ text_far _StopLearningMoveText
+ text_end
+
+DidNotLearnMoveText:
+ text_far _DidNotLearnMoveText
+ text_end
+
+AskForgetMoveText:
+ text_far _AskForgetMoveText
+ text_end
+
+Text_1_2_and_Poof:
+ text_far Text_MoveForgetCount ; 1, 2 and…
+ text_asm
+ push de
+ ld de, SFX_SWITCH_POKEMON
+ call PlaySFX
+ pop de
+ ld hl, .MoveForgotText
+ ret
+
+.MoveForgotText:
+ text_far _MoveForgotText
+ text_end
+
+MoveCantForgetHMText:
+ text_far _MoveCantForgetHMText
+ text_end
diff --git a/engine/pokemon/mail_2.asm b/engine/pokemon/mail_2.asm
new file mode 100644
index 00000000..f7cfe5c7
--- /dev/null
+++ b/engine/pokemon/mail_2.asm
@@ -0,0 +1,901 @@
+ReadPartyMonMail:
+ ld a, [wCurPartyMon]
+ ld hl, sPartyMail
+ ld bc, MAIL_STRUCT_LENGTH
+ call AddNTimes
+ ld d, h
+ ld e, l
+ReadAnyMail:
+ push de
+ call ClearBGPalettes
+ call ClearSprites
+ call ClearTilemap
+ call DisableLCD
+ call LoadFontsExtra
+ pop de
+ call .LoadGFX
+ call EnableLCD
+ call WaitBGMap
+ ld a, [wBuffer3]
+ ld e, a
+ farcall LoadMailPalettes
+ call SetPalettes
+ xor a
+ ldh [hJoyPressed], a
+ call .loop
+ call ClearBGPalettes
+ call DisableLCD
+ call LoadStandardFont
+ jp EnableLCD
+
+.loop
+ call GetJoypad
+ ldh a, [hJoyPressed]
+ and A_BUTTON | B_BUTTON | START
+ jr z, .loop
+ and START
+ jr nz, .pressed_start
+ ret
+
+.pressed_start
+ ld a, [wJumptableIndex]
+ push af
+ callfar PrintMailAndExit ; printer
+ pop af
+ ld [wJumptableIndex], a
+ jr .loop
+
+.LoadGFX:
+ ld h, d
+ ld l, e
+ push hl
+ ld a, BANK(sPartyMail)
+ call OpenSRAM
+ ld de, sPartyMon1MailAuthorID - sPartyMon1Mail
+ add hl, de
+ ld a, [hli]
+ ld [wBuffer1], a
+ ld a, [hli]
+ ld [wBuffer2], a
+ ld a, [hli]
+ ld [wCurPartySpecies], a
+ ld b, [hl]
+ call CloseSRAM
+ ld hl, MailGFXPointers
+ ld c, 0
+.loop2
+ ld a, [hli]
+ cp b
+ jr z, .got_pointer
+ cp -1
+ jr z, .invalid
+ inc c
+ inc hl
+ inc hl
+ jr .loop2
+
+.invalid
+ ld hl, MailGFXPointers
+ inc hl
+
+.got_pointer
+ ld a, c
+ ld [wBuffer3], a
+ ld a, [hli]
+ ld h, [hl]
+ ld l, a
+ ld de, .done
+ pop bc
+ push de
+ jp hl
+.done
+ ret
+
+MailGFXPointers:
+ dbw FLOWER_MAIL, LoadFlowerMailGFX
+ dbw SURF_MAIL, LoadSurfMailGFX
+ dbw LITEBLUEMAIL, LoadLiteBlueMailGFX
+ dbw PORTRAITMAIL, LoadPortraitMailGFX
+ dbw LOVELY_MAIL, LoadLovelyMailGFX
+ dbw EON_MAIL, LoadEonMailGFX
+ dbw MORPH_MAIL, LoadMorphMailGFX
+ dbw BLUESKY_MAIL, LoadBlueSkyMailGFX
+ dbw MUSIC_MAIL, LoadMusicMailGFX
+ dbw MIRAGE_MAIL, LoadMirageMailGFX
+ db -1
+
+LoadSurfMailGFX:
+ push bc
+ ld hl, vTiles2 tile $31
+ ld de, SurfMailBorderGFX
+ ld c, 8 * LEN_1BPP_TILE
+ call LoadMailGFX_Color2
+ ld de, MailLaprasGFX
+ ld c, 6 * LEN_1BPP_TILE
+ call LoadMailGFX_Color3
+ ld de, SurfMailWaveGFX
+ ld c, 1 * LEN_1BPP_TILE
+ call LoadMailGFX_Color2
+ jr FinishLoadingSurfLiteBlueMailGFX
+
+LoadLiteBlueMailGFX:
+ push bc
+ ld hl, vTiles2 tile $31
+ ld de, LiteBlueMailBorderGFX
+ ld c, 8 * LEN_1BPP_TILE
+ call LoadMailGFX_Color2
+ ld de, MailDratiniGFX
+ ld c, 6 * LEN_1BPP_TILE
+ call LoadMailGFX_Color3
+ ld de, PortraitMailUnderlineGFX
+ ld c, 1 * LEN_1BPP_TILE
+ call LoadMailGFX_Color2
+
+FinishLoadingSurfLiteBlueMailGFX:
+ ld de, SurfLiteBlueMailSmallShapesGFX
+ ld c, 2 * LEN_1BPP_TILE
+ call LoadMailGFX_Color2
+ ld c, 2 * LEN_1BPP_TILE
+ call LoadMailGFX_Color1
+ ld de, SurfLiteBlueMailLargeShapesGFX
+ ld c, 8 * LEN_1BPP_TILE
+ call LoadMailGFX_Color1
+ ld c, 8 * LEN_1BPP_TILE
+ call LoadMailGFX_Color2
+
+ call DrawMailBorder
+ hlcoord 2, 15
+ ld a, $3f
+ call Mail_Draw16TileRow
+ ld a, $39
+ hlcoord 15, 14
+ call Mail_Draw3x2Graphic
+ ld a, $44
+ hlcoord 2, 2
+ call Mail_Draw2x2Graphic
+ hlcoord 15, 11
+ call Mail_Draw2x2Graphic
+ ld a, $4c
+ hlcoord 3, 12
+ call Mail_Draw2x2Graphic
+ hlcoord 15, 2
+ call Mail_Draw2x2Graphic
+ ld a, $50
+ hlcoord 6, 3
+ call Mail_Draw2x2Graphic
+ ld a, $40
+ hlcoord 13, 2
+ ld [hli], a
+ hlcoord 6, 14
+ ld [hl], a
+ ld a, $41
+ hlcoord 4, 5
+ ld [hli], a
+ hlcoord 17, 5
+ ld [hli], a
+ hlcoord 13, 12
+ ld [hl], a
+ ld a, $42
+ hlcoord 9, 2
+ ld [hli], a
+ hlcoord 14, 5
+ ld [hli], a
+ hlcoord 3, 10
+ ld [hl], a
+ ld a, $43
+ hlcoord 6, 11
+ ld [hli], a
+ pop hl
+ jp MailGFX_PlaceMessage
+
+LoadEonMailGFX:
+ push bc
+ ld hl, vTiles2 tile $31
+ ld de, EonMailBorder1GFX
+ ld c, 1 * LEN_1BPP_TILE
+ call LoadMailGFX_Color2
+ ld de, EonMailBorder2GFX
+ ld c, 1 * LEN_1BPP_TILE
+ call LoadMailGFX_Color1
+ ld de, EonMailBorder2GFX
+ ld c, 1 * LEN_1BPP_TILE
+ call LoadMailGFX_Color1
+ ld de, EonMailBorder1GFX
+ ld c, 1 * LEN_1BPP_TILE
+ call LoadMailGFX_Color2
+ ld de, SurfMailBorderGFX + 6 * LEN_1BPP_TILE
+ ld c, 1 * LEN_1BPP_TILE
+ call LoadMailGFX_Color2
+ ld de, MailEeveeGFX
+ ld c, 6 * LEN_1BPP_TILE
+ call LoadMailGFX_Color3
+ ld hl, vTiles2 tile $3d
+ ld de, MailLargeCircleGFX
+ ld c, 4 * LEN_1BPP_TILE
+ call LoadMailGFX_Color1
+ ld de, EonMailBorder2GFX
+ ld c, 1 * LEN_1BPP_TILE
+ call LoadMailGFX_Color2
+
+ ld a, $31
+ hlcoord 0, 0
+ call Mail_Place18TileAlternatingRow
+ hlcoord 1, 17
+ call Mail_Place18TileAlternatingRow
+ ld a, $33
+ hlcoord 0, 1
+ call Mail_Place16TileAlternatingColumn
+ hlcoord 19, 0
+ call Mail_Place16TileAlternatingColumn
+ hlcoord 2, 15
+ ld a, $35
+ call Mail_Draw16TileRow
+ inc a
+ hlcoord 15, 14
+ call Mail_Draw3x2Graphic
+ call LovelyEonMail_PlaceIcons
+ pop hl
+ jp MailGFX_PlaceMessage
+
+LoadLovelyMailGFX:
+ push bc
+ ld hl, vTiles2 tile $31
+ ld de, LovelyMailBorderGFX
+ ld c, 5 * LEN_1BPP_TILE
+ call LoadMailGFX_Color2
+ ld de, MailPoliwagGFX
+ ld c, 6 * LEN_1BPP_TILE
+ call LoadMailGFX_Color3
+ ld de, LovelyMailUnderlineGFX
+ ld c, 1 * LEN_1BPP_TILE
+ call LoadMailGFX_Color2
+ ld de, LovelyMailLargeHeartGFX
+ ld c, 4 * LEN_1BPP_TILE
+ call LoadMailGFX_Color2
+ ld de, LovelyMailSmallHeartGFX
+ ld c, 1 * LEN_1BPP_TILE
+ call LoadMailGFX_Color1
+
+ call DrawMailBorder2
+ hlcoord 2, 15
+ ld a, $3c
+ call Mail_Draw16TileRow
+ ld a, $36
+ hlcoord 15, 14
+ call Mail_Draw3x2Graphic
+ call LovelyEonMail_PlaceIcons
+ pop hl
+ jp MailGFX_PlaceMessage
+
+LovelyEonMail_PlaceIcons:
+ ld a, $3d
+ hlcoord 2, 2
+ call Mail_Draw2x2Graphic
+ hlcoord 16, 2
+ call Mail_Draw2x2Graphic
+ hlcoord 9, 4
+ call Mail_Draw2x2Graphic
+ hlcoord 2, 11
+ call Mail_Draw2x2Graphic
+ hlcoord 6, 12
+ call Mail_Draw2x2Graphic
+ hlcoord 12, 11
+ call Mail_Draw2x2Graphic
+ ld a, $41
+ hlcoord 5, 4
+ ld [hl], a
+ hlcoord 6, 2
+ ld [hl], a
+ hlcoord 12, 4
+ ld [hl], a
+ hlcoord 14, 2
+ ld [hl], a
+ hlcoord 3, 13
+ ld [hl], a
+ hlcoord 9, 11
+ ld [hl], a
+ hlcoord 16, 12
+ ld [hl], a
+ ret
+
+LoadMorphMailGFX:
+ push bc
+ ld hl, vTiles2 tile $31
+ ld bc, 5 * LEN_1BPP_TILE
+ call MailGFX_GenerateMonochromeTilesColor2
+ ld de, MorphMailBorderCornerGFX + 3 * LEN_1BPP_TILE
+ ld c, 1 * LEN_1BPP_TILE
+ call LoadMailGFX_Color2
+ ld de, MorphMailBorderCornerGFX
+ ld c, 1 * LEN_1BPP_TILE
+ call LoadMailGFX_Color2
+ ld de, MorphMailBorderGFX
+ ld c, 1 * LEN_1BPP_TILE
+ call LoadMailGFX_Color2
+ ld de, EonMailBorder1GFX
+ ld c, 1 * LEN_1BPP_TILE
+ call LoadMailGFX_Color1
+ ld de, MorphMailDividerGFX
+ ld c, 1 * LEN_1BPP_TILE
+ call LoadMailGFX_Color2
+ ld de, MailDittoGFX
+ ld c, 6 * LEN_1BPP_TILE
+ call LoadMailGFX_Color3
+ call DrawMailBorder2
+ ld a, $31
+ hlcoord 1, 1
+ call Mail_Draw2x2Graphic
+ hlcoord 17, 15
+ call Mail_Draw2x2Graphic
+ hlcoord 1, 3
+ ld [hl], a
+ hlcoord 3, 1
+ ld [hl], a
+ hlcoord 16, 16
+ ld [hl], a
+ hlcoord 18, 14
+ ld [hl], a
+ ld a, $36
+ hlcoord 1, 4
+ ld [hl], a
+ hlcoord 2, 3
+ ld [hl], a
+ hlcoord 3, 2
+ ld [hl], a
+ hlcoord 4, 1
+ ld [hl], a
+ inc a
+ hlcoord 15, 16
+ ld [hl], a
+ hlcoord 16, 15
+ ld [hl], a
+ hlcoord 17, 14
+ ld [hl], a
+ hlcoord 18, 13
+ ld [hl], a
+ inc a
+ hlcoord 2, 15
+ ld b, $e
+ call Mail_DrawRowLoop
+ inc a
+ hlcoord 2, 11
+ call Mail_Draw16TileRow
+ hlcoord 2, 5
+ call Mail_Draw16TileRow
+ inc a
+ hlcoord 6, 1
+ call Mail_Draw13TileRow
+ hlcoord 1, 16
+ call Mail_Draw13TileRow
+ inc a
+ hlcoord 3, 13
+ call Mail_Draw3x2Graphic
+ pop hl
+ jp MailGFX_PlaceMessage
+
+LoadBlueSkyMailGFX:
+ push bc
+ ld hl, vTiles2 tile $31
+ ld de, EonMailBorder1GFX
+ ld c, 1 * LEN_1BPP_TILE
+ call LoadMailGFX_Color2
+ ld a, $ff
+ ld bc, 1 tiles
+ call ByteFill
+ ld de, BlueSkyMailGrassGFX
+ ld c, 1 * LEN_1BPP_TILE
+ call LoadMailGFX_Color3
+ ld de, MailDragoniteGFX
+ ld c, 23 * LEN_1BPP_TILE
+ call LoadMailGFX_Color3
+ ld de, MailCloudGFX
+ ld c, 6 * LEN_1BPP_TILE
+ call LoadMailGFX_Color1
+ ld de, FlowerMailBorderGFX + 6 * LEN_1BPP_TILE
+ ld c, 1 * LEN_1BPP_TILE
+ call LoadMailGFX_Color1
+ ld de, MailCloudGFX
+ ld c, 1 * LEN_1BPP_TILE
+ call LoadMailGFX_Color1
+ ld de, MailCloudGFX + 2 * LEN_1BPP_TILE
+ ld c, 2 * LEN_1BPP_TILE
+ call LoadMailGFX_Color1
+ ld de, MailCloudGFX + 5 * LEN_1BPP_TILE
+ ld c, 1 * LEN_1BPP_TILE
+ call LoadMailGFX_Color1
+
+ ld a, $31
+ hlcoord 0, 0
+ call Mail_DrawFullWidthBorder
+ hlcoord 0, 1
+ call Mail_DrawLeftRightBorder
+ hlcoord 19, 1
+ call Mail_DrawLeftRightBorder
+ inc a
+ hlcoord 0, 17
+ call Mail_DrawFullWidthBorder
+ inc a
+ hlcoord 0, 16
+ call Mail_DrawFullWidthBorder
+ inc a
+ hlcoord 2, 2
+ call Mail_Place6TileRow
+ hlcoord 3, 3
+ call Mail_Place6TileRow
+ hlcoord 4, 4
+ call Mail_Place6TileRow
+ dec hl
+ ld [hl], $7f
+ dec a
+ hlcoord 15, 14
+ call Mail_Draw2x2Graphic
+ add $4
+ hlcoord 15, 16
+ ld [hli], a
+ inc a
+ ld [hl], a
+ inc a
+ push af
+ hlcoord 12, 1
+ call Mail_Draw3x2Graphic
+ pop af
+ hlcoord 15, 4
+ call Mail_Draw3x2Graphic
+ inc a
+ hlcoord 2, 11
+ call Mail_Draw16TileRow
+ inc a
+ hlcoord 10, 3
+ call Mail_Draw2x2Graphic
+ pop hl
+ jp MailGFX_PlaceMessage
+
+Mail_Place6TileRow:
+ ld b, $6
+.loop
+ ld [hli], a
+ inc a
+ dec b
+ jr nz, .loop
+ ret
+
+LoadFlowerMailGFX:
+ push bc
+ ld hl, vTiles2 tile $31
+ ld de, FlowerMailBorderGFX
+ ld c, 8 * LEN_1BPP_TILE
+ call LoadMailGFX_Color1
+ ld de, MailOddishGFX
+ ld c, 4 * LEN_1BPP_TILE
+ call LoadMailGFX_Color3
+ ld de, FlowerMailBorderGFX + 6 * LEN_1BPP_TILE
+ ld c, 1 * LEN_1BPP_TILE
+ call LoadMailGFX_Color2
+ ld de, FlowerMailFlowerGFX
+ ld c, 4 * LEN_1BPP_TILE
+ call LoadMailGFX_Color1
+ ld c, 4 * LEN_1BPP_TILE
+ call LoadMailGFX_Color2
+
+ call DrawMailBorder
+ hlcoord 2, 15
+ ld a, $3d ; underline
+ call Mail_Draw16TileRow
+ ld a, $39 ; oddish
+ hlcoord 16, 13
+ call Mail_Draw2x2Graphic
+ hlcoord 2, 13
+ call Mail_Draw2x2Graphic
+ ld a, $3e
+ hlcoord 2, 2
+ call Mail_Draw2x2Graphic
+ hlcoord 5, 3
+ call Mail_Draw2x2Graphic
+ hlcoord 10, 2
+ call Mail_Draw2x2Graphic
+ hlcoord 16, 3
+ call Mail_Draw2x2Graphic
+ hlcoord 5, 11
+ call Mail_Draw2x2Graphic
+ hlcoord 16, 10
+ call Mail_Draw2x2Graphic
+ ld a, $42
+ hlcoord 3, 4
+ call Mail_Draw2x2Graphic
+ hlcoord 12, 3
+ call Mail_Draw2x2Graphic
+ hlcoord 14, 2
+ call Mail_Draw2x2Graphic
+ hlcoord 2, 10
+ call Mail_Draw2x2Graphic
+ hlcoord 14, 11
+ call Mail_Draw2x2Graphic
+ pop hl
+ jp MailGFX_PlaceMessage
+
+LoadPortraitMailGFX:
+ push bc
+ ld hl, vTiles2 tile $31
+ ld de, PortraitMailBorderGFX
+ ld c, 5 * LEN_1BPP_TILE
+ call LoadMailGFX_Color2
+ ld de, PortraitMailUnderlineGFX
+ ld c, 1 * LEN_1BPP_TILE
+ call LoadMailGFX_Color2
+ ld hl, vTiles2 tile $3d
+ ld de, PortraitMailLargePokeballGFX
+ ld c, 4 * LEN_1BPP_TILE
+ call LoadMailGFX_Color1
+ ld de, PortraitMailSmallPokeballGFX
+ ld c, 1 * LEN_1BPP_TILE
+ call LoadMailGFX_Color2
+
+ call DrawMailBorder2
+ hlcoord 8, 15
+ ld a, $36
+ ld b, $a
+ call Mail_DrawRowLoop
+ call LovelyEonMail_PlaceIcons
+ ld a, $1
+ ld [wUnownLetter], a
+ hlcoord 1, 10
+ call PrepMonFrontpic
+ pop hl
+ jp MailGFX_PlaceMessage
+
+LoadMusicMailGFX:
+ push bc
+ ld hl, vTiles2 tile $31
+ ld de, MusicMailBorderGFX
+ ld c, 4 * LEN_1BPP_TILE
+ call LoadMailGFX_Color2
+ ld de, MorphMailBorderGFX
+ ld c, 2 * LEN_1BPP_TILE
+ call LoadMailGFX_Color2
+ ld de, MailNatuGFX
+ ld c, 6 * LEN_1BPP_TILE
+ call LoadMailGFX_Color3
+ xor a
+ ld bc, 1 tiles
+ call ByteFill
+ ld de, MusicMailLargeNoteGFX
+ ld c, 3 * LEN_1BPP_TILE
+ call LoadMailGFX_Color1
+ ld de, MusicMailSmallNoteGFX
+ ld c, 1 * LEN_1BPP_TILE
+ call LoadMailGFX_Color1
+
+ ld a, $31
+ hlcoord 0, 0
+ call Mail_Place18TileAlternatingRow
+ hlcoord 1, 17
+ call Mail_Place18TileAlternatingRow
+ ld a, $33
+ hlcoord 0, 1
+ call Mail_Place16TileAlternatingColumn
+ hlcoord 19, 0
+ call Mail_Place16TileAlternatingColumn
+ ld a, $35
+ hlcoord 2, 15
+ call Mail_Place14TileAlternatingRow
+ ld a, $37
+ hlcoord 15, 14
+ call Mail_Draw3x2Graphic
+ call LovelyEonMail_PlaceIcons
+ pop hl
+ jp MailGFX_PlaceMessage
+
+LoadMirageMailGFX:
+ push bc
+ ld hl, vTiles2 tile $31
+ ld bc, 5 * LEN_1BPP_TILE
+ call MailGFX_GenerateMonochromeTilesColor2
+ ld de, BlueSkyMailGrassGFX
+ ld c, 1 * LEN_1BPP_TILE
+ call LoadMailGFX_Color2
+ ld de, MailMewGFX
+ ld c, 18 * LEN_1BPP_TILE
+ call LoadMailGFX_Color2
+ ld de, LiteBlueMailBorderGFX + 1 * LEN_1BPP_TILE
+ ld c, 1 * LEN_1BPP_TILE
+ call LoadMailGFX_Color1
+ ld de, LiteBlueMailBorderGFX + 6 * LEN_1BPP_TILE
+ ld c, 1 * LEN_1BPP_TILE
+ call LoadMailGFX_Color1
+
+ call DrawMailBorder2
+ ld a, $36
+ hlcoord 1, 16
+ call Mail_DrawTopBottomBorder
+ inc a
+ hlcoord 15, 14
+ call Mail_Draw3x2Graphic
+ inc a
+ hlcoord 15, 16
+ ld [hli], a
+ inc a
+ ld [hl], a
+ ld a, $3f
+ hlcoord 1, 1
+ call Mail_Place18TileAlternatingRow
+ ld a, $41
+ hlcoord 0, 2
+ call Mail_Place14TileAlternatingColumn
+ ld a, $43
+ hlcoord 19, 2
+ call Mail_Place14TileAlternatingColumn
+ ld a, $45
+ hlcoord 0, 1
+ ld [hl], a
+ inc a
+ hlcoord 19, 1
+ ld [hl], a
+ inc a
+ hlcoord 0, 16
+ ld [hl], a
+ inc a
+ hlcoord 19, 16
+ ld [hl], a
+ inc a
+ hlcoord 2, 5
+ call Mail_Draw16TileRow
+ inc a
+ hlcoord 2, 11
+ call Mail_Draw16TileRow
+ pop hl
+ jp MailGFX_PlaceMessage
+
+MailGFX_GenerateMonochromeTilesColor2:
+.loop
+ xor a
+ ld [hli], a
+ ld a, $ff
+ ld [hli], a
+ dec bc
+ ld a, b
+ or c
+ jr nz, .loop
+ ret
+
+MailGFX_PlaceMessage:
+ ld bc, MAIL_STRUCT_LENGTH
+ ld de, wTempMail
+ ld a, BANK(sPartyMail)
+ call OpenSRAM
+ call CopyBytes
+ call CloseSRAM
+ ld hl, wTempMailAuthor
+ ld de, wMonOrItemNameBuffer
+ ld bc, NAME_LENGTH - 1
+ call CopyBytes
+ ld a, "@"
+ ld [wTempMailAuthor], a
+ ld [wMonOrItemNameBuffer + NAME_LENGTH - 1], a
+ ld de, wTempMailMessage
+ hlcoord 2, 7
+ call PlaceString
+ ld de, wMonOrItemNameBuffer
+ ld a, [de]
+ and a
+ ret z
+ ld a, [wBuffer3]
+ hlcoord 8, 14
+ cp $3 ; PORTRAITMAIL
+ jr z, .place_author
+ hlcoord 6, 14
+ cp $6 ; MORPH_MAIL
+ jr z, .place_author
+ hlcoord 5, 14
+
+.place_author
+ jp PlaceString
+
+Unreferenced_Functionbb4c5:
+.loop
+ ld a, [hl]
+ xor $ff
+ ld [hli], a
+ dec bc
+ ld a, b
+ or c
+ jr nz, .loop
+ ret
+
+DrawMailBorder:
+ hlcoord 0, 0
+ ld a, $31
+ ld [hli], a
+ inc a
+ call Mail_DrawTopBottomBorder
+ inc a
+ ld [hli], a
+ inc a
+ call Mail_DrawLeftRightBorder
+ ld a, $36
+ ld [hli], a
+ inc a
+ call Mail_DrawTopBottomBorder
+ hlcoord 19, 1
+ ld a, $35
+ call Mail_DrawLeftRightBorder
+ ld a, $38
+ ld [hl], a
+ ret
+
+DrawMailBorder2:
+ hlcoord 0, 0
+ ld a, $31
+ ld [hli], a
+ inc a
+ call Mail_DrawTopBottomBorder
+ ld [hl], $31
+ inc hl
+ inc a
+ call Mail_DrawLeftRightBorder
+ ld [hl], $31
+ inc hl
+ inc a
+ call Mail_DrawTopBottomBorder
+ hlcoord 19, 1
+ ld a, $35
+ call Mail_DrawLeftRightBorder
+ ld [hl], $31
+ ret
+
+Mail_Place14TileAlternatingRow:
+ push af
+ ld b, 14 / 2
+ jr Mail_PlaceAlternatingRow
+
+Mail_Place16TileAlternatingRow:
+ push af
+ ld b, 16 / 2
+ jr Mail_PlaceAlternatingRow
+
+Mail_Place18TileAlternatingRow:
+ push af
+ ld b, 18 / 2
+
+Mail_PlaceAlternatingRow:
+.loop
+ ld [hli], a
+ inc a
+ ld [hli], a
+ dec a
+ dec b
+ jr nz, .loop
+ ld [hl], a
+ pop af
+ ret
+
+Mail_Place14TileAlternatingColumn:
+ push af
+ ld b, 14 / 2
+ jr Mail_PlaceAlternatingColumn
+
+Mail_Place16TileAlternatingColumn:
+ push af
+ ld b, 16 / 2
+
+Mail_PlaceAlternatingColumn:
+.loop
+ ld [hl], a
+ ld de, SCREEN_WIDTH
+ add hl, de
+ inc a
+ ld [hl], a
+ add hl, de
+ dec a
+ dec b
+ jr nz, .loop
+ ld [hl], a
+ pop af
+ ret
+
+Mail_Draw7TileRow:
+ ld b, $7
+ jr Mail_DrawRowLoop
+
+Mail_Draw13TileRow:
+ ld b, $d
+ jr Mail_DrawRowLoop
+
+Mail_Draw16TileRow:
+ ld b, $10
+ jr Mail_DrawRowLoop
+
+Mail_DrawTopBottomBorder:
+ ld b, SCREEN_WIDTH - 2
+ jr Mail_DrawRowLoop
+
+Mail_DrawFullWidthBorder:
+ ld b, SCREEN_WIDTH
+
+Mail_DrawRowLoop:
+.loop
+ ld [hli], a
+ dec b
+ jr nz, .loop
+ ret
+
+Mail_DrawLeftRightBorder:
+ ld b, SCREEN_HEIGHT - 2
+ ld de, SCREEN_WIDTH
+.loop
+ ld [hl], a
+ add hl, de
+ dec b
+ jr nz, .loop
+ ret
+
+Mail_Draw2x2Graphic:
+ push af
+ ld [hli], a
+ inc a
+ ld [hl], a
+ ld bc, SCREEN_WIDTH - 1
+ add hl, bc
+ inc a
+ ld [hli], a
+ inc a
+ ld [hl], a
+ pop af
+ ret
+
+Mail_Draw3x2Graphic:
+ ld [hli], a
+ inc a
+ ld [hli], a
+ inc a
+ ld [hl], a
+ ld bc, SCREEN_WIDTH - 2
+ add hl, bc
+ inc a
+ ld [hli], a
+ inc a
+ ld [hli], a
+ inc a
+ ld [hl], a
+ ret
+
+LoadMailGFX_Color1:
+.loop
+ ld a, [de]
+ inc de
+ ld [hli], a
+ xor a
+ ld [hli], a
+ dec c
+ jr nz, .loop
+ ret
+
+LoadMailGFX_Color2:
+.loop
+ xor a
+ ld [hli], a
+ ld a, [de]
+ inc de
+ ld [hli], a
+ dec c
+ jr nz, .loop
+ ret
+
+LoadMailGFX_Color3:
+.loop
+ ld a, [de]
+ inc de
+ ld [hli], a
+ ld [hli], a
+ dec c
+ jr nz, .loop
+ ret
+
+INCLUDE "gfx/mail.asm"
+
+ItemIsMail:
+ ld a, d
+ ld hl, MailItems
+ ld de, 1
+ jp IsInArray
+
+INCLUDE "data/items/mail_items.asm"
diff --git a/engine/pokemon/mon_menu.asm b/engine/pokemon/mon_menu.asm
new file mode 100644
index 00000000..aa211ae1
--- /dev/null
+++ b/engine/pokemon/mon_menu.asm
@@ -0,0 +1,1293 @@
+HasNoItems:
+ ld a, [wNumItems]
+ and a
+ ret nz
+ ld a, [wNumKeyItems]
+ and a
+ ret nz
+ ld a, [wNumBalls]
+ and a
+ ret nz
+ ld hl, wTMsHMs
+ ld b, NUM_TMS + NUM_HMS
+.loop
+ ld a, [hli]
+ and a
+ jr nz, .done
+ dec b
+ jr nz, .loop
+ scf
+ ret
+.done
+ and a
+ ret
+
+TossItemFromPC:
+ push de
+ call PartyMonItemName
+ farcall _CheckTossableItem
+ ld a, [wItemAttributeParamBuffer]
+ and a
+ jr nz, .key_item
+ ld hl, .ItemsTossOutHowManyText
+ call MenuTextbox
+ farcall SelectQuantityToToss
+ push af
+ call CloseWindow
+ call ExitMenu
+ pop af
+ jr c, .quit
+ ld hl, .ItemsThrowAwayText
+ call MenuTextbox
+ call YesNoBox
+ push af
+ call ExitMenu
+ pop af
+ jr c, .quit
+ pop hl
+ ld a, [wCurItemQuantity]
+ call TossItem
+ call PartyMonItemName
+ ld hl, .ItemsDiscardedText
+ call MenuTextbox
+ call ExitMenu
+ and a
+ ret
+
+.key_item
+ call .CantToss
+.quit
+ pop hl
+ scf
+ ret
+
+.ItemsTossOutHowManyText:
+ text_far _ItemsTossOutHowManyText
+ text_end
+
+.ItemsThrowAwayText:
+ text_far _ItemsThrowAwayText
+ text_end
+
+.ItemsDiscardedText:
+ text_far _ItemsDiscardedText
+ text_end
+
+.CantToss:
+ ld hl, .ItemsTooImportantText
+ call MenuTextboxBackup
+ ret
+
+.ItemsTooImportantText:
+ text_far _ItemsTooImportantText
+ text_end
+
+CantUseItem:
+ ld hl, ItemsOakWarningText
+ call MenuTextboxWaitButton
+ ret
+
+ItemsOakWarningText:
+ text_far _ItemsOakWarningText
+ text_end
+
+PartyMonItemName:
+ ld a, [wCurItem]
+ ld [wNamedObjectIndexBuffer], a
+ call GetItemName
+ call CopyName1
+ ret
+
+CancelPokemonAction:
+ farcall InitPartyMenuWithCancel
+ farcall UnfreezeMonIcons
+ ld a, 1
+ ret
+
+PokemonActionSubmenu:
+ hlcoord 1, 15
+ lb bc, 2, 18
+ call ClearBox
+ farcall MonSubmenu
+ call GetCurNick
+ ld a, [wMenuSelection]
+ ld hl, .Actions
+ ld de, 3
+ call IsInArray
+ jr nc, .nothing
+
+ inc hl
+ ld a, [hli]
+ ld h, [hl]
+ ld l, a
+ jp hl
+
+.nothing
+ ld a, 0
+ ret
+
+.Actions:
+ dbw MONMENUITEM_CUT, MonMenu_Cut
+ dbw MONMENUITEM_FLY, MonMenu_Fly
+ dbw MONMENUITEM_SURF, MonMenu_Surf
+ dbw MONMENUITEM_STRENGTH, MonMenu_Strength
+ dbw MONMENUITEM_FLASH, MonMenu_Flash
+ dbw MONMENUITEM_WHIRLPOOL, MonMenu_Whirlpool
+ dbw MONMENUITEM_DIG, MonMenu_Dig
+ dbw MONMENUITEM_TELEPORT, MonMenu_Teleport
+ dbw MONMENUITEM_SOFTBOILED, MonMenu_Softboiled_MilkDrink
+ dbw MONMENUITEM_MILKDRINK, MonMenu_Softboiled_MilkDrink
+ dbw MONMENUITEM_HEADBUTT, MonMenu_Headbutt
+ dbw MONMENUITEM_WATERFALL, MonMenu_Waterfall
+ dbw MONMENUITEM_ROCKSMASH, MonMenu_RockSmash
+ dbw MONMENUITEM_SWEETSCENT, MonMenu_SweetScent
+ dbw MONMENUITEM_STATS, OpenPartyStats
+ dbw MONMENUITEM_SWITCH, SwitchPartyMons
+ dbw MONMENUITEM_ITEM, GiveTakePartyMonItem
+ dbw MONMENUITEM_CANCEL, CancelPokemonAction
+ dbw MONMENUITEM_MOVE, ManagePokemonMoves
+ dbw MONMENUITEM_MAIL, MonMailAction
+
+SwitchPartyMons:
+; Don't try if there's nothing to switch!
+ ld a, [wPartyCount]
+ cp 2
+ jr c, .DontSwitch
+
+ ld a, [wCurPartyMon]
+ inc a
+ ld [wSwitchMon], a
+
+ farcall HoldSwitchmonIcon
+ farcall InitPartyMenuNoCancel
+
+ ld a, PARTYMENUACTION_MOVE
+ ld [wPartyMenuActionText], a
+ farcall WritePartyMenuTilemap
+ farcall PrintPartyMenuText
+
+ hlcoord 0, 1
+ ld bc, SCREEN_WIDTH * 2
+ ld a, [wSwitchMon]
+ dec a
+ call AddNTimes
+ ld [hl], "▷"
+ call WaitBGMap
+ call SetPalettes
+ call DelayFrame
+
+ farcall PartyMenuSelect
+ bit 1, b
+ jr c, .DontSwitch
+
+ farcall _SwitchPartyMons
+
+ xor a
+ ld [wPartyMenuActionText], a
+
+ farcall LoadPartyMenuGFX
+ farcall InitPartyMenuWithCancel
+ farcall InitPartyMenuGFX
+
+ ld a, 1
+ ret
+
+.DontSwitch:
+ xor a
+ ld [wPartyMenuActionText], a
+ call CancelPokemonAction
+ ret
+
+GiveTakePartyMonItem:
+; Eggs can't hold items!
+ ld a, [wCurPartySpecies]
+ cp EGG
+ jr z, .cancel
+
+ ld hl, GiveTakeItemMenuData
+ call LoadMenuHeader
+ call VerticalMenu
+ call ExitMenu
+ jr c, .cancel
+
+ call GetCurNick
+ ld hl, wStringBuffer1
+ ld de, wMonOrItemNameBuffer
+ ld bc, MON_NAME_LENGTH
+ call CopyBytes
+ ld a, [wMenuCursorY]
+ cp 1
+ jr nz, .take
+
+ call LoadStandardMenuHeader
+ call ClearPalettes
+ call .GiveItem
+ call ClearPalettes
+ call LoadFontsBattleExtra
+ call ExitMenu
+ ld a, 0
+ ret
+
+.take
+ call TakePartyItem
+ ld a, 3
+ ret
+
+.cancel
+ ld a, 3
+ ret
+
+.GiveItem:
+ farcall DepositSellInitPackBuffers
+
+.loop
+ farcall DepositSellPack
+
+ ld a, [wPackUsedItem]
+ and a
+ jr z, .quit
+
+ ld a, [wCurPocket]
+ cp KEY_ITEM_POCKET
+ jr z, .next
+
+ call CheckTossableItem
+ ld a, [wItemAttributeParamBuffer]
+ and a
+ jr nz, .next
+
+ call TryGiveItemToPartymon
+ jr .quit
+
+.next
+ ld hl, ItemCantHeldText
+ call MenuTextboxBackup
+ jr .loop
+
+.quit
+ ret
+
+TryGiveItemToPartymon:
+ call SpeechTextbox
+ call PartyMonItemName
+ call GetPartyItemLocation
+ ld a, [hl]
+ and a
+ jr z, .give_item_to_mon
+
+ push hl
+ ld d, a
+ farcall ItemIsMail
+ pop hl
+ jr c, .please_remove_mail
+ ld a, [hl]
+ jr .already_holding_item
+
+.give_item_to_mon
+ call GiveItemToPokemon
+ ld hl, PokemonHoldItemText
+ call MenuTextboxBackup
+ call GivePartyItem
+ ret
+
+.please_remove_mail
+ ld hl, PokemonRemoveMailText
+ call MenuTextboxBackup
+ ret
+
+.already_holding_item
+ ld [wNamedObjectIndexBuffer], a
+ call GetItemName
+ ld hl, PokemonAskSwapItemText
+ call StartMenuYesNo
+ jr c, .abort
+
+ call GiveItemToPokemon
+ ld a, [wNamedObjectIndexBuffer]
+ push af
+ ld a, [wCurItem]
+ ld [wNamedObjectIndexBuffer], a
+ pop af
+ ld [wCurItem], a
+ call ReceiveItemFromPokemon
+ jr nc, .bag_full
+
+ ld hl, PokemonSwapItemText
+ call MenuTextboxBackup
+ ld a, [wNamedObjectIndexBuffer]
+ ld [wCurItem], a
+ call GivePartyItem
+ ret
+
+.bag_full
+ ld a, [wNamedObjectIndexBuffer]
+ ld [wCurItem], a
+ call ReceiveItemFromPokemon
+ ld hl, ItemStorageFullText
+ call MenuTextboxBackup
+
+.abort
+ ret
+
+GivePartyItem:
+ call GetPartyItemLocation
+ ld a, [wCurItem]
+ ld [hl], a
+ ld d, a
+ farcall ItemIsMail
+ jr nc, .done
+ call ComposeMailMessage
+
+.done
+ ret
+
+TakePartyItem:
+ call SpeechTextbox
+ call GetPartyItemLocation
+ ld a, [hl]
+ and a
+ jr z, .asm_13053
+
+ ld [wCurItem], a
+ call ReceiveItemFromPokemon
+ jr nc, .asm_1305b
+
+ farcall ItemIsMail
+ call GetPartyItemLocation
+ ld a, [hl]
+ ld [wNamedObjectIndexBuffer], a
+ ld [hl], NO_ITEM
+ call GetItemName
+ ld hl, PokemonTookItemText
+ call MenuTextboxBackup
+ jr .asm_13061
+
+.asm_13053
+ ld hl, PokemonNotHoldingText
+ call MenuTextboxBackup
+ jr .asm_13061
+
+.asm_1305b
+ ld hl, ItemStorageFullText
+ call MenuTextboxBackup
+
+.asm_13061
+ ret
+
+GiveTakeItemMenuData:
+ db MENU_SPRITE_ANIMS | MENU_BACKUP_TILES ; flags
+ menu_coords 12, 12, SCREEN_WIDTH - 1, SCREEN_HEIGHT - 1
+ dw .Items
+ db 1 ; default option
+
+.Items:
+ db STATICMENU_CURSOR ; flags
+ db 2 ; # items
+ db "GIVE@"
+ db "TAKE@"
+
+PokemonSwapItemText:
+ text_far _PokemonSwapItemText
+ text_end
+
+PokemonHoldItemText:
+ text_far _PokemonHoldItemText
+ text_end
+
+PokemonRemoveMailText:
+ text_far _PokemonRemoveMailText
+ text_end
+
+PokemonNotHoldingText:
+ text_far _PokemonNotHoldingText
+ text_end
+
+ItemStorageFullText:
+ text_far _ItemStorageFullText
+ text_end
+
+PokemonTookItemText:
+ text_far _PokemonTookItemText
+ text_end
+
+PokemonAskSwapItemText:
+ text_far _PokemonAskSwapItemText
+ text_end
+
+ItemCantHeldText:
+ text_far _ItemCantHeldText
+ text_end
+
+GetPartyItemLocation:
+ push af
+ ld a, MON_ITEM
+ call GetPartyParamLocation
+ pop af
+ ret
+
+ReceiveItemFromPokemon:
+ ld a, 1
+ ld [wItemQuantityChangeBuffer], a
+ ld hl, wNumItems
+ jp ReceiveItem
+
+GiveItemToPokemon:
+ ld a, 1
+ ld [wItemQuantityChangeBuffer], a
+ ld hl, wNumItems
+ jp TossItem
+
+StartMenuYesNo:
+ call MenuTextbox
+ call YesNoBox
+ jp ExitMenu
+
+ComposeMailMessage:
+ ld de, wTempMailMessage
+ farcall _ComposeMailMessage
+ ld hl, wPlayerName
+ ld de, wTempMailAuthor
+ ld bc, NAME_LENGTH - 1
+ call CopyBytes
+ ld hl, wPlayerID
+ ld bc, 2
+ call CopyBytes
+ ld a, [wCurPartySpecies]
+ ld [de], a
+ inc de
+ ld a, [wCurItem]
+ ld [de], a
+ ld a, [wCurPartyMon]
+ ld hl, sPartyMail
+ ld bc, MAIL_STRUCT_LENGTH
+ call AddNTimes
+ ld d, h
+ ld e, l
+ ld hl, wTempMail
+ ld bc, MAIL_STRUCT_LENGTH
+ ld a, BANK(sPartyMail)
+ call OpenSRAM
+ call CopyBytes
+ call CloseSRAM
+ ret
+
+MonMailAction:
+; If in the time capsule or trade center,
+; selecting the mail only allows you to
+; read the mail.
+ ld a, [wLinkMode]
+ cp LINK_TIMECAPSULE
+ jr z, .read
+ cp LINK_TRADECENTER
+ jr z, .read
+
+; Show the READ/TAKE/QUIT menu.
+ ld hl, .MenuHeader
+ call LoadMenuHeader
+ call VerticalMenu
+ call ExitMenu
+
+; Interpret the menu.
+ jp c, .done
+ ld a, [wMenuCursorY]
+ cp $1
+ jr z, .read
+ cp $2
+ jr z, .take
+ jp .done
+
+.read
+ farcall ReadPartyMonMail
+ ld a, $0
+ ret
+
+.take
+ ld hl, .MailAskSendToPCText
+ call StartMenuYesNo
+ jr c, .RemoveMailToBag
+ ld a, [wCurPartyMon]
+ ld b, a
+ farcall SendMailToPC
+ jr c, .MailboxFull
+ ld hl, .MailSentToPCText
+ call MenuTextboxBackup
+ jr .done
+
+.MailboxFull:
+ ld hl, .MailboxFullText
+ call MenuTextboxBackup
+ jr .done
+
+.RemoveMailToBag:
+ ld hl, .MailLoseMessageText
+ call StartMenuYesNo
+ jr c, .done
+ call GetPartyItemLocation
+ ld a, [hl]
+ ld [wCurItem], a
+ call ReceiveItemFromPokemon
+ jr nc, .BagIsFull
+ call GetPartyItemLocation
+ ld [hl], $0
+ call GetCurNick
+ ld hl, .MailDetachedText
+ call MenuTextboxBackup
+ jr .done
+
+.BagIsFull:
+ ld hl, .MailNoSpaceText
+ call MenuTextboxBackup
+ jr .done
+
+.done
+ ld a, $3
+ ret
+
+.MenuHeader:
+ db MENU_BACKUP_TILES ; flags
+ menu_coords 9, 10, SCREEN_WIDTH - 1, SCREEN_HEIGHT - 1
+ dw .MenuData
+ db 1 ; default option
+
+.MenuData:
+ db STATICMENU_CURSOR ; flags
+ db 3 ; items
+ db "READ@"
+ db "TAKE@"
+ db "QUIT@"
+
+.MailLoseMessageText:
+ text_far _MailLoseMessageText
+ text_end
+
+.MailDetachedText:
+ text_far _MailDetachedText
+ text_end
+
+.MailNoSpaceText:
+ text_far _MailNoSpaceText
+ text_end
+
+.MailAskSendToPCText:
+ text_far _MailAskSendToPCText
+ text_end
+
+.MailboxFullText:
+ text_far _MailboxFullText
+ text_end
+
+.MailSentToPCText:
+ text_far _MailSentToPCText
+ text_end
+
+OpenPartyStats:
+ call LoadStandardMenuHeader
+ call ClearSprites
+; PartyMon
+ xor a
+ ld [wMonType], a
+ call LowVolume
+ predef StatsScreenInit
+ call MaxVolume
+ call Call_ExitMenu
+ ld a, 0
+ ret
+
+MonMenu_Cut:
+ farcall CutFunction
+ ld a, [wFieldMoveSucceeded]
+ cp $1
+ jr nz, .Fail
+ ld b, $4
+ ld a, $2
+ ret
+
+.Fail:
+ ld a, $3
+ ret
+
+MonMenu_Fly:
+ farcall FlyFunction
+ ld a, [wFieldMoveSucceeded]
+ cp $2
+ jr z, .Fail
+ cp $0
+ jr z, .Error
+ ld b, $4
+ ld a, $2
+ ret
+
+.Fail:
+ ld a, $3
+ ret
+
+.Error:
+ ld a, $0
+ ret
+
+.Unreferenced:
+ ld a, $1
+ ret
+
+MonMenu_Flash:
+ farcall FlashFunction
+ ld a, [wFieldMoveSucceeded]
+ cp $1
+ jr nz, .Fail
+ ld b, $4
+ ld a, $2
+ ret
+
+.Fail:
+ ld a, $3
+ ret
+
+MonMenu_Strength:
+ farcall StrengthFunction
+ ld a, [wFieldMoveSucceeded]
+ cp $1
+ jr nz, .Fail
+ ld b, $4
+ ld a, $2
+ ret
+
+.Fail:
+ ld a, $3
+ ret
+
+MonMenu_Whirlpool:
+ farcall WhirlpoolFunction
+ ld a, [wFieldMoveSucceeded]
+ cp $1
+ jr nz, .Fail
+ ld b, $4
+ ld a, $2
+ ret
+
+.Fail:
+ ld a, $3
+ ret
+
+MonMenu_Waterfall:
+ farcall WaterfallFunction
+ ld a, [wFieldMoveSucceeded]
+ cp $1
+ jr nz, .Fail
+ ld b, $4
+ ld a, $2
+ ret
+
+.Fail:
+ ld a, $3
+ ret
+
+MonMenu_Teleport:
+ farcall TeleportFunction
+ ld a, [wFieldMoveSucceeded]
+ and a
+ jr z, .Fail
+ ld b, $4
+ ld a, $2
+ ret
+
+.Fail:
+ ld a, $3
+ ret
+
+MonMenu_Surf:
+ farcall SurfFunction
+ ld a, [wFieldMoveSucceeded]
+ and a
+ jr z, .Fail
+ ld b, $4
+ ld a, $2
+ ret
+
+.Fail:
+ ld a, $3
+ ret
+
+MonMenu_Dig:
+ farcall DigFunction
+ ld a, [wFieldMoveSucceeded]
+ cp $1
+ jr nz, .Fail
+ ld b, $4
+ ld a, $2
+ ret
+
+.Fail:
+ ld a, $3
+ ret
+
+MonMenu_Softboiled_MilkDrink:
+ call .CheckMonHasEnoughHP
+ jr nc, .NotEnoughHP
+ farcall Softboiled_MilkDrinkFunction
+ jr .finish
+
+.NotEnoughHP:
+ ld hl, .PokemonNotEnoughHPText
+ call PrintText
+
+.finish
+ xor a
+ ld [wPartyMenuActionText], a
+ ld a, $3
+ ret
+
+.PokemonNotEnoughHPText:
+ text_far _PokemonNotEnoughHPText
+ text_end
+
+.CheckMonHasEnoughHP:
+; Need to have at least (MaxHP / 5) HP left.
+ ld a, MON_MAXHP
+ call GetPartyParamLocation
+ ld a, [hli]
+ ldh [hDividend + 0], a
+ ld a, [hl]
+ ldh [hDividend + 1], a
+ ld a, 5
+ ldh [hDivisor], a
+ ld b, 2
+ call Divide
+ ld a, MON_HP + 1
+ call GetPartyParamLocation
+ ldh a, [hQuotient + 3]
+ sub [hl]
+ dec hl
+ ldh a, [hQuotient + 2]
+ sbc [hl]
+ ret
+
+MonMenu_Headbutt:
+ farcall HeadbuttFunction
+ ld a, [wFieldMoveSucceeded]
+ cp $1
+ jr nz, .Fail
+ ld b, $4
+ ld a, $2
+ ret
+
+.Fail:
+ ld a, $3
+ ret
+
+MonMenu_RockSmash:
+ farcall RockSmashFunction
+ ld a, [wFieldMoveSucceeded]
+ cp $1
+ jr nz, .Fail
+ ld b, $4
+ ld a, $2
+ ret
+
+.Fail:
+ ld a, $3
+ ret
+
+MonMenu_SweetScent:
+ farcall SweetScentFromMenu
+ ld b, $4
+ ld a, $2
+ ret
+
+ChooseMoveToDelete:
+ ld hl, wOptions
+ ld a, [hl]
+ push af
+ set NO_TEXT_SCROLL, [hl]
+ call LoadFontsBattleExtra
+ call .ChooseMoveToDelete
+ pop bc
+ ld a, b
+ ld [wOptions], a
+ push af
+ call ClearBGPalettes
+ pop af
+ ret
+
+.ChooseMoveToDelete
+ call SetUpMoveScreenBG
+ ld de, DeleteMoveScreenAttrs
+ call SetMenuAttributes
+ call SetUpMoveList
+ ld hl, w2DMenuFlags1
+ set 6, [hl]
+ jr .enter_loop
+
+.loop
+ call ScrollingMenuJoypad
+ bit B_BUTTON_F, a
+ jp nz, .b_button
+ bit A_BUTTON_F, a
+ jp nz, .a_button
+
+.enter_loop
+ call PrepareToPlaceMoveData
+ call PlaceMoveData
+ jp .loop
+
+.a_button
+ and a
+ jr .finish
+
+.b_button
+ scf
+
+.finish
+ push af
+ xor a
+ ld [wSwitchMon], a
+ ld hl, w2DMenuFlags1
+ res 6, [hl]
+ call ClearSprites
+ call ClearTilemap
+ pop af
+ ret
+
+DeleteMoveScreenAttrs:
+ db 3, 1
+ db 3, 1
+ db $40, $00
+ dn 2, 0
+ db D_UP | D_DOWN | A_BUTTON | B_BUTTON
+
+ManagePokemonMoves:
+ ld a, [wCurPartySpecies]
+ cp EGG
+ jr z, .egg
+ ld hl, wOptions
+ ld a, [hl]
+ push af
+ set NO_TEXT_SCROLL, [hl]
+ call MoveScreenLoop
+ pop af
+ ld [wOptions], a
+ call ClearBGPalettes
+
+.egg
+ ld a, $0
+ ret
+
+MoveScreenLoop:
+ ld a, [wCurPartyMon]
+ inc a
+ ld [wPartyMenuCursor], a
+ call SetUpMoveScreenBG
+ call PlaceMoveScreenArrows
+ ld de, MoveScreenAttributes
+ call SetMenuAttributes
+.loop
+ call SetUpMoveList
+ ld hl, w2DMenuFlags1
+ set 6, [hl]
+ jr .skip_joy
+
+.joy_loop
+ call ScrollingMenuJoypad
+ bit 1, a
+ jp nz, .b_button
+ bit 0, a
+ jp nz, .a_button
+ bit 4, a
+ jp nz, .d_right
+ bit 5, a
+ jp nz, .d_left
+
+.skip_joy
+ call PrepareToPlaceMoveData
+ ld a, [wMoveSwapBuffer]
+ and a
+ jr nz, .moving_move
+ call PlaceMoveData
+ jp .joy_loop
+
+.moving_move
+ ld a, " "
+ hlcoord 1, 11
+ ld bc, 5
+ call ByteFill
+ hlcoord 1, 12
+ lb bc, 5, SCREEN_WIDTH - 2
+ call ClearBox
+ hlcoord 1, 12
+ ld de, String_MoveWhere
+ call PlaceString
+ jp .joy_loop
+.b_button
+ call PlayClickSFX
+ call WaitSFX
+ ld a, [wMoveSwapBuffer]
+ and a
+ jp z, .exit
+
+ ld a, [wMoveSwapBuffer]
+ ld [wMenuCursorY], a
+ xor a
+ ld [wMoveSwapBuffer], a
+ hlcoord 1, 2
+ lb bc, 8, SCREEN_WIDTH - 2
+ call ClearBox
+ jp .loop
+
+.d_right
+ ld a, [wMoveSwapBuffer]
+ and a
+ jp nz, .joy_loop
+
+ ld a, [wCurPartyMon]
+ ld b, a
+ push bc
+ call .cycle_right
+ pop bc
+ ld a, [wCurPartyMon]
+ cp b
+ jp z, .joy_loop
+ jp MoveScreenLoop
+
+.d_left
+ ld a, [wMoveSwapBuffer]
+ and a
+ jp nz, .joy_loop
+ ld a, [wCurPartyMon]
+ ld b, a
+ push bc
+ call .cycle_left
+ pop bc
+ ld a, [wCurPartyMon]
+ cp b
+ jp z, .joy_loop
+ jp MoveScreenLoop
+
+.cycle_right
+ ld a, [wCurPartyMon]
+ inc a
+ ld [wCurPartyMon], a
+ ld c, a
+ ld b, 0
+ ld hl, wPartySpecies
+ add hl, bc
+ ld a, [hl]
+ cp -1
+ jr z, .cycle_left
+ cp EGG
+ ret nz
+ jr .cycle_right
+
+.cycle_left
+ ld a, [wCurPartyMon]
+ and a
+ ret z
+.cycle_left_loop
+ ld a, [wCurPartyMon]
+ dec a
+ ld [wCurPartyMon], a
+ ld c, a
+ ld b, 0
+ ld hl, wPartySpecies
+ add hl, bc
+ ld a, [hl]
+ cp EGG
+ ret nz
+ ld a, [wCurPartyMon]
+ and a
+ jr z, .cycle_right
+ jr .cycle_left_loop
+
+.a_button
+ call PlayClickSFX
+ call WaitSFX
+ ld a, [wMoveSwapBuffer]
+ and a
+ jr nz, .place_move
+ ld a, [wMenuCursorY]
+ ld [wMoveSwapBuffer], a
+ call PlaceHollowCursor
+ jp .moving_move
+
+.place_move
+ ld hl, wPartyMon1Moves
+ ld bc, PARTYMON_STRUCT_LENGTH
+ ld a, [wCurPartyMon]
+ call AddNTimes
+ push hl
+ call .copy_move
+ pop hl
+ ld bc, $15
+ add hl, bc
+ call .copy_move
+ ld a, [wBattleMode]
+ jr z, .swap_moves
+ ld hl, wBattleMonMoves
+ ld bc, $20
+ ld a, [wCurPartyMon]
+ call AddNTimes
+ push hl
+ call .copy_move
+ pop hl
+ ld bc, 6
+ add hl, bc
+ call .copy_move
+
+.swap_moves
+ ld de, SFX_SWITCH_POKEMON
+ call PlaySFX
+ call WaitSFX
+ ld de, SFX_SWITCH_POKEMON
+ call PlaySFX
+ call WaitSFX
+ hlcoord 1, 2
+ lb bc, 8, 18
+ call ClearBox
+ hlcoord 10, 10
+ lb bc, 1, 9
+ call ClearBox
+ jp .loop
+
+.copy_move
+ push hl
+ ld a, [wMenuCursorY]
+ dec a
+ ld c, a
+ ld b, $0
+ add hl, bc
+ ld d, h
+ ld e, l
+ pop hl
+ ld a, [wMoveSwapBuffer]
+ dec a
+ ld c, a
+ ld b, $0
+ add hl, bc
+ ld a, [de]
+ ld b, [hl]
+ ld [hl], a
+ ld a, b
+ ld [de], a
+ ret
+
+.exit
+ xor a
+ ld [wMoveSwapBuffer], a
+ ld hl, w2DMenuFlags1
+ res 6, [hl]
+ call ClearSprites
+ jp ClearTilemap
+
+MoveScreenAttributes:
+ db 3, 1
+ db 3, 1
+ db $40, $00
+ dn 2, 0
+ db D_UP | D_DOWN | D_LEFT | D_RIGHT | A_BUTTON | B_BUTTON
+
+String_MoveWhere:
+ db "Where?@"
+
+SetUpMoveScreenBG:
+ call ClearBGPalettes
+ call ClearTilemap
+ call ClearSprites
+ xor a
+ ldh [hBGMapMode], a
+ farcall LoadStatsScreenPageTilesGFX
+ farcall ClearSpriteAnims2
+ ld a, [wCurPartyMon]
+ ld e, a
+ ld d, $0
+ ld hl, wPartySpecies
+ add hl, de
+ ld a, [hl]
+ ld [wTempIconSpecies], a
+ ld e, MONICON_MOVES
+ farcall LoadMenuMonIcon
+ hlcoord 0, 1
+ ld b, 9
+ ld c, 18
+ call Textbox
+ hlcoord 0, 11
+ ld b, 5
+ ld c, 18
+ call Textbox
+ hlcoord 2, 0
+ lb bc, 2, 3
+ call ClearBox
+ xor a
+ ld [wMonType], a
+ ld hl, wPartyMonNicknames
+ ld a, [wCurPartyMon]
+ call GetNick
+ hlcoord 5, 1
+ call PlaceString
+ push bc
+ farcall CopyMonToTempMon
+ pop hl
+ call PrintLevel
+ ld hl, wPlayerHPPal
+ call SetHPPal
+ ld b, SCGB_MOVE_LIST
+ call GetSGBLayout
+ hlcoord 16, 0
+ lb bc, 1, 3
+ jp ClearBox
+
+SetUpMoveList:
+ xor a
+ ldh [hBGMapMode], a
+ ld [wMoveSwapBuffer], a
+ ld [wMonType], a
+ predef CopyMonToTempMon
+ ld hl, wTempMonMoves
+ ld de, wListMoves_MoveIndicesBuffer
+ ld bc, NUM_MOVES
+ call CopyBytes
+ ld a, SCREEN_WIDTH * 2
+ ld [wBuffer1], a
+ hlcoord 2, 3
+ predef ListMoves
+ hlcoord 10, 4
+ predef ListMovePP
+ call WaitBGMap
+ call SetPalettes
+ ld a, [wNumMoves]
+ inc a
+ ld [w2DMenuNumRows], a
+ hlcoord 0, 11
+ ld b, 5
+ ld c, 18
+ jp Textbox
+
+PrepareToPlaceMoveData:
+ ld hl, wPartyMon1Moves
+ ld bc, PARTYMON_STRUCT_LENGTH
+ ld a, [wCurPartyMon]
+ call AddNTimes
+ ld a, [wMenuCursorY]
+ dec a
+ ld c, a
+ ld b, $0
+ add hl, bc
+ ld a, [hl]
+ ld [wCurSpecies], a
+ hlcoord 1, 12
+ lb bc, 5, 18
+ jp ClearBox
+
+PlaceMoveData:
+ xor a
+ ldh [hBGMapMode], a
+ hlcoord 0, 10
+ ld de, String_MoveType_Top
+ call PlaceString
+ hlcoord 0, 11
+ ld de, String_MoveType_Bottom
+ call PlaceString
+ hlcoord 11, 12
+ ld de, String_MoveAtk
+ call PlaceString
+ ld a, [wCurSpecies]
+ ld b, a
+ hlcoord 2, 12
+ predef PrintMoveType
+ ld a, [wCurSpecies]
+ dec a
+ ld hl, Moves + MOVE_POWER
+ ld bc, MOVE_LENGTH
+ call AddNTimes
+ ld a, BANK(Moves)
+ call GetFarByte
+ hlcoord 16, 12
+ cp 2
+ jr c, .no_power
+ ld [wDeciramBuffer], a
+ ld de, wDeciramBuffer
+ lb bc, 1, 3
+ call PrintNum
+ jr .description
+
+.no_power
+ ld de, String_MoveNoPower
+ call PlaceString
+
+.description
+ hlcoord 1, 14
+ predef PrintMoveDesc
+ ld a, $1
+ ldh [hBGMapMode], a
+ ret
+
+String_MoveType_Top:
+ db "┌─────┐@"
+String_MoveType_Bottom:
+ db "│TYPE/└@"
+String_MoveAtk:
+ db "ATTK/@"
+String_MoveNoPower:
+ db "---@"
+
+PlaceMoveScreenArrows:
+ call PlaceMoveScreenLeftArrow
+ call PlaceMoveScreenRightArrow
+ ret
+
+PlaceMoveScreenLeftArrow:
+ ld a, [wCurPartyMon]
+ and a
+ ret z
+ ld c, a
+ ld e, a
+ ld d, 0
+ ld hl, wPartyCount
+ add hl, de
+.loop
+ ld a, [hl]
+ and a
+ jr z, .prev
+ cp EGG
+ jr z, .prev
+ cp NUM_POKEMON + 1
+ jr c, .legal
+
+.prev
+ dec hl
+ dec c
+ jr nz, .loop
+ ret
+
+.legal
+ hlcoord 16, 0
+ ld [hl], "◀"
+ ret
+
+PlaceMoveScreenRightArrow:
+ ld a, [wCurPartyMon]
+ inc a
+ ld c, a
+ ld a, [wPartyCount]
+ cp c
+ ret z
+ ld e, c
+ ld d, 0
+ ld hl, wPartySpecies
+ add hl, de
+.loop
+ ld a, [hl]
+ cp -1
+ ret z
+ and a
+ jr z, .next
+ cp EGG
+ jr z, .next
+ cp NUM_POKEMON + 1
+ jr c, .legal
+
+.next
+ inc hl
+ jr .loop
+
+.legal
+ hlcoord 18, 0
+ ld [hl], "▶"
+ ret
diff --git a/engine/pokemon/mon_submenu.asm b/engine/pokemon/mon_submenu.asm
new file mode 100644
index 00000000..148f1da6
--- /dev/null
+++ b/engine/pokemon/mon_submenu.asm
@@ -0,0 +1,290 @@
+INCLUDE "data/mon_menu.asm"
+
+MonSubmenu:
+ xor a
+ ldh [hBGMapMode], a
+ call GetMonSubmenuItems
+ farcall FreezeMonIcons
+ ld hl, .MenuHeader
+ call LoadMenuHeader
+ call .GetTopCoord
+ call PopulateMonMenu
+
+ ld a, 1
+ ldh [hBGMapMode], a
+ call MonMenuLoop
+ ld [wMenuSelection], a
+
+ call ExitMenu
+ ret
+
+.MenuHeader:
+ db MENU_BACKUP_TILES ; flags
+ menu_coords 6, 0, SCREEN_WIDTH - 1, SCREEN_HEIGHT - 1
+ dw 0
+ db 1 ; default option
+
+.GetTopCoord:
+; TopCoord = 1 + BottomCoord - 2 * (NumSubmenuItems + 1)
+ ld a, [wBuffer1]
+ inc a
+ add a
+ ld b, a
+ ld a, [wMenuBorderBottomCoord]
+ sub b
+ inc a
+ ld [wMenuBorderTopCoord], a
+ call MenuBox
+ ret
+
+MonMenuLoop:
+.loop
+ ld a, MENU_UNUSED_3 | MENU_BACKUP_TILES_2 ; flags
+ ld [wMenuDataFlags], a
+ ld a, [wBuffer1] ; items
+ ld [wMenuDataItems], a
+ call InitVerticalMenuCursor
+ ld hl, w2DMenuFlags1
+ set 6, [hl]
+ call StaticMenuJoypad
+ ld de, SFX_READ_TEXT_2
+ call PlaySFX
+ ldh a, [hJoyPressed]
+ bit A_BUTTON_F, a
+ jr nz, .select
+ bit B_BUTTON_F, a
+ jr nz, .cancel
+ jr .loop
+
+.cancel
+ ld a, MONMENUITEM_CANCEL
+ ret
+
+.select
+ ld a, [wMenuCursorY]
+ dec a
+ ld c, a
+ ld b, 0
+ ld hl, wBuffer2
+ add hl, bc
+ ld a, [hl]
+ ret
+
+PopulateMonMenu:
+ call MenuBoxCoord2Tile
+ ld bc, 2 * SCREEN_WIDTH + 2
+ add hl, bc
+ ld de, wBuffer2
+.loop
+ ld a, [de]
+ inc de
+ cp -1
+ ret z
+ push de
+ push hl
+ call GetMonMenuString
+ pop hl
+ call PlaceString
+ ld bc, 2 * SCREEN_WIDTH
+ add hl, bc
+ pop de
+ jr .loop
+
+GetMonMenuString:
+ ld hl, MonMenuOptions + 1
+ ld de, 3
+ call IsInArray
+ dec hl
+ ld a, [hli]
+ cp MONMENU_MENUOPTION
+ jr z, .NotMove
+ inc hl
+ ld a, [hl]
+ ld [wNamedObjectIndexBuffer], a
+ call GetMoveName
+ ret
+
+.NotMove:
+ inc hl
+ ld a, [hl]
+ dec a
+ ld hl, MonMenuOptionStrings
+ call GetNthString
+ ld d, h
+ ld e, l
+ ret
+
+GetMonSubmenuItems:
+ call ResetMonSubmenu
+ ld a, [wCurPartySpecies]
+ cp EGG
+ jr z, .egg
+ ld a, [wLinkMode]
+ and a
+ jr nz, .skip_moves
+ ld a, MON_MOVES
+ call GetPartyParamLocation
+ ld d, h
+ ld e, l
+ ld c, NUM_MOVES
+.loop
+ push bc
+ push de
+ ld a, [de]
+ and a
+ jr z, .next
+ push hl
+ call IsFieldMove
+ pop hl
+ jr nc, .next
+ call AddMonMenuItem
+
+.next
+ pop de
+ inc de
+ pop bc
+ dec c
+ jr nz, .loop
+
+.skip_moves
+ ld a, MONMENUITEM_STATS
+ call AddMonMenuItem
+ ld a, MONMENUITEM_SWITCH
+ call AddMonMenuItem
+ ld a, MONMENUITEM_MOVE
+ call AddMonMenuItem
+ ld a, [wLinkMode]
+ and a
+ jr nz, .skip2
+ push hl
+ ld a, MON_ITEM
+ call GetPartyParamLocation
+ ld d, [hl]
+ farcall ItemIsMail
+ pop hl
+ ld a, MONMENUITEM_MAIL
+ jr c, .ok
+ ld a, MONMENUITEM_ITEM
+
+.ok
+ call AddMonMenuItem
+
+.skip2
+ ld a, [wBuffer1]
+ cp NUM_MONMENU_ITEMS
+ jr z, .ok2
+ ld a, MONMENUITEM_CANCEL
+ call AddMonMenuItem
+
+.ok2
+ call TerminateMonSubmenu
+ ret
+
+.egg
+ ld a, MONMENUITEM_STATS
+ call AddMonMenuItem
+ ld a, MONMENUITEM_SWITCH
+ call AddMonMenuItem
+ ld a, MONMENUITEM_CANCEL
+ call AddMonMenuItem
+ call TerminateMonSubmenu
+ ret
+
+IsFieldMove:
+ ld b, a
+ ld hl, MonMenuOptions
+.next
+ ld a, [hli]
+ cp -1
+ jr z, .nope
+ cp MONMENU_MENUOPTION
+ jr z, .nope
+ ld d, [hl]
+ inc hl
+ ld a, [hli]
+ cp b
+ jr nz, .next
+ ld a, d
+ scf
+
+.nope
+ ret
+
+ResetMonSubmenu:
+ xor a
+ ld [wBuffer1], a
+ ld hl, wBuffer2
+ ld bc, NUM_MONMENU_ITEMS + 1
+ call ByteFill
+ ret
+
+TerminateMonSubmenu:
+ ld a, [wBuffer1]
+ ld e, a
+ ld d, 0
+ ld hl, wBuffer2
+ add hl, de
+ ld [hl], -1
+ ret
+
+AddMonMenuItem:
+ push hl
+ push de
+ push af
+ ld a, [wBuffer1]
+ ld e, a
+ inc a
+ ld [wBuffer1], a
+ ld d, 0
+ ld hl, wBuffer2
+ add hl, de
+ pop af
+ ld [hl], a
+ pop de
+ pop hl
+ ret
+
+BattleMonMenu:
+ ld hl, MenuHeader_0x24e44
+ call CopyMenuHeader
+ xor a
+ ldh [hBGMapMode], a
+ call MenuBox
+ call UpdateSprites
+ call PlaceVerticalMenuItems
+ call WaitBGMap
+ call CopyMenuData
+ ld a, [wMenuDataFlags]
+ bit 7, a
+ jr z, .set_carry
+ call InitVerticalMenuCursor
+ ld hl, w2DMenuFlags1
+ set 6, [hl]
+ call StaticMenuJoypad
+ ld de, SFX_READ_TEXT_2
+ call PlaySFX
+ ldh a, [hJoyPressed]
+ bit B_BUTTON_F, a
+ jr z, .clear_carry
+ ret z
+
+.set_carry
+ scf
+ ret
+
+.clear_carry
+ and a
+ ret
+
+MenuHeader_0x24e44:
+ db 0 ; flags
+ menu_coords 11, 11, SCREEN_WIDTH - 1, SCREEN_HEIGHT - 1
+ dw MenuData_0x24e4c
+ db 1 ; default option
+
+MenuData_0x24e4c:
+ db STATICMENU_CURSOR | STATICMENU_NO_TOP_SPACING ; flags
+ db 3 ; items
+ db "SWITCH@"
+ db "STATS@"
+ db "CANCEL@"
diff --git a/engine/move_mon.asm b/engine/pokemon/move_mon.asm
index 7410375f..b1988f68 100755
--- a/engine/move_mon.asm
+++ b/engine/pokemon/move_mon.asm
@@ -1,34 +1,47 @@
-TryAddMonToParty:: ; d892 (3:5892)
+RANDY_OT_ID EQU 01001
+
+TryAddMonToParty:
+; Check if to copy wild mon or generate a new one
+ ; Whose is it?
ld de, wPartyCount
ld a, [wMonType]
and $f
- jr z, .asm_d89f
+ jr z, .getpartylocation ; PARTYMON
ld de, wOTPartyCount
-.asm_d89f
+
+.getpartylocation
+ ; Do we have room for it?
ld a, [de]
inc a
- cp $7
+ cp PARTY_LENGTH + 1
ret nc
+ ; Increase the party count
ld [de], a
- ld a, [de]
- ldh [hMoveMon], a
+ ld a, [de] ; Why are we doing this?
+ ldh [hMoveMon], a ; HRAM backup
add e
ld e, a
- jr nc, .asm_d8ad
+ jr nc, .loadspecies
inc d
-.asm_d8ad
+
+.loadspecies
+ ; Load the species of the Pokemon into the party list.
+ ; The terminator is usually here, but it'll be back.
ld a, [wCurPartySpecies]
ld [de], a
+ ; Load the terminator into the next slot.
inc de
- ld a, $ff
+ ld a, -1
ld [de], a
- ld hl, wPartyMon1OT
+ ; Now let's load the OT name.
+ ld hl, wPartyMonOT
ld a, [wMonType]
and $f
- jr z, .asm_d8c2
+ jr z, .loadOTname
ld hl, wOTPartyMonOT
-.asm_d8c2
- ldh a, [hMoveMon]
+
+.loadOTname
+ ldh a, [hMoveMon] ; Restore index from backup
dec a
call SkipNames
ld d, h
@@ -36,11 +49,12 @@ TryAddMonToParty:: ; d892 (3:5892)
ld hl, wPlayerName
ld bc, NAME_LENGTH
call CopyBytes
+ ; Only initialize the nickname for party mon
ld a, [wMonType]
and a
- jr nz, .asm_d8f6
+ jr nz, .skipnickname
ld a, [wCurPartySpecies]
- ld [wd151], a
+ ld [wNamedObjectIndexBuffer], a
call GetPokemonName
ld hl, wPartyMonNicknames
ldh a, [hMoveMon]
@@ -49,74 +63,83 @@ TryAddMonToParty:: ; d892 (3:5892)
ld d, h
ld e, l
ld hl, wStringBuffer1
- ld bc, NAME_LENGTH
+ ld bc, MON_NAME_LENGTH
call CopyBytes
-.asm_d8f6
+
+.skipnickname
ld hl, wPartyMon1Species
ld a, [wMonType]
and $f
- jr z, .asm_d903
- ld hl, wOTPartyMon1
-.asm_d903
+ jr z, .initializeStats
+ ld hl, wOTPartyMon1Species
+
+.initializeStats
ldh a, [hMoveMon]
dec a
ld bc, PARTYMON_STRUCT_LENGTH
call AddNTimes
GeneratePartyMonStats:
+; wBattleMode specifies whether it's a wild mon or not.
+; wMonType specifies whether it's an opposing mon or not.
+; wCurPartySpecies/wCurPartyLevel specify the species and level.
+; hl points to the wPartyMon struct to fill.
+
ld e, l
ld d, h
push hl
+
+ ; Initialize the species
ld a, [wCurPartySpecies]
ld [wCurSpecies], a
call GetBaseData
- ld a, [wd120]
+ ld a, [wBaseDexNo]
ld [de], a
inc de
+
+ ; Copy the item if it's a wild mon
ld a, [wBattleMode]
and a
ld a, $0
- jr z, .asm_d928
+ jr z, .skipitem
ld a, [wEnemyMonItem]
-.asm_d928
+.skipitem
ld [de], a
inc de
+
+ ; Copy the moves if it's a wild mon
push de
ld h, d
ld l, e
ld a, [wBattleMode]
and a
- jr z, .asm_d949
+ jr z, .randomlygeneratemoves
ld a, [wMonType]
and a
- jr nz, .asm_d949
+ jr nz, .randomlygeneratemoves
ld de, wEnemyMonMoves
+rept NUM_MOVES - 1
ld a, [de]
inc de
ld [hli], a
- ld a, [de]
- inc de
- ld [hli], a
- ld a, [de]
- inc de
- ld [hli], a
+endr
ld a, [de]
ld [hl], a
- jr .asm_d956
+ jr .next
-.asm_d949
+.randomlygeneratemoves
xor a
+rept NUM_MOVES - 1
ld [hli], a
- ld [hli], a
- ld [hli], a
+endr
ld [hl], a
- ld [wBuffer1], a
+ ld [wEvolutionOldSpecies], a
predef FillMoves
-.asm_d956
+
+.next
pop de
+rept NUM_MOVES
inc de
- inc de
- inc de
- inc de
+endr
; Initialize ID.
ld a, [wPlayerID]
@@ -145,47 +168,53 @@ GeneratePartyMonStats:
; Initialize stat experience.
xor a
ld b, MON_DVS - MON_STAT_EXP
-.asm_d980
+.loop
ld [de], a
inc de
dec b
- jr nz, .asm_d980
+ jr nz, .loop
+
pop hl
push hl
ld a, [wMonType]
and $f
- jr z, .asm_d998
+ jr z, .registerpokedex
+
push hl
- farcall GetTrainerDVs ; 9:7271
+ farcall GetTrainerDVs
pop hl
- jr .asm_d9bb
+ jr .initializeDVs
-.asm_d998
+.registerpokedex
ld a, [wCurPartySpecies]
- ld [wd151], a
+ ld [wTempSpecies], a
dec a
push de
call CheckCaughtMon
- ld a, [wd151]
+ ld a, [wTempSpecies]
dec a
call SetSeenAndCaughtMon
pop de
+
pop hl
push hl
ld a, [wBattleMode]
and a
- jr nz, .asm_d9f9
+ jr nz, .copywildmonDVs
+
call Random
ld b, a
call Random
ld c, a
-.asm_d9bb
+.initializeDVs
ld a, b
ld [de], a
inc de
ld a, c
ld [de], a
inc de
+
+ ; Initialize PP.
push hl
push de
inc hl
@@ -193,33 +222,45 @@ GeneratePartyMonStats:
call FillPP
pop de
pop hl
+rept NUM_MOVES
inc de
- inc de
- inc de
- inc de
- ld a, $46
+endr
+
+ ; Initialize happiness.
+ ld a, BASE_HAPPINESS
ld [de], a
inc de
+
xor a
+ ; PokerusStatus
ld [de], a
inc de
+ ; CaughtData/CaughtTime/CaughtLevel
ld [de], a
inc de
+ ; CaughtGender/CaughtLocation
ld [de], a
inc de
+
+ ; Initialize level.
ld a, [wCurPartyLevel]
ld [de], a
inc de
+
xor a
+ ; Status
ld [de], a
inc de
+ ; Unused
ld [de], a
inc de
- ld bc, $a
+
+ ; Initialize HP.
+ ld bc, MON_STAT_EXP - 1
add hl, bc
- ld a, $1
+ ld a, 1
ld c, a
- ld b, $0
+ ld b, FALSE
call CalcMonStatC
ldh a, [hProduct + 2]
ld [de], a
@@ -227,128 +268,147 @@ GeneratePartyMonStats:
ldh a, [hProduct + 3]
ld [de], a
inc de
- jr .asm_da2f
+ jr .initstats
-.asm_d9f9
- ld a, [wEnemyMonMovesEnd]
+.copywildmonDVs
+ ld a, [wEnemyMonDVs]
ld [de], a
inc de
- ld a, [wEnemyMonMovesEnd + 1]
+ ld a, [wEnemyMonDVs + 1]
ld [de], a
inc de
+
push hl
ld hl, wEnemyMonPP
- ld b, $4
-.asm_da09
+ ld b, NUM_MOVES
+.wildmonpploop
ld a, [hli]
ld [de], a
inc de
dec b
- jr nz, .asm_da09
+ jr nz, .wildmonpploop
pop hl
- ld a, $46
+
+ ; Initialize happiness.
+ ld a, BASE_HAPPINESS
ld [de], a
inc de
+
xor a
+ ; PokerusStatus
ld [de], a
inc de
+ ; CaughtData/CaughtTime/CaughtLevel
ld [de], a
inc de
+ ; CaughtGender/CaughtLocation
ld [de], a
inc de
+
+ ; Initialize level.
ld a, [wCurPartyLevel]
ld [de], a
inc de
+
ld hl, wEnemyMonStatus
+ ; Copy wEnemyMonStatus
ld a, [hli]
ld [de], a
inc de
+ ; Copy EnemyMonUnused
ld a, [hli]
ld [de], a
inc de
+ ; Copy wEnemyMonHP
ld a, [hli]
ld [de], a
inc de
ld a, [hl]
ld [de], a
inc de
-.asm_da2f
+
+.initstats
ld a, [wBattleMode]
dec a
- jr nz, .asm_da41
+ jr nz, .generatestats
ld hl, wEnemyMonMaxHP
- ld bc, $c
+ ld bc, PARTYMON_STRUCT_LENGTH - MON_MAXHP
call CopyBytes
pop hl
- jr .asm_da4b
+ jr .registerunowndex
-.asm_da41
+.generatestats
pop hl
- ld bc, $a
+ ld bc, MON_STAT_EXP - 1
add hl, bc
- ld b, $0
+ ld b, FALSE
call CalcMonStats
-.asm_da4b
+
+.registerunowndex
ld a, [wMonType]
and $f
- jr nz, .asm_da71
+ jr nz, .done
ld a, [wCurPartySpecies]
- cp $c9
- jr nz, .asm_da71
+ cp UNOWN
+ jr nz, .done
ld hl, wPartyMon1DVs
- ld a, [wPokemonData]
+ ld a, [wPartyCount]
dec a
ld bc, PARTYMON_STRUCT_LENGTH
call AddNTimes
predef GetUnownLetter
callfar UpdateUnownDex
-.asm_da71
- scf
+
+.done
+ scf ; When this function returns, the carry flag indicates success vs failure.
ret
-FillPP: ; da73 (3:5a73)
+FillPP:
push bc
- ld b, $4
-.asm_da76
+ ld b, NUM_MOVES
+.loop
ld a, [hli]
and a
- jr z, .asm_da95
+ jr z, .next
dec a
push hl
push de
push bc
- ld hl, $5afe
- ld bc, $7
+ ld hl, Moves
+ ld bc, MOVE_LENGTH
call AddNTimes
ld de, wStringBuffer1
- ld a, $10
+ ld a, BANK(Moves)
call FarCopyBytes
pop bc
pop de
pop hl
- ld a, [wStringBuffer1 + 5]
-.asm_da95
+ ld a, [wStringBuffer1 + MOVE_PP]
+
+.next
ld [de], a
inc de
dec b
- jr nz, .asm_da76
+ jr nz, .loop
pop bc
ret
-AddTempmonToParty: ; da9c (3:5a9c)
+AddTempmonToParty:
ld hl, wPartyCount
ld a, [hl]
- cp $6
+ cp PARTY_LENGTH
scf
ret z
+
inc a
ld [hl], a
ld c, a
- ld b, $0
+ ld b, 0
add hl, bc
ld a, [wCurPartySpecies]
ld [hli], a
ld [hl], $ff
+
ld hl, wPartyMon1Species
ld a, [wPartyCount]
dec a
@@ -358,44 +418,48 @@ AddTempmonToParty: ; da9c (3:5a9c)
ld d, h
ld hl, wTempMonSpecies
call CopyBytes
- ld hl, wPartyMon6StatsEnd
+
+ ld hl, wPartyMonOT
ld a, [wPartyCount]
dec a
call SkipNames
ld d, h
ld e, l
- ld hl, wOTPartyMon6StatsEnd
+ ld hl, wOTPartyMonOT
ld a, [wCurPartyMon]
call SkipNames
ld bc, NAME_LENGTH
call CopyBytes
+
ld hl, wPartyMonNicknames
ld a, [wPartyCount]
dec a
call SkipNames
ld d, h
ld e, l
- ld hl, wOTPartyMon1Nickname
+ ld hl, wOTPartyMonNicknames
ld a, [wCurPartyMon]
call SkipNames
- ld bc, NAME_LENGTH
+ ld bc, MON_NAME_LENGTH
call CopyBytes
+
ld a, [wCurPartySpecies]
- ld [wd151], a
+ ld [wNamedObjectIndexBuffer], a
cp EGG
- jr z, .asm_db18
+ jr z, .egg
dec a
call SetSeenAndCaughtMon
ld hl, wPartyMon1Happiness
- ld a, [wPokemonData]
+ ld a, [wPartyCount]
dec a
ld bc, PARTYMON_STRUCT_LENGTH
call AddNTimes
- ld [hl], 70
-.asm_db18
+ ld [hl], BASE_HAPPINESS
+.egg
+
ld a, [wCurPartySpecies]
cp UNOWN
- jr nz, .asm_db43
+ jr nz, .done
ld hl, wPartyMon1DVs
ld a, [wPartyCount]
dec a
@@ -405,62 +469,76 @@ AddTempmonToParty: ; da9c (3:5a9c)
callfar UpdateUnownDex
ld a, [wFirstUnownSeen]
and a
- jr nz, .asm_db43
- ld a, [wd11e]
+ jr nz, .done
+ ld a, [wUnownLetter]
ld [wFirstUnownSeen], a
-.asm_db43
+.done
+
and a
ret
-SendGetMonIntoFromBox: ; db45 (3:5b45)
- ld a, $1
+SendGetMonIntoFromBox:
+; Sents/Gets mon into/from Box depending on Parameter
+; wPokemonWithdrawDepositParameter == 0: get mon into Party
+; wPokemonWithdrawDepositParameter == 1: sent mon into Box
+; wPokemonWithdrawDepositParameter == 2: get mon from DayCare
+; wPokemonWithdrawDepositParameter == 3: put mon into DayCare
+
+ ld a, BANK(sBoxCount)
call OpenSRAM
ld a, [wPokemonWithdrawDepositParameter]
and a
- jr z, .asm_db66
- cp $2
- jr z, .asm_db66
- cp $3
+ jr z, .check_IfPartyIsFull
+ cp DAY_CARE_WITHDRAW
+ jr z, .check_IfPartyIsFull
+ cp DAY_CARE_DEPOSIT
ld hl, wBreedMon1Species
- jr z, .asm_dba1
+ jr z, .breedmon
+
+ ; we want to sent a mon into the Box
+ ; so check if there's enough space
ld hl, sBoxCount
ld a, [hl]
cp MONS_PER_BOX
- jr nz, .asm_db6f
- jp Functiondcb7
+ jr nz, .there_is_room
+ jp CloseSRAM_And_SetCarryFlag
-.asm_db66
+.check_IfPartyIsFull
ld hl, wPartyCount
ld a, [hl]
- cp $6
- jp z, Functiondcb7
-.asm_db6f
+ cp PARTY_LENGTH
+ jp z, CloseSRAM_And_SetCarryFlag
+
+.there_is_room
inc a
ld [hl], a
ld c, a
- ld b, $0
+ ld b, 0
add hl, bc
ld a, [wPokemonWithdrawDepositParameter]
- cp $2
+ cp DAY_CARE_WITHDRAW
ld a, [wBreedMon1Species]
- jr z, .asm_db82
+ jr z, .okay1
ld a, [wCurPartySpecies]
-.asm_db82
+
+.okay1
ld [hli], a
ld [hl], $ff
ld a, [wPokemonWithdrawDepositParameter]
dec a
- ld hl, wPartyMons
+ ld hl, wPartyMon1Species
ld bc, PARTYMON_STRUCT_LENGTH
- ld a, [wPokemonData]
- jr nz, .asm_db9d
+ ld a, [wPartyCount]
+ jr nz, .okay2
ld hl, sBoxMon1Species
ld bc, BOXMON_STRUCT_LENGTH
ld a, [sBoxCount]
-.asm_db9d
- dec a
+
+.okay2
+ dec a ; wPartyCount - 1
call AddNTimes
-.asm_dba1
+
+.breedmon
push hl
ld e, l
ld d, h
@@ -468,84 +546,96 @@ SendGetMonIntoFromBox: ; db45 (3:5b45)
and a
ld hl, sBoxMon1Species
ld bc, BOXMON_STRUCT_LENGTH
- jr z, .asm_dbbd
- cp $2
+ jr z, .okay3
+ cp DAY_CARE_WITHDRAW
ld hl, wBreedMon1Species
- jr z, .asm_dbc3
+ jr z, .okay4
ld hl, wPartyMon1Species
ld bc, PARTYMON_STRUCT_LENGTH
-.asm_dbbd
+
+.okay3
ld a, [wCurPartyMon]
call AddNTimes
-.asm_dbc3
+
+.okay4
ld bc, BOXMON_STRUCT_LENGTH
call CopyBytes
ld a, [wPokemonWithdrawDepositParameter]
- cp $3
+ cp DAY_CARE_DEPOSIT
ld de, wBreedMon1OT
- jr z, .asm_dbe8
+ jr z, .okay5
dec a
ld hl, wPartyMonOT
- ld a, [wPokemonData]
- jr nz, .asm_dbe2
+ ld a, [wPartyCount]
+ jr nz, .okay6
ld hl, sBoxMonOT
ld a, [sBoxCount]
-.asm_dbe2
+
+.okay6
dec a
call SkipNames
ld d, h
ld e, l
-.asm_dbe8
+
+.okay5
ld hl, sBoxMonOT
ld a, [wPokemonWithdrawDepositParameter]
and a
- jr z, .asm_dbfb
+ jr z, .okay7
ld hl, wBreedMon1OT
- cp $2
- jr z, .asm_dc01
- ld hl, wPartyMon6StatsEnd
-.asm_dbfb
+ cp DAY_CARE_WITHDRAW
+ jr z, .okay8
+ ld hl, wPartyMonOT
+
+.okay7
ld a, [wCurPartyMon]
call SkipNames
-.asm_dc01
+
+.okay8
ld bc, NAME_LENGTH
call CopyBytes
ld a, [wPokemonWithdrawDepositParameter]
- cp $3
+ cp DAY_CARE_DEPOSIT
ld de, wBreedMon1Nick
- jr z, .asm_dc26
+ jr z, .okay9
dec a
- ld hl, wPartyMon1Nickname
- ld a, [wPokemonData]
- jr nz, .asm_dc20
+ ld hl, wPartyMonNicknames
+ ld a, [wPartyCount]
+ jr nz, .okay10
ld hl, sBoxMonNicknames
ld a, [sBoxCount]
-.asm_dc20
+
+.okay10
dec a
call SkipNames
ld d, h
ld e, l
-.asm_dc26
+
+.okay9
ld hl, sBoxMonNicknames
ld a, [wPokemonWithdrawDepositParameter]
and a
- jr z, .asm_dc39
+ jr z, .okay11
ld hl, wBreedMon1Nick
- cp $2
- jr z, .asm_dc3f
- ld hl, wPartyMon1Nickname
-.asm_dc39
+ cp DAY_CARE_WITHDRAW
+ jr z, .okay12
+ ld hl, wPartyMonNicknames
+
+.okay11
ld a, [wCurPartyMon]
call SkipNames
-.asm_dc3f
- ld bc, NAME_LENGTH
+
+.okay12
+ ld bc, MON_NAME_LENGTH
call CopyBytes
pop hl
+
ld a, [wPokemonWithdrawDepositParameter]
- cp $1
- jr z, .asm_dcaa
- cp $3
- jp z, Functiondcb2
+ cp PC_DEPOSIT
+ jr z, .took_out_of_box
+ cp DAY_CARE_DEPOSIT
+ jp z, .CloseSRAM_And_ClearCarryFlag
+
push hl
srl a
add $2
@@ -555,35 +645,38 @@ SendGetMonIntoFromBox: ; db45 (3:5b45)
ld a, d
ld [wCurPartyLevel], a
pop hl
+
ld b, h
ld c, l
- ld hl, $1f
+ ld hl, MON_LEVEL
add hl, bc
ld [hl], a
- ld hl, $24
+ ld hl, MON_MAXHP
add hl, bc
ld d, h
ld e, l
- ld hl, $a
+ ld hl, MON_STAT_EXP - 1
add hl, bc
+
push bc
- ld b, $1
+ ld b, TRUE
call CalcMonStats
pop bc
+
ld a, [wPokemonWithdrawDepositParameter]
and a
- jr nz, Functiondcb2
- ld hl, $20
+ jr nz, .CloseSRAM_And_ClearCarryFlag
+ ld hl, MON_STATUS
add hl, bc
xor a
ld [hl], a
- ld hl, $22
+ ld hl, MON_HP
add hl, bc
ld d, h
ld e, l
ld a, [wCurPartySpecies]
- cp $fd
- jr z, .asm_dca4
+ cp EGG
+ jr z, .egg
inc hl
inc hl
ld a, [hli]
@@ -591,86 +684,88 @@ SendGetMonIntoFromBox: ; db45 (3:5b45)
ld a, [hl]
inc de
ld [de], a
- jr Functiondcb2
+ jr .CloseSRAM_And_ClearCarryFlag
-.asm_dca4
+.egg
xor a
ld [de], a
inc de
ld [de], a
- jr Functiondcb2
+ jr .CloseSRAM_And_ClearCarryFlag
-.asm_dcaa
+.took_out_of_box
ld a, [sBoxCount]
dec a
ld b, a
- call Functiondcbc
-Functiondcb2: ; dcb2 (3:5cb2)
+ call RestorePPOfDepositedPokemon
+.CloseSRAM_And_ClearCarryFlag:
call CloseSRAM
and a
ret
-Functiondcb7: ; dcb7 (3:5cb7)
+CloseSRAM_And_SetCarryFlag:
call CloseSRAM
scf
ret
-Functiondcbc: ; dcbc (3:5cbc)
+RestorePPOfDepositedPokemon:
ld a, b
- ld hl, sBoxMon1Species
+ ld hl, sBoxMons
ld bc, BOXMON_STRUCT_LENGTH
call AddNTimes
ld b, h
ld c, l
- ld hl, $17
+ ld hl, MON_PP
add hl, bc
push hl
push bc
ld de, wTempMonPP
- ld bc, $4
+ ld bc, NUM_MOVES
call CopyBytes
pop bc
- ld hl, $2
+ ld hl, MON_MOVES
add hl, bc
push hl
ld de, wTempMonMoves
- ld bc, $4
+ ld bc, NUM_MOVES
call CopyBytes
pop hl
pop de
+
ld a, [wMenuCursorY]
push af
ld a, [wMonType]
push af
- ld b, $0
-.asm_dcf2
+ ld b, 0
+.loop
ld a, [hli]
and a
- jr z, .asm_dd1e
+ jr z, .done
ld [wTempMonMoves], a
- ld a, $2
+ ld a, BOXMON
ld [wMonType], a
ld a, b
ld [wMenuCursorY], a
push bc
push hl
push de
- farcall GetMaxPPOfMove ; same bank
+ farcall GetMaxPPOfMove
pop de
pop hl
- ld a, [wd151]
+ ld a, [wTempPP]
ld b, a
ld a, [de]
- and $c0
+ and %11000000
add b
ld [de], a
pop bc
inc de
inc b
ld a, b
- cp $4
- jr c, .asm_dcf2
-.asm_dd1e
+ cp NUM_MOVES
+ jr c, .loop
+
+.done
pop af
ld [wMonType], a
pop af
@@ -685,12 +780,12 @@ RetrieveMonFromDayCareMan:
call WaitSFX
call GetBreedMon1LevelGrowth
ld a, b
- ld [wMovementBufferCount], a
+ ld [wceed], a
ld a, e
ld [wCurPartyLevel], a
xor a
ld [wPokemonWithdrawDepositParameter], a
- jp Functiondd6a
+ jp RetrieveBreedmon
RetrieveMonFromDayCareLady:
ld a, [wBreedMon2Species]
@@ -700,40 +795,41 @@ RetrieveMonFromDayCareLady:
call WaitSFX
call GetBreedMon2LevelGrowth
ld a, b
- ld [wMovementBufferCount], a
+ ld [wceed], a
ld a, e
ld [wCurPartyLevel], a
- ld a, $1
+ ld a, PC_DEPOSIT
ld [wPokemonWithdrawDepositParameter], a
- jp Functiondd6a ; super long jump
+ jp RetrieveBreedmon
-Functiondd6a: ; dd6a (3:5d6a)
- ld hl, wPokemonData
+RetrieveBreedmon:
+ ld hl, wPartyCount
ld a, [hl]
- cp $6
- jr nz, .asm_dd74
- scf ; We shouldn't be here if we've come this far.
+ cp PARTY_LENGTH
+ jr nz, .room_in_party
+ scf
ret
-.asm_dd74
+.room_in_party
inc a
ld [hl], a
ld c, a
- ld b, $0
+ ld b, 0
add hl, bc
ld a, [wPokemonWithdrawDepositParameter]
and a
ld a, [wBreedMon1Species]
ld de, wBreedMon1Nick
- jr z, .asm_dd8c
+ jr z, .okay
ld a, [wBreedMon2Species]
ld de, wBreedMon2Nick
-.asm_dd8c
+
+.okay
ld [hli], a
ld [wCurSpecies], a
ld a, $ff
ld [hl], a
- ld hl, wPartyMon1Nickname
+ ld hl, wPartyMonNicknames
ld a, [wPartyCount]
dec a
call SkipNames
@@ -752,60 +848,60 @@ Functiondd6a: ; dd6a (3:5d6a)
pop hl
call CopyBytes
push hl
- call Functionde20
+ call GetLastPartyMon
pop hl
ld bc, BOXMON_STRUCT_LENGTH
call CopyBytes
call GetBaseData
- call Functionde20
+ call GetLastPartyMon
ld b, d
ld c, e
- ld hl, $1f
+ ld hl, MON_LEVEL
add hl, bc
ld a, [wCurPartyLevel]
ld [hl], a
- ld hl, $24
+ ld hl, MON_MAXHP
add hl, bc
ld d, h
ld e, l
ld hl, $a
add hl, bc
push bc
- ld b, $1
+ ld b, TRUE
call CalcMonStats
ld hl, wPartyMon1Moves
- ld a, [wPokemonData]
+ ld a, [wPartyCount]
dec a
ld bc, PARTYMON_STRUCT_LENGTH
call AddNTimes
ld d, h
ld e, l
ld a, $1
- ld [wCurHPAnim], a
+ ld [wBuffer1], a
predef FillMoves
ld a, [wPartyCount]
dec a
ld [wCurPartyMon], a
- farcall Functionc6bc ; same bank
+ farcall HealPartyMon
ld a, [wCurPartyLevel]
ld d, a
callfar CalcExpAtLevel
pop bc
ld hl, $8
add hl, bc
- ldh a, [hQuotient]
+ ldh a, [hMultiplicand]
ld [hli], a
- ldh a, [hPrintNum3]
+ ldh a, [hMultiplicand + 1]
ld [hli], a
- ldh a, [hPrintNum4]
+ ldh a, [hMultiplicand + 2]
ld [hl], a
and a
ret
-Functionde20: ; de20 (3:5e20)
+GetLastPartyMon:
ld a, [wPartyCount]
dec a
- ld hl, wPartyMon1
+ ld hl, wPartyMon1Species
ld bc, PARTYMON_STRUCT_LENGTH
call AddNTimes
ld d, h
@@ -814,47 +910,50 @@ Functionde20: ; de20 (3:5e20)
DepositMonWithDayCareMan:
ld de, wBreedMon1Nick
- call Functionde4a
- xor a
+ call DepositBreedmon
+ xor a ; REMOVE_PARTY
ld [wPokemonWithdrawDepositParameter], a
jp RemoveMonFromPartyOrBox
DepositMonWithDayCareLady:
ld de, wBreedMon2Nick
- call Functionde4a
- xor a
+ call DepositBreedmon
+ xor a ; REMOVE_PARTY
ld [wPokemonWithdrawDepositParameter], a
jp RemoveMonFromPartyOrBox
-Functionde4a: ; de4a (3:5e4a)
+DepositBreedmon:
ld a, [wCurPartyMon]
ld hl, wPartyMonNicknames
call SkipNames
call CopyBytes
ld a, [wCurPartyMon]
- ld hl, wPartyMon1OT
+ ld hl, wPartyMonOT
call SkipNames
call CopyBytes
ld a, [wCurPartyMon]
- ld hl, wPartyMon1
+ ld hl, wPartyMon1Species
ld bc, PARTYMON_STRUCT_LENGTH
call AddNTimes
ld bc, BOXMON_STRUCT_LENGTH
jp CopyBytes
-SendMonIntoBox: ; de74 (3:5e74)
- ld a, $1
+SendMonIntoBox:
+; Sends the mon into one of Bills Boxes
+; the data comes mainly from 'wEnemyMon:'
+ ld a, BANK(sBoxCount)
call OpenSRAM
ld de, sBoxCount
ld a, [de]
- cp $14
- jp nc, Functiondf48
+ cp MONS_PER_BOX
+ jp nc, .full
inc a
ld [de], a
+
ld a, [wCurPartySpecies]
ld [wCurSpecies], a
ld c, a
-.asm_de8b
+.loop
inc de
ld a, [de]
ld b, a
@@ -862,25 +961,31 @@ SendMonIntoBox: ; de74 (3:5e74)
ld c, b
ld [de], a
inc a
- jr nz, .asm_de8b
+ jr nz, .loop
+
call GetBaseData
- call Functiondf4d
+ call ShiftBoxMon
+
ld hl, wPlayerName
ld de, sBoxMonOT
ld bc, NAME_LENGTH
call CopyBytes
+
ld a, [wCurPartySpecies]
- ld [wd151], a
+ ld [wNamedObjectIndexBuffer], a
call GetPokemonName
+
ld de, sBoxMonNicknames
ld hl, wStringBuffer1
- ld bc, NAME_LENGTH
+ ld bc, MON_NAME_LENGTH
call CopyBytes
+
ld hl, wEnemyMon
- ld de, sBoxMon1Species
- ld bc, $6
+ ld de, sBoxMon1
+ ld bc, 1 + 1 + NUM_MOVES ; species + item + moves
call CopyBytes
- ld hl, wGameData
+
+ ld hl, wPlayerID
ld a, [hli]
ld [de], a
inc de
@@ -892,31 +997,35 @@ SendMonIntoBox: ; de74 (3:5e74)
ld d, a
callfar CalcExpAtLevel
pop de
- ldh a, [hQuotient]
+ ldh a, [hProduct + 1]
ld [de], a
inc de
- ldh a, [hPrintNum3]
+ ldh a, [hProduct + 2]
ld [de], a
inc de
- ldh a, [hPrintNum4]
+ ldh a, [hProduct + 3]
ld [de], a
inc de
+
+ ; Set all 5 Experience Values to 0
xor a
- ld b, $a
-.asm_deeb
+ ld b, 2 * 5
+.loop2
ld [de], a
inc de
dec b
- jr nz, .asm_deeb
- ld hl, wEnemyMonMovesEnd
- ld b, $6
-.asm_def5
+ jr nz, .loop2
+
+ ld hl, wEnemyMonDVs
+ ld b, 2 + NUM_MOVES ; DVs and PP ; wEnemyMonHappiness - wEnemyMonDVs
+.loop3
ld a, [hli]
ld [de], a
inc de
dec b
- jr nz, .asm_def5
- ld a, $46
+ jr nz, .loop3
+
+ ld a, BASE_HAPPINESS
ld [de], a
inc de
xor a
@@ -932,90 +1041,109 @@ SendMonIntoBox: ; de74 (3:5e74)
dec a
call SetSeenAndCaughtMon
ld a, [wCurPartySpecies]
- cp $c9
- jr nz, .asm_df26
+ cp UNOWN
+ jr nz, .not_unown
ld hl, sBoxMon1DVs
predef GetUnownLetter
callfar UpdateUnownDex
-.asm_df26
+
+.not_unown
ld hl, sBoxMon1Moves
ld de, wTempMonMoves
- ld bc, $4
+ ld bc, NUM_MOVES
call CopyBytes
+
ld hl, sBoxMon1PP
ld de, wTempMonPP
- ld bc, $4
+ ld bc, NUM_MOVES
call CopyBytes
- ld b, $0
- call Functiondcbc
+
+ ld b, 0
+ call RestorePPOfDepositedPokemon
+
call CloseSRAM
scf
ret
-Functiondf48: ; df48 (3:5f48)
+.full
call CloseSRAM
and a
ret
-Functiondf4d: ; df4d (3:5f4d)
+ShiftBoxMon:
ld hl, sBoxMonOT
ld bc, NAME_LENGTH
- call Functiondf65
+ call .shift
+
ld hl, sBoxMonNicknames
- ld bc, NAME_LENGTH
- call Functiondf65
- ld hl, sBoxMon1Species
+ ld bc, MON_NAME_LENGTH
+ call .shift
+
+ ld hl, sBoxMons
ld bc, BOXMON_STRUCT_LENGTH
-Functiondf65: ; df65 (3:5f65)
+
+.shift
ld a, [sBoxCount]
- cp $2
+ cp 2
ret c
+
push hl
call AddNTimes
dec hl
ld e, l
ld d, h
pop hl
+
ld a, [sBoxCount]
dec a
call AddNTimes
dec hl
+
push hl
ld a, [sBoxCount]
dec a
- ld hl, $0
+ ld hl, 0
call AddNTimes
ld c, l
ld b, h
pop hl
-.asm_df89
+.loop
ld a, [hld]
ld [de], a
dec de
dec bc
ld a, c
or b
- jr nz, .asm_df89
+ jr nz, .loop
ret
-GiveEgg: ; df92 (3:5f92)
+GiveEgg::
ld a, [wCurPartySpecies]
push af
callfar GetPreEvolution
callfar GetPreEvolution
ld a, [wCurPartySpecies]
dec a
+
+; TryAddMonToParty sets Seen and Caught flags
+; when it is successful. This routine will make
+; sure that we aren't newly setting flags.
push af
call CheckCaughtMon
pop af
push bc
call CheckSeenMon
push bc
+
call TryAddMonToParty
+
+; If we haven't caught this Pokemon before receiving
+; the Egg, reset the flag that was just set by
+; TryAddMonToParty.
pop bc
ld a, c
and a
- jr nz, .asm_dfc9
+ jr nz, .skip_caught_flag
ld a, [wCurPartySpecies]
dec a
ld c, a
@@ -1023,11 +1151,15 @@ GiveEgg: ; df92 (3:5f92)
ld hl, wPokedexCaught
ld b, RESET_FLAG
predef SmallFarFlagAction
-.asm_dfc9
+
+.skip_caught_flag
+; If we haven't seen this Pokemon before receiving
+; the Egg, reset the flag that was just set by
+; TryAddMonToParty.
pop bc
ld a, c
and a
- jr nz, .asm_dfdf
+ jr nz, .skip_seen_flag
ld a, [wCurPartySpecies]
dec a
ld c, a
@@ -1035,26 +1167,27 @@ GiveEgg: ; df92 (3:5f92)
ld hl, wPokedexSeen
ld b, RESET_FLAG
predef SmallFarFlagAction
-.asm_dfdf
+
+.skip_seen_flag
pop af
ld [wCurPartySpecies], a
- ld a, [wPokemonData]
+ ld a, [wPartyCount]
dec a
ld bc, PARTYMON_STRUCT_LENGTH
ld hl, wPartyMon1Species
call AddNTimes
ld a, [wCurPartySpecies]
ld [hl], a
- ld hl, wPokemonData
+ ld hl, wPartyCount
ld a, [hl]
- ld b, $0
+ ld b, 0
ld c, a
add hl, bc
- ld a, $fd
+ ld a, EGG
ld [hl], a
- ld a, [wPokemonData]
+ ld a, [wPartyCount]
dec a
- ld hl, wPartyMon1Nickname
+ ld hl, wPartyMonNicknames
call SkipNames
ld de, String_Egg
call CopyName2
@@ -1064,11 +1197,12 @@ GiveEgg: ; df92 (3:5f92)
ld bc, PARTYMON_STRUCT_LENGTH
call AddNTimes
ld a, [wDebugFlags]
- bit 1, a
- ld a, $1
- jr nz, .asm_e028
+ bit DEBUG_FIELD_F, a
+ ld a, 1
+ jr nz, .got_init_happiness
ld a, [wBaseEggSteps]
-.asm_e028
+
+.got_init_happiness
ld [hl], a
ld a, [wPartyCount]
dec a
@@ -1084,119 +1218,132 @@ GiveEgg: ; df92 (3:5f92)
String_Egg:
db "EGG@"
-RemoveMonFromPartyOrBox: ; e03f (3:603f)
+RemoveMonFromPartyOrBox:
ld hl, wPartyCount
+
ld a, [wPokemonWithdrawDepositParameter]
and a
- jr z, .asm_e050
- ld a, $1
+ jr z, .okay
+
+ ld a, BANK(sBoxCount)
call OpenSRAM
ld hl, sBoxCount
-.asm_e050
+
+.okay
ld a, [hl]
dec a
ld [hli], a
ld a, [wCurPartyMon]
ld c, a
- ld b, $0
+ ld b, 0
add hl, bc
ld e, l
ld d, h
inc de
-.asm_e05d
+.loop
ld a, [de]
inc de
ld [hli], a
inc a
- jr nz, .asm_e05d
- ld hl, wPartyMon6StatsEnd
- ld d, $5
+ jr nz, .loop
+ ld hl, wPartyMonOT
+ ld d, PARTY_LENGTH - 1
ld a, [wPokemonWithdrawDepositParameter]
and a
- jr z, .asm_e073
+ jr z, .party
ld hl, sBoxMonOT
- ld d, $13
-.asm_e073
+ ld d, MONS_PER_BOX - 1
+
+.party
+ ; If this is the last mon in our party (box),
+ ; shift all the other mons up to close the gap.
ld a, [wCurPartyMon]
call SkipNames
ld a, [wCurPartyMon]
cp d
- jr nz, .asm_e084
- ld [hl], $ff
- jp .asm_e0f6
+ jr nz, .delete_inside
+ ld [hl], -1
+ jp .finish
-.asm_e084
+.delete_inside
+ ; Shift the OT names
ld d, h
ld e, l
- ld bc, NAME_LENGTH
+ ld bc, MON_NAME_LENGTH
add hl, bc
ld bc, wPartyMonNicknames
ld a, [wPokemonWithdrawDepositParameter]
and a
- jr z, .asm_e096
+ jr z, .party2
ld bc, sBoxMonNicknames
-.asm_e096
+.party2
call CopyDataUntil
- ld hl, wPartyMon1
+ ; Shift the struct
+ ld hl, wPartyMons
ld bc, PARTYMON_STRUCT_LENGTH
ld a, [wPokemonWithdrawDepositParameter]
and a
- jr z, .asm_e0ab
- ld hl, sBoxMon1Species
+ jr z, .party4
+ ld hl, sBoxMons
ld bc, BOXMON_STRUCT_LENGTH
-.asm_e0ab
+.party4
ld a, [wCurPartyMon]
call AddNTimes
ld d, h
ld e, l
ld a, [wPokemonWithdrawDepositParameter]
and a
- jr z, .asm_e0c2
+ jr z, .party5
ld bc, BOXMON_STRUCT_LENGTH
add hl, bc
ld bc, sBoxMonOT
- jr .asm_e0c9
+ jr .copy
-.asm_e0c2
+.party5
ld bc, PARTYMON_STRUCT_LENGTH
add hl, bc
ld bc, wPartyMonOT
-.asm_e0c9
+.copy
call CopyDataUntil
+ ; Shift the nicknames
ld hl, wPartyMonNicknames
ld a, [wPokemonWithdrawDepositParameter]
and a
- jr z, .asm_e0d8
+ jr z, .party6
ld hl, sBoxMonNicknames
-.asm_e0d8
- ld bc, NAME_LENGTH
+.party6
+ ld bc, MON_NAME_LENGTH
ld a, [wCurPartyMon]
call AddNTimes
ld d, h
ld e, l
- ld bc, NAME_LENGTH
+ ld bc, MON_NAME_LENGTH
add hl, bc
ld bc, wPartyMonNicknamesEnd
ld a, [wPokemonWithdrawDepositParameter]
and a
- jr z, .asm_e0f3
- ld bc, sBoxEnd
-.asm_e0f3
+ jr z, .party7
+ ld bc, sBoxMonNicknamesEnd
+.party7
call CopyDataUntil
-.asm_e0f6
+ ; Mail time!
+.finish
ld a, [wPokemonWithdrawDepositParameter]
and a
jp nz, CloseSRAM
ld a, [wLinkMode]
and a
ret nz
- ld a, $0
+ ; Shift mail
+ ld a, BANK(sPartyMail)
call OpenSRAM
- ld hl, wPokemonData
+ ; If this is the last mon in our party, no need to shift mail.
+ ld hl, wPartyCount
ld a, [wCurPartyMon]
cp [hl]
- jr z, .asm_e137
- ld hl, s0_a600
+ jr z, .close_sram
+ ; Shift our mail messages up.
+ ld hl, sPartyMail
ld bc, MAIL_STRUCT_LENGTH
call AddNTimes
push hl
@@ -1204,7 +1351,7 @@ RemoveMonFromPartyOrBox: ; e03f (3:603f)
pop de
ld a, [wCurPartyMon]
ld b, a
-.asm_e120
+.loop2
push bc
push hl
ld bc, MAIL_STRUCT_LENGTH
@@ -1218,8 +1365,8 @@ RemoveMonFromPartyOrBox: ; e03f (3:603f)
inc b
ld a, [wPartyCount]
cp b
- jr nz, .asm_e120
-.asm_e137
+ jr nz, .loop2
+.close_sram
jp CloseSRAM
ComputeNPCTrademonStats:
@@ -1239,7 +1386,7 @@ ComputeNPCTrademonStats:
push de
ld a, MON_STAT_EXP - 1
call GetPartyParamLocation
- ld b, $1
+ ld b, TRUE
call CalcMonStats
pop de
ld a, MON_HP
@@ -1251,14 +1398,14 @@ ComputeNPCTrademonStats:
ld [hl], a
ret
-CalcMonStats: ; e16d
-; Calculates all 6 Stats of a Pkmn
+CalcMonStats:
+; Calculates all 6 Stats of a mon
; b: Take into account stat EXP if TRUE
-; 'c' counts from 1-6 and points with 'BaseStats' to the base value
+; 'c' counts from 1-6 and points with 'wBaseStats' to the base value
; hl is the path to the Stat EXP
-; results in $ffb7 and $ffb8 are saved in [de]
+; de points to where the final stats will be saved
- ld c, $0
+ ld c, STAT_HP - 1 ; first stat
.loop
inc c
call CalcMonStatC
@@ -1269,12 +1416,11 @@ CalcMonStats: ; e16d
ld [de], a
inc de
ld a, c
- cp STAT_SDEF
+ cp STAT_SDEF ; last stat
jr nz, .loop
ret
-; e17b
-CalcMonStatC: ; e181
+CalcMonStatC:
; 'c' is 1-6 and points to the BaseStat
; 1: HP
; 2: Attack
@@ -1288,16 +1434,16 @@ CalcMonStatC: ; e181
ld a, b
ld d, a
push hl
- ld hl, wd121
+ ld hl, wBaseStats
dec hl ; has to be decreased, because 'c' begins with 1
- ld b, $0
+ ld b, 0
add hl, bc
ld a, [hl]
ld e, a
pop hl
push hl
ld a, c
- cp STAT_SDEF
+ cp STAT_SDEF ; last stat
jr nz, .not_spdef
dec hl
dec hl
@@ -1310,11 +1456,11 @@ CalcMonStatC: ; e181
add hl, bc
.sqrt_loop
xor a
- ldh [hMultiplicand], a
+ ldh [hMultiplicand + 0], a
ldh [hMultiplicand + 1], a
inc b
ld a, b
- cp $ff
+ cp -1
jr z, .no_stat_exp
ldh [hMultiplicand + 2], a
ldh [hMultiplier], a
@@ -1346,29 +1492,29 @@ CalcMonStatC: ; e181
jr z, .Special
cp STAT_SDEF
jr z, .Special
-; DV_HP = (DV_ATK & 1) << 3 + (DV_DEF & 1) << 2 + (DV_SPD & 1) << 1 + (DV_SPC & 1)
+; DV_HP = (DV_ATK & 1) << 3 | (DV_DEF & 1) << 2 | (DV_SPD & 1) << 1 | (DV_SPC & 1)
push bc
ld a, [hl]
swap a
- and $1
+ and 1
add a
add a
add a
ld b, a
ld a, [hli]
- and $1
+ and 1
add a
add a
add b
ld b, a
ld a, [hl]
swap a
- and $1
+ and 1
add a
add b
ld b, a
ld a, [hl]
- and $1
+ and 1
add b
pop bc
jr .GotDV
@@ -1435,45 +1581,45 @@ CalcMonStatC: ; e181
call Divide
ld a, c
cp STAT_HP
- ld a, 5
+ ld a, STAT_MIN_NORMAL
jr nz, .not_hp
ld a, [wCurPartyLevel]
ld b, a
- ldh a, [hQuotient + 2]
+ ldh a, [hQuotient + 3]
add b
ldh [hMultiplicand + 2], a
jr nc, .no_overflow_3
- ldh a, [hQuotient + 1]
+ ldh a, [hQuotient + 2]
inc a
ldh [hMultiplicand + 1], a
.no_overflow_3
- ld a, 10
+ ld a, STAT_MIN_HP
.not_hp
ld b, a
- ldh a, [hQuotient + 2]
+ ldh a, [hQuotient + 3]
add b
ldh [hMultiplicand + 2], a
jr nc, .no_overflow_4
- ldh a, [hQuotient + 1]
+ ldh a, [hQuotient + 2]
inc a
ldh [hMultiplicand + 1], a
.no_overflow_4
- ldh a, [hQuotient + 1]
- cp (1000 / $100) + 1
+ ldh a, [hQuotient + 2]
+ cp HIGH(MAX_STAT_VALUE + 1) + 1
jr nc, .max_stat
- cp 1000 / $100
+ cp HIGH(MAX_STAT_VALUE + 1)
jr c, .stat_value_okay
- ldh a, [hQuotient + 2]
- cp 1000 % $100
+ ldh a, [hQuotient + 3]
+ cp LOW(MAX_STAT_VALUE + 1)
jr c, .stat_value_okay
.max_stat
- ld a, 999 / $100
+ ld a, HIGH(MAX_STAT_VALUE)
ldh [hMultiplicand + 1], a
- ld a, 999 % $100
+ ld a, LOW(MAX_STAT_VALUE)
ldh [hMultiplicand + 2], a
.stat_value_okay
@@ -1482,15 +1628,15 @@ CalcMonStatC: ; e181
pop hl
ret
-GivePoke: ; Give a Pokemon from script
+GivePoke::
push de
push bc
- xor a
+ xor a ; PARTYMON
ld [wMonType], a
call TryAddMonToParty
- jr nc, .asm_e2c9
- ld hl, wPartyMon1Nickname
- ld a, [wPokemonData]
+ jr nc, .failed
+ ld hl, wPartyMonNicknames
+ ld a, [wPartyCount]
dec a
ld [wCurPartyMon], a
call SkipNames
@@ -1498,27 +1644,27 @@ GivePoke: ; Give a Pokemon from script
ld e, l
pop bc
ld a, b
- ld b, $0
+ ld b, 0
push bc
push de
push af
- ld a, [wd002]
+ ld a, [wCurItem]
and a
- jr z, .asm_e2fa
+ jr z, .done
ld a, [wCurPartyMon]
ld hl, wPartyMon1Item
ld bc, PARTYMON_STRUCT_LENGTH
call AddNTimes
- ld a, [wd002]
+ ld a, [wCurItem]
ld [hl], a
- jr .asm_e2fa
+ jr .done
-.asm_e2c9
+.failed
ld a, [wCurPartySpecies]
ld [wTempEnemyMonSpecies], a
callfar LoadEnemyMon
call SendMonIntoBox
- jp nc, Functione3af
+ jp nc, .FailedToGiveMon
ld a, BOXMON
ld [wMonType], a
xor a
@@ -1526,18 +1672,19 @@ GivePoke: ; Give a Pokemon from script
ld de, wMonOrItemNameBuffer
pop bc
ld a, b
- ld b, $1
+ ld b, 1
push bc
push de
push af
- ld a, [wd002]
+ ld a, [wCurItem]
and a
- jr z, .asm_e2fa
- ld a, [wd002]
+ jr z, .done
+ ld a, [wCurItem]
ld [sBoxMon1Item], a
-.asm_e2fa
+
+.done
ld a, [wCurPartySpecies]
- ld [wd151], a
+ ld [wNamedObjectIndexBuffer], a
ld [wTempEnemyMonSpecies], a
call GetPokemonName
ld hl, wStringBuffer1
@@ -1546,7 +1693,7 @@ GivePoke: ; Give a Pokemon from script
call CopyBytes
pop af
and a
- jr z, .asm_e381
+ jr z, .wildmon
pop de
pop bc
pop hl
@@ -1567,26 +1714,28 @@ GivePoke: ; Give a Pokemon from script
and a
push de
push bc
- jr nz, .asm_e360
+ jr nz, .send_to_box
+
push hl
ld a, [wCurPartyMon]
- ld hl, wPartyMon1OT
+ ld hl, wPartyMonOT
call SkipNames
ld d, h
ld e, l
pop hl
+.otnameloop
ld a, [wScriptBank]
call FarCopyBytes
ld a, [wCurPartyMon]
ld hl, wPartyMon1ID
ld bc, PARTYMON_STRUCT_LENGTH
call AddNTimes
- ld a, 01001 / $100
+ ld a, HIGH(RANDY_OT_ID)
ld [hli], a
- ld [hl], 01001 % $100
- jr .asm_e38d
+ ld [hl], LOW(RANDY_OT_ID)
+ jr .skip_nickname
-.asm_e360
+.send_to_box
ld a, BANK(sBoxMonOT)
call OpenSRAM
ld de, sBoxMonOT
@@ -1599,20 +1748,21 @@ GivePoke: ; Give a Pokemon from script
call Random
ld [hl], a
call CloseSRAM
- jr .asm_e38d
+ jr .skip_nickname
-.asm_e381
- callfar Functionc7cd0
+.wildmon
+ callfar GiveANickname_YesNo
pop de
- jr c, .asm_e38d
+ jr c, .skip_nickname
call InitNickname
-.asm_e38d
+
+.skip_nickname
pop bc
pop de
ld a, b
and a
ret z
- ld hl, TextJump_WasSentToBillsPC
+ ld hl, WasSentToBillsPCText
call PrintText
ld a, BANK(sBoxMonNicknames)
call OpenSRAM
@@ -1624,28 +1774,28 @@ GivePoke: ; Give a Pokemon from script
ld b, $1
ret
-Functione3af: ; e3af (3:63af)
+.FailedToGiveMon:
pop bc
pop de
ld b, $2
ret
-TextJump_WasSentToBillsPC:
- text_far Text_WasSentToBillsPC
- db "@"
+WasSentToBillsPCText:
+ text_far _WasSentToBillsPCText
+ text_end
-InitNickname: ; e3b9 (3:63b9)
+InitNickname:
push de
call LoadStandardMenuHeader
call DisableSpriteUpdates
pop de
push de
- ld b, $0
+ ld b, NAME_MON
farcall NamingScreen
pop hl
ld de, wStringBuffer1
call InitName
- ld a, $4 ; XXX could this be in bank 4 in pokered?
+ ld a, $4 ; ExitAllMenus is in bank 0, XXX could this be in bank 4 in pokered?
ld hl, ExitAllMenus
rst FarCall
ret
diff --git a/engine/pokemon/move_mon_wo_mail.asm b/engine/pokemon/move_mon_wo_mail.asm
new file mode 100644
index 00000000..79f70d05
--- /dev/null
+++ b/engine/pokemon/move_mon_wo_mail.asm
@@ -0,0 +1,133 @@
+InsertPokemonIntoBox:
+ ld a, BANK(sBoxCount)
+ call OpenSRAM
+ ld hl, sBoxCount
+ call InsertSpeciesIntoBoxOrParty
+ ld a, [sBoxCount]
+ dec a
+ ld [wNextBoxOrPartyIndex], a
+ ld hl, sBoxMonNicknames
+ ld bc, MON_NAME_LENGTH
+ ld de, wBufferMonNick
+ call InsertDataIntoBoxOrParty
+ ld a, [sBoxCount]
+ dec a
+ ld [wNextBoxOrPartyIndex], a
+ ld hl, sBoxMonOT
+ ld bc, NAME_LENGTH
+ ld de, wBufferMonOT
+ call InsertDataIntoBoxOrParty
+ ld a, [sBoxCount]
+ dec a
+ ld [wNextBoxOrPartyIndex], a
+ ld hl, sBoxMons
+ ld bc, BOXMON_STRUCT_LENGTH
+ ld de, wBufferMon
+ call InsertDataIntoBoxOrParty
+ ld hl, wBufferMonMoves
+ ld de, wTempMonMoves
+ ld bc, NUM_MOVES
+ call CopyBytes
+ ld hl, wBufferMonPP
+ ld de, wTempMonPP
+ ld bc, NUM_MOVES
+ call CopyBytes
+ ld a, [wCurPartyMon]
+ ld b, a
+ farcall RestorePPOfDepositedPokemon
+ jp CloseSRAM
+
+InsertPokemonIntoParty:
+ ld hl, wPartyCount
+ call InsertSpeciesIntoBoxOrParty
+ ld a, [wPartyCount]
+ dec a
+ ld [wNextBoxOrPartyIndex], a
+ ld hl, wPartyMonNicknames
+ ld bc, MON_NAME_LENGTH
+ ld de, wBufferMonNick
+ call InsertDataIntoBoxOrParty
+ ld a, [wPartyCount]
+ dec a
+ ld [wNextBoxOrPartyIndex], a
+ ld hl, wPartyMonOT
+ ld bc, NAME_LENGTH
+ ld de, wBufferMonOT
+ call InsertDataIntoBoxOrParty
+ ld a, [wPartyCount]
+ dec a
+ ld [wNextBoxOrPartyIndex], a
+ ld hl, wPartyMons
+ ld bc, PARTYMON_STRUCT_LENGTH
+ ld de, wBufferMon
+ call InsertDataIntoBoxOrParty
+ ret
+
+InsertSpeciesIntoBoxOrParty:
+ inc [hl]
+ inc hl
+ ld a, [wCurPartyMon]
+ ld c, a
+ ld b, 0
+ add hl, bc
+ ld a, [wCurPartySpecies]
+ ld c, a
+.loop
+ ld a, [hl]
+ ld [hl], c
+ inc hl
+ inc c
+ ld c, a
+ jr nz, .loop
+ ret
+
+InsertDataIntoBoxOrParty:
+ push de
+ push hl
+ push bc
+ ld a, [wNextBoxOrPartyIndex]
+ dec a
+ call AddNTimes
+ push hl
+ add hl, bc
+ ld d, h
+ ld e, l
+ pop hl
+.loop
+ push bc
+ ld a, [wNextBoxOrPartyIndex]
+ ld b, a
+ ld a, [wCurPartyMon]
+ cp b
+ pop bc
+ jr z, .insert
+ push hl
+ push de
+ push bc
+ call CopyBytes
+ pop bc
+ pop de
+ pop hl
+ push hl
+ ld a, l
+ sub c
+ ld l, a
+ ld a, h
+ sbc b
+ ld h, a
+ pop de
+ ld a, [wNextBoxOrPartyIndex]
+ dec a
+ ld [wNextBoxOrPartyIndex], a
+ jr .loop
+
+.insert
+ pop bc
+ pop hl
+ ld a, [wCurPartyMon]
+ call AddNTimes
+ ld d, h
+ ld e, l
+ pop hl
+ call CopyBytes
+ ret
diff --git a/engine/pokemon/print_move_description.asm b/engine/pokemon/print_move_description.asm
new file mode 100644
index 00000000..e002e3d1
--- /dev/null
+++ b/engine/pokemon/print_move_description.asm
@@ -0,0 +1,16 @@
+PrintMoveDesc:
+ push hl
+ ld hl, MoveDescriptions
+ ld a, [wCurSpecies]
+ dec a
+ ld c, a
+ ld b, 0
+ add hl, bc
+ add hl, bc
+ ld a, BANK(MoveDescriptions)
+ call GetFarHalfword
+ ld d, h
+ ld e, l
+ pop hl
+ ld a, BANK(MoveDescriptions)
+ jp FarString
diff --git a/engine/pokemon/search2.asm b/engine/pokemon/search2.asm
new file mode 100644
index 00000000..c33d84ed
--- /dev/null
+++ b/engine/pokemon/search2.asm
@@ -0,0 +1,134 @@
+_FindPartyMonAboveLevel:
+ ld hl, wPartyMon1Level
+ call FindAboveLevel
+ ret
+
+_FindPartyMonAtLeastThatHappy:
+ ld hl, wPartyMon1Happiness
+ call FindAtLeastThatHappy
+ ret
+
+_FindPartyMonThatSpecies:
+ ld hl, wPartyMon1Species
+ jp FindThatSpecies
+
+_FindPartyMonThatSpeciesYourTrainerID:
+ ld hl, wPartyMon1Species
+ call FindThatSpecies
+ ret z
+ ld a, c
+ ld hl, wPartyMon1ID
+ ld bc, PARTYMON_STRUCT_LENGTH
+ call AddNTimes
+ ld a, [wPlayerID]
+ cp [hl]
+ jr nz, .nope
+ inc hl
+ ld a, [wPlayerID + 1]
+ cp [hl]
+ jr nz, .nope
+ ld a, $1
+ and a
+ ret
+
+.nope
+ xor a
+ ret
+
+FindAtLeastThatHappy:
+; Sets the bits for the Pokemon that have a happiness greater than or equal to b.
+; The lowest bits are used. Sets z if no Pokemon in your party is at least that happy.
+ ld c, $0
+ ld a, [wPartyCount]
+ ld d, a
+.loop
+ ld a, d
+ dec a
+ push hl
+ push bc
+ ld bc, PARTYMON_STRUCT_LENGTH
+ call AddNTimes
+ pop bc
+ ld a, b
+ cp [hl]
+ pop hl
+ jr z, .greater_equal
+ jr nc, .lower
+
+.greater_equal
+ ld a, c
+ or $1
+ ld c, a
+
+.lower
+ sla c
+ dec d
+ jr nz, .loop
+ call RetroactivelyIgnoreEggs
+ ld a, c
+ and a
+ ret
+
+FindAboveLevel:
+ ld c, $0
+ ld a, [wPartyCount]
+ ld d, a
+.loop
+ ld a, d
+ dec a
+ push hl
+ push bc
+ ld bc, PARTYMON_STRUCT_LENGTH
+ call AddNTimes
+ pop bc
+ ld a, b
+ cp [hl]
+ pop hl
+ jr c, .greater
+ ld a, c
+ or $1
+ ld c, a
+
+.greater
+ sla c
+ dec d
+ jr nz, .loop
+ call RetroactivelyIgnoreEggs
+ ld a, c
+ and a
+ ret
+
+FindThatSpecies:
+; Find species b in your party.
+; If you have no Pokemon, returns c = -1 and z.
+; If that species is in your party, returns its location in c, and nz.
+; Otherwise, returns z.
+ ld c, -1
+ ld hl, wPartySpecies
+.loop
+ ld a, [hli]
+ cp -1
+ ret z
+ inc c
+ cp b
+ jr nz, .loop
+ ld a, $1
+ and a
+ ret
+
+RetroactivelyIgnoreEggs:
+ ld e, %11111110
+ ld hl, wPartySpecies
+.loop
+ ld a, [hli]
+ cp -1
+ ret z
+ cp EGG
+ jr nz, .skip_notegg
+ ld a, c
+ and e
+ ld c, a
+
+.skip_notegg
+ rlc e
+ jr .loop
diff --git a/engine/predef.asm b/engine/predef.asm
index b0d0eb56..e18765b0 100755
--- a/engine/predef.asm
+++ b/engine/predef.asm
@@ -25,4 +25,4 @@ GetPredefPointer::
ret
-INCLUDE "data/predef_pointers.asm" \ No newline at end of file
+INCLUDE "data/predef_pointers.asm"
diff --git a/engine/rtc/rtc.asm b/engine/rtc/rtc.asm
new file mode 100644
index 00000000..e56bed45
--- /dev/null
+++ b/engine/rtc/rtc.asm
@@ -0,0 +1,210 @@
+Unreferenced_StopRTC:
+ ld a, SRAM_ENABLE
+ ld [MBC3SRamEnable], a
+ call LatchClock
+ ld a, RTC_DH
+ ld [MBC3SRamBank], a
+ ld a, [MBC3RTC]
+ set 6, a ; halt
+ ld [MBC3RTC], a
+ call CloseSRAM
+ ret
+
+StartRTC:
+ ld a, SRAM_ENABLE
+ ld [MBC3SRamEnable], a
+ call LatchClock
+ ld a, RTC_DH
+ ld [MBC3SRamBank], a
+ ld a, [MBC3RTC]
+ res 6, a ; halt
+ ld [MBC3RTC], a
+ call CloseSRAM
+ ret
+
+GetTimeOfDay::
+; get time of day based on the current hour
+ ldh a, [hHours] ; hour
+ ld hl, TimesOfDay
+
+.check
+; if we're within the given time period,
+; get the corresponding time of day
+ cp [hl]
+ jr c, .match
+; else, get the next entry
+ inc hl
+ inc hl
+; try again
+ jr .check
+
+.match
+; get time of day
+ inc hl
+ ld a, [hl]
+ ld [wTimeOfDay], a
+ ret
+
+TimesOfDay:
+; hours for the time of day
+; 0400-0959 morn | 1000-1759 day | 1800-0359 nite
+ db MORN_HOUR, NITE_F
+ db DAY_HOUR, MORN_F
+ db NITE_HOUR, DAY_F
+ db MAX_HOUR, NITE_F
+ db -1, MORN_F
+
+Unreferenced_1404e:
+ db 20, NITE_F
+ db 40, MORN_F
+ db 60, DAY_F
+ db -1, MORN_F
+
+StageRTCTimeForSave:
+ call UpdateTime
+ ld hl, wRTC
+ ld a, [wCurDay]
+ ld [hli], a
+ ldh a, [hHours]
+ ld [hli], a
+ ldh a, [hMinutes]
+ ld [hli], a
+ ldh a, [hSeconds]
+ ld [hli], a
+ ret
+
+SaveRTC:
+ ld a, SRAM_ENABLE
+ ld [MBC3SRamEnable], a
+ call LatchClock
+ ld hl, MBC3RTC
+ ld a, RTC_DH
+ ld [MBC3SRamBank], a
+ res 7, [hl]
+ ld a, BANK(sRTCStatusFlags)
+ ld [MBC3SRamBank], a
+ xor a
+ ld [sRTCStatusFlags], a
+ call CloseSRAM
+ ret
+
+StartClock::
+ call _GetClock
+ call GetClock
+ call _FixDays
+ call FixDays
+ jr nc, .skip_set
+ ; bit 5: Day count exceeds 139
+ ; bit 6: Day count exceeds 255
+ call RecordRTCStatus ; set flag on sRTCStatusFlags
+
+.skip_set
+ call StartRTC
+ ret
+
+_FixDays:
+ ld hl, hRTCDayHi
+ bit 7, [hl]
+ jr nz, .set_bit_7
+ bit 6, [hl]
+ jr nz, .set_bit_7
+ xor a
+ ret
+
+.set_bit_7
+ ; Day count exceeds 16383
+ ld a, %10000000
+ call RecordRTCStatus ; set bit 7 on sRTCStatusFlags
+ ret
+
+_GetClock:
+ ld a, SRAM_ENABLE
+ ld [MBC3SRamEnable], a
+ call LatchClock
+ ld a, RTC_DH
+ ld [MBC3SRamBank], a
+ ld a, [MBC3RTC]
+ push af
+ call CloseSRAM
+ pop af
+ bit 6, a ; halt
+ ret z
+
+ ld a, BANK(sRTCStatusFlags)
+ call OpenSRAM
+ ld a, $34
+ ld [sUnusedRTCMinutes], a
+ ld a, $12
+ ld [sUnusedRTCHours], a
+ call CloseSRAM
+ ret
+
+ClockContinue:
+ call CheckRTCStatus
+ ld c, a
+ and %11000000 ; Day count exceeded 255 or 16383
+ jr nz, .time_overflow
+
+ ld a, c
+ and %00100000 ; Day count exceeded 139
+ jr z, .dont_update
+
+ call UpdateTime
+ ld a, [wRTC + 0]
+ ld b, a
+ ld a, [wCurDay]
+ cp b
+ jr c, .dont_update
+
+.time_overflow
+ farcall ClearDailyTimers
+ ret
+
+.dont_update
+ xor a
+ ret
+
+_InitTime::
+ call GetClock
+ call FixDays
+ ld hl, hRTCSeconds
+ ld de, wStartSecond
+
+ ld a, [wStringBuffer2 + 3]
+ sub [hl]
+ dec hl
+ jr nc, .okay_secs
+ add 60
+.okay_secs
+ ld [de], a
+ dec de
+
+ ld a, [wStringBuffer2 + 2]
+ sbc [hl]
+ dec hl
+ jr nc, .okay_mins
+ add 60
+.okay_mins
+ ld [de], a
+ dec de
+
+ ld a, [wStringBuffer2 + 1]
+ sbc [hl]
+ dec hl
+ jr nc, .okay_hrs
+ add 24
+.okay_hrs
+ ld [de], a
+ dec de
+
+ ld a, [wStringBuffer2]
+ sbc [hl]
+ dec hl
+ jr nc, .okay_days
+ add 140
+ ld c, 7
+ call SimpleDivide
+
+.okay_days
+ ld [de], a
+ ret
diff --git a/engine/rtc/timeset.asm b/engine/rtc/timeset.asm
new file mode 100644
index 00000000..b89d1af7
--- /dev/null
+++ b/engine/rtc/timeset.asm
@@ -0,0 +1,722 @@
+TIMESET_UP_ARROW EQU "♂" ; $ef
+TIMESET_DOWN_ARROW EQU "♀" ; $f5
+
+InitClock:
+; Ask the player to set the time.
+ ldh a, [hInMenu]
+ push af
+ ld a, $1
+ ldh [hInMenu], a
+
+ ld a, $0
+ ld [wSpriteUpdatesEnabled], a
+ ld a, $10
+ ld [wMusicFade], a
+ ld a, LOW(MUSIC_NONE)
+ ld [wMusicFadeID], a
+ ld a, HIGH(MUSIC_NONE)
+ ld [wMusicFadeID + 1], a
+ ld c, 8
+ call DelayFrames
+ call RotateFourPalettesLeft
+ call ClearTilemap
+ call ClearSprites
+ xor a
+ ldh [hBGMapMode], a
+ call LoadStandardFont
+ ld de, TimeSetBackgroundGFX
+ ld hl, vTiles2 tile $00
+ lb bc, BANK(TimeSetBackgroundGFX), 1
+ call Request1bpp
+ ld de, TimeSetUpArrowGFX
+ ld hl, vTiles2 tile $01
+ lb bc, BANK(TimeSetUpArrowGFX), 1
+ call Request1bpp
+ ld de, TimeSetDownArrowGFX
+ ld hl, vTiles2 tile $02
+ lb bc, BANK(TimeSetDownArrowGFX), 1
+ call Request1bpp
+ call .ClearScreen
+ call WaitBGMap
+ call RotateFourPalettesRight
+ ld hl, OakTimeWokeUpText
+ call PrintText
+ ld hl, wTimeSetBuffer
+ ld bc, wTimeSetBufferEnd - wTimeSetBuffer
+ xor a
+ call ByteFill
+ ld a, 10 ; default hour = 10 AM
+ ld [wInitHourBuffer], a
+
+.loop
+ ld hl, OakTimeWhatTimeIsItText
+ call PrintText
+ hlcoord 3, 7
+ lb bc, 2, 15
+ call Textbox
+ hlcoord 11, 7
+ ld [hl], $1
+ hlcoord 11, 10
+ ld [hl], $2
+ hlcoord 4, 9
+ call DisplayHourOClock
+ ld c, 10
+ call DelayFrames
+
+.SetHourLoop:
+ call JoyTextDelay
+ call SetHour
+ jr nc, .SetHourLoop
+
+ ld a, [wInitHourBuffer]
+ ld [wStringBuffer2 + 1], a
+ call .ClearScreen
+ ld hl, OakTimeWhatHoursText
+ call PrintText
+ call YesNoBox
+ jr nc, .HourIsSet
+ call .ClearScreen
+ jr .loop
+
+.HourIsSet:
+ ld hl, OakTimeHowManyMinutesText
+ call PrintText
+ hlcoord 11, 7
+ lb bc, 2, 7
+ call Textbox
+ hlcoord 15, 7
+ ld [hl], $1
+ hlcoord 15, 10
+ ld [hl], $2
+ hlcoord 12, 9
+ call DisplayMinutesWithMinString
+ ld c, 10
+ call DelayFrames
+
+.SetMinutesLoop:
+ call JoyTextDelay
+ call SetMinutes
+ jr nc, .SetMinutesLoop
+
+ ld a, [wInitMinuteBuffer]
+ ld [wStringBuffer2 + 2], a
+ call .ClearScreen
+ ld hl, OakTimeWhoaMinutesText
+ call PrintText
+ call YesNoBox
+ jr nc, .MinutesAreSet
+ call .ClearScreen
+ jr .HourIsSet
+
+.MinutesAreSet:
+ call InitTimeOfDay
+ ld hl, OakText_ResponseToSetTime
+ call PrintText
+ call WaitPressAorB_BlinkCursor
+ pop af
+ ldh [hInMenu], a
+ ret
+
+.ClearScreen:
+ xor a
+ ldh [hBGMapMode], a
+ hlcoord 0, 0
+ ld bc, SCREEN_HEIGHT * SCREEN_WIDTH
+ xor a
+ call ByteFill
+ ld a, $1
+ ldh [hBGMapMode], a
+ ret
+
+SetHour:
+ ldh a, [hJoyPressed]
+ and A_BUTTON
+ jr nz, .Confirm
+
+ ld hl, hJoyLast
+ ld a, [hl]
+ and D_UP
+ jr nz, .up
+ ld a, [hl]
+ and D_DOWN
+ jr nz, .down
+ call DelayFrame
+ and a
+ ret
+
+.down
+ ld hl, wInitHourBuffer
+ ld a, [hl]
+ and a
+ jr nz, .DecreaseThroughMidnight
+ ld a, 23 + 1
+.DecreaseThroughMidnight:
+ dec a
+ ld [hl], a
+ jr .okay
+
+.up
+ ld hl, wInitHourBuffer
+ ld a, [hl]
+ cp 23
+ jr c, .AdvanceThroughMidnight
+ ld a, -1
+.AdvanceThroughMidnight:
+ inc a
+ ld [hl], a
+
+.okay
+ hlcoord 4, 9
+ ld a, " "
+ ld bc, 15
+ call ByteFill
+ hlcoord 4, 9
+ call DisplayHourOClock
+ call WaitBGMap
+ and a
+ ret
+
+.Confirm:
+ scf
+ ret
+
+DisplayHourOClock:
+ push hl
+ ld a, [wInitHourBuffer]
+ ld c, a
+ ld e, l
+ ld d, h
+ call PrintHour
+ inc hl
+ ld de, String_oclock
+ call PlaceString
+ pop hl
+ ret
+
+UnreferencedFunction907ba:
+ ld h, d
+ ld l, e
+ push hl
+ call DisplayHourOClock
+ pop de
+ inc de
+ inc de
+ ld a, ":"
+ ld [de], a
+ inc de
+ push de
+ ld hl, 3
+ add hl, de
+ ld a, [de]
+ inc de
+ ld [hli], a
+ ld a, [de]
+ ld [hl], a
+ pop hl
+ call DisplayMinutesWithMinString
+ inc hl
+ inc hl
+ inc hl
+ ret
+
+SetMinutes:
+ ldh a, [hJoyPressed]
+ and A_BUTTON
+ jr nz, .a_button
+ ld hl, hJoyLast
+ ld a, [hl]
+ and D_UP
+ jr nz, .d_up
+ ld a, [hl]
+ and D_DOWN
+ jr nz, .d_down
+ call DelayFrame
+ and a
+ ret
+
+.d_down
+ ld hl, wInitMinuteBuffer
+ ld a, [hl]
+ and a
+ jr nz, .decrease
+ ld a, 59 + 1
+.decrease
+ dec a
+ ld [hl], a
+ jr .finish_dpad
+
+.d_up
+ ld hl, wInitMinuteBuffer
+ ld a, [hl]
+ cp 59
+ jr c, .increase
+ ld a, -1
+.increase
+ inc a
+ ld [hl], a
+.finish_dpad
+ hlcoord 12, 9
+ ld a, " "
+ ld bc, 7
+ call ByteFill
+ hlcoord 12, 9
+ call DisplayMinutesWithMinString
+ call WaitBGMap
+ and a
+ ret
+.a_button
+ scf
+ ret
+
+DisplayMinutesWithMinString:
+ ld de, wInitMinuteBuffer
+ call PrintTwoDigitNumberLeftAlign
+ inc hl
+ ld de, String_min
+ call PlaceString
+ ret
+
+PrintTwoDigitNumberLeftAlign:
+ push hl
+ ld a, " "
+ ld [hli], a
+ ld [hl], a
+ pop hl
+ lb bc, PRINTNUM_LEFTALIGN | 1, 2
+ call PrintNum
+ ret
+
+OakTimeWokeUpText:
+ text_far _OakTimeWokeUpText
+ text_end
+
+OakTimeWhatTimeIsItText:
+ text_far _OakTimeWhatTimeIsItText
+ text_end
+
+String_oclock:
+ db "o'clock@"
+
+OakTimeWhatHoursText:
+ ; What?@ @
+ text_far _OakTimeWhatHoursText
+ text_asm
+ hlcoord 1, 16
+ call DisplayHourOClock
+ ld hl, .OakTimeHoursQuestionMarkText
+ ret
+
+.OakTimeHoursQuestionMarkText:
+ text_far _OakTimeHoursQuestionMarkText
+ text_end
+
+OakTimeHowManyMinutesText:
+ text_far _OakTimeHowManyMinutesText
+ text_end
+
+String_min:
+ db "min.@"
+
+OakTimeWhoaMinutesText:
+ ; Whoa!@ @
+ text_far _OakTimeWhoaMinutesText
+ text_asm
+ hlcoord 7, 14
+ call DisplayMinutesWithMinString
+ ld hl, .OakTimeMinutesQuestionMarkText
+ ret
+
+.OakTimeMinutesQuestionMarkText:
+ text_far _OakTimeMinutesQuestionMarkText
+ text_end
+
+OakText_ResponseToSetTime:
+ text_asm
+ decoord 1, 14
+ ld a, [wInitHourBuffer]
+ ld c, a
+ call PrintHour
+ ld [hl], ":"
+ inc hl
+ ld de, wInitMinuteBuffer
+ lb bc, PRINTNUM_LEADINGZEROS | 1, 2
+ call PrintNum
+ ld b, h
+ ld c, l
+ ld a, [wInitHourBuffer]
+ cp MORN_HOUR
+ jr c, .nite
+ cp DAY_HOUR + 1
+ jr c, .morn
+ cp NITE_HOUR
+ jr c, .day
+.nite
+ ld hl, .OakTimeSoDarkText
+ ret
+.morn
+ ld hl, .OakTimeOversleptText
+ ret
+.day
+ ld hl, .OakTimeYikesText
+ ret
+
+.OakTimeOversleptText:
+ text_far _OakTimeOversleptText
+ text_end
+
+.OakTimeYikesText:
+ text_far _OakTimeYikesText
+ text_end
+
+.OakTimeSoDarkText:
+ text_far _OakTimeSoDarkText
+ text_end
+
+TimeSetBackgroundGFX:
+INCBIN "gfx/new_game/timeset_bg.1bpp"
+TimeSetUpArrowGFX:
+INCBIN "gfx/new_game/up_arrow.1bpp"
+TimeSetDownArrowGFX:
+INCBIN "gfx/new_game/down_arrow.1bpp"
+
+SetDayOfWeek:
+ ldh a, [hInMenu]
+ push af
+ ld a, $1
+ ldh [hInMenu], a
+ ld de, TimeSetUpArrowGFX
+ ld hl, vTiles0 tile TIMESET_UP_ARROW
+ lb bc, BANK(TimeSetUpArrowGFX), 1
+ call Request1bpp
+ ld de, TimeSetDownArrowGFX
+ ld hl, vTiles0 tile TIMESET_DOWN_ARROW
+ lb bc, BANK(TimeSetDownArrowGFX), 1
+ call Request1bpp
+ xor a
+ ld [wTempDayOfWeek], a
+.loop
+ hlcoord 0, 12
+ lb bc, 4, 18
+ call Textbox
+ call LoadStandardMenuHeader
+ ld hl, .OakTimeWhatDayIsItText
+ call PrintText
+ hlcoord 9, 3
+ lb bc, 2, 9
+ call Textbox
+ hlcoord 14, 3
+ ld [hl], TIMESET_UP_ARROW
+ hlcoord 14, 6
+ ld [hl], TIMESET_DOWN_ARROW
+ hlcoord 10, 5
+ call .PlaceWeekdayString
+ call ApplyTilemap
+ ld c, 10
+ call DelayFrames
+.loop2
+ call JoyTextDelay
+ call .GetJoypadAction
+ jr nc, .loop2
+ call ExitMenu
+ call UpdateSprites
+ ld hl, .ConfirmWeekdayText
+ call PrintText
+ call YesNoBox
+ jr c, .loop
+ ld a, [wTempDayOfWeek]
+ ld [wStringBuffer2], a
+ call InitDayOfWeek
+ call LoadStandardFont
+ pop af
+ ldh [hInMenu], a
+ ret
+
+.GetJoypadAction:
+ ldh a, [hJoyPressed]
+ and A_BUTTON
+ jr z, .not_A
+ scf
+ ret
+
+.not_A
+ ld hl, hJoyLast
+ ld a, [hl]
+ and D_UP
+ jr nz, .d_up
+ ld a, [hl]
+ and D_DOWN
+ jr nz, .d_down
+ call DelayFrame
+ and a
+ ret
+
+.d_down
+ ld hl, wTempDayOfWeek
+ ld a, [hl]
+ and a
+ jr nz, .decrease
+ ld a, SATURDAY + 1
+
+.decrease
+ dec a
+ ld [hl], a
+ jr .finish_dpad
+
+.d_up
+ ld hl, wTempDayOfWeek
+ ld a, [hl]
+ cp 6
+ jr c, .increase
+ ld a, SUNDAY - 1
+
+.increase
+ inc a
+ ld [hl], a
+
+.finish_dpad
+ xor a
+ ldh [hBGMapMode], a
+ hlcoord 10, 4
+ lb bc, 2, 9
+ call ClearBox
+ hlcoord 10, 5
+ call .PlaceWeekdayString
+ call WaitBGMap
+ and a
+ ret
+
+.PlaceWeekdayString:
+ push hl
+ ld a, [wTempDayOfWeek]
+ ld e, a
+ ld d, 0
+ ld hl, .WeekdayStrings
+ add hl, de
+ add hl, de
+ ld a, [hli]
+ ld d, [hl]
+ ld e, a
+ pop hl
+ call PlaceString
+ ret
+
+.WeekdayStrings:
+; entries correspond to wCurDay constants (see constants/wram_constants.asm)
+ dw .Sunday
+ dw .Monday
+ dw .Tuesday
+ dw .Wednesday
+ dw .Thursday
+ dw .Friday
+ dw .Saturday
+ dw .Sunday
+
+.Sunday: db " SUNDAY@"
+.Monday: db " MONDAY@"
+.Tuesday: db " TUESDAY@"
+.Wednesday: db "WEDNESDAY@"
+.Thursday: db "THURSDAY@"
+.Friday: db " FRIDAY@"
+.Saturday: db "SATURDAY@"
+
+.OakTimeWhatDayIsItText:
+ text_far _OakTimeWhatDayIsItText
+ text_end
+
+.ConfirmWeekdayText:
+ text_asm
+ hlcoord 1, 14
+ call .PlaceWeekdayString
+ ld hl, .OakTimeIsItText
+ ret
+
+.OakTimeIsItText:
+ text_far _OakTimeIsItText
+ text_end
+
+InitialSetDSTFlag:
+ ld a, [wDST]
+ set 7, a
+ ld [wDST], a
+ predef UpdateTimePredef
+ hlcoord 1, 14
+ lb bc, 3, 18
+ call ClearBox
+ ld hl, .Text
+ call PlaceHLTextAtBC
+ ret
+
+.Text:
+ text_asm
+ call UpdateTime
+ ldh a, [hHours]
+ ld b, a
+ ldh a, [hMinutes]
+ ld c, a
+ decoord 1, 14
+ farcall PrintHoursMins
+ ld hl, .DSTIsThatOKText
+ ret
+
+.DSTIsThatOKText:
+ text_far _DSTIsThatOKText
+ text_end
+
+InitialClearDSTFlag:
+ ld a, [wDST]
+ res 7, a
+ ld [wDST], a
+ predef UpdateTimePredef
+ hlcoord 1, 14
+ lb bc, 3, 18
+ call ClearBox
+ ld hl, .Text
+ call PlaceHLTextAtBC
+ ret
+
+.Text:
+ text_asm
+ call UpdateTime
+ ldh a, [hHours]
+ ld b, a
+ ldh a, [hMinutes]
+ ld c, a
+ decoord 1, 14
+ farcall PrintHoursMins
+ ld hl, .TimeAskOkayText
+ ret
+
+.TimeAskOkayText:
+ text_far _TimeAskOkayText
+ text_end
+
+MrChrono:
+ hlcoord 1, 14
+ lb bc, 3, SCREEN_WIDTH - 2
+ call ClearBox
+ ld hl, .Text
+ call PlaceHLTextAtBC
+ ret
+
+.Text:
+ text_asm
+ call UpdateTime
+
+ hlcoord 1, 14
+ ld [hl], "R"
+ inc hl
+ ld [hl], "T"
+ inc hl
+ ld [hl], " "
+ inc hl
+
+ ld de, hRTCDayLo
+ call .PrintTime
+
+ hlcoord 1, 16
+ ld [hl], "D"
+ inc hl
+ ld [hl], "F"
+ inc hl
+ ld [hl], " "
+ inc hl
+
+ ld de, wStartDay
+ call .PrintTime
+
+ ld [hl], " "
+ inc hl
+
+ ld a, [wDST]
+ bit 7, a
+ jr z, .off
+
+ ld [hl], "O"
+ inc hl
+ ld [hl], "N"
+ inc hl
+ jr .done
+
+.off
+ ld [hl], "O"
+ inc hl
+ ld [hl], "F"
+ inc hl
+ ld [hl], "F"
+ inc hl
+
+.done
+ ld hl, .NowOnDebug
+ ret
+
+.NowOnDebug:
+ text "<PARA>Now on DEBUG…"
+ prompt
+
+.PrintTime:
+ lb bc, 1, 3
+ call PrintNum
+ ld [hl], "."
+ inc hl
+ inc de
+ lb bc, PRINTNUM_LEADINGZEROS | 1, 2
+ call PrintNum
+ ld [hl], ":"
+ inc hl
+ inc de
+ lb bc, PRINTNUM_LEADINGZEROS | 1, 2
+ call PrintNum
+ ret
+
+PrintHour:
+ ld l, e
+ ld h, d
+ push bc
+ call GetTimeOfDayString
+ call PlaceString
+ ld l, c
+ ld h, b
+ inc hl
+ pop bc
+ call AdjustHourForAMorPM
+ ld [wDeciramBuffer], a
+ ld de, wDeciramBuffer
+ call PrintTwoDigitNumberLeftAlign
+ ret
+
+GetTimeOfDayString:
+ ld a, c
+ cp MORN_HOUR
+ jr c, .nite
+ cp DAY_HOUR
+ jr c, .morn
+ cp NITE_HOUR
+ jr c, .day
+.nite
+ ld de, .nite_string
+ ret
+.morn
+ ld de, .morn_string
+ ret
+.day
+ ld de, .day_string
+ ret
+
+.nite_string: db "NITE@"
+.morn_string: db "MORN@"
+.day_string: db "DAY@"
+
+AdjustHourForAMorPM:
+; Convert the hour stored in c (0-23) to a 1-12 value
+ ld a, c
+ or a
+ jr z, .midnight
+ cp NOON_HOUR
+ ret c
+ ret z
+ sub NOON_HOUR
+ ret
+
+.midnight
+ ld a, NOON_HOUR
+ ret
diff --git a/engine/sine.asm b/engine/sine.asm
deleted file mode 100644
index e22d785a..00000000
--- a/engine/sine.asm
+++ /dev/null
@@ -1,40 +0,0 @@
-_Sine:: ; 8ac9 (2:4ac9)
- ld a, e
- and $3f
- cp $20
- jr nc, .negative
- call .GetSine
- ld a, h
- ret
-.negative
- and $1f
- call .GetSine
- ld a, h
- xor $ff
- inc a
- ret
-
-.GetSine: ; 8adf (2:4adf)
- ld e, a
- ld a, d
- ld d, $0
- ld hl, .SineWave
- add hl, de
- add hl, de
- ld e, [hl]
- inc hl
- ld d, [hl]
- ld hl, $0
-.loop
- srl a
- jr nc, .no_add
- add hl, de
-.no_add
- sla e
- rl d
- and a
- jr nz, .loop
- ret
-
-.SineWave:
- sine_table $100
diff --git a/engine/smallflag.asm b/engine/smallflag.asm
new file mode 100644
index 00000000..04cbfcc2
--- /dev/null
+++ b/engine/smallflag.asm
@@ -0,0 +1,71 @@
+SmallFarFlagAction:
+; Perform action b on bit c in flag array hl.
+; If checking a flag, check flag array d:hl unless d is 0.
+
+; For longer flag arrays, see FlagAction.
+
+ push hl
+ push bc
+
+; Divide by 8 to get the byte we want.
+ push bc
+ srl c
+ srl c
+ srl c
+ ld b, 0
+ add hl, bc
+ pop bc
+
+; Which bit we want from the byte
+ ld a, c
+ and 7
+ ld c, a
+
+; Shift left until we can mask the bit
+ ld a, 1
+ jr z, .shifted
+.shift
+ add a
+ dec c
+ jr nz, .shift
+.shifted
+ ld c, a
+
+; What are we doing to this flag?
+ dec b
+ jr z, .set ; 1 = SET_FLAG
+ dec b
+ jr z, .check ; 2 = CHECK_FLAG
+; 0 = RESET_FLAG
+
+.reset
+ ld a, c
+ cpl
+ and [hl]
+ ld [hl], a
+ jr .done
+
+.set
+ ld a, [hl]
+ or c
+ ld [hl], a
+ jr .done
+
+.check
+ ld a, d
+ cp 0
+ jr nz, .farcheck
+
+ ld a, [hl]
+ and c
+ jr .done
+
+.farcheck
+ call GetFarByte
+ and c
+
+.done
+ pop bc
+ pop hl
+ ld c, a
+ ret
diff --git a/engine/specials.asm b/engine/specials.asm
deleted file mode 100755
index ad6c2085..00000000
--- a/engine/specials.asm
+++ /dev/null
@@ -1,572 +0,0 @@
-Special:: ; c22b
- ld hl, SpecialsPointers ; $4239
- add hl, de
- add hl, de
- add hl, de
- ld b, [hl]
- inc hl
- ld a, [hli]
- ld h, [hl]
- ld l, a
- ld a, b
- rst FarCall
- ret
-
-; Special routines can be used with the "special" map script command.
-; They often use wScriptVar for arguments and return values.
-
-add_special: MACRO
-; Some ROM0 specials have a nonzero bank.
-\1Special::
-IF _NARG == 1
- dba \1
-ELSE
- dbw \2, \1
-ENDC
-ENDM
-
-SpecialsPointers:
- add_special WarpToSpawnPoint
-
-; Communications
- add_special SetBitsForLinkTradeRequest
- add_special WaitForLinkedFriend
- add_special CheckLinkTimeout
- add_special TryQuickSave
- add_special CheckBothSelectedSameRoom
- add_special FailedLinkToPast
- add_special CloseLink
- add_special WaitForOtherPlayerToExit
- add_special SetBitsForBattleRequest
- add_special SetBitsForTimeCapsuleRequest
- add_special CheckTimeCapsuleCompatibility
- add_special EnterTimeCapsule
- add_special TradeCenter
- add_special Colosseum
- add_special TimeCapsule
- add_special CableClubCheckWhichChris
- add_special CheckMysteryGift
- add_special GetMysteryGiftItem
- add_special UnlockMysteryGift
-
-; Map events
- add_special BugContestJudging
- add_special CheckPartyFullAfterContest
- add_special ContestDropOffMons
- add_special ContestReturnMons
- add_special GiveParkBalls
- add_special CheckMagikarpLength
- add_special MagikarpHouseSign
- add_special HealParty
- add_special PokemonCenterPC
- add_special PlayersHousePC
- add_special DayCareMan
- add_special DayCareLady
- add_special DayCareManOutside
- add_special MoveDeletion
- add_special BankOfMom
- add_special MagnetTrain
- add_special NameRival
- add_special SetDayOfWeek
- add_special OverworldTownMap
- add_special UnownPrinter
- add_special MapRadio
- add_special UnownPuzzle
- add_special SlotMachine
- add_special CardFlip
- add_special DummyNonfunctionalGameCornerGame
- add_special ClearBGPalettesBufferScreen
- add_special FadeOutPalettes
- add_special FadeBlackQuickly
- add_special FadeInPalettes
- add_special FadeInQuickly
- add_special ReloadSpritesNoPalettes, $02
- add_special ClearBGPalettes
- add_special UpdateTimePals
- add_special ClearTilemap
- add_special UpdateSprites
- add_special ReplacePlayerSprite
- add_special GameCornerPrizeMonCheckDex
- add_special UnusedSetSeenMon
- add_special WaitSFX, $03
- add_special PlayMapMusic
- add_special RestartMapMusic
- add_special HealMachineAnim
- add_special SurfStartStep
- add_special FindPartyMonAboveLevel
- add_special FindPartyMonAtLeastThatHappy
- add_special FindPartyMonThatSpecies
- add_special FindPartyMonThatSpeciesYourTrainerID
- add_special UnusedCheckUnusedTwoDayTimer
- add_special DayCareMon1
- add_special DayCareMon2
- add_special SelectRandomBugContestContestants
- add_special ActivateFishingSwarm
- add_special ToggleMaptileDecorations
- add_special ToggleDecorationsVisibility
- add_special GiveShuckle
- add_special ReturnShuckle
- add_special BillsGrandfather
- add_special CheckPokerus
- add_special DisplayCoinCaseBalance
- add_special DisplayMoneyAndCoinBalance
- add_special PlaceMoneyTopRight
- add_special CheckForLuckyNumberWinners
- add_special CheckLuckyNumberShowFlag
- add_special ResetLuckyNumberShowFlag
- add_special PrintTodaysLuckyNumber
- add_special SelectApricornForKurt
- add_special NameRater
- add_special DisplayLinkRecord
- add_special GetFirstPokemonHappiness
- add_special CheckFirstMonIsEgg
- add_special RandomUnseenWildMon
- add_special RandomPhoneWildMon
- add_special RandomPhoneMon
- add_special LoadUsedSpritesGFX
- add_special PlaySlowCry
- add_special SnorlaxAwake
- add_special YoungerHaircutBrother
- add_special OlderHaircutBrother
- add_special DaisysGrooming
- add_special PlayCurMonCry
- add_special ProfOaksPCBoot
- add_special GameboyCheck
- add_special TrainerHouse
- add_special PhotoStudio
- add_special InitRoamMons
- add_special FadeOutMusic
- add_special Diploma
- add_special PrintDiploma
- add_special InitialSetDSTFlag
- add_special InitialClearDSTFlag
- add_special MrChrono
- add_special SpecialNone
-
-SpecialNone: ; c389
- ret
-
-GameCornerPrizeMonCheckDex: ; c38a
- ld a, [wScriptVar]
- dec a
- call CheckCaughtMon
- ret nz
- ld a, [wScriptVar]
- dec a
- call SetSeenAndCaughtMon
- call FadeToMenu
- ld a, [wScriptVar]
- ld [wd151], a
- farcall NewPokedexEntry
- call ExitAllMenus
- ret
-
-UnusedSetSeenMon: ; c3ac
- ld a, [wScriptVar]
- dec a
- call SetSeenMon
- ret
-
-FindPartyMonAboveLevel: ; c3b4
- ld a, [wScriptVar]
- ld b, a
- farcall PartySearch_MaximumLevel ; same bank
- jr z, asm_c3f2
- jr asm_c3ec
-
-FindPartyMonAtLeastThatHappy: ; c3c2
- ld a, [wScriptVar]
- ld b, a
- farcall PartySearch_MinimumHappiness ; same bank
- jr z, asm_c3f2
- jr asm_c3ec
-
-FindPartyMonThatSpecies: ; c3d0
- ld a, [wScriptVar]
- ld b, a
- farcall PartySearch_SameSpecies ; same bank
- jr z, asm_c3f2
- jr asm_c3ec
-
-FindPartyMonThatSpeciesYourTrainerID: ; c3de
- ld a, [wScriptVar]
- ld b, a
- farcall PartySearch_SameSpeciesAndYourID ; same bank
- jr z, asm_c3f2
- jr asm_c3ec
-
-asm_c3ec
- ld a, $1
- ld [wScriptVar], a
- ret
-
-asm_c3f2
- xor a
- ld [wScriptVar], a
- ret
-
-NameRival: ; c3f7
- ld b, $2
- ld de, wRivalName
- farcall NamingScreen_
- ld hl, wRivalName
- ld de, .DefaultName
- call InitName
- ret
-
-.DefaultName:
-IF DEF(GOLD)
- db "SILVER@"
-ENDC
-
-IF DEF(SILVER)
- db "GOLD@"
-ENDC
-
-NameRater:
- farcall _NameRater
- ret
-
-OverworldTownMap: ; c41a (3:441a)
- call FadeToMenu
- farcall Function9188a
- call ExitAllMenus
- ret
-
-UnownPrinter: ; c427 (3:4427)
- call FadeToMenu
- farcall Function16e3a
- call ExitAllMenus
- ret
-
-DisplayLinkRecord: ; c434 (3:4434)
- call FadeToMenu
- farcall Function3f55d
- call ExitAllMenus
- ret
-
-PlayersHousePC: ; c441 (3:4441)
- xor a
- ld [wScriptVar], a
- farcall Function159b0
- ld a, c
- ld [wScriptVar], a
- ret
-
-CheckMysteryGift: ; c450 (3:4450)
- ld a, $0
- call OpenSRAM
- ld a, [$abe2]
- and a
- jr z, .asm_c45c
- inc a
-.asm_c45c
- ld [wScriptVar], a
- call CloseSRAM
- ret
-
-GetMysteryGiftItem: ; c463 (3:4463)
- ld a, $0
- call OpenSRAM
- ld a, [$abe2]
- ld [wd002], a
- ld a, $1
- ld [wItemQuantityChangeBuffer], a
- ld hl, wNumItems
- call ReceiveItem
- jr nc, .asm_c497
- xor a
- ld [$abe2], a
- call CloseSRAM
- ld a, [wd002]
- ld [wd151], a
- call GetItemName
- ld hl, ReceivedMysteryGiftText ; $449f
- call PrintText
- ld a, $1
- ld [wScriptVar], a
- ret
-
-.asm_c497
- call CloseSRAM
- xor a
- ld [wScriptVar], a
- ret
-
-ReceivedMysteryGiftText:
- text_far ReceivedMysteryGiftText_
- db "@"
-
-BugContestJudging: ; c4a4 (3:44a4)
- farcall Function13a5f
- ld a, b
- ld [wScriptVar], a
- ret
-
-MapRadio: ; c4af (3:44af)
- ld a, [wScriptVar]
- ld e, a
- farcall Function919c1
- ret
-
-UnownPuzzle: ; c4ba (3:44ba)
- call FadeToMenu
- farcall Functione199d
- ld a, [wFieldMoveSucceeded]
- ld [wScriptVar], a
- call ExitAllMenus
- ret
-
-SlotMachine: ; c4cd (3:44cd)
- call Functionc508
- ret c
- ld a, BANK(Function92c36)
- ld hl, Function92c36
- call Functionc4f4
- ret
-
-CardFlip: ; c4da (3:44da)
- call Functionc508
- ret c
- ld a, BANK(Functione0909)
- ld hl, Functione0909
- call Functionc4f4
- ret
-
-DummyNonfunctionalGameCornerGame: ; c4e7 (3:44e7)
- call Functionc508
- ret c
- ld a, BANK(Functione2668)
- ld hl, Functione2668
- call Functionc4f4
- ret
-
-Functionc4f4: ; c4f4 (3:44f4)
- call FarQueueScript
- call FadeToMenu
- ld hl, wQueuedScriptBank
- ld a, [hli]
- push af
- ld a, [hli]
- ld h, [hl]
- ld l, a
- pop af
- rst FarCall
- call ExitAllMenus
- ret
-
-Functionc508: ; c508 (3:4508)
- ld hl, wCoins
- ld a, [hli]
- or [hl]
- jr z, .asm_c51e
- ld a, COIN_CASE
- ld [wd002], a
- ld hl, wNumItems
- call CheckItem
- jr nc, .asm_c523
- and a
- ret
-
-.asm_c51e
- ld hl, .NoCoinsText
- jr .asm_c526
-
-.asm_c523
- ld hl, .NoCoinCaseText
-.asm_c526
- call PrintText
- scf
- ret
-
-.NoCoinsText:
- text_far NoCoinsText_
- db "@"
-
-.NoCoinCaseText:
- text_far NoCoinCaseText_
- db "@"
-
-ClearBGPalettesBufferScreen: ; c535 (3:4535)
- call ClearBGPalettes
- call BufferScreen
- ret
-
-Functionc53c: ; c53c (3:453c)
- jr c, .asm_c543
- xor a
- ld [wScriptVar], a
- ret
-
-.asm_c543
- ld a, $1
- ld [wScriptVar], a
- ret
-
-UnusedCheckUnusedTwoDayTimer: ; c549 (3:4549)
- farcall Function118f8
- ld a, [wUnusedTwoDayTimer]
- ld [wScriptVar], a
- ret
-
-ActivateFishingSwarm: ; c556 (3:4556)
- ld a, [wScriptVar]
- ld [wFishingSwarmFlag], a
- jr .asm_c566
-
-.asm_c55e
- ld a, d
- ld [wDunsparceMapGroup], a
- ld a, e
- ld [wDunsparceMapNumber], a
-.asm_c566
- SetFlag ENGINE_SPECIAL_WILDDATA
- ret
-
-Functionc56c:
- CheckFlagHL ENGINE_SPECIAL_WILDDATA
- jr z, .asm_c578
- xor a
- ld [wScriptVar], a
- ret
-
-.asm_c578
- ld a, $1
- ld [wScriptVar], a
- xor a
- ld [wFishingSwarmFlag], a
- ld [wDunsparceMapGroup], a
- ld [wDunsparceMapNumber], a
- ret
-
-CheckPokerus: ; c588 (3:4588)
- farcall Functionc7a40
- jp Functionc53c
-
-ResetLuckyNumberShowFlag: ; c591 (3:4591)
- farcall Function11917
- ClearFlag ENGINE_LUCKY_NUMBER_SHOW
- farcall LoadOrRegenerateLuckyIDNumber
- ret
-
-CheckLuckyNumberShowFlag: ; c5a3 (3:45a3)
- farcall Function1192e
- jp Functionc53c
-
-CountUnown: ; c5ac (3:45ac)
- ld hl, wUnownDex
- ld b, $0
-.asm_c5b1
- ld a, [hli]
- and a
- ret z
- inc b
- ld a, b
- cp $1a
- jr c, .asm_c5b1
- ret
-
-SelectApricornForKurt: ; c5bb (3:45bb)
- farcall Function24b8d
- ld a, c
- ld [wScriptVar], a
- and a
- ret z
- ld [wd002], a
- ld a, $1
- ld [wItemQuantityChangeBuffer], a
- ld hl, wNumItems
- call TossItem
- ret
-
-SnorlaxAwake: ; c5d6 (3:45d6)
- ld a, [wChannelsEnd]
- cp $40
- jr nz, .asm_c5fb
- ld a, [wXCoord]
- ld b, a
- ld a, [wYCoord]
- ld c, a
- ld hl, .ProximityCoords
-.asm_c5e8
- ld a, [hli]
- cp $ff
- jr z, .asm_c5fb
- cp b
- jr nz, .asm_c5f8
- ld a, [hli]
- cp c
- jr nz, .asm_c5e8
- ld a, $1
- jr .asm_c5fc
-
-.asm_c5f8
- inc hl
- jr .asm_c5e8
-
-.asm_c5fb
- xor a
-.asm_c5fc
- ld [wScriptVar], a
- ret
-
-.ProximityCoords:
- ; x, y
- db 33, 8 ; left
- db 34, 10 ; below
- db 35, 10 ; below
- db 36, 8 ; right
- db 36, 9 ; right
- db -1
-
-PlayCurMonCry: ; c60b (3:460b)
- ld a, [wCurPartySpecies]
- jp PlayMonCry
-
-GameboyCheck: ; c611 (3:4611)
- ldh a, [hCGB]
- and a
- jr nz, .asm_c622
- ldh a, [hSGB]
- and a
- jr nz, .asm_c61e
- xor a
- jr .asm_c624
-
-.asm_c61e
- ld a, $1
- jr .asm_c624
-
-.asm_c622
- ld a, $2
-.asm_c624
- ld [wScriptVar], a
- ret
-
-FadeOutMusic: ; c628 (3:4628)
- ld a, $0
- ld [wMusicFadeID], a
- ld a, $0
- ld [wMusicFadeID + 1], a
- ld a, $2
- ld [wMusicFade], a
- ret
-
-Diploma: ; c638 (3:4638)
- call FadeToMenu
- farcall Functione0002
- call ExitAllMenus
- ret
-
-PrintDiploma: ; c645 (3:4645)
- call FadeToMenu
- farcall Function84684
- call ExitAllMenus
- ret
-
-TrainerHouse: ; c652 (3:4652)
- ld a, $0
- call OpenSRAM
- ld a, [$abfd]
- ld [wScriptVar], a
- jp CloseSRAM
diff --git a/engine/step_types.asm b/engine/step_types.asm
deleted file mode 100755
index 91858f98..00000000
--- a/engine/step_types.asm
+++ /dev/null
@@ -1,719 +0,0 @@
-StepTypesJumptable: ; 4b1e
- dw ObjectMovementReset
- dw MapObjectMovementPattern
- dw Function4e02
- dw Function4db4
- dw Function4df8
- dw Function4de3
- dw Function4e2d
- dw Function4e1e
- dw Function4b5d
- dw Function4b96
- dw Function4e5a
- dw Function4dd6
- dw Function4bef
- dw Function4c60
- dw Function4ceb
- dw Function4ea4
- dw Function4d55
- dw Function4d86
- dw Function4d9f
- dw Function4edb
- dw Function4f0a
- dw Function4f0a
- dw Function4f4e
- dw Function4f51
- dw Function4dc7
-
-Function4b50: ; 4b50 (1:4b50)
- ld hl, $a
- add hl, bc
- dec [hl]
- ret nz
- ld hl, $9
- add hl, bc
- ld [hl], $1
- ret
-
-Function4b5d: ; 4b5d (1:4b5d)
- call Object28AnonymousJumptable
- dw Function4b64
- dw Function4b80
-
-Function4b64:
- call AddStepVector
- call Function4f7d
- ld hl, $a
- add hl, bc
- dec [hl]
- ret nz
- call CopyNextCoordsTileToStandingCoordsTile
- call GetNextTile
- ld hl, $5
- add hl, bc
- res 3, [hl]
- call IncrementObjectStructField28
- ret
-
-Function4b80:
- call AddStepVector
- call Function4f7d
- ld hl, $a
- add hl, bc
- dec [hl]
- ret nz
- call CopyNextCoordsTileToStandingCoordsTile
- ld hl, $9
- add hl, bc
- ld [hl], $1
- ret
-
-Function4b96: ; 4b96 (1:4b96)
- call Object28AnonymousJumptable
- dw Function4ba1
- dw Function4ba9
- dw Function4bc9
- dw Function4bd4
-
-Function4ba1:
- ld hl, wPlayerStepFlags
- set 7, [hl]
- call IncrementObjectStructField28
-Function4ba9:
- call Function4f7d
- call UpdatePlayerStep
- ld hl, $a
- add hl, bc
- dec [hl]
- ret nz
- call CopyNextCoordsTileToStandingCoordsTile
- ld hl, $5
- add hl, bc
- res 3, [hl]
- ld hl, wPlayerStepFlags
- set 6, [hl]
- set 4, [hl]
- call IncrementObjectStructField28
- ret
-
-Function4bc9:
- call GetNextTile
- ld hl, wPlayerStepFlags
- set 7, [hl]
- call IncrementObjectStructField28
-Function4bd4:
- call Function4f7d
- call UpdatePlayerStep
- ld hl, $a
- add hl, bc
- dec [hl]
- ret nz
- ld hl, wPlayerStepFlags
- set 6, [hl]
- call CopyNextCoordsTileToStandingCoordsTile
- ld hl, $9
- add hl, bc
- ld [hl], $1
- ret
-
-Function4bef: ; 4bef (1:4bef)
- call Object28AnonymousJumptable
- dw Function4bfa
- dw Function4c09
- dw Function4c19
- dw Function4c34
-
-Function4bfa:
- ld hl, $c
- add hl, bc
- ld [hl], $0
- ld hl, $a
- add hl, bc
- ld [hl], $10
- call IncrementObjectStructField28
-Function4c09:
- ld hl, $b
- add hl, bc
- ld [hl], $4
- ld hl, $a
- add hl, bc
- dec [hl]
- ret nz
- call IncrementObjectStructField28
- ret
-
-Function4c19:
- ld hl, $c
- add hl, bc
- ld [hl], $0
- ld hl, $1f
- add hl, bc
- ld [hl], $10
- ld hl, $a
- add hl, bc
- ld [hl], $10
- ld hl, $5
- add hl, bc
- res 3, [hl]
- call IncrementObjectStructField28
-Function4c34:
- ld hl, $b
- add hl, bc
- ld [hl], $4
- ld hl, $1f
- add hl, bc
- inc [hl]
- ld a, [hl]
- ld d, $60
- call Sine
- ld a, h
- sub $60
- ld hl, $1a
- add hl, bc
- ld [hl], a
- ld hl, $a
- add hl, bc
- dec [hl]
- ret nz
- ld hl, $c
- add hl, bc
- ld [hl], $0
- ld hl, $9
- add hl, bc
- ld [hl], $1
- ret
-
-Function4c60: ; 4c60 (1:4c60)
- call Object28AnonymousJumptable
- dw Function4c71
- dw Function4c81
- dw Function4c8a
- dw Function4ca0
- dw Function4cc2
- dw Function4ccc
- dw Function4cd8
-
-Function4c71:
- ld hl, $b
- add hl, bc
- ld [hl], $0
- ld hl, $a
- add hl, bc
- ld [hl], $10
- call IncrementObjectStructField28
- ret
-
-Function4c81:
- ld hl, $a
- add hl, bc
- dec [hl]
- ret nz
- call IncrementObjectStructField28
-Function4c8a:
- ld hl, $c
- add hl, bc
- ld [hl], $0
- ld hl, $1f
- add hl, bc
- ld [hl], $0
- ld hl, $a
- add hl, bc
- ld [hl], $10
- call IncrementObjectStructField28
- ret
-
-Function4ca0:
- ld hl, $b
- add hl, bc
- ld [hl], $4
- ld hl, $1f
- add hl, bc
- inc [hl]
- ld a, [hl]
- ld d, $60
- call Sine
- ld a, h
- sub $60
- ld hl, $1a
- add hl, bc
- ld [hl], a
- ld hl, $a
- add hl, bc
- dec [hl]
- ret nz
- call IncrementObjectStructField28
-Function4cc2:
- ld hl, $a
- add hl, bc
- ld [hl], $10
- call IncrementObjectStructField28
- ret
-
-Function4ccc:
- ld hl, $b
- add hl, bc
- ld [hl], $4
- ld hl, $a
- add hl, bc
- dec [hl]
- ret nz
-Function4cd8:
- ld hl, $c
- add hl, bc
- ld [hl], $0
- ld hl, $1a
- add hl, bc
- ld [hl], $0
- ld hl, $9
- add hl, bc
- ld [hl], $1
- ret
-
-Function4ceb: ; 4ceb (1:4ceb)
- call Object28AnonymousJumptable
- dw Function4cf6
- dw Function4d05
- dw Function4d26
- dw Function4d42
-
-Function4cf6:
- ld hl, $b
- add hl, bc
- ld [hl], $0
- ld hl, $a
- add hl, bc
- ld [hl], $10
- call IncrementObjectStructField28
-Function4d05:
- ld hl, $a
- add hl, bc
- dec [hl]
- ret nz
- ld hl, $b
- add hl, bc
- ld [hl], $2
- ld hl, $c
- add hl, bc
- ld [hl], $0
- ld hl, $1f
- add hl, bc
- ld [hl], $0
- ld hl, $a
- add hl, bc
- ld [hl], $10
- call IncrementObjectStructField28
-Function4d26:
- ld hl, $1f
- add hl, bc
- inc [hl]
- ld a, [hl]
- ld d, $60
- call Sine
- ld a, h
- sub $60
- ld hl, $1a
- add hl, bc
- ld [hl], a
- ld hl, $a
- add hl, bc
- dec [hl]
- ret nz
- call IncrementObjectStructField28
-Function4d42:
- ld hl, $c
- add hl, bc
- ld [hl], $0
- ld hl, $1a
- add hl, bc
- ld [hl], $0
- ld hl, $9
- add hl, bc
- ld [hl], $1
- ret
-
-Function4d55: ; 4d55 (1:4d55)
- call Object28AnonymousJumptable
- dw Function4d5c
- dw Function4d6b
-
-Function4d5c:
- ld hl, $a
- add hl, bc
- ld [hl], $8
- ld hl, $1a
- add hl, bc
- ld [hl], $0
- call IncrementObjectStructField28
-Function4d6b:
- ld hl, $1a
- add hl, bc
- ld a, [hl]
- xor $1
- ld [hl], a
- ld hl, $a
- add hl, bc
- dec [hl]
- ret nz
- ld hl, $1a
- add hl, bc
- ld [hl], $0
- ld hl, $9
- add hl, bc
- ld [hl], $1
- ret
-
-Function4d86: ; 4d86 (1:4d86)
- call Function4d8c
- jp Function4b50
-
-Function4d8c: ; 4d8c (1:4d8c)
- ld hl, $a
- add hl, bc
- ld a, [hl]
- and $1
- ld a, $1
- jr z, .asm_4d99
- ld a, $0
-.asm_4d99
- ld hl, $b
- add hl, bc
- ld [hl], a
- ret
-
-Function4d9f: ; 4d9f (1:4d9f)
- ld hl, $a
- add hl, bc
- ld a, [hl]
- and $1
- ld a, $4
- jr z, .asm_4dac
- ld a, $5
-.asm_4dac
- ld hl, $b
- add hl, bc
- ld [hl], a
- jp Function4b50
-
-Function4db4: ; 4db4 (1:4db4)
- ld hl, $7
- add hl, bc
- ld [hl], $ff
- ld hl, $a
- add hl, bc
- dec [hl]
- ret nz
- ld hl, $9
- add hl, bc
- ld [hl], $1
- ret
-
-Function4dc7: ; 4dc7 (1:4dc7)
- ld hl, $7
- add hl, bc
- ld [hl], $ff
- ld hl, $a
- add hl, bc
- dec [hl]
- ret nz
- jp DeleteMapObject
-
-Function4dd6: ; 4dd6 (1:4dd6)
- ld hl, $a
- add hl, bc
- dec [hl]
- ret nz
- ld hl, $9
- add hl, bc
- ld [hl], $1
- ret
-
-Function4de3: ; 4de3 (1:4de3)
- call Object28AnonymousJumptable
- dw Function4dea
- dw Function4df8
-
-Function4dea:
- call RestoreDefaultMovement
- call GetInitialFacing
- ld hl, $8
- add hl, bc
- ld [hl], a
- call IncrementObjectStructField28
-Function4df8: ; 4df8 (1:4df8)
- call Function4f5a
- ld hl, $7
- add hl, bc
- ld [hl], $ff
- ret
-
-Function4e02: ; 4e02 (1:4e02)
- call Function4f5a
- call AddStepVector
- ld hl, $a
- add hl, bc
- dec [hl]
- ret nz
- call CopyNextCoordsTileToStandingCoordsTile
- ld hl, $7
- add hl, bc
- ld [hl], $ff
- ld hl, $9
- add hl, bc
- ld [hl], $1
- ret
-
-Function4e1e: ; 4e1e (1:4e1e)
- call AddStepVector
- ld hl, $a
- add hl, bc
- dec [hl]
- ret nz
- call CopyNextCoordsTileToStandingCoordsTile
- jp Function4af6
-
-Function4e2d: ; 4e2d (1:4e2d)
- call Object28AnonymousJumptable
- dw Function4e34
- dw Function4e3c
-
-Function4e34:
- ld hl, wPlayerStepFlags
- set 7, [hl]
- call IncrementObjectStructField28
-Function4e3c:
- call UpdatePlayerStep
- ld hl, $a
- add hl, bc
- dec [hl]
- ret nz
- ld hl, wPlayerStepFlags
- set 6, [hl]
- call CopyNextCoordsTileToStandingCoordsTile
- ld hl, $7
- add hl, bc
- ld [hl], $ff
- ld hl, $9
- add hl, bc
- ld [hl], $1
- ret
-
-Function4e5a: ; 4e5a (1:4e5a)
- call Object28AnonymousJumptable
- dw Function4e65
- dw Function4e7b
- dw Function4e84
- dw Function4e97
-
-Function4e65:
- ld hl, $7
- add hl, bc
- ld [hl], $ff
- ld hl, $c
- add hl, bc
- ld a, [hl]
- ld [hl], $2
- ld hl, $a
- add hl, bc
- ld [hl], $2
- call IncrementObjectStructField28
-Function4e7b:
- ld hl, $a
- add hl, bc
- dec [hl]
- ret nz
- call IncrementObjectStructField28
-Function4e84:
- ld hl, $1d
- add hl, bc
- ld a, [hl]
- ld hl, $8
- add hl, bc
- ld [hl], a
- ld hl, $a
- add hl, bc
- ld [hl], $2
- call IncrementObjectStructField28
-Function4e97:
- ld hl, $a
- add hl, bc
- dec [hl]
- ret nz
- ld hl, $9
- add hl, bc
- ld [hl], $1
- ret
-
-Function4ea4: ; 4ea4 (1:4ea4)
- call AddStepVector
- ld hl, $a
- add hl, bc
- dec [hl]
- ret nz
- push bc
- ld hl, $10
- add hl, bc
- ld d, [hl]
- ld hl, $11
- add hl, bc
- ld e, [hl]
- ld hl, $1
- add hl, bc
- ld a, [hl]
- ld b, a
- farcall CopyDECoordsToMapObject
- pop bc
- ld hl, $5
- add hl, bc
- res 2, [hl]
- call CopyNextCoordsTileToStandingCoordsTile
- ld hl, $7
- add hl, bc
- ld [hl], $ff
- ld hl, $9
- add hl, bc
- ld [hl], $1
- ret
-
-Function4edb: ; 4edb (1:4edb)
- ld hl, $1d
- add hl, bc
- ld e, [hl]
- inc hl
- ld d, [hl]
- ld hl, $0
- add hl, de
- ld a, [hl]
- and a
- jr z, .asm_4f07
- ld hl, $17
- add hl, de
- ld a, [hl]
- ld hl, $17
- add hl, bc
- ld [hl], a
- ld hl, $18
- add hl, de
- ld a, [hl]
- ld hl, $18
- add hl, bc
- ld [hl], a
- ld hl, $a
- add hl, bc
- ld a, [hl]
- and a
- ret z
- dec [hl]
- ret nz
-.asm_4f07
- jp DeleteMapObject
-
-Function4f0a: ; 4f0a (1:4f0a)
- call Object28AnonymousJumptable
- dw Function4f11
- dw Function4f1a
-
-Function4f11:
- xor a
- ld hl, $1d
- add hl, bc
- ld [hl], a
- call IncrementObjectStructField28
-Function4f1a:
- ld hl, $1d
- add hl, bc
- ld d, [hl]
- ld a, [wPlayerStepVectorY]
- sub d
- ld [wPlayerStepVectorY], a
- ld hl, $a
- add hl, bc
- dec [hl]
- jr z, .asm_4f3f
- ld a, [hl]
- call Function4f43
- ld hl, $1d
- add hl, bc
- ld [hl], a
- ld d, a
- ld a, [wPlayerStepVectorY]
- add d
- ld [wPlayerStepVectorY], a
- ret
-
-.asm_4f3f
- call DeleteMapObject
- ret
-
-Function4f43: ; 4f43 (1:4f43)
- ld hl, $1e
- add hl, bc
- and $1
- ld a, [hl]
- ret z
- cpl
- inc a
- ret
-
-Function4f4e: ; 4f4e (1:4f4e)
- call Object28AnonymousJumptable
-Function4f51: ; 4f51 (1:4f51)
- call Object28AnonymousJumptable
- dw Function4f5a
- dw Function4f5a
- dw Function4f5a
-
-Function4f5a: ; 4f5a (1:4f5a)
- ret
-
-Function4f5b:
- ld hl, $1d
- add hl, bc
- inc [hl]
- ld a, [hl]
- srl a
- srl a
- and $7
- ld l, a
- ld h, $0
- ld de, .data
- add hl, de
- ld a, [hl]
- ld hl, $1a
- add hl, bc
- ld [hl], a
- ret
-
-.data
- db 0, -1, -2, -3, -4, -3, -2, -1
-
-Function4f7d: ; 4f7d (1:4f7d)
- call GetStepVector
- ld a, h
- ld hl, $1f
- add hl, bc
- ld e, [hl]
- add e
- ld [hl], a
- nop
- srl e
- ld d, $0
- ld hl, .data
- add hl, de
- ld a, [hl]
- ld hl, $1a
- add hl, bc
- ld [hl], a
- ret
-
-.data
- db -4, -6, -8, -10, -11, -12, -12, -12
- db -11, -10, -9, -8, -6, -4, 0, 0
-
-Function4fa8:
- ld a, [wce87]
- ld hl, wce88
- ld [hl], a
- ld a, $3e
- ld [wce87], a
- ld a, [hl]
- ret
diff --git a/engine/tilesets/map_palettes.asm b/engine/tilesets/map_palettes.asm
new file mode 100644
index 00000000..858098e6
--- /dev/null
+++ b/engine/tilesets/map_palettes.asm
@@ -0,0 +1,110 @@
+_SwapTextboxPalettes::
+ hlcoord 0, 0
+ decoord 0, 0, wAttrmap
+ ld b, SCREEN_HEIGHT
+.loop
+ ld c, SCREEN_WIDTH
+.innerloop
+ ld a, [hli]
+ push hl
+ srl a
+ jr c, .UpperNybble
+ ld hl, wTilesetPalettes
+ add [hl]
+ ld l, a
+ ld a, [wTilesetPalettes + 1]
+ adc 0
+ ld h, a
+ ld a, [hl]
+ and $f
+ bit 3, a
+ jr z, .next
+ jr .asm_8038
+
+.UpperNybble:
+ ld hl, wTilesetPalettes
+ add [hl]
+ ld l, a
+ ld a, [wTilesetPalettes + 1]
+ adc 0
+ ld h, a
+ ld a, [hl]
+ swap a
+ and $f
+ bit 3, a
+ jr z, .next
+
+.asm_8038
+ ld a, [wMapGroup]
+ dec a
+ ld hl, Unknown85d7
+ add l
+ ld l, a
+ jr nc, .asm_8044
+ inc h
+.asm_8044
+ ld a, [hl]
+
+.next
+ pop hl
+ ld [de], a
+ inc de
+ dec c
+ jr nz, .innerloop
+ dec b
+ jr nz, .loop
+ ret
+
+_ScrollBGMapPalettes::
+ ld hl, wBGMapBuffer
+ ld de, wBGMapPalBuffer
+.loop
+ ld a, [hli]
+ push hl
+ srl a
+ jr c, .UpperNybble
+
+; .LowerNybble
+ ld hl, wTilesetPalettes
+ add [hl]
+ ld l, a
+ ld a, [wTilesetPalettes + 1]
+ adc 0
+ ld h, a
+ ld a, [hl]
+ and $f
+ bit 3, a
+ jr z, .next
+ jr .asm_8083
+
+.UpperNybble:
+ ld hl, wTilesetPalettes
+ add [hl]
+ ld l, a
+ ld a, [wTilesetPalettes + 1]
+ adc 0
+ ld h, a
+ ld a, [hl]
+ swap a
+ and $f
+ bit 3, a
+ jr z, .next
+
+.asm_8083
+ ld a, [wMapGroup]
+ dec a
+ ld hl, Unknown85d7
+ add l
+ ld l, a
+ jr nc, .asm_808f
+ inc h
+.asm_808f
+ ld a, [hl]
+
+.next
+ pop hl
+ ld [de], a
+ inc de
+ dec c
+ jr nz, .loop
+ ret
diff --git a/engine/title.asm b/engine/title.asm
deleted file mode 100755
index 94863c56..00000000
--- a/engine/title.asm
+++ /dev/null
@@ -1,450 +0,0 @@
-IntroSequence: ; 6241 (1:6241)
- callfar Copyright_GFPresents
- jr c, StartTitleScreen
- callfar GoldSilverIntro
-StartTitleScreen:
- call InitTitleScreen
- call DelayFrame
-.asm_6255
- call TitleScreenFrame
- jr nc, .asm_6255
- call ClearSprites
- call ClearBGPalettes
- ld hl, rLCDC
- res 2, [hl]
- call ClearTilemap
- xor a
- ldh [hLCDCPointer], a
- ld b, $8
- call GetSGBLayout
- call UpdateTimePals
- ld a, [wce64]
- cp $5
- jr c, .asm_627b
- xor a
-.asm_627b
- ld e, a
- ld d, $0
- ld hl, .Jumptable
- add hl, de
- add hl, de
- ld a, [hli]
- ld h, [hl]
- ld l, a
- jp hl
-
-.Jumptable
- dw MainMenu_
- dw DeleteSaveData
- dw IntroSequence
- dw IntroSequence
- dw ResetClock
-
-InitTitleScreen: ; 6291 (1:6291)
- call ClearBGPalettes
- xor a
- ld [wTimeOfDayPal], a
- ld de, MUSIC_NONE
- call PlayMusic
- call ClearTilemap
- call DisableLCD
- call ClearSprites
- xor a
- ldh [hBGMapMode], a
- ldh [hMapAnims], a
- ldh [hSCY], a
- ldh [hSCX], a
- ld hl, $8000
- ld bc, $2000
- xor a
- call ByteFill
- farcall ClearAnimatedObjectBuffer
-
- ld hl, TitleScreenGFX1
- ld de, $9000
- ld a, BANK(TitleScreenGFX1)
- call FarDecompress
-
- ld hl, TitleScreenGFX2
- ld de, $8800
- ld a, BANK(TitleScreenGFX2)
- call FarDecompress
-
- ld hl, TitleScreenGFX4
- ld de, $8000
- ld a, BANK(TitleScreenGFX4)
- call FarDecompress
-
- ld hl, TitleScreenGFX3
- ld de, $8f80
- ld bc, $80
- ld a, BANK(TitleScreenGFX3)
- call FarCopyBytes
-
- call Function636e
- call Function63b6
- ld hl, wAnimatedObjectDynamicVTileOffsets
- xor a
- ld [hli], a
- ld [hl], a
- ld hl, rLCDC
- set 2, [hl]
- call EnableLCD
- xor a
- ld hl, wce63
- ld [hli], a
- ld [hli], a
- ld [hli], a
- ld [hl], a
- ld de, $6058
- ld a, $2c ; HO-OH
- call InitSpriteAnimStruct
- ld hl, wAnimatedObjectStruct1
- ld de, wAnimatedObjectStruct10
- ld bc, $a
- call CopyBytes
- ld hl, wAnimatedObjectStruct1
- ld [hl], $0
- ld hl, wc700
- ld bc, $90
- xor a
- call ByteFill
- ld a, $43
- ldh [hLCDCPointer], a
- ld b, $c
- call GetSGBLayout
- call Function6341
- ld de, MUSIC_TITLE
- call PlayMusic
- ret
-
-Function6341: ; 6341 (1:6341)
- ldh a, [hCGB]
- and a
- jr nz, .asm_6365
- ldh a, [hSGB]
- and a
- jr nz, .asm_6358
- ld a, $d8
- ldh [rBGP], a
-IF DEF(GOLD)
- ld a, $ff
- ldh [rOBP0], a
- ld a, $f8
-ENDC
-IF DEF(SILVER)
- ld a, $f0
- ldh [rOBP0], a
- ld a, $f0
-ENDC
- ldh [rOBP1], a
- ret
-
-.asm_6358
- ld a, $e4
- ldh [rBGP], a
-IF DEF(GOLD)
- ld a, $ff
- ldh [rOBP0], a
- ld a, $e4
-ENDC
-IF DEF(SILVER)
- ld a, $f0
- ldh [rOBP0], a
- ld a, $e0
-ENDC
- ldh [rOBP1], a
- ret
-
-.asm_6365
- ld a, $e4
- call DmgToCgbBGPals
-IF DEF(SILVER)
- ld a, $e0
-ENDC
- call DmgToCgbObjPal0
- ret
-
-Function636e: ; 636e (1:636e)
- ldh a, [hCGB]
- and a
- ret z
- ld a, $1
- ldh [rVBK], a
- ld hl, $9800
- ld bc, $240
- xor a
- call ByteFill
- ld hl, $9800
- ld bc, $714
- ld a, $1
- call Function63a6
- ld hl, $98c5
- ld bc, $10a
- ld a, $3
- call Function63a6
- ld hl, $9980
- ld bc, $a0
- ld a, $4
- call ByteFill
- ld a, $0
- ldh [rVBK], a
- ret
-
-Function63a6: ; 63a6 (1:63a6)
- push bc
- push hl
-.asm_63a8
- ld [hli], a
- dec c
- jr nz, .asm_63a8
- pop hl
- ld bc, $20
- add hl, bc
- pop bc
- dec b
- jr nz, Function63a6
- ret
-
-Function63b6: ; 63b6 (1:63b6)
- ld hl, GSIntroTilemap ; $4616
- ld de, $9800
-.asm_63bc
- ld a, BANK(GSIntroTilemap) ; $26
- call GetFarByte
- cp $ff
- jr z, .asm_63ca
- inc hl
- ld [de], a
- inc de
- jr .asm_63bc
-
-.asm_63ca
- ldh a, [hCGB]
- and a
- ret nz
- ld hl, $9960
- ld bc, $20
- ld a, $50
- call ByteFill
- ret
-
-TitleScreenFrame: ; 63da (1:63da)
- call Function63fe
- ld a, [wce63]
- bit 7, a
- jr nz, .asm_63fc
- call Function640f
- ld a, $1
- ldh [hOAMUpdate], a
- farcall AnimatedObjects_PlayFrame
- xor a
- ldh [hOAMUpdate], a
- call Function64b1
- call DelayFrame
- and a
- ret
-
-.asm_63fc
- scf
- ret
-
-Function63fe: ; 63fe (1:63fe)
-IF DEF(GOLD)
- ldh a, [hVBlankCounter]
- and $7
- ret nz
-ENDC
- ld hl, wc75f
- ld a, [hl]
- dec a
- ld bc, $28
- call ByteFill
- ret
-
-Function640f: ; 640f (1:640f)
- ld e, a
- ld d, $0
- ld hl, .Jumptable ; $641b
- add hl, de
- add hl, de
- ld a, [hli]
- ld h, [hl]
- ld l, a
- jp hl
-
-.Jumptable
- dw Function6426
- dw Function6434
- dw Function648b
-
-Function6421:
- ld hl, wce63
- inc [hl]
- ret
-
-Function6426:
- ld hl, wce63
- inc [hl]
- ld hl, wce65
-IF DEF(GOLD)
- ld de, $13c0
-ENDC
-IF DEF(SILVER)
- ld de, $1140
-ENDC
- ld [hl], e
- inc hl
- ld [hl], d
- ret
-
-Function6434:
- ld hl, wce65
- ld e, [hl]
- inc hl
- ld d, [hl]
- ld a, e
- or d
- jr z, .asm_646b
- dec de
- ld [hl], d
- dec hl
- ld [hl], e
- call GetJoypad
- ld hl, hJoyDown
- ld a, [hl]
- and D_UP + B_BUTTON + SELECT
- cp D_UP + B_BUTTON + SELECT
- jr z, .asm_6460
- ld a, [hl]
- and D_DOWN + B_BUTTON + SELECT
- cp D_DOWN + B_BUTTON + SELECT
- jr z, .asm_6480
- ld a, [hl]
- and START | A_BUTTON
- jr nz, .asm_645c
- ret
-
-.asm_645c
- ld a, $0
- jr .asm_6462
-
-.asm_6460
- ld a, $1
-.asm_6462
- ld [wce64], a
- ld hl, wce63
- set 7, [hl]
- ret
-
-.asm_646b
- ld hl, wce63
- inc [hl]
- xor a
- ld [wMusicFadeID], a
- ld [wMusicFadeID + 1], a
- ld hl, wMusicFade
- ld [hl], $8
- ld hl, wce65
- inc [hl]
- ret
-
-.asm_6480
- ld a, $4
- ld [wce64], a
- ld hl, wce63
- set 7, [hl]
- ret
-
-Function648b:
- ld hl, wce65
- inc [hl]
- ld a, [wMusicFade]
- and a
- ret nz
- ld a, $2
- ld [wce64], a
- ld hl, wce63
- set 7, [hl]
- ret
-
-DeleteSaveData:
- farcall DeleteSaveData_
- jp Init
-
-ResetClock:
- farcall ResetClock_
- jp Init
-
-Function64b1: ; 64b1 (1:64b1)
- ld a, [wce65]
- and $3
- ret nz
-IF DEF(GOLD)
- ld bc, wAnimatedObjectStruct10Index
- ld hl, $a
- add hl, bc
- ld l, [hl]
- ld h, $0
- add hl, hl
- add hl, hl
- ld de, .Data_64e0
- add hl, de
- ld a, [wce65]
- and $4
- srl a
- srl a
- ld e, a
- ld d, $0
- add hl, de
- add hl, de
- ld a, [hli]
- and a
- ret z
- ld e, a
- ld d, [hl]
-ENDC
-
-IF DEF(SILVER)
- ld de, $7c58
-ENDC
- ld a, $f
- call InitSpriteAnimStruct
- ret
-
-IF DEF(GOLD)
-.Data_64e0:
- db $5c, $50, $00, $00
- db $5c, $68, $5c, $58
- db $5c, $68, $5c, $78
- db $5c, $88, $5c, $78
- db $00, $00, $5c, $78
- db $00, $00, $5c, $58
-ENDC
-
-Copyright:
- call ClearTilemap
- call LoadFontsExtra
- ld de, CopyrightGFX
- ld hl, vTiles2 tile $60
- lb bc, BANK(CopyrightGFX), 30
- call Request2bpp
- hlcoord 2, 7
- ld de, CopyrightString
- jp PlaceString
-
-CopyrightString:
- db $60, $61, $62, $63, $7a, $7b, $7c, $7d
- db $65, $66, $67, $68, $69, $6a
- next $60, $61, $62, $63, $7a, $7b, $7c, $7d
- db $6b, $6c, $6d, $6e, $6f, $70, $71, $72
- next $60, $61, $62, $63, $7a, $7b, $7c, $7d
- db $73, $74, $75, $76, $77, $78, $79, $71, $72
- db "@"
-
-GameInit:: ; 6545 (1:6545)
- call ClearWindowData
- ld a, $5
- ld hl, $4f60
- rst FarCall
- jp IntroSequence
diff --git a/engine/variables.asm b/engine/variables.asm
deleted file mode 100755
index 7e6906ee..00000000
--- a/engine/variables.asm
+++ /dev/null
@@ -1,119 +0,0 @@
-GetVarAction_::
- ld a, c
- cp NUM_VARS
- jr c, .valid
- xor a
-.valid
- ld c, a
- ld b, 0
- ld hl, .VarActionTable
- add hl, bc
- add hl, bc
- add hl, bc
- ld e, [hl]
- inc hl
- ld d, [hl]
- inc hl
- ld b, [hl]
- ld a, b
- and RETVAR_EXECUTE
- jr nz, .call
- ld a, b
- and RETVAR_ADDR_DE
- ret nz
- ld a, [de]
- jr .loadstringbuffer2
-
-.call
- call _de_
- ret
-
-.loadstringbuffer2
- ld de, wStringBuffer2
- ld [de], a
- ret
-
-.VarActionTable:
- dwb wStringBuffer2, RETVAR_STRBUF2
- dwb wPartyCount, RETVAR_STRBUF2
- dwb .BattleResult, RETVAR_EXECUTE
- dwb wBattleType, RETVAR_ADDR_DE
- dwb wTimeOfDay, RETVAR_STRBUF2
- dwb .CountCaughtMons, RETVAR_EXECUTE
- dwb .CountSeenMons, RETVAR_EXECUTE
- dwb .CountBadges, RETVAR_EXECUTE
- dwb wPlayerState, RETVAR_ADDR_DE
- dwb .PlayerFacing, RETVAR_EXECUTE
- dwb hHours, RETVAR_STRBUF2
- dwb .DayOfWeek, RETVAR_EXECUTE
- dwb wMapGroup, RETVAR_STRBUF2
- dwb wMapNumber, RETVAR_STRBUF2
- dwb .UnownCaught, RETVAR_EXECUTE
- dwb wPermission, RETVAR_STRBUF2
- dwb .BoxFreeSpace, RETVAR_EXECUTE
- dwb wBugContestMinsRemaining, RETVAR_STRBUF2
- dwb wXCoord, RETVAR_STRBUF2
- dwb wYCoord, RETVAR_STRBUF2
- dwb wSpecialPhoneCallID, RETVAR_STRBUF2
- dwb 0, 0
-
-.CountCaughtMons: ; 41cf
-; Caught mons.
- ld hl, wPokedexCaught
- ld b, $20
- call CountSetBits
- ld a, [wd151]
- jp .loadstringbuffer2
-
-.CountSeenMons: ; 41dd
-; Seen mons.
- ld hl, wPokedexSeen
- ld b, $20
- call CountSetBits
- ld a, [wd151]
- jp .loadstringbuffer2
-
-.CountBadges: ; 41eb
-; Number of owned badges.
- ld hl, wBadges
- ld b, 2
- call CountSetBits
- ld a, [wd151]
- jp .loadstringbuffer2
-
-.PlayerFacing: ; 41f9
-; The direction the player is facing.
- ld a, [wPlayerDirection]
- and $c
- rrca
- rrca
- jp .loadstringbuffer2
-
-.DayOfWeek: ; 4203
-; The day of the week.
- call GetWeekday
- jp .loadstringbuffer2
-
-.UnownCaught: ; 4209
-; Number of unique Unown caught.
- call CountUnown ; gold: c5ac | silver: c5aa
- ld a, b
- jp .loadstringbuffer2
-
-.BoxFreeSpace: ; 4210
-; Remaining slots in the current box.
- ld a, BANK(sBoxCount)
- call OpenSRAM
- ld hl, sBoxCount
- ld a, MONS_PER_BOX
- sub [hl]
- ld b, a
- call CloseSRAM
- ld a, b
- jp .loadstringbuffer2
-
-.BattleResult: ; 4223
- ld a, [wBattleResult]
- and $7f
- jp .loadstringbuffer2
-; 422b